Skip to content

A library for working with Usenet. It offers an NNTP client, an NZB file parser, builder, writer, a yEnc encoder and decoder.

License

Notifications You must be signed in to change notification settings

keimpema/Usenet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

91 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Usenet

A library for working with Usenet. It offers:

  • an NNTP client
  • an NZB file parser, builder and writer
  • a yEnc encoder and decoder

It is mainly focused on keeping memory usage low. Server responses can be enumerated as they come in. Binary messages will be encoded to yEnc format streaming and yEnc-encoded data will be decoded to binary data streaming.

The NNTP client is compliant with RFC 2980, RFC 3977, RFC 4643 and RFC 6048.

Build status

Getting Started

Install Nuget package:

PM> Install-Package Usenet

Examples

Connect to Usenet server:

var client = new NntpClient(new NntpConnection());
await client.ConnectAsync(hostname, port, useSsl);

Authenticate:

client.Authenticate(username, password);

Enable logging:

ILoggerFactory factory = new SomeLoggerFactory();
Usenet.Logger.Factory = factory;

Retrieve article:

NntpArticleResponse response = client.Article(messageId);
if (response.Success) {
    foreach (string line in response.Article.Body) {
        ...
    }
}

Build an article and post to server:

string messageId = $"{Guid.NewGuid()}@example.net";

NntpArticle newArticle = new NntpArticleBuilder()
    .SetMessageId(messageId)
    .SetFrom("Randomposter <randomposter@example.net>")
    .SetSubject("Random test post #1")
    .AddGroups("alt.test.clienttest", "alt.test")
    .AddLine("This is a message with id " + messageId)
    .AddLine("with multiple lines")
    .Build();

client.Post(newArticle);

Parse an NZB file, download, decode and write the parts streaming to a file:

NzbDocument nzbDocument = NzbParser.Parse(File.ReadAllText(nzbPath));

foreach (NzbFile file in nzbDocument.Files)
{
    foreach (NzbSegment segment in file.Segments)
    {
        // retrieve article from Usenet server
        NntpArticleResponse response = client.Article(segment.MessageId);

        // decode the yEnc-encoded article
        using (YencStream yencStream = YencStreamDecoder.Decode(response.Article.Body))
        {
            YencHeader header = yencStream.Header;

            if (!File.Exists(header.FileName))
            {
                // create file and pre-allocate disk space for it
                using (FileStream stream = File.Create(header.FileName))
                {
                    stream.SetLength(header.FileSize);
                }
            }
            using (FileStream stream = File.Open(
                header.FileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite))
            {
                // copy incoming parts to file
                stream.Position = header.PartOffset;
                yencStream.CopyTo(stream);
            }
        }
    }
}

Build an NZB document and write to file:

IFileProvider fileProvider = new PhysicalFileProvider(Path.GetFullPath("testdata"));

NzbBuilder builder = new NzbBuilder()
    .AddGroups("alt.test.clienttest")
    .SetMessageBase("random.local")
    .SetPartSize(50_000)
    .SetPoster("random poster <random.poster@random.com>")
    .AddMetaData("title", "Testing upload Pictures.rar");

foreach (string fileName in fileNames)
{
    builder.AddFile(fileProvider.GetFileInfo(fileName));
}

NzbDocument nzbDocument = builder.Build();

using (FileStream file = File.Open("Pictures.nzb"))
using (var writer = new StreamWriter(file, UsenetEncoding.Default))
{
    await writer.WriteNzbDocumentAsync(nzbDocument);
}

Encode the files from an NZB document in yEnc format and upload streaming:

foreach (NzbFile file in nzbDocument.Files)
{
    // open file stream
    IFileInfo fileInfo = fileProvider.GetFileInfo(file.FileName);
    using (Stream stream = fileInfo.CreateReadStream())
    {
        foreach (NzbSegment segment in file.Segments)
        {
            stream.Position = segment.Offset;

            // encode in yEnc format
            IEnumerable<string> encodedBody = YencEncoder.Encode(new YencHeader(
                file.FileName, file.Size, 128, segment.Number, file.Segments.Count,
                segment.Size, segment.Offset), stream);

            // create article
            NntpArticle article = new NntpArticleBuilder()
                .AddGroups(file.Groups)
                .SetMessageId(segment.MessageId)
                .SetFrom(file.Poster)
                .SetSubject(segment.MessageId)
                .SetBody(encodedBody)
                .Build();

            // post article
            client.Post(article);
        }
    }
}

Close connection:

client.Quit();

License

This project is licensed under the MIT License - see the LICENSE.md file for details.

Acknowledgments

This project was heavily inspired by Kristian Hellang's work:

About

A library for working with Usenet. It offers an NNTP client, an NZB file parser, builder, writer, a yEnc encoder and decoder.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages