rek2_nntp

Crates.iorek2_nntp
lib.rsrek2_nntp
version1.0.6
created_at2023-09-19 02:56:22.199781+00
updated_at2025-06-19 05:18:59.880844+00
descriptionThis is a Rust library that provides a way to interact with NNTP servers, compliant with RFC 3977 and RFC 4643.
homepagehttps://sr.ht/~rek2/rek2_nntp/
repositoryhttps://git.sr.ht/~rek2/rek2_nntp
max_upload_size
id976457
size111,897
CF_ReK2 (r3k2)

documentation

https://docs.rs/rek2_nntp

README

ReK2 NNTP RFC3977/RFC4643 Rust Library

  • By Chris F.N. aka ReK2

builds.sr.ht status Crates.io Version rek2_nntp is a Rust asynchronous NNTP client library compliant with RFC 3977 and RFC 4643. It allows you to connect to NNTP servers to read, list, and post articles securely via TLS/SSL.

Features

  • ✅ Authentication (with TLS/SSL)
  • ✅ Listing available newsgroups (LIST)
  • ✅ Reading articles (ARTICLE)
  • ✅ Posting articles (POST)
  • ✅ Selecting newsgroups (GROUP)
  • ✅ Retrieving new newsgroups (NEWGROUPS)
  • ✅ Retrieving article headers (HEAD)
  • ✅ Retrieving article bodies (BODY)
  • ✅ Retrieving article statistics (STAT)
  • ✅ Graceful session termination (QUIT)
  • ✅ Fast article header fetching via (XOVER)
  • ⚠️ Retrieving new articles (NEWNEWS) (often disabled on modern servers, use with caution)

Installation

Add the following to your project's Cargo.toml:

[dependencies]
rek2_nntp = "1.0.0"  # Replace with the latest version

Then, run:

cargo build

Usage

Authentication

use rek2_nntp::authenticate;

#[tokio::main]
async fn main() {
    let result = authenticate("news.example.com", "username", "password").await;
    match result {
        Ok(mut connection) => {
            println!("Successfully authenticated!");
            // You can now use `connection` with other commands
        }
        Err(err) => {
            eprintln!("Failed to authenticate: {}", err);
        }
    }
}

Listing Newsgroups

use rek2_nntp::{authenticate, list_newsgroups};

let mut connection = authenticate("news.example.com", "username", "password").await?;

let newsgroups = list_newsgroups(&mut connection).await?;
for group in newsgroups.iter().take(10) {
    println!("{} ({}-{}) Status: {}", group.name, group.low, group.high, group.status);
}

Reading Articles from a Newsgroup

use rek2_nntp::{authenticate, read_from_group};

let mut connection = authenticate("news.example.com", "username", "password").await?;

// Read first 5 articles from "comp.lang.rust"
let articles = read_from_group(&mut connection, "comp.lang.rust", Some((1, 5))).await?;
for article in articles {
    println!("Header: {}\nBody: {}", article.header, article.body);
}

Posting an Article

use rek2_nntp::{authenticate, post_to_group, PostArticle};

let mut connection = authenticate("news.example.com", "username", "password").await?;

let article = PostArticle {
    from: "user@example.com".to_string(),
    newsgroups: "comp.lang.rust".to_string(),
    subject: "Hello Rust!".to_string(),
    body: "This is a test article posted using rek2_nntp".to_string(),
};

post_to_group(&mut connection, &article, &"comp.lang.rust".to_string()).await?;
println!("Article posted successfully!");

Selecting a Newsgroup (GROUP)

use rek2_nntp::{authenticate, group};

let mut connection = authenticate("news.example.com", "username", "password").await?;

let response = group(&mut connection, "comp.lang.c").await?;
println!("Server Response: {}", response);

Retrieving New Newsgroups (NEWGROUPS)

use rek2_nntp::{authenticate, newgroups};

let mut connection = authenticate("news.example.com", "username", "password").await?;

let groups = newgroups(&mut connection, "20250101", "000000", None).await?;
for group in groups.iter().take(5) {
    println!("Newsgroup: {}", group.name);
}

Retrieving Article Headers (HEAD)

use rek2_nntp::{authenticate, head, group};

let mut connection = authenticate("news.example.com", "username", "password").await?;
let _ = group(&mut connection, "comp.lang.c").await?;

let header = head(&mut connection, "1").await?;
println!("Header: {}", header);

Retrieving Article Bodies (BODY)

use rek2_nntp::{authenticate, body, group};

let mut connection = authenticate("news.example.com", "username", "password").await?;
let _ = group(&mut connection, "comp.lang.c").await?;

let article_body = body(&mut connection, "1").await?;
println!("Body: {}", article_body);

Retrieving Article Statistics (STAT)

use rek2_nntp::{authenticate, stat, group};

let mut connection = authenticate("news.example.com", "username", "password").await?;
let _ = group(&mut connection, "comp.lang.c").await?;

let message_id = stat(&mut connection, "1").await?;
println!("Message ID: {}", message_id);

Fetch overview headers for a range of articles in a newsgroup (XOVER)

let articles = fetch_xover_range(&mut conn, "alt.test", Some((1, 50))).await?;
for art in articles {
    println!("{} — {}", art.article_id, art.subject);
}

Gracefully Ending the Session (QUIT)

use rek2_nntp::{authenticate, quit};

let mut connection = authenticate("news.example.com", "username", "password").await?;
quit(&mut connection).await?;
println!("Session closed.");

Running Integration Tests

Set environment variables before running tests:

export NNTP_HOST=news.example.com
export NNTP_USERNAME=username
export NNTP_PASSWORD=password

Then run:

cargo test -- --nocapture

Contributing

Contributions are welcome!

License

This library is licensed under the GNU GPL v3.

Commit count: 0

cargo fmt