📄 contactview.cpp
字号:
#define FVERIFY(x) if (!(x)) \
{ \
MessageBox("Contact load failed: read incorrect size from file 'contacts.dat' please delete this file so a new one may be created.", "Internal error", MB_OK|MB_ICONSTOP); \
exit(1); \
}
void CContactView::LoadContacts()
{
HANDLE hFile;
unsigned long read;
hFile = CreateFile("contacts.dat", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
getcwd(cwd, sizeof(cwd));
if (hFile == (void *)0xFFFFFFFF)
{
Me.SetScreenName("Default Screen Name");
return;
}
char screenname[512];
bool NotAdded = false;
int sz, total, i;
ReadFile(hFile, &sz, sizeof(int), &read, NULL);
FVERIFY(read == sizeof(int));
ReadFile(hFile, screenname, sz, &read, NULL);
FVERIFY((int) read == sz);
screenname[sz] = 0;
Me.SetScreenName(screenname);
ReadFile(hFile, &total, sizeof(int), &read, NULL);
FVERIFY(read == sizeof(int))
for (i = 0; i < total; i++)
{
CContact *Contact = new CContact();
List.AddTail(Contact);
unsigned char seg1, seg2, seg3, seg4, onblock;
ReadFile(hFile, &sz, sizeof(int), &read, NULL);
FVERIFY(read == sizeof(int))
ReadFile(hFile, screenname, sz, &read, NULL);
FVERIFY((int) read == sz)
screenname[sz] = 0;
Contact->SetScreenName(screenname);
ReadFile(hFile, &seg1, sizeof(unsigned char), &read, NULL);
FVERIFY(read == sizeof(unsigned char))
ReadFile(hFile, &seg2, sizeof(unsigned char), &read, NULL);
FVERIFY(read == sizeof(unsigned char))
ReadFile(hFile, &seg3, sizeof(unsigned char), &read, NULL);
FVERIFY(read == sizeof(unsigned char))
ReadFile(hFile, &seg4, sizeof(unsigned char), &read, NULL);
FVERIFY(read == sizeof(unsigned char))
CNetmsgView *View = (CNetmsgView *)GetParent();
if (View->IsMyIp(IP(seg1, seg2, seg3, seg4)))
{
NotAdded = true;
delete Contact;
List.RemoveAt(List.Find(Contact));
ReadFile(hFile, &onblock, sizeof(unsigned char), &read, NULL);
FVERIFY(read == sizeof(unsigned char))
continue;
}
Contact->SetHost(IP(seg1, seg2, seg3, seg4));
ReadFile(hFile, &onblock, sizeof(unsigned char), &read, NULL);
FVERIFY(read == sizeof(unsigned char))
if (onblock) Contact->Flags |= CFL_BLOCKED;
Contact->SetSock(NULL);
PluginsContactAdded(Contact);
}
CloseHandle(hFile);
if (NotAdded)
{
MessageBox("One or more contacts in the contact list had hosts which belong to this machine, these contacts were not loaded.", "Load contacts", MB_OK|MB_ICONWARNING);
}
}
void CContactView::OnClose()
{
CListCtrl::OnClose();
}
void CContactView::Destroy()
{
POSITION pos;
SaveContacts();
pos = List.GetHeadPosition();
while (pos)
{
CContact *Contact = List.GetNext(pos);
CNetSocket *Socket = Contact->GetSock();
if (IsSocket(Socket))
{
Socket->Close();
delete Socket;
}
List.RemoveAt(List.Find(Contact));
delete Contact;
}
DeleteEmoticons();
}
void CContactView::ClaimSock(SOCKET Sock, CContact *Contact)
{
if (!IsContact(Contact))
return;
CNetSocket *NewSock = new CNetSocket(Contact);
NewSock->Attach(Sock);
NewSock->Init();
Contact->SetSock(NewSock);
Contact->Attempted = true;
}
void ::SendToAllOnline(bool bSendToBlocked, bool bSendIfMeOffline, char *fmt, ...)
{
va_list args;
va_start(args, fmt);
POSITION pos;
pos = GetApp()->View->List.GetHeadPosition();
if (!bSendIfMeOffline && GetApp()->View->Me.IsOffline())
return;
while (pos)
{
CContact *Contact = GetApp()->View->List.GetNext(pos);
if (IsSocket(Contact->GetSock()))
{
if (!bSendToBlocked)
{
if (Contact->IsBlocked())
continue;
else
Contact->GetSock()->SendStringV(fmt, args);
}
else
Contact->GetSock()->SendStringV(fmt, args);
}
}
}
void CContactView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
CListCtrl::OnLButtonDblClk(nFlags, point);
CContact *Contact = GetFromListItem(GetSelectionMark());
RECT rect;
GetItemRect(GetSelectionMark(), &rect, LVIR_BOUNDS);
if (!Contact) return;
if (point.x > rect.left && point.x < rect.right && point.y > rect.top && point.y < rect.bottom)
NewConversation(Contact, NULL);
}
void CContactView::AcceptSock()
{
unsigned int PeerPort;
CString PeerAddress;
CNetSocket* NewSock = new CNetSocket();
ListenSocket->Accept(*NewSock);
NewSock->Init();
NewSock->GetPeerName(PeerAddress, PeerPort);
if (GetApp()->MainView->IsMyIp(IP(PeerAddress)))
{
NewSock->SendString("ERROR You cannot connect from this host");
delete NewSock;
return;
}
SetOnline(IP(PeerAddress), NewSock);
}
void CContactView::NewConversation(CContact *With, char *DefaultMsg)
{
if (!IsContact(With))
return;
if (With->IsConvWindowOpen())
{
With->pThread->Conv->SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
With->pThread->Conv->ShowWindow(SW_RESTORE);
With->pThread->Conv->SetWindowPos(&wndNoTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
return;
}
if (With->Flags & CFL_ACTIVE) return;
if (With->IsOffline())
{
MessageBox("You cannot send instant messages to offline users", "Cannot send message", MB_OK|MB_ICONSTOP);
return;
}
if (DefaultMsg && AfxGetApp()->GetProfileInt("Settings", "UsePopup", 1))
{
char buf[512];
sndPlaySound("alert2.wav", SND_ASYNC);
sprintf(buf, "%s says: %s", With->GetTruncatedScreenName(20), DefaultMsg);
CPopWndThread *PopThread = new CPopWndThread(buf);
PopThread->View = this;
PopThread->Contact = With;
PopThread->pLast = LastPopup;
PopThread->CreateThread();
}
CConversationThread *Thread = new CConversationThread(With, DefaultMsg);
With->pThread = Thread;
Thread->CreateThread();
With->Flags |= CFL_ACTIVE;
PluginsConversationWindowOpened(With);
}
void CContactView::StartFileTransfer(HWND parentWnd, CContact *Contact, bool Sending, char *FileName, int Port, unsigned long FileSize)
{
if (!IsContact(Contact))
return;
if (!IsWindow(parentWnd))
return;
if (Contact->IsOffline())
{
if (Sending) ::MessageBox(parentWnd, "You cannot send files to offline users", "Send file", MB_OK|MB_ICONSTOP);
return;
}
if (Contact->IsBlocked())
{
if (Sending) ::MessageBox(parentWnd, "You cannot send files to blocked users", "Send file", MB_OK|MB_ICONSTOP);
return;
}
if (Me.IsOffline())
{
if (Sending) ::MessageBox(parentWnd, "You cannot send files with your status is set to 'Appear Offline'", "Send file", MB_OK|MB_ICONSTOP);
return;
}
if (Contact->IsTransfering())
{
if (Contact->Transfer->Finished)
{
if (Contact->Transfer->StatusConv)
Contact->Transfer->StatusConv->Remove();
if (Contact->Transfer->StatusDlg)
Contact->Transfer->StatusDlg->Remove();
Contact->Transfer->Kill();
}
else
{
::MessageBox(parentWnd, "You already have transfers open with this contact", "File transfer", MB_OK|MB_ICONSTOP);
return;
}
}
CFileSocketThread *Thread = new CFileSocketThread(Contact, Sending, FileName, Port, FileSize);
Thread->CreateThread();
Contact->Transfer = Thread;
Contact->Flags |= CFL_TRANSFER;
}
LRESULT CContactView::OnSendMessage(WPARAM wParam, LPARAM lParam)
{
MESSAGE *Msg = (MESSAGE *)lParam;
if (!IsContact(Msg->To))
return 0L;
if (!IsSocket(Msg->To->GetSock()) || Msg->To->IsOffline() || Msg->To->IsBlocked())
{
return 0L;
}
strrpl(Msg->Message, "\r", "");
strrpl(Msg->Message, "\n", "$CRLF");
Msg->To->GetSock()->SendString("MESSAGE %s", Msg->Message);
delete Msg;
return 1L;
}
LRESULT CContactView::OnSockConnect(WPARAM wParam, LPARAM lParam)
{
ClaimSock((SOCKET)wParam, (CContact *)lParam);
return 0L;
}
LRESULT CContactView::OnDestroyThread(WPARAM wParam, LPARAM lParam)
{
CConversationThread *Thread = (CConversationThread *)lParam;
Thread->pWith->Flags &= ~CFL_ACTIVE;
Thread->pWith->Flags &= ~CFL_DLGCREATED;
Thread->pWith->pThread = NULL;
Thread->PostThreadMessage(WM_QUIT, 0, 0);
return 0L;
}
LRESULT CContactView::OnBlockContact(WPARAM wParam, LPARAM lParam)
{
CContact *Contact = (CContact *)lParam;
if (!IsContact(Contact))
return 0L;
Contact->SetBlocked(wParam ? true : false, Contact->pThread->Conv->GetSafeHwnd());
return 0L;
}
LRESULT CContactView::OnTypeNotify(WPARAM wParam, LPARAM lParam)
{
CContact *Contact = (CContact *)lParam;
if (!IsContact(Contact))
return 0L;
if (!IsSocket(Contact->GetSock()))
return 0L;
if (wParam) Contact->GetSock()->SendString("TYPING");
else Contact->GetSock()->SendString("NOTTYPING");
return 0L;
}
LRESULT CContactView::OnRequestSend(WPARAM wParam, LPARAM lParam)
{
XFER *Xfer = (XFER *)lParam;
if (!IsContact(Xfer->Contact))
return 0L;
if (!IsSocket(Xfer->Contact->GetSock()))
return 0L;
Xfer->Contact->GetSock()->SendString("FILE %d %u %s", Xfer->port, Xfer->filelen, Xfer->filename);
delete Xfer;
return 0L;
}
LRESULT CContactView::OnCancelSend(WPARAM wParam, LPARAM lParam)
{
CContact *Contact = (CContact *)lParam;
if (!IsContact(Contact))
return 0L;
if (!IsSocket(Contact->GetSock()))
return 0L;
Contact->GetSock()->SendString("CANCELXFER");
return 0L;
}
LRESULT CContactView::OnTransferComplete(WPARAM wParam, LPARAM lParam)
{
CContact *Contact = (CContact *)lParam;
if (!IsContact(Contact))
return 0L;
if (!IsSocket(Contact->GetSock()))
return 0L;
Contact->GetSock()->SendString("TRANSFERCOMPLETE");
return 0L;
}
void CContactView::OnDropFiles(HDROP hDropInfo)
{
CListCtrl::OnDropFiles(hDropInfo);
POINT point;
RECT rect;
int i, item = -1;
DragQueryPoint(hDropInfo, &point);
for (i = 0; i < GetItemCount(); i++)
{
GetItemRect(i, &rect, LVIR_BOUNDS);
if (point.x > rect.left && point.x < rect.right && point.y > rect.top && point.y < rect.bottom)
{
item = i;
break;
}
}
if (item < 0) return;
CContact *Contact = GetFromListItem(item);
if (!Contact) return;
DragQueryFile(hDropInfo, 0, File, sizeof(File));
StartFileTransfer(GetSafeHwnd(), Contact, true, File);
}
void CContactView::OnTimer(UINT nIDEvent)
{
CListCtrl::OnTimer(nIDEvent);
}
void CContactView::SetMeOffline(bool bOffline)
{
if (bOffline)
{
POSITION pos;
pos = List.GetHeadPosition();
while (pos)
{
CContact *Contact = List.GetNext(pos);
if (Contact->IsTransfering())
{
MessageBox("You cannot set to 'Appear Offline' with transfer windows open", "Appear offline", MB_OK|MB_ICONSTOP);
return;
}
}
Me.Flags |= CFL_OFFLINE;
SendToAllOnline(false, true, "OFFLINE");
BuildList();
}
else
{
Me.Flags &= ~CFL_OFFLINE;
::SendMyOnline(NULL);
BuildList();
}
POSITION pos;
pos = List.GetHeadPosition();
while (pos)
{
CContact *Contact = List.GetNext(pos);
if (Contact->IsConvWindowOpen())
{
Contact->pThread->Conv->UpdateWindow();
}
}
PluginsContactStatusChanged(&Me, CT_OFFLINE);
}
void CContactView::ChangeMyName(const char *NewName)
{
Me.SetScreenName(NewName);
SendToAllOnline(false, false, "NAME %s", Me.GetScreenName());
BuildList();
PluginsContactStatusChanged(&Me, CT_NAME);
}
LRESULT CContactView::OnUpdateFont(WPARAM wParam, LPARAM lParam)
{
ChangeMyFont();
return 0L;
}
void CContactView::ChangeMyFont() //the one and only Me.uFont should be pre updated
{
char font[512];
uital2(&Me.uFont, sizeof(USERFONT), font); //ahh fuckit, send em full USERFONT struct
SendToAllOnline(false, false, "FONT %s", font);
AfxGetApp()->WriteProfileBinary("Settings", "MyFont", (LPBYTE)&Me.uFont, sizeof(USERFONT));
PluginsContactStatusChanged(&Me, CT_FONT);
}
bool IsContact(CContact *Contact)
{
CList<CContact *, CContact *> *List = &GetApp()->View->List;
POSITION pos;
pos = List->GetHeadPosition();
if (!Contact) return false;
if (Contact == &GetApp()->View->Me)
return true;
while (pos)
{
if (List->GetNext(pos) == Contact)
return true;
}
return false;
}
void CContactView::OnClick(NMHDR* pNMHDR, LRESULT* pResult)
{
*pResult = 0;
}
void CContactView::OnLButtonDown(UINT nFlags, CPoint point)
{
CListCtrl::OnLButtonDown(nFlags, point);
RedrawWindow();
//why? because when Windows XP visual styles are applied
//to this program it doesn't redraw previously selected items, otherwise, not needed.
}
void CContactView::OnCustomdraw(NMHDR* pNMHDR, LRESULT* pResult)
{
NMLVCUSTOMDRAW* lplvcd = (NMLVCUSTOMDRAW*)pNMHDR;
CDC* pDC = CDC::FromHandle(lplvcd->nmcd.hdc);
switch (lplvcd->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
{
*pResult = CDRF_NOTIFYITEMDRAW;
break;
}
case CDDS_ITEMPREPAINT:
{
*pResult = CDRF_DODEFAULT;
int iRow = lplvcd->nmcd.dwItemSpec;
if (iRow == OfflineItem || iRow == 1)
{
lplvcd->clrText = GetColor(COL_LINEFRAMES);
pDC->SelectObject(&FontBold);
*pResult = CDRF_NEWFONT;
}
break;
}
default:
*pResult = CDRF_DODEFAULT;
}
}
void CContactView::LoadEmoticons()
{
fstream f;
char szFileName[1024];
char szActivationText[64];
f.open("emoticons.ini", ios::in);
if (f.eof())
return;
while (!f.eof())
{
f.getline(szActivationText, sizeof(szActivationText));
if (f.eof())
return;
f.getline(szFileName, sizeof(szFileName));
AddEmoticon(szFileName, szActivationText);
}
}
void CContactView::DeleteEmoticons()
{
POSITION pos;
pos = Emoticons.GetHeadPosition();
while (pos)
{
EMOTICON *Emoticon = Emoticons.GetNext(pos);
FreeResource(Emoticon->hBitmap);
Emoticons.RemoveAt(Emoticons.Find(Emoticon));
delete Emoticon;
}
}
void CContactView::AddEmoticon(char *szFileName, char *szActivationText)
{
EMOTICON *Emoticon = new EMOTICON;
strcpy(Emoticon->szActivationText, szActivationText);
strcpy(Emoticon->szFileName, szFileName);
Emoticon->hBitmap = (HBITMAP)::LoadImage(NULL, szFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!Emoticon->hBitmap)
{
delete Emoticon;
return;
}
Emoticons.AddTail(Emoticon);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -