From e1ca8a12e6111e5ec0bb4cb35e5edebc2bf1e3ae Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Mon, 23 Jul 2012 09:55:08 +0000 Subject: NewXstatusNotify: changed folder structure git-svn-id: http://svn.miranda-ng.org/main/trunk@1113 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/NewXstatusNotify/src/common.h | 154 ++++ plugins/NewXstatusNotify/src/indsnd.cpp | 681 +++++++++++++++ plugins/NewXstatusNotify/src/indsnd.h | 41 + plugins/NewXstatusNotify/src/main.cpp | 1369 ++++++++++++++++++++++++++++++ plugins/NewXstatusNotify/src/options.cpp | 1074 +++++++++++++++++++++++ plugins/NewXstatusNotify/src/options.h | 90 ++ plugins/NewXstatusNotify/src/popup.cpp | 175 ++++ plugins/NewXstatusNotify/src/popup.h | 54 ++ plugins/NewXstatusNotify/src/resource.h | 147 ++++ plugins/NewXstatusNotify/src/utils.cpp | 124 +++ plugins/NewXstatusNotify/src/utils.h | 33 + plugins/NewXstatusNotify/src/version.h | 4 + plugins/NewXstatusNotify/src/xstatus.cpp | 524 ++++++++++++ plugins/NewXstatusNotify/src/xstatus.h | 106 +++ 14 files changed, 4576 insertions(+) create mode 100644 plugins/NewXstatusNotify/src/common.h create mode 100644 plugins/NewXstatusNotify/src/indsnd.cpp create mode 100644 plugins/NewXstatusNotify/src/indsnd.h create mode 100644 plugins/NewXstatusNotify/src/main.cpp create mode 100644 plugins/NewXstatusNotify/src/options.cpp create mode 100644 plugins/NewXstatusNotify/src/options.h create mode 100644 plugins/NewXstatusNotify/src/popup.cpp create mode 100644 plugins/NewXstatusNotify/src/popup.h create mode 100644 plugins/NewXstatusNotify/src/resource.h create mode 100644 plugins/NewXstatusNotify/src/utils.cpp create mode 100644 plugins/NewXstatusNotify/src/utils.h create mode 100644 plugins/NewXstatusNotify/src/version.h create mode 100644 plugins/NewXstatusNotify/src/xstatus.cpp create mode 100644 plugins/NewXstatusNotify/src/xstatus.h (limited to 'plugins/NewXstatusNotify/src') diff --git a/plugins/NewXstatusNotify/src/common.h b/plugins/NewXstatusNotify/src/common.h new file mode 100644 index 0000000000..3cc765af4d --- /dev/null +++ b/plugins/NewXstatusNotify/src/common.h @@ -0,0 +1,154 @@ +/* + NewXstatusNotify YM - Plugin for Miranda IM + Copyright (c) 2001-2004 Luca Santarelli + Copyright (c) 2005-2007 Vasilich + Copyright (c) 2007-2011 yaho + + 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 +*/ + +#ifndef COMMON_H +#define COMMON_H + +#pragma once + +#define STRICT +#define WIN32_LEAN_AND_MEAN +#define _CRT_SECURE_NO_WARNINGS + +#define _WIN32_WINNT 0x0500 +#define WINVER 0x0600 +#define MIRANDA_VER 0x0A00 + +//Standard Windows "libraries" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "m_awaymsg.h" +#include "m_button.h" +#include "m_clc.h" +#include "m_database.h" +#include "m_genmenu.h" +#include "m_history.h" +#include "m_icolib.h" +#include "m_ignore.h" +#include "m_langpack.h" +#include "m_message.h" +#include "m_options.h" +#include "m_popup.h" +#include "m_protosvc.h" +#include "m_skin.h" +#include "m_system.h" +#include "m_userinfo.h" +#include "m_utils.h" +#include "m_icq.h" + +#include "m_metacontacts.h" +#include "m_toptoolbar.h" +#include "resource.h" + +#define MIID_NXSN { 0xebf19652, 0xe434, 0x4d79, { 0x98, 0x97, 0x91, 0xa0, 0xff, 0x22, 0x6f, 0x51 } } + +#define MODULE "NewStatusNotify" + +#define WM_AWAYMSG WM_USER + 0x0192 + +#define MAX_STATUSTEXT 36 +#define MAX_STANDARDTEXT 36 +#define MAX_SKINSOUNDNAME 36 +#define MAX_SKINSOUNDDESC 36 + +#define GENDER_UNSPECIFIED 0 +#define GENDER_MALE 1 +#define GENDER_FEMALE 2 + +#define ID_STATUS_FROMOFFLINE 1 +#define ID_STATUS_EXTRASTATUS 40081 +#define ID_STATUS_MIN ID_STATUS_OFFLINE +#define ID_STATUS_MAX ID_STATUS_OUTTOLUNCH +#define ID_STATUS_MAX2 ID_STATUS_EXTRASTATUS + 1 +#define STATUS_COUNT ID_STATUS_MAX2 - ID_STATUS_MIN +#define Index(ID_STATUS) ID_STATUS - ID_STATUS_OFFLINE + +#define COLOR_BG_AVAILDEFAULT RGB(173,206,247) +#define COLOR_BG_NAVAILDEFAULT RGB(255,189,189) +#define COLOR_TX_DEFAULT RGB(0,0,0) + +#define ICO_NOTIFICATION_OFF "notification_off" +#define ICO_NOTIFICATION_ON "notification_on" + +#define JS_PARSE_XMPP_URI "/ParseXmppURI" + +typedef struct tagSTATUS +{ + int ID; + int icon; + TCHAR lpzMStatusText[MAX_STATUSTEXT]; + TCHAR lpzFStatusText[MAX_STATUSTEXT]; + TCHAR lpzUStatusText[MAX_STATUSTEXT]; + TCHAR lpzStandardText[MAX_STANDARDTEXT]; + char lpzSkinSoundName[MAX_SKINSOUNDNAME]; + char lpzSkinSoundDesc[MAX_SKINSOUNDDESC]; + char lpzSkinSoundFile[MAX_PATH]; + COLORREF colorBack; + COLORREF colorText; +} STATUS; + +typedef struct tagPLUGINDATA +{ + WORD newStatus; + WORD oldStatus; + HANDLE hAwayMsgProcess; + HANDLE hAwayMsgHook; +} PLUGINDATA; + +typedef struct { + HANDLE hContact; + TCHAR *cust; + TCHAR *oldstatusmsg; + TCHAR *newstatusmsg; + char *proto; + int compare; +} STATUSMSGINFO; + +/* +HANDLE hContact = (HANDLE)wParam; +WORD oldStatus = LOWORD(lParam); +WORD newStatus = HIWORD(lParam); +oldStatus is the status the contact was before the change. +newStatus is the status the contact is now. +Cast them to (int) if you need them that way. +*/ +#define ME_STATUSCHANGE_CONTACTSTATUSCHANGED "Miranda/StatusChange/ContactStatusChanged" + +#define MS_STATUSCHANGE_MENUCOMMAND "NewStatusNotify/EnableDisableMenuCommand" + +#define TMR_CONNECTIONTIMEOUT 10000 + +#endif //COMMON_H diff --git a/plugins/NewXstatusNotify/src/indsnd.cpp b/plugins/NewXstatusNotify/src/indsnd.cpp new file mode 100644 index 0000000000..27a8b9a02a --- /dev/null +++ b/plugins/NewXstatusNotify/src/indsnd.cpp @@ -0,0 +1,681 @@ +/* + NewXstatusNotify YM - Plugin for Miranda IM + Copyright (c) 2001-2004 Luca Santarelli + Copyright (c) 2005-2007 Vasilich + Copyright (c) 2007-2011 yaho + + 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 "common.h" +#include "options.h" +#include "indsnd.h" +#include "utils.h" + +extern STATUS StatusList[]; +extern OPTIONS opt; +extern HINSTANCE hInst; + +void PreviewSound(HWND hList) +{ + TCHAR buff[MAX_PATH], stzSoundPath[MAX_PATH]; + + LVITEM lvi = {0}; + lvi.mask = LVIF_PARAM; + lvi.iItem = ListView_GetNextItem(hList, -1, LVNI_SELECTED); + ListView_GetItem(hList, &lvi); + + int hlpStatus = lvi.lParam; + + ListView_GetItemText(hList, lvi.iItem, 1, buff, SIZEOF(buff)); + if (_tcscmp(buff, TranslateT(DEFAULT_SOUND)) == 0) + { + if (hlpStatus == ID_STATUS_FROMOFFLINE) + SkinPlaySound("UserFromOffline"); + else + SkinPlaySound(StatusList[Index(hlpStatus)].lpzSkinSoundName); + } + else + { + CallService(MS_UTILS_PATHTOABSOLUTET, (WPARAM)buff, (LPARAM)stzSoundPath); + PlaySound(stzSoundPath, NULL, SND_ASYNC | SND_FILENAME); + } +} + +BOOL RemoveSoundFromList(HWND hList) +{ + int iSel = ListView_GetSelectionMark(hList); + if (iSel != -1) + { + iSel = -1; + while ((iSel = ListView_GetNextItem(hList, iSel, LVNI_SELECTED)) != -1) + ListView_SetItemText(hList, iSel, 1, TranslateT(DEFAULT_SOUND)); + return TRUE; + } + + return FALSE; +} + +TCHAR *SelectSound(HWND hwndDlg, TCHAR *buff) +{ + OPENFILENAME ofn = {0}; + + HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST); + ListView_GetItemText(hList, ListView_GetNextItem(hList,- 1, LVNI_SELECTED), 1, buff, SIZEOF(buff)); + + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = GetParent(hwndDlg); + ofn.hInstance = hInst; + TCHAR filter[MAX_PATH]; + mir_sntprintf(filter, SIZEOF(filter), _T("%s (*.wav)%c*.WAV%c%s (*.*)%c*%c"), TranslateT("Wave Files"), 0, 0, TranslateT("All Files"), 0, 0); + ofn.lpstrFilter = filter; + ofn.lpstrFile = buff; + ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER | OFN_NOCHANGEDIR; + ofn.nMaxFile = MAX_PATH; + ofn.nMaxFileTitle = MAX_PATH; + ofn.lpstrDefExt = _T("wav"); + if (GetOpenFileName(&ofn)) + return buff; + + return NULL; +} + +HIMAGELIST GetStatusIconsImgList(char *szProto) +{ + HIMAGELIST hList = NULL; + if (szProto) + { + hList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16 | ILC_MASK, STATUS_COUNT, 0); + if (hList != NULL) + { + for (int i = ID_STATUS_MIN; i <= ID_STATUS_MAX; i++) + ImageList_AddIcon(hList, LoadSkinnedProtoIcon(szProto, StatusList[Index(i)].ID)); + ImageList_AddIcon(hList, LoadSkinnedIcon(SKINICON_OTHER_USERONLINE)); + } + } + + return hList; +} + +INT_PTR CALLBACK DlgProcSoundUIPage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static HANDLE hContact = NULL; + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + + hContact = (HANDLE)lParam; + char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST); + + ListView_SetImageList(hList, GetStatusIconsImgList(szProto), LVSIL_SMALL); + ListView_SetExtendedListViewStyleEx(hList, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP); + + RECT rc = {0}; + GetClientRect(hList, &rc); + + LV_COLUMN lvc = {0}; + lvc.mask = LVCF_WIDTH | LVCF_TEXT; + lvc.cx = STATUS_COLUMN; + lvc.pszText = TranslateT("Status"); + ListView_InsertColumn(hList, 0, &lvc); + + lvc.cx = rc.right - STATUS_COLUMN - GetSystemMetrics(SM_CXVSCROLL); + lvc.pszText = TranslateT("Sound for the status"); + ListView_InsertColumn(hList, 1, &lvc); + + if (szProto) + { + DBVARIANT dbv; + TCHAR buff[MAX_PATH]; + + for (int i = ID_STATUS_MAX; i >= ID_STATUS_MIN; i--) + { + int flags = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_2, 0); + if (flags == 0) + flags = PF2_ONLINE|PF2_INVISIBLE|PF2_SHORTAWAY|PF2_LONGAWAY|PF2_LIGHTDND|PF2_HEAVYDND|PF2_FREECHAT|PF2_OUTTOLUNCH|PF2_ONTHEPHONE; + + if ((flags & Proto_Status2Flag(i)) || i == ID_STATUS_OFFLINE) + { + LV_ITEM lvi = {0}; + lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; + lvi.iItem = 0; + lvi.iSubItem = 0; + lvi.iImage = Index(i); + lvi.lParam = (LPARAM)i; + lvi.pszText = TranslateTS(StatusList[Index(i)].lpzStandardText); + lvi.iItem = ListView_InsertItem(hList, &lvi); + + if (!DBGetContactSettingTString(hContact, MODULE, StatusList[Index(i)].lpzSkinSoundName, &dbv)) + { + _tcscpy(buff, dbv.ptszVal); + DBFreeVariant(&dbv); + } + else + _tcscpy(buff, TranslateT(DEFAULT_SOUND)); + + ListView_SetItemText(hList, lvi.iItem, 1, buff); + } + } + + LV_ITEM lvi = {0}; + lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; + lvi.iItem = 0; + lvi.iSubItem = 0; + lvi.iImage = Index(ID_STATUS_MAX) + 1; // additional icon + lvi.lParam = (LPARAM)ID_STATUS_FROMOFFLINE; + lvi.pszText = TranslateT("From offline"); + lvi.iItem = ListView_InsertItem(hList, &lvi); + + if (!DBGetContactSettingTString(hContact, MODULE, "UserFromOffline", &dbv)) + { + _tcscpy(buff, dbv.ptszVal); + DBFreeVariant(&dbv); + } + else + _tcscpy(buff, TranslateT(DEFAULT_SOUND)); + + ListView_SetItemText(hList, lvi.iItem, 1, buff); + } + + CheckDlgButton(hwndDlg, IDC_CHECK_NOTIFYSOUNDS, DBGetContactSettingByte(hContact, MODULE, "EnableSounds", 1)); + CheckDlgButton(hwndDlg, IDC_CHECK_NOTIFYPOPUPS, DBGetContactSettingByte(hContact, MODULE, "EnablePopups", 1)); + + ShowWindow(GetDlgItem(hwndDlg, IDC_INDSNDLIST), opt.UseIndSnd ? SW_SHOW : SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg, IDC_TEXT_ENABLE_IS), opt.UseIndSnd ? SW_HIDE : SW_SHOW); + ShowWindow(GetDlgItem(hwndDlg, IDC_CHANGE), opt.UseIndSnd ? SW_SHOW : SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg, IDC_PREVIEW), opt.UseIndSnd ? SW_SHOW : SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg, IDC_DELETE), opt.UseIndSnd ? SW_SHOW : SW_HIDE); + + return TRUE; + } + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_PREVIEW: + { + HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST); + if (ListView_GetSelectionMark(hList) != -1) + PreviewSound(hList); + break; + } + case IDC_CHANGE: + { + HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST); + int iSel = ListView_GetNextItem(GetDlgItem(hwndDlg, IDC_INDSNDLIST), -1, LVNI_SELECTED); + if (iSel != -1) + { + TCHAR stzFilePath[MAX_PATH]; + if (SelectSound(hwndDlg, stzFilePath) != NULL) + { + iSel = -1; + while ((iSel = ListView_GetNextItem(hList, iSel, LVNI_SELECTED)) != -1) + ListView_SetItemText(hList, iSel, 1, stzFilePath); + + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + break; + } + case IDC_DELETE: + { + HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST); + if (ListView_GetSelectionMark(hList) != -1) + { + if (RemoveSoundFromList(GetDlgItem(hwndDlg, IDC_INDSNDLIST))) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + break; + } + case IDC_CHECK_NOTIFYSOUNDS: + { + DBWriteContactSettingByte(hContact, MODULE, "EnableSounds", IsDlgButtonChecked(hwndDlg, IDC_CHECK_NOTIFYSOUNDS) ? 1 : 0); + break; + } + case IDC_CHECK_NOTIFYPOPUPS: + { + DBWriteContactSettingByte(hContact, MODULE, "EnablePopups", IsDlgButtonChecked(hwndDlg, IDC_CHECK_NOTIFYPOPUPS) ? 1 : 0); + break; + } + } + break; + } + case WM_NOTIFY: + { + LPNMHDR pParam = (LPNMHDR)lParam; + if (pParam->code == PSN_APPLY) + { + TCHAR buff[MAX_PATH]; + HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST); + + LVITEM lvi = {0}; + lvi.mask = LVIF_PARAM; + //Cycle through the list reading the text associated to each status. + for (lvi.iItem = ListView_GetItemCount(hList) - 1; lvi.iItem >= 0; lvi.iItem--) + { + ListView_GetItem(hList, &lvi); + ListView_GetItemText(hList, lvi.iItem, 1, buff, SIZEOF(buff)); + + if (!_tcscmp(buff, TranslateT(DEFAULT_SOUND))) + { + if (lvi.lParam == ID_STATUS_FROMOFFLINE) + DBDeleteContactSetting(hContact, MODULE, "UserFromOffline"); + else + DBDeleteContactSetting(hContact, MODULE, StatusList[Index(lvi.lParam)].lpzSkinSoundName); + } + else + { + TCHAR stzSoundPath[MAX_PATH] = { 0 }; + CallService(MS_UTILS_PATHTORELATIVET, (WPARAM)buff, (LPARAM)stzSoundPath); + if (lvi.lParam == ID_STATUS_FROMOFFLINE) + DBWriteContactSettingTString(hContact, MODULE, "UserFromOffline", stzSoundPath); + else + DBWriteContactSettingTString(hContact, MODULE, StatusList[Index(lvi.lParam)].lpzSkinSoundName, stzSoundPath); + } + } + + return TRUE; + } + + int hlpControlID = (int)wParam; + switch (hlpControlID) + { + case IDC_INDSNDLIST: + { + if (pParam->code == NM_DBLCLK) + { + TCHAR stzFilePath[MAX_PATH]; + if (SelectSound(hwndDlg, stzFilePath) != NULL) + { + int iSel = -1; + HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST); + while ((iSel = ListView_GetNextItem(hList, iSel, LVNI_SELECTED)) != -1) + ListView_SetItemText(hList, iSel, 1, stzFilePath); + + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + return TRUE; + } + else if (pParam->code == LVN_KEYDOWN) + { + LPNMLVKEYDOWN pnkd = (LPNMLVKEYDOWN)lParam; + if (pnkd->wVKey == VK_DELETE) + RemoveSoundFromList(GetDlgItem(hwndDlg, IDC_INDSNDLIST)); + } + + break; + } + } + break; + } + } + return FALSE; +} + +int UserInfoInitialise(WPARAM wParam, LPARAM lParam) +{ + if (lParam == NULL) + return 0; + + OPTIONSDIALOGPAGE odp = {0}; + odp.cbSize = sizeof(odp); + odp.position = 100000000; + odp.hInstance = hInst; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_SOUNDS); + odp.pszTitle = LPGEN("Status Notify"); + odp.pfnDlgProc = DlgProcSoundUIPage; + UserInfo_AddPage(wParam, &odp); + + return 0; +} + +void ResetListOptions(HWND hwndList) +{ + SendMessage(hwndList, CLM_SETBKBITMAP, 0, (LPARAM)NULL); + SendMessage(hwndList, CLM_SETBKCOLOR, GetSysColor(COLOR_WINDOW), 0); + SendMessage(hwndList, CLM_SETGREYOUTFLAGS, 0, 0); + SendMessage(hwndList, CLM_SETLEFTMARGIN, 4, 0); + SendMessage(hwndList, CLM_SETINDENT, 10, 0); + + for (int i = 0; i <= FONTID_MAX; i++) + SendMessage(hwndList, CLM_SETTEXTCOLOR, i, GetSysColor(COLOR_WINDOWTEXT)); + + SetWindowLongPtr(hwndList, GWL_STYLE, GetWindowLongPtr(hwndList,GWL_STYLE) | CLS_SHOWHIDDEN); +} + +__inline int GetExtraImage(HWND hwndList, HANDLE hItem, int column) +{ + return SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(column, 0)); +} + +__inline void SetExtraImage(HWND hwndList, HANDLE hItem, int column, int imageID) +{ + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(column, imageID)); +} + +void SetAllContactsIcons(HWND hwndList) +{ + BYTE EnableSounds, EnablePopups, EnableXStatus, EnableLogging; + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact) + { + HANDLE hItem = (HANDLE)SendMessage(hwndList, CLM_FINDCONTACT, (WPARAM)hContact, 0); + if (hItem) + { + char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0); + if (szProto) + { + EnableSounds = DBGetContactSettingByte(hContact, MODULE, "EnableSounds", 1); + EnablePopups = DBGetContactSettingByte(hContact, MODULE, "EnablePopups", 1); + EnableXStatus = DBGetContactSettingByte(hContact, MODULE, "EnableXStatusNotify", 1); + EnableLogging = DBGetContactSettingByte(hContact, MODULE, "EnableLogging", 1); + } + else + EnableSounds = EnablePopups = EnableXStatus = EnableLogging = 0; + + SetExtraImage(hwndList, hItem, EXTRA_IMAGE_SOUND, EnableSounds ? EXTRA_IMAGE_SOUND : EXTRA_IMAGE_DOT); + SetExtraImage(hwndList, hItem, EXTRA_IMAGE_POPUP, EnablePopups? EXTRA_IMAGE_POPUP : EXTRA_IMAGE_DOT); + SetExtraImage(hwndList, hItem, EXTRA_IMAGE_XSTATUS, EnableXStatus ? EXTRA_IMAGE_XSTATUS : EXTRA_IMAGE_DOT); + SetExtraImage(hwndList, hItem, EXTRA_IMAGE_LOGGING, EnableLogging ? EXTRA_IMAGE_LOGGING : EXTRA_IMAGE_DOT); + SetExtraImage(hwndList, hItem, EXTRA_IMAGE_DISABLEALL, EXTRA_IMAGE_DISABLEALL); + SetExtraImage(hwndList, hItem, EXTRA_IMAGE_ENABLEALL, EXTRA_IMAGE_ENABLEALL); + } + + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } +} + +void SetGroupsIcons(HWND hwndList, HANDLE hFirstItem, HANDLE hParentItem, int *groupChildCount) +{ + int iconOn[6] = {1,1,1,1,1,1}; + int childCount[6] = {0}; + HANDLE hItem; + + int typeOfFirst = SendMessage(hwndList, CLM_GETITEMTYPE, (WPARAM)hFirstItem, 0); + if (typeOfFirst == CLCIT_GROUP) + hItem = hFirstItem; + else + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTGROUP, (LPARAM)hFirstItem); + + while (hItem) + { + HANDLE hChildItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem); + if (hChildItem) + SetGroupsIcons(hwndList, hChildItem, hItem, childCount); + + for (int i = 0; i < SIZEOF(iconOn); i++) + { + if (iconOn[i] && GetExtraImage(hwndList, hItem, i) == EXTRA_IMAGE_DOT) + iconOn[i] = 0; + } + + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTGROUP, (LPARAM)hItem); + } + + //check contacts + if (typeOfFirst == CLCIT_CONTACT) + hItem = hFirstItem; + else + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hFirstItem); + + while(hItem) + { + for (int i = 0; i < SIZEOF(iconOn); i++) + { + int image = GetExtraImage(hwndList, hItem, i); + if (iconOn[i] && image == EXTRA_IMAGE_DOT) + iconOn[i] = 0; + + if (image != EXTRA_IMAGE_BLANK) + childCount[i]++; + } + + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hItem); + } + + //set icons + for(int i = 0; i < SIZEOF(iconOn); i++) + { + SetExtraImage(hwndList, hParentItem, i, childCount[i] ? (iconOn[i] ? i : EXTRA_IMAGE_DOT) : EXTRA_IMAGE_BLANK); + if (groupChildCount) + groupChildCount[i] += childCount[i]; + } +} + +void SetAllChildrenIcons(HWND hwndList, HANDLE hFirstItem, int column, int image) +{ + HANDLE hItem, hChildItem; + + int typeOfFirst = SendMessage(hwndList, CLM_GETITEMTYPE, (WPARAM)hFirstItem, 0); + if (typeOfFirst == CLCIT_GROUP) + hItem = hFirstItem; + else + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTGROUP, (LPARAM)hFirstItem); + + while(hItem) + { + hChildItem = (HANDLE)SendMessage(hwndList ,CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem); + if (hChildItem) + SetAllChildrenIcons(hwndList, hChildItem, column, image); + + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTGROUP, (LPARAM)hItem); + } + + if (typeOfFirst == CLCIT_CONTACT) + hItem = hFirstItem; + else + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hFirstItem); + + while(hItem) + { + int oldIcon = GetExtraImage(hwndList, hItem, column); + if (oldIcon != EXTRA_IMAGE_BLANK && oldIcon != image) + SetExtraImage(hwndList, hItem, column, image); + + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hItem); + } +} + +INT_PTR CALLBACK DlgProcFiltering(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static HANDLE hItemAll; + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + + HIMAGELIST hImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16 | ILC_MASK, 3, 3); + + ImageList_AddIcon(hImageList, LoadIcon(hInst,MAKEINTRESOURCE(IDI_SOUND))); + SendDlgItemMessage(hwndDlg,IDC_SOUNDICON,STM_SETICON, (WPARAM)ImageList_GetIcon(hImageList, EXTRA_IMAGE_SOUND, ILD_NORMAL), 0); + ImageList_AddIcon(hImageList, LoadIcon(hInst, MAKEINTRESOURCE(IDI_POPUP))); + SendDlgItemMessage(hwndDlg, IDC_POPUPICON, STM_SETICON, (WPARAM)ImageList_GetIcon(hImageList, EXTRA_IMAGE_POPUP, ILD_NORMAL), 0); + ImageList_AddIcon(hImageList, LoadIcon(hInst,MAKEINTRESOURCE(IDI_XSTATUS))); + SendDlgItemMessage(hwndDlg, IDC_XSTATUSICON, STM_SETICON, (WPARAM)ImageList_GetIcon(hImageList, EXTRA_IMAGE_XSTATUS, ILD_NORMAL), 0); + ImageList_AddIcon(hImageList, LoadIcon(hInst,MAKEINTRESOURCE(IDI_LOGGING))); + SendDlgItemMessage(hwndDlg, IDC_LOGGINGICON, STM_SETICON, (WPARAM)ImageList_GetIcon(hImageList, EXTRA_IMAGE_LOGGING, ILD_NORMAL), 0); + ImageList_AddIcon(hImageList, LoadIcon(hInst,MAKEINTRESOURCE(IDI_DISABLEALL))); + SendDlgItemMessage(hwndDlg, IDC_DISABLEALLICON, STM_SETICON, (WPARAM)ImageList_GetIcon(hImageList, EXTRA_IMAGE_DISABLEALL, ILD_NORMAL), 0); + ImageList_AddIcon(hImageList, LoadIcon(hInst,MAKEINTRESOURCE(IDI_ENABLEALL))); + SendDlgItemMessage(hwndDlg, IDC_ENABLEALLICON, STM_SETICON, (WPARAM)ImageList_GetIcon(hImageList, EXTRA_IMAGE_ENABLEALL, ILD_NORMAL), 0); + + ImageList_AddIcon(hImageList, LoadSkinnedIcon(SKINICON_OTHER_SMALLDOT)); + + SendDlgItemMessage(hwndDlg, IDC_INDSNDLIST, CLM_SETEXTRAIMAGELIST, 0, (LPARAM)hImageList); + SendDlgItemMessage(hwndDlg, IDC_INDSNDLIST, CLM_SETEXTRACOLUMNS, 6, 0); + + HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST); + ResetListOptions(hList); + + CLCINFOITEM cii = {0}; + cii.cbSize = sizeof(cii); + cii.flags = CLCIIF_GROUPFONT; + cii.pszText = TranslateT("** All contacts **"); + hItemAll = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_INDSNDLIST, CLM_ADDINFOITEM, 0, (LPARAM)&cii); + + return TRUE; + } + case WM_SETFOCUS: + { + SetFocus(GetDlgItem(hwndDlg, IDC_INDSNDLIST)); + break; + } + case WM_NOTIFY: + { + HWND hList = GetDlgItem(hwndDlg, IDC_INDSNDLIST); + switch(((LPNMHDR)lParam)->idFrom) + { + case IDC_INDSNDLIST: + switch (((LPNMHDR)lParam)->code) + { + case CLN_NEWCONTACT: + case CLN_LISTREBUILT: + SetAllContactsIcons(hList); + //fall through + case CLN_CONTACTMOVED: + SetGroupsIcons(hList, (HANDLE)SendMessage(hList, CLM_GETNEXTITEM, CLGN_ROOT, 0), hItemAll, NULL); + break; + case CLN_OPTIONSCHANGED: + ResetListOptions(hList); + break; + case NM_CLICK: + { + NMCLISTCONTROL *nm = (NMCLISTCONTROL*)lParam; + DWORD hitFlags; + + // Make sure we have an extra column + if (nm->iColumn == -1) break; + + // Find clicked item + HANDLE hItem = (HANDLE)SendMessage(hList, CLM_HITTEST, (WPARAM)&hitFlags, MAKELPARAM(nm->pt.x, nm->pt.y)); + if (hItem == NULL) break; + if (!(hitFlags & CLCHT_ONITEMEXTRA)) break; + + int itemType = SendMessage(hList, CLM_GETITEMTYPE, (WPARAM)hItem, 0); + + // Get image in clicked column + int image = GetExtraImage(hList, hItem, nm->iColumn); + if (image == EXTRA_IMAGE_DOT) + image = nm->iColumn; + else if (image >= EXTRA_IMAGE_SOUND && image <= EXTRA_IMAGE_LOGGING) + image = EXTRA_IMAGE_DOT; + + // Get item type (contact, group, etc...) + if (itemType == CLCIT_CONTACT) + { + if (image == EXTRA_IMAGE_DISABLEALL) + { + for (int i = 0; i < 4; i++) + SetExtraImage(hList, hItem, i, EXTRA_IMAGE_DOT); + } + else if (image == EXTRA_IMAGE_ENABLEALL) + { + for (int i = 0; i < 4; i++) + SetExtraImage(hList, hItem, i, i); + } + else + { + SetExtraImage(hList, hItem, nm->iColumn, image); + } + } + else if (itemType == CLCIT_INFO || itemType == CLCIT_GROUP) + { + if (itemType == CLCIT_GROUP) + hItem = (HANDLE)SendMessage(hList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem); + + if (hItem) + { + if (image == EXTRA_IMAGE_DISABLEALL) + { + for (int i = 0; i < 4; i++) + SetAllChildrenIcons(hList, hItem, i, EXTRA_IMAGE_DOT); + } + else if (image == EXTRA_IMAGE_ENABLEALL) + { + for (int i = 0; i < 4; i++) + SetAllChildrenIcons(hList, hItem, i, i); + } + else + { + SetAllChildrenIcons(hList, hItem, nm->iColumn, image); + } + } + } + + // Update the all/none icons + SetGroupsIcons(hList, (HANDLE)SendMessage(hList, CLM_GETNEXTITEM, CLGN_ROOT, 0), hItemAll, NULL); + // Activate Apply button + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + } + } + break; + case 0: + switch (((LPNMHDR)lParam)->code) + { + case PSN_APPLY: + { + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + do + { + HANDLE hItem = (HANDLE)SendMessage(hList, CLM_FINDCONTACT, (WPARAM)hContact, 0); + if (hItem) + { + if (GetExtraImage(hList, hItem, EXTRA_IMAGE_SOUND) == EXTRA_IMAGE_SOUND) + DBDeleteContactSetting(hContact, MODULE, "EnableSounds"); + else + DBWriteContactSettingByte(hContact, MODULE, "EnableSounds", 0); + + if (GetExtraImage(hList, hItem, EXTRA_IMAGE_POPUP) == EXTRA_IMAGE_POPUP) + DBDeleteContactSetting(hContact, MODULE, "EnablePopups"); + else + DBWriteContactSettingByte(hContact, MODULE, "EnablePopups", 0); + + if(GetExtraImage(hList, hItem, EXTRA_IMAGE_XSTATUS) == EXTRA_IMAGE_XSTATUS) + DBDeleteContactSetting(hContact, MODULE, "EnableXStatusNotify"); + else + DBWriteContactSettingByte(hContact, MODULE, "EnableXStatusNotify", 0); + + if (GetExtraImage(hList, hItem, EXTRA_IMAGE_LOGGING) == EXTRA_IMAGE_LOGGING) + DBDeleteContactSetting(hContact, MODULE, "EnableLogging"); + else + DBWriteContactSettingByte(hContact, MODULE, "EnableLogging", 0); + + } + } while(hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0)); + + return TRUE; + } + } + break; + } + break; + } + case WM_DESTROY: + { + HIMAGELIST hImageList = (HIMAGELIST)SendMessage(GetDlgItem(hwndDlg, IDC_INDSNDLIST), CLM_GETEXTRAIMAGELIST, 0, 0); + for (int i = 0; i < ImageList_GetImageCount(hImageList); i++) + DestroyIcon(ImageList_GetIcon(hImageList, i, ILD_NORMAL)); + ImageList_Destroy(hImageList); + break; + } + } + return FALSE; +} + diff --git a/plugins/NewXstatusNotify/src/indsnd.h b/plugins/NewXstatusNotify/src/indsnd.h new file mode 100644 index 0000000000..c4dde34ea1 --- /dev/null +++ b/plugins/NewXstatusNotify/src/indsnd.h @@ -0,0 +1,41 @@ +/* + NewXstatusNotify YM - Plugin for Miranda IM + Copyright (c) 2001-2004 Luca Santarelli + Copyright (c) 2005-2007 Vasilich + Copyright (c) 2007-2011 yaho + + 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 +*/ + +#ifndef INDSND_H +#define INDSND_H + +#define EXTRA_IMAGE_SOUND 0 +#define EXTRA_IMAGE_POPUP 1 +#define EXTRA_IMAGE_XSTATUS 2 +#define EXTRA_IMAGE_LOGGING 3 +#define EXTRA_IMAGE_DISABLEALL 4 +#define EXTRA_IMAGE_ENABLEALL 5 +#define EXTRA_IMAGE_DOT 6 +#define EXTRA_IMAGE_BLANK 0xFF + +#define STATUS_COLUMN 110 + +#define DEFAULT_SOUND "(default sound)" + +int UserInfoInitialise(WPARAM wParam, LPARAM lParam); +INT_PTR CALLBACK DlgProcFiltering(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +#endif \ No newline at end of file diff --git a/plugins/NewXstatusNotify/src/main.cpp b/plugins/NewXstatusNotify/src/main.cpp new file mode 100644 index 0000000000..82370f15f5 --- /dev/null +++ b/plugins/NewXstatusNotify/src/main.cpp @@ -0,0 +1,1369 @@ +/* + NewXstatusNotify YM - Plugin for Miranda IM + Copyright (c) 2001-2004 Luca Santarelli + Copyright (c) 2005-2007 Vasilich + Copyright (c) 2007-2011 yaho + + 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 "common.h" +#include "indsnd.h" +#include "options.h" +#include "popup.h" +#include "utils.h" +#include "version.h" +#include "xstatus.h" + +HINSTANCE hInst; + + +LIST eventList( 10 ); +LIST xstatusList( 10 ); + +HANDLE hStatusModeChange, hServiceMenu, hHookContactStatusChanged, hEnableDisableMenu; +HANDLE hToolbarButton; + +char szMetaModuleName[256] = {0}; +STATUS StatusList[STATUS_COUNT]; +DWORD LoadTime = 0; +int hLangpack; + +extern OPTIONS opt; + +PLUGININFOEX pluginInfoEx = { + sizeof(PLUGININFOEX), + "NewXstatusNotify YM", + __VERSION_DWORD, + "Notifies you when a contact changes his/her (X)status or status message.", + "Luca Santarelli, Vasilich, yaho", + "yaho@miranda-easy.net", + "© 2001-2004 Luca Santarelli, 2005-2007 Vasilich, 2007-2011 yaho", + "http://miranda-easy.net/mods.php", + UNICODE_AWARE, + MIID_NXSN +}; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + hInst = hinstDLL; + DisableThreadLibraryCalls(hInst); + return TRUE; +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfoEx; +} + +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_USERONLINE, MIID_LAST}; + +BYTE GetGender(HANDLE hContact) +{ + char *szProto =(char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (szProto) + { + switch (DBGetContactSettingByte(hContact, szProto, "Gender", 0)) + { + case 'M': case 'm': + return GENDER_MALE; + case 'F': case 'f': + return GENDER_FEMALE; + default: + return GENDER_UNSPECIFIED; + } + } + + return GENDER_UNSPECIFIED; +} + +HANDLE GetIconHandle(char *szIcon) +{ + char szSettingName[64]; + mir_snprintf(szSettingName, sizeof(szSettingName), "%s_%s", MODULE, szIcon); + return (HANDLE)CallService(MS_SKIN2_GETICONHANDLE, 0, (LPARAM)szSettingName); +} + +__inline void AddXSC(XSTATUSCHANGE *xsc) +{ + xstatusList.insert(xsc); +} + +__inline void RemoveXSC(XSTATUSCHANGE *xsc) +{ + int id = xstatusList.getIndex(xsc); + if (id != -1) + xstatusList.remove(id); +} + +XSTATUSCHANGE *FindXSC(HANDLE hContact) +{ + for (int i = 0; i < xstatusList.getCount(); i++) { + XSTATUSCHANGE* xsc = xstatusList[i]; + if (xsc->hContact == hContact) + return xsc; + } + + return NULL; +} + +XSTATUSCHANGE *FindAndRemoveXSC(HANDLE hContact) +{ + XSTATUSCHANGE *result = FindXSC(hContact); + if (result) RemoveXSC(result); + return result; +} + +bool IsNewExtraStatus(HANDLE hContact, char *szSetting, TCHAR *newStatusTitle) +{ + DBVARIANT dbv; + bool result = true; + + if (!DBGetContactSettingTString(hContact, MODULE, szSetting, &dbv)) + { + result = _tcscmp(newStatusTitle, dbv.ptszVal) ? true : false; + DBFreeVariant(&dbv); + } + + return result; +} + +int ProcessExtraStatus(DBCONTACTWRITESETTING *cws, HANDLE hContact) +{ + XSTATUSCHANGE *xsc; + char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + + if (ProtoServiceExists(szProto, JS_PARSE_XMPP_URI)) + { + if (cws->value.type == DBVT_DELETED) + return 0; + + if (hContact == NULL) + return 0; + + if (strstr(cws->szSetting, "/mood/") || strstr(cws->szSetting, "/activity/")) // Jabber mood or activity changed + { + char *szSetting; + int type; + + if (strstr(cws->szSetting, "/mood/")) + { + type = TYPE_JABBER_MOOD; + szSetting = "LastJabberMood"; + } + else + { + type = TYPE_JABBER_ACTIVITY; + szSetting = "LastJabberActivity"; + } + + if (strstr(cws->szSetting, "title")) + { + TCHAR *stzValue = db2t(&cws->value); + if (stzValue) + { + if (!IsNewExtraStatus(hContact, szSetting, stzValue)) + { + mir_free(stzValue); + return 0; + } + + xsc = NewXSC(hContact, szProto, type, NOTIFY_NEW_XSTATUS, stzValue, NULL); + DBWriteContactSettingTString(hContact, MODULE, szSetting, stzValue); + } + else + { + xsc = NewXSC(hContact, szProto, type, NOTIFY_REMOVE, NULL, NULL); + DBWriteContactSettingTString(hContact, MODULE, szSetting, _T("")); + } + + AddXSC(xsc); + if (xsc != NULL) + { + ExtraStatusChanged(xsc); + FreeXSC(xsc); + } + } + else if (strstr(cws->szSetting, "text")) + { + xsc = FindAndRemoveXSC(hContact); + TCHAR *stzValue = db2t(&cws->value); + if (stzValue) + { + if (xsc != NULL) + xsc->stzText = stzValue; + else + xsc = NewXSC(hContact, szProto, type, NOTIFY_NEW_MESSAGE, NULL, stzValue); + } + + if (xsc != NULL) + { + ExtraStatusChanged(xsc); + FreeXSC(xsc); + } + } + + return 1; + } + } + else if (strstr(cws->szSetting, "XStatus") || strcmp(cws->szSetting, "StatusNote") == 0) + { + if (strcmp(cws->szSetting, "XStatusName") == 0) + { + xsc = FindAndRemoveXSC(hContact); + if (xsc) FreeXSC(xsc); + + if (cws->value.type == DBVT_DELETED) + { + xsc = NewXSC(hContact, szProto, TYPE_ICQ_XSTATUS, NOTIFY_REMOVE, NULL, NULL); + } + else + { + TCHAR *stzValue = db2t(&cws->value); + if (!stzValue) + { + TCHAR buff[64]; + int statusID = DBGetContactSettingByte(hContact, szProto, "XStatusId", -1); + GetDefaultXstatusName(statusID, szProto, buff, SIZEOF(buff)); + stzValue = mir_tstrdup(buff); + } + + xsc = NewXSC(hContact, szProto, TYPE_ICQ_XSTATUS, NOTIFY_NEW_XSTATUS, stzValue, NULL); + } + + AddXSC(xsc); + if (xsc != NULL) + { + ExtraStatusChanged(xsc); + FreeXSC(xsc); + } + } + else if (strstr(cws->szSetting, "XStatusMsg") || strcmp(cws->szSetting, "StatusNote") == 0) + { + if (cws->value.type == DBVT_DELETED) + return 1; + + TCHAR *stzValue = db2t(&cws->value); + xsc = FindXSC(hContact); + if (xsc) + { + if (xsc->action == NOTIFY_NEW_XSTATUS) + xsc->stzText = stzValue; + } + else + { + xsc = NewXSC(hContact, szProto, TYPE_ICQ_XSTATUS, NOTIFY_NEW_MESSAGE, NULL, stzValue); + AddXSC(xsc); + } + if (xsc != NULL) + { + ExtraStatusChanged(xsc); + FreeXSC(xsc); + } + } + + return 1; + } + + return 0; +} + +static int __inline CheckStr(char *str, int not_empty, int empty) { + if (str == NULL || str[0] == '\0') + return empty; + else + return not_empty; +} + + +static int __inline CheckStrW(WCHAR *str, int not_empty, int empty) { + if (str == NULL || str[0] == L'\0') + return empty; + else + return not_empty; +} + + +WCHAR *mir_dupToUnicodeEx(char *ptr, UINT CodePage) +{ + if (ptr == NULL) + return NULL; + + size_t size = strlen(ptr) + 1; + WCHAR *tmp = (WCHAR *) mir_alloc(size * sizeof(WCHAR)); + + MultiByteToWideChar(CodePage, 0, ptr, -1, tmp, (int)size * sizeof(WCHAR)); + return tmp; +} + +static int CompareStatusMsg(STATUSMSGINFO *smi, DBCONTACTWRITESETTING *cws_new) { + DBVARIANT dbv_old; + int ret; + + switch (cws_new->value.type) + { + case DBVT_DELETED: + smi->newstatusmsg = NULL; + break; + case DBVT_ASCIIZ: + + smi->newstatusmsg = (CheckStr(cws_new->value.pszVal, 0, 1) ? NULL : mir_dupToUnicodeEx(cws_new->value.pszVal, CP_ACP)); + break; + case DBVT_UTF8: + smi->newstatusmsg = (CheckStr(cws_new->value.pszVal, 0, 1) ? NULL : mir_dupToUnicodeEx(cws_new->value.pszVal, CP_UTF8)); + break; + case DBVT_WCHAR: + smi->newstatusmsg = (CheckStrW(cws_new->value.pwszVal, 0, 1) ? NULL : mir_wstrdup(cws_new->value.pwszVal)); + + break; + default: + smi->newstatusmsg = NULL; + break; + } + + if (! + + DBGetContactSettingW(smi->hContact, "UserOnline", "OldStatusMsg", &dbv_old) + + ) + { + switch (dbv_old.type) + { + case DBVT_ASCIIZ: + + smi->oldstatusmsg = (CheckStr(dbv_old.pszVal, 0, 1) ? NULL : mir_dupToUnicodeEx(dbv_old.pszVal, CP_ACP)); + break; + case DBVT_UTF8: + smi->oldstatusmsg = (CheckStr(dbv_old.pszVal, 0, 1) ? NULL : mir_dupToUnicodeEx(dbv_old.pszVal, CP_UTF8)); + break; + case DBVT_WCHAR: + smi->oldstatusmsg = (CheckStrW(dbv_old.pwszVal, 0, 1) ? NULL : mir_wstrdup(dbv_old.pwszVal)); + + break; + default: + smi->oldstatusmsg = NULL; + break; + } + + if (cws_new->value.type == DBVT_DELETED) + if ( + + dbv_old.type == DBVT_WCHAR) + ret = CheckStrW(dbv_old.pwszVal, 2, 0); + else if (dbv_old.type == DBVT_UTF8 || + + dbv_old.type == DBVT_ASCIIZ) + ret = CheckStr(dbv_old.pszVal, 2, 0); + else + ret = 2; + else if (dbv_old.type != cws_new->value.type) + + ret = (lstrcmpW(smi->newstatusmsg, smi->oldstatusmsg) ? CheckStrW(smi->newstatusmsg, 1, 2) : 0); + + else if (dbv_old.type == DBVT_ASCIIZ) + ret = (lstrcmpA(cws_new->value.pszVal, dbv_old.pszVal) ? CheckStr(cws_new->value.pszVal, 1, 2) : 0); + + else if (dbv_old.type == DBVT_UTF8) + ret = (lstrcmpA(cws_new->value.pszVal, dbv_old.pszVal) ? CheckStr(cws_new->value.pszVal, 1, 2) : 0); + else if (dbv_old.type == DBVT_WCHAR) + ret = (lstrcmpW(cws_new->value.pwszVal, dbv_old.pwszVal) ? CheckStrW(cws_new->value.pwszVal, 1, 2) : 0); + + DBFreeVariant(&dbv_old); + } + else + { + if (cws_new->value.type == DBVT_DELETED) + ret = 0; + else if ( + + cws_new->value.type == DBVT_WCHAR) + ret = CheckStrW(cws_new->value.pwszVal, 1, 0); + else if (cws_new->value.type == DBVT_UTF8 || + + cws_new->value.type == DBVT_ASCIIZ) + ret = CheckStr(cws_new->value.pszVal, 1, 0); + else + ret = 1; + + smi->oldstatusmsg = NULL; + } + + return ret; +} + +BOOL FreeSmiStr(STATUSMSGINFO *smi) +{ + mir_free(smi->newstatusmsg); + mir_free(smi->oldstatusmsg); + return 0; +} + +// return TRUE if timeout is over +BOOL TimeoutCheck() +{ + if (GetTickCount() - LoadTime > TMR_CONNECTIONTIMEOUT) + return TRUE; + return FALSE; +} + +TCHAR* AddCR(const TCHAR *statusmsg) { + TCHAR *tmp; + const TCHAR *found; + int i = 0, len = lstrlen(statusmsg), j; + tmp = (TCHAR*)mir_alloc(1024 * sizeof(TCHAR)); + *tmp = _T('\0'); + while((found = _tcsstr((statusmsg + i), _T("\n"))) != NULL && _tcslen(tmp) + 1 < 1024){ + j = (int)(found - statusmsg); + if(lstrlen(tmp) + j - i + 2 < 1024){ + tmp = _tcsncat(tmp, statusmsg + i, j - i); + } + else { + break; + } + if(j == 0 || *(statusmsg + j - 1) != _T('\r')) { + tmp = lstrcat(tmp, _T("\r")); + } + tmp = lstrcat(tmp, _T("\n")); + i = j + 1; + } + if(lstrlen(tmp) + len - i + 1 < 1024){ + tmp = lstrcat(tmp, statusmsg + i); + } + + return tmp; +} + +TCHAR* GetStr(STATUSMSGINFO *n, const TCHAR *tmplt) { + TCHAR tmp[1024]; + TCHAR *str; + int i; + int len; + + if (tmplt == NULL || tmplt[0] == _T('\0')) + return NULL; + + str = (TCHAR*)mir_alloc(2048 * sizeof(TCHAR)); + str[0] = _T('\0'); + len = lstrlen(tmplt); + + for (i = 0; i < len; i++) + { + tmp[0] = _T('\0'); + + if (tmplt[i] == _T('%')) + { + i++; + switch (tmplt[i]) + { + case 'n': + if (n->compare == 2 || _tcscmp(n->newstatusmsg, TranslateT("")) == 0) + lstrcpyn(tmp, TranslateT(""), SIZEOF(tmp)); + else { + TCHAR *_tmp = AddCR(n->newstatusmsg); + lstrcpyn(tmp, _tmp, SIZEOF(tmp)); + mir_free(_tmp); + } + break; + case 'o': + if (n->oldstatusmsg == NULL || n->oldstatusmsg[0] == _T('\0') || _tcscmp(n->oldstatusmsg, TranslateT("")) == 0) + lstrcpyn(tmp, TranslateT(""), SIZEOF(tmp)); + else { + TCHAR *_tmp = AddCR(n->oldstatusmsg); + lstrcpyn(tmp, _tmp, SIZEOF(tmp)); + mir_free(_tmp); + } + break; + case 'c': + if (n->cust == NULL || n->cust[0] == _T('\0')) lstrcpyn(tmp, TranslateT("Contact"), SIZEOF(tmp)); + else lstrcpyn(tmp, n->cust, SIZEOF(tmp)); + break; + default: + //lstrcpyn(tmp, _T("%"), TMPMAX); + i--; + tmp[0] = tmplt[i]; tmp[1] = _T('\0'); + break; + } + } + else if (tmplt[i] == _T('\\')) + { + i++; + switch (tmplt[i]) + { + case 'n': + //_tcscat_s(tmp, TMPMAX, _T("\r\n")); + tmp[0] = _T('\r'); tmp[1] = _T('\n'); tmp[2] = _T('\0'); + break; + case 't': + //_tcscat_s(tmp, TMPMAX, _T("\t")); + tmp[0] = _T('\t'); tmp[1] = _T('\0'); + break; + default: + //lstrcpyn(tmp, _T("\\"), TMPMAX); + i--; + tmp[0] = tmplt[i]; tmp[1] = _T('\0'); + break; + } + } + else + { + tmp[0] = tmplt[i]; tmp[1] = _T('\0'); + } + + if (tmp[0] != _T('\0')) + { + if (lstrlen(tmp) + lstrlen(str) < 2044) + { + lstrcat(str, tmp); + } + else + { + lstrcat(str, _T("...")); + break; + } + } + } + + return str; +} + +int ProcessStatus(DBCONTACTWRITESETTING *cws, HANDLE hContact) +{ + if (strcmp(cws->szSetting, "Status") == 0) + { + WORD newStatus = cws->value.wVal; + if (newStatus < ID_STATUS_MIN || newStatus > ID_STATUS_MAX) + return 0; + + DBVARIANT dbv; + if (!DBGetContactSettingString(hContact, "Protocol", "p", &dbv)) + { + BOOL temp = strcmp(cws->szModule, dbv.pszVal) != 0; + DBFreeVariant(&dbv); + if (temp) return 0; + } + + WORD oldStatus = DBGetContactSettingRangedWord(hContact, "UserOnline", "OldStatus", ID_STATUS_OFFLINE, ID_STATUS_MIN, ID_STATUS_MAX); + if (oldStatus == newStatus) + return 0; + + //If we get here, the two stauses differ, so we can proceed. + DBWriteContactSettingWord(hContact, "UserOnline", "OldStatus", newStatus); + + //If *Miranda* ignores the UserOnline event, exit! + if (CallService(MS_IGNORE_ISIGNORED, (WPARAM)hContact, IGNOREEVENT_USERONLINE)) + return 0; + + //If we get here, we have to notify the Hooks. + NotifyEventHooks(hHookContactStatusChanged, (WPARAM)hContact, (LPARAM)MAKELPARAM(oldStatus, newStatus)); + return 1; + } + + if (!lstrcmpA(cws->szModule, "CList") && !lstrcmpA(cws->szSetting, "StatusMsg")) + { + STATUSMSGINFO smi; + BOOL retem = TRUE, rettime = TRUE; + + DBVARIANT dbv; + if ( !DBGetContactSettingString(hContact, "Protocol", "p", &dbv)) { + char dbSetting[128]; + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_enabled", dbv.pszVal); + db_free(&dbv); + + if (!DBGetContactSettingByte(NULL, MODULE, dbSetting, 1)) + return 0; + } + smi.proto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + + //don't show popup when mradio connecting and disconnecting + if (_stricmp(smi.proto, "mRadio") == 0 && !cws->value.type == DBVT_DELETED) + { + TCHAR buf[MAX_PATH]; + mir_sntprintf(buf, SIZEOF(buf), _T(" (%s)"), TranslateT("connecting")); + char* pszUtf = mir_utf8encodeT(buf); + mir_sntprintf(buf, SIZEOF(buf), _T(" (%s)"), TranslateT("aborting")); + char* pszUtf2 = mir_utf8encodeT(buf); + mir_sntprintf(buf, SIZEOF(buf), _T(" (%s)"), TranslateT("playing")); + char* pszUtf3 = mir_utf8encodeT(buf); + if (_stricmp(cws->value.pszVal, pszUtf) == 0 || _stricmp(cws->value.pszVal, pszUtf2) == 0 || _stricmp(cws->value.pszVal, pszUtf3) == 0) + { + mir_free(pszUtf); + mir_free(pszUtf2); + mir_free(pszUtf3); + return 0; + } + else + { + mir_free(pszUtf); + mir_free(pszUtf2); + mir_free(pszUtf3); + } + } + + if (smi.proto != NULL && CallProtoService(smi.proto, PS_GETSTATUS, 0, 0) != ID_STATUS_OFFLINE) + { + smi.hContact = hContact; + smi.compare = CompareStatusMsg(&smi, cws); + if ((smi.compare == 0) || (opt.IgnoreEmpty && (smi.compare == 2))) + return FreeSmiStr(&smi); + + if (cws->value.type == DBVT_DELETED) + { + DBDeleteContactSetting(smi.hContact, "UserOnline", "OldStatusMsg"); + } + else + { + DBCONTACTWRITESETTING cws_old; + cws_old.szModule = "UserOnline"; + cws_old.szSetting = "OldStatusMsg"; + cws_old.value = cws->value; + CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)smi.hContact, (LPARAM)&cws_old); + } + smi.cust = (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)smi.hContact, GCDNF_TCHAR); + + if (opt.IgnoreEmpty && (smi.compare == 2)) + retem = FALSE; + else if (!TimeoutCheck() && !opt.PopupOnConnect) + rettime = FALSE; + + char status[8]; + mir_snprintf(status, SIZEOF(status), "%d", IDC_CHK_STATUS_MESSAGE); + if (DBGetContactSettingByte(hContact, MODULE, "EnablePopups", 1) && DBGetContactSettingByte(0, MODULE, status, 1) && retem && rettime) + { + POPUPDATAT ppd = {0}; + char* protoname = (char*)CallService(MS_PROTO_GETCONTACTBASEACCOUNT, (WPARAM)smi.hContact, 0); + PROTOACCOUNT* pdescr = (PROTOACCOUNT*)CallService(MS_PROTO_GETACCOUNT, 0, (LPARAM)protoname); + protoname = mir_t2a(pdescr->tszAccountName); + protoname = (char*)mir_realloc(protoname, lstrlenA(protoname) + lstrlenA("_TSMChange") + 1); + lstrcatA(protoname, "_TSMChange"); + TCHAR *str; + DBVARIANT dbVar = {0}; + DBGetContactSettingTString(NULL, MODULE, protoname, &dbVar); + if (lstrcmp(dbVar.ptszVal, NULL) == 0) + { + DBFreeVariant(&dbVar); + str = GetStr(&smi, TranslateT(DEFAULT_POPUP_STATUSMESSAGE)); + } + else + { + str = GetStr(&smi, dbVar.ptszVal); + } + mir_free(protoname); + + ppd.lchContact = smi.hContact; + ppd.lchIcon = LoadSkinnedProtoIcon(smi.proto, DBGetContactSettingWord(smi.hContact, smi.proto, "Status", ID_STATUS_ONLINE)); + lstrcpyn(ppd.lptzContactName, smi.cust, MAX_CONTACTNAME); + lstrcpyn(ppd.lptzText, str, MAX_SECONDLINE); + switch (opt.Colors) + { + case POPUP_COLOR_OWN: + ppd.colorBack = StatusList[Index(DBGetContactSettingWord(smi.hContact, smi.proto, "Status", ID_STATUS_ONLINE))].colorBack; + ppd.colorText = StatusList[Index(DBGetContactSettingWord(smi.hContact, smi.proto, "Status", ID_STATUS_ONLINE))].colorText; + break; + case POPUP_COLOR_WINDOWS: + ppd.colorBack = GetSysColor(COLOR_BTNFACE); + ppd.colorText = GetSysColor(COLOR_WINDOWTEXT); + break; + case POPUP_COLOR_POPUP: + ppd.colorBack = ppd.colorText = 0; + break; + } + ppd.PluginWindowProc = (WNDPROC)PopupDlgProc; + ppd.PluginData = NULL; + ppd.iSeconds = opt.PopupTimeout; + PUAddPopUpT(&ppd); + mir_free(str); + } + mir_free(smi.newstatusmsg); + mir_free(smi.oldstatusmsg); + return 1; + } + } + return 0; +} + +int ContactSettingChanged(WPARAM wParam, LPARAM lParam) +{ + DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *)lParam; + HANDLE hContact = (HANDLE)wParam; + + if (hContact == NULL) + return 0; + + char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (szProto == NULL) + return 0; + + if (DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) + { + if (ProcessExtraStatus(cws, hContact)) + return 0; + } + + ProcessStatus(cws, hContact); + return 0; +} + +int StatusModeChanged(WPARAM wParam, LPARAM lParam) +{ + char *szProto = (char *)lParam; + if (opt.AutoDisable && (!opt.OnlyGlobalChanges || szProto == NULL)) + { + if (opt.DisablePopupGlobally && ServiceExists(MS_POPUP_QUERY)) + { + char szSetting[12]; + wsprintfA(szSetting, "p%d", wParam); + BYTE hlpDisablePopup = DBGetContactSettingByte(0, MODULE, szSetting, 0); + + if (hlpDisablePopup != opt.PopupAutoDisabled) + { + BYTE hlpPopupStatus = (BYTE)CallService(MS_POPUP_QUERY, PUQS_GETSTATUS, 0); + opt.PopupAutoDisabled = hlpDisablePopup; + + if (hlpDisablePopup) + { + DBWriteContactSettingByte(0, MODULE, "OldPopupStatus", hlpPopupStatus); + CallService(MS_POPUP_QUERY, PUQS_DISABLEPOPUPS, 0); + } + else + { + if (hlpPopupStatus == FALSE) + { + if (DBGetContactSettingByte(0, MODULE, "OldPopupStatus", TRUE) == TRUE) + CallService(MS_POPUP_QUERY, PUQS_ENABLEPOPUPS, 0); + else + CallService(MS_POPUP_QUERY, PUQS_DISABLEPOPUPS, 0); + } + } + } + } + + if (opt.DisableSoundGlobally) + { + char szSetting[12]; + wsprintfA(szSetting, "s%d", wParam); + BYTE hlpDisableSound = DBGetContactSettingByte(0, MODULE, szSetting, 0); + + if (hlpDisableSound != opt.SoundAutoDisabled) + { + BYTE hlpUseSound = DBGetContactSettingByte(NULL, "Skin", "UseSound", 1); + opt.SoundAutoDisabled = hlpDisableSound; + + if (hlpDisableSound) + { + DBWriteContactSettingByte(0, MODULE, "OldUseSound", hlpUseSound); + DBWriteContactSettingByte(0, "Skin", "UseSound", FALSE); + } + else + { + if (hlpUseSound == FALSE) + DBWriteContactSettingByte(0, "Skin", "UseSound", DBGetContactSettingByte(0, MODULE, "OldUseSound", 1)); + } + } + } + } + + return 0; +} + +void ShowStatusChangePopup(HANDLE hContact, char *szProto, WORD oldStatus, WORD newStatus) +{ + TCHAR stzStatusText[MAX_SECONDLINE] = {0}; + WORD myStatus = (WORD)CallProtoService(szProto, PS_GETSTATUS, (WPARAM)0, (LPARAM)0); + + POPUPDATAT ppd = {0}; + ppd.lchContact = hContact; + ppd.lchIcon = LoadSkinnedProtoIcon(szProto, newStatus); + _tcscpy(ppd.lptzContactName, (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GSMDF_TCHAR)); + + if (opt.ShowGroup) //add group name to popup title + { + DBVARIANT dbv; + if (!DBGetContactSettingTString(hContact, "CList", "Group", &dbv)) + { + _tcscat(ppd.lptzContactName, _T(" (")); + _tcscat(ppd.lptzContactName, dbv.ptszVal); + _tcscat(ppd.lptzContactName, _T(")")); + DBFreeVariant(&dbv); + } + } + + if (opt.ShowStatus) + { + if (opt.UseAlternativeText) + { + switch (GetGender(hContact)) + { + case GENDER_MALE: + _tcsncpy(stzStatusText, StatusList[Index(newStatus)].lpzMStatusText, MAX_STATUSTEXT); + break; + case GENDER_FEMALE: + _tcsncpy(stzStatusText, StatusList[Index(newStatus)].lpzFStatusText, MAX_STATUSTEXT); + break; + case GENDER_UNSPECIFIED: + _tcsncpy(stzStatusText, StatusList[Index(newStatus)].lpzUStatusText, MAX_STATUSTEXT); + break; + } + } + else + { + _tcsncpy(stzStatusText, StatusList[Index(newStatus)].lpzStandardText, MAX_STATUSTEXT); + } + + if (opt.ShowPreviousStatus) + { + TCHAR buff[MAX_STATUSTEXT]; + wsprintf(buff, TranslateTS(STRING_SHOWPREVIOUSSTATUS), StatusList[Index(oldStatus)].lpzStandardText); + _tcscat(_tcscat(stzStatusText, _T(" ")), buff); + } + } + + if (opt.ReadAwayMsg && + myStatus != ID_STATUS_INVISIBLE && + StatusHasAwayMessage(szProto, newStatus)) + { + DBWriteContactSettingTString(hContact, MODULE, "LastPopupText", stzStatusText); + } + + _tcscpy(ppd.lptzText, stzStatusText); + + switch (opt.Colors) + { + case POPUP_COLOR_OWN: + ppd.colorBack = StatusList[Index(newStatus)].colorBack; + ppd.colorText = StatusList[Index(newStatus)].colorText; + break; + case POPUP_COLOR_WINDOWS: + ppd.colorBack = GetSysColor(COLOR_BTNFACE); + ppd.colorText = GetSysColor(COLOR_WINDOWTEXT); + break; + case POPUP_COLOR_POPUP: + ppd.colorBack = ppd.colorText = 0; + break; + } + + ppd.PluginWindowProc = (WNDPROC)PopupDlgProc; + + PLUGINDATA *pdp = (PLUGINDATA *)mir_alloc(sizeof(PLUGINDATA)); + pdp->oldStatus = oldStatus; + pdp->newStatus = newStatus; + pdp->hAwayMsgHook = NULL; + pdp->hAwayMsgProcess = NULL; + ppd.PluginData = pdp; + ppd.iSeconds = opt.PopupTimeout; + PUAddPopUpT(&ppd); +} + +void BlinkIcon(HANDLE hContact, char* szProto, WORD status) +{ + CLISTEVENT cle = {0}; + TCHAR stzTooltip[256]; + + cle.cbSize = sizeof(cle); + cle.flags = CLEF_ONLYAFEW | CLEF_TCHAR; + cle.hContact = hContact; + cle.hDbEvent = hContact; + if (opt.BlinkIcon_Status) + cle.hIcon = LoadSkinnedProtoIcon(szProto, status); + else + cle.hIcon = LoadSkinnedIcon(SKINICON_OTHER_USERONLINE); + cle.pszService = "UserOnline/Description"; + cle.ptszTooltip = stzTooltip; + + TCHAR *hlpName = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR); + mir_sntprintf(stzTooltip, SIZEOF(stzTooltip), TranslateT("%s is now %s"), hlpName, StatusList[Index(status)].lpzStandardText); + CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cle); +} + +void PlayChangeSound(HANDLE hContact, WORD oldStatus, WORD newStatus) +{ + DBVARIANT dbv; + if (opt.UseIndSnd) + { + TCHAR stzSoundFile[MAX_PATH] = {0}; + if (!DBGetContactSettingTString(hContact, MODULE, "UserFromOffline", &dbv) && + oldStatus == ID_STATUS_OFFLINE) + { + _tcscpy(stzSoundFile, dbv.ptszVal); + DBFreeVariant(&dbv); + } + else if (!DBGetContactSettingTString(hContact, MODULE, StatusList[Index(newStatus)].lpzSkinSoundName, &dbv)) + { + lstrcpy(stzSoundFile, dbv.ptszVal); + DBFreeVariant(&dbv); + } + + if (stzSoundFile[0]) + { + //Now make path to IndSound absolute, as it isn't registered + TCHAR stzSoundPath[MAX_PATH]; + CallService(MS_UTILS_PATHTOABSOLUTET, (WPARAM)stzSoundFile, (LPARAM)stzSoundPath); + PlaySound(stzSoundPath, NULL, SND_ASYNC | SND_FILENAME | SND_NOSTOP); + return; + } + } + + char szSoundFile[MAX_PATH] = {0}; + + if (!DBGetContactSettingByte(0, "SkinSoundsOff", "UserFromOffline", 0) && + !DBGetContactSettingString(0,"SkinSounds", "UserFromOffline", &dbv) && + oldStatus == ID_STATUS_OFFLINE) + { + strcpy(szSoundFile, "UserFromOffline"); + DBFreeVariant(&dbv); + } + else if (!DBGetContactSettingByte(0, "SkinSoundsOff", StatusList[Index(newStatus)].lpzSkinSoundName, 0) && + !DBGetContactSetting(0, "SkinSounds", StatusList[Index(newStatus)].lpzSkinSoundName, &dbv)) + { + strcpy(szSoundFile, StatusList[Index(newStatus)].lpzSkinSoundName); + DBFreeVariant(&dbv); + } + + if (szSoundFile[0]) + SkinPlaySound(szSoundFile); +} + +int ContactStatusChanged(WPARAM wParam, LPARAM lParam) +{ + WORD oldStatus = LOWORD(lParam); + WORD newStatus = HIWORD(lParam); + HANDLE hContact = (HANDLE)wParam; + char buff[8], szProto[64], szSubProto[64]; + bool bEnablePopup = true, bEnableSound = true; + + char *hlpProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0); + if (hlpProto == NULL || opt.TempDisabled) + return 0; + + strcpy(szProto, hlpProto); + WORD myStatus = (WORD)CallProtoService(szProto, PS_GETSTATUS, (WPARAM)0, (LPARAM)0); + + if (strcmp(szProto, szMetaModuleName) == 0) //this contact is Meta + { + HANDLE hSubContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0); + strcpy(szSubProto, (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hSubContact,0)); + + if (newStatus == ID_STATUS_OFFLINE) + { + // read last online proto for metaconatct if exists, + // to avoid notifying when meta went offline but default contact's proto still online + DBVARIANT dbv; + if (!DBGetContactSettingString(hContact, szProto, "LastOnline", &dbv)) + { + strcpy(szSubProto, dbv.pszVal); + DBFreeVariant(&dbv); + } + } + else + DBWriteContactSettingString(hContact, szProto, "LastOnline", szSubProto); + + if (!DBGetContactSettingByte(0, MODULE, szSubProto, 1)) + return 0; + + strcpy(szProto, szSubProto); + } + else + { + if (myStatus == ID_STATUS_OFFLINE) + return 0; + } + + if (!opt.FromOffline || oldStatus != ID_STATUS_OFFLINE) // Either it wasn't a change from Offline or we didn't enable that. + { + wsprintfA(buff, "%d", newStatus); + if (DBGetContactSettingByte(0, MODULE, buff, 1) == 0) + return 0; // "Notify when a contact changes to one of..." is unchecked + } + + if (!opt.HiddenContactsToo && (DBGetContactSettingByte(hContact, "CList", "Hidden", 0) == 1)) + return 0; + + // we don't want to be notified if new chatroom comes online + if (DBGetContactSettingByte(hContact, szProto, "ChatRoom", 0) == 1) + return 0; + + // check if that proto from which we received statuschange notification, isn't in autodisable list + char statusIDs[12], statusIDp[12]; + if (opt.AutoDisable) + { + wsprintfA(statusIDs, "s%d", myStatus); + wsprintfA(statusIDp, "p%d", myStatus); + bEnableSound = DBGetContactSettingByte(0, MODULE, statusIDs, 1) ? FALSE : TRUE; + bEnablePopup = DBGetContactSettingByte(0, MODULE, statusIDp, 1) ? FALSE : TRUE; + } + + if (bEnablePopup && DBGetContactSettingByte(hContact, MODULE, "EnablePopups", 1) && TimeoutCheck()) + ShowStatusChangePopup(hContact, szProto, oldStatus, newStatus); + + if (opt.BlinkIcon) + BlinkIcon(hContact, szProto, newStatus); + + if (bEnableSound && + DBGetContactSettingByte(0, "Skin", "UseSound", TRUE) && + DBGetContactSettingByte(hContact, MODULE, "EnableSounds", 1)) + { + PlayChangeSound(hContact, oldStatus, newStatus); + } + + if (opt.Log) + { + TCHAR stzName[64], stzStatus[MAX_STATUSTEXT], stzOldStatus[MAX_STATUSTEXT]; + TCHAR stzDate[MAX_STATUSTEXT], stzTime[MAX_STATUSTEXT]; + TCHAR stzText[1024]; + + _tcscpy(stzName, (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)); + _tcsncpy(stzStatus, StatusList[Index(newStatus)].lpzStandardText, MAX_STATUSTEXT); + _tcsncpy(stzOldStatus, StatusList[Index(oldStatus)].lpzStandardText, MAX_STATUSTEXT); + GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL,_T("HH':'mm"), stzTime, SIZEOF(stzTime)); + GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL,_T("dd/MM/yyyy"), stzDate, SIZEOF(stzDate)); + wsprintf(stzText, TranslateT("%s, %s. %s changed to: %s (was: %s).\r\n"), stzDate, stzTime, stzName, stzStatus, stzOldStatus); + LogToFile(stzText); + } + + return 0; +} + +void InitStatusList() +{ + int index = 0; + //Online + index = Index(ID_STATUS_ONLINE); + StatusList[index].ID = ID_STATUS_ONLINE; + StatusList[index].icon = SKINICON_STATUS_ONLINE; + lstrcpyn(StatusList[index].lpzMStatusText, TranslateT("(M) is back online!"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzFStatusText, TranslateT("(F) is back online!"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzUStatusText, TranslateT("(U) is back online!"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzStandardText, TranslateT("Online"), MAX_STANDARDTEXT); + lstrcpynA(StatusList[index].lpzSkinSoundName, "UserOnline", MAX_SKINSOUNDNAME); + lstrcpynA(StatusList[index].lpzSkinSoundDesc, Translate("User: Online"), MAX_SKINSOUNDDESC); + lstrcpynA(StatusList[index].lpzSkinSoundFile, "global.wav", MAX_PATH); + StatusList[index].colorBack = DBGetContactSettingDword(NULL, MODULE, "40072bg", COLOR_BG_AVAILDEFAULT); + StatusList[index].colorText = DBGetContactSettingDword(NULL, MODULE, "40072tx", COLOR_TX_DEFAULT); + + //Offline + index = Index(ID_STATUS_OFFLINE); + StatusList[index].ID = ID_STATUS_OFFLINE; + StatusList[index].icon = SKINICON_STATUS_OFFLINE; + lstrcpyn(StatusList[index].lpzMStatusText, TranslateT("(M) went offline! :("), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzFStatusText, TranslateT("(F) went offline! :("), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzUStatusText, TranslateT("(U) went offline! :("), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzStandardText, TranslateT("Offline"), MAX_STANDARDTEXT); + lstrcpynA(StatusList[index].lpzSkinSoundName, "UserOffline", MAX_SKINSOUNDNAME); + lstrcpynA(StatusList[index].lpzSkinSoundDesc, Translate("User: Offline"), MAX_SKINSOUNDDESC); + lstrcpynA(StatusList[index].lpzSkinSoundFile, "offline.wav", MAX_PATH); + StatusList[index].colorBack = DBGetContactSettingDword(NULL, MODULE, "40071bg", COLOR_BG_NAVAILDEFAULT); + StatusList[index].colorText = DBGetContactSettingDword(NULL, MODULE, "40071tx", COLOR_TX_DEFAULT); + + //Invisible + index = Index(ID_STATUS_INVISIBLE); + StatusList[index].ID = ID_STATUS_INVISIBLE; + StatusList[index].icon = SKINICON_STATUS_INVISIBLE; + lstrcpyn(StatusList[index].lpzMStatusText, TranslateT("(M) hides in shadows..."), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzFStatusText, TranslateT("(F) hides in shadows..."), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzUStatusText, TranslateT("(U) hides in shadows..."), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzStandardText, TranslateT("Invisible"), MAX_STANDARDTEXT); + lstrcpynA(StatusList[index].lpzSkinSoundName, "UserInvisible", MAX_SKINSOUNDNAME); + lstrcpynA(StatusList[index].lpzSkinSoundDesc, Translate("User: Invisible"), MAX_SKINSOUNDDESC); + lstrcpynA(StatusList[index].lpzSkinSoundFile, "invisible.wav", MAX_PATH); + StatusList[index].colorBack = DBGetContactSettingDword(NULL, MODULE, "40078bg", COLOR_BG_AVAILDEFAULT); + StatusList[index].colorText = DBGetContactSettingDword(NULL, MODULE, "40078tx", COLOR_TX_DEFAULT); + + //Free for chat + index = Index(ID_STATUS_FREECHAT); + StatusList[index].ID = ID_STATUS_FREECHAT; + StatusList[index].icon = SKINICON_STATUS_FREE4CHAT; + lstrcpyn(StatusList[index].lpzMStatusText, TranslateT("(M) feels talkative!"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzFStatusText, TranslateT("(F) feels talkative!"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzUStatusText, TranslateT("(U) feels talkative!"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzStandardText, TranslateT("Free for chat"), MAX_STANDARDTEXT); + lstrcpynA(StatusList[index].lpzSkinSoundName, "UserFreeForChat", MAX_SKINSOUNDNAME); + lstrcpynA(StatusList[index].lpzSkinSoundDesc, Translate("User: Free For Chat"), MAX_SKINSOUNDDESC); + lstrcpynA(StatusList[index].lpzSkinSoundFile, "free4chat.wav", MAX_PATH); + StatusList[index].colorBack = DBGetContactSettingDword(NULL, MODULE, "40077bg", COLOR_BG_AVAILDEFAULT); + StatusList[index].colorText = DBGetContactSettingDword(NULL, MODULE, "40077tx", COLOR_TX_DEFAULT); + + //Away + index = Index(ID_STATUS_AWAY); + StatusList[index].ID = ID_STATUS_AWAY; + StatusList[index].icon = SKINICON_STATUS_AWAY; + lstrcpyn(StatusList[index].lpzMStatusText, TranslateT("(M) went Away"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzFStatusText, TranslateT("(F) went Away"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzUStatusText, TranslateT("(U) went Away"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzStandardText, TranslateT("Away"), MAX_STANDARDTEXT); + lstrcpynA(StatusList[index].lpzSkinSoundName, "UserAway", MAX_SKINSOUNDNAME); + lstrcpynA(StatusList[index].lpzSkinSoundDesc, Translate("User: Away"), MAX_SKINSOUNDDESC); + lstrcpynA(StatusList[index].lpzSkinSoundFile, "away.wav", MAX_PATH); + StatusList[index].colorBack = DBGetContactSettingDword(NULL, MODULE, "40073bg", COLOR_BG_NAVAILDEFAULT); + StatusList[index].colorText = DBGetContactSettingDword(NULL, MODULE, "40073tx", COLOR_TX_DEFAULT); + + //NA + index = Index(ID_STATUS_NA); + StatusList[index].ID = ID_STATUS_NA; + StatusList[index].icon = SKINICON_STATUS_NA; + lstrcpyn(StatusList[index].lpzMStatusText, TranslateT("(M) isn't there anymore!"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzFStatusText, TranslateT("(F) isn't there anymore!"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzUStatusText, TranslateT("(U) isn't there anymore!"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzStandardText, TranslateT("NA"), MAX_STANDARDTEXT); + lstrcpynA(StatusList[index].lpzSkinSoundName, "UserNA", MAX_SKINSOUNDNAME); + lstrcpynA(StatusList[index].lpzSkinSoundDesc, Translate("User: Not Available"), MAX_SKINSOUNDDESC); + lstrcpynA(StatusList[index].lpzSkinSoundFile, "na.wav", MAX_PATH); + StatusList[index].colorBack = DBGetContactSettingDword(NULL, MODULE, "40075bg", COLOR_BG_NAVAILDEFAULT); + StatusList[index].colorText = DBGetContactSettingDword(NULL, MODULE, "40075tx", COLOR_TX_DEFAULT); + + //Occupied + index = Index(ID_STATUS_OCCUPIED); + StatusList[index].ID = ID_STATUS_OCCUPIED; + StatusList[index].icon = SKINICON_STATUS_OCCUPIED; + lstrcpyn(StatusList[index].lpzMStatusText, TranslateT("(M) has something else to do."), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzFStatusText, TranslateT("(F) has something else to do."), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzUStatusText, TranslateT("(U) has something else to do."), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzStandardText, TranslateT("Occupied"), MAX_STANDARDTEXT); + lstrcpynA(StatusList[index].lpzSkinSoundName, "UserOccupied", MAX_SKINSOUNDNAME); + lstrcpynA(StatusList[index].lpzSkinSoundDesc, Translate("User: Occupied"), MAX_SKINSOUNDDESC); + lstrcpynA(StatusList[index].lpzSkinSoundFile, "occupied.wav", MAX_PATH); + StatusList[index].colorBack = DBGetContactSettingDword(NULL, MODULE, "40076bg", COLOR_BG_NAVAILDEFAULT); + StatusList[index].colorText = DBGetContactSettingDword(NULL, MODULE, "40076tx", COLOR_TX_DEFAULT); + + //DND + index = Index(ID_STATUS_DND); + StatusList[index].ID = ID_STATUS_DND; + StatusList[index].icon = SKINICON_STATUS_DND; + lstrcpyn(StatusList[index].lpzMStatusText, TranslateT("(M) doesn't want to be disturbed!"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzFStatusText, TranslateT("(F) doesn't want to be disturbed!"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzUStatusText, TranslateT("(U) doesn't want to be disturbed!"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzStandardText, TranslateT("DND"), MAX_STANDARDTEXT); + lstrcpynA(StatusList[index].lpzSkinSoundName, "UserDND", MAX_SKINSOUNDNAME); + lstrcpynA(StatusList[index].lpzSkinSoundDesc, Translate("User: Do Not Disturb"), MAX_SKINSOUNDDESC); + lstrcpynA(StatusList[index].lpzSkinSoundFile, "dnd.wav", MAX_PATH); + StatusList[index].colorBack = DBGetContactSettingDword(NULL, MODULE, "40074bg", COLOR_BG_NAVAILDEFAULT); + StatusList[index].colorText = DBGetContactSettingDword(NULL, MODULE, "40074tx", COLOR_TX_DEFAULT); + + //OutToLunch + index = Index(ID_STATUS_OUTTOLUNCH); + StatusList[index].ID = ID_STATUS_OUTTOLUNCH; + StatusList[index].icon = SKINICON_STATUS_OUTTOLUNCH; + lstrcpyn(StatusList[index].lpzMStatusText, TranslateT("(M) is eating something"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzFStatusText, TranslateT("(F) is eating something"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzUStatusText, TranslateT("(U) is eating something"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzStandardText, TranslateT("Out to lunch"), MAX_STANDARDTEXT); + lstrcpynA(StatusList[index].lpzSkinSoundName, "UserOutToLunch", MAX_SKINSOUNDNAME); + lstrcpynA(StatusList[index].lpzSkinSoundDesc, Translate("User: Out To Lunch"), MAX_SKINSOUNDDESC); + lstrcpynA(StatusList[index].lpzSkinSoundFile, "lunch.wav", MAX_PATH); + StatusList[index].colorBack = DBGetContactSettingDword(NULL, MODULE, "40080bg", COLOR_BG_NAVAILDEFAULT); + StatusList[index].colorText = DBGetContactSettingDword(NULL, MODULE, "40080tx", COLOR_TX_DEFAULT); + + //OnThePhone + index = Index(ID_STATUS_ONTHEPHONE); + StatusList[index].ID = ID_STATUS_ONTHEPHONE; + StatusList[index].icon = SKINICON_STATUS_ONTHEPHONE; + lstrcpyn(StatusList[index].lpzMStatusText, TranslateT("(M) had to answer the phone"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzFStatusText, TranslateT("(F) had to answer the phone"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzUStatusText, TranslateT("(U) had to answer the phone"), MAX_STATUSTEXT); + lstrcpyn(StatusList[index].lpzStandardText, TranslateT("On the phone"), MAX_STANDARDTEXT); + lstrcpynA(StatusList[index].lpzSkinSoundName, "UserOnThePhone", MAX_SKINSOUNDNAME); + lstrcpynA(StatusList[index].lpzSkinSoundDesc, Translate("User: On The Phone"), MAX_SKINSOUNDDESC); + lstrcpynA(StatusList[index].lpzSkinSoundFile, "phone.wav", MAX_PATH); + StatusList[index].colorBack = DBGetContactSettingDword(NULL, MODULE, "40079bg", COLOR_BG_NAVAILDEFAULT); + StatusList[index].colorText = DBGetContactSettingDword(NULL, MODULE, "40079tx", COLOR_TX_DEFAULT); + + //Extra status + index = Index(ID_STATUS_EXTRASTATUS); + StatusList[index].ID = ID_STATUS_EXTRASTATUS; + StatusList[index].colorBack = DBGetContactSettingDword(NULL, MODULE, "40081bg", COLOR_BG_AVAILDEFAULT); + StatusList[index].colorText = DBGetContactSettingDword(NULL, MODULE, "40081tx", COLOR_TX_DEFAULT); +} + +int ProtoAck(WPARAM wParam,LPARAM lParam) +{ + ACKDATA *ack = (ACKDATA *)lParam; + + if (ack->type == ACKTYPE_STATUS) + { + WORD newStatus = (WORD)ack->lParam; + WORD oldStatus = (WORD)ack->hProcess; + char *szProto = (char *)ack->szModule; + + if (oldStatus == newStatus) + return 0; + + if (newStatus == ID_STATUS_OFFLINE) + { + //The protocol switched to offline. Disable the popups for this protocol + DBWriteContactSettingByte(NULL, MODULE, szProto, 0); + } + else if (oldStatus < ID_STATUS_ONLINE && newStatus >= ID_STATUS_ONLINE) + { + //The protocol changed from a disconnected status to a connected status. + //Enable the popups for this protocol. + LoadTime = GetTickCount(); + } + } + + return 0; +} + +INT_PTR EnableDisableMenuCommand(WPARAM wParam, LPARAM lParam) +{ + opt.TempDisabled = !opt.TempDisabled; + DBWriteContactSettingByte(0, MODULE, "TempDisable", opt.TempDisabled); + + CLISTMENUITEM mi = {0}; + mi.cbSize = sizeof(mi); + mi.flags = CMIM_ICON | CMIM_NAME | CMIF_TCHAR; + if (opt.TempDisabled) + { + mi.ptszName = _T("Enable status notification"); + mi.icolibItem = GetIconHandle(ICO_NOTIFICATION_OFF); + } + else + { + mi.ptszName = _T("Disable status notification"); + mi.icolibItem = GetIconHandle(ICO_NOTIFICATION_ON); + } + + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hEnableDisableMenu, (LPARAM)&mi); + CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)hToolbarButton, opt.TempDisabled ? TTBST_PUSHED : TTBST_RELEASED); + return 0; +} + +void InitMainMenuItem() +{ + CLISTMENUITEM mi = { 0 }; + mi.cbSize = sizeof(mi); + mi.flags = CMIF_TCHAR | CMIF_ICONFROMICOLIB; + mi.ptszPopupName = ServiceExists(MS_POPUP_ADDPOPUP) ? _T("PopUps") : NULL; + mi.pszService = MS_STATUSCHANGE_MENUCOMMAND; + hEnableDisableMenu = Menu_AddMainMenuItem(&mi); + + opt.TempDisabled = !opt.TempDisabled; + EnableDisableMenuCommand(0, 0); + + hServiceMenu = (HANDLE)CreateServiceFunction(MS_STATUSCHANGE_MENUCOMMAND, EnableDisableMenuCommand); +} + +struct _tag_iconList +{ + char *szDescr; + char *szName; + int iIconID; +} +static const iconList[] = +{ + { "Notification enabled", ICO_NOTIFICATION_OFF, IDI_NOTIFICATION_OFF }, + { "Notification disabled", ICO_NOTIFICATION_ON, IDI_NOTIFICATION_ON } +}; + +void InitIcolib() +{ + char szFile[MAX_PATH]; + char szSettingName[100]; + SKINICONDESC sid = {0}; + + sid.cbSize = sizeof(sid); + sid.cx = sid.cy = 16; + sid.pszDefaultFile = szFile; + sid.pszName = szSettingName; + sid.pszSection = MODULE; + + GetModuleFileNameA(hInst, szFile, MAX_PATH); + + for (int i = 0; i < SIZEOF(iconList); i++) + { + mir_snprintf(szSettingName, sizeof(szSettingName), "%s_%s", MODULE, iconList[i].szName); + sid.pszDescription = Translate(iconList[i].szDescr); + sid.iDefaultIndex = -iconList[i].iIconID; + Skin_AddIcon(&sid); + } +} + +void InitSound() +{ + for (int i = ID_STATUS_MIN; i <= ID_STATUS_MAX; i++) + SkinAddNewSoundEx(StatusList[Index(i)].lpzSkinSoundName, LPGEN("Status Notify"), StatusList[Index(i)].lpzSkinSoundDesc); + + SkinAddNewSoundEx("UserFromOffline", LPGEN("Status Notify"), LPGEN("User: from offline (has priority!)")); + SkinAddNewSoundEx(XSTATUS_SOUND_CHANGED, LPGEN("Status Notify"), LPGEN("Extra status changed")); + SkinAddNewSoundEx(XSTATUS_SOUND_MSGCHANGED, LPGEN("Status Notify"), LPGEN("Extra status message changed")); + SkinAddNewSoundEx(XSTATUS_SOUND_REMOVED, LPGEN("Status Notify"), LPGEN("Extra status removed")); +} + +int InitTopToolbar(WPARAM, LPARAM) +{ + TTBButton tbb = {0}; + tbb.cbSize = sizeof(TTBButton); + tbb.pszService = MS_STATUSCHANGE_MENUCOMMAND; + tbb.name = LPGEN("Toggle status notification"); + tbb.pszTooltipUp = LPGEN("Status notification enabled"); + tbb.pszTooltipDn = LPGEN("Status notification disabled"); + tbb.hIconHandleUp = GetIconHandle(ICO_NOTIFICATION_ON); + tbb.hIconHandleDn = GetIconHandle(ICO_NOTIFICATION_OFF); + tbb.dwFlags = (opt.TempDisabled ? TTBBF_PUSHED : 0); + hToolbarButton = TopToolbar_AddButton(&tbb); + return 0; +} + +int ModulesLoaded(WPARAM wParam, LPARAM lParam) +{ + InitMainMenuItem(); + + HookEvent(ME_USERINFO_INITIALISE, UserInfoInitialise); + HookEvent(ME_STATUSCHANGE_CONTACTSTATUSCHANGED, ContactStatusChanged); + HookEvent(ME_MSG_WINDOWEVENT, OnWindowEvent); + HookEvent(ME_TTB_MODULELOADED, InitTopToolbar); + + int count = 0; + PROTOACCOUNT **accounts = NULL; + CallService(MS_PROTO_ENUMACCOUNTS, (WPARAM)&count, (LPARAM)&accounts); + for (int i = 0; i < count; i++) + if (IsAccountEnabled(accounts[i])) + DBWriteContactSettingByte(NULL, MODULE, accounts[i]->szModuleName, 0); + + if (ServiceExists(MS_MC_GETPROTOCOLNAME)) + strcpy(szMetaModuleName, (char *)CallService(MS_MC_GETPROTOCOLNAME, 0, 0)); + + return 0; +} + +extern "C" int __declspec(dllexport) Load(void) +{ + mir_getLP(&pluginInfoEx); + + //"Service" Hook, used when the DB settings change: we'll monitor the "status" setting. + HookEvent(ME_DB_CONTACT_SETTINGCHANGED, ContactSettingChanged); + //We create this Hook which will notify everyone when a contact changes his status. + hHookContactStatusChanged = CreateHookableEvent(ME_STATUSCHANGE_CONTACTSTATUSCHANGED); + HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded); + //We add the option page and the user info page (it's needed because options are loaded after plugins) + HookEvent(ME_OPT_INITIALISE, OptionsInitialize); + //This is needed for "NoSound"-like routines. + HookEvent(ME_CLIST_STATUSMODECHANGE, StatusModeChanged); + HookEvent(ME_PROTO_ACK, ProtoAck); + + LoadOptions(); + InitStatusList(); + InitIcolib(); + InitSound(); + + CallService(MS_DB_SETSETTINGRESIDENT, (WPARAM)TRUE, (LPARAM)"MetaContacts/LastOnline"); + CallService(MS_DB_SETSETTINGRESIDENT, (WPARAM)TRUE, (LPARAM)"NewStatusNotify/LastPopupText"); + return 0; +} + +extern "C" int __declspec(dllexport) Unload(void) +{ + DestroyHookableEvent(hHookContactStatusChanged); + DestroyServiceFunction(hServiceMenu); + xstatusList.destroy(); + return 0; +} \ No newline at end of file diff --git a/plugins/NewXstatusNotify/src/options.cpp b/plugins/NewXstatusNotify/src/options.cpp new file mode 100644 index 0000000000..808092d498 --- /dev/null +++ b/plugins/NewXstatusNotify/src/options.cpp @@ -0,0 +1,1074 @@ +/* + NewXstatusNotify YM - Plugin for Miranda IM + Copyright (c) 2001-2004 Luca Santarelli + Copyright (c) 2005-2007 Vasilich + Copyright (c) 2007-2011 yaho + + 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 "common.h" +#include "indsnd.h" +#include "options.h" +#include "popup.h" +#include "xstatus.h" +#include "utils.h" + +OPTIONS opt = {0}; +TEMPLATES templates = {0}; +BOOL UpdateListFlag = FALSE; +LIST ProtoTemplates(10); +int LastItem = 0; + +extern HINSTANCE hInst; +extern HANDLE hEnableDisableMenu; +extern STATUS StatusList[STATUS_COUNT]; + +INT_PTR CALLBACK DlgProcAutoDisableOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +void LoadTemplates() +{ + DBGetStringDefault(0, MODULE, "TPopupDelimiter", templates.PopupDelimiter, SIZEOF(templates.PopupDelimiter), DEFAULT_POPUP_DELIMITER); + DBGetStringDefault(0, MODULE, "TPopupChange", templates.PopupNewXstatus, SIZEOF(templates.PopupNewXstatus), DEFAULT_POPUP_NEW); + DBGetStringDefault(0, MODULE, "TPopupChangeMsg", templates.PopupNewMsg, SIZEOF(templates.PopupNewMsg), DEFAULT_POPUP_CHANGEMSG); + DBGetStringDefault(0, MODULE, "TPopupRemoval", templates.PopupRemove, SIZEOF(templates.PopupRemove), DEFAULT_POPUP_REMOVE); + + DBGetStringDefault(0, MODULE, "TLogDelimiter", templates.LogDelimiter, SIZEOF(templates.LogDelimiter), DEFAULT_LOG_DELIMITER); + DBGetStringDefault(0, MODULE, "TLogChange", templates.LogNewXstatus, SIZEOF(templates.LogNewXstatus), DEFAULT_LOG_NEW); + DBGetStringDefault(0, MODULE, "TLogChangeMsg", templates.LogNewMsg, SIZEOF(templates.LogNewMsg), DEFAULT_LOG_CHANGEMSG); + DBGetStringDefault(0, MODULE, "TLogRemoval", templates.LogRemove, SIZEOF(templates.LogRemove), DEFAULT_LOG_REMOVE); + DBGetStringDefault(0, MODULE, "TLogOpening", templates.LogOpening, SIZEOF(templates.LogOpening), DEFAULT_LOG_OPENING); + templates.PopupFlags = DBGetContactSettingByte(0, MODULE, "TPopupFlags", NOTIFY_NEW_XSTATUS | NOTIFY_NEW_MESSAGE); + templates.LogFlags = DBGetContactSettingByte(0, MODULE, "TLogFlags", NOTIFY_NEW_XSTATUS | NOTIFY_NEW_MESSAGE | NOTIFY_OPENING_ML); +} + +void LoadOptions() +{ + // IDD_OPT_POPUP + opt.Colors = DBGetContactSettingByte(0,MODULE, "Colors", DEFAULT_COLORS); + opt.ShowGroup = DBGetContactSettingByte(0, MODULE, "ShowGroup", 0); + opt.ShowStatus = DBGetContactSettingByte(0, MODULE, "ShowStatus", 1); + opt.UseAlternativeText = DBGetContactSettingByte(0, MODULE, "UseAlternativeText", 0); + opt.ShowPreviousStatus = DBGetContactSettingByte(0, MODULE, "ShowPreviousStatus", 0); + opt.ReadAwayMsg = DBGetContactSettingByte(0, MODULE, "ReadAwayMsg", 0); + opt.PopupTimeout = DBGetContactSettingDword(0, MODULE, "PopupTimeout", 0); + opt.LeftClickAction= DBGetContactSettingByte(0, MODULE, "LeftClickAction", 5); + opt.RightClickAction = DBGetContactSettingByte(0, MODULE, "RightClickAction", 1); + // IDD_OPT_XPOPUP + opt.PDisableForMusic = DBGetContactSettingByte(0, MODULE, "PDisableForMusic", 1); + opt.PTruncateMsg = DBGetContactSettingByte(0, MODULE, "PTruncateMsg", 0); + opt.PMsgLen = DBGetContactSettingDword(0, MODULE, "PMsgLen", 64); + // IDD_OPT_GENERAL + opt.FromOffline = DBGetContactSettingByte(0, MODULE, "FromOffline", 1); + opt.AutoDisable = DBGetContactSettingByte(0, MODULE, "AutoDisable", 1); + opt.HiddenContactsToo = DBGetContactSettingByte(0, MODULE, "HiddenContactsToo", 1); + opt.UseIndSnd = DBGetContactSettingByte(0, MODULE, "UseIndSounds", 1); + opt.BlinkIcon = DBGetContactSettingByte(0, MODULE, "BlinkIcon", 0); + opt.BlinkIcon_Status = DBGetContactSettingByte(0, MODULE, "BlinkIcon_Status", 0); + opt.Log = DBGetContactSettingByte(0, MODULE, "Log", 0); + DBGetStringDefault(0, MODULE, "LogFilePath", opt.LogFilePath, MAX_PATH, _T("")); + // IDD_AUTODISABLE + opt.OnlyGlobalChanges = DBGetContactSettingByte(0, MODULE, "OnlyGlobalChanges", 1); + opt.DisablePopupGlobally = DBGetContactSettingByte(0, MODULE, "DisablePopupGlobally", 1); + opt.DisableSoundGlobally = DBGetContactSettingByte(0, MODULE, "DisableSoundGlobally", 1); + // IDD_OPT_XLOG + opt.EnableLogging = DBGetContactSettingByte(0, MODULE, "EnableLogging", 0); + opt.PreventIdentical = DBGetContactSettingByte(0, MODULE, "PreventIdentical", 1); + opt.KeepInHistory = DBGetContactSettingByte(0, MODULE, "KeepInHistory", 0); + opt.LDisableForMusic = DBGetContactSettingByte(0, MODULE, "LDisableForMusic", 1); + opt.LTruncateMsg = DBGetContactSettingByte(0, MODULE, "LTruncateMsg", 0); + opt.LMsgLen = DBGetContactSettingDword(0, MODULE, "LMsgLen", 128); + //IDD_OPT_SMPOPUP + opt.IgnoreEmpty = DBGetContactSettingByte(0, MODULE, "IgnoreEmpty", 1); + opt.PopupOnConnect = DBGetContactSettingByte(0, MODULE, "PopupOnConnect", 0); + // OTHER + opt.TempDisabled = DBGetContactSettingByte(0, MODULE, "TempDisable", 0); + + LoadTemplates(); + + return; +} + +void SaveTemplates() +{ + DBWriteContactSettingTString(0, MODULE, "TPopupDelimiter", templates.PopupDelimiter); + DBWriteContactSettingTString(0, MODULE, "TPopupChange", templates.PopupNewXstatus); + DBWriteContactSettingTString(0, MODULE, "TPopupChangeMsg", templates.PopupNewMsg); + DBWriteContactSettingTString(0, MODULE, "TPopupRemoval", templates.PopupRemove); + DBWriteContactSettingTString(0, MODULE, "TLogDelimiter", templates.LogDelimiter); + DBWriteContactSettingTString(0, MODULE, "TLogChange", templates.LogNewXstatus); + DBWriteContactSettingTString(0, MODULE, "TLogChangeMsg", templates.LogNewMsg); + DBWriteContactSettingTString(0, MODULE, "TLogRemoval", templates.LogRemove); + DBWriteContactSettingTString(0, MODULE, "TLogOpening", templates.LogOpening); + DBWriteContactSettingByte(0, MODULE, "TPopupFlags", templates.PopupFlags); + DBWriteContactSettingByte(0, MODULE, "TLogFlags", templates.LogFlags); + + for (int i = 0; i < ProtoTemplates.getCount(); i++) { + PROTOTEMPLATE *prototemplate = ProtoTemplates[i]; + TCHAR str[MAX_PATH]; + mir_sntprintf(str, SIZEOF(str), _T("%s_TSMChange"), prototemplate->ProtoName); + char *szstr = mir_t2a(str); + DBWriteContactSettingTString(0, MODULE, szstr, prototemplate->ProtoTemplate); + } +} + +void SaveOptions() +{ + // IDD_OPT_POPUP + DBWriteContactSettingByte(0, MODULE, "Colors", opt.Colors); + DBWriteContactSettingByte(0, MODULE, "ShowGroup", opt.ShowGroup); + DBWriteContactSettingByte(0, MODULE, "ShowStatus", opt.ShowStatus); + DBWriteContactSettingByte(0, MODULE, "UseAlternativeText", opt.UseAlternativeText); + DBWriteContactSettingByte(0, MODULE, "ShowPreviousStatus", opt.ShowPreviousStatus); + DBWriteContactSettingByte(0, MODULE, "ReadAwayMsg", opt.ReadAwayMsg); + DBWriteContactSettingDword(0, MODULE, "PopupTimeout", opt.PopupTimeout); + DBWriteContactSettingByte(0, MODULE, "LeftClickAction", opt.LeftClickAction); + DBWriteContactSettingByte(0, MODULE, "RightClickAction", opt.RightClickAction); + // IDD_OPT_XPOPUP + DBWriteContactSettingByte(0, MODULE, "PDisableForMusic", opt.PDisableForMusic); + DBWriteContactSettingByte(0, MODULE, "PTruncateMsg", opt.PTruncateMsg); + DBWriteContactSettingDword(0, MODULE, "PMsgLen", opt.PMsgLen); + // IDD_OPT_GENERAL + DBWriteContactSettingByte(0, MODULE, "FromOffline", opt.FromOffline); + DBWriteContactSettingByte(0, MODULE, "AutoDisable", opt.AutoDisable); + DBWriteContactSettingByte(0, MODULE, "HiddenContactsToo", opt.HiddenContactsToo); + DBWriteContactSettingByte(0, MODULE, "UseIndSounds", opt.UseIndSnd); + DBWriteContactSettingByte(0, MODULE, "BlinkIcon", opt.BlinkIcon); + DBWriteContactSettingByte(0, MODULE, "BlinkIcon_Status", opt.BlinkIcon_Status); + DBWriteContactSettingByte(0, MODULE, "Log", opt.Log); + DBWriteContactSettingTString(0, MODULE, "LogFilePath", opt.LogFilePath); + // IDD_AUTODISABLE + DBWriteContactSettingByte(0, MODULE, "OnlyGlobalChanges", opt.OnlyGlobalChanges); + DBWriteContactSettingByte(0, MODULE, "DisablePopupGlobally", opt.DisablePopupGlobally); + DBWriteContactSettingByte(0, MODULE, "DisableSoundGlobally", opt.DisableSoundGlobally); + // IDD_OPT_XLOG + DBWriteContactSettingByte(0, MODULE, "EnableLogging", opt.EnableLogging); + DBWriteContactSettingByte(0, MODULE, "PreventIdentical", opt.PreventIdentical); + DBWriteContactSettingByte(0, MODULE, "KeepInHistory", opt.KeepInHistory); + DBWriteContactSettingByte(0, MODULE, "LDisableForMusic", opt.LDisableForMusic); + DBWriteContactSettingByte(0, MODULE, "LTruncateMsg", opt.LTruncateMsg); + DBWriteContactSettingDword(0, MODULE, "LMsgLen", opt.LMsgLen); + //IDD_OPT_SMPOPUP + DBWriteContactSettingByte(0, MODULE, "IgnoreEmpty", opt.IgnoreEmpty); + DBWriteContactSettingByte(0, MODULE, "PopupOnConnect", opt.PopupOnConnect); +} + +INT_PTR CALLBACK DlgProcGeneralOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + + CheckDlgButton(hwndDlg, IDC_AUTODISABLE, opt.AutoDisable); + EnableWindow(GetDlgItem(hwndDlg, IDC_CONFIGUREAUTODISABLE), opt.AutoDisable); + + CheckDlgButton(hwndDlg, IDC_HIDDENCONTACTSTOO, opt.HiddenContactsToo); + CheckDlgButton(hwndDlg, IDC_USEINDIVSOUNDS, opt.UseIndSnd); + CheckDlgButton(hwndDlg, IDC_BLINKICON, opt.BlinkIcon); + CheckDlgButton(hwndDlg, IDC_BLINKICON_STATUS, opt.BlinkIcon_Status); + EnableWindow(GetDlgItem(hwndDlg, IDC_BLINKICON_STATUS), opt.BlinkIcon); + + CheckDlgButton(hwndDlg, IDC_LOG, opt.Log); + SetDlgItemText(hwndDlg, IDC_LOGFILE, opt.LogFilePath); + EnableWindow(GetDlgItem(hwndDlg, IDC_LOGFILE), opt.Log); + EnableWindow(GetDlgItem(hwndDlg, IDC_BT_CHOOSELOGFILE), opt.Log); + EnableWindow(GetDlgItem(hwndDlg, IDC_BT_VIEWLOG), opt.Log); + + //Statuses notified + char status[8]; + for (int i = ID_STATUS_MIN; i <= ID_STATUS_MAX2; i++) + { + wsprintfA(status, "%d", i); + CheckDlgButton(hwndDlg, i, DBGetContactSettingByte(0, MODULE, status, 1)); + } + CheckDlgButton(hwndDlg, IDC_CHK_FROMOFFLINE, opt.FromOffline); + + return TRUE; + } + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + case IDC_CONFIGUREAUTODISABLE: + CreateDialog(hInst, MAKEINTRESOURCE(IDD_AUTODISABLE), hwndDlg, DlgProcAutoDisableOpts); + return FALSE; + case IDC_AUTODISABLE: + EnableWindow(GetDlgItem(hwndDlg, IDC_CONFIGUREAUTODISABLE), IsDlgButtonChecked(hwndDlg, IDC_AUTODISABLE)); + break; + case IDC_BLINKICON: + EnableWindow(GetDlgItem(hwndDlg, IDC_BLINKICON_STATUS), IsDlgButtonChecked(hwndDlg, IDC_BLINKICON)); + break; + case IDC_BT_VIEWLOG: + ShowLog(opt.LogFilePath); + return FALSE; + case IDC_BT_CHOOSELOGFILE: + { + TCHAR buff[MAX_PATH]; + OPENFILENAME ofn = {0}; + + GetDlgItemText(hwndDlg, IDC_LOGFILE, buff, MAX_PATH); + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.lpstrFile = buff; + ofn.nMaxFile = MAX_PATH; + ofn.hwndOwner = hwndDlg; + TCHAR filter[MAX_PATH]; + mir_sntprintf(filter, SIZEOF(filter), _T("%s (*.*)%c*.*%c%s (*.log)%c*.log%c%s (*.txt)%c*.txt%c"), TranslateT("All Files"), 0, 0, TranslateT("Log"), 0, 0, TranslateT("Text"), 0, 0); + ofn.lpstrFilter = filter; + ofn.nFilterIndex = 2; + ofn.lpstrInitialDir = buff; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; + ofn.lpstrDefExt = _T("log"); + if (GetSaveFileName(&ofn)) + SetDlgItemText(hwndDlg, IDC_LOGFILE, buff); + + break; + } + case IDC_LOG: + EnableWindow(GetDlgItem(hwndDlg, IDC_LOGFILE), IsDlgButtonChecked(hwndDlg, IDC_LOG)); + EnableWindow(GetDlgItem(hwndDlg, IDC_BT_CHOOSELOGFILE), IsDlgButtonChecked(hwndDlg, IDC_LOG)); + EnableWindow(GetDlgItem(hwndDlg, IDC_BT_VIEWLOG), IsDlgButtonChecked(hwndDlg, IDC_LOG)); + break; + case IDC_HYPERLINK: + { + OPENOPTIONSDIALOG ood = {0}; + ood.cbSize = sizeof(ood); + ood.pszGroup = "Customize"; + ood.pszPage = "Sounds"; + CallService(MS_OPT_OPENOPTIONS, 0, (LPARAM)&ood); + return FALSE; + } + } + + if (HIWORD(wParam) == BN_CLICKED || (HIWORD(wParam) == EN_CHANGE && (HWND)lParam == GetFocus())) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + + break; + } + case WM_NOTIFY: + { + if (((LPNMHDR)lParam)->code == PSN_APPLY) + { + opt.AutoDisable = IsDlgButtonChecked(hwndDlg, IDC_AUTODISABLE); + opt.BlinkIcon = IsDlgButtonChecked(hwndDlg, IDC_BLINKICON); + opt.BlinkIcon_Status = IsDlgButtonChecked(hwndDlg, IDC_BLINKICON_STATUS); + opt.HiddenContactsToo = IsDlgButtonChecked(hwndDlg, IDC_HIDDENCONTACTSTOO); + opt.UseIndSnd = IsDlgButtonChecked(hwndDlg, IDC_USEINDIVSOUNDS); + + opt.Log = IsDlgButtonChecked(hwndDlg, IDC_LOG); + GetDlgItemText(hwndDlg, IDC_LOGFILE, opt.LogFilePath, SIZEOF(opt.LogFilePath)); + + //Notified statuses + char status[8]; + for (int i = ID_STATUS_MIN; i <= ID_STATUS_MAX2; i++) + { + wsprintfA(status, "%d", i); + DBWriteContactSettingByte(NULL, MODULE, status, (BYTE)IsDlgButtonChecked(hwndDlg, i)); + } + opt.FromOffline = IsDlgButtonChecked(hwndDlg, IDC_CHK_FROMOFFLINE); + + SaveOptions(); + return TRUE; + } + } + } + + return FALSE; +} + +void EnablePopupTextControls(HWND hwndDlg, BOOL bEnable) +{ + EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWALTDESCS), bEnable); + EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWPREVIOUSSTATUS), bEnable); + //EnableWindow(GetDlgItem(hwndDlg, IDC_READAWAYMSG), bEnable); +} + +INT_PTR CALLBACK DlgProcPopUpOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + + CheckDlgButton(hwndDlg, IDC_USEOWNCOLORS, (opt.Colors == POPUP_COLOR_OWN) ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_USEPOPUPCOLORS, (opt.Colors == POPUP_COLOR_POPUP) ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_USEWINCOLORS, (opt.Colors == POPUP_COLOR_WINDOWS) ? 1 : 0); + + for (int i = ID_STATUS_MIN; i <= ID_STATUS_MAX2 - 1; i++) + { + SendDlgItemMessage(hwndDlg, (i+2000), CPM_SETCOLOUR, 0, StatusList[Index(i)].colorBack); + SendDlgItemMessage(hwndDlg, (i+1000), CPM_SETCOLOUR, 0, StatusList[Index(i)].colorText); + EnableWindow(GetDlgItem(hwndDlg, (i+2000)), (opt.Colors == POPUP_COLOR_OWN)); + EnableWindow(GetDlgItem(hwndDlg, (i+1000)), (opt.Colors == POPUP_COLOR_OWN)); + } + + CheckDlgButton(hwndDlg, IDC_SHOWSTATUS, opt.ShowStatus); + CheckDlgButton(hwndDlg, IDC_SHOWALTDESCS, opt.UseAlternativeText); + CheckDlgButton(hwndDlg, IDC_READAWAYMSG, opt.ReadAwayMsg); + CheckDlgButton(hwndDlg, IDC_SHOWPREVIOUSSTATUS, opt.ShowPreviousStatus); + CheckDlgButton(hwndDlg, IDC_SHOWGROUP, opt.ShowGroup); + + SendDlgItemMessage(hwndDlg, IDC_TIMEOUT_VALUE, EM_LIMITTEXT, 3, 0); + SendDlgItemMessage(hwndDlg, IDC_TIMEOUT_VALUE_SPIN, UDM_SETRANGE32, -1, 999); + SetDlgItemInt(hwndDlg, IDC_TIMEOUT_VALUE, opt.PopupTimeout, TRUE); + + //Mouse actions + for (int i = 0; i < SIZEOF(PopupActions); i++) + { + SendMessage(GetDlgItem(hwndDlg, IDC_STATUS_LC), CB_SETITEMDATA, SendMessage(GetDlgItem(hwndDlg, IDC_STATUS_LC), CB_ADDSTRING, 0, (LPARAM)TranslateTS(PopupActions[i].Text)), PopupActions[i].Action); + SendMessage(GetDlgItem(hwndDlg, IDC_STATUS_RC), CB_SETITEMDATA, SendMessage(GetDlgItem(hwndDlg, IDC_STATUS_RC), CB_ADDSTRING, 0, (LPARAM)TranslateTS(PopupActions[i].Text)), PopupActions[i].Action); + } + + SendDlgItemMessage(hwndDlg, IDC_STATUS_LC, CB_SETCURSEL, opt.LeftClickAction, 0); + SendDlgItemMessage(hwndDlg, IDC_STATUS_RC, CB_SETCURSEL, opt.RightClickAction, 0); + + EnablePopupTextControls(hwndDlg, opt.ShowStatus); + + return TRUE; + } + case WM_COMMAND: + { + WORD idCtrl = LOWORD(wParam); + if (HIWORD(wParam) == CPN_COLOURCHANGED) + { + if(idCtrl > 40070) + { + COLORREF colour = SendDlgItemMessage(hwndDlg, idCtrl, CPM_GETCOLOUR, 0, 0); + if ((idCtrl > 41070) && (idCtrl < 42070)) //Text colour + StatusList[Index(idCtrl - 1000)].colorText = colour; + else //Background colour + StatusList[Index(idCtrl - 2000)].colorBack = colour; + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + return TRUE; + } + } + + if (HIWORD(wParam) == BN_CLICKED) + { + switch(idCtrl) + { + case IDC_USEOWNCOLORS: + case IDC_USEWINCOLORS: + case IDC_USEPOPUPCOLORS: + { + for (int i = ID_STATUS_MIN; i <= ID_STATUS_MAX2 - 1; i++) + { + EnableWindow(GetDlgItem(hwndDlg, (i+2000)), idCtrl == IDC_USEOWNCOLORS); //Background + EnableWindow(GetDlgItem(hwndDlg, (i+1000)), idCtrl == IDC_USEOWNCOLORS); //Text + } + + break; + } + case IDC_SHOWSTATUS: + { + EnablePopupTextControls(hwndDlg, IsDlgButtonChecked(hwndDlg, IDC_SHOWSTATUS)); + break; + } + case IDC_PREVIEW: + { + POPUPDATAT ppd = {0}; + ppd.iSeconds = opt.PopupTimeout; + + for (int i = ID_STATUS_MIN; i <= (ID_STATUS_MAX+1); i++) + { + WORD status = i <= ID_STATUS_MAX2 ? i : ID_STATUS_MIN; + ppd.lchIcon = LoadSkinnedIcon(StatusList[Index(status)].icon); + + _tcscpy(ppd.lptzContactName, (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)NULL, GSMDF_TCHAR)); + _tcscpy(ppd.lptzText, _T("")); + + if (opt.ShowStatus) + { + if (opt.UseAlternativeText == 1) + _tcscpy(ppd.lptzText, StatusList[Index(status)].lpzUStatusText); + else + _tcscpy(ppd.lptzText, StatusList[Index(status)].lpzStandardText); + + if (opt.ShowPreviousStatus) + { + TCHAR buff[MAX_STATUSTEXT]; + mir_sntprintf(buff, SIZEOF(buff), TranslateTS(STRING_SHOWPREVIOUSSTATUS), StatusList[Index(status)].lpzStandardText); + mir_sntprintf(ppd.lptzText, SIZEOF(ppd.lptzText), _T("%s %s"), ppd.lptzText, buff); + } + } + + if (opt.ReadAwayMsg) + { + if (ppd.lptzText[0]) _tcscat(ppd.lptzText, _T("\n")); + _tcscat(ppd.lptzText, TranslateT("This is status message")); + } + + switch (opt.Colors) + { + case POPUP_COLOR_WINDOWS: + ppd.colorBack = GetSysColor(COLOR_BTNFACE); + ppd.colorText = GetSysColor(COLOR_WINDOWTEXT); + break; + case POPUP_COLOR_OWN: + ppd.colorBack = StatusList[Index(status)].colorBack; + ppd.colorText = StatusList[Index(status)].colorText; + break; + case POPUP_COLOR_POPUP: + ppd.colorBack = ppd.colorText = 0; + break; + } + + PUAddPopUpT(&ppd); + } + + return FALSE; + } + } + } + + if ((HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == CBN_SELCHANGE || HIWORD(wParam) == EN_CHANGE) && (HWND)lParam == GetFocus()) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + + break; + } + case WM_NOTIFY: + { + if (((LPNMHDR)lParam)->code == PSN_APPLY) + { + char str[8]; + DWORD ctlColour = 0; + for (int i = ID_STATUS_MIN; i <= ID_STATUS_MAX2 - 1; i++) + { + ctlColour = SendDlgItemMessage(hwndDlg, (i+2000), CPM_GETCOLOUR, 0, 0); + StatusList[Index(i)].colorBack = SendDlgItemMessage(hwndDlg, (i+2000), CPM_GETCOLOUR, 0, 0); + wsprintfA(str, "%ibg", i); + DBWriteContactSettingDword(0, MODULE, str, ctlColour); + + ctlColour = SendDlgItemMessage(hwndDlg, (i+1000), CPM_GETCOLOUR, 0, 0); + StatusList[Index(i)].colorText = ctlColour; + wsprintfA(str, "%itx", i); + DBWriteContactSettingDword(0, MODULE, str, ctlColour); + } + + if (IsDlgButtonChecked(hwndDlg, IDC_USEOWNCOLORS)) + opt.Colors = POPUP_COLOR_OWN; + else if (IsDlgButtonChecked(hwndDlg, IDC_USEPOPUPCOLORS)) + opt.Colors = POPUP_COLOR_POPUP; + else + opt.Colors = POPUP_COLOR_WINDOWS; + + opt.ShowStatus = IsDlgButtonChecked(hwndDlg, IDC_SHOWSTATUS); + opt.UseAlternativeText = IsDlgButtonChecked(hwndDlg, IDC_SHOWALTDESCS); + opt.ReadAwayMsg = IsDlgButtonChecked(hwndDlg, IDC_READAWAYMSG); + opt.ShowPreviousStatus = IsDlgButtonChecked(hwndDlg, IDC_SHOWPREVIOUSSTATUS); + opt.ShowGroup = IsDlgButtonChecked(hwndDlg, IDC_SHOWGROUP); + opt.PopupTimeout = GetDlgItemInt(hwndDlg, IDC_TIMEOUT_VALUE, 0, TRUE); + opt.LeftClickAction = (BYTE)SendDlgItemMessage(hwndDlg, IDC_STATUS_LC, CB_GETCURSEL, 0, 0); + opt.RightClickAction = (BYTE)SendDlgItemMessage(hwndDlg, IDC_STATUS_RC, CB_GETCURSEL, 0, 0); + + SaveOptions(); + return TRUE; + } + + break; + } + } + + return FALSE; +} + +INT_PTR CALLBACK DlgProcAutoDisableOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + CheckDlgButton(hwndDlg, IDC_CHK_PGLOBAL, opt.DisablePopupGlobally); + CheckDlgButton(hwndDlg, IDC_CHK_SGLOBAL, opt.DisableSoundGlobally); + CheckDlgButton(hwndDlg, IDC_CHK_ONLYGLOBAL, opt.OnlyGlobalChanges); + + char str[8]; + for (int i = ID_STATUS_MIN; i <= ID_STATUS_MAX; i++) + { + wsprintfA(str, "p%d", i); + CheckDlgButton(hwndDlg, i, DBGetContactSettingByte(0, MODULE, str, 0)); + } + + for (int i = ID_STATUS_MIN; i <= ID_STATUS_MAX; i++) + { + wsprintfA(str, "s%d", i); + CheckDlgButton(hwndDlg, (i+2000),DBGetContactSettingByte(NULL, MODULE, str, 0)); + } + + return TRUE; + } + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_OK: + char str[8]; + opt.DisablePopupGlobally = IsDlgButtonChecked(hwndDlg, IDC_CHK_PGLOBAL); + opt.DisableSoundGlobally = IsDlgButtonChecked(hwndDlg, IDC_CHK_SGLOBAL); + opt.OnlyGlobalChanges = IsDlgButtonChecked(hwndDlg, IDC_CHK_ONLYGLOBAL); + + for (int i = ID_STATUS_MIN; i <= ID_STATUS_MAX; i++) + { + wsprintfA(str, "p%d", i); + DBWriteContactSettingByte(NULL, MODULE, str, IsDlgButtonChecked(hwndDlg, i)); + } + for (int i = ID_STATUS_MIN; i <= ID_STATUS_MAX; i++) + { + wsprintfA(str, "s%d", i); + DBWriteContactSettingByte(NULL, MODULE, str, IsDlgButtonChecked(hwndDlg, i+2000)); + } + + SaveOptions(); + //Fall through + case IDC_CANCEL: + DestroyWindow(hwndDlg); + break; + } + break; + } + case WM_CLOSE: + { + DestroyWindow(hwndDlg); + break; + } + } + + return FALSE; +} + +int ResetTemplatesToDefault(HWND hwndDlg) +{ + int result = MessageBox(hwndDlg, + TranslateT("Do you want to reset all templates to default?"), + TranslateT("Reset templates"), + MB_ICONQUESTION | MB_YESNO); + if (result == IDYES) + { + SetDlgItemText(hwndDlg, IDC_ED_TDELIMITER, DEFAULT_POPUP_DELIMITER); + SetDlgItemText(hwndDlg, IDC_ED_TCHANGE, DEFAULT_POPUP_NEW); + SetDlgItemText(hwndDlg, IDC_ED_TCHANGEMSG, DEFAULT_POPUP_CHANGEMSG); + SetDlgItemText(hwndDlg, IDC_ED_TREMOVE, DEFAULT_POPUP_REMOVE); + SetDlgItemText(hwndDlg, IDC_POPUPTEXT, TranslateT(DEFAULT_POPUP_STATUSMESSAGE)); + CheckDlgButton(hwndDlg, IDC_CHK_XSTATUSCHANGE, 1); + CheckDlgButton(hwndDlg, IDC_CHK_MSGCHANGE, 1); + CheckDlgButton(hwndDlg, IDC_CHK_REMOVE, 1); + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_TCHANGE), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_TCHANGEMSG), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_TREMOVE), TRUE); + } + + return result; +} + +INT_PTR CALLBACK DlgProcXPopupOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + + SendDlgItemMessage(hwndDlg, IDC_ED_MSGLEN, EM_LIMITTEXT, 3, 0); + SendDlgItemMessage(hwndDlg, IDC_UD_MSGLEN, UDM_SETRANGE, 0, MAKELONG(999, 1)); + + CheckDlgButton(hwndDlg, IDC_CHK_DISABLEMUSIC, opt.PDisableForMusic); + CheckDlgButton(hwndDlg, IDC_CHK_CUTMSG, opt.PTruncateMsg); + SetDlgItemInt(hwndDlg, IDC_ED_MSGLEN, opt.PMsgLen, FALSE); + + // Templates + CheckDlgButton(hwndDlg, IDC_CHK_XSTATUSCHANGE, templates.PopupFlags & NOTIFY_NEW_XSTATUS ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_CHK_MSGCHANGE, templates.PopupFlags & NOTIFY_NEW_MESSAGE ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_CHK_REMOVE, templates.PopupFlags & NOTIFY_REMOVE ? 1 : 0); + + SetDlgItemText(hwndDlg, IDC_ED_TDELIMITER, templates.PopupDelimiter); + SetDlgItemText(hwndDlg, IDC_ED_TCHANGE, templates.PopupNewXstatus); + SetDlgItemText(hwndDlg, IDC_ED_TCHANGEMSG, templates.PopupNewMsg); + SetDlgItemText(hwndDlg, IDC_ED_TREMOVE, templates.PopupRemove); + + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_TCHANGE), templates.PopupFlags & NOTIFY_NEW_XSTATUS); + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_TCHANGEMSG), templates.PopupFlags & NOTIFY_NEW_MESSAGE); + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_TREMOVE), templates.PopupFlags & NOTIFY_REMOVE); + + // Buttons + SendDlgItemMessage(hwndDlg, IDC_BT_VARIABLES, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Show available variables"), BATF_TCHAR); + HICON hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_VARIABLES)); + SendDlgItemMessage(hwndDlg, IDC_BT_VARIABLES, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); + DestroyIcon(hIcon); + + SendDlgItemMessage(hwndDlg, IDC_BT_RESET, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Reset all templates to default"), BATF_TCHAR); + hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_RESET)); + SendDlgItemMessage(hwndDlg, IDC_BT_RESET, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); + DestroyIcon(hIcon); + + return TRUE; + } + case WM_COMMAND: + { + switch (HIWORD(wParam)) + { + case BN_CLICKED: + { + switch (LOWORD(wParam)) + { + case IDC_CHK_CUTMSG: + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_MSGLEN), IsDlgButtonChecked(hwndDlg, IDC_CHK_CUTMSG)); + break; + case IDC_CHK_XSTATUSCHANGE: + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_TCHANGE), IsDlgButtonChecked(hwndDlg, IDC_CHK_XSTATUSCHANGE)); + break; + case IDC_CHK_MSGCHANGE: + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_TCHANGEMSG), IsDlgButtonChecked(hwndDlg, IDC_CHK_MSGCHANGE)); + break; + case IDC_CHK_REMOVE: + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_TREMOVE), IsDlgButtonChecked(hwndDlg, IDC_CHK_REMOVE)); + break; + case IDC_BT_VARIABLES: + MessageBox(hwndDlg, VARIABLES_HELP_TEXT, TranslateT("Variables"), MB_OK | MB_ICONINFORMATION); + break; + case IDC_BT_RESET: + if (ResetTemplatesToDefault(hwndDlg) == IDYES) break; + else return FALSE; + } + + if (LOWORD(wParam) != IDC_BT_VARIABLES) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + + break; + } + case EN_CHANGE: + { + if ((HWND)lParam == GetFocus()) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + } + + } + + return TRUE; + } + case WM_NOTIFY: + { + if (((LPNMHDR)lParam)->code == PSN_APPLY ) + { + opt.PDisableForMusic = IsDlgButtonChecked(hwndDlg, IDC_CHK_DISABLEMUSIC); + opt.PTruncateMsg = IsDlgButtonChecked(hwndDlg, IDC_CHK_CUTMSG); + opt.PMsgLen = GetDlgItemInt(hwndDlg, IDC_ED_MSGLEN, 0, FALSE); + + templates.PopupFlags = 0; + templates.PopupFlags |= (IsDlgButtonChecked(hwndDlg, IDC_CHK_XSTATUSCHANGE) ? NOTIFY_NEW_XSTATUS : 0) | + (IsDlgButtonChecked(hwndDlg, IDC_CHK_MSGCHANGE) ? NOTIFY_NEW_MESSAGE : 0) | + (IsDlgButtonChecked(hwndDlg, IDC_CHK_REMOVE) ? NOTIFY_REMOVE : 0); + + // Templates + GetDlgItemText(hwndDlg, IDC_ED_TDELIMITER, templates.PopupDelimiter, SIZEOF(templates.PopupDelimiter)); + GetDlgItemText(hwndDlg, IDC_ED_TCHANGE, templates.PopupNewXstatus, SIZEOF(templates.PopupNewXstatus)); + GetDlgItemText(hwndDlg, IDC_ED_TCHANGEMSG, templates.PopupNewMsg, SIZEOF(templates.PopupNewMsg)); + GetDlgItemText(hwndDlg, IDC_ED_TREMOVE, templates.PopupRemove, SIZEOF(templates.PopupRemove)); + + // Save options to db + SaveOptions(); + SaveTemplates(); + } + + return TRUE; + } + } + + return FALSE; +} + +bool IsSuitableProto( PROTOACCOUNT* pa ) +{ + if ( pa == NULL ) + return false; + + if ( pa->bDynDisabled || !pa->bIsEnabled ) + return false; + + if ( CallProtoService( pa->szProtoName, PS_GETCAPS, PFLAGNUM_2, 0 ) == 0 ) + return false; + + return true; +} + +INT_PTR CALLBACK DlgProcSMPopupOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + { + CheckDlgButton(hwndDlg, IDC_ONCONNECT, opt.PopupOnConnect); + CheckDlgButton(hwndDlg, IDC_PUIGNOREREMOVE, opt.IgnoreEmpty); + + // Buttons + SendDlgItemMessage(hwndDlg, IDC_BT_VARIABLES, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Show available variables"), BATF_TCHAR); + HICON hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_VARIABLES)); + SendDlgItemMessage(hwndDlg, IDC_BT_VARIABLES, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); + DestroyIcon(hIcon); + + SendDlgItemMessage(hwndDlg, IDC_BT_RESET, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Reset all templates to default"), BATF_TCHAR); + hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_RESET)); + SendDlgItemMessage(hwndDlg, IDC_BT_RESET, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); + DestroyIcon(hIcon); + + // proto list + HWND hList = GetDlgItem(hwndDlg, IDC_PROTOCOLLIST); + SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES); + LVCOLUMN lvCol = {0}; + lvCol.mask = LVCF_WIDTH|LVCF_TEXT; + lvCol.pszText=TranslateT("Protocol"); + lvCol.cx = 118; + ListView_InsertColumn(hList, 0, &lvCol); + // fill the list + LVITEM lvItem = {0}; + lvItem.mask=LVIF_TEXT|LVIF_PARAM; + lvItem.iItem=0; + lvItem.iSubItem=0; + + int count; + PROTOACCOUNT** protos; + ProtoEnumAccounts( &count, &protos ); + + for(int i=0; i < count; i++) { + if ( !IsSuitableProto( protos[i] )) + continue; + + UpdateListFlag = TRUE; + lvItem.pszText = protos[i]->tszAccountName; + lvItem.lParam = (LPARAM)protos[i]->szModuleName; + PROTOTEMPLATE *prototemplate = (PROTOTEMPLATE *)mir_alloc(sizeof(PROTOTEMPLATE)); + prototemplate->ProtoName = protos[i]->tszAccountName; + TCHAR protoname[MAX_PATH] = {0}; + mir_sntprintf(protoname, SIZEOF(protoname), _T("%s_TSMChange"), protos[i]->tszAccountName); + char *szprotoname = mir_t2a(protoname); + DBVARIANT dbVar = {0}; + DBGetContactSettingTString(NULL, MODULE, szprotoname, &dbVar); + if (lstrcmp(dbVar.ptszVal, NULL) == 0) { + DBFreeVariant(&dbVar); + _tcsncpy(prototemplate->ProtoTemplate, TranslateT(DEFAULT_POPUP_STATUSMESSAGE), SIZEOF(prototemplate->ProtoTemplate)); + } + else _tcsncpy(prototemplate->ProtoTemplate, dbVar.ptszVal, SIZEOF(prototemplate->ProtoTemplate)); + + mir_free(szprotoname); + ListView_InsertItem(hList,&lvItem); + ProtoTemplates.insert(prototemplate, ProtoTemplates.getCount()); + + char dbSetting[128]; + mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_enabled", protos[i]->szModuleName); + ListView_SetCheckState(hList, lvItem.iItem, DBGetContactSettingByte(NULL, MODULE, dbSetting, TRUE)); + lvItem.iItem++; + } + UpdateListFlag = FALSE; + } + return TRUE; + + case WM_COMMAND: + switch (HIWORD(wParam)) { + case BN_CLICKED: + switch (LOWORD(wParam)) { + case IDC_BT_VARIABLES: + MessageBox(0, VARIABLES_SM_HELP_TEXT, TranslateT("Variables"), MB_OK | MB_ICONINFORMATION); + break; + + case IDC_BT_RESET: + if (ResetTemplatesToDefault(hwndDlg) == IDYES) break; + else return FALSE; + } + + if (LOWORD(wParam) != IDC_BT_VARIABLES) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + + break; + + case EN_CHANGE: + if ((HWND)lParam == GetFocus()) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + } + return TRUE; + + case WM_NOTIFY: + if (((NMHDR*)lParam)->idFrom == IDC_PROTOCOLLIST) { + switch(((NMHDR*)lParam)->code) { + case LVN_ITEMCHANGED: + { + NMLISTVIEW *nmlv = (NMLISTVIEW *)lParam; + if (nmlv->uNewState == 3 && !UpdateListFlag) + { + HWND hList = GetDlgItem(hwndDlg,IDC_PROTOCOLLIST); + PROTOTEMPLATE *prototemplate; + if (ListView_GetHotItem(hList) != ListView_GetSelectionMark(hList)) { + prototemplate = ProtoTemplates[ListView_GetSelectionMark(hList)]; + GetDlgItemText(hwndDlg, IDC_POPUPTEXT, prototemplate->ProtoTemplate, MAX_PATH); + ProtoTemplates.remove( ListView_GetSelectionMark(hList)); + ProtoTemplates.insert(prototemplate, ListView_GetSelectionMark(hList)); + + } + LastItem = ListView_GetHotItem(hList); + prototemplate = ProtoTemplates[LastItem]; + SetDlgItemText(hwndDlg, IDC_POPUPTEXT, prototemplate->ProtoTemplate); + } + if ((nmlv->uNewState^nmlv->uOldState)&LVIS_STATEIMAGEMASK && !UpdateListFlag) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + break; + } + } + + if (((LPNMHDR)lParam)->code == PSN_APPLY ) { + opt.IgnoreEmpty = IsDlgButtonChecked(hwndDlg, IDC_PUIGNOREREMOVE); + opt.PopupOnConnect = IsDlgButtonChecked(hwndDlg, IDC_ONCONNECT); + + // Templates + PROTOTEMPLATE *prototemplate = ProtoTemplates[LastItem]; + GetDlgItemText(hwndDlg, IDC_POPUPTEXT, prototemplate->ProtoTemplate, MAX_PATH); + ProtoTemplates.remove(LastItem); + ProtoTemplates.insert(prototemplate, LastItem); + + // Save options to db + SaveOptions(); + SaveTemplates(); + HWND hList = GetDlgItem(hwndDlg,IDC_PROTOCOLLIST); + LVITEM lvItem = {0}; + lvItem.mask=LVIF_PARAM; + for (int i=0;icode == PSN_APPLY ) + { + opt.EnableLogging = IsDlgButtonChecked(hwndDlg, IDC_CHK_LOGGING); + opt.KeepInHistory = IsDlgButtonChecked(hwndDlg, IDC_CHK_SAVETOHISTORY); + opt.PreventIdentical = IsDlgButtonChecked(hwndDlg, IDC_CHK_PREVENTIDENTICAL); + opt.LDisableForMusic = IsDlgButtonChecked(hwndDlg, IDC_CHK_DISABLEMUSIC); + opt.LTruncateMsg = IsDlgButtonChecked(hwndDlg, IDC_CHK_CUTMSG); + opt.LMsgLen = GetDlgItemInt(hwndDlg, IDC_ED_MSGLEN, 0, FALSE); + + templates.LogFlags = 0; + templates.LogFlags |= (IsDlgButtonChecked(hwndDlg, IDC_CHK_XSTATUSCHANGE) ? NOTIFY_NEW_XSTATUS : 0) | + (IsDlgButtonChecked(hwndDlg, IDC_CHK_MSGCHANGE) ? NOTIFY_NEW_MESSAGE : 0) | + (IsDlgButtonChecked(hwndDlg, IDC_CHK_REMOVE) ? NOTIFY_REMOVE : 0) | + (IsDlgButtonChecked(hwndDlg, IDC_CHK_OPENING) ? NOTIFY_OPENING_ML : 0); + + // Templates + GetDlgItemText(hwndDlg, IDC_ED_TDELIMITER, templates.LogDelimiter, SIZEOF(templates.LogDelimiter)); + GetDlgItemText(hwndDlg, IDC_ED_TCHANGE, templates.LogNewXstatus, SIZEOF(templates.LogNewXstatus)); + GetDlgItemText(hwndDlg, IDC_ED_TCHANGEMSG, templates.LogNewMsg, SIZEOF(templates.LogNewMsg)); + GetDlgItemText(hwndDlg, IDC_ED_TREMOVE, templates.LogRemove, SIZEOF(templates.LogRemove)); + GetDlgItemText(hwndDlg, IDC_ED_TOPENING, templates.LogOpening, SIZEOF(templates.LogOpening)); + + SaveOptions(); + SaveTemplates(); + } + return TRUE; + } + } + + return FALSE; +} + +int OptionsInitialize(WPARAM wParam, LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp = {0}; + + odp.cbSize = sizeof(odp); + odp.position = -100000000; + odp.hInstance = hInst; + odp.flags = ODPF_BOLDGROUPS; + odp.pszTitle = LPGEN("Status Notify"); + odp.pszGroup = LPGEN("Status"); + odp.pszTab = LPGEN("General"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_GENERAL); + odp.pfnDlgProc = DlgProcGeneralOpts; + Options_AddPage(wParam, &odp); + + odp.pszTab = LPGEN("Filtering"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_FILTERS); + odp.pfnDlgProc = DlgProcFiltering; + Options_AddPage(wParam, &odp); + + odp.pszTab = LPGEN("Message log"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_XLOG); + odp.pfnDlgProc = DlgProcXLogOpts; + Options_AddPage(wParam, &odp); + + if (ServiceExists(MS_POPUP_ADDPOPUP)) { + odp.pszTitle = LPGEN("Status Notify"); + odp.pszGroup = LPGEN("Popups"); + odp.pszTab = LPGEN("General"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_POPUP); + odp.pfnDlgProc = DlgProcPopUpOpts; + Options_AddPage(wParam, &odp); + + odp.pszTab = LPGEN("Extra status"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_XPOPUP); + odp.pfnDlgProc = DlgProcXPopupOpts; + Options_AddPage(wParam, &odp); + + odp.pszTab = LPGEN("Status message"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SMPOPUP); + odp.pfnDlgProc = DlgProcSMPopupOpts; + Options_AddPage(wParam, &odp); + } + + return 0; +} \ No newline at end of file diff --git a/plugins/NewXstatusNotify/src/options.h b/plugins/NewXstatusNotify/src/options.h new file mode 100644 index 0000000000..59c1bfff4f --- /dev/null +++ b/plugins/NewXstatusNotify/src/options.h @@ -0,0 +1,90 @@ +/* + NewXstatusNotify YM - Plugin for Miranda IM + Copyright (c) 2001-2004 Luca Santarelli + Copyright (c) 2005-2007 Vasilich + Copyright (c) 2007-2011 yaho + + 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 +*/ + +#ifndef OPTIONS_H +#define OPTIONS_H + +#include "common.h" + +#define DEFAULT_LOGFILE "NewStatusNotify.log" + +typedef struct tagOPTIONS { + // IDD_OPT_POPUP + BYTE Colors; + BYTE ShowGroup; + BYTE ShowStatus; + BYTE UseAlternativeText; + BYTE ShowPreviousStatus; + BYTE ReadAwayMsg; + int PopupTimeout; + BYTE LeftClickAction; + BYTE RightClickAction; + // IDD_OPT_XPOPUP + BYTE PDisableForMusic; + BYTE PTruncateMsg; + DWORD PMsgLen; + // IDD_OPT_GENERAL + BYTE FromOffline; + BYTE AutoDisable; + BYTE HiddenContactsToo; + BYTE UseIndSnd; + BYTE BlinkIcon; + BYTE BlinkIcon_Status; + BYTE Log; + TCHAR LogFilePath[MAX_PATH]; + // IDD_AUTODISABLE + BYTE OnlyGlobalChanges; + BYTE DisableSoundGlobally; + BYTE DisablePopupGlobally; + // IDD_OPT_XLOG + BYTE EnableLogging; + BYTE PreventIdentical; + BYTE KeepInHistory; + BYTE LDisableForMusic; + BYTE LTruncateMsg; + DWORD LMsgLen; + //IDD_OPT_SMPOPUP + BYTE PopupOnConnect; + BYTE IgnoreEmpty; + // OTHER + BYTE TempDisabled; + BYTE PopupAutoDisabled; + BYTE SoundAutoDisabled; +} OPTIONS; + +typedef struct tagTEMPLATES { + BYTE PopupFlags; + BYTE LogFlags; + TCHAR PopupDelimiter[32]; + TCHAR PopupNewXstatus[256]; + TCHAR PopupNewMsg[256]; + TCHAR PopupRemove[256]; + TCHAR LogDelimiter[32]; + TCHAR LogNewXstatus[256]; + TCHAR LogNewMsg[256]; + TCHAR LogRemove[256]; + TCHAR LogOpening[256]; +} TEMPLATES; + +int OptionsInitialize(WPARAM wParam, LPARAM lParam); +void LoadOptions(); + +#endif \ No newline at end of file diff --git a/plugins/NewXstatusNotify/src/popup.cpp b/plugins/NewXstatusNotify/src/popup.cpp new file mode 100644 index 0000000000..c8e7d32e32 --- /dev/null +++ b/plugins/NewXstatusNotify/src/popup.cpp @@ -0,0 +1,175 @@ +/* + NewXstatusNotify YM - Plugin for Miranda IM + Copyright (c) 2001-2004 Luca Santarelli + Copyright (c) 2005-2007 Vasilich + Copyright (c) 2007-2011 yaho + + 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 "common.h" +#include "popup.h" +#include "options.h" +#include "utils.h" + +extern OPTIONS opt; + +void QueryAwayMessage(HWND hWnd, PLUGINDATA *pdp) +{ + HANDLE hContact = PUGetContact(hWnd); + char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (szProto) + { + if ((CallProtoService(szProto, PS_GETCAPS,PFLAGNUM_1, 0) & PF1_MODEMSGRECV) && + (CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_3, 0) & Proto_Status2Flag(pdp->newStatus))) + { + //The following HookEventMessage will hook the ME_PROTO_ACK event and send a WM_AWAYMSG to hWnd when the hooks get notified. + pdp->hAwayMsgHook = HookEventMessage(ME_PROTO_ACK, hWnd, WM_AWAYMSG); + //The following instruction asks Miranda to retrieve the away message and associates a hProcess (handle) to this request. This handle will appear in the ME_PROTO_ACK event. + pdp->hAwayMsgProcess = (HANDLE)CallContactService(hContact, PSS_GETAWAYMSG, 0, 0); + } + } +} + +void ReceivedAwayMessage(HWND hWnd, LPARAM lParam, PLUGINDATA * pdp) +{ + ACKDATA *ack = (ACKDATA *)lParam; + if (ack->type != ACKTYPE_AWAYMSG || ack->hProcess != pdp->hAwayMsgProcess) + return; + + //The first thing we go is removing the hook from the chain to avoid useless calls. + UnhookEvent(pdp->hAwayMsgHook); + pdp->hAwayMsgHook = NULL; + + if (ack->result != ACKRESULT_SUCCESS) + return; + + DBVARIANT dbv; + HANDLE hContact = PUGetContact(hWnd); + + if ( DBGetContactSettingTString(hContact, MODULE, "LastPopupText", &dbv)) + return; + + TCHAR stzText[MAX_SECONDLINE], *tszStatus = (TCHAR*)ack->lParam; + _tcscpy(stzText, dbv.ptszVal); + DBFreeVariant(&dbv); + + if (tszStatus == NULL || *tszStatus == 0) + return; + + if (stzText[0]) + _tcscat(stzText, _T("\n")); + _tcscat(stzText, tszStatus); + SendMessage(hWnd, WM_SETREDRAW, FALSE, 0); + PUChangeTextT(hWnd, stzText); + SendMessage(hWnd, WM_SETREDRAW, TRUE, 0); +} + +void PopupAction(HWND hWnd, BYTE action) +{ + HANDLE hContact = PUGetContact(hWnd); + if (hContact && hContact != INVALID_HANDLE_VALUE) { + switch (action) { + case PCA_OPENMESSAGEWND: + CallServiceSync(ServiceExists("SRMsg/LaunchMessageWindow") ? "SRMsg/LaunchMessageWindow" : MS_MSG_SENDMESSAGE, (WPARAM)hContact, 0); + break; + + case PCA_OPENMENU: + { + POINT pt = {0}; + HMENU hMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)hContact, 0); + GetCursorPos(&pt); + TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hWnd, NULL); + DestroyMenu(hMenu); + } + return; + + case PCA_OPENDETAILS: + CallServiceSync(MS_USERINFO_SHOWDIALOG, (WPARAM)hContact, 0); + break; + + case PCA_OPENHISTORY: + CallServiceSync(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM)hContact, 0); + break; + + case PCA_CLOSEPOPUP: + break; + + case PCA_DONOTHING: + return; + } + + PUDeletePopUp(hWnd); + } +} + +INT_PTR CALLBACK PopupDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + PLUGINDATA *pdp = NULL; + + switch(message) + { + case WM_MEASUREITEM: //Needed by the contact's context menu + return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam); + + case WM_DRAWITEM: //Needed by the contact's context menu + return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam); + + case WM_COMMAND: + //This one returns TRUE if it processed the menu command, and FALSE if it did not process it. + if (CallServiceSync(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM)PUGetContact(hwnd))) + break; + + PopupAction(hwnd, opt.LeftClickAction); + break; + + case WM_CONTEXTMENU: + PopupAction(hwnd, opt.RightClickAction); + break; + + case UM_FREEPLUGINDATA: + pdp = (PLUGINDATA *)PUGetPluginData(hwnd); + if (pdp != NULL) { + if (pdp->hAwayMsgHook != NULL) { + UnhookEvent(pdp->hAwayMsgHook); + pdp->hAwayMsgHook = NULL; + } + + mir_free(pdp); + } + return FALSE; + + case UM_INITPOPUP: + pdp = (PLUGINDATA *)PUGetPluginData(hwnd); + if (pdp != NULL) { + char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)PUGetContact(hwnd), 0); + if (szProto && opt.ReadAwayMsg && StatusHasAwayMessage(szProto, pdp->newStatus)) { + WORD myStatus = (WORD)CallProtoService(szProto, PS_GETSTATUS, 0, 0); + if (myStatus != ID_STATUS_INVISIBLE) + QueryAwayMessage(hwnd, pdp); + } + } + + return FALSE; + + case WM_AWAYMSG: //We're here because ME_PROTO_ACK has been hooked to this window (too!). + pdp = (PLUGINDATA *)PUGetPluginData(hwnd); + if (pdp != NULL) + ReceivedAwayMessage(hwnd, lParam, pdp); + return FALSE; + } + + return DefWindowProc(hwnd, message, wParam, lParam); +} diff --git a/plugins/NewXstatusNotify/src/popup.h b/plugins/NewXstatusNotify/src/popup.h new file mode 100644 index 0000000000..e6e56f6c5b --- /dev/null +++ b/plugins/NewXstatusNotify/src/popup.h @@ -0,0 +1,54 @@ +/* + NewXstatusNotify YM - Plugin for Miranda IM + Copyright (c) 2001-2004 Luca Santarelli + Copyright (c) 2005-2007 Vasilich + Copyright (c) 2007-2011 yaho + + 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 +*/ + +#ifndef POPUP_H +#define POPUP_H + +#define POPUP_COLOR_OWN 1 +#define POPUP_COLOR_WINDOWS 2 +#define POPUP_COLOR_POPUP 3 +#define DEFAULT_COLORS POPUP_COLOR_POPUP + +// Actions on popup click +#define PCA_OPENMESSAGEWND 0 // open message window +#define PCA_CLOSEPOPUP 1 // close popup +#define PCA_OPENDETAILS 2 // open contact details window +#define PCA_OPENMENU 3 // open contact menu +#define PCA_OPENHISTORY 4 // open contact history +#define PCA_DONOTHING 5 // do nothing + +#define STRING_SHOWPREVIOUSSTATUS _T("(was %s)") + +static struct { + TCHAR *Text; + int Action; +} PopupActions[] = { + _T("Open message window"), PCA_OPENMESSAGEWND, + _T("Close popup"), PCA_CLOSEPOPUP, + _T("Open contact details window"), PCA_OPENDETAILS, + _T("Open contact menu"), PCA_OPENMENU, + _T("Open contact history"), PCA_OPENHISTORY, + _T("Do nothing"), PCA_DONOTHING +}; + +INT_PTR CALLBACK PopupDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +#endif \ No newline at end of file diff --git a/plugins/NewXstatusNotify/src/resource.h b/plugins/NewXstatusNotify/src/resource.h new file mode 100644 index 0000000000..b68a263716 --- /dev/null +++ b/plugins/NewXstatusNotify/src/resource.h @@ -0,0 +1,147 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by resource.rc +// +#define IDD_OPT_XPOPUP 101 +#define IDD_INFO_SOUNDS 102 +#define IDD_OPT_GENERAL 103 +#define IDI_RESET 109 +#define IDI_VARIABLES 110 +#define IDD_AUTODISABLE 113 +#define IDD_OPT_FILTERS 114 +#define IDD_OPT_POPUP 115 +#define IDD_OPT_XLOG 116 +#define IDI_POPUP 117 +#define IDD_OPT_SMPOPUP 117 +#define IDI_SOUND 118 +#define IDI_LOGGING 119 +#define IDI_XSTATUS 120 +#define IDI_DISABLEALL 121 +#define IDI_ENABLEALL 122 +#define IDI_NOTIFICATION_OFF 123 +#define IDI_NOTIFICATION_ON 124 +#define IDI_STATUS_MESSAGE 125 +#define IDC_STATUS_STATIC_INFINITE 1002 +#define IDC_STATUS_STATIC_DEFAULT 1003 +#define IDC_TIMEOUT_VALUE_SPIN 1004 +#define IDC_STATUS_STATIC_SEC 1005 +#define IDC_STATUS_LC 1006 +#define IDC_USEWINCOLORS 1007 +#define IDC_STATUS_RC 1008 +#define IDC_READAWAYMSG 1011 +#define IDC_CHK_DISABLEMUSIC 1011 +#define IDC_SHOWPREVIOUSSTATUS 1012 +#define IDC_CHK_CUTMSG 1012 +#define IDC_USEPOPUPCOLORS 1013 +#define IDC_ED_MSGLEN 1013 +#define IDC_ED_TOPENING 1018 +#define IDC_ED_TCHANGE 1024 +#define IDC_ED_TCHANGEMSG 1025 +#define IDC_BT_VARIABLES 1028 +#define IDC_BT_RESET 1029 +#define IDC_PREVIEW 1030 +#define IDC_CHANGE 1031 +#define IDC_CHK_MSGCHANGE 1031 +#define IDC_DELETE 1032 +#define IDC_CHK_XSTATUSCHANGE 1032 +#define IDC_CHK_OPENING 1033 +#define IDC_UD_MSGLEN 1034 +#define IDC_CHK_PGLOBAL 1035 +#define IDC_CHK_SGLOBAL 1036 +#define IDC_CHK_ONLYGLOBAL 1037 +#define IDC_HYPERLINK 1038 +#define IDC_CHK_REMOVE 1039 +#define IDC_ED_TREMOVE 1040 +#define IDC_ED_TDELIMITER 1042 +#define IDC_INDSNDLIST 1044 +#define IDC_HIDDENCONTACTSTOO 1052 +#define IDC_USEINDIVSOUNDS 1053 +#define IDC_OK 1055 +#define IDC_CANCEL 1056 +#define IDC_CONFIGUREAUTODISABLE 1057 +#define IDC_AUTODISABLE 1060 +#define IDC_LOG 1061 +#define IDC_TIMEOUT_VALUE 1066 +#define IDC_BLINKICON 1067 +#define IDC_BLINKICON_STATUS 1068 +#define IDC_SOUNDICON 1069 +#define IDC_POPUPICON 1070 +#define IDC_CHECK_NOTIFYSOUNDS 1071 +#define IDC_CHECK_NOTIFYPOPUPS 1073 +#define IDC_TEXT_ENABLE_IS 1074 +#define IDC_USEOWNCOLORS 1076 +#define IDC_SHOWALTDESCS 1077 +#define IDC_LOGGINGICON 1078 +#define IDC_SHOWSTATUS 1078 +#define IDC_XSTATUSICON 1079 +#define IDC_DISABLEALLICON 1080 +#define IDC_ENABLEALLICON 1081 +#define IDC_SHOWGROUP 1082 +#define IDC_STATUSMESSAGEICON 1082 +#define IDC_ONCONNECT 1101 +#define IDC_PUIGNOREREMOVE 1102 +#define IDC_POPUPTEXT 1115 +#define IDC_PROTOCOLLIST 1207 +#define IDC_LOGFILE 2029 +#define IDC_BT_CHOOSELOGFILE 2030 +#define IDC_BT_VIEWLOG 2031 +#define IDC_CHK_LOGGING 2034 +#define IDC_CHK_SAVETOHISTORY 2039 +#define IDC_CHK_PREVENTIDENTICAL 2040 +#define IDC_CHK_OFFLINE 40071 +#define IDC_CHK_ONLINE 40072 +#define IDC_CHK_AWAY 40073 +#define IDC_CHK_DND 40074 +#define IDC_CHK_NA 40075 +#define IDC_CHK_OCCUPIED 40076 +#define IDC_CHK_FREECHAT 40077 +#define IDC_CHK_INVISIBLE 40078 +#define IDC_CHK_ONTHEPHONE 40079 +#define IDC_CHK_OUTTOLUNCH 40080 +#define IDC_CHK_XSTATUS 40081 +#define IDC_CHK_STATUS_MESSAGE 40082 +#define IDC_CHK_FROMOFFLINE 40083 +#define IDC_OFFLINE_TX 41071 +#define IDC_ONLINE_TX 41072 +#define IDC_AWAY_TX 41073 +#define IDC_DND_TX 41074 +#define IDC_NA_TX 41075 +#define IDC_OCCUPIED_TX 41076 +#define IDC_FREEFORCHAT_TX 41077 +#define IDC_INVISIBLE_TX 41078 +#define IDC_ONTHEPHONE_TX 41079 +#define IDC_OUTTOLUNCH_TX 41080 +#define IDC_XSTATUS_TX 41081 +#define IDC_STATUSMESSAGE_TX 41082 +#define IDC_OFFLINE_BG 42071 +#define IDC_ONLINE_BG 42072 +#define IDC_CHK_ONLINE2 42072 +#define IDC_AWAY_BG 42073 +#define IDC_CHK_AWAY2 42073 +#define IDC_DND_BG 42074 +#define IDC_CHK_DND2 42074 +#define IDC_NA_BG 42075 +#define IDC_CHK_NA2 42075 +#define IDC_OCCUPIED_BG 42076 +#define IDC_CHK_OCCUPIED2 42076 +#define IDC_FREEFORCHAT_BG 42077 +#define IDC_CHK_FREECHAT2 42077 +#define IDC_INVISIBLE_BG 42078 +#define IDC_CHK_INVISIBLE2 42078 +#define IDC_ONTHEPHONE_BG 42079 +#define IDC_CHK_ONTHEPHONE2 42079 +#define IDC_OUTTOLUNCH_BG 42080 +#define IDC_CHK_OUTTOLUNCH2 42080 +#define IDC_XSTATUS_BG 42081 +#define IDC_STATUSMESSAGE_BG 42082 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 111 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1044 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/NewXstatusNotify/src/utils.cpp b/plugins/NewXstatusNotify/src/utils.cpp new file mode 100644 index 0000000000..bfa8184ddf --- /dev/null +++ b/plugins/NewXstatusNotify/src/utils.cpp @@ -0,0 +1,124 @@ +/* + NewXstatusNotify YM - Plugin for Miranda IM + Copyright (c) 2001-2004 Luca Santarelli + Copyright (c) 2005-2007 Vasilich + Copyright (c) 2007-2011 yaho + + 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 "common.h" +#include "options.h" + +extern OPTIONS opt; +extern STATUS StatusList[STATUS_COUNT]; + +TCHAR *db2t(DBVARIANT *dbv) +{ + TCHAR *buff; + switch (dbv->type) + { + case DBVT_ASCIIZ: buff = mir_a2t(dbv->pszVal); break; + case DBVT_WCHAR: buff = mir_tstrdup(dbv->ptszVal); break; + case DBVT_UTF8: buff = mir_utf8decodeT(dbv->pszVal); break; + default: buff = mir_tstrdup(_T("")); + } + + if (buff[0] == 0) + { + mir_free(buff); + buff = NULL; + } + + return buff; +} + +int DBGetStringDefault(HANDLE hContact, const char *szModule, const char *szSetting, TCHAR *setting, int size, const TCHAR *defaultValue) +{ + DBVARIANT dbv; + if (!DBGetContactSettingTString(hContact, szModule, szSetting, &dbv)) + { + _tcsncpy(setting, dbv.ptszVal, size); + DBFreeVariant(&dbv); + return 0; + } + + _tcsncpy(setting, defaultValue, size); + return 1; +} + +void HigherLower(int maxValue, int minValue) +{ + TCHAR str[64] = { 0 }; + wsprintf(str, TranslateT("You cannot specify a value lower than %d and higher than %d."), minValue, maxValue); +} + +void ShowLog(TCHAR *file) +{ + int res = (int)ShellExecute(NULL, _T("open"), file, NULL, NULL, SW_SHOW); + if (res <= 32) // error + MessageBox(0, TranslateT("Can't open the log file!"), TranslateT("NewXstatusNotify"), MB_OK | MB_ICONERROR); +} + +int ProtoServiceExists(const char *szModule, const char *szService) +{ + char str[MAXMODULELABELLENGTH]; + if (szModule == NULL || szService == NULL) + return 0; + + strcpy(str,szModule); + strcat(str,szService); + return ServiceExists(str); +} + +BOOL StatusHasAwayMessage(char *szProto, int status) +{ + if (szProto != NULL) + { + unsigned long iSupportsSM = (unsigned long)CallProtoService(szProto, PS_GETCAPS, (WPARAM)PFLAGNUM_3, (LPARAM)0); + return (iSupportsSM & Proto_Status2Flag(status)) ? TRUE : FALSE; + } + else + { + switch (status) + { + case ID_STATUS_AWAY: + case ID_STATUS_NA: + case ID_STATUS_OCCUPIED: + case ID_STATUS_DND: + case ID_STATUS_FREECHAT: + case ID_STATUS_ONTHEPHONE: + case ID_STATUS_OUTTOLUNCH: + return TRUE; + default: + return FALSE; + } + } +} + +void LogToFile(TCHAR *stzText) +{ + FILE *fp = _tfopen(opt.LogFilePath, _T("a+b, ccs=UTF-8")); + if (fp) + { + char *encodedText = mir_utf8encodeT(stzText); + if (encodedText) + { + fprintf(fp, encodedText); + mir_free(encodedText); + } + fclose(fp); + } +} \ No newline at end of file diff --git a/plugins/NewXstatusNotify/src/utils.h b/plugins/NewXstatusNotify/src/utils.h new file mode 100644 index 0000000000..0ff5c93e23 --- /dev/null +++ b/plugins/NewXstatusNotify/src/utils.h @@ -0,0 +1,33 @@ +/* + NewXstatusNotify YM - Plugin for Miranda IM + Copyright (c) 2001-2004 Luca Santarelli + Copyright (c) 2005-2007 Vasilich + Copyright (c) 2007-2011 yaho + + 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 +*/ + +#ifndef UTILS_H +#define UTILS_H + +TCHAR *db2t(DBVARIANT *dbv); +int DBGetStringDefault(HANDLE hContact, const char *szModule, const char *szSetting, TCHAR *setting, int size, const TCHAR *defaultValue); +void HigherLower(int maxValue, int minValue); +void ShowLog(TCHAR *file); +int ProtoServiceExists(const char *szModule, const char *szService); +BOOL StatusHasAwayMessage(char *szProto, int status); +void LogToFile(TCHAR *stzText); + +#endif \ No newline at end of file diff --git a/plugins/NewXstatusNotify/src/version.h b/plugins/NewXstatusNotify/src/version.h new file mode 100644 index 0000000000..10ac34a753 --- /dev/null +++ b/plugins/NewXstatusNotify/src/version.h @@ -0,0 +1,4 @@ +#define __FILEVERSION_STRING 1,4,0,9 +#define __VERSION_STRING "1.4.0.9" +#define __VERSION_DWORD PLUGIN_MAKE_VERSION(1, 4, 0, 9) + diff --git a/plugins/NewXstatusNotify/src/xstatus.cpp b/plugins/NewXstatusNotify/src/xstatus.cpp new file mode 100644 index 0000000000..4356af37fb --- /dev/null +++ b/plugins/NewXstatusNotify/src/xstatus.cpp @@ -0,0 +1,524 @@ +/* + NewXstatusNotify YM - Plugin for Miranda IM + Copyright (c) 2007-2011 yaho + + 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 "common.h" +#include "options.h" +#include "popup.h" +#include "utils.h" +#include "xstatus.h" + +extern LIST eventList; +extern OPTIONS opt; +extern TEMPLATES templates; + +XSTATUSCHANGE *NewXSC(HANDLE hContact, char *szProto, int xstatusType, int action, TCHAR *stzTitle, TCHAR *stzText) +{ + XSTATUSCHANGE *xsc = (XSTATUSCHANGE *)mir_alloc(sizeof(XSTATUSCHANGE)); + xsc->hContact = hContact; + xsc->szProto = szProto; + xsc->type = xstatusType; + xsc->action = action; + xsc->stzTitle = stzTitle; + xsc->stzText = stzText; + return xsc; +} + +void FreeXSC(XSTATUSCHANGE *xsc) +{ + if (xsc) + { + if (xsc->stzTitle) mir_free(xsc->stzTitle); + if (xsc->stzText) mir_free(xsc->stzText); + mir_free(xsc); + xsc = NULL; + } +} + +void RemoveLoggedEvents(HANDLE hContact) +{ + for (int i = eventList.getCount()-1; i >= 0; i--) + { + DBEVENT *dbevent = eventList[i]; + if (dbevent->hContact == hContact) + { + CallService(MS_DB_EVENT_DELETE, (WPARAM)dbevent->hContact, (LPARAM)dbevent->hDBEvent); + eventList.remove(i); + mir_free(dbevent); + } + } +} + +TCHAR *GetStatusTypeAsString(int type, TCHAR *buff) +{ + switch (type) { + case TYPE_JABBER_MOOD: + _tcscpy(buff, TranslateT("Mood")); break; + case TYPE_JABBER_ACTIVITY: + _tcscpy(buff, TranslateT("Activity")); break; + case TYPE_ICQ_XSTATUS: + _tcscpy(buff, TranslateT("Xstatus")); break; + default: + _tcscpy(buff, TranslateT("")); + } + + return buff; +} + +void ReplaceVars(XSTATUSCHANGE *xsc , TCHAR *Template, TCHAR *delimiter, TCHAR *buff) +{ + buff[0] = 0; + TCHAR *pch = _tcschr(Template, _T('%')); + while (pch != NULL) + { + size_t len = _tcslen(buff); + _tcsncat(buff, Template, pch - Template); + buff[len + pch - Template] = 0; + + if (pch[1] == _T('N') || pch[1] == _T('T') || pch[1] == _T('I') || pch[1] == _T('D') || pch[1] == _T('B')) + { + switch (pch[1]) + { + case _T('N'): + { + TCHAR stzType[32]; + _tcscat(buff, GetStatusTypeAsString(xsc->type, stzType)); + break; + } + case _T('T'): + { + if (xsc->stzTitle) + _tcscat(buff, xsc->stzTitle); + break; + } + case _T('I'): + { + if (xsc->stzText) + _tcscat(buff, xsc->stzText); + break; + } + case _T('D'): + { + if (xsc->stzText) + { + if (_tcscmp(delimiter, _T("%B")) == 0) + _tcscat(buff, _T("\r\n")); + else + _tcscat(buff, delimiter); + } + break; + } + case _T('B'): + { + _tcscat(buff, _T("\r\n")); + break; + } + } + + Template = pch + 2; + } + else + { + _tcscat(buff, _T("%")); + Template = pch + 1; + } + + pch = _tcschr(Template, _T('%')); + } + + // append rest of the text + if (Template != NULL) + _tcscat(buff, Template); +} + +void ShowPopup(XSTATUSCHANGE *xsc) +{ + DBVARIANT dbv; + char szSetting[64]; + + POPUPDATAT ppd = {0}; + ppd.lchContact = xsc->hContact; + + switch(xsc->type) + { + case TYPE_JABBER_MOOD: + case TYPE_JABBER_ACTIVITY: + { + mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/%s", xsc->szProto, (xsc->type == TYPE_JABBER_MOOD) ? "mood" : "activity", "icon"); + if (!DBGetContactSettingString(xsc->hContact, "AdvStatus", szSetting, &dbv)) + { + ppd.lchIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)dbv.pszVal); + DBFreeVariant(&dbv); + } + break; + } + case TYPE_ICQ_XSTATUS: + { + int statusId = DBGetContactSettingByte(xsc->hContact, xsc->szProto, "XStatusId", 0); + ppd.lchIcon = (HICON)CallProtoService(xsc->szProto, PS_ICQ_GETCUSTOMSTATUSICON, statusId, LR_SHARED); + } + } + + if (ppd.lchIcon == NULL) + ppd.lchIcon = LoadSkinnedProtoIcon(xsc->szProto, DBGetContactSettingWord(xsc->hContact, xsc->szProto, "Status", ID_STATUS_ONLINE)); + + switch (opt.Colors) + { + case POPUP_COLOR_OWN: + ppd.colorBack = DBGetContactSettingDword(0, MODULE, "40081bg", COLOR_BG_AVAILDEFAULT); + ppd.colorText = DBGetContactSettingDword(0, MODULE, "40081tx", COLOR_TX_DEFAULT); + break; + case POPUP_COLOR_WINDOWS: + ppd.colorBack = GetSysColor(COLOR_BTNFACE); + ppd.colorText = GetSysColor(COLOR_WINDOWTEXT); + break; + case POPUP_COLOR_POPUP: + ppd.colorBack = ppd.colorText = 0; + break; + } + + TCHAR *ptszGroup = NULL, + *ptszNick = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)xsc->hContact, GSMDF_TCHAR); + if (opt.ShowGroup) { //add group name to popup title + if (!DBGetContactSettingTString(xsc->hContact, "CList", "Group", &dbv)) { + ptszGroup = NEWTSTR_ALLOCA(dbv.ptszVal); + DBFreeVariant(&dbv); + } + } + + if (ptszGroup) + mir_sntprintf(ppd.lptzContactName, SIZEOF(ppd.lptzContactName),_T("%s (%s)"), ptszNick, ptszGroup); + else + _tcsncpy(ppd.lptzContactName, ptszNick, SIZEOF(ppd.lptzContactName)); + + // cut message if needed + if (opt.PTruncateMsg && (opt.PMsgLen > 0) && xsc->stzText && (_tcslen(xsc->stzText) > opt.PMsgLen)) + { + TCHAR buff[MAX_TEXT_LEN + 3]; + _tcsncpy(buff, xsc->stzText, opt.PMsgLen); + buff[opt.PMsgLen] = 0; + _tcscat(buff, _T("...")); + mir_free(xsc->stzText); + xsc->stzText = mir_tstrdup(buff); + } + + TCHAR *Template = _T(""); + switch (xsc->action) + { + case NOTIFY_NEW_XSTATUS: + Template = templates.PopupNewXstatus; break; + case NOTIFY_NEW_MESSAGE: + Template = templates.PopupNewMsg; break; + case NOTIFY_REMOVE: + Template = templates.PopupRemove; break; + case NOTIFY_OPENING_ML: + Template = templates.LogOpening; break; + } + + TCHAR stzPopupText[2*MAX_TEXT_LEN]; + ReplaceVars(xsc, Template, templates.PopupDelimiter, stzPopupText); + _tcsncpy(ppd.lptzText, stzPopupText, SIZEOF(ppd.lptzText)); + ppd.lptzText[SIZEOF(ppd.lptzText) - 1] = 0; + + ppd.PluginWindowProc = (WNDPROC)PopupDlgProc; + ppd.iSeconds = opt.PopupTimeout; + PUAddPopUpT(&ppd); +} + +void PlayXStatusSound(int action) +{ + switch (action) + { + case NOTIFY_NEW_XSTATUS: + SkinPlaySound(XSTATUS_SOUND_CHANGED); break; + case NOTIFY_NEW_MESSAGE: + SkinPlaySound(XSTATUS_SOUND_MSGCHANGED); break; + case NOTIFY_REMOVE: + SkinPlaySound(XSTATUS_SOUND_REMOVED); break; + } +} + +void LogToMessageWindow(XSTATUSCHANGE *xsc, BOOL opening) +{ + // cut message if needed + if (opt.LTruncateMsg && (opt.LMsgLen > 0) && xsc->stzText && (_tcslen(xsc->stzText) > opt.LMsgLen)) + { + TCHAR buff[MAX_TEXT_LEN + 3]; + _tcsncpy(buff, xsc->stzText, opt.LMsgLen); + buff[opt.LMsgLen] = 0; + _tcscat(buff, _T("...")); + mir_free(xsc->stzText); + xsc->stzText = mir_tstrdup(buff); + } + + TCHAR *Template = _T(""); + switch (xsc->action) + { + case NOTIFY_NEW_XSTATUS: + Template = templates.LogNewXstatus; break; + case NOTIFY_NEW_MESSAGE: + Template = templates.LogNewMsg; break; + case NOTIFY_REMOVE: + Template = templates.LogRemove; break; + case NOTIFY_OPENING_ML: + Template = templates.LogOpening; break; + } + + TCHAR stzLogText[2*MAX_TEXT_LEN]; + TCHAR stzLastLog[2*MAX_TEXT_LEN]; + ReplaceVars(xsc, Template, templates.LogDelimiter, stzLogText); + DBGetStringDefault(xsc->hContact, MODULE, DB_LASTLOG, stzLastLog, SIZEOF(stzLastLog), _T("")); + + if (!opt.KeepInHistory || !(opt.PreventIdentical && _tcscmp(stzLastLog, stzLogText) == 0)) + { + DBWriteContactSettingTString(xsc->hContact, MODULE, DB_LASTLOG, stzLogText); + + char *blob; + + blob = mir_utf8encodeT(stzLogText); + + + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + dbei.cbBlob = (DWORD)strlen(blob) + 1; + dbei.pBlob = (PBYTE) blob; + dbei.eventType = EVENTTYPE_STATUSCHANGE; + dbei.flags = DBEF_READ; + + dbei.flags |= DBEF_UTF; + + dbei.timestamp = (DWORD)time(NULL); + dbei.szModule = xsc->szProto; + HANDLE hDBEvent = (HANDLE)CallService(MS_DB_EVENT_ADD, (WPARAM)xsc->hContact, (LPARAM)&dbei); + mir_free(blob); + + if (!opt.KeepInHistory) + { + DBEVENT *dbevent = (DBEVENT *)mir_alloc(sizeof(DBEVENT)); + dbevent->hContact = xsc->hContact; + dbevent->hDBEvent = hDBEvent; + eventList.insert(dbevent); + } + } +} + +void LogChangeToFile(XSTATUSCHANGE *xsc) +{ + TCHAR stzName[256], stzType[32]; + TCHAR stzDate[32], stzTime[32]; + TCHAR stzText[MAX_TEXT_LEN]; + + GetStatusTypeAsString(xsc->type, stzType); + + _tcscpy(stzName, (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)xsc->hContact, GCDNF_TCHAR)); + GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL,_T("HH':'mm"), stzTime, SIZEOF(stzTime)); + GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL,_T("dd/MM/yyyy"), stzDate, SIZEOF(stzDate)); + + if (xsc->action == NOTIFY_REMOVE) + mir_sntprintf(stzText, SIZEOF(stzText), TranslateT("%s, %s. %s removed %s.\r\n"), stzDate, stzTime, stzName, stzType); + else + mir_sntprintf(stzText, SIZEOF(stzText), TranslateT("%s, %s. %s changed %s to: %s.\r\n"), stzDate, stzTime, stzName, stzType, xsc->stzTitle); + + LogToFile(stzText); +} + +void ExtraStatusChanged(XSTATUSCHANGE *xsc) +{ + BOOL bEnablePopup = true, bEnableSound = true; + char buff[12] = {0}; + + wsprintfA(buff, "%d", ID_STATUS_EXTRASTATUS); + + if ((DBGetContactSettingByte(0, MODULE, buff, 1) == 0) || + (DBGetContactSettingWord(xsc->hContact, xsc->szProto, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE) || + (!opt.HiddenContactsToo && DBGetContactSettingByte(xsc->hContact, "CList", "Hidden", 0)) || + (opt.TempDisabled)) + { + return; + } + + char statusIDs[12], statusIDp[12]; + if (opt.AutoDisable) + { + WORD myStatus = (WORD)CallProtoService(xsc->szProto, PS_GETSTATUS, 0, 0); + wsprintfA(statusIDs, "s%d", myStatus); + wsprintfA(statusIDp, "p%d", myStatus); + bEnableSound = DBGetContactSettingByte(0, MODULE, statusIDs, 1) ? FALSE : TRUE; + bEnablePopup = DBGetContactSettingByte(0, MODULE, statusIDp, 1) ? FALSE : TRUE; + } + + if (!(templates.PopupFlags & xsc->action)) + bEnableSound = bEnablePopup = false; + + int xstatusID = DBGetContactSettingByte(xsc->hContact, xsc->szProto, "XStatusId", 0); + if (opt.PDisableForMusic && xsc->type == TYPE_ICQ_XSTATUS && xstatusID == XSTATUS_MUSIC) + bEnableSound = bEnablePopup = false; + + if (bEnablePopup && DBGetContactSettingByte(xsc->hContact, MODULE, "EnableXStatusNotify", 1) && TimeoutCheck()) + ShowPopup(xsc); + + if (bEnableSound && DBGetContactSettingByte(xsc->hContact, MODULE, "EnableXStatusNotify", 1)) + PlayXStatusSound(xsc->action); + + BYTE enableLog = opt.EnableLogging; + if (opt.LDisableForMusic && xsc->type == TYPE_ICQ_XSTATUS && xstatusID == XSTATUS_MUSIC) + enableLog = FALSE; + + if (!(templates.LogFlags & xsc->action)) + enableLog = FALSE; + + if (enableLog && DBGetContactSettingByte(xsc->hContact, MODULE, "EnableLogging", 1) && + CallService(MS_MSG_MOD_MESSAGEDIALOGOPENED, (WPARAM)xsc->hContact, 0)) + { + LogToMessageWindow(xsc, FALSE); + } + + if (opt.Log) + LogChangeToFile(xsc); +} + +TCHAR *GetDefaultXstatusName(int statusID, char *szProto, TCHAR *buff, int bufflen) +{ + TCHAR nameBuff[64]; + buff[0] = 0; + + ICQ_CUSTOM_STATUS xstatus = {0}; + xstatus.cbSize = sizeof(ICQ_CUSTOM_STATUS); + xstatus.flags = CSSF_MASK_NAME | CSSF_DEFAULT_NAME | CSSF_TCHAR; + xstatus.ptszName = nameBuff; + xstatus.wParam = (WPARAM *)&statusID; + if (!CallProtoService(szProto, PS_ICQ_GETCUSTOMSTATUSEX, 0, (LPARAM)&xstatus)) + { + _tcsncpy(buff, TranslateTS(nameBuff), bufflen); + buff[bufflen - 1] = 0; + } + + return buff; +} + +TCHAR *GetIcqXStatus(HANDLE hContact, char *szProto, char *szValue, TCHAR *buff, int bufflen) +{ + DBVARIANT dbv; + buff[0] = 0; + + int statusID = DBGetContactSettingByte(hContact, szProto, "XStatusId", -1); + if (statusID != -1) + { + if (!DBGetContactSettingTString(hContact, szProto, szValue, &dbv)) + { + if ((strcmp(szValue, "XStatusName") == 0) && dbv.ptszVal[0] == 0) + GetDefaultXstatusName(statusID, szProto, buff, bufflen); + else + _tcsncpy(buff, dbv.ptszVal, bufflen); + + buff[bufflen - 1] = 0; + DBFreeVariant(&dbv); + } + } + + return buff; +} + +TCHAR *GetJabberAdvStatusText(HANDLE hContact, char *szProto, char *szSlot, char *szValue, TCHAR *buff, int bufflen) +{ + DBVARIANT dbv; + char szSetting[128]; + buff[0] = 0; + + mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/%s", szProto, szSlot, szValue); + if (!DBGetContactSettingTString(hContact, "AdvStatus", szSetting, &dbv)) + { + _tcsncpy(buff, dbv.ptszVal, bufflen); + buff[bufflen - 1] = 0; + DBFreeVariant(&dbv); + } + + return buff; +} + +void LogXstatusChange(HANDLE hContact, char *szProto, int xstatusType, TCHAR *stzTitle, TCHAR *stzText) +{ + XSTATUSCHANGE *xsc = + NewXSC( + hContact, + szProto, + xstatusType, + NOTIFY_OPENING_ML, + stzTitle[0] ? mir_tstrdup(stzTitle): NULL, + stzText[0] ? mir_tstrdup(stzText) : NULL + ); + + LogToMessageWindow(xsc, TRUE); + FreeXSC(xsc); +} + +void AddEventThread(void *arg) +{ + HANDLE hContact = (HANDLE)arg; + TCHAR stzTitle[MAX_TITLE_LEN], stzText[MAX_TEXT_LEN]; + + char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (szProto == NULL) return; + + if (ProtoServiceExists(szProto, JS_PARSE_XMPP_URI)) + { + GetJabberAdvStatusText(hContact, szProto, "mood", "title", stzTitle, SIZEOF(stzTitle)); + if (stzTitle[0]) + { + GetJabberAdvStatusText(hContact, szProto, "mood", "text", stzText, SIZEOF(stzText)); + LogXstatusChange(hContact, szProto, TYPE_JABBER_MOOD, stzTitle, stzText); + } + + GetJabberAdvStatusText(hContact, szProto, "activity", "title", stzTitle, SIZEOF(stzTitle)); + if (stzTitle[0]) + { + GetJabberAdvStatusText(hContact, szProto, "activity", "text", stzText, SIZEOF(stzText)); + LogXstatusChange(hContact, szProto, TYPE_JABBER_ACTIVITY, stzTitle, stzText); + } + } + else + { + GetIcqXStatus(hContact, szProto, "XStatusName", stzTitle, SIZEOF(stzTitle)); + if (stzTitle[0]) + { + GetIcqXStatus(hContact, szProto, "XStatusMsg", stzText, SIZEOF(stzText)); + LogXstatusChange(hContact, szProto, TYPE_ICQ_XSTATUS, stzTitle, stzText); + } + } +} + +int OnWindowEvent(WPARAM wParam, LPARAM lParam) +{ + MessageWindowEventData *mwed = (MessageWindowEventData *)lParam; + + if (mwed->uType == MSG_WINDOW_EVT_CLOSE && !opt.KeepInHistory) + { + RemoveLoggedEvents(mwed->hContact); + return 0; + } + + if (opt.EnableLogging && + (mwed->uType == MSG_WINDOW_EVT_OPEN) && + (templates.LogFlags & NOTIFY_OPENING_ML) && + (DBGetContactSettingByte(mwed->hContact, MODULE, "EnableLogging", 1) == 1)) + { + mir_forkthread(AddEventThread, mwed->hContact); + } + + return 0; +} diff --git a/plugins/NewXstatusNotify/src/xstatus.h b/plugins/NewXstatusNotify/src/xstatus.h new file mode 100644 index 0000000000..d5a76acb52 --- /dev/null +++ b/plugins/NewXstatusNotify/src/xstatus.h @@ -0,0 +1,106 @@ +/* + NewXstatusNotify YM - Plugin for Miranda IM + Copyright (c) 2007-2011 yaho + + 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 +*/ + +#ifndef XSTATUS_H +#define XSTATUS_H + +#define NOTIFY_NEW_XSTATUS 1 +#define NOTIFY_NEW_MESSAGE 2 +#define NOTIFY_REMOVE 4 +#define NOTIFY_OPENING_ML 8 + +#define TYPE_ICQ_XSTATUS 1 +#define TYPE_JABBER_MOOD 2 +#define TYPE_JABBER_ACTIVITY 3 + +#define XSTATUS_MUSIC 11 + +#define MAX_TITLE_LEN 256 +#define MAX_TEXT_LEN 2048 + +// Database setting names +#define DB_LASTLOG "LastLog" + +// Sounds +#define XSTATUS_SOUND_CHANGED "XStatusChanged" +#define XSTATUS_SOUND_MSGCHANGED "XStatusMsgChanged" +#define XSTATUS_SOUND_REMOVED "XStatusRemove" + +// tabSRMM stuff (logging to message window) +#define EVENTTYPE_STATUSCHANGE 25368 +#define MS_MSG_MOD_MESSAGEDIALOGOPENED "SRMsg_MOD/MessageDialogOpened" + +// Default templates +#define DEFAULT_POPUP_DELIMITER _T("%B") +#define DEFAULT_POPUP_NEW TranslateT("changed %N to: %T%D%I") +#define DEFAULT_POPUP_CHANGEMSG TranslateT("changed %N message to:%D%I") +#define DEFAULT_POPUP_REMOVE TranslateT("removed %N") +#define DEFAULT_POPUP_STATUSMESSAGE "changed his/her status message to %n" + +#define DEFAULT_LOG_DELIMITER _T(": ") +#define DEFAULT_LOG_NEW TranslateT("changed %N @ %T%D%I") +#define DEFAULT_LOG_CHANGEMSG TranslateT("changed %N message @ %I") +#define DEFAULT_LOG_REMOVE TranslateT("removed %N") +#define DEFAULT_LOG_OPENING TranslateT("has %N @ %T%D%I") + +// Variables help text +#define VARIABLES_HELP_TEXT TranslateT("These variables are available:\r\n\r\n\ +%N\textra status name (Xstatus, Mood, Activity)\r\n\ +%T\textra status title\r\n\ +%I\textra status text\r\n\ +%D\tdelimiter\r\n\ +%B\tline break (can be used as delimiter)") + +#define VARIABLES_SM_HELP_TEXT TranslateT("These variables are available:\r\n\r\n\ +%n\tNew Status Message\r\n\ +%o\tOld Status Message\r\n\ +%c\tCustom Nickname\r\n\ +\\n\tline break\r\n\ +\\t\ttab stop") + +typedef struct tagXSTATUSCHANGE +{ + HANDLE hContact; + char *szProto; + int type; + int action; + TCHAR *stzTitle; + TCHAR *stzText; +} XSTATUSCHANGE; + +typedef struct tagDBEVENT +{ + HANDLE hContact; + HANDLE hDBEvent; +} DBEVENT; + +typedef struct tagPROTOTEMPLATE +{ + TCHAR *ProtoName; + TCHAR ProtoTemplate[MAX_PATH]; +} PROTOTEMPLATE; + +TCHAR *GetDefaultXstatusName(int statusID, char *szProto, TCHAR *buff, int bufflen); +XSTATUSCHANGE *NewXSC(HANDLE hContact, char *szProto, int xstatusType, int action, TCHAR *stzTitle, TCHAR *stzText); +void FreeXSC(XSTATUSCHANGE *xsc); +void ExtraStatusChanged(XSTATUSCHANGE *xsc); +int OnWindowEvent(WPARAM wParam, LPARAM lParam); +BOOL TimeoutCheck(); + +#endif \ No newline at end of file -- cgit v1.2.3