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

📄 recvdlg.cpp

📁 带有工程文件的飞鸽传输源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	FD_ZERO(&rfd);
	FD_SET(fileObj->conInfo->sd, &rfd);

	for (int waitCnt=0; waitCnt < 120 && fileObj->hThread != NULL; waitCnt++)
	{
		tv.tv_sec = 1, tv.tv_usec = 0;
		if ((sock_ret = ::select(fileObj->conInfo->sd + 1, &rfd, NULL, NULL, &tv)) > 0)
		{
			waitCnt = 0;
			if ((recvDlg->*RecvFileFunc)() != TRUE)
				break;
			if (fileObj->status == FS_COMPLETE)
				break;
		}
		else if (sock_ret == 0) {
			FD_ZERO(&rfd);
			FD_SET(fileObj->conInfo->sd, &rfd);
			fileObj->conInfo->lastTick = ::GetTickCount();
			recvDlg->PostMessage(WM_RECVDLG_FILEBUTTON, 0, 0);
		}
		else if (sock_ret == SOCKET_ERROR) {
			break;
		}
	}
	recvDlg->CloseRecvFile(fileObj->status == FS_COMPLETE ? TRUE : FALSE);
	if (fileObj->status != FS_COMPLETE)
		fileObj->status = FS_ERROR;

	recvDlg->PostMessage(WM_TCPEVENT, fileObj->conInfo->sd, FD_CLOSE);
	::ExitThread(0);
	return	0;
}

BOOL TRecvDlg::CloseRecvFile(BOOL setAttr)
{
	if (fileObj->hFile != INVALID_HANDLE_VALUE)
	{
		if (setAttr)
		{
			FILETIME	ft;
			UnixTime2FileTime(fileObj->curFileInfo.Mtime(), &ft);
#if 1	// 巄掕張抲乮protocol format 曄峏偺壜擻惈乯
			if (fileObj->isDir || (fileObj->curFileInfo.Mtime() & 0xffffff00))
#endif
				::SetFileTime(fileObj->hFile, NULL, &ft, &ft);
		}
		fileObj->totalTrans += fileObj->offset;
		fileObj->totalFiles++;
		fileObj->offset = fileObj->woffset = 0;

		::CloseHandle(fileObj->hFile);
		fileObj->hFile = INVALID_HANDLE_VALUE;
	}
	return	TRUE;
}

BOOL DecodeDirEntry(char *buf, FileInfo *info)
{
	char	*tok, *ptr, *p;

	ConvertShareMsgEscape(buf);	// "::" -> ';'

	if ((tok = separate_token(buf, ':', &p)) == NULL)	// header size
		return	FALSE;

	if ((tok = separate_token(NULL, ':', &p)) == NULL)	// fname
		return	FALSE;
	info->SetFnameExt(tok);
	while ((ptr = strchr(tok, '?')) != NULL)	// UNICODE 傑偱偺巄掕
		*ptr = '_';

	if (strlen(tok) >= MAX_PATH)
		return	FALSE;

	if ((tok = separate_token(NULL, ':', &p)) == NULL)	// size
		return	FALSE;
	info->SetSize(hex2ll(tok));

	if ((tok = separate_token(NULL, ':', &p)) == NULL)	// attr
		return	FALSE;
	info->SetAttr(strtoul(tok, 0, 16));

	while ((tok = separate_token(NULL, ':', &p)) != NULL)	// exattr
	{
		if ((ptr = strchr(tok, '=')) == NULL)
			continue;
		*ptr = 0;

		UINT	exattr = strtoul(tok, 0, 16);
		UINT	val = strtoul(ptr + 1, 0, 16);

		switch (exattr) {
		case IPMSG_FILE_MTIME:		info->SetMtime(val); break;
//		case IPMSG_FILE_CREATETIME:	info->SetCrtime(val); break;	尰忬偱偼巊傢側偄
//		case IPMSG_FILE_ATIME:		info->SetAtime(val); break;		尰忬偱偼巊傢側偄
		default: break;
		}
	}
	return	TRUE;
}

