From f85cc8b86c7604966f438654d74f1c1f699b10d7 Mon Sep 17 00:00:00 2001 From: yuanyuanxiang <962914132@qq.com> Date: Fri, 8 May 2026 14:03:45 +0200 Subject: [PATCH] Fix: Linux client UTF-8 path/active-window garbled on server --- linux/main.cpp | 6 ++++- server/2015Remote/2015RemoteDlg.cpp | 36 +++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/linux/main.cpp b/linux/main.cpp index 7ee772c..fd1187e 100644 --- a/linux/main.cpp +++ b/linux/main.cpp @@ -1170,7 +1170,11 @@ int main(int argc, char* argv[]) } // 构造并发送心跳包(与 Windows 端 KernelManager::SendHeartbeat 格式一致) - std::string activity = utf8ToGbk(activityChecker.Check()); + // ActiveWnd 直接发 UTF-8——与 LOGIN_INFOR.moduleVersion 中声明的 + // CLIENT_CAP_UTF8 一致;服务端按 cap 位用 CP_UTF8 解码。早期为兼容 + // MBCS 老服务端做过 utf8ToGbk 转换,但现在新版 Linux 客户端经 + // libsign 网关只能连新版服务端,无需再转。 + std::string activity = activityChecker.Check(); Heartbeat hb; hb.Time = GetUnixMs(); diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index c2ba46f..2f5e99f 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -178,15 +178,25 @@ bool SupportsFileTransferV2(context* ctx) { } // 获取客户端协议字符串编码:优先看自身能力位,若是子连接(CAPABILITIES 为空) -// 则通过 peer IP 查主连接。找不到则默认 CP936。 +// 则通过 peer IP 查主连接。Linux/macOS 客户端文件系统路径与 locale 现代发行版 +// 默认就是 UTF-8——即便客户端二进制是早于 CLIENT_CAP_UTF8 引入(commit 0aa7588) +// 之前编译的,没声明 cap 位,事实上仍发 UTF-8 字节,按 client type 兜底走 UTF-8。 +// 找不到则默认 CP936。 UINT GetClientEncoding(context* ctx) { if (!ctx) return 936; // 主连接情形:CAPABILITIES 已由 LOGIN_INFOR 处理流程填好 if (ctx->SupportsUtf8()) return CP_UTF8; + // 客户端类型兜底:LNX / MAC 默认 UTF-8(兼容老二进制无 UTF-8 cap 位的情形) + CString clientType = ctx->GetAdditionalData(RES_CLIENT_TYPE); + if (clientType == "LNX" || clientType == "MAC") return CP_UTF8; // 子连接情形:CAPABILITIES 为空 -> 通过 IP 找主连接 if (g_2015RemoteDlg) { context* mainCtx = g_2015RemoteDlg->FindHostByIP(ctx->GetPeerName()); - if (mainCtx && mainCtx->SupportsUtf8()) return CP_UTF8; + if (mainCtx) { + if (mainCtx->SupportsUtf8()) return CP_UTF8; + CString mainType = mainCtx->GetAdditionalData(RES_CLIENT_TYPE); + if (mainType == "LNX" || mainType == "MAC") return CP_UTF8; + } } return 936; } @@ -7550,6 +7560,28 @@ void CMy2015RemoteDlg::OnListClick(NMHDR* pNMHDR, LRESULT* pResult) CString res[RES_MAX]; CString startTime = ctx->GetClientData(ONLINELIST_STARTTIME); ctx->GetAdditionalData(res); + // 客户端 RES_* 字符串编码取决于客户端能力位:UTF-8 客户端(Linux/macOS/新 Win) + // 发的是 UTF-8 字节,老客户端是 CP_ACP。这里统一规整到 CP_ACP,让下游 FormatL + // 与既有 ANSI 字符串拼接以及最终 CP_ACP→wide 的浮窗渲染都能正确识别。 + // 若服务端运行系统的 ANSI 代码页不能容纳客户端字符(如德语服务端遇到中文路径), + // 不可表示的字符会变 '?' —— 与项目其它路径的既有限制一致,不在本次修复范围。 + UINT cp = GetClientEncoding(ctx); + if (cp != CP_ACP) { + for (int i = 0; i < RES_MAX; i++) { + if (res[i].IsEmpty()) continue; + int wlen = MultiByteToWideChar(cp, 0, res[i].GetString(), -1, NULL, 0); + if (wlen <= 1) continue; + std::wstring wbuf(wlen - 1, L'\0'); + MultiByteToWideChar(cp, 0, res[i].GetString(), -1, &wbuf[0], wlen); + int alen = WideCharToMultiByte(CP_ACP, 0, wbuf.c_str(), -1, NULL, 0, NULL, NULL); + if (alen <= 1) continue; + CString out; + WideCharToMultiByte(CP_ACP, 0, wbuf.c_str(), -1, + out.GetBufferSetLength(alen - 1), alen, NULL, NULL); + out.ReleaseBuffer(alen - 1); + res[i] = out; + } + } FlagType type = ctx->GetFlagType(); static std::map typMap = { {FLAG_WINOS, "WinOS"}, {FLAG_UNKNOWN, "Unknown"}, {FLAG_SHINE, "Shine"},