commit 15fab62468e9586e98d89e940cfdf8bc0974a97d
parent 468c760ce2502ccc994cc4d5415fdcf93cfbcbc5
Author: Mario Rosell R. Martinez <mario@mariorosell.es>
Date: Sat, 28 Mar 2026 21:19:45 +0100
article: Add anntp_article
Diffstat:
| M | anntp.h | | | 91 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 91 insertions(+), 0 deletions(-)
diff --git a/anntp.h b/anntp.h
@@ -193,6 +193,7 @@ ANNTP_API void anntp_freeconn(AnntpConnection* conn);
ANNTP_API ssize_t anntp_read(AnntpConnection* conn, uchar_t* buf, size_t bufsize);
ANNTP_API ssize_t anntp_write(AnntpConnection* conn, const uchar_t* buf, size_t bufsize);
ANNTP_API int anntp_group(AnntpConnection* conn, const char* group, AnntpGroup* out_group);
+ANNTP_API ssize_t anntp_article(AnntpConnection*, size_t num, AnntpArticle* out_art);
ANNTP_API ssize_t anntp_write_all(AnntpConnection* conn, const uchar_t* buf, size_t bufsize);
ANNTP_API ssize_t anntp_writeline(AnntpConnection* conn, const char* buf);
ANNTP_API ssize_t anntp_readline(AnntpConnection* conn, char* buf, size_t maxlen);
@@ -301,6 +302,94 @@ cleanup:
return NULL;
}
+static char*
+anntp__trim_left(char* s)
+{
+ while (*s == ' ' || *s == '\t')
+ s++;
+ return s;
+}
+
+ssize_t
+anntp_article(AnntpConnection* cv, size_t n, AnntpArticle* art)
+{
+ if (!cv || !art)
+ return ANNTPE(ANE_PARAMS);
+
+ char cmd[ANNTP_BUFSIZE];
+ char line[ANNTP_BUFSIZE];
+
+ snprintf(cmd, sizeof(cmd), "ARTICLE %zu", n);
+
+ if (anntp_writeline(cv, cmd) <= 0)
+ return ANNTPE(ANE_IO);
+
+ ssize_t r = anntp_readline(cv, line, sizeof(line));
+ if (r <= 0)
+ return ANNTPE(ANE_IO);
+
+ if (strncmp(line, "220", 3) != 0)
+ return ANNTPE(ANE_PROTO);
+
+ size_t cap = ANNTP_BUFSIZE * 8;
+ char* buf = (char*)ANNTP_MALLOC(cap);
+ if (!buf)
+ return ANNTPE(ANE_IO);
+
+ ssize_t len = anntp_readdot(cv, buf, cap);
+ if (len < 0) {
+ ANNTP_FREE(buf);
+ return len;
+ }
+
+ memset(art, 0, sizeof(*art));
+ art->n = (AnntpArticleNumber)n;
+
+ char* p = buf;
+ char* body_start = NULL;
+
+ while (*p) {
+ char* line_start = p;
+
+ char* nl = strchr(p, '\n');
+ if (!nl)
+ break;
+
+ *nl = '\0';
+ p = nl + 1;
+
+ /* end of headers */
+ if (line_start[0] == '\r' || line_start[0] == '\0') {
+ body_start = p;
+ break;
+ }
+
+ if (strncmp(line_start, "Message-ID:", 11) == 0) {
+ char* v = anntp__trim_left(line_start + 11);
+ art->id = ANNTP_STRDUP(v);
+ }
+ else if (strncmp(line_start, "From:", 5) == 0) {
+ char* v = anntp__trim_left(line_start + 5);
+ art->from = ANNTP_STRDUP(v);
+ }
+ else if (strncmp(line_start, "Date:", 5) == 0) {
+ char* v = anntp__trim_left(line_start + 5);
+ art->date = ANNTP_STRDUP(v);
+ }
+ }
+
+ if (body_start) {
+ size_t blen = strlen(body_start);
+ art->body = (char*)ANNTP_MALLOC(blen + 1);
+ if (art->body) {
+ memcpy(art->body, body_start, blen + 1);
+ }
+ }
+
+ ANNTP_FREE(buf);
+ return (ssize_t)len;
+}
+
void
anntp_freeconn(AnntpConnection* cv)
{
@@ -485,6 +574,8 @@ anntp_readdot(AnntpConnection* cv, char* buf, size_t maxlen)
return (ssize_t)pos;
}
+
+
int
anntp_readdot_cb(AnntpConnection* cv, AnntpLineCb cb, void* extra)
{