summaryrefslogtreecommitdiff
path: root/plugins/TabSRMM/src/mim.cpp
diff options
context:
space:
mode:
authorRobert Pösel <robyer@seznam.cz>2014-04-23 14:43:51 +0000
committerRobert Pösel <robyer@seznam.cz>2014-04-23 14:43:51 +0000
commit1babf569634e2f7cee4932cd5ccb20fe125b7a61 (patch)
tree52de48f405e147e3574d3eec9b9e87d3bed4f9c1 /plugins/TabSRMM/src/mim.cpp
parent373e84ed50b36d871bab20b5b7ba8710a693ec7e (diff)
TabSRMM: Use consistent "%s is typing..." messages as in chat and scriver
git-svn-id: http://svn.miranda-ng.org/main/trunk@9056 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/TabSRMM/src/mim.cpp')
-rw-r--r--plugins/TabSRMM/src/mim.cpp1344
1 files changed, 672 insertions, 672 deletions
diff --git a/plugins/TabSRMM/src/mim.cpp b/plugins/TabSRMM/src/mim.cpp
index d6a45b2aa1..649ed59f93 100644
--- a/plugins/TabSRMM/src/mim.cpp
+++ b/plugins/TabSRMM/src/mim.cpp
@@ -1,672 +1,672 @@
-/*
- * Miranda NG: the free IM client for Microsoft* Windows*
- *
- * Copyright (c) 2000-09 Miranda ICQ/IM project,
- * all portions of this codebase are copyrighted to the people
- * listed in contributors.txt.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * you should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * part of tabSRMM messaging plugin for Miranda.
- *
- * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
- *
- * wraps some parts of Miranda API
- * Also, OS dependent stuff (visual styles api etc.)
- *
- */
-
-#include "commonheaders.h"
-
-PDTTE CMimAPI::m_pfnDrawThemeTextEx = 0;
-DEFICA CMimAPI::m_pfnDwmExtendFrameIntoClientArea = 0;
-DICE CMimAPI::m_pfnDwmIsCompositionEnabled = 0;
-DRT CMimAPI::m_pfnDwmRegisterThumbnail = 0;
-BPI CMimAPI::m_pfnBufferedPaintInit = 0;
-BPU CMimAPI::m_pfnBufferedPaintUninit = 0;
-BBP CMimAPI::m_pfnBeginBufferedPaint = 0;
-EBP CMimAPI::m_pfnEndBufferedPaint = 0;
-BBW CMimAPI::m_pfnDwmBlurBehindWindow = 0;
-DGC CMimAPI::m_pfnDwmGetColorizationColor = 0;
-BPSA CMimAPI::m_pfnBufferedPaintSetAlpha = 0;
-DWMIIB CMimAPI::m_pfnDwmInvalidateIconicBitmaps = 0;
-DWMSWA CMimAPI::m_pfnDwmSetWindowAttribute = 0;
-DWMUT CMimAPI::m_pfnDwmUpdateThumbnailProperties = 0;
-DURT CMimAPI::m_pfnDwmUnregisterThumbnail = 0;
-DSIT CMimAPI::m_pfnDwmSetIconicThumbnail = 0;
-DSILP CMimAPI::m_pfnDwmSetIconicLivePreviewBitmap = 0;
-bool CMimAPI::m_shutDown = 0;
-TCHAR CMimAPI::m_userDir[] = _T("\0");
-
-bool CMimAPI::m_haveBufferedPaint = false;
-
-/**
- * Case insensitive _tcsstr
- *
- * @param szString TCHAR *: String to be searched
- * @param szSearchFor
- *TCHAR *: String that should be found in szString
- *
- * @return TCHAR *: found position of szSearchFor in szString. 0 if szSearchFor was not found
- */
-const TCHAR* CMimAPI::StriStr(const TCHAR *szString, const TCHAR *szSearchFor)
-{
- assert(szString != 0 && szSearchFor != 0);
-
- if (!szString || *szString == 0)
- return NULL;
-
- if (!szSearchFor || *szSearchFor == 0)
- return szString;
-
- for (; *szString; ++szString) {
- if (_totupper(*szString) == _totupper(*szSearchFor)) {
- const TCHAR *h, *n;
- for (h = szString, n = szSearchFor; *h && *n; ++h, ++n)
- if (_totupper(*h) != _totupper(*n))
- break;
-
- if (!*n)
- return szString;
- }
- }
- return NULL;
-}
-
-int CMimAPI::pathIsAbsolute(const TCHAR *path) const
-{
- if (!path || !(lstrlen(path) > 2))
- return 0;
- if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\'))
- return 1;
- return 0;
-}
-
-size_t CMimAPI::pathToRelative(const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase) const
-{
- const TCHAR *tszBase = szBase ? szBase : m_szProfilePath;
-
- pOut[0] = 0;
- if (!pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH)
- return 0;
- if (!pathIsAbsolute(pSrc)) {
- mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
- return lstrlen(pOut);
- }
-
- TCHAR szTmp[MAX_PATH];
- mir_sntprintf(szTmp, SIZEOF(szTmp), _T("%s"), pSrc);
- if (StriStr(szTmp, tszBase)) {
- if (tszBase[lstrlen(tszBase) - 1] == '\\')
- mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc + lstrlen(tszBase));
- else {
- mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc + lstrlen(tszBase) + 1 );
- //pOut[0]='.';
- }
- return(lstrlen(pOut));
- }
-
- mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
- return(lstrlen(pOut));
-}
-
-/**
- * Translate a relativ path to an absolute, using the current profile
- * data directory.
- *
- * @param pSrc TCHAR *: input path + filename (relative)
- * @param pOut TCHAR *: the result
- * @param szBase TCHAR *: (OPTIONAL) base path for the translation. Can be 0 in which case
- * the function will use m_szProfilePath (usually \tabSRMM below %miranda_userdata%
- *
- * @return
- */
-size_t CMimAPI::pathToAbsolute(const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase) const
-{
- const TCHAR *tszBase = szBase ? szBase : m_szProfilePath;
-
- pOut[0] = 0;
- if (!pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH)
- return 0;
- if (pathIsAbsolute(pSrc) && pSrc[0]!='.')
- mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
- else if (pSrc[0]=='.')
- mir_sntprintf(pOut, MAX_PATH, _T("%s\\%s"), tszBase, pSrc + 1);
- else
- mir_sntprintf(pOut, MAX_PATH, _T("%s\\%s"), tszBase, pSrc);
-
- return lstrlen(pOut);
-}
-
-/*
- * window list functions
- */
-
-void CMimAPI::BroadcastMessage(UINT msg, WPARAM wParam, LPARAM lParam)
-{
- WindowList_Broadcast(m_hMessageWindowList, msg, wParam, lParam);
-}
-
-void CMimAPI::BroadcastMessageAsync(UINT msg, WPARAM wParam, LPARAM lParam)
-{
- WindowList_BroadcastAsync(m_hMessageWindowList, msg, wParam, lParam);
-}
-
-HWND CMimAPI::FindWindow(MCONTACT h) const
-{
- return WindowList_Find(m_hMessageWindowList, h);
-}
-
-INT_PTR CMimAPI::AddWindow(HWND hWnd, MCONTACT h)
-{
- return WindowList_Add(m_hMessageWindowList, hWnd, h);
-}
-
-INT_PTR CMimAPI::RemoveWindow(HWND hWnd)
-{
- return WindowList_Remove(m_hMessageWindowList, hWnd);
-}
-
-int CMimAPI::FoldersPathChanged(WPARAM wParam, LPARAM lParam)
-{
- return M.foldersPathChanged();
-}
-
-void CMimAPI::configureCustomFolders()
-{
- m_hDataPath = FoldersRegisterCustomPathT(LPGEN("TabSRMM"), LPGEN("Data path"), const_cast<TCHAR *>(getDataPath()));
- m_hSkinsPath = FoldersRegisterCustomPathT(LPGEN("Skins"), LPGEN("TabSRMM"), const_cast<TCHAR *>(getSkinPath()));
- m_hAvatarsPath = FoldersRegisterCustomPathT(LPGEN("Avatars"), LPGEN("Saved TabSRMM avatars"), const_cast<TCHAR *>(getSavedAvatarPath()));
- m_hChatLogsPath = FoldersRegisterCustomPathT(LPGEN("TabSRMM"), LPGEN("Group chat logs root"), const_cast<TCHAR *>(getChatLogPath()));
-
- if (m_hDataPath)
- HookEvent(ME_FOLDERS_PATH_CHANGED, CMimAPI::FoldersPathChanged);
-
- foldersPathChanged();
-}
-
-INT_PTR CMimAPI::foldersPathChanged()
-{
- TCHAR szTemp[MAX_PATH + 2] = {'\0'};
-
- if (m_hDataPath) {
- FoldersGetCustomPathT(m_hDataPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getDataPath()));
- mir_sntprintf(m_szProfilePath, MAX_PATH, _T("%s"), szTemp);
-
- FoldersGetCustomPathT(m_hSkinsPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getSkinPath()));
- mir_sntprintf(m_szSkinsPath, MAX_PATH - 1, _T("%s"), szTemp);
- Utils::ensureTralingBackslash(m_szSkinsPath);
-
- FoldersGetCustomPathT(m_hAvatarsPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getSavedAvatarPath()));
- mir_sntprintf(m_szSavedAvatarsPath, MAX_PATH, _T("%s"), szTemp);
-
- FoldersGetCustomPathT(m_hChatLogsPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getChatLogPath()));
- mir_sntprintf(m_szChatLogsPath, MAX_PATH, _T("%s"), szTemp);
- Utils::ensureTralingBackslash(m_szChatLogsPath);
- }
-
- CreateDirectoryTreeT(m_szProfilePath);
- CreateDirectoryTreeT(m_szSkinsPath);
- CreateDirectoryTreeT(m_szSavedAvatarsPath);
-
- Skin->extractSkinsAndLogo(true);
- Skin->setupAeroSkins();
- return 0;
-}
-
-const TCHAR* CMimAPI::getUserDir()
-{
- if (m_userDir[0] == 0) {
- if ( ServiceExists(MS_FOLDERS_REGISTER_PATH))
- lstrcpyn(m_userDir, L"%miranda_userdata%", SIZEOF(m_userDir));
- else
- lstrcpyn(m_userDir, VARST( _T("%miranda_userdata%")), SIZEOF(m_userDir));
-
- Utils::ensureTralingBackslash(m_userDir);
- }
- return m_userDir;
-}
-
-void CMimAPI::InitPaths()
-{
- m_szProfilePath[0] = 0;
- m_szSkinsPath[0] = 0;
- m_szSavedAvatarsPath[0] = 0;
-
- const TCHAR *szUserdataDir = getUserDir();
-
- mir_sntprintf(m_szProfilePath, MAX_PATH, _T("%stabSRMM"), szUserdataDir);
- if (ServiceExists(MS_FOLDERS_REGISTER_PATH)) {
- lstrcpyn(m_szChatLogsPath, _T("%miranda_logpath%"), MAX_PATH);
- lstrcpyn(m_szSkinsPath, _T("%miranda_path%\\Skins\\TabSRMM"), MAX_PATH);
- }
- else {
- lstrcpyn(m_szChatLogsPath, VARST(_T("%miranda_logpath%")), MAX_PATH);
- lstrcpyn(m_szSkinsPath, VARST(_T("%miranda_path%\\Skins\\TabSRMM")), MAX_PATH);
- }
-
- Utils::ensureTralingBackslash(m_szChatLogsPath);
- replaceStrT(g_Settings.pszLogDir, m_szChatLogsPath);
-
- Utils::ensureTralingBackslash(m_szSkinsPath);
-
- mir_sntprintf(m_szSavedAvatarsPath, MAX_PATH, _T("%s\\Saved Contact Pictures"), m_szProfilePath);
-}
-
-bool CMimAPI::getAeroState()
-{
- BOOL result = FALSE;
- m_isAero = m_DwmActive = false;
- if (IsWinVerVistaPlus()) {
- m_DwmActive = (m_pfnDwmIsCompositionEnabled && (m_pfnDwmIsCompositionEnabled(&result) == S_OK) && result) ? true : false;
- m_isAero = (CSkin::m_skinEnabled == false) && GetByte("useAero", 1) && CSkin::m_fAeroSkinsValid && m_DwmActive;
-
- }
- m_isVsThemed = IsThemeActive() != 0;
- return m_isAero;
-}
-
-/**
- * Initialize various Win32 API functions which are not common to all versions of Windows.
- * We have to work with functions pointers here.
- */
-
-void CMimAPI::InitAPI()
-{
- m_hUxTheme = 0;
-
- /*
- * vista+ DWM API
- */
- m_hDwmApi = 0;
- if (IsWinVerVistaPlus()) {
- m_hDwmApi = Utils::loadSystemLibrary(L"\\dwmapi.dll");
- if (m_hDwmApi) {
- m_pfnDwmExtendFrameIntoClientArea = (DEFICA)GetProcAddress(m_hDwmApi,"DwmExtendFrameIntoClientArea");
- m_pfnDwmIsCompositionEnabled = (DICE)GetProcAddress(m_hDwmApi,"DwmIsCompositionEnabled");
- m_pfnDwmRegisterThumbnail = (DRT)GetProcAddress(m_hDwmApi, "DwmRegisterThumbnail");
- m_pfnDwmBlurBehindWindow = (BBW)GetProcAddress(m_hDwmApi, "DwmEnableBlurBehindWindow");
- m_pfnDwmGetColorizationColor = (DGC)GetProcAddress(m_hDwmApi, "DwmGetColorizationColor");
- m_pfnDwmInvalidateIconicBitmaps = (DWMIIB)GetProcAddress(m_hDwmApi, "DwmInvalidateIconicBitmaps");
- m_pfnDwmSetWindowAttribute = (DWMSWA)GetProcAddress(m_hDwmApi, "DwmSetWindowAttribute");
- m_pfnDwmUpdateThumbnailProperties = (DWMUT)GetProcAddress(m_hDwmApi, "DwmUpdateThumbnailProperties");
- m_pfnDwmUnregisterThumbnail = (DURT)GetProcAddress(m_hDwmApi, "DwmUnregisterThumbnail");
- m_pfnDwmSetIconicThumbnail = (DSIT)GetProcAddress(m_hDwmApi, "DwmSetIconicThumbnail");
- m_pfnDwmSetIconicLivePreviewBitmap = (DSILP)GetProcAddress(m_hDwmApi, "DwmSetIconicLivePreviewBitmap");
- }
- /*
- * additional uxtheme APIs (Vista+)
- */
- m_hUxTheme = Utils::loadSystemLibrary(L"\\uxtheme.dll");
- if (m_hUxTheme) {
- m_pfnDrawThemeTextEx = (PDTTE)GetProcAddress(m_hUxTheme, "DrawThemeTextEx");
- m_pfnBeginBufferedPaint = (BBP)GetProcAddress(m_hUxTheme, "BeginBufferedPaint");
- m_pfnEndBufferedPaint = (EBP)GetProcAddress(m_hUxTheme, "EndBufferedPaint");
- m_pfnBufferedPaintInit = (BPI)GetProcAddress(m_hUxTheme, "BufferedPaintInit");
- m_pfnBufferedPaintUninit = (BPU)GetProcAddress(m_hUxTheme, "BufferedPaintUnInit");
- m_pfnBufferedPaintSetAlpha = (BPSA)GetProcAddress(m_hUxTheme, "BufferedPaintSetAlpha");
- m_haveBufferedPaint = (m_pfnBeginBufferedPaint != 0 && m_pfnEndBufferedPaint != 0) ? true : false;
- if (m_haveBufferedPaint)
- m_pfnBufferedPaintInit();
- }
- }
- else m_haveBufferedPaint = false;
-}
-
-/**
- * hook subscriber function for incoming message typing events
- */
-
-int CMimAPI::TypingMessage(WPARAM hContact, LPARAM lParam)
-{
- HWND hwnd = 0;
- int issplit = 1, foundWin = 0, preTyping = 0;
- BOOL fShowOnClist = TRUE;
-
- if (hContact) {
- if ((hwnd = M.FindWindow(hContact)) && M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPING, SRMSGDEFSET_SHOWTYPING))
- preTyping = SendMessage(hwnd, DM_TYPING, 0, lParam);
-
- if (hwnd && IsWindowVisible(hwnd))
- foundWin = MessageWindowOpened(0, (LPARAM)hwnd);
- else
- foundWin = 0;
-
- TContainerData *pContainer = NULL;
- if (hwnd) {
- SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer);
- if (pContainer == NULL)
- return 0; // should never happen
- }
-
- if ( M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGCLIST, SRMSGDEFSET_SHOWTYPINGCLIST)) {
- if (!hwnd && !M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGNOWINOPEN, 1))
- fShowOnClist = FALSE;
- if (hwnd && !M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGWINOPEN, 1))
- fShowOnClist = FALSE;
- }
- else fShowOnClist = FALSE;
-
- if ((!foundWin || !(pContainer->dwFlags & CNT_NOSOUND)) && preTyping != (lParam != 0))
- SkinPlaySound((lParam) ? "TNStart" : "TNStop");
-
- if (M.GetByte(SRMSGMOD, "ShowTypingPopup", 0)) {
- BOOL fShow = FALSE;
- int iMode = M.GetByte("MTN_PopupMode", 0);
-
- switch(iMode) {
- case 0:
- fShow = TRUE;
- break;
- case 1:
- if (!foundWin || !(pContainer && pContainer->hwndActive == hwnd && GetForegroundWindow() == pContainer->hwnd))
- fShow = TRUE;
- break;
- case 2:
- if (hwnd == 0)
- fShow = TRUE;
- else {
- if (PluginConfig.m_HideOnClose) {
- TContainerData *pContainer = 0;
- SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer);
- if (pContainer && pContainer->fHidden)
- fShow = TRUE;
- }
- }
- break;
- }
- if (fShow)
- TN_TypingMessage(hContact, lParam);
- }
-
- if (lParam) {
- TCHAR szTip[256];
- mir_sntprintf(szTip, SIZEOF(szTip), TranslateT("%s is typing a message."), pcli->pfnGetContactDisplayName(hContact, 0));
- if (fShowOnClist && ServiceExists(MS_CLIST_SYSTRAY_NOTIFY) && M.GetByte(SRMSGMOD, "ShowTypingBalloon", 0)) {
- MIRANDASYSTRAYNOTIFY tn;
- tn.szProto = NULL;
- tn.cbSize = sizeof(tn);
- tn.tszInfoTitle = TranslateT("Typing Notification");
- tn.tszInfo = szTip;
- tn.dwInfoFlags = NIIF_INFO | NIIF_INTERN_UNICODE;
- tn.uTimeout = 1000 * 4;
- CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&tn);
- }
- if (fShowOnClist) {
- CLISTEVENT cle = { sizeof(cle) };
- cle.hContact = hContact;
- cle.hDbEvent = (HANDLE)1;
- cle.flags = CLEF_ONLYAFEW | CLEF_TCHAR;
- cle.hIcon = PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING];
- cle.pszService = "SRMsg/TypingMessage";
- cle.ptszTooltip = szTip;
- CallServiceSync(MS_CLIST_REMOVEEVENT, hContact, 1);
- CallServiceSync(MS_CLIST_ADDEVENT, hContact, (LPARAM)&cle);
- }
- }
- }
- return 0;
-}
-
-/**
- * this is the global ack dispatcher. It handles both ACKTYPE_MESSAGE and ACKTYPE_AVATAR events
- * for ACKTYPE_MESSAGE it searches the corresponding send job in the queue and, if found, dispatches
- * it to the owners window
- *
- * ACKTYPE_AVATAR no longer handled here, because we have avs services now.
- */
-
-int CMimAPI::ProtoAck(WPARAM wParam, LPARAM lParam)
-{
- ACKDATA *pAck = (ACKDATA*)lParam;
- if (lParam == 0)
- return 0;
-
- HWND hwndDlg = 0;
- int i=0, iFound = SendQueue::NR_SENDJOBS;
- SendJob *jobs = sendQueue->getJobByIndex(0);
-
- if (pAck->type == ACKTYPE_MESSAGE) {
- MCONTACT hMeta = db_mc_getMeta(pAck->hContact);
- for (int j = 0; j < SendQueue::NR_SENDJOBS; j++) {
- SendJob &p = jobs[j];
- if (pAck->hProcess == p.hSendId && pAck->hContact == p.hOwner) {
- TWindowData *dat = p.hwndOwner ? (TWindowData*)GetWindowLongPtr(p.hwndOwner, GWLP_USERDATA) : NULL;
- if (dat == NULL) {
- sendQueue->ackMessage(NULL, (WPARAM)MAKELONG(j, i), lParam);
- return 0;
- }
- if (dat->hContact == p.hOwner || dat->hContact == hMeta) {
- iFound = j;
- break;
- }
- }
- if (iFound != SendQueue::NR_SENDJOBS) // no mathing entry found in this queue entry.. continue
- break;
- }
- if (iFound == SendQueue::NR_SENDJOBS) // no matching send info found in the queue
- sendLater->processAck(pAck);
- else // try to find the process handle in the list of open send later jobs
- SendMessage(jobs[iFound].hwndOwner, HM_EVENTSENT, (WPARAM)MAKELONG(iFound, i), lParam);
- }
- return 0;
-}
-
-int CMimAPI::PrebuildContactMenu(WPARAM hContact, LPARAM lParam)
-{
- if (hContact == NULL)
- return NULL;
-
- bool bEnabled = false;
- char *szProto = GetContactProto(hContact);
- if (szProto) {
- // leave this menu item hidden for chats
- if ( !db_get_b(hContact, szProto, "ChatRoom", 0 ))
- if ( CallProtoService( szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND)
- bEnabled = true;
- }
-
- Menu_ShowItem(PluginConfig.m_hMenuItem, bEnabled);
- return 0;
-}
-
-/**
- * this handler is called first in the message window chain - it will handle events for which a message window
- * is already open. if not, it will do nothing and the 2nd handler (MessageEventAdded) will perform all
- * the needed actions.
- *
- * this handler POSTs the event to the message window procedure - so it is fast and can exit quickly which will
- * improve the overall responsiveness when receiving messages.
- */
-
-int CMimAPI::DispatchNewEvent(WPARAM hContact, LPARAM lParam)
-{
- if (hContact) {
- HWND h = M.FindWindow(hContact);
- if (h == NULL)
- h = M.FindWindow(hContact = db_event_getContact((HANDLE)lParam));
- if (h)
- PostMessage(h, HM_DBEVENTADDED, hContact, lParam); // was SENDMESSAGE !!! XXX
- }
- return 0;
-}
-
-/**
- * Message event added is called when a new message is added to the database
- * if no session is open for the contact, this function will determine if and how a new message
- * session (tab) must be created.
- *
- * if a session is already created, it just does nothing and DispatchNewEvent() will take care.
- */
-
-int CMimAPI::MessageEventAdded(WPARAM hContact, LPARAM lParam)
-{
- TCHAR szName[CONTAINER_NAMELEN + 1];
-
- HANDLE hDbEvent = (HANDLE)lParam;
- DBEVENTINFO dbei = { sizeof(dbei) };
- db_event_get(hDbEvent, &dbei);
-
- HWND hwnd = M.FindWindow(hContact);
- if (hwnd == NULL)
- hwnd = M.FindWindow(db_event_getContact(hDbEvent));
-
- BOOL isCustomEvent = IsCustomEvent(dbei.eventType);
- BOOL isShownCustomEvent = DbEventIsForMsgWindow(&dbei);
- if (dbei.markedRead() || (isCustomEvent && !isShownCustomEvent))
- return 0;
-
- CallServiceSync(MS_CLIST_REMOVEEVENT, hContact, 1);
-
- bool bAllowAutoCreate = false;
- bool bAutoPopup = M.GetByte(SRMSGSET_AUTOPOPUP, SRMSGDEFSET_AUTOPOPUP) != 0;
- bool bAutoCreate = M.GetByte("autotabs", 1) != 0;
- bool bAutoContainer = M.GetByte("autocontainer", 1) != 0;
- DWORD dwStatusMask = M.GetDword("autopopupmask", -1);
-
- if (hwnd) {
- TContainerData *pTargetContainer = 0;
- SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pTargetContainer);
- if (pTargetContainer == NULL || !PluginConfig.m_HideOnClose || IsWindowVisible(pTargetContainer->hwnd))
- return 0;
-
- WINDOWPLACEMENT wp = { 0 };
- wp.length = sizeof(wp);
- GetWindowPlacement(pTargetContainer->hwnd, &wp);
- GetContainerNameForContact(hContact, szName, CONTAINER_NAMELEN);
-
- if (bAutoPopup || bAutoCreate) {
- if (bAutoPopup) {
- if (wp.showCmd == SW_SHOWMAXIMIZED)
- ShowWindow(pTargetContainer->hwnd, SW_SHOWMAXIMIZED);
- else
- ShowWindow(pTargetContainer->hwnd, SW_SHOWNOACTIVATE);
- return 0;
- }
-
- TContainerData *pContainer = FindContainerByName(szName);
- if (pContainer != NULL) {
- if (bAutoContainer) {
- ShowWindow(pTargetContainer->hwnd, SW_SHOWMINNOACTIVE);
- return 0;
- }
- goto nowindowcreate;
- }
- else if (bAutoContainer) {
- ShowWindow(pTargetContainer->hwnd, SW_SHOWMINNOACTIVE);
- return 0;
- }
- }
- }
- else {
- switch (dbei.eventType) {
- case EVENTTYPE_AUTHREQUEST:
- case EVENTTYPE_ADDED:
- return 0;
-
- case EVENTTYPE_FILE:
- tabSRMM_ShowPopup(hContact, hDbEvent, dbei.eventType, 0, 0, 0, dbei.szModule, 0);
- return 0;
- }
- }
-
- // if no window is open, we are not interested in anything else but unread message events
- // new message
- if (!nen_options.iNoSounds)
- SkinPlaySound("AlertMsg");
-
- if (nen_options.iNoAutoPopup)
- goto nowindowcreate;
-
- GetContainerNameForContact(hContact, szName, CONTAINER_NAMELEN);
-
- if (dwStatusMask == -1)
- bAllowAutoCreate = true;
- else {
- char *szProto = GetContactProto(hContact);
- if (szProto && !strcmp(szProto, META_PROTO)) {
- MCONTACT hSubconttact = (MCONTACT)CallService(MS_MC_GETMOSTONLINECONTACT, hContact, 0);
- szProto = GetContactProto(hSubconttact);
- }
- if (szProto) {
- DWORD dwStatus = (DWORD)CallProtoService(szProto, PS_GETSTATUS, 0, 0);
- if (dwStatus == 0 || dwStatus <= ID_STATUS_OFFLINE || ((1 << (dwStatus - ID_STATUS_ONLINE)) & dwStatusMask)) // should never happen, but...
- bAllowAutoCreate = true;
- }
- }
-
- if (bAllowAutoCreate && (bAutoPopup || bAutoCreate)) {
- if (bAutoPopup) {
- TContainerData *pContainer = FindContainerByName(szName);
- if (pContainer == NULL)
- pContainer = CreateContainer(szName, FALSE, hContact);
- if (pContainer)
- CreateNewTabForContact(pContainer, hContact, 0, NULL, TRUE, TRUE, FALSE, 0);
- return 0;
- }
-
- bool bActivate = false, bPopup = M.GetByte("cpopup", 0) != 0;
- TContainerData *pContainer = FindContainerByName(szName);
- if (pContainer != NULL) {
- //if ((IsIconic(pContainer->hwnd)) && PluginConfig.haveAutoSwitch())
- // pContainer->dwFlags |= CNT_DEFERREDTABSELECT;
- if (M.GetByte("limittabs", 0) && !wcsncmp(pContainer->szName, L"default", 6)) {
- if ((pContainer = FindMatchingContainer(L"default", hContact)) != NULL) {
- CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent);
- return 0;
- }
- }
- else {
- CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent);
- return 0;
- }
- }
- if (bAutoContainer) {
- if ((pContainer = CreateContainer(szName, CNT_CREATEFLAG_MINIMIZED, hContact)) != NULL) { // 2 means create minimized, don't popup...
- CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent);
- SendMessageW(pContainer->hwnd, WM_SIZE, 0, 0);
- }
- return 0;
- }
- }
-
- /*
- * for tray support, we add the event to the tray menu. otherwise we send it back to
- * the contact list for flashing
- */
-nowindowcreate:
- if (!(dbei.flags & DBEF_READ)) {
- UpdateTrayMenu(0, 0, dbei.szModule, NULL, hContact, 1);
- if (!nen_options.bTraySupport) {
- TCHAR toolTip[256], *contactName;
-
- CLISTEVENT cle = { sizeof(cle) };
- cle.hContact = hContact;
- cle.hDbEvent = hDbEvent;
- cle.flags = CLEF_TCHAR;
- cle.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
- cle.pszService = "SRMsg/ReadMessage";
- contactName = pcli->pfnGetContactDisplayName(hContact, 0);
- mir_sntprintf(toolTip, SIZEOF(toolTip), TranslateT("Message from %s"), contactName);
- cle.ptszTooltip = toolTip;
- CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cle);
- }
- tabSRMM_ShowPopup(hContact, hDbEvent, dbei.eventType, 0, 0, 0, dbei.szModule, 0);
- }
- return 0;
-}
-
-CMimAPI M;
-FI_INTERFACE *FIF = 0;
+/*
+ * Miranda NG: the free IM client for Microsoft* Windows*
+ *
+ * Copyright (c) 2000-09 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * wraps some parts of Miranda API
+ * Also, OS dependent stuff (visual styles api etc.)
+ *
+ */
+
+#include "commonheaders.h"
+
+PDTTE CMimAPI::m_pfnDrawThemeTextEx = 0;
+DEFICA CMimAPI::m_pfnDwmExtendFrameIntoClientArea = 0;
+DICE CMimAPI::m_pfnDwmIsCompositionEnabled = 0;
+DRT CMimAPI::m_pfnDwmRegisterThumbnail = 0;
+BPI CMimAPI::m_pfnBufferedPaintInit = 0;
+BPU CMimAPI::m_pfnBufferedPaintUninit = 0;
+BBP CMimAPI::m_pfnBeginBufferedPaint = 0;
+EBP CMimAPI::m_pfnEndBufferedPaint = 0;
+BBW CMimAPI::m_pfnDwmBlurBehindWindow = 0;
+DGC CMimAPI::m_pfnDwmGetColorizationColor = 0;
+BPSA CMimAPI::m_pfnBufferedPaintSetAlpha = 0;
+DWMIIB CMimAPI::m_pfnDwmInvalidateIconicBitmaps = 0;
+DWMSWA CMimAPI::m_pfnDwmSetWindowAttribute = 0;
+DWMUT CMimAPI::m_pfnDwmUpdateThumbnailProperties = 0;
+DURT CMimAPI::m_pfnDwmUnregisterThumbnail = 0;
+DSIT CMimAPI::m_pfnDwmSetIconicThumbnail = 0;
+DSILP CMimAPI::m_pfnDwmSetIconicLivePreviewBitmap = 0;
+bool CMimAPI::m_shutDown = 0;
+TCHAR CMimAPI::m_userDir[] = _T("\0");
+
+bool CMimAPI::m_haveBufferedPaint = false;
+
+/**
+ * Case insensitive _tcsstr
+ *
+ * @param szString TCHAR *: String to be searched
+ * @param szSearchFor
+ *TCHAR *: String that should be found in szString
+ *
+ * @return TCHAR *: found position of szSearchFor in szString. 0 if szSearchFor was not found
+ */
+const TCHAR* CMimAPI::StriStr(const TCHAR *szString, const TCHAR *szSearchFor)
+{
+ assert(szString != 0 && szSearchFor != 0);
+
+ if (!szString || *szString == 0)
+ return NULL;
+
+ if (!szSearchFor || *szSearchFor == 0)
+ return szString;
+
+ for (; *szString; ++szString) {
+ if (_totupper(*szString) == _totupper(*szSearchFor)) {
+ const TCHAR *h, *n;
+ for (h = szString, n = szSearchFor; *h && *n; ++h, ++n)
+ if (_totupper(*h) != _totupper(*n))
+ break;
+
+ if (!*n)
+ return szString;
+ }
+ }
+ return NULL;
+}
+
+int CMimAPI::pathIsAbsolute(const TCHAR *path) const
+{
+ if (!path || !(lstrlen(path) > 2))
+ return 0;
+ if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\'))
+ return 1;
+ return 0;
+}
+
+size_t CMimAPI::pathToRelative(const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase) const
+{
+ const TCHAR *tszBase = szBase ? szBase : m_szProfilePath;
+
+ pOut[0] = 0;
+ if (!pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH)
+ return 0;
+ if (!pathIsAbsolute(pSrc)) {
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
+ return lstrlen(pOut);
+ }
+
+ TCHAR szTmp[MAX_PATH];
+ mir_sntprintf(szTmp, SIZEOF(szTmp), _T("%s"), pSrc);
+ if (StriStr(szTmp, tszBase)) {
+ if (tszBase[lstrlen(tszBase) - 1] == '\\')
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc + lstrlen(tszBase));
+ else {
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc + lstrlen(tszBase) + 1 );
+ //pOut[0]='.';
+ }
+ return(lstrlen(pOut));
+ }
+
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
+ return(lstrlen(pOut));
+}
+
+/**
+ * Translate a relativ path to an absolute, using the current profile
+ * data directory.
+ *
+ * @param pSrc TCHAR *: input path + filename (relative)
+ * @param pOut TCHAR *: the result
+ * @param szBase TCHAR *: (OPTIONAL) base path for the translation. Can be 0 in which case
+ * the function will use m_szProfilePath (usually \tabSRMM below %miranda_userdata%
+ *
+ * @return
+ */
+size_t CMimAPI::pathToAbsolute(const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase) const
+{
+ const TCHAR *tszBase = szBase ? szBase : m_szProfilePath;
+
+ pOut[0] = 0;
+ if (!pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH)
+ return 0;
+ if (pathIsAbsolute(pSrc) && pSrc[0]!='.')
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
+ else if (pSrc[0]=='.')
+ mir_sntprintf(pOut, MAX_PATH, _T("%s\\%s"), tszBase, pSrc + 1);
+ else
+ mir_sntprintf(pOut, MAX_PATH, _T("%s\\%s"), tszBase, pSrc);
+
+ return lstrlen(pOut);
+}
+
+/*
+ * window list functions
+ */
+
+void CMimAPI::BroadcastMessage(UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WindowList_Broadcast(m_hMessageWindowList, msg, wParam, lParam);
+}
+
+void CMimAPI::BroadcastMessageAsync(UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WindowList_BroadcastAsync(m_hMessageWindowList, msg, wParam, lParam);
+}
+
+HWND CMimAPI::FindWindow(MCONTACT h) const
+{
+ return WindowList_Find(m_hMessageWindowList, h);
+}
+
+INT_PTR CMimAPI::AddWindow(HWND hWnd, MCONTACT h)
+{
+ return WindowList_Add(m_hMessageWindowList, hWnd, h);
+}
+
+INT_PTR CMimAPI::RemoveWindow(HWND hWnd)
+{
+ return WindowList_Remove(m_hMessageWindowList, hWnd);
+}
+
+int CMimAPI::FoldersPathChanged(WPARAM wParam, LPARAM lParam)
+{
+ return M.foldersPathChanged();
+}
+
+void CMimAPI::configureCustomFolders()
+{
+ m_hDataPath = FoldersRegisterCustomPathT(LPGEN("TabSRMM"), LPGEN("Data path"), const_cast<TCHAR *>(getDataPath()));
+ m_hSkinsPath = FoldersRegisterCustomPathT(LPGEN("Skins"), LPGEN("TabSRMM"), const_cast<TCHAR *>(getSkinPath()));
+ m_hAvatarsPath = FoldersRegisterCustomPathT(LPGEN("Avatars"), LPGEN("Saved TabSRMM avatars"), const_cast<TCHAR *>(getSavedAvatarPath()));
+ m_hChatLogsPath = FoldersRegisterCustomPathT(LPGEN("TabSRMM"), LPGEN("Group chat logs root"), const_cast<TCHAR *>(getChatLogPath()));
+
+ if (m_hDataPath)
+ HookEvent(ME_FOLDERS_PATH_CHANGED, CMimAPI::FoldersPathChanged);
+
+ foldersPathChanged();
+}
+
+INT_PTR CMimAPI::foldersPathChanged()
+{
+ TCHAR szTemp[MAX_PATH + 2] = {'\0'};
+
+ if (m_hDataPath) {
+ FoldersGetCustomPathT(m_hDataPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getDataPath()));
+ mir_sntprintf(m_szProfilePath, MAX_PATH, _T("%s"), szTemp);
+
+ FoldersGetCustomPathT(m_hSkinsPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getSkinPath()));
+ mir_sntprintf(m_szSkinsPath, MAX_PATH - 1, _T("%s"), szTemp);
+ Utils::ensureTralingBackslash(m_szSkinsPath);
+
+ FoldersGetCustomPathT(m_hAvatarsPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getSavedAvatarPath()));
+ mir_sntprintf(m_szSavedAvatarsPath, MAX_PATH, _T("%s"), szTemp);
+
+ FoldersGetCustomPathT(m_hChatLogsPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getChatLogPath()));
+ mir_sntprintf(m_szChatLogsPath, MAX_PATH, _T("%s"), szTemp);
+ Utils::ensureTralingBackslash(m_szChatLogsPath);
+ }
+
+ CreateDirectoryTreeT(m_szProfilePath);
+ CreateDirectoryTreeT(m_szSkinsPath);
+ CreateDirectoryTreeT(m_szSavedAvatarsPath);
+
+ Skin->extractSkinsAndLogo(true);
+ Skin->setupAeroSkins();
+ return 0;
+}
+
+const TCHAR* CMimAPI::getUserDir()
+{
+ if (m_userDir[0] == 0) {
+ if ( ServiceExists(MS_FOLDERS_REGISTER_PATH))
+ lstrcpyn(m_userDir, L"%miranda_userdata%", SIZEOF(m_userDir));
+ else
+ lstrcpyn(m_userDir, VARST( _T("%miranda_userdata%")), SIZEOF(m_userDir));
+
+ Utils::ensureTralingBackslash(m_userDir);
+ }
+ return m_userDir;
+}
+
+void CMimAPI::InitPaths()
+{
+ m_szProfilePath[0] = 0;
+ m_szSkinsPath[0] = 0;
+ m_szSavedAvatarsPath[0] = 0;
+
+ const TCHAR *szUserdataDir = getUserDir();
+
+ mir_sntprintf(m_szProfilePath, MAX_PATH, _T("%stabSRMM"), szUserdataDir);
+ if (ServiceExists(MS_FOLDERS_REGISTER_PATH)) {
+ lstrcpyn(m_szChatLogsPath, _T("%miranda_logpath%"), MAX_PATH);
+ lstrcpyn(m_szSkinsPath, _T("%miranda_path%\\Skins\\TabSRMM"), MAX_PATH);
+ }
+ else {
+ lstrcpyn(m_szChatLogsPath, VARST(_T("%miranda_logpath%")), MAX_PATH);
+ lstrcpyn(m_szSkinsPath, VARST(_T("%miranda_path%\\Skins\\TabSRMM")), MAX_PATH);
+ }
+
+ Utils::ensureTralingBackslash(m_szChatLogsPath);
+ replaceStrT(g_Settings.pszLogDir, m_szChatLogsPath);
+
+ Utils::ensureTralingBackslash(m_szSkinsPath);
+
+ mir_sntprintf(m_szSavedAvatarsPath, MAX_PATH, _T("%s\\Saved Contact Pictures"), m_szProfilePath);
+}
+
+bool CMimAPI::getAeroState()
+{
+ BOOL result = FALSE;
+ m_isAero = m_DwmActive = false;
+ if (IsWinVerVistaPlus()) {
+ m_DwmActive = (m_pfnDwmIsCompositionEnabled && (m_pfnDwmIsCompositionEnabled(&result) == S_OK) && result) ? true : false;
+ m_isAero = (CSkin::m_skinEnabled == false) && GetByte("useAero", 1) && CSkin::m_fAeroSkinsValid && m_DwmActive;
+
+ }
+ m_isVsThemed = IsThemeActive() != 0;
+ return m_isAero;
+}
+
+/**
+ * Initialize various Win32 API functions which are not common to all versions of Windows.
+ * We have to work with functions pointers here.
+ */
+
+void CMimAPI::InitAPI()
+{
+ m_hUxTheme = 0;
+
+ /*
+ * vista+ DWM API
+ */
+ m_hDwmApi = 0;
+ if (IsWinVerVistaPlus()) {
+ m_hDwmApi = Utils::loadSystemLibrary(L"\\dwmapi.dll");
+ if (m_hDwmApi) {
+ m_pfnDwmExtendFrameIntoClientArea = (DEFICA)GetProcAddress(m_hDwmApi,"DwmExtendFrameIntoClientArea");
+ m_pfnDwmIsCompositionEnabled = (DICE)GetProcAddress(m_hDwmApi,"DwmIsCompositionEnabled");
+ m_pfnDwmRegisterThumbnail = (DRT)GetProcAddress(m_hDwmApi, "DwmRegisterThumbnail");
+ m_pfnDwmBlurBehindWindow = (BBW)GetProcAddress(m_hDwmApi, "DwmEnableBlurBehindWindow");
+ m_pfnDwmGetColorizationColor = (DGC)GetProcAddress(m_hDwmApi, "DwmGetColorizationColor");
+ m_pfnDwmInvalidateIconicBitmaps = (DWMIIB)GetProcAddress(m_hDwmApi, "DwmInvalidateIconicBitmaps");
+ m_pfnDwmSetWindowAttribute = (DWMSWA)GetProcAddress(m_hDwmApi, "DwmSetWindowAttribute");
+ m_pfnDwmUpdateThumbnailProperties = (DWMUT)GetProcAddress(m_hDwmApi, "DwmUpdateThumbnailProperties");
+ m_pfnDwmUnregisterThumbnail = (DURT)GetProcAddress(m_hDwmApi, "DwmUnregisterThumbnail");
+ m_pfnDwmSetIconicThumbnail = (DSIT)GetProcAddress(m_hDwmApi, "DwmSetIconicThumbnail");
+ m_pfnDwmSetIconicLivePreviewBitmap = (DSILP)GetProcAddress(m_hDwmApi, "DwmSetIconicLivePreviewBitmap");
+ }
+ /*
+ * additional uxtheme APIs (Vista+)
+ */
+ m_hUxTheme = Utils::loadSystemLibrary(L"\\uxtheme.dll");
+ if (m_hUxTheme) {
+ m_pfnDrawThemeTextEx = (PDTTE)GetProcAddress(m_hUxTheme, "DrawThemeTextEx");
+ m_pfnBeginBufferedPaint = (BBP)GetProcAddress(m_hUxTheme, "BeginBufferedPaint");
+ m_pfnEndBufferedPaint = (EBP)GetProcAddress(m_hUxTheme, "EndBufferedPaint");
+ m_pfnBufferedPaintInit = (BPI)GetProcAddress(m_hUxTheme, "BufferedPaintInit");
+ m_pfnBufferedPaintUninit = (BPU)GetProcAddress(m_hUxTheme, "BufferedPaintUnInit");
+ m_pfnBufferedPaintSetAlpha = (BPSA)GetProcAddress(m_hUxTheme, "BufferedPaintSetAlpha");
+ m_haveBufferedPaint = (m_pfnBeginBufferedPaint != 0 && m_pfnEndBufferedPaint != 0) ? true : false;
+ if (m_haveBufferedPaint)
+ m_pfnBufferedPaintInit();
+ }
+ }
+ else m_haveBufferedPaint = false;
+}
+
+/**
+ * hook subscriber function for incoming message typing events
+ */
+
+int CMimAPI::TypingMessage(WPARAM hContact, LPARAM lParam)
+{
+ HWND hwnd = 0;
+ int issplit = 1, foundWin = 0, preTyping = 0;
+ BOOL fShowOnClist = TRUE;
+
+ if (hContact) {
+ if ((hwnd = M.FindWindow(hContact)) && M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPING, SRMSGDEFSET_SHOWTYPING))
+ preTyping = SendMessage(hwnd, DM_TYPING, 0, lParam);
+
+ if (hwnd && IsWindowVisible(hwnd))
+ foundWin = MessageWindowOpened(0, (LPARAM)hwnd);
+ else
+ foundWin = 0;
+
+ TContainerData *pContainer = NULL;
+ if (hwnd) {
+ SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer);
+ if (pContainer == NULL)
+ return 0; // should never happen
+ }
+
+ if ( M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGCLIST, SRMSGDEFSET_SHOWTYPINGCLIST)) {
+ if (!hwnd && !M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGNOWINOPEN, 1))
+ fShowOnClist = FALSE;
+ if (hwnd && !M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGWINOPEN, 1))
+ fShowOnClist = FALSE;
+ }
+ else fShowOnClist = FALSE;
+
+ if ((!foundWin || !(pContainer->dwFlags & CNT_NOSOUND)) && preTyping != (lParam != 0))
+ SkinPlaySound((lParam) ? "TNStart" : "TNStop");
+
+ if (M.GetByte(SRMSGMOD, "ShowTypingPopup", 0)) {
+ BOOL fShow = FALSE;
+ int iMode = M.GetByte("MTN_PopupMode", 0);
+
+ switch(iMode) {
+ case 0:
+ fShow = TRUE;
+ break;
+ case 1:
+ if (!foundWin || !(pContainer && pContainer->hwndActive == hwnd && GetForegroundWindow() == pContainer->hwnd))
+ fShow = TRUE;
+ break;
+ case 2:
+ if (hwnd == 0)
+ fShow = TRUE;
+ else {
+ if (PluginConfig.m_HideOnClose) {
+ TContainerData *pContainer = 0;
+ SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer);
+ if (pContainer && pContainer->fHidden)
+ fShow = TRUE;
+ }
+ }
+ break;
+ }
+ if (fShow)
+ TN_TypingMessage(hContact, lParam);
+ }
+
+ if (lParam) {
+ TCHAR szTip[256];
+ mir_sntprintf(szTip, SIZEOF(szTip), TranslateT("%s is typing a message"), pcli->pfnGetContactDisplayName(hContact, 0));
+ if (fShowOnClist && ServiceExists(MS_CLIST_SYSTRAY_NOTIFY) && M.GetByte(SRMSGMOD, "ShowTypingBalloon", 0)) {
+ MIRANDASYSTRAYNOTIFY tn;
+ tn.szProto = NULL;
+ tn.cbSize = sizeof(tn);
+ tn.tszInfoTitle = TranslateT("Typing Notification");
+ tn.tszInfo = szTip;
+ tn.dwInfoFlags = NIIF_INFO | NIIF_INTERN_UNICODE;
+ tn.uTimeout = 1000 * 4;
+ CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&tn);
+ }
+ if (fShowOnClist) {
+ CLISTEVENT cle = { sizeof(cle) };
+ cle.hContact = hContact;
+ cle.hDbEvent = (HANDLE)1;
+ cle.flags = CLEF_ONLYAFEW | CLEF_TCHAR;
+ cle.hIcon = PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING];
+ cle.pszService = "SRMsg/TypingMessage";
+ cle.ptszTooltip = szTip;
+ CallServiceSync(MS_CLIST_REMOVEEVENT, hContact, 1);
+ CallServiceSync(MS_CLIST_ADDEVENT, hContact, (LPARAM)&cle);
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * this is the global ack dispatcher. It handles both ACKTYPE_MESSAGE and ACKTYPE_AVATAR events
+ * for ACKTYPE_MESSAGE it searches the corresponding send job in the queue and, if found, dispatches
+ * it to the owners window
+ *
+ * ACKTYPE_AVATAR no longer handled here, because we have avs services now.
+ */
+
+int CMimAPI::ProtoAck(WPARAM wParam, LPARAM lParam)
+{
+ ACKDATA *pAck = (ACKDATA*)lParam;
+ if (lParam == 0)
+ return 0;
+
+ HWND hwndDlg = 0;
+ int i=0, iFound = SendQueue::NR_SENDJOBS;
+ SendJob *jobs = sendQueue->getJobByIndex(0);
+
+ if (pAck->type == ACKTYPE_MESSAGE) {
+ MCONTACT hMeta = db_mc_getMeta(pAck->hContact);
+ for (int j = 0; j < SendQueue::NR_SENDJOBS; j++) {
+ SendJob &p = jobs[j];
+ if (pAck->hProcess == p.hSendId && pAck->hContact == p.hOwner) {
+ TWindowData *dat = p.hwndOwner ? (TWindowData*)GetWindowLongPtr(p.hwndOwner, GWLP_USERDATA) : NULL;
+ if (dat == NULL) {
+ sendQueue->ackMessage(NULL, (WPARAM)MAKELONG(j, i), lParam);
+ return 0;
+ }
+ if (dat->hContact == p.hOwner || dat->hContact == hMeta) {
+ iFound = j;
+ break;
+ }
+ }
+ if (iFound != SendQueue::NR_SENDJOBS) // no mathing entry found in this queue entry.. continue
+ break;
+ }
+ if (iFound == SendQueue::NR_SENDJOBS) // no matching send info found in the queue
+ sendLater->processAck(pAck);
+ else // try to find the process handle in the list of open send later jobs
+ SendMessage(jobs[iFound].hwndOwner, HM_EVENTSENT, (WPARAM)MAKELONG(iFound, i), lParam);
+ }
+ return 0;
+}
+
+int CMimAPI::PrebuildContactMenu(WPARAM hContact, LPARAM lParam)
+{
+ if (hContact == NULL)
+ return NULL;
+
+ bool bEnabled = false;
+ char *szProto = GetContactProto(hContact);
+ if (szProto) {
+ // leave this menu item hidden for chats
+ if ( !db_get_b(hContact, szProto, "ChatRoom", 0 ))
+ if ( CallProtoService( szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND)
+ bEnabled = true;
+ }
+
+ Menu_ShowItem(PluginConfig.m_hMenuItem, bEnabled);
+ return 0;
+}
+
+/**
+ * this handler is called first in the message window chain - it will handle events for which a message window
+ * is already open. if not, it will do nothing and the 2nd handler (MessageEventAdded) will perform all
+ * the needed actions.
+ *
+ * this handler POSTs the event to the message window procedure - so it is fast and can exit quickly which will
+ * improve the overall responsiveness when receiving messages.
+ */
+
+int CMimAPI::DispatchNewEvent(WPARAM hContact, LPARAM lParam)
+{
+ if (hContact) {
+ HWND h = M.FindWindow(hContact);
+ if (h == NULL)
+ h = M.FindWindow(hContact = db_event_getContact((HANDLE)lParam));
+ if (h)
+ PostMessage(h, HM_DBEVENTADDED, hContact, lParam); // was SENDMESSAGE !!! XXX
+ }
+ return 0;
+}
+
+/**
+ * Message event added is called when a new message is added to the database
+ * if no session is open for the contact, this function will determine if and how a new message
+ * session (tab) must be created.
+ *
+ * if a session is already created, it just does nothing and DispatchNewEvent() will take care.
+ */
+
+int CMimAPI::MessageEventAdded(WPARAM hContact, LPARAM lParam)
+{
+ TCHAR szName[CONTAINER_NAMELEN + 1];
+
+ HANDLE hDbEvent = (HANDLE)lParam;
+ DBEVENTINFO dbei = { sizeof(dbei) };
+ db_event_get(hDbEvent, &dbei);
+
+ HWND hwnd = M.FindWindow(hContact);
+ if (hwnd == NULL)
+ hwnd = M.FindWindow(db_event_getContact(hDbEvent));
+
+ BOOL isCustomEvent = IsCustomEvent(dbei.eventType);
+ BOOL isShownCustomEvent = DbEventIsForMsgWindow(&dbei);
+ if (dbei.markedRead() || (isCustomEvent && !isShownCustomEvent))
+ return 0;
+
+ CallServiceSync(MS_CLIST_REMOVEEVENT, hContact, 1);
+
+ bool bAllowAutoCreate = false;
+ bool bAutoPopup = M.GetByte(SRMSGSET_AUTOPOPUP, SRMSGDEFSET_AUTOPOPUP) != 0;
+ bool bAutoCreate = M.GetByte("autotabs", 1) != 0;
+ bool bAutoContainer = M.GetByte("autocontainer", 1) != 0;
+ DWORD dwStatusMask = M.GetDword("autopopupmask", -1);
+
+ if (hwnd) {
+ TContainerData *pTargetContainer = 0;
+ SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pTargetContainer);
+ if (pTargetContainer == NULL || !PluginConfig.m_HideOnClose || IsWindowVisible(pTargetContainer->hwnd))
+ return 0;
+
+ WINDOWPLACEMENT wp = { 0 };
+ wp.length = sizeof(wp);
+ GetWindowPlacement(pTargetContainer->hwnd, &wp);
+ GetContainerNameForContact(hContact, szName, CONTAINER_NAMELEN);
+
+ if (bAutoPopup || bAutoCreate) {
+ if (bAutoPopup) {
+ if (wp.showCmd == SW_SHOWMAXIMIZED)
+ ShowWindow(pTargetContainer->hwnd, SW_SHOWMAXIMIZED);
+ else
+ ShowWindow(pTargetContainer->hwnd, SW_SHOWNOACTIVATE);
+ return 0;
+ }
+
+ TContainerData *pContainer = FindContainerByName(szName);
+ if (pContainer != NULL) {
+ if (bAutoContainer) {
+ ShowWindow(pTargetContainer->hwnd, SW_SHOWMINNOACTIVE);
+ return 0;
+ }
+ goto nowindowcreate;
+ }
+ else if (bAutoContainer) {
+ ShowWindow(pTargetContainer->hwnd, SW_SHOWMINNOACTIVE);
+ return 0;
+ }
+ }
+ }
+ else {
+ switch (dbei.eventType) {
+ case EVENTTYPE_AUTHREQUEST:
+ case EVENTTYPE_ADDED:
+ return 0;
+
+ case EVENTTYPE_FILE:
+ tabSRMM_ShowPopup(hContact, hDbEvent, dbei.eventType, 0, 0, 0, dbei.szModule, 0);
+ return 0;
+ }
+ }
+
+ // if no window is open, we are not interested in anything else but unread message events
+ // new message
+ if (!nen_options.iNoSounds)
+ SkinPlaySound("AlertMsg");
+
+ if (nen_options.iNoAutoPopup)
+ goto nowindowcreate;
+
+ GetContainerNameForContact(hContact, szName, CONTAINER_NAMELEN);
+
+ if (dwStatusMask == -1)
+ bAllowAutoCreate = true;
+ else {
+ char *szProto = GetContactProto(hContact);
+ if (szProto && !strcmp(szProto, META_PROTO)) {
+ MCONTACT hSubconttact = (MCONTACT)CallService(MS_MC_GETMOSTONLINECONTACT, hContact, 0);
+ szProto = GetContactProto(hSubconttact);
+ }
+ if (szProto) {
+ DWORD dwStatus = (DWORD)CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+ if (dwStatus == 0 || dwStatus <= ID_STATUS_OFFLINE || ((1 << (dwStatus - ID_STATUS_ONLINE)) & dwStatusMask)) // should never happen, but...
+ bAllowAutoCreate = true;
+ }
+ }
+
+ if (bAllowAutoCreate && (bAutoPopup || bAutoCreate)) {
+ if (bAutoPopup) {
+ TContainerData *pContainer = FindContainerByName(szName);
+ if (pContainer == NULL)
+ pContainer = CreateContainer(szName, FALSE, hContact);
+ if (pContainer)
+ CreateNewTabForContact(pContainer, hContact, 0, NULL, TRUE, TRUE, FALSE, 0);
+ return 0;
+ }
+
+ bool bActivate = false, bPopup = M.GetByte("cpopup", 0) != 0;
+ TContainerData *pContainer = FindContainerByName(szName);
+ if (pContainer != NULL) {
+ //if ((IsIconic(pContainer->hwnd)) && PluginConfig.haveAutoSwitch())
+ // pContainer->dwFlags |= CNT_DEFERREDTABSELECT;
+ if (M.GetByte("limittabs", 0) && !wcsncmp(pContainer->szName, L"default", 6)) {
+ if ((pContainer = FindMatchingContainer(L"default", hContact)) != NULL) {
+ CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent);
+ return 0;
+ }
+ }
+ else {
+ CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent);
+ return 0;
+ }
+ }
+ if (bAutoContainer) {
+ if ((pContainer = CreateContainer(szName, CNT_CREATEFLAG_MINIMIZED, hContact)) != NULL) { // 2 means create minimized, don't popup...
+ CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent);
+ SendMessageW(pContainer->hwnd, WM_SIZE, 0, 0);
+ }
+ return 0;
+ }
+ }
+
+ /*
+ * for tray support, we add the event to the tray menu. otherwise we send it back to
+ * the contact list for flashing
+ */
+nowindowcreate:
+ if (!(dbei.flags & DBEF_READ)) {
+ UpdateTrayMenu(0, 0, dbei.szModule, NULL, hContact, 1);
+ if (!nen_options.bTraySupport) {
+ TCHAR toolTip[256], *contactName;
+
+ CLISTEVENT cle = { sizeof(cle) };
+ cle.hContact = hContact;
+ cle.hDbEvent = hDbEvent;
+ cle.flags = CLEF_TCHAR;
+ cle.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+ cle.pszService = "SRMsg/ReadMessage";
+ contactName = pcli->pfnGetContactDisplayName(hContact, 0);
+ mir_sntprintf(toolTip, SIZEOF(toolTip), TranslateT("Message from %s"), contactName);
+ cle.ptszTooltip = toolTip;
+ CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cle);
+ }
+ tabSRMM_ShowPopup(hContact, hDbEvent, dbei.eventType, 0, 0, 0, dbei.szModule, 0);
+ }
+ return 0;
+}
+
+CMimAPI M;
+FI_INTERFACE *FIF = 0;