/// <summary> /// Creates a <see cref="NntpArticle"/> with al the properties from the <see cref="NntpArticleBuilder"/>. /// </summary> /// <returns>The <see cref="NntpArticle"/>.</returns> public NntpArticle Build() { if (!messageId.HasValue) { throw new NntpException(Resources.Nntp.MessageIdHeaderNotSet); } if (string.IsNullOrWhiteSpace(from)) { throw new NntpException(Resources.Nntp.FromHeaderNotSet); } if (string.IsNullOrWhiteSpace(subject)) { throw new NntpException(Resources.Nntp.SubjectHeaderNotSet); } if (groupsBuilder.IsEmpty) { throw new NntpException(Resources.Nntp.NewsgroupsHeaderNotSet); } NntpGroups groups = groupsBuilder.Build(); headers.Add(NntpHeaders.From, from); headers.Add(NntpHeaders.Subject, subject); if (dateTime.HasValue) { string formattedDate = dateTime.Value.ToUniversalTime().ToString(dateFormat); headers.Add(NntpHeaders.Date, $"{formattedDate} +0000"); } return(new NntpArticle(0, messageId, groups, headers, body)); }
public NntpArticleResponse Parse(int code, string message, IEnumerable <string> dataBlock) { if (!IsSuccessResponse(code)) { return(new NntpArticleResponse(code, message, false, null)); } // get response line string[] responseSplit = message.Split(' '); if (responseSplit.Length < 2) { log.LogError("Invalid response message: {Message} Expected: {{number}} {{messageid}}", message); } long.TryParse(responseSplit.Length > 0 ? responseSplit[0] : null, out long number); string messageId = responseSplit.Length > 1 ? responseSplit[1] : string.Empty; if (dataBlock == null) { // no headers and no body return(new NntpArticleResponse(code, message, true, new NntpArticle(number, messageId, null, null, null))); } using (IEnumerator <string> enumerator = dataBlock.GetEnumerator()) { // get headers if requested MultiValueDictionary <string, string> headers = (requestType & ArticleRequestType.Head) == ArticleRequestType.Head ? GetHeaders(enumerator) : MultiValueDictionary <string, string> .Empty; // get groups NntpGroups groups = headers.TryGetValue(NntpHeaders.Newsgroups, out ICollection <string> values) ? new NntpGroupsBuilder().Add(values).Build() : null; // get body if requested IEnumerable <string> bodyLines = (requestType & ArticleRequestType.Body) == ArticleRequestType.Body ? EnumerateBodyLines(enumerator) : new string[0]; if (dataBlock is ICollection <string> ) { // no need to keep enumerator if input is not a stream // memoize the body lines bodyLines = bodyLines.ToList(); } return(new NntpArticleResponse( code, message, true, new NntpArticle(number, messageId, groups, headers, bodyLines))); } }
private static NzbFile GetFile(NzbParserContext context, XElement fileElement) { string poster = (string)fileElement.Attribute(NzbKeywords.Poster) ?? string.Empty; if (!long.TryParse((string)fileElement.Attribute(NzbKeywords.Date) ?? "0", out long unixTimestamp)) { throw new InvalidNzbDataException(Resources.Nzb.InvalidDateAttriubute); } DateTimeOffset date = DateTimeOffset.FromUnixTimeSeconds(unixTimestamp); string subject = (string)fileElement.Attribute(NzbKeywords.Subject) ?? string.Empty; string fileName = GetFileName(subject); NntpGroups groups = GetGroups(context, fileElement.Element(context.Namespace + NzbKeywords.Groups)); IEnumerable <NzbSegment> segments = GetSegments(context, fileElement.Element(context.Namespace + NzbKeywords.Segments)); return(new NzbFile(poster, subject, fileName, date, groups, segments)); }
/// <summary> /// Creates a new instance of the <see cref="NzbFile"/> class. /// </summary> /// <param name="poster">The name of the poster. This is a copy of the article's From header field.</param> /// <param name="subject">A slightly munged copy of the article's subject. The segment counter (xx/yy) /// usually found at the end, is replaced with (1/yy). You can use the yy to /// confirm all segments are present.</param> /// <param name="fileName">The file name extracted from the subject.</param> /// <param name="date">The date the server saw this article.</param> /// <param name="groups">The list of groups that reference this file.</param> /// <param name="segments">The list of segments that make up this file.</param> public NzbFile( string poster, string subject, string fileName, DateTimeOffset date, NntpGroups groups, IEnumerable <NzbSegment> segments) { Poster = poster; Subject = subject; FileName = fileName; Date = date; Groups = groups ?? NntpGroups.Empty; Segments = (segments ?? new List <NzbSegment>(0)).OrderBy(s => s.Number).ToImmutableList(); Size = Segments.Sum(s => s.Size); }
public void ConstructWithSameGroupsShouldReturnSingleGroupString() { var groups = new NntpGroups(new[] { "group1", "group1" }); Assert.Equal("group1", groups.ToString()); }
public void ConstructWithMultipleGroupsShouldReturnMultipleGroupsString() { var groups = new NntpGroups(new [] { "group1", "group2" }); Assert.Equal("group1;group2", groups.ToString()); }
public void ConstructWithNullEnumerableShouldReturnEmptyString() { var groups = new NntpGroups((IEnumerable <string>?)null); Assert.Equal("", groups.ToString()); }
public void ConstructWithNullShouldReturnEmptyString() { var groups = new NntpGroups((string?)null); Assert.Equal("", groups.ToString()); }
/// <summary> /// Adds a file to the NZB document. Additional newsgroups may be provided. /// Optionally the default poster van be overriden. /// </summary> /// <param name="fileInfo">The file to add.</param> /// <param name="groups">The newsgroups to post the file in.</param> /// <param name="poster">Can be used to override the default poster.</param> /// <returns>The <see cref="NzbBuilder"/> so that additional calls can be chained.</returns> public NzbBuilder AddFile(IFileInfo fileInfo, NntpGroups groups = null, string poster = null) { Guard.ThrowIfNull(fileInfo, nameof(fileInfo)); files.Add(new File(fileInfo, groups ?? NntpGroups.Empty, poster)); return(this); }
public File(IFileInfo fileInfo, NntpGroups groups, string poster) { FileInfo = fileInfo; Groups = groups; Poster = poster; }