360 lines
12 KiB
Markdown
360 lines
12 KiB
Markdown
# Send Connector B-First Plan
|
|
|
|
Date: 2026-07-10
|
|
Node: C29 / write-side connector route correction
|
|
Decision owner: user/business manager
|
|
|
|
## Decision
|
|
|
|
The selected send route is now:
|
|
|
|
1. **Primary route B: in-process / sidecar connector** that reuses the already logged-in `IMPlatformClient.exe` runtime and its existing message/file send classes.
|
|
2. **Fallback route A: constrained UI/RPA wrapper** only if B cannot attach, load, or invoke safely.
|
|
3. **Network replay/protocol reimplementation remains deferred** because it would require independently reproducing login/session/ack behavior.
|
|
|
|
This document supersedes the previous C15/R5 conclusion for future send work. The old conclusion was correct for the evidence available at that time: no write connector had been selected. This node records the newly approved route and the evidence that makes B worth trying first.
|
|
|
|
## Business goal
|
|
|
|
Expose controlled MCP actions for digital employees:
|
|
|
|
- `isphere_send_message`
|
|
- `isphere_send_file`
|
|
|
|
The implementation must preserve these business controls:
|
|
|
|
- target must be resolved from existing contact/group search results;
|
|
- text/file content must be previewed before execution;
|
|
- execution must use an `idempotency_key` and content hash;
|
|
- every outbound attempt must produce an audit record;
|
|
- early versions should support sandbox/test-target verification before normal production use.
|
|
|
|
## Static evidence summary
|
|
|
|
Offline package evidence under:
|
|
|
|
```text
|
|
runs/offline-evidence-intake/zyl-qqfile-20260709/
|
|
```
|
|
|
|
Relevant extracted binaries:
|
|
|
|
```text
|
|
zyl/Impp/IMPlatformClient.exe
|
|
zyl/Impp/smack.dll
|
|
zyl/Impp/IMPP.Interface.dll
|
|
zyl/Impp/IMPP.ServiceBase.dll
|
|
zyl/Impp/IMPP.Service.dll
|
|
zyl/Impp/TcpFileTransfer.dll
|
|
zyl/Impp/HYHC.IMPP.DAL.dll
|
|
```
|
|
|
|
Relevant IL snapshots:
|
|
|
|
```text
|
|
runs/offline-evidence-intake/zyl-qqfile-20260709/metadata/c28-il/IMPlatformClient.exe.il
|
|
runs/offline-evidence-intake/zyl-qqfile-20260709/metadata/c28-il/smack.dll.il
|
|
runs/offline-evidence-intake/zyl-qqfile-20260709/metadata/c28-il/IMPP.Interface.dll.il
|
|
runs/offline-evidence-intake/zyl-qqfile-20260709/metadata/c28-il/IMPP.Service.dll.il
|
|
runs/offline-evidence-intake/zyl-qqfile-20260709/metadata/c28-il/IMPP.ServiceBase.dll.il
|
|
```
|
|
|
|
## Text-send call chain
|
|
|
|
### Preferred sidecar candidate
|
|
|
|
`IMPlatformClient.exe` contains a high-level helper:
|
|
|
|
```text
|
|
IMPP.Client.Core.Plugins.Manager.AppContextManager.SendTxtMessageByJid(jid, chatType, content)
|
|
```
|
|
|
|
Observed behavior from IL:
|
|
|
|
- for direct/P2P chat, it gets a `P2PChatManager` from `IMPPManager.Instance`;
|
|
- it resolves a `Chat` by JID;
|
|
- it finds or opens a chat form;
|
|
- it calls `frmP2PChat.SendTxtMessage(content)`;
|
|
- for temporary/reserved group chat, it calls the corresponding room form send method.
|
|
|
|
This is the best B-route first target because it reuses the logged-in client's own state and UI/business rules.
|
|
|
|
### Central message construction candidate
|
|
|
|
`IMPlatformClient.exe` also contains:
|
|
|
|
```text
|
|
IMPP.Client.Core.MessageEngine.MessageScheduling.SendChatMessage(chat, msgText, toJid, messageType, isSaveMessage, msgGuid, IsReceipt)
|
|
```
|
|
|
|
Observed behavior from IL:
|
|
|
|
- reads local font/style settings;
|
|
- builds message body via `UtilsText.GetMessageStyleBodyText`;
|
|
- decides `chat` vs `groupchat`;
|
|
- creates `smack.packet.XmppMessage`;
|
|
- sets body, subject, offline flag, receipt flag, time, and message type;
|
|
- calls `chat.SendMessage(xmppMessage)`;
|
|
- optionally persists/parses message through `MessageManager.MessageParsing`.
|
|
|
|
This is the cleanest lower-level B candidate if the sidecar can obtain a valid `Chat` object from the running client context.
|
|
|
|
### Protocol bottom
|
|
|
|
`smack.dll` provides the real wire-send chain:
|
|
|
|
```text
|
|
com.vision.smack.Chat.SendMessage(XmppMessage)
|
|
-> com.vision.smack.XMPPConnection.send(string)
|
|
-> Sharp.Xmpp.Core.XmppCore.Send(string)
|
|
-> stream.Write(...)
|
|
```
|
|
|
|
This proves that the send capability exists in the installed client binaries. It also shows why an external reimplementation is less attractive: it would need the same active connection, stanza format, message id, receipt, and session state.
|
|
|
|
## Important trap: plugin interface text send is not enough
|
|
|
|
`IMPP.Interface.dll` declares:
|
|
|
|
```text
|
|
IAppContextManager.SendP2PMessage(string pJid, string pMessage)
|
|
IAppContextManager.SendP2PFiles(UserInfo[] pUserInfo, string[] pFiles)
|
|
IAppContextManager.SendChatRoomMessage(string pRoomJid, string pMessage, string pluginID)
|
|
IAppContextManager.SendPluginMessage(string pluginID, int command, string para)
|
|
```
|
|
|
|
But the implementation of:
|
|
|
|
```text
|
|
IMPP.Client.Core.Plugins.Manager.AppContextManager.SendP2PMessage(...)
|
|
```
|
|
|
|
records the plugin call and then throws `NotImplementedException`.
|
|
|
|
Therefore the B route must **not** choose `SendP2PMessage` as the text-send entry. The sidecar should prefer `SendTxtMessageByJid` or, if necessary, `MessageScheduling.SendChatMessage` with an existing `Chat` object.
|
|
|
|
## File-send call chain
|
|
|
|
File sending appears split into upload plus file-message notification.
|
|
|
|
### Upload engine
|
|
|
|
`IMPP.ServiceBase.dll` defines `IFileTransfer`.
|
|
|
|
`IMPP.Service.dll` implements:
|
|
|
|
```text
|
|
IMPP.Service.BLL.FileTransfer.FileUpload(...)
|
|
IMPP.Service.BLL.FileTransfer.AsynFileUpload(...)
|
|
IMPP.Service.BLL.FileTransfer.FileDownload(...)
|
|
IMPP.Service.BLL.FileTransfer.SyncFileTransfer(...)
|
|
```
|
|
|
|
### Offline file send
|
|
|
|
`IMPlatformClient.exe` contains:
|
|
|
|
```text
|
|
IMPP.Client.OffLineFileSend.sendFile()
|
|
IMPP.Client.OffLineFileSend.trans_UploadCompleted(fileId)
|
|
```
|
|
|
|
Observed behavior:
|
|
|
|
- builds a generated file GUID;
|
|
- builds remote name as `filename____guid.ext`;
|
|
- uses `Config.ServerInfo.HTTPFileServer` and `FileTransferManager.GetDomain`;
|
|
- creates `FileUploadPara`;
|
|
- calls `IMPPManager.Instance.Service.FileTransfer.FileUpload(uploadPara)`;
|
|
- after upload completion, creates an `OFFLINE_FILE_TRANSFER;...` message body;
|
|
- calls `Chat.sendFileMessage(...)`;
|
|
- sets packet id to `fileId` and records metadata.
|
|
|
|
### Native TCP file transfer
|
|
|
|
`TcpFileTransfer.dll` is native and exposes strings/exports indicating:
|
|
|
|
```text
|
|
Send
|
|
SendFile
|
|
GetTcpFileMsgGuid
|
|
_StartWaitForSendFileThread@8
|
|
_StartRecvFileThread@24
|
|
```
|
|
|
|
This is a candidate for online/TCP file transfer, but the first B route should use the managed offline-file path because it is closer to the normal client business flow and already integrates upload metadata with XMPP file messages.
|
|
|
|
## Proposed sidecar architecture
|
|
|
|
```text
|
|
Go MCP Server
|
|
-> controlled action contract and audit
|
|
-> C# WinHelper / Sidecar command
|
|
-> B-route sidecar adapter
|
|
-> running IMPlatformClient context
|
|
-> existing AppContextManager / MessageScheduling / OffLineFileSend / smack.dll
|
|
```
|
|
|
|
The sidecar should be a narrow adapter, not a general-purpose remote code executor.
|
|
|
|
### Candidate sidecar operations
|
|
|
|
```text
|
|
version
|
|
self_check
|
|
probe_client_runtime
|
|
probe_send_entrypoints
|
|
resolve_runtime_jid
|
|
preview_send_message
|
|
send_message_after_approval
|
|
preview_send_file
|
|
send_file_after_approval
|
|
read_send_audit
|
|
```
|
|
|
|
The first implementation slice should stop before real production send:
|
|
|
|
```text
|
|
version
|
|
self_check
|
|
probe_client_runtime
|
|
probe_send_entrypoints
|
|
```
|
|
|
|
Then run a live sandbox observation before enabling `send_message_after_approval`.
|
|
|
|
## B-route validation gates
|
|
|
|
### Gate B1: runtime discovery
|
|
|
|
Pass condition:
|
|
|
|
- find a running `IMPlatformClient.exe` process;
|
|
- record PID, bitness, install path, module list summary;
|
|
- confirm the discovered path matches the extracted evidence family;
|
|
- confirm whether the sidecar must be x86 or x64.
|
|
|
|
Stop condition:
|
|
|
|
- no logged-in process;
|
|
- process bitness incompatible with available sidecar build;
|
|
- module names differ too much from the extracted package.
|
|
|
|
### Gate B2: entrypoint availability
|
|
|
|
Pass condition:
|
|
|
|
- confirm `IMPlatformClient.exe` exposes `AppContextManager` and `MessageScheduling` in the runtime module set;
|
|
- confirm `smack.dll` is loaded or loadable from the same install directory;
|
|
- confirm `IMPP.Interface.dll` and `IMPP.Service*.dll` are present.
|
|
|
|
Stop condition:
|
|
|
|
- app is not .NET Framework / cannot inspect CLR runtime safely;
|
|
- required assemblies are missing;
|
|
- only `SendP2PMessage` is available but `SendTxtMessageByJid`/`MessageScheduling` cannot be reached.
|
|
|
|
### Gate B3: non-mutating dynamic observation
|
|
|
|
Pass condition:
|
|
|
|
- during one operator-approved manual test send, observe the expected chain:
|
|
- `SendTxtMessageByJid` or UI send method;
|
|
- `MessageScheduling.SendChatMessage`;
|
|
- `Chat.SendMessage`;
|
|
- `XMPPConnection.send`;
|
|
- capture only redacted method names, argument shape, message id/hash, and success/ack indicator.
|
|
|
|
Stop condition:
|
|
|
|
- method chain differs from static evidence;
|
|
- no success/ack indicator can be mapped;
|
|
- message id/idempotency cannot be correlated.
|
|
|
|
### Gate B4: sidecar dry run
|
|
|
|
Pass condition:
|
|
|
|
- sidecar can resolve the target JID/chat type;
|
|
- sidecar can build a preview object without sending;
|
|
- preview contains target, content hash, connector, and proposed entrypoint;
|
|
- audit event is appended.
|
|
|
|
Stop condition:
|
|
|
|
- no deterministic target resolution;
|
|
- preview cannot distinguish direct vs group chat;
|
|
- no auditable dry-run object.
|
|
|
|
### Gate B5: one sandbox send
|
|
|
|
Pass condition:
|
|
|
|
- one explicit test target only;
|
|
- one idempotency key only;
|
|
- one message content hash only;
|
|
- success/ack or local sent-record evidence captured;
|
|
- duplicate retry with same idempotency key is rejected locally.
|
|
|
|
Stop condition:
|
|
|
|
- duplicate send risk;
|
|
- wrong target risk;
|
|
- no post-send verification.
|
|
|
|
## A-route fallback
|
|
|
|
A remains the backup route if B cannot be made reliable.
|
|
|
|
A should not be arbitrary desktop control. It should expose only:
|
|
|
|
```text
|
|
search_contact(query)
|
|
open_conversation(target)
|
|
write_draft(text)
|
|
verify_draft(target, text_hash)
|
|
send_after_approval(approval_id)
|
|
upload_file(path)
|
|
verify_send_result()
|
|
```
|
|
|
|
A-route fallback is activated when any of these happen:
|
|
|
|
- B cannot attach/probe safely;
|
|
- required runtime classes are unavailable in the logged-in process;
|
|
- B can observe but cannot invoke without unstable side effects;
|
|
- B cannot provide idempotency/audit guarantees;
|
|
- sidecar bitness/runtime mismatch is too costly to resolve in the current cycle.
|
|
|
|
## MCP contract impact
|
|
|
|
The MCP business tools should not expose B/A internals directly. They should keep the stable user-facing shape:
|
|
|
|
```text
|
|
isphere_send_message(target_type, target_id, content_text, mode, idempotency_key, content_sha256)
|
|
isphere_send_file(target_type, target_id, file_path, mode, idempotency_key, file_sha256)
|
|
```
|
|
|
|
Connector metadata should show the route:
|
|
|
|
```text
|
|
connector = "implatform-sidecar" | "uia-rpa"
|
|
connector_stage = "preview" | "sandbox_send" | "production"
|
|
```
|
|
|
|
## Next implementation loop
|
|
|
|
R5b/C30-live returned-probe intake is now complete. The live probe confirmed a running x86 `IMPlatformClient.exe` `4.1.2.6842`, installed B-route candidate DLLs, and A-route UIA controls, but it did not prove runtime send entrypoint reachability. It also observed an offline-send blocker in the captured chat windows.
|
|
|
|
Next node should be **R6a/C31 non-mutating send connector preflight**:
|
|
|
|
1. Use the C# WinHelper read-only op `probe_client_runtime`.
|
|
2. Add or run `probe_send_entrypoints` against copied/installed binaries to confirm `SendTxtMessageByJid`, `MessageScheduling.SendChatMessage`, `Chat.SendMessage`, and file-upload/file-message candidates by metadata only.
|
|
3. Add or run a UIA preflight classifier for `skinAlphaTxt`, `rtbSendMessage`, `btnSend`, `发送文件`, and offline-send message state.
|
|
4. Do not send, click, type, upload, attach hooks, or capture network traffic in this node.
|
|
5. Update `capability-source-matrix.md` after B2/A-route preflight passes or fails.
|
|
|
|
## Current status
|
|
|
|
B is selected as the primary send/file-send route. The first non-mutating runtime probe has now been run against a real logged-in environment through the returned live-probe package. B can continue only through non-mutating entrypoint confirmation; A remains the fallback and now has concrete UIA selector evidence, but production send remains blocked until dry-run/idempotency/audit and sandbox-send evidence exist.
|