added comments in news.c and nntp.c
[claws.git] / src / nntp.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999,2000 Hiroyuki Yamamoto
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <glib.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "intl.h"
29 #include "nntp.h"
30 #include "socket.h"
31 #include "utils.h"
32
33 static gint verbose = 1;
34
35 static void nntp_gen_send(gint sock, const gchar *format, ...);
36 static gint nntp_gen_recv(gint sock, gchar *buf, gint size);
37
38 gint nntp_open(const gchar *server, gushort port, gchar *buf)
39 {
40         SockInfo *sockinfo;
41         gint sock;
42
43         if ((sockinfo = sock_connect(server, port)) == NULL) {
44                 log_warning(_("Can't connect to NNTP server: %s:%d\n"),
45                             server, port);
46                 return -1;
47         }
48         sock = sockinfo->sock;
49         sock_sockinfo_free(sockinfo);
50
51         if (nntp_ok(sock, buf) == NN_SUCCESS)
52                 return sock;
53         else {
54                 sock_close(sock);
55                 return -1;
56         }
57 }
58
59 gint nntp_group(gint sock, const gchar *group,
60                 gint *num, gint *first, gint *last)
61 {
62         gint ok;
63         gint resp;
64         gchar buf[NNTPBUFSIZE];
65
66         nntp_gen_send(sock, "GROUP %s", group);
67
68         if ((ok = nntp_ok(sock, buf)) != NN_SUCCESS)
69                 return ok;
70
71         if (sscanf(buf, "%d %d %d %d", &resp, num, first, last)
72             != 4) {
73                 log_warning(_("protocol error: %s\n"), buf);
74                 return NN_PROTOCOL;
75         }
76
77         return NN_SUCCESS;
78 }
79
80 gint nntp_get_article(gint sock, const gchar *cmd, gint num, gchar **msgid)
81 {
82         gint ok;
83         gchar buf[NNTPBUFSIZE];
84
85         if (num > 0)
86                 nntp_gen_send(sock, "%s %d", cmd, num);
87         else
88                 nntp_gen_send(sock, cmd);
89
90         if ((ok = nntp_ok(sock, buf)) != NN_SUCCESS)
91                 return ok;
92
93         extract_parenthesis(buf, '<', '>');
94         if (buf[0] == '\0') {
95                 log_warning(_("protocol error\n"));
96                 return NN_PROTOCOL;
97         }
98         *msgid = g_strdup(buf);
99
100         return NN_SUCCESS;
101 }
102
103 gint nntp_article(gint sock, gint num, gchar **msgid)
104 {
105         return nntp_get_article(sock, "ARTICLE", num, msgid);
106 }
107
108 gint nntp_body(gint sock, gint num, gchar **msgid)
109 {
110         return nntp_get_article(sock, "BODY", num, msgid);
111 }
112
113 gint nntp_head(gint sock, gint num, gchar **msgid)
114 {
115         return nntp_get_article(sock, "HEAD", num, msgid);
116 }
117
118 gint nntp_stat(gint sock, gint num, gchar **msgid)
119 {
120         return nntp_get_article(sock, "STAT", num, msgid);
121 }
122
123 gint nntp_next(gint sock, gint *num, gchar **msgid)
124 {
125         gint ok;
126         gint resp;
127         gchar buf[NNTPBUFSIZE];
128
129         nntp_gen_send(sock, "NEXT");
130
131         if ((ok = nntp_ok(sock, buf)) != NN_SUCCESS)
132                 return ok;
133
134         if (sscanf(buf, "%d %d", &resp, num) != 2) {
135                 log_warning(_("protocol error: %s\n"), buf);
136                 return NN_PROTOCOL;
137         }
138
139         extract_parenthesis(buf, '<', '>');
140         if (buf[0] == '\0') {
141                 log_warning(_("protocol error\n"));
142                 return NN_PROTOCOL;
143         }
144         *msgid = g_strdup(buf);
145
146         return NN_SUCCESS;
147 }
148
149 gint nntp_xover(gint sock, gint first, gint last)
150 {
151         gint ok;
152         gchar buf[NNTPBUFSIZE];
153
154         nntp_gen_send(sock, "XOVER %d-%d", first, last);
155         if ((ok = nntp_ok(sock, buf)) != NN_SUCCESS)
156                 return ok;
157
158         return NN_SUCCESS;
159 }
160
161 gint nntp_post(gint sock, FILE *fp)
162 {
163         gint ok;
164         gchar buf[NNTPBUFSIZE];
165
166         nntp_gen_send(sock, "POST");
167         if ((ok = nntp_ok(sock, buf)) != NN_SUCCESS)
168                 return ok;
169
170         while (fgets(buf, sizeof(buf), fp) != NULL) {
171                 strretchomp(buf);
172                 if (buf[0] == '.') {
173                         if (sock_write(sock, ".", 1) < 0) {
174                                 log_warning(_("Error occurred while posting\n"));
175                                 return NN_SOCKET;
176                         }
177                 }
178
179                 if (sock_puts(sock, buf) < 0) {
180                         log_warning(_("Error occurred while posting\n"));
181                         return NN_SOCKET;
182                 }
183         }
184
185         sock_write(sock, ".\r\n", 3);
186         if ((ok = nntp_ok(sock, buf)) != NN_SUCCESS)
187                 return ok;
188
189         return NN_SUCCESS;
190 }
191
192 gint nntp_newgroups(gint sock)
193 {
194         return NN_SUCCESS;
195 }
196
197 gint nntp_newnews(gint sock)
198 {
199         return NN_SUCCESS;
200 }
201
202 gint nntp_mode(gint sock, gboolean stream)
203 {
204         gint ok;
205
206         nntp_gen_send(sock, "MODE %s", stream ? "STREAM" : "READER");
207         ok = nntp_ok(sock, NULL);
208
209         return ok;
210 }
211
212 gint nntp_ok(gint sock, gchar *argbuf)
213 {
214         gint ok;
215         gchar buf[NNTPBUFSIZE];
216
217         if ((ok = nntp_gen_recv(sock, buf, sizeof(buf))) == NN_SUCCESS) {
218                 if (strlen(buf) < 4)
219                         return NN_ERROR;
220
221                 if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') &&
222                     buf[3] == ' ') {
223                         if (argbuf)
224                                 strcpy(argbuf, buf);
225
226                         return NN_SUCCESS;
227                 } else
228                         return NN_ERROR;
229         }
230
231         return ok;
232 }
233
234 static void nntp_gen_send(gint sock, const gchar *format, ...)
235 {
236         gchar buf[NNTPBUFSIZE];
237         va_list args;
238
239         va_start(args, format);
240         g_vsnprintf(buf, sizeof(buf), format, args);
241         va_end(args);
242
243         if (verbose)
244                 log_print("NNTP> %s\n", buf);
245
246         strcat(buf, "\r\n");
247         sock_write(sock, buf, strlen(buf));
248 }
249
250 static gint nntp_gen_recv(gint sock, gchar *buf, gint size)
251 {
252         if (sock_read(sock, buf, size) == -1)
253                 return NN_SOCKET;
254
255         strretchomp(buf);
256
257         if (verbose)
258                 log_print("NNTP< %s\n", buf);
259
260         return NN_SUCCESS;
261 }
262
263 /*
264   nntp_list sends the command "LIST" to the news server,
265   a function is needed to read the newsgroups list.
266  */
267
268 gint nntp_list(gint sock)
269 {
270         GList * result = NULL;
271
272         gint ok;
273         gint resp;
274         gchar buf[NNTPBUFSIZE];
275
276         nntp_gen_send(sock, "LIST");
277
278         if ((ok = nntp_ok(sock, buf)) != NN_SUCCESS)
279                 return NN_ERROR;
280
281         if (verbose)
282                 log_print("NNTP< %s\n", buf);
283
284         return NN_SUCCESS;
285 }