如何从 Indy 中的 SendCmd 获得可解析的响应?

How to get a parsable response from SendCmd in Indy?

如果我使用 TIdImap4.SendCmd 手动向 Indy 发送不受支持的命令,我有点困惑如何检索完整响应以手动解析它。

我正在发送以下命令来手动请求邮件的 Gmail 标签,因为这是 :

  IMAP.SendCmd(ImapCmdNum(),'UID FETCH '+uid+' (X-GM-LABELS)',['OK','BAD','NO'], false);

调用此命令后,我检查了我的 Indy 日志文件,它成功地从服务器接收到适当的响应:

Sent 9/19/2015 11:10:40 AM: C5 UID FETCH 2385 (X-GM-LABELS)<EOL>
Recv 9/19/2015 11:10:40 AM: * 542 FETCH (X-GM-LABELS (testlabel) UID 2385)<EOL>C5 OK Success<EOL>

但现在除了 'OK' 来自 Indy 之外,我似乎无法获得该响应的任何部分。我在调试器中尝试了以下内容,其中 none 具有原始响应或其他任何我可能手动解析的内容:

IMAP.LastCmdResult = ('OK', 21E60, nil, 21EC0)
IMAP.LastCmdResult.Text = ()
IMAP.LastCmdResult.Code = 'OK'
IMAP.LastCmdResult.NumericCode = 0
IMAP.LastCmdResult.FormattedReply = ()

来自 SendCmd 文档:

SendCmd is an overloaded function used to send the command specified in AOut to the peer connection.

SendCmd uses IOHandler to write the command in AOut to the peer connection.

AResponse indicates the response allowed for the command.

SendCmd calls GetResponse to determine if the response from the peer connection is allowed. If the response is not allowed, an exception is raised during processing in GetResponse.

When AResponse is contains -1, GetResponse is called with an empty array to indicate that any response code is permitted for the command. Otherwise, the value in AResponse is used to valid the response code.

Use LastCmdResult to access the numeric and text portions of the response for the command.

我对此的理解是,我应该使用 LastCmdResult 访问各种 "portions of the response",但其中 none 具有原始响应或响应的任何部分,但 "OK" 除外,那么如何从对 SendCmd 的响应中获取可解析的内容?

您要查找的文字实际上在 LastCmdResult.Text 属性 中。调试器没有向您显示它,但这是标签数据所在的位置。

正如我 2 个月前在对 的评论中告诉您的那样,您链接到:

Look at the implementation of TIdIMAP4.UIDRetrieveFlags(). It calls SendCmd() followed by ParseLastCmdResult() to parse the returned flags. You will have to replicate the same logic, substituting fdGmailLabels where fdFlags is currently being used (minus the call to ParseMessageFlagString() that is parsing the flags string to a TIdMessageFlagsSet).

如果您查看 TIdIMAP4.UIDRetrieveFlags() 的实现,然后查看您的代码,您甚至没有正确地开始调用 SendCmd()。您将错误的值传递给 ATag 参数(unless ImapCmdNum() 只是调用 TIdIMAP4.NewCmdCounter - TIdIMAP4 需要生成命令计数器以便将它们与回复相匹配),重要的是,您将错误的值传递给 AExpectedResponses 参数。

试试这个(我测试过它并且有效):

type
  TIdIMAP4Access = class(TIdIMAP4);
  TIdIMAPLineStructAccess = class(TIdIMAPLineStruct);

var
  uid: string;
  labels: string;
begin
  ...
  uid := ...;
  labels := '';
  IMAP.SendCmd('UID FETCH ' + uid + ' (X-GM-LABELS)', ['FETCH','UID']);
  if IMAP.LastCmdResult.Code = IMAP_OK then
  begin
    if IMAP.LastCmdResult.Text.Count > 0 then
    begin
      // The requested data is in IMAP.LastCmdResult.Text[0].

      // You can either parse it manually, or use the below
      // code to let TIdIMAP4 parse it for you...

      if TIdIMAP4Access(IMAP).ParseLastCmdResult(IMAP.LastCmdResult.Text[0], 'FETCH', ['X-GM-LABELS']) then begin
        labels := TIdIMAPLineStructAccess(TIdIMAP4Access(IMAP).FLineStruct).IMAPValue;
      end;
    end;
  end;
  ...
end;