/// <summary> /// Creates a new instance of the <see cref="NntpArticleBuilder"/> class. /// </summary> public NntpArticleBuilder() { headers = new MultiValueDictionary <string, string>(); body = new List <string>(); groupsBuilder = new NntpGroupsBuilder(); messageId = NntpMessageId.Empty; }
/// <summary> /// Creates a new instance of the <see cref="NntpStatResponse"/> class. /// </summary> /// <param name="code">The response code received from the server.</param> /// <param name="message">The response message received from the server.</param> /// <param name="success">A value indicating whether the command succeeded or failed.</param> /// <param name="responseType">The type of the response received from the server.</param> /// <param name="number">The <see cref="NntpArticle"/> number received from the server.</param> /// <param name="messageId">The <see cref="NntpMessageId"/> received from the server.</param> public NntpStatResponse(int code, string message, bool success, NntpStatResponseType responseType, int number, NntpMessageId messageId) : base(code, message, success) { ResponseType = responseType; Number = number; MessageId = messageId ?? NntpMessageId.Empty; }
public void SerializedInstanceShouldBeDeserializedCorrectly(string messageId) { var expectedMessageId = new NntpMessageId(messageId); string json = JsonConvert.SerializeObject(expectedMessageId); var actualMessageId = JsonConvert.DeserializeObject <NntpMessageId>(json); Assert.Equal(expectedMessageId, actualMessageId); }
/// <summary> /// Creates a new instance of the <see cref="NzbSegment"/> class. /// </summary> /// <param name="number">Segment number of the article, gleaned by parsing (yy/zz).</param> /// <param name="size">Size of the article, in bytes, as a number, with no comma separation.</param> /// <param name="messageId">The Message-ID of this article.</param> public NzbSegment( int number, long size, NntpMessageId messageId) { Number = number; Size = size; MessageId = messageId ?? NntpMessageId.Empty; }
public void EqualsWithSameValuesShouldReturnTrue(string first, string second) { var firstMessageId = new NntpMessageId(first); var secondMessageId = new NntpMessageId(second); Assert.Equal(firstMessageId, secondMessageId); Assert.True(firstMessageId == secondMessageId); Assert.True(firstMessageId.Equals(secondMessageId)); }
private static void WriteHeader(INntpConnection connection, string key, string val) { if (key == NntpHeaders.MessageId) { val = new NntpMessageId(val); } string line = $"{key}: {val}"; if (line.Length <= maxHeaderLength) { connection.WriteLine(line); return; } // header line is too long, fold it connection.WriteLine(line.Substring(0, maxHeaderLength)); line = line.Substring(maxHeaderLength); while (line.Length > maxHeaderLength) { connection.WriteLine("\t" + line.Substring(0, maxHeaderLength - 1)); line = line.Substring(maxHeaderLength - 1); } connection.WriteLine("\t" + line); }
//connection.Command($"XFEATURE COMPRESS GZIP{(withTerminator ? " TERMINATOR" : string.Empty)}", new ResponseParser(290)); public NntpMultiLineResponse Xzhdr(string field, NntpMessageId messageId) => throw new NotImplementedException();
/// <summary> /// The <a href="https://tools.ietf.org/html/rfc3977#section-8.6">LIST HEADERS</a> /// command returns a list of fields that may be /// retrieved using the HDR command. /// </summary> /// <param name="messageId">The message-id of the article to received from the server.</param> /// <returns>A multi-line response containg a list of header /// fields that may be retrieved using the HDR command.</returns> public NntpMultiLineResponse ListHeaders(NntpMessageId messageId) => connection.MultiLineCommand($"LIST HEADERS {messageId}", new MultiLineResponseParser(215));
/// <summary> /// The <a href="https://tools.ietf.org/html/rfc3977#section-8.5">HDR</a> /// command provides access to specific fields from an article /// specified by message-id, or from a specified article or range of /// articles in the currently selected newsgroup. /// </summary> /// <param name="field">The header field to retrieve.</param> /// <param name="messageId">The message-id of the article to received from the server.</param> /// <returns>A multi-line response containing the specfied header fields.</returns> public NntpMultiLineResponse Hdr(string field, NntpMessageId messageId) => connection.MultiLineCommand($"HDR {field} {messageId}", new MultiLineResponseParser(225));
/// <summary> /// The <a href="https://tools.ietf.org/html/rfc3977#section-8.3">OVER</a> /// command returns the contents of all the fields in the /// database for an article specified by message-id, or from a specified /// article or range of articles in the currently selected newsgroup. /// </summary> /// <param name="messageId">The message-id of the article to received from the server.</param> /// <returns>A multi-line response containing header fields.</returns> public NntpMultiLineResponse Over(NntpMessageId messageId) => connection.MultiLineCommand($"OVER {messageId}", new MultiLineResponseParser(224));
/// <summary> /// The <a href="https://tools.ietf.org/html/rfc3977#section-6.2.4">STAT</a> /// command behaves identically to the ARTICLE command except /// that, if the article exists, it is NOT presented to the client and /// the response code is 223 instead of 220. Note that the response is /// NOT multi-line. /// </summary> /// <param name="messageId">The message-id of the article to received from the server.</param> /// <returns>A stat response object.</returns> public NntpStatResponse Stat(NntpMessageId messageId) => connection.Command($"STAT {messageId.ThrowIfNullOrWhiteSpace(nameof(messageId))}", new StatResponseParser());
/// <summary> /// The <a href="https://tools.ietf.org/html/rfc3977#section-6.2.3">BODY</a> /// command behaves identically to the ARTICLE command except /// that, if the article exists, the response code is 222 instead of 220 /// and only the body is presented (the empty line separating the headers /// and body MUST NOT be included). /// </summary> /// <param name="messageId">The message-id of the article to received from the server.</param> /// <returns>An article response object.</returns> public NntpArticleResponse Body(NntpMessageId messageId) => connection.MultiLineCommand( $"BODY {messageId.ThrowIfNullOrWhiteSpace(nameof(messageId))}", new ArticleResponseParser(ArticleRequestType.Body));
/// <summary> /// Initialize the <see cref="NntpArticleBuilder"/> from the given <see cref="NntpArticle"/>. /// All properties are overwritten. /// </summary> /// <param name="article">The <see cref="NntpArticle"/> to initialize the <see cref="NntpArticleBuilder"/> with.</param> /// <returns>The <see cref="NntpArticleBuilder"/> so that additional calls can be chained.</returns> public NntpArticleBuilder InitializeFrom(NntpArticle article) { messageId = null; from = null; subject = null; headers.Clear(); body.Clear(); groups.Clear(); foreach (KeyValuePair <string, ICollection <string> > header in article.Headers) { foreach (string value in header.Value) { switch (header.Key) { case NntpHeaders.MessageId: // skip additional messageid's break; case NntpHeaders.From: if (from == null) { from = value; } break; case NntpHeaders.Subject: if (subject == null) { subject = value; } break; case NntpHeaders.Date: if (dateTime == null) { if (DateTimeOffset.TryParseExact(value, dateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTimeOffset headerDateTime)) { dateTime = headerDateTime; } } break; case NntpHeaders.Newsgroups: // convert group header to list of groups, do not add as header AddGroups(value); break; default: headers.Add(header.Key, value); break; } } } body.AddRange(article.Body); messageId = article.MessageId; return(this); }
/// <summary> /// Sets the article's required <see cref="NntpHeaders.MessageId"/> header. /// </summary> /// <param name="value">The <see cref="NntpHeaders.MessageId"/> header value.</param> /// <returns>The <see cref="NntpArticleBuilder"/> so that additional calls can be chained.</returns> public NntpArticleBuilder SetMessageId(NntpMessageId value) { messageId = value.ThrowIfNullOrWhiteSpace(nameof(value)); return(this); }
/// <summary> /// Initialize the <see cref="NntpArticleBuilder"/> from the given <see cref="NntpArticle"/>. /// All properties are overwritten. /// </summary> /// <param name="article">The <see cref="NntpArticle"/> to initialize the <see cref="NntpArticleBuilder"/> with.</param> /// <returns>The <see cref="NntpArticleBuilder"/> so that additional calls can be chained.</returns> public NntpArticleBuilder InitializeFrom(NntpArticle article) { Guard.ThrowIfNull(article, nameof(article)); messageId = new NntpMessageId(article.MessageId.Value); groupsBuilder = new NntpGroupsBuilder().Add(article.Groups); headers = new MultiValueDictionary <string, string>(); from = null; subject = null; dateTime = null; body = null; foreach (KeyValuePair <string, ImmutableHashSet <string> > header in article.Headers) { foreach (string value in header.Value) { switch (header.Key) { case NntpHeaders.MessageId: if (!messageId.HasValue) { messageId = value; } else { log.Warn("Found more than 1 {messageId} header. Skipping it.", NntpHeaders.MessageId); } break; case NntpHeaders.From: if (from == null) { from = value; } else { log.Warn("Found more than 1 {from} header. Skipping it.", NntpHeaders.From); } break; case NntpHeaders.Subject: if (subject == null) { subject = value; } else { log.Warn("Found more than 1 {subject} header. Skipping it.", NntpHeaders.Subject); } break; case NntpHeaders.Date: if (dateTime == null) { if (DateTimeOffset.TryParseExact(value, dateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTimeOffset headerDateTime)) { dateTime = headerDateTime; } else { log.Warn("{date} header has invalid value {value}. Skipping it.", NntpHeaders.Date, value); } } else { log.Warn("Found more than 1 {date} header. Skipping it.", NntpHeaders.Date); } break; case NntpHeaders.Newsgroups: // convert group header to list of groups, do not add as header groupsBuilder.Add(value); break; default: headers.Add(header.Key, value); break; } } } // make copy of body body = article.Body.ToList(); return(this); }
/// <summary> /// Throws an <exception cref="ArgumentNullException"/> if the messageId of it's value is null. /// Throws an <exception cref="ArgumentException"/> if the value of the messageId is empty or /// if it consists only of white-space characters. /// </summary> /// <param name="messageId">The messageId to check.</param> /// <param name="name">The name of the messageId.</param> /// <returns>The original <see cref="NntpMessageId"/>.</returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentException"></exception> public static NntpMessageId ThrowIfNullOrWhiteSpace(this NntpMessageId messageId, string name) { Guard.ThrowIfNull(messageId, name); Guard.ThrowIfNullOrWhiteSpace(messageId.Value, name); return(messageId); }