⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 contactview.cpp

📁 vc++6.0开发网络典型应用实例导航 1. 本光盘提供了本书中所有的实例源程序文件。 2. 附录文件夹下是Winsock 函数参考以及错误码列表
💻 CPP
📖 第 1 页 / 共 2 页
字号:

#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 + -