From 938aaa96f63e6cab2803eab57f67e93f5c352df0 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Tue, 14 Jan 2014 15:06:48 +0000 Subject: kernel chat's engine, part 1 (compiles ok, doesn't work at all, not linked to the core) git-svn-id: http://svn.miranda-ng.org/main/trunk@7645 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- src/modules/chat/manager.cpp | 1639 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1639 insertions(+) create mode 100644 src/modules/chat/manager.cpp (limited to 'src/modules/chat/manager.cpp') diff --git a/src/modules/chat/manager.cpp b/src/modules/chat/manager.cpp new file mode 100644 index 0000000000..b50bc34598 --- /dev/null +++ b/src/modules/chat/manager.cpp @@ -0,0 +1,1639 @@ +/* +Chat module plugin for Miranda IM + +Copyright 2000-12 Miranda IM, 2012-14 Miranda NG project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\..\core\commonheaders.h" + +#include "chat.h" + +#define WINDOWS_COMMANDS_MAX 30 +#define STATUSICONCOUNT 6 + +SESSION_INFO *m_WndList = 0; +TABLIST *g_TabList = 0; +MODULEINFO *m_ModList = 0; + +static void SetActiveSessionEx(SESSION_INFO *si) +{ + if (si) { + replaceStrT(ci.szActiveWndID, si->ptszID); + replaceStr(ci.szActiveWndModule, si->pszModule); + } +} + +static void SetActiveSession(const TCHAR *pszID, const char* pszModule) +{ + SESSION_INFO *si = ci.SM_FindSession(pszID, pszModule); + if (si) + SetActiveSessionEx(si); +} + +static SESSION_INFO* GetActiveSession(void) +{ + SESSION_INFO *si = ci.SM_FindSession(ci.szActiveWndID, ci.szActiveWndModule); + if (si) + return si; + + return m_WndList; +} + +//--------------------------------------------------- +// Session Manager functions +// +// Keeps track of all sessions and its windows +//--------------------------------------------------- + +static SESSION_INFO* SM_AddSession(const TCHAR *pszID, const char* pszModule) +{ + if (!pszID || !pszModule) + return NULL; + + if (!ci.SM_FindSession(pszID, pszModule)) { + SESSION_INFO*node = (SESSION_INFO*)mir_alloc(sizeof(SESSION_INFO)); + ZeroMemory(node, sizeof(SESSION_INFO)); + node->ptszID = mir_tstrdup(pszID); + node->pszModule = mir_strdup(pszModule); + + if (m_WndList == NULL) { // list is empty + m_WndList = node; + node->next = NULL; + } + else { + node->next = m_WndList; + m_WndList = node; + } + return node; + } + return NULL; +} + +static int SM_RemoveSession(const TCHAR *pszID, const char* pszModule, BOOL removeContact) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + if (!pszModule) + return FALSE; + + while (pTemp != NULL) { + if ((!pszID && pTemp->iType != GCW_SERVER || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) // match + { + COMMANDINFO *pCurComm; + DWORD dw = pTemp->dwItemData; + + if (!ci.pSettings->TabsEnable) { + if (pTemp->hWnd) + SendMessage(pTemp->hWnd, GC_EVENT_CONTROL + WM_USER + 500, SESSION_TERMINATE, 0); + } + else if (ci.tabSession.hWnd) + SendMessage(ci.tabSession.hWnd, GC_REMOVETAB, 1, (LPARAM)pTemp); + + if (pTemp->hWnd) + ci.tabSession.nUsersInNicklist = 0; + + DoEventHook(pTemp->ptszID, pTemp->pszModule, GC_SESSION_TERMINATE, NULL, NULL, (DWORD)pTemp->dwItemData); + + if (pLast == NULL) + m_WndList = pTemp->next; + else + pLast->next = pTemp->next; + + ci.UM_RemoveAll(&pTemp->pUsers); + ci.TM_RemoveAll(&pTemp->pStatuses); + ci.LM_RemoveAll(&pTemp->pLog, &pTemp->pLogEnd); + pTemp->iStatusCount = 0; + pTemp->nUsersInNicklist = 0; + + // contact may have been deleted here already, since function may be called after deleting + // contact so the handle may be invalid, therefore db_get_b shall return 0 + if (pTemp->hContact && db_get_b(pTemp->hContact, pTemp->pszModule, "ChatRoom", 0) != 0) { + CList_SetOffline(pTemp->hContact, pTemp->iType == GCW_CHATROOM ? TRUE : FALSE); + db_set_s(pTemp->hContact, pTemp->pszModule, "Topic", ""); + db_set_s(pTemp->hContact, pTemp->pszModule, "StatusBar", ""); + db_unset(pTemp->hContact, "CList", "StatusMsg"); + + if (removeContact) + CallService(MS_DB_CONTACT_DELETE, (WPARAM)pTemp->hContact, 0); + } + + mir_free(pTemp->pszModule); + mir_free(pTemp->ptszID); + mir_free(pTemp->ptszName); + mir_free(pTemp->ptszStatusbarText); + mir_free(pTemp->ptszTopic); + mir_free(pTemp->pszID); + mir_free(pTemp->pszName); + + // delete commands + pCurComm = pTemp->lpCommands; + while (pCurComm != NULL) { + COMMANDINFO *pNext = pCurComm->next; + mir_free(pCurComm->lpCommand); + mir_free(pCurComm); + pCurComm = pNext; + } + + mir_free(pTemp); + if (pszID) + return (int)dw; + if (pLast) + pTemp = pLast->next; + else + pTemp = m_WndList; + } + else { + pLast = pTemp; + pTemp = pTemp->next; + } + } + return FALSE; +} + +static SESSION_INFO* SM_FindSession(const TCHAR *pszID, const char* pszModule) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + if (!pszID || !pszModule) + return NULL; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) + return pTemp; + + pLast = pTemp; + pTemp = pTemp->next; + } + return NULL; +} + +static BOOL SM_SetOffline(const TCHAR *pszID, const char* pszModule) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + if (!pszModule) + return FALSE; + + while (pTemp != NULL) { + if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + ci.UM_RemoveAll(&pTemp->pUsers); + pTemp->nUsersInNicklist = 0; + if (pTemp->hWnd) + ci.tabSession.nUsersInNicklist = 0; + if (pTemp->iType != GCW_SERVER) + pTemp->bInitDone = FALSE; + if (ci.pSettings->TabsEnable && pTemp->hWnd) + ci.tabSession.pUsers = 0; + + if (pszID) + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +static BOOL SM_SetStatusEx(const TCHAR *pszID, const char* pszModule, const TCHAR* pszText, int flags) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + if (!pszModule) + return FALSE; + + while (pTemp != NULL) { + if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + ci.UM_SetStatusEx(pTemp->pUsers, pszText, flags); + if (pTemp->hWnd) + RedrawWindow(GetDlgItem(pTemp->hWnd, IDC_LIST), NULL, NULL, RDW_INVALIDATE); + if (pszID) + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +static HICON SM_GetStatusIcon(SESSION_INFO *si, USERINFO * ui) +{ + if (!ui || !si) + return NULL; + + STATUSINFO *ti = ci.TM_FindStatus(si->pStatuses, ci.TM_WordToString(si->pStatuses, ui->Status)); + if (ti != NULL) { + if ((INT_PTR)ti->hIcon >= STATUSICONCOUNT) + return ti->hIcon; + + int id = si->iStatusCount - (int)ti->hIcon - 1; + if (id == 0) + return ci.hIcons[ICON_STATUS0]; + if (id == 1) + return ci.hIcons[ICON_STATUS1]; + if (id == 2) + return ci.hIcons[ICON_STATUS2]; + if (id == 3) + return ci.hIcons[ICON_STATUS3]; + if (id == 4) + return ci.hIcons[ICON_STATUS4]; + if (id == 5) + return ci.hIcons[ICON_STATUS5]; + } + return ci.hIcons[ICON_STATUS0]; +} + +static BOOL SM_AddEventToAllMatchingUID(GCEVENT *gce) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + int bManyFix = 0; + + while (pTemp != NULL) { + if (!lstrcmpiA(pTemp->pszModule, gce->pDest->pszModule)) { + if (ci.UM_FindUser(pTemp->pUsers, gce->ptszUID)) { + if (pTemp->bInitDone) { + if (ci.SM_AddEvent(pTemp->ptszID, pTemp->pszModule, gce, FALSE) && pTemp->hWnd && pTemp->bInitDone) { + ci.tabSession.pLog = pTemp->pLog; + ci.tabSession.pLogEnd = pTemp->pLogEnd; + SendMessage(pTemp->hWnd, GC_ADDLOG, 0, 0); + } + else if (pTemp->hWnd && pTemp->bInitDone) { + ci.tabSession.pLog = pTemp->pLog; + ci.tabSession.pLogEnd = pTemp->pLogEnd; + SendMessage(pTemp->hWnd, GC_REDRAWLOG2, 0, 0); + } + if (!(gce->dwFlags & GCEF_NOTNOTIFY)) + DoSoundsFlashPopupTrayStuff(pTemp, gce, FALSE, bManyFix); + bManyFix++; + if ((gce->dwFlags & GCEF_ADDTOLOG) && ci.pSettings->LoggingEnabled) + LogToFile(pTemp, gce); + } + } + } + + pLast = pTemp; + pTemp = pTemp->next; + } + + return 0; +} + +static BOOL SM_AddEvent(const TCHAR *pszID, const char* pszModule, GCEVENT *gce, BOOL bIsHighlighted) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + if (!pszID || !pszModule) + return TRUE; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + LOGINFO *li = ci.LM_AddEvent(&pTemp->pLog, &pTemp->pLogEnd); + pTemp->iEventCount += 1; + + li->iType = gce->pDest->iType; + li->ptszNick = mir_tstrdup(gce->ptszNick); + li->ptszText = mir_tstrdup(gce->ptszText); + li->ptszStatus = mir_tstrdup(gce->ptszStatus); + li->ptszUserInfo = mir_tstrdup(gce->ptszUserInfo); + + li->bIsMe = gce->bIsMe; + li->time = gce->time; + li->bIsHighlighted = bIsHighlighted; + + if (ci.pSettings->iEventLimit > 0 && pTemp->iEventCount > ci.pSettings->iEventLimit + 20) { + ci.LM_TrimLog(&pTemp->pLog, &pTemp->pLogEnd, pTemp->iEventCount - ci.pSettings->iEventLimit); + pTemp->iEventCount = ci.pSettings->iEventLimit; + return FALSE; + } + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +static USERINFO* SM_AddUser(const TCHAR *pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszNick, WORD wStatus) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + if (!pszID || !pszModule) + return NULL; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + USERINFO *p = ci.UM_AddUser(pTemp->pStatuses, &pTemp->pUsers, pszUID, pszNick, wStatus); + pTemp->nUsersInNicklist++; + if (pTemp->hWnd) + ci.tabSession.nUsersInNicklist++; + return p; + } + pLast = pTemp; + pTemp = pTemp->next; + } + + return 0; +} + +static BOOL SM_MoveUser(const TCHAR *pszID, const char* pszModule, const TCHAR* pszUID) +{ + SESSION_INFO *pTemp = m_WndList; + + if (!pszID || !pszModule || !pszUID) + return FALSE; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + ci.UM_SortUser(&pTemp->pUsers, pszUID); + return TRUE; + } + pTemp = pTemp->next; + } + + return FALSE; +} + +static BOOL SM_RemoveUser(const TCHAR *pszID, const char* pszModule, const TCHAR* pszUID) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + if (!pszModule || !pszUID) + return FALSE; + + while (pTemp != NULL) { + if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + DWORD dw; + USERINFO *ui = ci.UM_FindUser(pTemp->pUsers, pszUID); + if (ui) { + pTemp->nUsersInNicklist--; + if (pTemp->hWnd) { + ci.tabSession.pUsers = pTemp->pUsers; + ci.tabSession.nUsersInNicklist--; + } + + dw = ci.UM_RemoveUser(&pTemp->pUsers, pszUID); + + if (pTemp->hWnd) + SendMessage(pTemp->hWnd, GC_UPDATENICKLIST, 0, 0); + + if (pszID) + return TRUE; + } + } + + pLast = pTemp; + pTemp = pTemp->next; + } + + return 0; +} + +static USERINFO* SM_GetUserFromIndex(const TCHAR *pszID, const char* pszModule, int index) +{ + SESSION_INFO *pTemp = m_WndList; + + if (!pszModule) + return FALSE; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) + return ci.UM_FindUserFromIndex(pTemp->pUsers, index); + pTemp = pTemp->next; + } + + return NULL; +} + + +STATUSINFO * SM_AddStatus(const TCHAR *pszID, const char* pszModule, const TCHAR* pszStatus) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + if (!pszID || !pszModule) + return NULL; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + STATUSINFO *ti = ci.TM_AddStatus(&pTemp->pStatuses, pszStatus, &pTemp->iStatusCount); + if (ti) + pTemp->iStatusCount++; + if (ci.pSettings->TabsEnable && pTemp->hWnd) + ci.tabSession.pStatuses = pTemp->pStatuses; + return ti; + } + pLast = pTemp; + pTemp = pTemp->next; + } + + return 0; +} + +static BOOL SM_GiveStatus(const TCHAR *pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszStatus) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + if (!pszID || !pszModule) + return FALSE; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + USERINFO *ui = ci.UM_GiveStatus(pTemp->pUsers, pszUID, ci.TM_StringToWord(pTemp->pStatuses, pszStatus)); + if (ui) { + SM_MoveUser(pTemp->ptszID, pTemp->pszModule, ui->pszUID); + if (pTemp->hWnd) + SendMessage(pTemp->hWnd, GC_UPDATENICKLIST, 0, 0); + } + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + + return FALSE; +} + +static BOOL SM_SetContactStatus(const TCHAR *pszID, const char* pszModule, const TCHAR* pszUID, WORD wStatus) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszID || !pszModule) + return FALSE; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + USERINFO *ui = ci.UM_SetContactStatus(pTemp->pUsers, pszUID, wStatus); + if (ui) { + SM_MoveUser(pTemp->ptszID, pTemp->pszModule, ui->pszUID); + if (pTemp->hWnd) + SendMessage(pTemp->hWnd, GC_UPDATENICKLIST, 0, 0); + } + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + + return FALSE; +} + +static BOOL SM_TakeStatus(const TCHAR *pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszStatus) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + if (!pszID || !pszModule) + return FALSE; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + USERINFO* ui = ci.UM_TakeStatus(pTemp->pUsers, pszUID, ci.TM_StringToWord(pTemp->pStatuses, pszStatus)); + if (ui) { + SM_MoveUser(pTemp->ptszID, pTemp->pszModule, ui->pszUID); + if (pTemp->hWnd) + SendMessage(pTemp->hWnd, GC_UPDATENICKLIST, 0, 0); + } + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + + return FALSE; +} + +static LRESULT SM_SendMessage(const TCHAR *pszID, const char* pszModule, UINT msg, WPARAM wParam, LPARAM lParam) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + while (pTemp && pszModule) { + if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + if (pTemp->hWnd) { + LRESULT i = SendMessage(pTemp->hWnd, msg, wParam, lParam); + if (pszID) + return i; + } + if (pszID) + return 0; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +static BOOL SM_PostMessage(const TCHAR *pszID, const char* pszModule, UINT msg, WPARAM wParam, LPARAM lParam) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + if (!pszID || !pszModule) + return 0; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + if (pTemp->hWnd) + return PostMessage(pTemp->hWnd, msg, wParam, lParam); + + return FALSE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return FALSE; +} + +static BOOL SM_BroadcastMessage(const char* pszModule, UINT msg, WPARAM wParam, LPARAM lParam, BOOL bAsync) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + while (pTemp != NULL) { + if (!pszModule || !lstrcmpiA(pTemp->pszModule, pszModule)) { + if (pTemp->hWnd) { + if (bAsync) + PostMessage(pTemp->hWnd, msg, wParam, lParam); + else + SendMessage(pTemp->hWnd, msg, wParam, lParam); + } + + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +static BOOL SM_SetStatus(const TCHAR *pszID, const char* pszModule, int wStatus) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + if (!pszModule) + return FALSE; + + while (pTemp != NULL) { + if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + pTemp->wStatus = wStatus; + if (pTemp->hWnd && ci.pSettings->TabsEnable) + ci.tabSession.wStatus = wStatus; + + if (pTemp->hContact) { + if (pTemp->iType != GCW_SERVER && wStatus != ID_STATUS_OFFLINE) + db_unset(pTemp->hContact, "CList", "Hidden"); + + db_set_w(pTemp->hContact, pTemp->pszModule, "Status", (WORD)wStatus); + } + + if (ci.pSettings->TabsEnable && ci.tabSession.hWnd) + PostMessage(ci.tabSession.hWnd, GC_FIXTABICONS, 0, (LPARAM)pTemp); + + if (pszID) + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +static BOOL SM_SendUserMessage(const TCHAR *pszID, const char* pszModule, const TCHAR* pszText) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + if (!pszModule || !pszText) + return FALSE; + + while (pTemp != NULL) { + if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + if (pTemp->iType == GCW_CHATROOM) + DoEventHook(pTemp->ptszID, pTemp->pszModule, GC_USER_MESSAGE, NULL, pszText, 0); + if (pszID) + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +static SESSION_INFO* SM_GetPrevWindow(SESSION_INFO *si) +{ + BOOL bFound = FALSE; + SESSION_INFO* pTemp = m_WndList; + + if (!si) + return NULL; + + while (pTemp != NULL) { + if (si == pTemp) { + if (bFound) + return NULL; + else + bFound = TRUE; + } + else if (bFound == TRUE && pTemp->hWnd) + return pTemp; + pTemp = pTemp->next; + if (pTemp == NULL && bFound) + pTemp = m_WndList; + } + return NULL; +} + +SESSION_INFO* SM_GetNextWindow(SESSION_INFO *si) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + if (!si) + return NULL; + + while (pTemp != NULL) { + if (si == pTemp) { + if (pLast) { + if (pLast != pTemp) + return pLast; + else + return NULL; + } + } + if (pTemp->hWnd) + pLast = pTemp; + pTemp = pTemp->next; + if (pTemp == NULL) + pTemp = m_WndList; + } + return NULL; +} + +static BOOL SM_ChangeUID(const TCHAR *pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszNewUID) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + if (!pszModule) + return FALSE; + + while (pTemp != NULL) { + if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + USERINFO* ui = ci.UM_FindUser(pTemp->pUsers, pszUID); + if (ui) + replaceStrT(ui->pszUID, pszNewUID); + + if (pszID) + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + + +static BOOL SM_SetTabbedWindowHwnd(SESSION_INFO *si, HWND hwnd) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + while (pTemp != NULL) { + if (si && si == pTemp) { + pTemp->hWnd = hwnd; + } + else + pTemp->hWnd = NULL; + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +static BOOL SM_ChangeNick(const TCHAR *pszID, const char* pszModule, GCEVENT *gce) +{ + SESSION_INFO *pTemp = m_WndList, *pLast = NULL; + + if (!pszModule) + return FALSE; + + while (pTemp != NULL) { + if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + USERINFO* ui = ci.UM_FindUser(pTemp->pUsers, gce->ptszUID); + if (ui) { + replaceStrT(ui->pszNick, gce->ptszText); + SM_MoveUser(pTemp->ptszID, pTemp->pszModule, ui->pszUID); + if (pTemp->hWnd) + SendMessage(pTemp->hWnd, GC_UPDATENICKLIST, 0, 0); + } + + if (pszID) + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +static BOOL SM_RemoveAll(void) +{ + while (m_WndList) { + SESSION_INFO*pLast = m_WndList->next; + + if (m_WndList->hWnd) + SendMessage(m_WndList->hWnd, GC_EVENT_CONTROL + WM_USER + 500, SESSION_TERMINATE, 0); + DoEventHook(m_WndList->ptszID, m_WndList->pszModule, GC_SESSION_TERMINATE, NULL, NULL, (DWORD)m_WndList->dwItemData); + if (m_WndList->hContact) + CList_SetOffline(m_WndList->hContact, m_WndList->iType == GCW_CHATROOM ? TRUE : FALSE); + db_set_s(m_WndList->hContact, m_WndList->pszModule, "Topic", ""); + db_unset(m_WndList->hContact, "CList", "StatusMsg"); + db_set_s(m_WndList->hContact, m_WndList->pszModule, "StatusBar", ""); + + ci.UM_RemoveAll(&m_WndList->pUsers); + ci.TM_RemoveAll(&m_WndList->pStatuses); + ci.LM_RemoveAll(&m_WndList->pLog, &m_WndList->pLogEnd); + m_WndList->iStatusCount = 0; + m_WndList->nUsersInNicklist = 0; + + mir_free(m_WndList->pszModule); + mir_free(m_WndList->ptszID); + mir_free(m_WndList->ptszName); + mir_free(m_WndList->ptszStatusbarText); + mir_free(m_WndList->ptszTopic); + mir_free(m_WndList->pszID); + mir_free(m_WndList->pszName); + + while (m_WndList->lpCommands != NULL) { + COMMANDINFO *pNext = m_WndList->lpCommands->next; + mir_free(m_WndList->lpCommands->lpCommand); + mir_free(m_WndList->lpCommands); + m_WndList->lpCommands = pNext; + } + + mir_free(m_WndList); + m_WndList = pLast; + } + m_WndList = NULL; + return TRUE; +} + +static void SM_AddCommand(const TCHAR *pszID, const char* pszModule, const char* lpNewCommand) +{ + SESSION_INFO* pTemp = m_WndList; + while (pTemp != NULL) { + if (lstrcmpi(pTemp->ptszID, pszID) == 0 && lstrcmpiA(pTemp->pszModule, pszModule) == 0) { // match + COMMANDINFO *node = (COMMANDINFO *)mir_alloc(sizeof(COMMANDINFO)); + node->lpCommand = mir_strdup(lpNewCommand); + node->last = NULL; // always added at beginning! + + // new commands are added at start + if (pTemp->lpCommands == NULL) { + node->next = NULL; + pTemp->lpCommands = node; + } + else { + node->next = pTemp->lpCommands; + pTemp->lpCommands->last = node; // hmm, weird + pTemp->lpCommands = node; + } + pTemp->lpCurrentCommand = NULL; // current command + pTemp->wCommandsNum++; + + if (pTemp->wCommandsNum > WINDOWS_COMMANDS_MAX) { + COMMANDINFO *pCurComm = pTemp->lpCommands; + COMMANDINFO *pLast; + while (pCurComm->next != NULL) { pCurComm = pCurComm->next; } + pLast = pCurComm->last; + mir_free(pCurComm->lpCommand); + mir_free(pCurComm); + pLast->next = NULL; + // done + pTemp->wCommandsNum--; + } + } + pTemp = pTemp->next; + } +} + +static char* SM_GetPrevCommand(const TCHAR *pszID, const char* pszModule) // get previous command. returns NULL if previous command does not exist. current command remains as it was. +{ + SESSION_INFO* pTemp = m_WndList; + while (pTemp != NULL) { + if (lstrcmpi(pTemp->ptszID, pszID) == 0 && lstrcmpiA(pTemp->pszModule, pszModule) == 0) { // match + COMMANDINFO *pPrevCmd = NULL; + if (pTemp->lpCurrentCommand != NULL) { + if (pTemp->lpCurrentCommand->next != NULL) // not NULL + pPrevCmd = pTemp->lpCurrentCommand->next; // next command (newest at beginning) + else + pPrevCmd = pTemp->lpCurrentCommand; + } + else pPrevCmd = pTemp->lpCommands; + + pTemp->lpCurrentCommand = pPrevCmd; // make it the new command + return(((pPrevCmd) ? (pPrevCmd->lpCommand) : (NULL))); + } + pTemp = pTemp->next; + } + return(NULL); +} + +static char* SM_GetNextCommand(const TCHAR *pszID, const char* pszModule) // get next command. returns NULL if next command does not exist. current command becomes NULL (a prev command after this one will get you the last command) +{ + SESSION_INFO* pTemp = m_WndList; + while (pTemp != NULL) { + if (lstrcmpi(pTemp->ptszID, pszID) == 0 && lstrcmpiA(pTemp->pszModule, pszModule) == 0) { // match + COMMANDINFO *pNextCmd = NULL; + if (pTemp->lpCurrentCommand != NULL) + pNextCmd = pTemp->lpCurrentCommand->last; // last command (newest at beginning) + + pTemp->lpCurrentCommand = pNextCmd; // make it the new command + return(((pNextCmd) ? (pNextCmd->lpCommand) : (NULL))); + } + pTemp = pTemp->next; + } + return(NULL); +} + +static int SM_GetCount(const char* pszModule) +{ + SESSION_INFO* pTemp = m_WndList; + int count = 0; + + while (pTemp != NULL) { + if (!lstrcmpiA(pszModule, pTemp->pszModule)) + count++; + + pTemp = pTemp->next; + } + return count; +} + +static SESSION_INFO* SM_FindSessionByIndex(const char* pszModule, int iItem) +{ + SESSION_INFO* pTemp = m_WndList; + int count = 0; + while (pTemp != NULL) { + if (!lstrcmpiA(pszModule, pTemp->pszModule)) { + if (iItem == count) + return pTemp; + else + count++; + } + + pTemp = pTemp->next; + } + return NULL; + +} + +static char* SM_GetUsers(SESSION_INFO *si) +{ + SESSION_INFO* pTemp = m_WndList; + USERINFO* utemp = NULL; + char* p = NULL; + int alloced = 0; + + if (si == NULL) + return NULL; + + while (pTemp != NULL) { + if (si == pTemp) { + if ((utemp = pTemp->pUsers) == NULL) + return NULL; + + break; + } + pTemp = pTemp->next; + } + + do { + int pLen = lstrlenA(p), nameLen = lstrlen(utemp->pszUID); + if (pLen + nameLen + 2 > alloced) + p = (char *)mir_realloc(p, alloced += 4096); + + WideCharToMultiByte(CP_ACP, 0, utemp->pszUID, -1, p + pLen, nameLen + 1, 0, 0); + lstrcpyA(p + pLen + nameLen, " "); + utemp = utemp->next; + } + while (utemp != NULL); + return p; +} + + + + + + +//--------------------------------------------------- +// Module Manager functions +// +// Necessary to keep track of all modules +// that has registered with the plugin +//--------------------------------------------------- + +static MODULEINFO* MM_AddModule(const char* pszModule) +{ + if (!pszModule) + return NULL; + if (!ci.MM_FindModule(pszModule)) { + MODULEINFO *node = (MODULEINFO*)mir_alloc(sizeof(MODULEINFO)); + ZeroMemory(node, sizeof(MODULEINFO)); + + node->pszModule = (char*)mir_alloc(lstrlenA(pszModule) + 1); + lstrcpyA(node->pszModule, pszModule); + + if (m_ModList == NULL) // list is empty + { + m_ModList = node; + node->next = NULL; + } + else { + node->next = m_ModList; + m_ModList = node; + } + return node; + } + return FALSE; +} + +static void MM_IconsChanged(void) +{ + MODULEINFO *pTemp = m_ModList, *pLast = NULL; + ImageList_ReplaceIcon(ci.hIconsList, 0, LoadSkinnedIcon(SKINICON_EVENT_MESSAGE)); + // ImageList_ReplaceIcon(ci.hIconsList, 1, LoadIconEx("overlay", FALSE)); + while (pTemp != NULL) { + pTemp->OnlineIconIndex = ImageList_ReplaceIcon(ci.hIconsList, pTemp->OnlineIconIndex, LoadSkinnedProtoIcon(pTemp->pszModule, ID_STATUS_ONLINE)); + pTemp->OfflineIconIndex = ImageList_ReplaceIcon(ci.hIconsList, pTemp->OfflineIconIndex, LoadSkinnedProtoIcon(pTemp->pszModule, ID_STATUS_OFFLINE)); + + if (pTemp->hOfflineIcon) + DestroyIcon(pTemp->hOfflineIcon); + if (pTemp->hOnlineIcon) + DestroyIcon(pTemp->hOnlineIcon); + if (pTemp->hOnlineTalkIcon) + DestroyIcon(pTemp->hOnlineTalkIcon); + if (pTemp->hOfflineTalkIcon) + DestroyIcon(pTemp->hOfflineTalkIcon); + pTemp->hOfflineIcon = ImageList_GetIcon(ci.hIconsList, pTemp->OfflineIconIndex, ILD_TRANSPARENT); + pTemp->hOnlineIcon = ImageList_GetIcon(ci.hIconsList, pTemp->OnlineIconIndex, ILD_TRANSPARENT); + + pTemp->hOnlineTalkIcon = ImageList_GetIcon(ci.hIconsList, pTemp->OnlineIconIndex, ILD_TRANSPARENT | INDEXTOOVERLAYMASK(1)); + ImageList_ReplaceIcon(ci.hIconsList, pTemp->OnlineIconIndex + 1, pTemp->hOnlineTalkIcon); + + pTemp->hOfflineTalkIcon = ImageList_GetIcon(ci.hIconsList, pTemp->OfflineIconIndex, ILD_TRANSPARENT | INDEXTOOVERLAYMASK(1)); + ImageList_ReplaceIcon(ci.hIconsList, pTemp->OfflineIconIndex + 1, pTemp->hOfflineTalkIcon); + + pLast = pTemp; + pTemp = pTemp->next; + } + return; +} + +static void MM_FontsChanged(void) +{ + MODULEINFO *pTemp = m_ModList; + while (pTemp != NULL) { + pTemp->pszHeader = Log_CreateRtfHeader(pTemp); + pTemp = pTemp->next; + } + return; +} + +static MODULEINFO* MM_FindModule(const char* pszModule) +{ + MODULEINFO *pTemp = m_ModList, *pLast = NULL; + + if (!pszModule) + return NULL; + + while (pTemp != NULL) { + if (lstrcmpiA(pTemp->pszModule, pszModule) == 0) + return pTemp; + + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +// stupid thing.. +static void MM_FixColors() +{ + MODULEINFO *pTemp = m_ModList; + + while (pTemp != NULL) { + CheckColorsInModule(pTemp->pszModule); + pTemp = pTemp->next; + } + return; +} + +static BOOL MM_RemoveAll(void) +{ + while (m_ModList != NULL) { + MODULEINFO *pLast = m_ModList->next; + mir_free(m_ModList->pszModule); + mir_free(m_ModList->ptszModDispName); + mir_free(m_ModList->pszHeader); + mir_free(m_ModList->crColors); + + if (m_ModList->hOfflineIcon) + DestroyIcon(m_ModList->hOfflineIcon); + if (m_ModList->hOnlineIcon) + DestroyIcon(m_ModList->hOnlineIcon); + if (m_ModList->hOnlineTalkIcon) + DestroyIcon(m_ModList->hOnlineTalkIcon); + if (m_ModList->hOfflineTalkIcon) + DestroyIcon(m_ModList->hOfflineTalkIcon); + + mir_free(m_ModList); + m_ModList = pLast; + } + m_ModList = NULL; + return TRUE; +} + + + +//--------------------------------------------------- +// Tab list manager functions +// +// Necessary to keep track of what tabs should +// be restored +//--------------------------------------------------- + +static BOOL TabM_AddTab(const TCHAR *pszID, const char* pszModule) +{ + TABLIST *node = NULL; + if (!pszID || !pszModule) + return FALSE; + + node = (TABLIST*)mir_alloc(sizeof(TABLIST)); + ZeroMemory(node, sizeof(TABLIST)); + node->pszID = mir_tstrdup(pszID); + node->pszModule = mir_strdup(pszModule); + + if (g_TabList == NULL) { // list is empty + g_TabList = node; + node->next = NULL; + } + else { + node->next = g_TabList; + g_TabList = node; + } + return TRUE; +} + +static BOOL TabM_RemoveAll(void) +{ + while (g_TabList != NULL) { + TABLIST * pLast = g_TabList->next; + mir_free(g_TabList->pszModule); + mir_free(g_TabList->pszID); + mir_free(g_TabList); + g_TabList = pLast; + } + g_TabList = NULL; + return TRUE; +} + +//--------------------------------------------------- +// Status manager functions +// +// Necessary to keep track of what user statuses +// per window nicklist that is available +//--------------------------------------------------- + +static STATUSINFO * TM_AddStatus(STATUSINFO** ppStatusList, const TCHAR* pszStatus, int* iCount) +{ + if (!ppStatusList || !pszStatus) + return NULL; + + if (!ci.TM_FindStatus(*ppStatusList, pszStatus)) { + STATUSINFO *node = (STATUSINFO*)mir_alloc(sizeof(STATUSINFO)); + ZeroMemory(node, sizeof(STATUSINFO)); + replaceStrT(node->pszGroup, pszStatus); + node->hIcon = (HICON)(*iCount); + while ((int)node->hIcon > STATUSICONCOUNT - 1) + node->hIcon--; + + if (*ppStatusList == NULL) // list is empty + { + node->Status = 1; + *ppStatusList = node; + node->next = NULL; + } + else { + node->Status = ppStatusList[0]->Status * 2; + node->next = *ppStatusList; + *ppStatusList = node; + } + return node; + + } + return FALSE; +} + +static STATUSINFO* TM_FindStatus(STATUSINFO* pStatusList, const TCHAR* pszStatus) +{ + STATUSINFO *pTemp = pStatusList, *pLast = NULL; + + if (!pStatusList || !pszStatus) + return NULL; + + while (pTemp != NULL) { + if (lstrcmpi(pTemp->pszGroup, pszStatus) == 0) + return pTemp; + + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +static WORD TM_StringToWord(STATUSINFO* pStatusList, const TCHAR* pszStatus) +{ + STATUSINFO *pTemp = pStatusList, *pLast = NULL; + + if (!pStatusList || !pszStatus) + return 0; + + while (pTemp != NULL) { + if (lstrcmpi(pTemp->pszGroup, pszStatus) == 0) + return pTemp->Status; + + if (pTemp->next == NULL) + return pStatusList->Status; + + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +static TCHAR* TM_WordToString(STATUSINFO* pStatusList, WORD Status) +{ + STATUSINFO *pTemp = pStatusList, *pLast = NULL; + + if (!pStatusList) + return NULL; + + while (pTemp != NULL) { + if (pTemp->Status&Status) { + Status -= pTemp->Status; + if (Status == 0) + return pTemp->pszGroup; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +static BOOL TM_RemoveAll(STATUSINFO** ppStatusList) +{ + + if (!ppStatusList) + return FALSE; + + while (*ppStatusList != NULL) { + STATUSINFO *pLast = ppStatusList[0]->next; + mir_free(ppStatusList[0]->pszGroup); + if ((int)ppStatusList[0]->hIcon > 10) + DestroyIcon(ppStatusList[0]->hIcon); + mir_free(*ppStatusList); + *ppStatusList = pLast; + } + *ppStatusList = NULL; + return TRUE; +} + +//--------------------------------------------------- +// User manager functions +// +// Necessary to keep track of the users +// in a window nicklist +//--------------------------------------------------- + +static int UM_CompareItem(USERINFO * u1, const TCHAR* pszNick, WORD wStatus) +{ + int i; + + WORD dw1 = u1->Status; + WORD dw2 = wStatus; + + for (i = 0; i < 8; i++) { + if ((dw1 & 1) && !(dw2 & 1)) + return -1; + if ((dw2 & 1) && !(dw1 & 1)) + return 1; + if ((dw1 & 1) && (dw2 & 1)) + return lstrcmp(u1->pszNick, pszNick); + + dw1 = dw1 >> 1; + dw2 = dw2 >> 1; + } + return lstrcmp(u1->pszNick, pszNick); +} + +static USERINFO * UM_SortUser(USERINFO** ppUserList, const TCHAR* pszUID) +{ + USERINFO * pTemp = *ppUserList, *pLast = NULL; + USERINFO * node = NULL; + + if (!pTemp || !pszUID) + return NULL; + + while (pTemp && lstrcmpi(pTemp->pszUID, pszUID)) { + pLast = pTemp; + pTemp = pTemp->next; + } + + if (pTemp) { + node = pTemp; + if (pLast) + pLast->next = pTemp->next; + else + *ppUserList = pTemp->next; + pTemp = *ppUserList; + + pLast = NULL; + + while (pTemp && UM_CompareItem(pTemp, node->pszNick, node->Status) <= 0) { + pLast = pTemp; + pTemp = pTemp->next; + } + + if (*ppUserList == NULL) { // list is empty + *ppUserList = node; + node->next = NULL; + } + else { + if (pLast) { + node->next = pTemp; + pLast->next = node; + } + else { + node->next = *ppUserList; + *ppUserList = node; + } + } + + return node; + } + return NULL; +} + +USERINFO* UM_AddUser(STATUSINFO* pStatusList, USERINFO** ppUserList, const TCHAR* pszUID, const TCHAR* pszNick, WORD wStatus) +{ + USERINFO * pTemp = *ppUserList, *pLast = NULL; + + if (!pStatusList || !ppUserList) + return NULL; + + while (pTemp && UM_CompareItem(pTemp, pszNick, wStatus) <= 0) { + pLast = pTemp; + pTemp = pTemp->next; + } + + // if (!UM_FindUser(*ppUserList, pszUI, wStatus) + USERINFO *node = (USERINFO*)mir_alloc(sizeof(USERINFO)); + ZeroMemory(node, sizeof(USERINFO)); + replaceStrT(node->pszUID, pszUID); + + if (*ppUserList == NULL) { // list is empty + *ppUserList = node; + node->next = NULL; + } + else { + if (pLast) { + node->next = pTemp; + pLast->next = node; + } + else { + node->next = *ppUserList; + *ppUserList = node; + } + } + + return node; +} + +static USERINFO* UM_FindUser(USERINFO* pUserList, const TCHAR* pszUID) +{ + USERINFO *pTemp = pUserList, *pLast = NULL; + + if (!pUserList || !pszUID) + return NULL; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->pszUID, pszUID)) + return pTemp; + + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +static USERINFO* UM_FindUserFromIndex(USERINFO* pUserList, int index) +{ + if (!pUserList) + return NULL; + + int i = 0; + USERINFO *pTemp = pUserList; + while (pTemp != NULL) { + if (i == index) + return pTemp; + + pTemp = pTemp->next; + i++; + } + return NULL; +} + +static USERINFO* UM_GiveStatus(USERINFO* pUserList, const TCHAR* pszUID, WORD status) +{ + if (!pUserList || !pszUID) + return NULL; + + USERINFO *pTemp = pUserList, *pLast = NULL; + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->pszUID, pszUID)) { + pTemp->Status |= status; + return pTemp; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +static USERINFO* UM_SetContactStatus(USERINFO* pUserList, const TCHAR* pszUID, WORD status) +{ + USERINFO *pTemp = pUserList, *pLast = NULL; + + if (!pUserList || !pszUID) + return NULL; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->pszUID, pszUID)) { + pTemp->ContactStatus = status; + return pTemp; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +static BOOL UM_SetStatusEx(USERINFO* pUserList, const TCHAR* pszText, int flags) +{ + USERINFO *pTemp = pUserList, *pLast = NULL; + int bOnlyMe = (flags & GC_SSE_ONLYLISTED) != 0, bSetStatus = (flags & GC_SSE_ONLINE) != 0; + char cDelimiter = (flags & GC_SSE_TABDELIMITED) ? '\t' : ' '; + + while (pTemp != NULL) { + if (!bOnlyMe) + pTemp->iStatusEx = 0; + + if (pszText != NULL) { + TCHAR* s = (TCHAR *)_tcsstr(pszText, pTemp->pszUID); + if (s) { + pTemp->iStatusEx = 0; + if (s == pszText || s[-1] == cDelimiter) { + int len = lstrlen(pTemp->pszUID); + if (s[len] == cDelimiter || s[len] == '\0') + pTemp->iStatusEx = (!bOnlyMe || bSetStatus) ? 1 : 0; + } + } + } + + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +static USERINFO* UM_TakeStatus(USERINFO* pUserList, const TCHAR* pszUID, WORD status) +{ + if (!pUserList || !pszUID) + return NULL; + + USERINFO *pTemp = pUserList, *pLast = NULL; + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->pszUID, pszUID)) { + pTemp->Status &= ~status; + return pTemp; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +static TCHAR* UM_FindUserAutoComplete(USERINFO* pUserList, const TCHAR* pszOriginal, const TCHAR* pszCurrent) +{ + if (!pUserList || !pszOriginal || !pszCurrent) + return NULL; + + TCHAR* pszName = NULL; + USERINFO *pTemp = pUserList; + while (pTemp != NULL) { + if (pTemp->pszNick && my_strstri(pTemp->pszNick, pszOriginal) == pTemp->pszNick) + if (lstrcmpi(pTemp->pszNick, pszCurrent) > 0 && (!pszName || lstrcmpi(pTemp->pszNick, pszName) < 0)) + pszName = pTemp->pszNick; + + pTemp = pTemp->next; + } + return pszName; +} + +static BOOL UM_RemoveUser(USERINFO** ppUserList, const TCHAR* pszUID) +{ + USERINFO *pTemp = *ppUserList, *pLast = NULL; + + if (!ppUserList || !pszUID) + return FALSE; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->pszUID, pszUID)) { + if (pLast == NULL) + *ppUserList = pTemp->next; + else + pLast->next = pTemp->next; + mir_free(pTemp->pszNick); + mir_free(pTemp->pszUID); + mir_free(pTemp); + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return FALSE; +} + +static BOOL UM_RemoveAll(USERINFO** ppUserList) +{ + if (!ppUserList) + return FALSE; + + while (*ppUserList != NULL) { + USERINFO *pLast = ppUserList[0]->next; + mir_free(ppUserList[0]->pszUID); + mir_free(ppUserList[0]->pszNick); + mir_free(*ppUserList); + *ppUserList = pLast; + } + *ppUserList = NULL; + return TRUE; +} + +//--------------------------------------------------- +// Log manager functions +// +// Necessary to keep track of events +// in a window log +//--------------------------------------------------- + +static LOGINFO* LM_AddEvent(LOGINFO** ppLogListStart, LOGINFO** ppLogListEnd) +{ + if (!ppLogListStart || !ppLogListEnd) + return NULL; + + LOGINFO *node = (LOGINFO*)mir_calloc(sizeof(LOGINFO)); + if (*ppLogListStart == NULL) { // list is empty + *ppLogListStart = node; + *ppLogListEnd = node; + node->next = NULL; + node->prev = NULL; + } + else { + ppLogListStart[0]->prev = node; + node->next = *ppLogListStart; + *ppLogListStart = node; + ppLogListStart[0]->prev = NULL; + } + + return node; +} + +static BOOL LM_TrimLog(LOGINFO** ppLogListStart, LOGINFO** ppLogListEnd, int iCount) +{ + LOGINFO *pTemp = *ppLogListEnd; + while (pTemp != NULL && iCount > 0) { + *ppLogListEnd = pTemp->prev; + if (*ppLogListEnd == NULL) + *ppLogListStart = NULL; + + mir_free(pTemp->ptszNick); + mir_free(pTemp->ptszUserInfo); + mir_free(pTemp->ptszText); + mir_free(pTemp->ptszStatus); + mir_free(pTemp); + pTemp = *ppLogListEnd; + iCount--; + } + ppLogListEnd[0]->next = NULL; + + return TRUE; +} + +static BOOL LM_RemoveAll(LOGINFO** ppLogListStart, LOGINFO** ppLogListEnd) +{ + while (*ppLogListStart != NULL) { + LOGINFO *pLast = ppLogListStart[0]->next; + mir_free(ppLogListStart[0]->ptszText); + mir_free(ppLogListStart[0]->ptszNick); + mir_free(ppLogListStart[0]->ptszStatus); + mir_free(ppLogListStart[0]->ptszUserInfo); + mir_free(*ppLogListStart); + *ppLogListStart = pLast; + } + *ppLogListStart = NULL; + *ppLogListEnd = NULL; + return TRUE; +} + +CHAT_MANAGER ci = +{ + SetActiveSession, + SetActiveSessionEx, + GetActiveSession, + SM_AddSession, + SM_RemoveSession, + SM_FindSession, + SM_AddUser, + SM_ChangeUID, + SM_ChangeNick, + SM_RemoveUser, + SM_SetOffline, + SM_SetTabbedWindowHwnd, + SM_GetStatusIcon, + SM_SetStatus, + SM_SetStatusEx, + SM_SendUserMessage, + SM_AddStatus, + SM_GetNextWindow, + SM_GetPrevWindow, + SM_AddEventToAllMatchingUID, + SM_AddEvent, + SM_SendMessage, + SM_PostMessage, + SM_BroadcastMessage, + SM_RemoveAll, + SM_GiveStatus, + SM_SetContactStatus, + SM_TakeStatus, + SM_MoveUser, + SM_AddCommand, + SM_GetPrevCommand, + SM_GetNextCommand, + SM_GetCount, + SM_FindSessionByIndex, + SM_GetUsers, + SM_GetUserFromIndex, + + MM_AddModule, + MM_FindModule, + MM_FixColors, + MM_FontsChanged, + MM_IconsChanged, + MM_RemoveAll, + + TabM_AddTab, + TabM_RemoveAll, + + TM_AddStatus, + TM_FindStatus, + TM_StringToWord, + TM_WordToString, + TM_RemoveAll, + + UM_SetStatusEx, + UM_AddUser, + UM_SortUser, + UM_FindUser, + UM_FindUserFromIndex, + UM_GiveStatus, + UM_SetContactStatus, + UM_TakeStatus, + UM_FindUserAutoComplete, + UM_RemoveUser, + UM_RemoveAll, + + LM_AddEvent, + LM_TrimLog, + LM_RemoveAll +}; + +INT_PTR SvcGetChatManager(WPARAM, LPARAM) +{ + return (INT_PTR)&ci; +} -- cgit v1.2.3