Statistics
| Revision:

root / src / nntp.c @ 1

History | View | Annotate | Download (9.12 KB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2004 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
#if USE_SSL
33
#  include "ssl.h"
34
#endif
35

    
36
static gint verbose = 1;
37

    
38
static void nntp_session_destroy(Session        *session);
39

    
40
static gint nntp_ok                (SockInfo        *sock,
41
                                 gchar                *argbuf);
42

    
43
static gint nntp_gen_send        (SockInfo        *sock,
44
                                 const gchar        *format,
45
                                 ...);
46
static gint nntp_gen_recv        (SockInfo        *sock,
47
                                 gchar                *buf,
48
                                 gint                 size);
49
static gint nntp_gen_command        (NNTPSession        *session,
50
                                 gchar                *argbuf,
51
                                 const gchar        *format,
52
                                 ...);
53

    
54

    
55
#if USE_SSL
56
Session *nntp_session_new(const gchar *server, gushort port, gchar *buf,
57
                          const gchar *userid, const gchar *passwd,
58
                          SSLType ssl_type)
59
#else
60
Session *nntp_session_new(const gchar *server, gushort port, gchar *buf,
61
                          const gchar *userid, const gchar *passwd)
62
#endif
63
{
64
        NNTPSession *session;
65
        SockInfo *sock;
66

    
67
        if ((sock = sock_connect(server, port)) == NULL) {
68
                log_warning(_("Can't connect to NNTP server: %s:%d\n"),
69
                            server, port);
70
                return NULL;
71
        }
72

    
73
#if USE_SSL
74
        if (ssl_type == SSL_TUNNEL && !ssl_init_socket(sock)) {
75
                sock_close(sock);
76
                return NULL;
77
        }
78
#endif
79

    
80
        if (nntp_ok(sock, buf) != NN_SUCCESS) {
81
                sock_close(sock);
82
                return NULL;
83
        }
84

    
85
        session = g_new0(NNTPSession, 1);
86

    
87
        session_init(SESSION(session));
88

    
89
        SESSION(session)->type                        = SESSION_NEWS;
90
        SESSION(session)->server                = g_strdup(server);
91
        SESSION(session)->sock                        = sock;
92
        SESSION(session)->last_access_time        = time(NULL);
93
        SESSION(session)->data                        = NULL;
94

    
95
        SESSION(session)->destroy                = nntp_session_destroy;
96

    
97
        session->group = NULL;
98

    
99
        if (userid && passwd) {
100
                gint ok;
101

    
102
                session->userid = g_strdup(userid);
103
                session->passwd = g_strdup(passwd);
104

    
105
                ok = nntp_gen_send(sock, "AUTHINFO USER %s", session->userid);
106
                if (ok != NN_SUCCESS) {
107
                        session_destroy(SESSION(session));
108
                        return NULL;
109
                }
110
                ok = nntp_ok(sock, NULL);
111
                if (ok == NN_AUTHCONT) {
112
                        ok = nntp_gen_send(sock, "AUTHINFO PASS %s",
113
                                           session->passwd);
114
                        if (ok != NN_SUCCESS) {
115
                                session_destroy(SESSION(session));
116
                                return NULL;
117
                        }
118
                        ok = nntp_ok(sock, NULL);
119
                        if (ok != NN_SUCCESS)
120
                                session->auth_failed = TRUE;
121
                }
122
                if (ok == NN_SOCKET) {
123
                        session_destroy(SESSION(session));
124
                        return NULL;
125
                }
126
        }
127

    
128
        session_set_access_time(SESSION(session));
129

    
130
        return SESSION(session);
131
}
132

    
133
static void nntp_session_destroy(Session *session)
134
{
135
        NNTPSession *nntp_session = NNTP_SESSION(session);
136

    
137
        g_return_if_fail(session != NULL);
138

    
139
        g_free(nntp_session->group);
140
        g_free(nntp_session->userid);
141
        g_free(nntp_session->passwd);
142
}
143

    
144
gint nntp_group(NNTPSession *session, const gchar *group,
145
                gint *num, gint *first, gint *last)
146
{
147
        gint ok;
148
        gint resp;
149
        gchar buf[NNTPBUFSIZE];
150

    
151
        ok = nntp_gen_command(session, buf, "GROUP %s", group);
152

    
153
        if (ok != NN_SUCCESS && ok != NN_SOCKET && ok != NN_AUTHREQ) {
154
                ok = nntp_mode(session, FALSE);
155
                if (ok == NN_SUCCESS)
156
                        ok = nntp_gen_command(session, buf, "GROUP %s", group);
157
        }
158

    
159
        if (ok != NN_SUCCESS)
160
                return ok;
161

    
162
        if (sscanf(buf, "%d %d %d %d", &resp, num, first, last)
163
            != 4) {
164
                log_warning(_("protocol error: %s\n"), buf);
165
                return NN_PROTOCOL;
166
        }
167

    
168
        return NN_SUCCESS;
169
}
170

    
171
gint nntp_get_article(NNTPSession *session, const gchar *cmd, gint num,
172
                      gchar **msgid)
173
{
174
        gint ok;
175
        gchar buf[NNTPBUFSIZE];
176

    
177
        if (num > 0)
178
                ok = nntp_gen_command(session, buf, "%s %d", cmd, num);
179
        else
180
                ok = nntp_gen_command(session, buf, cmd);
181

    
182
        if (ok != NN_SUCCESS)
183
                return ok;
184

    
185
        extract_parenthesis(buf, '<', '>');
186
        if (buf[0] == '\0') {
187
                log_warning(_("protocol error\n"));
188
                *msgid = g_strdup("0");
189
        } else
190
                *msgid = g_strdup(buf);
191

    
192
        return NN_SUCCESS;
193
}
194

    
195
gint nntp_article(NNTPSession *session, gint num, gchar **msgid)
196
{
197
        return nntp_get_article(session, "ARTICLE", num, msgid);
198
}
199

    
200
gint nntp_body(NNTPSession *session, gint num, gchar **msgid)
201
{
202
        return nntp_get_article(session, "BODY", num, msgid);
203
}
204

    
205
gint nntp_head(NNTPSession *session, gint num, gchar **msgid)
206
{
207
        return nntp_get_article(session, "HEAD", num, msgid);
208
}
209

    
210
gint nntp_stat(NNTPSession *session, gint num, gchar **msgid)
211
{
212
        return nntp_get_article(session, "STAT", num, msgid);
213
}
214

    
215
gint nntp_next(NNTPSession *session, gint *num, gchar **msgid)
216
{
217
        gint ok;
218
        gint resp;
219
        gchar buf[NNTPBUFSIZE];
220

    
221
        ok = nntp_gen_command(session, buf, "NEXT");
222

    
223
        if (ok != NN_SUCCESS)
224
                return ok;
225

    
226
        if (sscanf(buf, "%d %d", &resp, num) != 2) {
227
                log_warning(_("protocol error: %s\n"), buf);
228
                return NN_PROTOCOL;
229
        }
230

    
231
        extract_parenthesis(buf, '<', '>');
232
        if (buf[0] == '\0') {
233
                log_warning(_("protocol error\n"));
234
                return NN_PROTOCOL;
235
        }
236
        *msgid = g_strdup(buf);
237

    
238
        return NN_SUCCESS;
239
}
240

    
241
gint nntp_xover(NNTPSession *session, gint first, gint last)
242
{
243
        gint ok;
244
        gchar buf[NNTPBUFSIZE];
245

    
246
        ok = nntp_gen_command(session, buf, "XOVER %d-%d", first, last);
247
        if (ok != NN_SUCCESS)
248
                return ok;
249

    
250
        return NN_SUCCESS;
251
}
252

    
253
gint nntp_xhdr(NNTPSession *session, const gchar *header, gint first, gint last)
254
{
255
        gint ok;
256
        gchar buf[NNTPBUFSIZE];
257

    
258
        ok = nntp_gen_command(session, buf, "XHDR %s %d-%d",
259
                              header, first, last);
260
        if (ok != NN_SUCCESS)
261
                return ok;
262

    
263
        return NN_SUCCESS;
264
}
265

    
266
gint nntp_list(NNTPSession *session)
267
{
268
        return nntp_gen_command(session, NULL, "LIST");
269
}
270

    
271
gint nntp_post(NNTPSession *session, FILE *fp)
272
{
273
        gint ok;
274
        gchar buf[NNTPBUFSIZE];
275
        gchar *msg;
276

    
277
        ok = nntp_gen_command(session, buf, "POST");
278
        if (ok != NN_SUCCESS)
279
                return ok;
280

    
281
        msg = get_outgoing_rfc2822_str(fp);
282
        if (sock_write_all(SESSION(session)->sock, msg, strlen(msg)) < 0) {
283
                log_warning(_("Error occurred while posting\n"));
284
                g_free(msg);
285
                return NN_SOCKET;
286
        }
287
        g_free(msg);
288

    
289
        sock_write_all(SESSION(session)->sock, ".\r\n", 3);
290
        if ((ok = nntp_ok(SESSION(session)->sock, buf)) != NN_SUCCESS)
291
                return ok;
292

    
293
        session_set_access_time(SESSION(session));
294

    
295
        return NN_SUCCESS;
296
}
297

    
298
gint nntp_newgroups(NNTPSession *session)
299
{
300
        return NN_SUCCESS;
301
}
302

    
303
gint nntp_newnews(NNTPSession *session)
304
{
305
        return NN_SUCCESS;
306
}
307

    
308
gint nntp_mode(NNTPSession *session, gboolean stream)
309
{
310
        gint ok;
311

    
312
        ok = nntp_gen_command(session, NULL, "MODE %s",
313
                              stream ? "STREAM" : "READER");
314

    
315
        return ok;
316
}
317

    
318
static gint nntp_ok(SockInfo *sock, gchar *argbuf)
319
{
320
        gint ok;
321
        gchar buf[NNTPBUFSIZE];
322

    
323
        if ((ok = nntp_gen_recv(sock, buf, sizeof(buf))) == NN_SUCCESS) {
324
                if (strlen(buf) < 3)
325
                        return NN_ERROR;
326

    
327
                if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') &&
328
                    (buf[3] == ' ' || buf[3] == '\0')) {
329
                        if (argbuf)
330
                                strcpy(argbuf, buf);
331

    
332
                        if (!strncmp(buf, "381", 3))
333
                                return NN_AUTHCONT;
334

    
335
                        return NN_SUCCESS;
336
                } else if (!strncmp(buf, "480", 3))
337
                        return NN_AUTHREQ;
338
                else
339
                        return NN_ERROR;
340
        }
341

    
342
        return ok;
343
}
344

    
345
static gint nntp_gen_send(SockInfo *sock, const gchar *format, ...)
346
{
347
        gchar buf[NNTPBUFSIZE];
348
        va_list args;
349

    
350
        va_start(args, format);
351
        g_vsnprintf(buf, sizeof(buf), format, args);
352
        va_end(args);
353

    
354
        if (verbose) {
355
                if (!g_strncasecmp(buf, "AUTHINFO PASS", 13))
356
                        log_print("NNTP> AUTHINFO PASS ********\n");
357
                else
358
                        log_print("NNTP> %s\n", buf);
359
        }
360

    
361
        strcat(buf, "\r\n");
362
        if (sock_write_all(sock, buf, strlen(buf)) < 0) {
363
                log_warning(_("Error occurred while sending command\n"));
364
                return NN_SOCKET;
365
        }
366

    
367
        return NN_SUCCESS;
368
}
369

    
370
static gint nntp_gen_recv(SockInfo *sock, gchar *buf, gint size)
371
{
372
        if (sock_gets(sock, buf, size) == -1)
373
                return NN_SOCKET;
374

    
375
        strretchomp(buf);
376

    
377
        if (verbose)
378
                log_print("NNTP< %s\n", buf);
379

    
380
        return NN_SUCCESS;
381
}
382

    
383
static gint nntp_gen_command(NNTPSession *session, gchar *argbuf,
384
                             const gchar *format, ...)
