summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <lekensteyn@gmail.com>2012-11-01 21:42:36 +0100
committerPeter Wu <lekensteyn@gmail.com>2012-11-01 21:42:36 +0100
commit473822539e549cae1874d6ead6d04839ffb33316 (patch)
tree99bfb2e5ee37fad5dd52468773d7c8e98918467e
parenta132c4b6081f4bc80108cc1650dc29247185386a (diff)
downloadc-files-473822539e549cae1874d6ead6d04839ffb33316.tar.gz
nttp-get: retrieve mail from using NNTP
-rw-r--r--nntp-get.c126
1 files changed, 126 insertions, 0 deletions
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 <stdio.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <netdb.h>
+
+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;
+}