anntp

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

nntpsh.c (3012B)


      1 /*
      2  * anntp v0.1: nntpsh.c - example 1 - nntp shell
      3  *
      4  * This program basically connects to a host and allows you to run commands.
      5  *
      6  * Pretty basic, uses readdot_cb and writeline, as well as the basic lifecycle functions and standard C.
      7  */
      8 
      9 #include <arpa/inet.h>
     10 #include <stdbool.h>
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 
     15 #define ANNTP_TLS
     16 #define ANNTP_IMPLEMENTATION
     17 #include "../anntp.h"
     18 
     19 static char             argv0[256];
     20 static char             host[0x100];
     21 static char             port[0x10];
     22 static bool             usetls;
     23 static AnntpConnection* c;
     24 
     25 /* anntp_readdot_cb callback */
     26 static inline int
     27 puts_cb(const char* l, void* _)
     28 {
     29 	(void*)_;
     30 	printf("< %s", l);
     31 
     32 	return 0;
     33 }
     34 
     35 static inline void
     36 cli(int argc, char** argv)
     37 {
     38 	if (argc < 3 || argc > 4) {
     39 		fprintf(stderr, "usage: %s <host> <port> [tls]\n", argv[0]);
     40 		exit(EXIT_FAILURE);
     41 	}
     42 
     43 	if (argc == 4) {
     44 		usetls = true;
     45 	} else {
     46 		usetls = false; /* initialize tls nevertheless */
     47 	}
     48 
     49 	/* copy host */
     50 	strncpy(host, argv[1], sizeof(host) - 1);
     51 	host[sizeof(host) - 1] = '\0';
     52 
     53 	/* copy port */
     54 	strncpy(port, argv[2], sizeof(port) - 1);
     55 	port[sizeof(port) - 1] = '\0';
     56 
     57 	/* copy argv0 */
     58 	strncpy(argv0, argv[0], sizeof(argv0) - 1);
     59 	argv0[sizeof(argv0) - 1] = '\0';
     60 }
     61 
     62 void
     63 setup(void) {
     64 	c = anntp_mkconn(host, port, usetls);
     65 	if (!c) {
     66 		fprintf(stderr, "%s: can't create connection\n", argv0);
     67 		exit(EXIT_FAILURE);
     68 	}
     69 
     70 	char* ipstr = inet_ntoa(c->addr);
     71 	printf("Connected to host `%s' (%s)\n", host, ipstr);
     72 	puts("Use the `quit' command to exit.");
     73 }
     74 
     75 static void
     76 sendin(char line[512])
     77 {
     78 	if (line[0] == '\n' || line[0] == '\0')
     79 		return;
     80 
     81 	line[strcspn(line, "\n")] = 0;  /* remove newline */
     82 
     83 	ssize_t n = anntp_writeline(c, line);
     84 
     85 	if (ANNTP_ISERR(n)) {
     86 		fprintf(stderr, "< error: %s\n", anntp_strerror(ANNTP_CODE(n)));
     87 		exit(EXIT_FAILURE);
     88 	}
     89 }
     90 
     91 void
     92 teardown(void) {
     93 	anntp_freeconn(c);
     94 }
     95 
     96 int
     97 main(int argc, char** argv)
     98 {
     99 	cli(argc, argv);
    100 	anntp_init();
    101 
    102 	setup();
    103 
    104 	/* read greeting */
    105 	char bbuf[4096];
    106 	ssize_t n = anntp_readline(c, bbuf, 4096);
    107 	if (ANNTP_ISERR(n)) {
    108 		fprintf(stderr, "< error: %s", anntp_strerror(ANNTP_CODE(n)));	
    109 		return EXIT_FAILURE;
    110 	}
    111 
    112 	puts(bbuf);
    113 
    114 	for (;;) {
    115 		char line[512];
    116 
    117 		printf("nntp> ");
    118 		fflush(stdout);
    119 
    120 		if (fgets(line, sizeof(line), stdin) == NULL) {
    121 			fprintf(stderr, "%s: error reading input", argv[0]);
    122 		}
    123 
    124 		if (strncmp(line, "quit", 4) == 0) {
    125 			return EXIT_SUCCESS;
    126 		}
    127 
    128 		sendin(line);
    129 		char resp[4096];
    130 		n = anntp_readline(c, resp, sizeof(resp));
    131 
    132 		if (ANNTP_ISERR(n)) {
    133 			fprintf(stderr, "< error: %s", anntp_strerror(ANNTP_CODE(n)));
    134 			continue;
    135 		}
    136 
    137 		puts(resp);
    138 
    139 		int code = atoi(resp);
    140 
    141 		/* multiline responses */
    142 		switch (code) {
    143 		case 100: /* fallthrough */
    144 		case 101:
    145 		case 215:
    146 		case 220:
    147 		case 222:
    148 		case 224:
    149 		case 230:
    150 		case 231:
    151 			anntp_readdot_cb(c, puts_cb, NULL);
    152 			break;
    153 
    154 		default:
    155 			/* single line responses have nothing else to read */
    156 			break;
    157 		}
    158 	}
    159 
    160 	teardown();
    161 	return EXIT_SUCCESS;
    162 }
    163