anntp

a nntp implementation in pure C99
Log | Files | Refs | README | LICENSE

commit dd107d31c32bcc3fb7b4792060470e0cd4c40310
parent f656a66a6bf497e196458cd39dbccccba0935dbe
Author: Mario Rosell R. Martinez <mario@mariorosell.es>
Date:   Fri, 20 Mar 2026 20:10:31 +0100

Import

Diffstat:
M.gitignore | 1-
Aexamples/nntpsh.c | 158+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 158 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore @@ -1,4 +1,3 @@ -*.c *.swp *.swo a.out diff --git a/examples/nntpsh.c b/examples/nntpsh.c @@ -0,0 +1,158 @@ +/* + * anntp v0.1: nntpsh.c - example 1 - nntp shell + * + * This program basically connects to a host and allows you to run commands. + * + * Pretty basic, uses readdot_cb and writeline, as well as the basic lifecycle functions and standard C. + */ + +#include <arpa/inet.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define ANNTP_TLS +#define ANNTP_IMPLEMENTATION +#include "../anntp.h" + +static char host[0x100]; +static char port[0x10]; +static bool usetls; +static AnntpConnection* c; + +/* anntp_readdot_cb callback */ + static inline int +puts_cb(const char* l, void* _) +{ + (void*)_; + printf("< %s", l); + + return 0; +} + + static inline void +cli(int argc, char** argv) +{ + if (argc < 3 || argc > 4) { + fprintf(stderr, "usage: %s <host> <port> [tls]\n", argv[0]); + exit(EXIT_FAILURE); + } + + if (argc == 4) { + usetls = true; + } else { + usetls = false; /* initialize tls nevertheless */ + } + + /* copy host */ + strncpy(host, argv[1], sizeof(host) - 1); + host[sizeof(host) - 1] = '\0'; + + /* copy port */ + strncpy(port, argv[2], sizeof(port) - 1); + port[sizeof(port) - 1] = '\0'; +} + +void +setup(void) { + c = anntp_mkconn(host, port, usetls); + if (!c) { + fprintf(stderr, "%s: can't create connection\n"); + exit(EXIT_FAILURE); + } + + char* ipstr = inet_ntoa(c->addr); + printf("Connected to host `%s' (%s)\n", host, ipstr); + puts("Use the `quit' command to exit."); +} + +static void +sendin(char line[512]) +{ + if (line[0] == '\n' || line[0] == '\0') + return; + + line[strcspn(line, "\n")] = 0; // remove newline + + ssize_t n = anntp_writeline(c, line); + + if (ANNTP_ISERR(n)) { + fprintf(stderr, "< error: %s\n", anntp_strerror(ANNTP_CODE(n))); + exit(EXIT_FAILURE); + } +} + +void +teardown(void) { + anntp_freeconn(c); +} + +int +main(int argc, char** argv) +{ + cli(argc, argv); + anntp_init(); + + setup(); + + /* read greeting */ + char bbuf[4096]; + ssize_t n = anntp_readline(c, bbuf, 4096); + if (ANNTP_ISERR(n)) { + fprintf(stderr, "< error: %s", anntp_strerror(ANNTP_CODE(n))); + return EXIT_FAILURE; + } + + puts(bbuf); + + for (;;) { + char line[512]; + + printf("nntp> "); + fflush(stdout); + + if (fgets(line, sizeof(line), stdin) == NULL) { + fprintf(stderr, "%s: error reading input", argv[0]); + } + + if (strncmp(line, "quit", 4) == 0) { + return EXIT_SUCCESS; + } + + sendin(line); + char resp[4096]; + n = anntp_readline(c, resp, sizeof(resp)); + + if (ANNTP_ISERR(n)) { + fprintf(stderr, "< error: %s", anntp_strerror(ANNTP_CODE(n))); + continue; + } + + puts(resp); + + int code = atoi(resp); + + /* multiline responses */ + switch (code) { + case 100: /* fallthrough */ + case 101: + case 215: + case 220: + case 222: + case 224: + case 230: + case 231: + anntp_readdot_cb(c, puts_cb, NULL); + break; + + default: + /* single line responses have nothing else to read */ + break; + } + } + + teardown(); + return EXIT_SUCCESS; +} +