namespace Swan.Net.Smtp
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
///
/// Represents an SMTP server response object.
///
public class SmtpServerReply
{
#region Constructors
///
/// Initializes a new instance of the class.
///
/// The response code.
/// The status code.
/// The content.
public SmtpServerReply(int responseCode, string statusCode, params string[] content)
{
Content = new List();
ReplyCode = responseCode;
EnhancedStatusCode = statusCode;
Content.AddRange(content);
IsValid = responseCode >= 200 && responseCode < 600;
ReplyCodeSeverity = SmtpReplyCodeSeverities.Unknown;
ReplyCodeCategory = SmtpReplyCodeCategories.Unknown;
if (!IsValid) return;
if (responseCode >= 200) ReplyCodeSeverity = SmtpReplyCodeSeverities.PositiveCompletion;
if (responseCode >= 300) ReplyCodeSeverity = SmtpReplyCodeSeverities.PositiveIntermediate;
if (responseCode >= 400) ReplyCodeSeverity = SmtpReplyCodeSeverities.TransientNegative;
if (responseCode >= 500) ReplyCodeSeverity = SmtpReplyCodeSeverities.PermanentNegative;
if (responseCode >= 600) ReplyCodeSeverity = SmtpReplyCodeSeverities.Unknown;
if (int.TryParse(responseCode.ToString(CultureInfo.InvariantCulture).Substring(1, 1), out var middleDigit))
{
if (middleDigit >= 0 && middleDigit <= 5)
ReplyCodeCategory = (SmtpReplyCodeCategories) middleDigit;
}
}
///
/// Initializes a new instance of the class.
///
public SmtpServerReply()
: this(0, string.Empty, string.Empty)
{
// placeholder
}
///
/// Initializes a new instance of the class.
///
/// The response code.
/// The status code.
/// The content.
public SmtpServerReply(int responseCode, string statusCode, string content)
: this(responseCode, statusCode, new[] {content})
{
}
///
/// Initializes a new instance of the class.
///
/// The response code.
/// The content.
public SmtpServerReply(int responseCode, string content)
: this(responseCode, string.Empty, content)
{
}
#endregion
#region Pre-built responses (https://tools.ietf.org/html/rfc5321#section-4.2.2)
///
/// Gets the command unrecognized reply.
///
public static SmtpServerReply CommandUnrecognized =>
new SmtpServerReply(500, "Syntax error, command unrecognized");
///
/// Gets the syntax error arguments reply.
///
public static SmtpServerReply SyntaxErrorArguments =>
new SmtpServerReply(501, "Syntax error in parameters or arguments");
///
/// Gets the command not implemented reply.
///
public static SmtpServerReply CommandNotImplemented => new SmtpServerReply(502, "Command not implemented");
///
/// Gets the bad sequence of commands reply.
///
public static SmtpServerReply BadSequenceOfCommands => new SmtpServerReply(503, "Bad sequence of commands");
///
/// Gets the protocol violation reply.
/// =
public static SmtpServerReply ProtocolViolation =>
new SmtpServerReply(451, "Requested action aborted: error in processing");
///
/// Gets the system status bye reply.
///
public static SmtpServerReply SystemStatusBye =>
new SmtpServerReply(221, "Service closing transmission channel");
///
/// Gets the system status help reply.
/// =
public static SmtpServerReply SystemStatusHelp => new SmtpServerReply(221, "Refer to RFC 5321");
///
/// Gets the bad syntax command empty reply.
///
public static SmtpServerReply BadSyntaxCommandEmpty => new SmtpServerReply(400, "Error: bad syntax");
///
/// Gets the OK reply.
///
public static SmtpServerReply Ok => new SmtpServerReply(250, "OK");
///
/// Gets the authorization required reply.
///
public static SmtpServerReply AuthorizationRequired => new SmtpServerReply(530, "Authorization Required");
#endregion
#region Properties
///
/// Gets the response severity.
///
public SmtpReplyCodeSeverities ReplyCodeSeverity { get; }
///
/// Gets the response category.
///
public SmtpReplyCodeCategories ReplyCodeCategory { get; }
///
/// Gets the numeric response code.
///
public int ReplyCode { get; }
///
/// Gets the enhanced status code.
///
public string EnhancedStatusCode { get; }
///
/// Gets the content.
///
public List Content { get; }
///
/// Returns true if the response code is between 200 and 599.
///
public bool IsValid { get; }
///
/// Gets a value indicating whether this instance is positive.
///
public bool IsPositive => ReplyCode >= 200 && ReplyCode <= 399;
#endregion
#region Methods
///
/// Parses the specified text into a Server Reply for thorough analysis.
///
/// The text.
/// A new instance of SMTP server response object.
public static SmtpServerReply Parse(string text)
{
var lines = text.Split(new[] {"\r\n"}, StringSplitOptions.RemoveEmptyEntries);
if (lines.Length == 0) return new SmtpServerReply();
var lastLineParts = lines.Last().Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries);
var enhancedStatusCode = string.Empty;
int.TryParse(lastLineParts[0], out var responseCode);
if (lastLineParts.Length > 1)
{
if (lastLineParts[1].Split('.').Length == 3)
enhancedStatusCode = lastLineParts[1];
}
var content = new List();
for (var i = 0; i < lines.Length; i++)
{
var splitChar = i == lines.Length - 1 ? " " : "-";
var lineParts = lines[i].Split(new[] {splitChar}, 2, StringSplitOptions.None);
var lineContent = lineParts.Last();
if (string.IsNullOrWhiteSpace(enhancedStatusCode) == false)
lineContent = lineContent.Replace(enhancedStatusCode, string.Empty).Trim();
content.Add(lineContent);
}
return new SmtpServerReply(responseCode, enhancedStatusCode, content.ToArray());
}
///
/// Returns a that represents this instance.
///
///
/// A that represents this instance.
///
public override string ToString()
{
var responseCodeText = ReplyCode.ToString(CultureInfo.InvariantCulture);
var statusCodeText = string.IsNullOrWhiteSpace(EnhancedStatusCode)
? string.Empty
: $" {EnhancedStatusCode.Trim()}";
if (Content.Count == 0) return $"{responseCodeText}{statusCodeText}";
var builder = new StringBuilder();
for (var i = 0; i < Content.Count; i++)
{
var isLastLine = i == Content.Count - 1;
builder.Append(isLastLine
? $"{responseCodeText}{statusCodeText} {Content[i]}"
: $"{responseCodeText}-{Content[i]}\r\n");
}
return builder.ToString();
}
#endregion
}
}