📄 recvdlg.cpp
字号:
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 + -