385
{
386
        gchar buf[NNTPBUFSIZE];
387
        va_list args;
388
        gint ok;
389
        SockInfo *sock;
390

    
391
        va_start(args, format);
392
        g_vsnprintf(buf, sizeof(buf), format, args);
393
        va_end(args);
394

    
395
        sock = SESSION(session)->sock;
396
        ok = nntp_gen_send(sock, "%s", buf);
397
        if (ok != NN_SUCCESS)
398
                return ok;
399
        ok = nntp_ok(sock, argbuf);
400
        if (ok == NN_AUTHREQ) {
401
                if (!session->userid || !session->passwd) {
402
                        session->auth_failed = TRUE;
403
                        return ok;
404
                }
405

    
406
                ok = nntp_gen_send(sock, "AUTHINFO USER %s", session->userid);
407
                if (ok != NN_SUCCESS)
408
                        return ok;
409
                ok = nntp_ok(sock, NULL);
410
                if (ok == NN_AUTHCONT) {
411
                        ok = nntp_gen_send(sock, "AUTHINFO PASS %s",
412
                                           session->passwd);
413
                        if (ok != NN_SUCCESS)
414
                                return ok;
415
                        ok = nntp_ok(sock, NULL);
416
                }
417
                if (ok != NN_SUCCESS) {
418
                        session->auth_failed = TRUE;
419
                        return ok;
420
                }
421

    
422
                ok = nntp_gen_send(sock, "%s", buf);
423
                if (ok != NN_SUCCESS)
424
                        return ok;
425
                ok = nntp_ok(sock, argbuf);
426
        }
427

    
428
        session_set_access_time(SESSION(session));
429

    
430
        return ok;
431
}