BOOL TRecvDlg::RecvDirFile(void)
{
#define BIG_ALLOC	50
#define PEEK_SIZE	8

	if (fileObj->status == FS_DIRFILESTART || fileObj->status == FS_TRANSINFO)
	{
		int		size;
		if (fileObj->infoLen == 0)
		{
			if ((size = ::recv(fileObj->conInfo->sd, fileObj->info + (int)fileObj->offset, PEEK_SIZE - (int)fileObj->offset, 0)) <= 0)
				return	FALSE;
			if ((fileObj->offset += size) < PEEK_SIZE)
				return	TRUE;
			fileObj->info[fileObj->offset] = 0;
			if ((fileObj->infoLen = strtoul(fileObj->info, 0, 16)) >= sizeof(fileObj->info) -1 || fileObj->infoLen <= 0)
				return	FALSE;	// too big or small
		}
		if (fileObj->offset < fileObj->infoLen)
		{
			if ((size = ::recv(fileObj->conInfo->sd, fileObj->info + (int)fileObj->offset, fileObj->infoLen - (int)fileObj->offset, 0)) <= 0)
				return	FALSE;
			fileObj->offset += size;
		}
		if (fileObj->offset == fileObj->infoLen)
		{
			fileObj->info[fileObj->infoLen] = 0;
			if (DecodeDirEntry(fileObj->info, &fileObj->curFileInfo) == FALSE)
				return	FALSE;	// Illegal entry
			fileObj->offset = fileObj->infoLen = 0;	// 弶婜壔

			if (GET_MODE(fileObj->curFileInfo.Attr()) == IPMSG_FILE_DIR)
			{
				char	buf[MAX_BUF];
				const char *fname = fileObj->dirCnt == 0 ? fileObj->fileInfo->Fname() : fileObj->curFileInfo.Fname();

				if (MakePath(buf, fileObj->path, fname) >= MAX_PATH)
					return	MessageBox(buf, PATHTOOLONG_MSGSTR), FALSE;
				if (IsSafePath(buf, fname) == FALSE)
					return	FALSE;

				if (::CreateDirectory(buf, NULL) == FALSE)
					return	FALSE;
				strncpyz(fileObj->path, buf, MAX_PATH);
				fileObj->dirCnt++;
			}
			else if (GET_MODE(fileObj->curFileInfo.Attr()) == IPMSG_FILE_RETPARENT)
			{
				if (fileObj->curFileInfo.Mtime())	// directory 偺 time stamp 傪偁傢偣傞(NT宯偺傒)
				{
					FILETIME	ft;
					HANDLE		hFile;
					UnixTime2FileTime(fileObj->curFileInfo.Mtime(), &ft);
					if ((hFile = ::CreateFile(fileObj->path, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)) != INVALID_HANDLE_VALUE)
					{
						::SetFileTime(hFile, NULL, NULL, &ft);
						::CloseHandle(hFile);
					}
				}
				if (fileObj->curFileInfo.Attr() & IPMSG_FILE_RONLYOPT)
					::SetFileAttributes(fileObj->path, FILE_ATTRIBUTE_READONLY);
				if (--fileObj->dirCnt <= 0)
				{
					fileObj->status = FS_COMPLETE;
					return	TRUE;
				}
				if (PathToDir(fileObj->path, fileObj->path) == FALSE)
					return	FALSE;
			}
			else {
				if (fileObj->dirCnt == 0)
					return	FALSE;
				
				if (fileObj->curFileInfo.Size() == 0)	// 0byte file
				{
					if (OpenRecvFile())		// 0byte偺応崌偼嶌惉幐攕傪柍帇
						CloseRecvFile(TRUE);
				}
				fileObj->status = fileObj->curFileInfo.Size() ? FS_TRANSFILE : FS_TRANSINFO;
			}
			return	TRUE;
		}
	}

	if (fileObj->status == FS_TRANSFILE)
	{
		if (RecvFile() != TRUE)
		{
			CloseRecvFile();
			return	FALSE;
		}
		if (fileObj->status == FS_ENDFILE)
		{
			CloseRecvFile(TRUE);
			fileObj->status = FS_TRANSINFO;
		}
	}

	return	TRUE;
}

