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 $
18 #include <sys/types.h>
19 #include <sys/socket.h>
21 #include <netinet/in.h>
25 #define OURMAGIC 0xDEADBEEF
26 #define NNTPSERVICE "nntp"
27 #define NNTPPROTO "tcp"
29 typedef struct nntp_s
{
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_
,
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] = {
51 { "Service discontinued." /* 400 */
52 "", "", "", "", "", "", "", "", "" },
55 "No such news group.", /* 411 */
56 "No newsgroup has been selected.", /* 412 */
57 "", "", "", "", "", "", "" },
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 "", "", "", "", "", "" },
65 { "No such article found.", /* 430 */
67 "Article not wanted - do not send it.", /* 435 */
68 "Transfer failed - try again later.", /* 436 */
69 "Article rejected - do not try again.", /* 437 */
72 { "Posting not allowed.", /* 440 */
73 "Posting failed.", /* 441 */
74 "", "", "", "", "", "", "", "" }
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
)
91 struct hostent
*hostent
;
92 struct servent
*servent
;
93 struct sockaddr_in sockaddr
;
96 nh
= malloc(sizeof(nntp_t
));
98 fprintf(stderr
, "%s: Out of memory.\n", PROGNAME
);
102 nh
->magic
= OURMAGIC
;
103 nh
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
105 fprintf(stderr
, "%s: %s\n", PROGNAME
, strerror(errno
));
109 sockaddr
.sin_family
= AF_INET
;
110 hostent
= gethostbyname(hostname
);
111 if(hostent
== NULL
) {
112 fprintf(stderr
, "%s: %s\n", PROGNAME
, strerror(errno
));
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
));
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
));
130 i
= nntp_readresponse(nh
, NULL
);
132 fprintf(stderr
, "%s: %s\n", PROGNAME
, responses
[i
/100][i
/10%10][i
%10]);
139 int nntp_readresponse(nntp_t
*nh
, char **resbody
)
142 int respnum
, blen
= 128, i
, bufp
;
144 buffer
= malloc(blen
);
146 fprintf(stderr
, "%s: Out of memory in nntp_readresponse.\n",
153 i
= read(nh
->sock
, buffer
+bufp
, 1);
155 fprintf(stderr
, "%s: %s\n", PROGNAME
, strerror(errno
));
163 buffer
= realloc(buffer
, blen
);
165 fprintf(stderr
, "%s: Out of memory in "
166 "nntp_readresponse.\n", PROGNAME
);
170 } while(!(buffer
[bufp
-2] == '\r' && buffer
[bufp
-1] == '\n'));
173 respnum
= atoi(buffer
);
182 int nntp_readheader(nntp_t
*nh
, char **header
)
185 int blen
= 128, i
, bufp
;
187 buffer
= malloc(blen
);
189 fprintf(stderr
, "%s: Out of memory in nntp_readheader.\n",
196 i
= read(nh
->sock
, buffer
+bufp
, 1);
198 fprintf(stderr
, "%s: %s\n", PROGNAME
, strerror(errno
));
206 buffer
= realloc(buffer
, blen
);
208 fprintf(stderr
, "%s: Out of memory in "
209 "nntp_readheader.\n", PROGNAME
);
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'))));
228 int nntp_readbody(nntp_t
*nh
, char **body
)
231 int blen
= 128, i
, bufp
;
233 buffer
= malloc(blen
);
235 fprintf(stderr
, "%s: Out of memory in nntp_readbody.\n", PROGNAME
);
241 i
= read(nh
->sock
, buffer
+bufp
, 1);
243 fprintf(stderr
, "%s: %s\n", PROGNAME
, strerror(errno
));
251 buffer
= realloc(buffer
, blen
);
253 fprintf(stderr
, "%s: Out of memory in "
254 "nntp_readbody.\n", PROGNAME
);
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'));
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",
282 write(nh
->sock
, "QUIT\r\n", strlen("QUIT\r\n"));
288 int nntp_cmd_group(void *nh_
, char *group
, int *narticles
, int *firstart
,
291 nntp_t
*nh
= (nntp_t
*)nh_
;
293 char *respbody
, *p
, *cmdbuf
;
295 if(nh
->magic
!= OURMAGIC
) {
296 fprintf(stderr
, "%s: magic check failed for nntp_cmd_group!\n",
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
));
307 i
= nntp_readresponse(nh
, &respbody
);
309 fprintf(stderr
, "%s: %s\n", PROGNAME
, responses
[i
/100][i
/10%10][i
%10]);
313 p
= strtok(respbody
, " \t\n");
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 */
327 #define MAXARTNUMLEN 10
329 int nntp_cmd_article(void *nh_
, int artnum
, char **head
, char **body
)
331 nntp_t
*nh
= (nntp_t
*)nh_
;
333 char *respbody
, *cmdbuf
, *cmd
;
335 if(nh
->magic
!= OURMAGIC
) {
336 fprintf(stderr
, "%s: magic check failed for nntp_cmd_article!\n",
340 if(head
== NULL
&& body
== NULL
)
342 else if(head
== NULL
)
344 else if(body
== NULL
)
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
));
353 i
= nntp_readresponse(nh
, &respbody
);
355 fprintf(stderr
, "%s: %s\n", PROGNAME
, responses
[i
/100][i
/10%10][i
%10]);
359 if(nntp_readheader(nh
, head
) != 0) {
360 fprintf(stderr
, "%s: failed to read header.\n", PROGNAME
);
364 if(nntp_readbody(nh
, body
) != 0) {
365 fprintf(stderr
, "%s: failed to read body.\n", PROGNAME
);