www.pudn.com > eMule0.42e-Sources.zip > ChatSelector.cpp
//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-project.net )
//
//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., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "stdafx.h"
#include "emule.h"
#include "ChatSelector.h"
#include "packets.h"
#include "HTRichEditCtrl.h"
#include "emuledlg.h"
#include "UploadQueue.h"
#include "OtherFunctions.h"
#include "UpDownClient.h"
#include "Preferences.h"
#include "TaskbarNotifier.h"
#include "ListenSocket.h"
#include "ChatWnd.h"
#include "SafeFile.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define URLINDICATOR _T("http:|www.|.de |.net |.com |.org |.to |.tk |.cc |.fr |ftp:")
///////////////////////////////////////////////////////////////////////////////
// CChatItem
CChatItem::CChatItem()
{
client = NULL;
log = NULL;
messagepending = NULL;
notify = false;
history_pos = 0;
}
CChatItem::~CChatItem()
{
delete log;
delete[] messagepending;
}
///////////////////////////////////////////////////////////////////////////////
// CChatSelector
IMPLEMENT_DYNAMIC(CChatSelector, CClosableTabCtrl)
BEGIN_MESSAGE_MAP(CChatSelector, CClosableTabCtrl)
ON_WM_SIZE()
ON_WM_DESTROY()
ON_WM_TIMER()
ON_WM_SYSCOLORCHANGE()
ON_NOTIFY_REFLECT(TCN_SELCHANGE, OnTcnSelchangeChatsel)
ON_BN_CLICKED(IDC_CCLOSE, OnBnClickedCclose)
ON_BN_CLICKED(IDC_CSEND, OnBnClickedCsend)
END_MESSAGE_MAP()
CChatSelector::CChatSelector()
{
m_pCloseBtn = NULL;
m_pMessageBox = NULL;
m_pSendBtn = NULL;
m_lastemptyicon = false;
m_blinkstate = false;
m_Timer = 0;
m_bCloseable = true;
}
CChatSelector::~CChatSelector()
{
}
void CChatSelector::Init()
{
m_pCloseBtn = GetParent()->GetDlgItem(IDC_CCLOSE);
m_pCloseBtn->SetParent(this);
m_pSendBtn = GetParent()->GetDlgItem(IDC_CSEND);
m_pSendBtn->SetParent(this);
m_pMessageBox = GetParent()->GetDlgItem(IDC_CMESSAGE);
m_pMessageBox->SetParent(this);
ModifyStyle(0, WS_CLIPCHILDREN);
SetAllIcons();
VERIFY( (m_Timer = SetTimer(20, 1500, 0)) != NULL );
}
void CChatSelector::OnSysColorChange()
{
CClosableTabCtrl::OnSysColorChange();
SetAllIcons();
}
void CChatSelector::SetAllIcons()
{
CImageList iml;
iml.Create(16, 16, theApp.m_iDfltImageListColorFlags | ILC_MASK, 0, 1);
iml.Add(CTempIconLoader(_T("Chat")));
iml.Add(CTempIconLoader(_T("Message")));
iml.Add(CTempIconLoader(_T("MessagePending")));
SetImageList(&iml);
m_imlChat.DeleteImageList();
m_imlChat.Attach(iml.Detach());
SetPadding(CSize(10, 0));
}
void CChatSelector::UpdateFonts(CFont* pFont)
{
TCITEM item;
item.mask = TCIF_PARAM;
int i = 0;
while (GetItem(i++, &item)){
CChatItem* ci = (CChatItem*)item.lParam;
ci->log->SetFont(pFont);
}
}
CChatItem* CChatSelector::StartSession(CUpDownClient* client, bool show)
{
m_pMessageBox->SetFocus();
if (GetTabByClient(client) != 0xFFFF){
if (show){
SetCurSel(GetTabByClient(client));
ShowChat();
}
return NULL;
}
CChatItem* chatitem = new CChatItem();
chatitem->client = client;
chatitem->log = new CHTRichEditCtrl;
CRect rcChat;
GetChatSize(rcChat);
if (GetItemCount() == 0)
rcChat.top += 20;
chatitem->log->Create(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VSCROLL | ES_MULTILINE | ES_READONLY, rcChat, this, (UINT)-1);
chatitem->log->ModifyStyleEx(0, WS_EX_STATICEDGE, SWP_FRAMECHANGED);
chatitem->log->SendMessage(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3));
chatitem->log->SetEventMask(chatitem->log->GetEventMask() | ENM_LINK);
chatitem->log->SetFont(&theApp.emuledlg->m_fontHyperText);
CTime theTime = CTime::GetCurrentTime();
CString sessions = GetResString(IDS_CHAT_START) + client->GetUserName() + CString(_T(" - ")) + theTime.Format(_T("%c"))+ _T("\n");
chatitem->log->AppendKeyWord(sessions, RGB(255,0,0));
client->SetChatState(MS_CHATTING);
CString name;
if (client->GetUserName() != NULL)
name = client->GetUserName();
else
name.Format(_T("(%s)"), GetResString(IDS_UNKNOWN));
chatitem->log->SetTitle(name);
TCITEM newitem;
newitem.mask = TCIF_PARAM | TCIF_TEXT | TCIF_IMAGE;
newitem.lParam = (LPARAM)chatitem;
newitem.pszText = const_cast((LPCTSTR)name);
newitem.iImage = 0;
int iItemNr = InsertItem(GetItemCount(), &newitem);
if (show || IsWindowVisible()){
SetCurSel(iItemNr);
ShowChat();
}
return chatitem;
}
uint16 CChatSelector::GetTabByClient(CUpDownClient* client)
{
for (int i = 0; i < GetItemCount(); i++){
TCITEM cur_item;
cur_item.mask = TCIF_PARAM;
if (GetItem(i, &cur_item) && ((CChatItem*)cur_item.lParam)->client == client)
return i;
}
return (uint16)-1;
}
CChatItem* CChatSelector::GetItemByClient(CUpDownClient* client)
{
for (int i = 0; i < GetItemCount(); i++){
TCITEM cur_item;
cur_item.mask = TCIF_PARAM;
if (GetItem(i, &cur_item) && ((CChatItem*)cur_item.lParam)->client == client)
return (CChatItem*)cur_item.lParam;
}
return NULL;
}
void CChatSelector::ProcessMessage(CUpDownClient* sender, char* message)
{
sender->IncMessagesReceived();
CString strMessage = CString(message).MakeLower();
CString resToken;
int curPos = 0;
resToken = thePrefs.GetMessageFilter().Tokenize(_T("|"), curPos);
while (resToken != _T(""))
{
if (strMessage.Find(resToken.MakeLower()) > -1)
return;
resToken = thePrefs.GetMessageFilter().Tokenize(_T("|"), curPos);
}
CChatItem* ci = GetItemByClient(sender);
// advanced spamfilter check
if (IsSpam(strMessage, sender))
{
if (!sender->IsSpammer()){
if (thePrefs.GetVerbose())
theApp.emuledlg->AddDebugLogLine(false, _T("'%s' has been marked as spammer"), sender->GetUserName());
}
sender->SetSpammer(true);
if (ci)
EndSession(sender);
return;
}
bool isNewChatWindow = false;
if (!ci)
{
if (GetItemCount() >= thePrefs.GetMsgSessionsMax())
return;
ci = StartSession(sender, false);
isNewChatWindow = true;
}
if (thePrefs.GetIRCAddTimestamp())
AddTimeStamp(ci);
ci->log->AppendKeyWord(sender->GetUserName(), RGB(50,200,250));
ci->log->AppendText(_T(": "));
ci->log->AppendText(CString(message) + _T("\n"));
int iTabItem = GetTabByClient(sender);
if (GetCurSel() == iTabItem && GetParent()->IsWindowVisible())
{
// chat window is already visible
;
}
else if (GetCurSel() != iTabItem)
{
// chat window is already visible, but tab is not selected
ci->notify = true;
}
else
{
ci->notify = true;
if (isNewChatWindow || thePrefs.GetNotifierPopsEveryChatMsg())
theApp.emuledlg->ShowNotifier(GetResString(IDS_TBN_NEWCHATMSG) + _T(" ") + CString(sender->GetUserName()) + _T(":'") + CString(message) + _T("'\n"), TBN_CHAT);
isNewChatWindow = false;
}
}
bool CChatSelector::SendMessage(LPCTSTR message)
{
CChatItem* ci = GetCurrentChatItem();
if (!ci)
return false;
if (ci->history.GetCount() == thePrefs.GetMaxChatHistoryLines())
ci->history.RemoveAt(0);
ci->history.Add(CString(message));
ci->history_pos = ci->history.GetCount();
// advance spamfilter stuff
ci->client->IncMessagesSent();
ci->client->SetSpammer(false);
if (ci->client->GetChatState() == MS_CONNECTING)
return false;
if (thePrefs.GetIRCAddTimestamp())
AddTimeStamp(ci);
if (ci->client->socket && ci->client->socket->IsConnected())
{
uint16 mlen = (uint16)strlen(message);
Packet* packet = new Packet(OP_MESSAGE, mlen+2);
PokeUInt16(packet->pBuffer, mlen);
memcpy(packet->pBuffer + 2, message, mlen);
theApp.uploadqueue->AddUpDataOverheadOther(packet->size);
ci->client->socket->SendPacket(packet, true, true);
ci->log->AppendKeyWord(thePrefs.GetUserNick(), RGB(1,180,20));
ci->log->AppendText(_T(": "));
ci->log->AppendText(CString(message) + _T("\n"));
}
else
{
ci->log->AppendKeyWord(_T("*** ") + GetResString(IDS_CONNECTING), RGB(255,0,0));
ci->messagepending = nstrdup(message);
ci->client->SetChatState(MS_CONNECTING);
ci->client->TryToConnect();
}
return true;
}
void CChatSelector::ConnectingResult(CUpDownClient* sender, bool success)
{
CChatItem* ci = GetItemByClient(sender);
if (!ci)
return;
ci->client->SetChatState(MS_CHATTING);
if (!success){
if (ci->messagepending){
ci->log->AppendKeyWord(_T(" ") + GetResString(IDS_FAILED) + _T("\n"), RGB(255,0,0));
delete[] ci->messagepending;
ci->messagepending = NULL;
}
else{
if (thePrefs.GetIRCAddTimestamp())
AddTimeStamp(ci);
ci->log->AppendKeyWord(GetResString(IDS_CHATDISCONNECTED) + _T("\n"), RGB(255,0,0));
}
}
else if (ci->messagepending){
ci->log->AppendKeyWord(_T(" ok\n"), RGB(255,0,0));
uint16 mlen = (uint16)strlen(ci->messagepending);
Packet* packet = new Packet(OP_MESSAGE, mlen+2);
PokeUInt16(packet->pBuffer, mlen);
memcpy(packet->pBuffer + 2, ci->messagepending, mlen);
theApp.uploadqueue->AddUpDataOverheadOther(packet->size);
ci->client->socket->SendPacket(packet, true, true);
if (thePrefs.GetIRCAddTimestamp())
AddTimeStamp(ci);
ci->log->AppendKeyWord(thePrefs.GetUserNick(), RGB(1,180,20));
ci->log->AppendText(_T(": "));
ci->log->AppendText(CString(ci->messagepending) + _T("\n"));
delete[] ci->messagepending;
ci->messagepending = NULL;
}
else{
if (thePrefs.GetIRCAddTimestamp())
AddTimeStamp(ci);
ci->log->AppendKeyWord(_T("*** Connected\n"), RGB(255,0,0));
}
}
void CChatSelector::DeleteAllItems()
{
for (int i = 0; i < GetItemCount(); i++){
TCITEM cur_item;
cur_item.mask = TCIF_PARAM;
if (GetItem(i, &cur_item))
delete (CChatItem*)cur_item.lParam;
}
}
void CChatSelector::OnTimer(UINT_PTR nIDEvent)
{
m_blinkstate = !m_blinkstate;
bool globalnotify = false;
for (int i = 0; i < GetItemCount();i++)
{
TCITEM cur_item;
cur_item.mask = TCIF_PARAM | TCIF_IMAGE;
if (!GetItem(i, &cur_item))
break;
cur_item.mask = TCIF_IMAGE;
if (((CChatItem*)cur_item.lParam)->notify){
cur_item.iImage = (m_blinkstate) ? 1 : 2;
SetItem(i, &cur_item);
HighlightItem(i, TRUE);
globalnotify = true;
}
else if (cur_item.iImage != 0){
cur_item.iImage = 0;
SetItem(i, &cur_item);
HighlightItem(i, FALSE);
}
}
if (globalnotify) {
theApp.emuledlg->ShowMessageState(m_blinkstate ? 1 : 2);
m_lastemptyicon = false;
}
else if (!m_lastemptyicon) {
theApp.emuledlg->ShowMessageState(0);
m_lastemptyicon = true;
}
}
CChatItem* CChatSelector::GetCurrentChatItem()
{
int iCurSel = GetCurSel();
if (iCurSel == -1)
return NULL;
TCITEM cur_item;
cur_item.mask = TCIF_PARAM;
if (!GetItem(iCurSel, &cur_item))
return NULL;
return (CChatItem*)cur_item.lParam;
}
void CChatSelector::ShowChat()
{
CChatItem* ci = GetCurrentChatItem();
if (!ci)
return;
// show current chat window
ci->log->ShowWindow(SW_SHOW);
m_pMessageBox->SetFocus();
TCITEM item;
item.mask = TCIF_IMAGE;
item.iImage = 0;
SetItem(GetCurSel(), &item);
HighlightItem(GetCurSel(), FALSE);
// hide all other chat windows
item.mask = TCIF_PARAM;
int i = 0;
while (GetItem(i++, &item)){
CChatItem* ci2 = (CChatItem*)item.lParam;
if (ci2 != ci)
ci2->log->ShowWindow(SW_HIDE);
}
ci->notify = false;
}
void CChatSelector::OnTcnSelchangeChatsel(NMHDR *pNMHDR, LRESULT *pResult)
{
ShowChat();
*pResult = 0;
}
int CChatSelector::InsertItem(int nItem, TCITEM* pTabCtrlItem)
{
int iResult = CClosableTabCtrl::InsertItem(nItem, pTabCtrlItem);
RedrawWindow();
return iResult;
}
BOOL CChatSelector::DeleteItem(int nItem)
{
CClosableTabCtrl::DeleteItem(nItem);
RedrawWindow();
return TRUE;
}
void CChatSelector::EndSession(CUpDownClient* client)
{
int iCurSel;
if (client)
iCurSel = GetTabByClient(client);
else
iCurSel = GetCurSel();
if (iCurSel == -1)
return;
TCITEM item;
item.mask = TCIF_PARAM;
if (!GetItem(iCurSel, &item) || item.lParam == 0)
return;
CChatItem* ci = (CChatItem*)item.lParam;
ci->client->SetChatState(MS_NONE);
DeleteItem(iCurSel);
delete ci;
int iTabItems = GetItemCount();
if (iTabItems > 0){
// select next tab
if (iCurSel == CB_ERR)
iCurSel = 0;
else if (iCurSel >= iTabItems)
iCurSel = iTabItems - 1;
(void)SetCurSel(iCurSel); // returns CB_ERR if error or no prev. selection(!)
iCurSel = GetCurSel(); // get the real current selection
if (iCurSel == CB_ERR) // if still error
iCurSel = SetCurSel(0);
ShowChat();
}
}
void CChatSelector::GetChatSize(CRect& rcChat)
{
CRect rcClose, rcSend, rcMessage;
m_pCloseBtn->GetWindowRect(&rcClose);
m_pSendBtn->GetWindowRect(&rcSend);
m_pMessageBox->GetWindowRect(&rcMessage);
int iTop = rcClose.Height() > rcSend.Height() ? rcClose.Height() : rcSend.Height();
if (iTop < rcMessage.Height())
iTop = rcMessage.Height();
CRect rcClient;
GetClientRect(&rcClient);
AdjustRect(FALSE, rcClient);
rcChat.left = rcClient.left + 7;
rcChat.top = rcClient.top + 7;
rcChat.right = rcChat.left + rcClient.right - 18;
rcChat.bottom = rcChat.top + rcClient.Height() - 7 - iTop - 14;
}
void CChatSelector::OnSize(UINT nType, int cx, int cy)
{
CClosableTabCtrl::OnSize(nType, cx, cy);
CRect rect;
GetClientRect(&rect);
AdjustRect(FALSE, rect);
CRect rClose;
m_pCloseBtn->GetWindowRect(&rClose);
m_pCloseBtn->SetWindowPos(NULL, rect.right-7-rClose.Width(), rect.bottom-7-rClose.Height(),
rClose.Width(), rClose.Height(), SWP_NOZORDER);
CRect rSend;
m_pSendBtn->GetWindowRect(&rSend);
m_pSendBtn->SetWindowPos(NULL, rect.right-7-rClose.Width()-7-rSend.Width(), rect.bottom-7-rSend.Height(),
rSend.Width(), rSend.Height(), SWP_NOZORDER);
CRect rMessage;
m_pMessageBox->GetWindowRect(&rMessage);
m_pMessageBox->SetWindowPos(NULL, rect.left+7, rect.bottom-9-rMessage.Height(),
rect.right-7-rClose.Width()-7-rSend.Width()-21, rMessage.Height(), SWP_NOZORDER);
CRect rcChat;
GetChatSize(rcChat);
TCITEM item;
item.mask = TCIF_PARAM;
int i = 0;
while (GetItem(i++, &item)){
CChatItem* ci = (CChatItem*)item.lParam;
ci->log->SetWindowPos(NULL, rcChat.left, rcChat.top, rcChat.Width(), rcChat.Height(), SWP_NOZORDER);
}
}
void CChatSelector::OnBnClickedCclose()
{
EndSession();
}
void CChatSelector::OnBnClickedCsend()
{
CString strMessage;
m_pMessageBox->GetWindowText(strMessage);
strMessage.Trim();
if (!strMessage.IsEmpty())
{
if (SendMessage(strMessage))
m_pMessageBox->SetWindowText(_T(""));
}
m_pMessageBox->SetFocus();
}
BOOL CChatSelector::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN)
{
if (pMsg->wParam == VK_RETURN){
if (pMsg->hwnd == m_pMessageBox->m_hWnd)
OnBnClickedCsend();
}
if (pMsg->hwnd == m_pMessageBox->m_hWnd && (pMsg->wParam == VK_UP || pMsg->wParam == VK_DOWN)){
theApp.emuledlg->chatwnd->ScrollHistory(pMsg->wParam == VK_DOWN);
return TRUE;
}
}
return CClosableTabCtrl::PreTranslateMessage(pMsg);
}
void CChatSelector::Localize(void)
{
if (m_hWnd)
{
if (m_pSendBtn)
m_pSendBtn->SetWindowText(GetResString(IDS_CW_SEND));
else
GetParent()->GetDlgItem(IDC_CSEND)->SetWindowText(GetResString(IDS_CW_SEND));
if (m_pCloseBtn)
m_pCloseBtn->SetWindowText(GetResString(IDS_CW_CLOSE));
else
GetParent()->GetDlgItem(IDC_CCLOSE)->SetWindowText(GetResString(IDS_CW_CLOSE));
}
}
bool CChatSelector::IsSpam(CString strMessage, CUpDownClient* client)
{
// first step, spam dectection will be further improved in future versions
if ( !thePrefs.IsAdvSpamfilterEnabled() || client->IsFriend() ) // friends are never spammer... (but what if two spammers are friends :P )
return false;
if (client->IsSpammer())
return true;
// first fixed criteria: If a client sends me an URL in his first message before I response to him
// there is a 99,9% chance that it is some poor guy advising his leech mod, or selling you .. well you know :P
if (client->GetMessagesSent() == 0){
int curPos=0;
CString resToken = CString(URLINDICATOR).Tokenize(_T("|"), curPos);
while (resToken != _T("")){
if (strMessage.Find(resToken) > (-1) )
return true;
resToken= CString(URLINDICATOR).Tokenize(_T("|"),curPos);
}
}
// second fixed criteria: he sent me 5 or more messages and I didn't answered him once
if (client->GetMessagesReceived() > 4 && client->GetMessagesSent() == 0)
return true;
// to be continued
return false;
}
void CChatSelector::AddTimeStamp(CChatItem* ci)
{
ci->log->AppendText(CTime::GetCurrentTime().Format(_T("[%X] ")));
}
void CChatSelector::OnDestroy()
{
if (m_Timer){
KillTimer(m_Timer);
m_Timer = NULL;
}
CClosableTabCtrl::OnDestroy();
}