Fix: Linux client UTF-8 path/active-window garbled on server

This commit is contained in:
yuanyuanxiang
2026-05-08 14:03:45 +02:00
parent bc06fd5af5
commit f85cc8b86c
2 changed files with 39 additions and 3 deletions

View File

@@ -1170,7 +1170,11 @@ int main(int argc, char* argv[])
} }
// 构造并发送心跳包(与 Windows 端 KernelManager::SendHeartbeat 格式一致) // 构造并发送心跳包(与 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; Heartbeat hb;
hb.Time = GetUnixMs(); hb.Time = GetUnixMs();

View File

@@ -178,15 +178,25 @@ bool SupportsFileTransferV2(context* ctx) {
} }
// 获取客户端协议字符串编码优先看自身能力位若是子连接CAPABILITIES 为空) // 获取客户端协议字符串编码优先看自身能力位若是子连接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) { UINT GetClientEncoding(context* ctx) {
if (!ctx) return 936; if (!ctx) return 936;
// 主连接情形CAPABILITIES 已由 LOGIN_INFOR 处理流程填好 // 主连接情形CAPABILITIES 已由 LOGIN_INFOR 处理流程填好
if (ctx->SupportsUtf8()) return CP_UTF8; 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 找主连接 // 子连接情形CAPABILITIES 为空 -> 通过 IP 找主连接
if (g_2015RemoteDlg) { if (g_2015RemoteDlg) {
context* mainCtx = g_2015RemoteDlg->FindHostByIP(ctx->GetPeerName()); 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; return 936;
} }
@@ -7550,6 +7560,28 @@ void CMy2015RemoteDlg::OnListClick(NMHDR* pNMHDR, LRESULT* pResult)
CString res[RES_MAX]; CString res[RES_MAX];
CString startTime = ctx->GetClientData(ONLINELIST_STARTTIME); CString startTime = ctx->GetClientData(ONLINELIST_STARTTIME);
ctx->GetAdditionalData(res); 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(); FlagType type = ctx->GetFlagType();
static std::map<FlagType, std::string> typMap = { static std::map<FlagType, std::string> typMap = {
{FLAG_WINOS, "WinOS"}, {FLAG_UNKNOWN, "Unknown"}, {FLAG_SHINE, "Shine"}, {FLAG_WINOS, "WinOS"}, {FLAG_UNKNOWN, "Unknown"}, {FLAG_SHINE, "Shine"},