13 releases (6 stable)
Uses new Rust 2024
new 1.0.5 | Apr 24, 2025 |
---|---|
1.0.4 | Apr 23, 2025 |
0.1.6 | Apr 15, 2025 |
0.1.5 | Oct 1, 2023 |
0.1.1 | Sep 26, 2023 |
#367 in Network programming
831 downloads per month
Used in usenet_reborn
35KB
571 lines
ReK2 NNTP RFC3977/RFC4643 Rust Library
- By Chris F.N. aka ReK2
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!
- Issues and pull requests: ~rek2/rek2_nntp
- Mailing list for patches: ~rek2/rek2_nntp@lists.sr.ht
License
This library is licensed under the GNU GPL v3.
Dependencies
~12–23MB
~413K SLoC