2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
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 3 of the License, or
8 * (at your option) any later version.
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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include <glib/gi18n.h>
42 static gint verbose
= 1;
44 static void nntp_session_destroy(Session
*session
);
46 static gint
nntp_ok (SockInfo
*sock
,
49 static gint
nntp_gen_send (SockInfo
*sock
,
52 static gint
nntp_gen_recv (SockInfo
*sock
,
55 static gint
nntp_gen_command (NNTPSession
*session
,
61 Session
*nntp_session_new(const gchar
*server
, gushort port
, gchar
*buf
,
62 const gchar
*userid
, const gchar
*passwd
,
65 Session
*nntp_session_new(const gchar
*server
, gushort port
, gchar
*buf
,
66 const gchar
*userid
, const gchar
*passwd
)
72 if ((sock
= sock_connect(server
, port
)) == NULL
) {
73 log_warning(LOG_PROTOCOL
, _("Can't connect to NNTP server: %s:%d\n"),
79 if (ssl_type
== SSL_TUNNEL
&& !ssl_init_socket(sock
)) {
80 log_error(LOG_PROTOCOL
, _("SSL handshake failed\n"));
86 if (nntp_ok(sock
, buf
) != NN_SUCCESS
) {
91 session
= g_new0(NNTPSession
, 1);
93 session_init(SESSION(session
));
95 SESSION(session
)->type
= SESSION_NEWS
;
96 SESSION(session
)->server
= g_strdup(server
);
97 SESSION(session
)->sock
= sock
;
98 SESSION(session
)->last_access_time
= time(NULL
);
99 SESSION(session
)->data
= NULL
;
101 SESSION(session
)->destroy
= nntp_session_destroy
;
103 session
->group
= NULL
;
105 nntp_mode(session
, FALSE
);
107 if (userid
&& passwd
) {
110 session
->userid
= g_strdup(userid
);
111 session
->passwd
= g_strdup(passwd
);
113 ok
= nntp_gen_send(sock
, "AUTHINFO USER %s", session
->userid
);
114 if (ok
!= NN_SUCCESS
) {
115 session_destroy(SESSION(session
));
118 ok
= nntp_ok(sock
, NULL
);
119 if (ok
== NN_AUTHCONT
) {
120 ok
= nntp_gen_send(sock
, "AUTHINFO PASS %s",
122 if (ok
!= NN_SUCCESS
) {
123 session_destroy(SESSION(session
));
126 ok
= nntp_ok(sock
, NULL
);
127 if (ok
!= NN_SUCCESS
)
128 session
->auth_failed
= TRUE
;
130 if (ok
== NN_SOCKET
) {
131 session_destroy(SESSION(session
));
136 session_set_access_time(SESSION(session
));
138 return SESSION(session
);
141 void nntp_forceauth(NNTPSession
*session
, gchar
*buf
, const gchar
*userid
, const gchar
*passwd
)
144 if (!session
) return;
146 nntp_gen_command(session
, buf
, "AUTHINFO USER %s", userid
);
151 static void nntp_session_destroy(Session
*session
)
153 NNTPSession
*nntp_session
= NNTP_SESSION(session
);
155 g_return_if_fail(session
!= NULL
);
157 g_free(nntp_session
->group
);
158 g_free(nntp_session
->userid
);
159 g_free(nntp_session
->passwd
);
162 gint
nntp_group(NNTPSession
*session
, const gchar
*group
,
163 gint
*num
, gint
*first
, gint
*last
)
167 gchar buf
[NNTPBUFSIZE
];
169 ok
= nntp_gen_command(session
, buf
, "GROUP %s", group
);
171 if (ok
!= NN_SUCCESS
&& ok
!= NN_SOCKET
&& ok
!= NN_AUTHREQ
) {
172 ok
= nntp_mode(session
, FALSE
);
173 if (ok
== NN_SUCCESS
)
174 ok
= nntp_gen_command(session
, buf
, "GROUP %s", group
);
177 if (ok
!= NN_SUCCESS
)
180 if (sscanf(buf
, "%d %d %d %d", &resp
, num
, first
, last
)
182 log_warning(LOG_PROTOCOL
, _("protocol error: %s\n"), buf
);
189 gint
nntp_get_article(NNTPSession
*session
, const gchar
*cmd
, gint num
,
193 gchar buf
[NNTPBUFSIZE
];
196 ok
= nntp_gen_command(session
, buf
, "%s %d", cmd
, num
);
198 ok
= nntp_gen_command(session
, buf
, cmd
);
200 if (ok
!= NN_SUCCESS
)
203 extract_parenthesis(buf
, '<', '>');
204 if (buf
[0] == '\0') {
205 log_warning(LOG_PROTOCOL
, _("protocol error\n"));
206 *msgid
= g_strdup("0");
208 *msgid
= g_strdup(buf
);
213 gint
nntp_article(NNTPSession
*session
, gint num
, gchar
**msgid
)
215 return nntp_get_article(session
, "ARTICLE", num
, msgid
);
218 gint
nntp_body(NNTPSession
*session
, gint num
, gchar
**msgid
)
220 return nntp_get_article(session
, "BODY", num
, msgid
);
223 gint
nntp_head(NNTPSession
*session
, gint num
, gchar
**msgid
)
225 return nntp_get_article(session
, "HEAD", num
, msgid
);
228 gint
nntp_stat(NNTPSession
*session
, gint num
, gchar
**msgid
)
230 return nntp_get_article(session
, "STAT", num
, msgid
);
233 gint
nntp_next(NNTPSession
*session
, gint
*num
, gchar
**msgid
)
237 gchar buf
[NNTPBUFSIZE
];
239 ok
= nntp_gen_command(session
, buf
, "NEXT");
241 if (ok
!= NN_SUCCESS
)
244 if (sscanf(buf
, "%d %d", &resp
, num
) != 2) {
245 log_warning(LOG_PROTOCOL
, _("protocol error: %s\n"), buf
);
249 extract_parenthesis(buf
, '<', '>');
250 if (buf
[0] == '\0') {
251 log_warning(LOG_PROTOCOL
, _("protocol error\n"));
254 *msgid
= g_strdup(buf
);
259 gint
nntp_xover(NNTPSession
*session
, gint first
, gint last
)
262 gchar buf
[NNTPBUFSIZE
];
264 ok
= nntp_gen_command(session
, buf
, "XOVER %d-%d", first
, last
);
265 if (ok
!= NN_SUCCESS
)
271 gint
nntp_xhdr(NNTPSession
*session
, const gchar
*header
, gint first
, gint last
)
274 gchar buf
[NNTPBUFSIZE
];
276 ok
= nntp_gen_command(session
, buf
, "XHDR %s %d-%d",
277 header
, first
, last
);
278 if (ok
!= NN_SUCCESS
)
284 gint
nntp_list(NNTPSession
*session
)
286 return nntp_gen_command(session
, NULL
, "LIST");
289 gint
nntp_post(NNTPSession
*session
, FILE *fp
)
292 gchar buf
[NNTPBUFSIZE
];
295 ok
= nntp_gen_command(session
, buf
, "POST");
296 if (ok
!= NN_SUCCESS
)
299 msg
= get_outgoing_rfc2822_str(fp
);
300 if (sock_write_all(SESSION(session
)->sock
, msg
, strlen(msg
)) < 0) {
301 log_warning(LOG_PROTOCOL
, _("Error occurred while posting\n"));
307 sock_write_all(SESSION(session
)->sock
, ".\r\n", 3);
308 if ((ok
= nntp_ok(SESSION(session
)->sock
, buf
)) != NN_SUCCESS
)
311 session_set_access_time(SESSION(session
));
316 gint
nntp_newgroups(NNTPSession
*session
)
321 gint
nntp_newnews(NNTPSession
*session
)
326 gint
nntp_mode(NNTPSession
*session
, gboolean stream
)
330 ok
= nntp_gen_command(session
, NULL
, "MODE %s",
331 stream
? "STREAM" : "READER");
336 static gint
nntp_ok(SockInfo
*sock
, gchar
*argbuf
)
339 gchar buf
[NNTPBUFSIZE
];
341 if ((ok
= nntp_gen_recv(sock
, buf
, sizeof(buf
))) == NN_SUCCESS
) {
345 if ((buf
[0] == '1' || buf
[0] == '2' || buf
[0] == '3') &&
346 (buf
[3] == ' ' || buf
[3] == '\0')) {
350 if (!strncmp(buf
, "381", 3))
354 } else if (!strncmp(buf
, "480", 3))
363 static gint
nntp_gen_send(SockInfo
*sock
, const gchar
*format
, ...)
365 gchar buf
[NNTPBUFSIZE
];
368 va_start(args
, format
);
369 g_vsnprintf(buf
, sizeof(buf
), format
, args
);
373 if (!g_ascii_strncasecmp(buf
, "AUTHINFO PASS", 13))
374 log_print(LOG_PROTOCOL
, "NNTP> AUTHINFO PASS ********\n");
376 log_print(LOG_PROTOCOL
, "NNTP> %s\n", buf
);
380 if (sock_write_all(sock
, buf
, strlen(buf
)) < 0) {
381 log_warning(LOG_PROTOCOL
, _("Error occurred while sending command\n"));
388 static gint
nntp_gen_recv(SockInfo
*sock
, gchar
*buf
, gint size
)
390 if (sock_gets(sock
, buf
, size
) == -1)
396 log_print(LOG_PROTOCOL
, "NNTP< %s\n", buf
);
401 static gint
nntp_gen_command(NNTPSession
*session
, gchar
*argbuf
,
402 const gchar
*format
, ...)
404 gchar buf
[NNTPBUFSIZE
];
409 va_start(args
, format
);
410 g_vsnprintf(buf
, sizeof(buf
), format
, args
);
413 sock
= SESSION(session
)->sock
;
414 ok
= nntp_gen_send(sock
, "%s", buf
);
415 if (ok
!= NN_SUCCESS
)
417 ok
= nntp_ok(sock
, argbuf
);
418 if (ok
== NN_AUTHREQ
) {
419 if (!session
->userid
|| !session
->passwd
) {
420 session
->auth_failed
= TRUE
;
424 ok
= nntp_gen_send(sock
, "AUTHINFO USER %s", session
->userid
);
425 if (ok
!= NN_SUCCESS
)
427 ok
= nntp_ok(sock
, NULL
);
428 if (ok
== NN_AUTHCONT
) {
429 ok
= nntp_gen_send(sock
, "AUTHINFO PASS %s",
431 if (ok
!= NN_SUCCESS
)
433 ok
= nntp_ok(sock
, NULL
);
435 if (ok
!= NN_SUCCESS
) {
436 session
->auth_failed
= TRUE
;
440 ok
= nntp_gen_send(sock
, "%s", buf
);
441 if (ok
!= NN_SUCCESS
)
443 ok
= nntp_ok(sock
, argbuf
);
445 } else if (ok
== NN_AUTHCONT
) {
446 ok
= nntp_gen_send(sock
, "AUTHINFO PASS %s",
448 if (ok
!= NN_SUCCESS
) {
449 session
->auth_failed
= TRUE
;
452 ok
= nntp_ok(sock
, NULL
);
455 session_set_access_time(SESSION(session
));