问题描述
我正在使用本机消息传递(following the ping pong example in python)在Thunderbird中编写一个插件,以调用Delphi程序,以“ .eml”文件的形式在本地复制电子邮件。我面临的问题似乎是编码。另外,生成的文件在文件的开头和结尾都包含双引号(“”)以及转义的双引号(\“)。我只想拥有1对1的副本,而不希望更改其内容。
"test"
€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ
éöàäèüâêû
但是,在文件中,它看起来更像这样:
\"test\"
€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“â€â€¢â€“—˜™š›œžŸ
éöà äèüâêû
我可能已经找到问题了,在这里进行解释:
https://www.i18nqa.com/debug/utf8-debug.html
谢谢您的帮助!
这是我的background.js:
async function main() {
messenger.menus.create({
contexts : ["message_list"],id: "copy@mail.lu",onclick : passMsg,title: messenger.i18n.getMessage("lang.menuTitle")
});
}
async function passMsg(OnClickData) {
if (OnClickData.selectedMessages && OnClickData.selectedMessages.messages.length > 0) {
let MessageHeader = OnClickData.selectedMessages.messages[0];
let raw = await messenger.messages.getRaw(MessageHeader.id);
let port=browser.runtime.connectNative("copymail");
port.onMessage.addListener((message) => {
port.disconnect();
});
port.postMessage(raw);
} else {
console.log("No message selected");
}
}
main();
这是我的Delphi代码:
procedure WriteSTDInputToFile(const Filename: String);
var
Buffer: array [0 .. 3] of Byte;
msgLen: LongInt;
msg: UTF8String;
myFile: TextFile;
StdIn: THandleStream;
jsonValue: TJSONValue;
begin
StdIn := THandleStream.Create(GetStdHandle(STD_INPUT_HANDLE));
try
msgLen := 0;
if StdIn.Read(Buffer,SizeOf(msgLen)) > 0 then
msgLen := PLongInt(@Buffer)^;
if msgLen > 0 then
begin
SetLength(msg,msgLen);
StdIn.Read(PUTF8Char(msg)^,msgLen);
if msg <> '' then
begin
AssignFile(myFile,Filename,CP_UTF8);
ReWrite(myFile);
jsonValue := TJSONObject.ParseJSONValue(msg);
try
write(myFile,UTF8Encode(jsonValue.ToString));
finally
jsonValue.Free;
end;
CloseFile(myFile);
end;
end;
finally
if Assigned(StdIn) then
StdIn.Free;
end;
end;
"X-MDAV-Result: clean
X-MDAV-Processed: mail.test.lu,Wed,28 Oct 2020 08:13:22 +0100
X-Spam-Processed: mail.test.lu,28 Oct 2020 08:13:22 +0100
Return-path: <copy@mail.lu>
X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on MAIL01E
X-Spam-Level:
X-Spam-Status: No,score=0.7 required=10.0 tests=HTML_MESSAGE,MPART_ALT_DIFF
shortcircuit=no autolearn=disabled version=3.4.2
Authentication-Results: test.lu;
auth=pass (plain) smtp.auth=ascholtes@test.lu
Received: from [172.16.17.35] [(172.16.17.35)] by test.lu (172.31.3.6) with ESMTPSA id md50033234892.msg;
Wed,28 Oct 2020 08:13:21 +0100
X-MDRemoteIP: 172.16.17.35
X-MDArrival-Date: Wed,28 Oct 2020 08:13:21 +0100
X-Authenticated-Sender: ascholtes@test.lu
X-Rcpt-To: copy@mail.lu
X-MDRcpt-To: copy@mail.lu
X-Return-Path: copy@mail.lu
X-Envelope-From: copy@mail.lu
X-MDaemon-Deliver-To: ascholtes@test.lu
To: Ayuth Scholtes <copy@mail.lu>
From: Ayuth Scholtes <copy@mail.lu>
Subject: Test
Organization: CISS
Message-ID: <7eb36f7c-a7af-c272-c189-eded642c3e1c@test.lu>
Date: Wed,28 Oct 2020 08:13:21 +0100
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101
Thunderbird/68.10.0
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary=\"------------6068A746223BB2C9F1771938\"
Content-Language: lb-LU
This is a multi-part message in MIME format.
--------------6068A746223BB2C9F1771938
Content-Type: text/plain; charset=utf-8; format=flowed
Content-transfer-encoding: 8bit
|\"test\" â¬âÆââ¦â â¡Ëâ°Å â¹ÅŽâââââ¢ââËâ¢Å¡âºÅžŸ éöà äèüâêû|
--------------6068A746223BB2C9F1771938
Content-Type: text/html; charset=utf-8
Content-transfer-encoding: 8bit
<html>
<head>
<Meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">
</head>
<body>
<pre class=\"lang-pascal s-code-block hljs delphi\"><code>\"test\"
â¬âÆââ¦â â¡Ëâ°Å â¹ÅŽâââââ¢ââËâ¢Å¡âºÅžŸ
éöà äèüâêû</code></pre>
</body>
</html>
--------------6068A746223BB2C9F1771938--
"
解决方法
首先让我说,您在使用native messaging在Web扩展(Thunderbird附加组件)和本机应用程序之间传输数据方面做得很好。理解并设置它并不容易,但是您设法通过在问题中描述的一些小故障来传输所需的数据。
...生成的文件在文件的开头和结尾都包含双引号(
"
)以及转义的双引号(\"
)
在附加组件中,您将以字符串的形式获取原始电子邮件数据-console.log(typeof raw)
给出string
,然后将其传递给port.postMessage
。尽管文档说需要 JSON对象表示要发送的消息,但是根据某些标准,它似乎接受valid JSON的单个字符串值。在Delphi代码中,您通过STDIN
接收消息,并使用TJSONObject.ParseJSONValue
解析为TJSONValue
。实际上,它将创建TJSONString
的实例。您可以通过检查jsonValue.ClassName
的值来验证。当您使用jsonValue.ToString
时返回引号的问题,该返回的字符串的引号版本与解析前的字符串基本相同。使用Value
属性返回原始字符串值。
仅使用jsonValue.Value
不会帮助您解决编码问题。您从电子邮件客户端获得的原始消息数据在EML format中。它符合RFC-822,这意味着它是ASCII编码的,但是可以包含任意编码的消息部分(请参阅您自己的示例EML)。由于您只想保存EML文件而不考虑任何编码,因此最好的方法是传输EML的原始字节,但这并不是Javascript和本机消息传递API的即开即用功能。因此,我建议您将Base64编码的数据字符串发送到本机应用程序,在该应用程序中将其解码为可直接写入磁盘的原始字节。
要在附加使用功能btoa中将原始消息数据编码为Base64字符串:
port.postMessage(btoa(raw));
要在本机应用程序中接收消息,您可以执行以下操作:
uses
System.SysUtils,System.Classes,System.IOUtils,System.JSON,System.NetEncoding,Winapi.Windows;
procedure WriteSTDInputToFile(const FileName: string);
var
StdIn: THandleStream;
MsgLen: Cardinal;
Data: TBytes;
JSONValue: TJSONValue;
begin
StdIn := THandleStream.Create(GetStdHandle(STD_INPUT_HANDLE));
try
StdIn.ReadBuffer(MsgLen,SizeOf(MsgLen));
SetLength(Data,MsgLen);
StdIn.ReadBuffer(Data,MsgLen);
JSONValue := TJSONObject.ParseJSONValue(Data,0);
Data := TNetEncoding.Base64.DecodeStringToBytes(JSONValue.Value);
TFile.WriteAllBytes(FileName,Data);
finally
StdIn.Free;
end;
end;
请注意原始代码的一些改进:
-
Cardinal
使用MsgLen
类型。该协议定义输入的前4个字节以32位无符号整数表示消息长度。Cardinal
是Delphi的此类值的本机类型,或者您也可以使用UInt32
别名。 - 我使用
ReadBuffer
方法而不是Read
来读取STDIN,这会使程序在某些意外情况下崩溃。理想情况下,您应该处理此类情况,通过STDOUT发送错误消息作为响应,并在附加组件中处理响应。 - 我不会将传统的I / O例程与流混合使用。我什至没有使用流来写入代码中的输出文件。多谢
File.WriteAllBytes
的{{1}}来创建文件。 - 我没有选中
Syste.IOUtils
。这就是if Assigned(StdIn) then StdIn.Free;
已经为您服务的事情。
知道传入消息是带引号的Base64编码的字符串,因此可以省去JSON处理,从而使代码变为:
Free