C# 带有特殊字符的C Imap排序命令

C# 带有特殊字符的C Imap排序命令,c#,sorting,imap,mailsystem.net,C#,Sorting,Imap,Mailsystem.net,我正在处理imap排序扩展的一个问题: 我的命令如下: var query = "icône"; //byte[] bytes = Encoding.Default.GetBytes(query); //query = Encoding.UTF8.GetString(bytes); var command = "SORT (REVERSE ARRIVAL) UTF-8 " + "{" + query.Length +

我正在处理imap排序扩展的一个问题:

我的命令如下:

  var query = "icône";
            //byte[] bytes = Encoding.Default.GetBytes(query);
            //query = Encoding.UTF8.GetString(bytes);

            var command = "SORT (REVERSE ARRIVAL) UTF-8 " + "{" + query.Length + "}";
            var imapAnswerString = client.Command(command);
            imapAnswerString = client.Command(query);
我得到以下错误: IMAP命令排序错误:atom中的8位数据

我发现:


但我不知道如何准备代码来成功发送此请求。

您就快到了。您的最终命令应该是

x sort (reverse arrival) utf-8 subject {6+}
icône
也就是说,您只是缺少一个搜索词来描述IMAP服务器应该在哪里搜索icône并对结果进行排序。还有许多其他的搜索键,不仅仅是主题。请参阅RFC3501第49页和后续页面

Edit:6后面需要+以作为单个命令发送,但要求服务器支持LITERAL+扩展名。如果服务器不支持LITERAL+,则需要将命令分成多个段,如下所示:

C: a001 SORT (REVERSE ARRIVAL) UTF-8 SUBJECT {6}
S: + ok, whenever you are ready...
C: icône
S: ... <response goes here>

如果您想继续使用MailSystem.NET,arnt给出的答案是正确的

然而,正如我在下面为方便起见指出的,MailSystem.NET存在许多架构设计问题,使其无法使用

如果您使用另一种开源库,例如,您将更轻松地完成此搜索查询:

var query = SearchQuery.BodyContains ("icône");
var orderBy = new OrderBy[] { OrderBy.ReverseArrival };
var results = folder.Search (query, orderBy);
希望有帮助

MailSystem.NET中的体系结构问题包括:

MailSystem.NET无法正确处理文字标记-发送文字标记的目的不是追加,接收文字标记的目的不是获取请求中的实际消息数据。似乎没有一位作者注意到,服务器可能会选择对任何字符串响应使用文本

这是什么意思

这意味着服务器可以选择使用文本作为邮箱名称响应列表命令

这意味着BODYSTRUCTURE中的任何字段都可以是文本,而不必像它们假设的那样是带引号的字符串

还有更多

例如,MailSystem.NET也没有正确编码或引用邮箱名称:

MailSystem.NET中的示例:

public string RenameMailbox(string oldMailboxName, string newMailboxName)
{
    string response = this.Command("rename \"" + oldMailboxName + "\" \"" + newMailboxName + "\"");
    return response;
}
这值得让-吕克·皮卡德和威尔·莱克当面称赞。这段代码只是盲目地在邮箱名称周围加上双引号。这是错误的,至少有两个原因:

如果邮箱名称有双引号或反斜杠怎么办?它需要用“的”逃离他们。 如果mailboxName具有非ASCII字符或&,该怎么办?它需要使用UTF-7字符编码的修改版本对名称进行编码。 最重要的是?在.NETIMAP客户机中,我可以找到将整个响应从服务器读取为一个大字符串,然后尝试使用regex、IndexOf和Substring的组合来解析响应。更糟糕的是,大多数代码都是由开发人员编写的,他们不知道unicode字符计数(即string.Length)和八位字节计数(即字节计数)之间的区别,因此当他们试图解析对消息提取请求的响应时,他们会在解析响应第一行中的{}值后执行此操作:

int startIndex = response.IndexOf ("}") + 3;
int endIndex = startIndex + octets;

string msg = response.Substring (startIndex, endIndex - startIndex);
MailSystem.NET开发人员显然收到了关于这不适用于国际邮件的错误报告,因此他们的解决方案是:

public string Body(int messageOrdinal)
{
    this.ParentMailbox.SourceClient.SelectMailbox(this.ParentMailbox.Name);

    string response = this.ParentMailbox.SourceClient.Command("fetch "+messageOrdinal.ToString()+" body", getFetchOptions());
    return response.Substring(response.IndexOf("}")+3,response.LastIndexOf(" UID")-response.IndexOf("}")-7);
}
本质上,他们假设UID密钥/值对将出现在消息后面,并以此作为对他们无能的攻击。不幸的是,在现有的不称职的基础上增加更多的不称职只会增加不称职的程度,实际上并不能解决这个问题