BOOL TRecvDlg::OpenRecvFile(void)
{
	char	path[MAX_BUF];

	if (MakePath(path, fileObj->isDir ? fileObj->path : fileObj->saveDir, fileObj->curFileInfo.Fname()) >= MAX_PATH)
		return	MessageBox(path, PATHTOOLONG_MSGSTR), FALSE;
	if (IsSafePath(path, fileObj->curFileInfo.Fname()) == FALSE)
		return	MessageBox(path, NOTSAFEPATH_MSGSTR), FALSE;

	if ((fileObj->hFile = ::CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE)
		return	fileObj->isDir ? FALSE : (MessageBox(CREATEFAIL_MSGSTR, path), FALSE);

	if (fileObj->curFileInfo.Attr() & IPMSG_FILE_RONLYOPT)
		::SetFileAttributes(path, FILE_ATTRIBUTE_READONLY);

//::SetFilePointer(fileObj->hFile, OFFSET, 0, FILE_BEGIN);
//::SetEndOfFile(fileObj->hFile);

	return	TRUE;
}

BOOL TRecvDlg::RecvFile(void)
{
	int		wresid = (int)(fileObj->offset - fileObj->woffset);
	_int64	remain = fileObj->curFileInfo.Size() - fileObj->offset;
	int		size = 0;

	if (remain > cfg->TransMax - wresid)
		remain = cfg->TransMax - wresid;

	if ((size = ::recv(fileObj->conInfo->sd, fileObj->recvBuf + wresid, (int)remain, 0)) <= 0)
		return	FALSE;

	if (fileObj->hFile == INVALID_HANDLE_VALUE)
		if (OpenRecvFile() == FALSE)
			return	FALSE;

	wresid += size;
	if (fileObj->offset + size >= fileObj->curFileInfo.Size() || cfg->TransMax == wresid)
	{
		DWORD	wsize;
		if (::WriteFile(fileObj->hFile, fileObj->recvBuf, wresid, &wsize, 0) != TRUE || wresid != (int)wsize)
			return	MessageBox(WRITEFAIL_MSGSTR), FALSE;
		fileObj->woffset += wresid;
	}
	fileObj->offset += size;

	DWORD	nowTick = ::GetTickCount();

	if (nowTick - fileObj->conInfo->lastTick >= 1000)
	{
		fileObj->conInfo->lastTick = nowTick;
		PostMessage(WM_RECVDLG_FILEBUTTON, 0, 0);
	}

	if (fileObj->offset >= fileObj->curFileInfo.Size())
		fileObj->status = fileObj->isDir ? FS_ENDFILE : FS_COMPLETE;

	return	TRUE;
}

int MakeTransRateStr(char *buf, DWORD ticks, _int64 cur_size, _int64 total_size)
{
	int len = 0;
	buf[len++] = ' ';
	len += MakeSizeString(buf + len, cur_size) -2;	// "MB"晹暘傪敳偔
	buf[len++] = '/';
	len += MakeSizeString(buf + len, total_size);
	buf[len++] = ' ';
	len += MakeSizeString(buf + len, cur_size * 1000 / (ticks ? ticks : 10));
	return len + wsprintf(buf + len, "/s (%d%%)", (int)(cur_size * 100 / (total_size ? total_size : 1)));
}

int MakeDirTransRateStr(char *buf, DWORD ticks, _int64 cur_size, int files)
{
	int len = 0;
	buf[len++] = ' ';
	len += wsprintf(buf + len, "总计 ");
	len += MakeSizeString(buf + len, cur_size);
	len += wsprintf(buf + len, "/%d 个文件 (", files);
	len += MakeSizeString(buf + len, cur_size * 1000 / (ticks ? ticks : 1));
	return	len + wsprintf(buf + len, "/s)" );
}

class RecvTransEndDlg : public TDlg {
	RecvFileObj	*fileObj;

public:
	RecvTransEndDlg(RecvFileObj *_fileObj, TWin *_win) : TDlg(_fileObj->status == FS_COMPLETE ? TRANSEND_DIALOG : SUSPEND_DIALOG, _win) { fileObj = _fileObj; }
	virtual BOOL	EvCreate(LPARAM lParam);
	virtual BOOL	EvCommand(WORD wNotifyCode, WORD wID, LPARAM hwndCtl);
};

BOOL RecvTransEndDlg::EvCreate(LPARAM lParam)
{
	char	buf[MAX_BUF];
	DWORD	difftick = fileObj->lastTick - fileObj->startTick;
	int		len = 0;

	len += wsprintf(buf + len, "\r\n总计: ");
	len += MakeSizeString(buf + len, fileObj->totalTrans);
	len += wsprintf(buf + len, " (");
	len += MakeSizeString(buf + len, fileObj->totalTrans * 1000 / (difftick ? difftick : 1));
	len += wsprintf(buf + len, "/s)\r\n%d", difftick/1000);
	if (difftick/1000 < 20)
		len += wsprintf(buf + len, ".%02d", (difftick%1000) / 10);
	len += wsprintf(buf + len, " 秒   ");
	if (fileObj->totalFiles > 1 || fileObj->isDir)
		len += wsprintf(buf + len, "%d 个文件", fileObj->totalFiles);
	else
		len += wsprintf(buf + len, "%s", fileObj->fileInfo->Fname());

	if (fileObj->status == FS_COMPLETE)
	{
		if (fileObj->totalFiles > 1 || fileObj->isDir)
			EnableWindow(GetDlgItem(EXEC_BUTTON), FALSE);
	}

	SetDlgItemText(FILE_STATIC, buf);

	GetWindowRect(&rect);
	MoveWindow(rect.left + 30, rect.top + 30, rect.right - rect.left, rect.bottom - rect.top, TRUE);
	return	TRUE;
}

BOOL RecvTransEndDlg::EvCommand(WORD wNotifyCode, WORD wID, LPARAM hwndCtl)
{
	if (fileObj->status == FS_COMPLETE && wID == IDCANCEL)
		wID = IDOK;

	switch (wID)
	{
	case FOLDER_BUTTON: case EXEC_BUTTON: case IDCANCEL: case IDOK: case IDRETRY:
		EndDialog(wID);
		return	TRUE;
	}

	return	FALSE;
}

BOOL TRecvDlg::EndRecvFile(BOOL manual_suspend)
{
	if (fileObj->hThread)
	{
		HANDLE	hThread = fileObj->hThread;
		fileObj->hThread = 0;	// 拞抐偺崌恾
		WaitForSingleObject(hThread, INFINITE);
		::CloseHandle(hThread);
	}

	fileObj->lastTick = fileObj->conInfo->lastTick = ::GetTickCount();
	SetTransferButtonText();

	int			target = ShareMng::GetFileInfoNo(shareInfo, fileObj->fileInfo);
	FileInfo	*fileInfo = fileObj->fileInfo;
	BOOL		isSingleTrans = fileObj->startTick == fileObj->conInfo->startTick;

	::closesocket(fileObj->conInfo->sd);
	delete [] fileObj->recvBuf;
	delete fileObj->conInfo;
	fileObj->conInfo = NULL;

	if (fileObj->status == FS_COMPLETE)
	{
		for (int cnt=0; cnt < shareInfo->fileCnt; cnt++)
		{
			if (shareInfo->fileInfo[cnt]->IsSelected() && shareInfo->fileInfo[cnt] != fileInfo)
			{
				FreeDecodeShareMsgFile(shareInfo, target);
				return	SaveFile();
			}
		}
	}

	int ret = manual_suspend ? IDCANCEL : RecvTransEndDlg(fileObj, this).Exec();

	if (ret == EXEC_BUTTON || ret == FOLDER_BUTTON && fileObj->isDir && isSingleTrans)
	{
		char	buf[MAX_BUF];
		MakePath(buf, fileObj->saveDir, fileInfo->Fname());
		::ShellExecute(NULL, NULL, buf, 0, 0, SW_SHOW);
	}
	else if (ret == FOLDER_BUTTON)
		::ShellExecute(NULL, NULL, fileObj->saveDir, 0, 0, SW_SHOW);

	if (ret == IDOK || ret == FOLDER_BUTTON || ret == EXEC_BUTTON)
		FreeDecodeShareMsgFile(shareInfo, target);

	SetFileButton(this, FILE_BUTTON, shareInfo);
	EvSize(SIZE_RESTORED, 0, 0);

	if (ret == IDRETRY)
		PostMessage(WM_COMMAND, FILE_BUTTON, 0);

	return	TRUE;
}

void TRecvDlg::SetTransferButtonText(void)
{
	char	buf[MAX_LISTBUF];

	if (fileObj->conInfo == NULL)
		return;
	if (fileObj->isDir)
		MakeDirTransRateStr(buf, fileObj->conInfo->lastTick - fileObj->startTick, fileObj->totalTrans + fileObj->offset, fileObj->totalFiles);
	else
		MakeTransRateStr(buf, fileObj->conInfo->lastTick - fileObj->conInfo->startTick, fileObj->status < FS_COMPLETE ? fileObj->offset : fileObj->curFileInfo.Size(), fileObj->curFileInfo.Size());
	SetDlgItemText(FILE_BUTTON, buf);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -