Statistics
| Revision:

root / libsylph / nntp.c @ 2090

History | View | Annotate | Download (9.1 kB)

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