From 473822539e549cae1874d6ead6d04839ffb33316 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Thu, 1 Nov 2012 21:42:36 +0100 Subject: nttp-get: retrieve mail from using NNTP --- nntp-get.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 nntp-get.c diff --git a/nntp-get.c b/nntp-get.c new file mode 100644 index 0000000..9fbfd82 --- /dev/null +++ b/nntp-get.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +enum state { + STATE_CONNECTED, + STATE_GROUP_JOINED, + STATE_ARTICLE_RECV, + STATE_LAST +}; + +int main(int argc, char **argv) { + struct addrinfo hints = {0}; + struct addrinfo *addr; + int sockfd; + FILE *sockf; + char *host, *group, *messageid; + + if (argc == 2 && strchr(argv[1], '@')) { + host = "news.gmane.org"; + group = strdup("gmane.linux.kernel"); + messageid = argv[1]; + } else if (argc == 3 && strchr(argv[2], '@')) { + host = "news.gmane.org"; + + group = argv[1]; + if (strncmp(group, "gmane.", sizeof("gmane.") - 1)) { + group = malloc(strlen(argv[1]) + sizeof("gmane.")); + sprintf(group, "gmane.%s", argv[1]); + } + char *g = group; + while ((g = strchr(g, '-'))) *g = '.'; + + messageid = argv[2]; + } else if (argc == 4) { + host = argv[1]; + group = strdup(argv[2]); + messageid = argv[3]; + } else { + fprintf(stderr, "Usage: %s host group message-id\n" + "or: %s message-id\n", + *argv, *argv); + return 1; + } + + hints.ai_protocol = IPPROTO_TCP; + + if (getaddrinfo(host, "119", &hints, &addr)) { + perror("getaddrinfo"); + return 1; + } + + sockfd = socket(addr->ai_family, SOCK_STREAM, addr->ai_protocol); + if (sockfd < 0) { + perror("socket"); + goto err_free_addr; + } + sockf = fdopen(sockfd, "r"); + + if (connect(sockfd, addr->ai_addr, addr->ai_addrlen)) { + perror("connect"); + goto err_close_sock; + } + + enum state state = STATE_CONNECTED; + while (state != STATE_LAST) { + char buff[512]; + int r = -1; + if (fgets(buff, sizeof(buff), sockf) == NULL) { + perror("read response"); + goto err_close_sock; + } + switch (state) { + case STATE_CONNECTED: + if (strncmp(buff, "200 ", 4)) { + fprintf(stderr, "Invalid response: %s\n", buff); + goto err_close_sock; + } + r = snprintf(buff, sizeof(buff), "group %s\r\n", group); + break; + case STATE_GROUP_JOINED: + if (strncmp(buff, "211 ", 4)) { + fprintf(stderr, "Invalid response: %s\n", buff); + goto err_close_sock; + } + if (messageid[0] == '<') { + r = snprintf(buff, sizeof(buff), "article %s\r\n", messageid); + } else { + r = snprintf(buff, sizeof(buff), "article <%s>\r\n", messageid); + } + break; + case STATE_ARTICLE_RECV: + if (strncmp(buff, "220 ", 4)) { + fprintf(stderr, "Invalid response: %s\n", buff); + goto err_close_sock; + } + while (fgets(buff, sizeof(buff), sockf) != NULL) { + if (!strcmp(buff, "..\r\n")) puts("."); + else if (!strcmp(buff, ".\r\n")) break; + else fputs(buff, stdout); + } + r = snprintf(buff, sizeof(buff), "quit\r\n"); + break; + case STATE_LAST: + break; + } + state++; + if (r > 0) write(sockfd, buff, r); + } + + close(sockfd); + freeaddrinfo(addr); + free(group); + return 0; +err_close_sock: + close(sockfd); +err_free_addr: + freeaddrinfo(addr); + free(group); + return 1; +} -- cgit v1.2.1