/// <summary> /// Sends a command to the POP server. /// </summary> /// <param name="cmd">command to send to server</param> /// <returns>true if server responded "+OK"</returns> private PopCommandResponse SendCommand(string cmd) { PopCommandResponse response = PopCommandResponse.NullResponse; try { if (StreamWriter.BaseStream.CanWrite) { StreamWriter.WriteLine(cmd); StreamWriter.Flush(); response = PopCommandResponse.FromRawResponseString(StreamReader.ReadLine()); } } catch (Exception e) { if (e is IOException) { throw e; } else { string err = cmd + ":" + e.Message; Debug.WriteLine(e); throw new PopServerResponseErrException(err, e); } } return(response); }
/// <summary> /// Get the sizes of all the messages. /// </summary> /// <returns>Size of each message</returns> public IEnumerable <PopStat> List() { if (!Connected) { throw new InvalidOperationException("You must be connected."); } List <PopStat> sizes = null; PopCommandResponse response = SendCommand("LIST"); if (response.Success) { sizes = new List <PopStat>(); string line; while (null != (line = StreamReader.ReadLine()) && "." != line) { string[] s = line.Split(' '); if (s.Length > 1) { PopStat stat = new PopStat(); int.TryParse(s[0], out stat.MessageNumber); int.TryParse(s[1], out stat.Size); sizes.Add(stat); } } } return(new ReadOnlyCollection <PopStat>(sizes)); }
/// <summary> /// Get a list of message numbers with a unique identifier for each message number. /// </summary> public IEnumerable <PopUid> GetMessageUids() { if (!Connected) { throw new InvalidOperationException("You must be connected."); } List <PopUid> uids = new List <PopUid>(); PopCommandResponse response = SendCommand("UIDL"); if (response.Success) { string line; while (null != (line = StreamReader.ReadLine()) && "." != line) { string[] s = line.Split(' '); if (s.Length > 1) { PopUid uid = new PopUid(); int.TryParse(s[0], out uid.MessageNumber); uid.UniqueIdentifier = s[1]; uids.Add(uid); } } } return(new ReadOnlyCollection <PopUid>(uids)); }
/// <summary> /// Get max message number and mailbox size. /// </summary> /// <returns>PopStat object with the max message number and mailbox size.</returns> public PopStat SendStat() { PopCommandResponse response = SendCommand("STAT"); PopStat stat = new PopStat(); IList <int> v = response.IntValues(); if (v.Count > 1) { stat.MessageNumber = v[0]; stat.Size = v[1]; } return(stat); }
/// <summary> /// Get the size of a message /// </summary> /// <param name="intMessageNumber">message number</param> /// <returns>Size of message</returns> public PopStat List(int intMessageNumber) { if (!Connected) { throw new InvalidOperationException("You must be connected."); } PopCommandResponse response = SendCommand("LIST " + intMessageNumber.ToString()); PopStat stat = new PopStat(); IList <int> v = response.IntValues(); stat.MessageNumber = v[0]; stat.Size = v[1]; return(stat); }
/// <summary> /// Authenticate the user with APOP /// </summary> /// <param name="username">user name</param> /// <param name="password">password</param> private void SendApop(string username, string password) { PopCommandResponse response = SendCommand("APOP " + username + " " + ComputeHashAsHexString(password)); if (!response.Success) { if (Regex.IsMatch(response.RawValue, "lock", RegexOptions.IgnoreCase)) { throw new MailboxLockedException("Mailbox locked by another client. Try again later.", response.ToException()); } else { throw new PopAuthenticationException("APOP Authentication: " + response.RawValue, response.ToException()); } } }
/// <summary> /// Get unique identifier for the given message number. /// </summary> /// <param name="intMessageNumber">message number</param> public PopUid GetMessageUid(int intMessageNumber) { if (!Connected) { throw new InvalidOperationException("You must be connected."); } PopCommandResponse response = SendCommand("UIDL " + intMessageNumber.ToString()); if (response.Success) { if (response.Parameters.Count > 1) { PopUid uid = new PopUid(); int.TryParse(response.Parameters[0], out uid.MessageNumber); uid.UniqueIdentifier = response.Parameters[1]; } } throw new InvalidDataException("Server responded with invalid data: " + response.RawValue); }
/// <summary> /// Get the capabilities of the server. /// </summary> /// <returns></returns> public IEnumerable <string> Capabilities() { if (!Connected) { throw new InvalidOperationException("You must be connected."); } List <string> caps = new List <string>(); PopCommandResponse response = SendCommand("CAPA"); if (response.Success) { string line; while (null != (line = StreamReader.ReadLine()) && "." != line) { caps.Add(line); } } return(new ReadOnlyCollection <string>(caps)); }
/// <summary> /// fetches a message or a message header /// </summary> /// <param name="messageNumber">message number on the server</param> /// <param name="fetchHeaderOnly">Only return message header?</param> /// <returns>Stream of mime-encoded text data. Returns null of the command failed.</returns> private TextReader GetMessageReader(int messageNumber, bool fetchHeaderOnly) { string cmd; if (fetchHeaderOnly) { cmd = string.Format("TOP {0} 0", messageNumber.ToString()); } else { cmd = string.Format("RETR {0}", messageNumber.ToString()); } PopCommandResponse response = SendCommand(cmd); if (!response.Success) { response.Throw(); } return(StreamReader); }
/// <summary> /// Authenticate the user with USER/PASS /// </summary> /// <param name="username">user name</param> /// <param name="password">password</param> private void SendUserPass(string username, string password) { PopCommandResponse response = SendCommand("USER " + username); if (!response.Success) { throw new PopAuthenticationException("USER/PASS Authentication: " + response.RawValue, response.ToException()); } response = SendCommand("PASS " + password); if (!response.Success) { if (Regex.IsMatch(response.RawValue, "lock", RegexOptions.IgnoreCase)) { throw new MailboxLockedException("Mailbox locked by another client. Try again later.", response.ToException()); } else { throw new PopAuthenticationException("USER/PASS Authentication: " + response.RawValue, response.ToException()); } } }
static PopCommandResponse() { NullResponse = new PopCommandResponse( null ); }
static PopCommandResponse() { NullResponse = new PopCommandResponse(null); }
/// <summary> /// Connect to the server. Requires that the Port and Host properties be set. /// </summary> public void Connect() { if (Connected) { throw new InvalidOperationException("PopClient is already connected."); } if (Host == null || Host == default(string)) { throw new InvalidOperationException("The Host property must be set."); } string host = Host; int port = Port; SslProtocols sslProtocol = SslProtocol; ClientSocket.Connect(host, port); Stream stream = ClientSocket.GetStream(); if (SslProtocols.None != sslProtocol) { if (SslNegotiationMode.Connect == SslNegotiationMode) { //Implements POP3S capability for SSL/TLS connections on an alternate port. //For POPS/Connect, we negotiate an SslStream immediately. stream = NegotiateSslStream(host, sslProtocol, stream); } else { //UNDONE: test STARTTLS. (Need an account on a compatible server.) //For STLS, we have to start out with plain text and then issue the STLS command and if the server says +OK //we can negotiate TLS. Have to do this without using a StreamReader or StreamWriter because we need to change //the stream from a NetworkStream to an SslStream. The stream inside of a StreamReader and StreamWriter can't //be changed and closing the StreamReader or StreamWriter will close the stream upon which the SslStream is based. string response; try { //don't close or dispose these StreamReader and StreamWriter objects of the stream will be closed. StreamWriter writer = new StreamWriter(stream); StreamReader reader = new StreamReader(stream); writer.WriteLine("STLS"); response = reader.ReadLine(); } catch (Exception ex) { if (null != stream) { try{ stream.Dispose(); } catch (ObjectDisposedException) {} } this.Disconnect(); throw new StartTlsNegotiationException("STARTTLS negotiation failed. Consider using SslNegotiationMode.Connect.", ex); } if (PopCommandResponse.IsResponseSuccess(response)) { stream = NegotiateSslStream(host, sslProtocol, stream); } else { if (null != stream) { try{ stream.Dispose(); } catch (ObjectDisposedException) {} } this.Disconnect(); throw new StartTlsNegotiationException(response); } } } StreamReader = new StreamReader(stream, Encoding.Default, true); StreamWriter = new StreamWriter(stream); StreamWriter.AutoFlush = true; PopCommandResponse popresponse = PopCommandResponse.FromRawResponseString(StreamReader.ReadLine()); if (popresponse.Success) { Match match = Regex.Match(popresponse.RawValue, @"^\+OK\s.+(<.+>$)"); if (match.Success) { ApopTimestamp = match.Groups[1].Value; } } else { this.Disconnect(); popresponse.ToException(); } }