summaryrefslogtreecommitdiff
path: root/libsylph/nntp.c
diff options
context:
space:
mode:
authorSimeon Simeonov2018-02-26 11:23:00 +0100
committerSimeon Simeonov2018-02-26 11:23:00 +0100
commit0b3cbf57875fd692e4ba0b336fefa4bee1ed00dc (patch)
treeaf916a30553c78ce9d4f2d8658656a175c5b6921 /libsylph/nntp.c
Initial commit for sylpheed 3.7.0
Diffstat (limited to 'libsylph/nntp.c')
-rw-r--r--libsylph/nntp.c471
1 files changed, 471 insertions, 0 deletions
diff --git a/libsylph/nntp.c b/libsylph/nntp.c
new file mode 100644
index 0000000..64c9da1
--- /dev/null
+++ b/libsylph/nntp.c
@@ -0,0 +1,471 @@
1/*
2 * LibSylph -- E-Mail client library
3 * Copyright (C) 1999-2012 Hiroyuki Yamamoto
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library 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 GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21# include "config.h"
22#endif
23
24#include <glib.h>
25#include <glib/gi18n.h>
26#include <stdio.h>
27#include <string.h>
28
29#include "nntp.h"
30#include "socket.h"
31#include "utils.h"
32#if USE_SSL
33# include "ssl.h"
34#endif
35#include "socks.h"
36
37static gint verbose = 1;
38
39static void nntp_session_destroy(Session *session);
40
41static gint nntp_ok (SockInfo *sock,
42 gchar *argbuf);
43
44static gint nntp_gen_send (SockInfo *sock,
45 const gchar *format,
46 ...);
47static gint nntp_gen_recv (SockInfo *sock,
48 gchar *buf,
49 gint size);
50static gint nntp_gen_command (NNTPSession *session,
51 gchar *argbuf,
52 const gchar *format,
53 ...);
54
55
56#if USE_SSL
57Session *nntp_session_new_full(const gchar *server, gushort port,
58 SocksInfo *socks_info, gchar *buf,
59 const gchar *userid, const gchar *passwd,
60 SSLType ssl_type)
61#else
62Session *nntp_session_new_full(const gchar *server, gushort port,
63 SocksInfo *socks_info, gchar *buf,
64 const gchar *userid, const gchar *passwd)
65#endif
66{
67 NNTPSession *session;
68 SockInfo *sock;
69 const gchar *server_;
70 gushort port_;
71
72 if (socks_info) {
73 server_ = socks_info->proxy_host;
74 port_ = socks_info->proxy_port;
75 } else {
76 server_ = server;
77 port_ = port;
78 }
79
80 if ((sock = sock_connect(server_, port_)) == NULL) {
81 log_warning(_("Can't connect to NNTP server: %s:%d\n"),
82 server, port);
83 return NULL;
84 }
85
86 if (socks_info) {
87 if (socks_connect(sock, server, port, socks_info) < 0) {
88 log_warning("Can't establish SOCKS connection: %s:%d\n",
89 server, port);
90 sock_close(sock);
91 return NULL;
92 }
93 }
94
95#if USE_SSL
96 if (ssl_type == SSL_TUNNEL && !ssl_init_socket(sock)) {
97 log_warning("Can't establish NNTP session with: %s:%d\n",
98 server, port);
99 sock_close(sock);
100 return NULL;
101 }
102#endif
103
104 if (nntp_ok(sock, buf) != NN_SUCCESS) {
105 sock_close(sock);
106 return NULL;
107 }
108
109 session = g_new0(NNTPSession, 1);
110
111 session_init(SESSION(session));
112
113 SESSION(session)->type = SESSION_NEWS;
114 SESSION(session)->server = g_strdup(server);
115 SESSION(session)->sock = sock;
116 SESSION(session)->last_access_time = time(NULL);
117 SESSION(session)->data = NULL;
118
119 SESSION(session)->destroy = nntp_session_destroy;
120
121 session->group = NULL;
122
123 if (userid && passwd) {
124 gint ok;
125
126 session->userid = g_strdup(userid);
127 session->passwd = g_strdup(passwd);
128
129 ok = nntp_gen_send(sock, "AUTHINFO USER %s", session->userid);
130 if (ok != NN_SUCCESS) {
131 session_destroy(SESSION(session));
132 return NULL;
133 }
134 ok = nntp_ok(sock, NULL);
135 if (ok == NN_AUTHCONT) {
136 ok = nntp_gen_send(sock, "AUTHINFO PASS %s",
137 session->passwd);
138 if (ok != NN_SUCCESS) {
139 session_destroy(SESSION(session));
140 return NULL;
141 }
142 ok = nntp_ok(sock, NULL);
143 if (ok != NN_SUCCESS)
144 session->auth_failed = TRUE;
145 }
146 if (ok == NN_SOCKET) {
147 session_destroy(SESSION(session));
148 return NULL;
149 }
150 }
151
152 session_set_access_time(SESSION(session));
153
154 return SESSION(session);
155}
156
157#if USE_SSL
158Session *nntp_session_new(const gchar *server, gushort port, gchar *buf,
159 const gchar *userid, const gchar *passwd,
160 SSLType ssl_type)
161{
162 return nntp_session_new_full(server, port, NULL, buf, userid, passwd,
163 ssl_type);
164}
165#else
166Session *nntp_session_new(const gchar *server, gushort port, gchar *buf,
167 const gchar *userid, const gchar *passwd)
168{
169 return nntp_session_new_full(server, port, NULL, buf, userid, passwd);
170}
171#endif
172
173static void nntp_session_destroy(Session *session)
174{
175 NNTPSession *nntp_session = NNTP_SESSION(session);
176
177 g_return_if_fail(session != NULL);
178
179 g_free(nntp_session->group);
180 g_free(nntp_session->userid);
181 g_free(nntp_session->passwd);
182}
183
184gint nntp_group(NNTPSession *session, const gchar *group,
185 gint *num, gint *first, gint *last)
186{
187 gint ok;
188 gint resp;
189 gchar buf[NNTPBUFSIZE];
190
191 ok = nntp_gen_command(session, buf, "GROUP %s", group);
192
193 if (ok != NN_SUCCESS && ok != NN_SOCKET && ok != NN_AUTHREQ) {
194 ok = nntp_mode(session, FALSE);
195 if (ok == NN_SUCCESS)
196 ok = nntp_gen_command(session, buf, "GROUP %s", group);
197 }
198
199 if (ok != NN_SUCCESS)
200 return ok;
201
202 if (sscanf(buf, "%d %d %d %d", &resp, num, first, last)
203 != 4) {
204 log_warning(_("protocol error: %s\n"), buf);
205 return NN_PROTOCOL;
206 }
207
208 return NN_SUCCESS;
209}
210
211gint nntp_get_article(NNTPSession *session, const gchar *cmd, gint num,
212 gchar **msgid)
213{
214 gint ok;
215 gchar buf[NNTPBUFSIZE];
216
217 if (num > 0)
218 ok = nntp_gen_command(session, buf, "%s %d", cmd, num);
219 else
220 ok = nntp_gen_command(session, buf, cmd);
221
222 if (ok != NN_SUCCESS)
223 return ok;
224
225 extract_parenthesis(buf, '<', '>');
226 if (buf[0] == '\0') {
227 log_warning(_("protocol error\n"));
228 *msgid = g_strdup("0");
229 } else
230 *msgid = g_strdup(buf);
231
232 return NN_SUCCESS;
233}
234
235gint nntp_article(NNTPSession *session, gint num, gchar **msgid)
236{
237 return nntp_get_article(session, "ARTICLE", num, msgid);
238}
239
240gint nntp_body(NNTPSession *session, gint num, gchar **msgid)
241{
242 return nntp_get_article(session, "BODY", num, msgid);
243}
244
245gint nntp_head(NNTPSession *session, gint num, gchar **msgid)
246{
247 return nntp_get_article(session, "HEAD", num, msgid);
248}
249
250gint nntp_stat(NNTPSession *session, gint num, gchar **msgid)
251{
252 return nntp_get_article(session, "STAT", num, msgid);
253}
254
255gint nntp_next(NNTPSession *session, gint *num, gchar **msgid)
256{
257 gint ok;
258 gint resp;
259 gchar buf[NNTPBUFSIZE];
260
261 ok = nntp_gen_command(session, buf, "NEXT");
262
263 if (ok != NN_SUCCESS)
264 return ok;
265
266 if (sscanf(buf, "%d %d", &resp, num) != 2) {
267 log_warning(_("protocol error: %s\n"), buf);
268 return NN_PROTOCOL;
269 }
270
271 extract_parenthesis(buf, '<', '>');
272 if (buf[0] == '\0') {
273 log_warning(_("protocol error\n"));
274 return NN_PROTOCOL;
275 }
276 *msgid = g_strdup(buf);
277
278 return NN_SUCCESS;
279}
280
281gint nntp_xover(NNTPSession *session, gint first, gint last)
282{
283 gint ok;
284 gchar buf[NNTPBUFSIZE];
285
286 ok = nntp_gen_command(session, buf, "XOVER %d-%d", first, last);
287 if (ok != NN_SUCCESS)
288 return ok;
289
290 return NN_SUCCESS;
291}
292
293gint nntp_xhdr(NNTPSession *session, const gchar *header, gint first, gint last)
294{
295 gint ok;
296 gchar buf[NNTPBUFSIZE];
297
298 ok = nntp_gen_command(session, buf, "XHDR %s %d-%d",
299 header, first, last);
300 if (ok != NN_SUCCESS)
301 return ok;
302
303 return NN_SUCCESS;
304}
305
306gint nntp_list(NNTPSession *session)
307{
308 return nntp_gen_command(session, NULL, "LIST");
309}
310
311gint nntp_post(NNTPSession *session, FILE *fp)
312{
313 gint ok;
314 gchar buf[NNTPBUFSIZE];
315 gchar *msg;
316
317 ok = nntp_gen_command(session, buf, "POST");
318 if (ok != NN_SUCCESS)
319 return ok;
320
321 msg = get_outgoing_rfc2822_str(fp);
322 if (sock_write_all(SESSION(session)->sock, msg, strlen(msg)) < 0) {
323 log_warning(_("Error occurred while posting\n"));
324 g_free(msg);
325 return NN_SOCKET;
326 }
327 g_free(msg);
328
329 sock_write_all(SESSION(session)->sock, ".\r\n", 3);
330 if ((ok = nntp_ok(SESSION(session)->sock, buf)) != NN_SUCCESS)
331 return ok;
332
333 session_set_access_time(SESSION(session));
334
335 return NN_SUCCESS;
336}
337
338gint nntp_newgroups(NNTPSession *session)
339{
340 return NN_SUCCESS;
341}
342
343gint nntp_newnews(NNTPSession *session)
344{
345 return NN_SUCCESS;
346}
347
348gint nntp_mode(NNTPSession *session, gboolean stream)
349{
350 gint ok;
351
352 ok = nntp_gen_command(session, NULL, "MODE %s",
353 stream ? "STREAM" : "READER");
354
355 return ok;
356}
357
358static gint nntp_ok(SockInfo *sock, gchar *argbuf)
359{
360 gint ok;
361 gchar buf[NNTPBUFSIZE];
362
363 if ((ok = nntp_gen_recv(sock, buf, sizeof(buf))) == NN_SUCCESS) {
364 if (strlen(buf) < 3)
365 return NN_ERROR;
366
367 if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') &&
368 (buf[3] == ' ' || buf[3] == '\0')) {
369 if (argbuf)
370 strcpy(argbuf, buf);
371
372 if (!strncmp(buf, "381", 3))
373 return NN_AUTHCONT;
374
375 return NN_SUCCESS;
376 } else if (!strncmp(buf, "480", 3))
377 return NN_AUTHREQ;
378 else
379 return NN_ERROR;
380 }
381
382 return ok;
383}
384
385static gint nntp_gen_send(SockInfo *sock, const gchar *format, ...)
386{
387 gchar buf[NNTPBUFSIZE];
388 va_list args;
389
390 va_start(args, format);
391 g_vsnprintf(buf, sizeof(buf), format, args);
392 va_end(args);
393
394 if (verbose) {
395 if (!g_ascii_strncasecmp(buf, "AUTHINFO PASS", 13))
396 log_print("NNTP> AUTHINFO PASS ********\n");
397 else
398 log_print("NNTP> %s\n", buf);
399 }
400
401 strcat(buf, "\r\n");
402 if (sock_write_all(sock, buf, strlen(buf)) < 0) {
403 log_warning(_("Error occurred while sending command\n"));
404 return NN_SOCKET;
405 }
406
407 return NN_SUCCESS;
408}
409
410static gint nntp_gen_recv(SockInfo *sock, gchar *buf, gint size)
411{
412 if (sock_gets(sock, buf, size) == -1)
413 return NN_SOCKET;
414
415 strretchomp(buf);
416
417 if (verbose)
418 log_print("NNTP< %s\n", buf);
419
420 return NN_SUCCESS;
421}
422
423static gint nntp_gen_command(NNTPSession *session, gchar *argbuf,
424 const gchar *format, ...)
425{
426 gchar buf[NNTPBUFSIZE];
427 va_list args;
428 gint ok;
429 SockInfo *sock;
430
431 va_start(args, format);
432 g_vsnprintf(buf, sizeof(buf), format, args);
433 va_end(args);
434
435 sock = SESSION(session)->sock;
436 ok = nntp_gen_send(sock, "%s", buf);
437 if (ok != NN_SUCCESS)
438 return ok;
439 ok = nntp_ok(sock, argbuf);
440 if (ok == NN_AUTHREQ) {
441 if (!session->userid || !session->passwd) {
442 session->auth_failed = TRUE;
443 return ok;
444 }
445
446 ok = nntp_gen_send(sock, "AUTHINFO USER %s", session->userid);
447 if (ok != NN_SUCCESS)
448 return ok;
449 ok = nntp_ok(sock, NULL);
450 if (ok == NN_AUTHCONT) {
451 ok = nntp_gen_send(sock, "AUTHINFO PASS %s",
452 session->passwd);
453 if (ok != NN_SUCCESS)
454 return ok;
455 ok = nntp_ok(sock, NULL);
456 }
457 if (ok != NN_SUCCESS) {
458 session->auth_failed = TRUE;
459 return ok;
460 }
461
462 ok = nntp_gen_send(sock, "%s", buf);
463 if (ok != NN_SUCCESS)
464 return ok;
465 ok = nntp_ok(sock, argbuf);
466 }
467
468 session_set_access_time(SESSION(session));
469
470 return ok;
471}