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