Feature: Add download_file MCP tool (V2 protocol, SHA-256 verified)
download_file pulls a remote file or directory back to the controller over the existing V2 file-transfer protocol. It reuses COMMAND_LIST_DRIVE to open the file-manager sub-link, then sends CMD_DOWN_FILES_V2 so the Windows client streams COMMAND_SEND_FILE_V2 chunks and a per-file COMMAND_FILE_COMPLETE_V2 SHA-256 checksum over its own authenticated sub-connection. The server routes those two packet types into a new per-device FileTransferSession whenever a download is pending, so the headless path never opens the GUI progress dialog; the C2C and existing GUI branches are left untouched. Files are written under a normalized local_dir, and every chunk filename is resolved and verified to stay inside local_dir (directories included) to block .. traversal; overwrite=false skips existing files and counts them as skipped. One transfer per host (mutually exclusive with the one-shot pending registry), a dedicated McpFileTransfer=0-by-default gate surfaced in the settings dialog, and audit logging complete the change. upload_file remains future work. Co-Authored-By: deepseek-v4-pro
This commit is contained in:
@@ -2201,6 +2201,8 @@ BOOL CMy2015RemoteDlg::OnInitDialog()
|
||||
McpServer().SetTerminalEnabled(THIS_CFG.GetInt("settings", "McpTerminal", 0) != 0);
|
||||
// 远程控制开关:默认关;要求只读关(McpReadonly=0)才生效(工具列表/分派双重门控)。
|
||||
McpServer().SetRemoteControlEnabled(THIS_CFG.GetInt("settings", "McpRemoteControl", 0) != 0);
|
||||
// 文件传输开关:默认关;仅 download_file 门控(不要求只读关)。
|
||||
McpServer().SetFileTransferEnabled(THIS_CFG.GetInt("settings", "McpFileTransfer", 0) != 0);
|
||||
if (!McpServer().Start(mcpBind, mcpPort)) {
|
||||
Mprintf("McpServer start failed on %s:%d\n", mcpBind.c_str(), mcpPort);
|
||||
} else {
|
||||
@@ -5843,6 +5845,14 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject)
|
||||
// V2 文件传输(支持 C2C)
|
||||
FileChunkPacketV2* pkt = (FileChunkPacketV2*)szBuffer;
|
||||
|
||||
// P6:MCP download_file 挂起时接管流式子连接(dstClientID==0 → 主控端)。
|
||||
// OnFileChunkV2 自身会做 len 校验,这里先判长度再读 dstClientID,避免越界。
|
||||
if (len >= sizeof(FileChunkPacketV2) && pkt->dstClientID == 0 &&
|
||||
McpServer().IsFileTransferPending(ContextObject->GetClientID())) {
|
||||
McpServer().OnFileChunkV2(ContextObject->GetClientID(), ContextObject, szBuffer, len);
|
||||
break;
|
||||
}
|
||||
|
||||
if (pkt->dstClientID == 0) {
|
||||
// 目标是主控端:本地接收
|
||||
if (ContextObject->hDlg == NULL) {
|
||||
@@ -6103,6 +6113,13 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject)
|
||||
if (len < sizeof(FileCompletePacketV2)) break;
|
||||
FileCompletePacketV2* pkt = (FileCompletePacketV2*)szBuffer;
|
||||
|
||||
// P6:MCP download_file 挂起时接管完成校验包(dstClientID==0 → 主控端)。
|
||||
if (pkt->dstClientID == 0 &&
|
||||
McpServer().IsFileTransferPending(ContextObject->GetClientID())) {
|
||||
McpServer().OnFileCompleteV2(ContextObject->GetClientID(), szBuffer, len);
|
||||
break;
|
||||
}
|
||||
|
||||
if (pkt->dstClientID == 0) {
|
||||
// 目标是主控端:本地校验
|
||||
bool verifyOk = HandleFileCompleteV2((char*)szBuffer, len, 0);
|
||||
@@ -6436,6 +6453,13 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject)
|
||||
ContextObject->CancelIO(); // 只列盘 → 用完即关一次性子链接
|
||||
break;
|
||||
}
|
||||
// P6:MCP download_file 挂起时接管文件管理器子链接,下发 CMD_DOWN_FILES_V2。
|
||||
// true=已接管(保持子链接,ClearFileTransfer 收尾);false=会话已清理(迟到包)→ 关孤儿子链接。
|
||||
if (McpServer().IsFileTransferPending(devId)) {
|
||||
if (!McpServer().OnDownloadDriveList(devId, ContextObject))
|
||||
ContextObject->CancelIO();
|
||||
break;
|
||||
}
|
||||
ContextObject->EnableZstdContext(6);
|
||||
g_2015RemoteDlg->SendMessage(WM_OPENFILEMANAGERDIALOG, 0, (LPARAM)ContextObject);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user