DeleteMessagepublicvoid DeleteMessage(int messageNumber)
{
AssertDisposed();
ValidateMessageNumber(messageNumber);
if (State != ConnectionState.Transaction)
thrownew InvalidUseException("You cannot delete any messages without authenticating yourself towards the server first");
SendCommand("DELE " + messageNumber);
}
最后一行SendCommand需要提交一个DELE命令,跟进去看看它是怎么实现的:
SendCommandprivatevoid SendCommand(string command)
{
// Convert the command with CRLF afterwards as per RFC to a byte array which we can writebyte[] commandBytes = Encoding.ASCII.GetBytes(command + "\r\n");
// Write the command to the server
OutputStream.Write(commandBytes, 0, commandBytes.Length);
OutputStream.Flush(); // Flush the content as we now wait for a response// Read the response from the server. The response should be in ASCII
LastServerResponse = StreamUtility.ReadLineAsAscii(InputStream);
IsOkResponse(LastServerResponse);
}
Private Property/// <summary>/// This is the stream used to read off the server response to a command/// </summary>private Stream InputStream { get; set; }
/// <summary>/// This is the stream used to write commands to the server/// </summary>private Stream OutputStream { get; set; }
给它赋值的地方是调用Pop3Client类里的 public void Connect(Stream inputStream, Stream outputStream)方法,而这个Connect方法最终调用的Connect方法如下:
Connect/// <summary>/// Connects to a remote POP3 server/// </summary>/// <param name="hostname">The <paramref name="hostname"/> of the POP3 server</param>/// <param name="port">The port of the POP3 server</param>/// <param name="useSsl">True if SSL should be used. False if plain TCP should be used.</param>/// <param name="receiveTimeout">Timeout in milliseconds before a socket should time out from reading. Set to 0 or -1 to specify infinite timeout.</param>/// <param name="sendTimeout">Timeout in milliseconds before a socket should time out from sending. Set to 0 or -1 to specify infinite timeout.</param>/// <param name="certificateValidator">If you want to validate the certificate in a SSL connection, pass a reference to your validator. Supply <see langword="null"/> if default should be used.</param>/// <exception cref="PopServerNotAvailableException">If the server did not send an OK message when a connection was established</exception>/// <exception cref="PopServerNotFoundException">If it was not possible to connect to the server</exception>/// <exception cref="ArgumentNullException">If <paramref name="hostname"/> is <see langword="null"/></exception>/// <exception cref="ArgumentOutOfRangeException">If port is not in the range [<see cref="IPEndPoint.MinPort"/>, <see cref="IPEndPoint.MaxPort"/> or if any of the timeouts is less than -1.</exception>publicvoid Connect(string hostname, int port, bool useSsl, int receiveTimeout, int sendTimeout, RemoteCertificateValidationCallback certificateValidator)
{
AssertDisposed();
if (hostname == null)
thrownew ArgumentNullException("hostname");
if (hostname.Length == 0)
thrownew ArgumentException("hostname cannot be empty", "hostname");
if (port > IPEndPoint.MaxPort || port < IPEndPoint.MinPort)
thrownew ArgumentOutOfRangeException("port");
if (receiveTimeout < -1)
thrownew ArgumentOutOfRangeException("receiveTimeout");
if (sendTimeout < -1)
thrownew ArgumentOutOfRangeException("sendTimeout");
if (State != ConnectionState.Disconnected)
thrownew InvalidUseException("You cannot ask to connect to a POP3 server, when we are already connected to one. Disconnect first.");
TcpClient clientSocket = new TcpClient();
clientSocket.ReceiveTimeout = receiveTimeout;
clientSocket.SendTimeout = sendTimeout;
try
{
clientSocket.Connect(hostname, port);
}
catch (SocketException e)
{
// Close the socket - we are not connected, so no need to close stream underneath
clientSocket.Close();
DefaultLogger.Log.LogError("Connect(): " + e.Message);
thrownew PopServerNotFoundException("Server not found", e);
}
Stream stream;
if (useSsl)
{
// If we want to use SSL, open a new SSLStream on top of the open TCP stream.// We also want to close the TCP stream when the SSL stream is closed// If a validator was passed to us, use it.
SslStream sslStream;
if (certificateValidator == null)
{
sslStream = new SslStream(clientSocket.GetStream(), false);
}
else
{
sslStream = new SslStream(clientSocket.GetStream(), false, certificateValidator);
}
sslStream.ReadTimeout = receiveTimeout;
sslStream.WriteTimeout = sendTimeout;
// Authenticate the server
sslStream.AuthenticateAsClient(hostname);
stream = sslStream;
}
else
{
// If we do not want to use SSL, use plain TCP
stream = clientSocket.GetStream();
}
// Now do the connect with the same stream being used to read and write to
Connect(stream, stream); //In/OutputStream属性初始化
}
GetMessagepublic Message GetMessage(int messageNumber)
{
AssertDisposed();
ValidateMessageNumber(messageNumber);
if (State != ConnectionState.Transaction)
thrownew InvalidUseException("Cannot fetch a message, when the user has not been authenticated yet");
byte[] messageContent = GetMessageAsBytes(messageNumber);
returnnew Message(messageContent);
}
内部的GetMessageAsBytes方法最终果然还是走SendCommand方法:
GetMessageif (askOnlyForHeaders)
{
// 0 is the number of lines of the message body to fetch, therefore it is set to zero to fetch only headers
SendCommand("TOP " + messageNumber + " 0");
}
else
{
// Ask for the full message
SendCommand("RETR " + messageNumber);
}
根据我的跟踪,在测试中抛出异常的乱码来自于LastServerResponse(This is the last response the server sent back when a command was issued to it),在IsOKResponse方法中它不是以“+OK”开头就会抛出PopServerException异常:
IsOkResponse/// <summary>/// Tests a string to see if it is a "+OK" string.<br/>/// An "+OK" string should be returned by a compliant POP3/// server if the request could be served.<br/>/// <br/>/// The method does only check if it starts with "+OK"./// </summary>/// <param name="response">The string to examine</param>/// <exception cref="PopServerException">Thrown if server did not respond with "+OK" message</exception>privatestaticvoid IsOkResponse(string response)
{
if (response == null)
thrownew PopServerException("The stream used to retrieve responses from was closed");
if (response.StartsWith("+OK", StringComparison.OrdinalIgnoreCase))
return;
thrownew PopServerException("The server did not respond with a +OK response. The response was: \"" + response + "\"");
}
Message.SaveToFile/// <summary>/// Save this <see cref="Message"/> to a file.<br/>/// <br/>/// Can be loaded at a later time using the <see cref="LoadFromFile"/> method./// </summary>/// <param name="file">The File location to save the <see cref="Message"/> to. Existent files will be overwritten.</param>/// <exception cref="ArgumentNullException">If <paramref name="file"/> is <see langword="null"/></exception>/// <exception>Other exceptions relevant to file saving might be thrown as well</exception>publicvoid SaveToFile(FileInfo file)
{
if (file == null)
thrownew ArgumentNullException("file");
File.WriteAllBytes(file.FullName, RawMessage);
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步