Fixed a little bug when the newsrc wasn't found.
[noose.git] / nntp.c
blob226e62ebf2da5913dee326f7b0826ff05cc1856e
1 /*
2 * nntp.c
3 * Created: Sun Feb 25 20:37:47 2001 by tek@wiw.org
4 * Revised: Sun Feb 25 20:37:47 2001 (pending)
5 * Copyright 2001 Julian E. C. Squires (tek@wiw.org)
6 * This program comes with ABSOLUTELY NO WARRANTY.
7 * $Id: nntp.c,v 1.2 2001/02/26 06:00:54 tek Exp $
8 *
9 */
11 #include <errno.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <unistd.h>
17 #include <netdb.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/time.h>
21 #include <netinet/in.h>
23 #include "noose.h"
25 #define OURMAGIC 0xDEADBEEF
26 #define NNTPSERVICE "nntp"
27 #define NNTPPROTO "tcp"
29 typedef struct nntp_s {
30 long magic;
31 int sock;
32 } nntp_t;
34 void *nntp_connect(char *hostname);
35 void nntp_disconnect(void *nh_);
36 int nntp_cmd_group(void *nh_, char *group, int *narticles_, int *firstart_,
37 int *lastart_);
38 int nntp_cmd_article(void *nh_, int artnum, char **head, char **body);
40 static int nntp_readresponse(nntp_t *nh, char **resbody);
41 static int nntp_readheader(nntp_t *nh, char **header);
42 static int nntp_readbody(nntp_t *nh, char **body);
44 static char *responses[6][5][10] = {
45 { { "" } }, /* 0 */
46 { { "" } }, /* 1 */
47 { { "" } }, /* 2 */
48 { { "" } }, /* 3 */
49 /* 4** */
50 { /* 40* */
51 { "Service discontinued." /* 400 */
52 "", "", "", "", "", "", "", "", "" },
53 /* 41* */
54 { "", /* 410 */
55 "No such news group.", /* 411 */
56 "No newsgroup has been selected.", /* 412 */
57 "", "", "", "", "", "", "" },
58 /* 42* */
59 { "No current article has been selected.", /* 420 */
60 "No next article in this group.", /* 421 */
61 "No previous article in this group.", /* 422 */
62 "No such article number in this group.", /* 423 */
63 "", "", "", "", "", "" },
64 /* 43* */
65 { "No such article found.", /* 430 */
66 "", "", "", "",
67 "Article not wanted - do not send it.", /* 435 */
68 "Transfer failed - try again later.", /* 436 */
69 "Article rejected - do not try again.", /* 437 */
70 "", "" },
71 /* 44* */
72 { "Posting not allowed.", /* 440 */
73 "Posting failed.", /* 441 */
74 "", "", "", "", "", "", "", "" }
77 /* 5** */
79 /* 50* */
80 { "Command not recognized.", /* 500 */
81 "Command syntax error.", /* 501 */
82 "Access restriction or permission denied.", /* 502 */
83 "Program fault - command not performed.", /* 503 */
84 "", "", "", "", "", "" }
88 void *nntp_connect(char *hostname)
90 nntp_t *nh;
91 struct hostent *hostent;
92 struct servent *servent;
93 struct sockaddr_in sockaddr;
94 int i;
96 nh = malloc(sizeof(nntp_t));
97 if(nh == NULL) {
98 fprintf(stderr, "%s: Out of memory.\n", PROGNAME);
99 return NULL;
102 nh->magic = OURMAGIC;
103 nh->sock = socket(AF_INET, SOCK_STREAM, 0);
104 if(nh->sock == -1) {
105 fprintf(stderr, "%s: %s\n", PROGNAME, strerror(errno));
106 return NULL;
109 sockaddr.sin_family = AF_INET;
110 hostent = gethostbyname(hostname);
111 if(hostent == NULL) {
112 fprintf(stderr, "%s: %s\n", PROGNAME, strerror(errno));
113 return NULL;
115 memcpy(&sockaddr.sin_addr, hostent->h_addr_list[0], hostent->h_length);
117 servent = getservbyname(NNTPSERVICE, NNTPPROTO);
118 if(servent == NULL) {
119 fprintf(stderr, "%s: %s\n", PROGNAME, strerror(errno));
120 return NULL;
122 sockaddr.sin_port = servent->s_port;
124 if(connect(nh->sock, (const struct sockaddr *)&sockaddr,
125 sizeof(sockaddr)) == -1) {
126 fprintf(stderr, "%s: %s\n", PROGNAME, strerror(errno));
127 return NULL;
130 i = nntp_readresponse(nh, NULL);
131 if(i != 200) {
132 fprintf(stderr, "%s: %s\n", PROGNAME, responses[i/100][i/10%10][i%10]);
133 return NULL;
136 return (void *)nh;
139 int nntp_readresponse(nntp_t *nh, char **resbody)
141 char *buffer;
142 int respnum, blen = 128, i, bufp;
144 buffer = malloc(blen);
145 if(buffer == NULL) {
146 fprintf(stderr, "%s: Out of memory in nntp_readresponse.\n",
147 PROGNAME);
148 return 0;
150 bufp = 0;
152 do {
153 i = read(nh->sock, buffer+bufp, 1);
154 if(i == -1) {
155 fprintf(stderr, "%s: %s\n", PROGNAME, strerror(errno));
156 return 0;
159 bufp += i;
161 if(bufp >= blen) {
162 blen *= 2;
163 buffer = realloc(buffer, blen);
164 if(buffer == NULL) {
165 fprintf(stderr, "%s: Out of memory in "
166 "nntp_readresponse.\n", PROGNAME);
167 return 0;
170 } while(!(buffer[bufp-2] == '\r' && buffer[bufp-1] == '\n'));
171 buffer[bufp] = 0;
173 respnum = atoi(buffer);
174 if(resbody != NULL)
175 *resbody = buffer;
176 else
177 free(buffer);
179 return respnum;
182 int nntp_readheader(nntp_t *nh, char **header)
184 char *buffer;
185 int blen = 128, i, bufp;
187 buffer = malloc(blen);
188 if(buffer == NULL) {
189 fprintf(stderr, "%s: Out of memory in nntp_readheader.\n",
190 PROGNAME);
191 return -1;
193 bufp = 0;
195 do {
196 i = read(nh->sock, buffer+bufp, 1);
197 if(i == -1) {
198 fprintf(stderr, "%s: %s\n", PROGNAME, strerror(errno));
199 return -1;
202 bufp += i;
204 if(bufp >= blen) {
205 blen *= 2;
206 buffer = realloc(buffer, blen);
207 if(buffer == NULL) {
208 fprintf(stderr, "%s: Out of memory in "
209 "nntp_readheader.\n", PROGNAME);
210 return -1;
213 } while(!(buffer[bufp-1] == '\n' &&
214 buffer[bufp-2] == '\r' &&
215 (buffer[bufp-3] == '.' ||
216 (buffer[bufp-3] == '\n' &&
217 buffer[bufp-4] == '\r'))));
218 buffer[bufp] = 0;
220 if(header != NULL)
221 *header = buffer;
222 else
223 free(buffer);
225 return 0;
228 int nntp_readbody(nntp_t *nh, char **body)
230 char *buffer;
231 int blen = 128, i, bufp;
233 buffer = malloc(blen);
234 if(buffer == NULL) {
235 fprintf(stderr, "%s: Out of memory in nntp_readbody.\n", PROGNAME);
236 return -1;
238 bufp = 0;
240 do {
241 i = read(nh->sock, buffer+bufp, 1);
242 if(i == -1) {
243 fprintf(stderr, "%s: %s\n", PROGNAME, strerror(errno));
244 return -1;
247 bufp += i;
249 if(bufp >= blen) {
250 blen *= 2;
251 buffer = realloc(buffer, blen);
252 if(buffer == NULL) {
253 fprintf(stderr, "%s: Out of memory in "
254 "nntp_readbody.\n", PROGNAME);
255 return -1;
258 } while(!(buffer[bufp-1] == '\n' &&
259 buffer[bufp-2] == '\r' &&
260 buffer[bufp-3] == '.' &&
261 buffer[bufp-4] == '\n' &&
262 buffer[bufp-5] == '\r'));
263 buffer[bufp-3] = 0;
265 if(body != NULL)
266 *body = buffer;
267 else
268 free(buffer);
270 return 0;
273 void nntp_disconnect(void *nh_)
275 nntp_t *nh = (nntp_t *)nh_;
277 if(nh->magic != OURMAGIC) {
278 fprintf(stderr, "%s: magic check failed for nntp_disconnect!\n",
279 PROGNAME);
282 write(nh->sock, "QUIT\r\n", strlen("QUIT\r\n"));
283 close(nh->sock);
285 return;
288 int nntp_cmd_group(void *nh_, char *group, int *narticles, int *firstart,
289 int *lastart)
291 nntp_t *nh = (nntp_t *)nh_;
292 int i;
293 char *respbody, *p, *cmdbuf;
295 if(nh->magic != OURMAGIC) {
296 fprintf(stderr, "%s: magic check failed for nntp_cmd_group!\n",
297 PROGNAME);
300 cmdbuf = malloc(strlen("GROUP ")+strlen(group)+strlen("\r\n"));
301 strcpy(cmdbuf, "GROUP ");
302 strcat(cmdbuf, group);
303 strcat(cmdbuf, "\r\n");
304 write(nh->sock, cmdbuf, strlen(cmdbuf));
305 free(cmdbuf);
307 i = nntp_readresponse(nh, &respbody);
308 if(i != 211) {
309 fprintf(stderr, "%s: %s\n", PROGNAME, responses[i/100][i/10%10][i%10]);
310 return -1;
313 p = strtok(respbody, " \t\n");
314 /* response code */
315 p = strtok(NULL, " \t\n");
316 if(narticles != NULL) *narticles = atoi(p);
317 p = strtok(NULL, " \t\n");
318 if(firstart != NULL) *firstart = atoi(p);
319 p = strtok(NULL, " \t\n");
320 if(lastart != NULL) *lastart = atoi(p);
321 /* next would be group name */
323 free(respbody);
324 return 0;
327 #define MAXARTNUMLEN 10
329 int nntp_cmd_article(void *nh_, int artnum, char **head, char **body)
331 nntp_t *nh = (nntp_t *)nh_;
332 int i;
333 char *respbody, *cmdbuf, *cmd;
335 if(nh->magic != OURMAGIC) {
336 fprintf(stderr, "%s: magic check failed for nntp_cmd_article!\n",
337 PROGNAME);
340 if(head == NULL && body == NULL)
341 cmd = "STAT ";
342 else if(head == NULL)
343 cmd = "BODY ";
344 else if(body == NULL)
345 cmd = "HEAD ";
346 else
347 cmd = "ARTICLE ";
348 cmdbuf = malloc(strlen(cmd)+MAXARTNUMLEN+strlen("\r\n"));
349 sprintf(cmdbuf, "%s %d\r\n", cmd, artnum);
350 write(nh->sock, cmdbuf, strlen(cmdbuf));
351 free(cmdbuf);
353 i = nntp_readresponse(nh, &respbody);
354 if(i/10 != 22) {
355 fprintf(stderr, "%s: %s\n", PROGNAME, responses[i/100][i/10%10][i%10]);
356 return -1;
358 if(head != NULL)
359 if(nntp_readheader(nh, head) != 0) {
360 fprintf(stderr, "%s: failed to read header.\n", PROGNAME);
361 return -1;
363 if(body != NULL)
364 if(nntp_readbody(nh, body) != 0) {
365 fprintf(stderr, "%s: failed to read body.\n", PROGNAME);
366 return -1;
369 return 0;
372 /* EOF nntp.c */