IMAP规范特别指出,结果的顺序可能会有所不同,甚至可能不在相同的未标记响应中

不仅如此,他们的FETCH请求甚至都不会从服务器请求UID值,因此是否返回UID值取决于服务器

TL;博士

如何评估IMAP客户端库

在评估IMAP客户端库实现时,您应该做的第一件事是查看它们如何解析响应。如果他们不使用实际的标记器,你可以马上判断出这个库是由不知道他们在做什么的人编写的。这是远离火灾的最可靠的警告标志

库是否在中心位置(例如命令管道)处理未标记的*响应?或者它是否做了一些延迟的事情,比如尝试在每个发送命令的方法中解析它,例如ImapClient.SelectFolder、ImapClient.FetchMessage等?如果库没有在一个中心位置处理它,该位置可以正确处理这些未标记的响应和更新状态,并通知您一些重要的事情,如删除,请远离

如果库将整个响应甚至只是消息读入System.String,请远离


谢谢大家的回答

基本上,MailSystem.net发送请求的方式命令方法是这个问题的症结所在,实际上还有一些问题

命令方法应更正如下:

if (temp.StartsWith(stamp) || temp.ToLower().StartsWith("* " + command.Split(' ')[0].ToLower()) || (temp.StartsWith("+ ") && options.IsPlusCmdAllowed) || temp.Contains("BAD Error in IMAP command"))
                    {
                        lastline = temp;
                        break;
                    }
首先,向imap发送请求时,以下代码比原始代码工作得更好:

 //Convert stuff to have to right encoding in a char array
            var myCommand = stamp + ((stamp.Length > 0) ? " " : "") + command + "\r\n";
            var bytesUtf8 = Encoding.UTF8.GetBytes(myCommand);
            var commandCharArray = Encoding.UTF8.GetString(bytesUtf8).ToCharArray();

#if !PocketPC
            if (this._sslStream != null)
            {


                this._sslStream.Write(System.Text.Encoding.UTF8.GetBytes(commandCharArray));
            }
            else
            {
                base.GetStream().Write(System.Text.Encoding.UTF8.GetBytes(commandCharArray), 0, commandCharArray.Length);
            }
#endif

#if PocketPC
                        base.GetStream().Write(System.Text.Encoding.UTF8.GetBytes(commandCharArray), 0, commandCharArray.Length);
#endif
然后,用同样的方法,避免 一些死锁或错误异常,改进有效性测试如下:

if (temp.StartsWith(stamp) || temp.ToLower().StartsWith("* " + command.Split(' ')[0].ToLower()) || (temp.StartsWith("+ ") && options.IsPlusCmdAllowed) || temp.Contains("BAD Error in IMAP command"))
                    {
                        lastline = temp;
                        break;
                    }
最后,如果如下所示,则更新报税表:

if (lastline.StartsWith(stamp + " OK") || temp.ToLower().StartsWith("* " + command.Split(' ')[0].ToLower()) && !options.IsSecondCallCommand || temp.ToLower().StartsWith("* ") && options.IsSecondCallCommand && !temp.Contains("BAD") || temp.StartsWith("+ "))
                return bufferString;
通过此更改,所有命令都可以正常工作,也可以双击命令。与原始代码相比,副作用更少


这解决了我的大部分问题

最后,命令在网络上按如下方式发送:his.\u sslStream.WriteSystem.Text.Encoding.UTF8.GetBytesstamp+stamp.Length>0?:+command+\r\n\r\n,0,stamp.Length+stamp.Length>0?1:0+命令。长度+2;我一直看到你在IMAP标签下贴出很好的答案,最后才知道你是谁。我非常喜欢你对我在MailKit中实现的许多IMAP规范的贡献,尤其是移动扩展。我不能更改库。。。其他力量也在游戏中。不管怎样,我同意jstedfast的观点,这个库可以玩,而不是更多。我不是imap库的专家,但在命令处理方面还有很多错误。我必须快速解决这个问题,老实说,我会建议使用其他库。也许像jstedfast这样的专家的公开评估将是一个好主意!请注意,在发送第二个命令的内容之前,在第一个命令中使用字符计数时,此更改可能会影响其他方法。计数字符和utf8字节数组不相等。