From 0b3cbf57875fd692e4ba0b336fefa4bee1ed00dc Mon Sep 17 00:00:00 2001 From: Simeon Simeonov Date: Mon, 26 Feb 2018 11:23:00 +0100 Subject: Initial commit for sylpheed 3.7.0 --- libsylph/nntp.c | 471 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 471 insertions(+) create mode 100644 libsylph/nntp.c (limited to 'libsylph/nntp.c') 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 @@ +/* + * LibSylph -- E-Mail client library + * Copyright (C) 1999-2012 Hiroyuki Yamamoto + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include + +#include "nntp.h" +#include "socket.h" +#include "utils.h" +#if USE_SSL +# include "ssl.h" +#endif +#include "socks.h" + +static gint verbose = 1; + +static void nntp_session_destroy(Session *session); + +static gint nntp_ok (SockInfo *sock, + gchar *argbuf); + +static gint nntp_gen_send (SockInfo *sock, + const gchar *format, + ...); +static gint nntp_gen_recv (SockInfo *sock, + gchar *buf, + gint size); +static gint nntp_gen_command (NNTPSession *session, + gchar *argbuf, + const gchar *format, + ...); + + +#if USE_SSL +Session *nntp_session_new_full(const gchar *server, gushort port, + SocksInfo *socks_info, gchar *buf, + const gchar *userid, const gchar *passwd, + SSLType ssl_type) +#else +Session *nntp_session_new_full(const gchar *server, gushort port, + SocksInfo *socks_info, gchar *buf, + const gchar *userid, const gchar *passwd) +#endif +{ + NNTPSession *session; + SockInfo *sock; + const gchar *server_; + gushort port_; + + if (socks_info) { + server_ = socks_info->proxy_host; + port_ = socks_info->proxy_port; + } else { + server_ = server; + port_ = port; + } + + if ((sock = sock_connect(server_, port_)) == NULL) { + log_warning(_("Can't connect to NNTP server: %s:%d\n"), + server, port); + return NULL; + } + + if (socks_info) { + if (socks_connect(sock, server, port, socks_info) < 0) { + log_warning("Can't establish SOCKS connection: %s:%d\n", + server, port); + sock_close(sock); + return NULL; + } + } + +#if USE_SSL + if (ssl_type == SSL_TUNNEL && !ssl_init_socket(sock)) { + log_warning("Can't establish NNTP session with: %s:%d\n", + server, port); + sock_close(sock); + return NULL; + } +#endif + + if (nntp_ok(sock, buf) != NN_SUCCESS) { + sock_close(sock); + return NULL; + } + + session = g_new0(NNTPSession, 1); + + session_init(SESSION(session)); + + SESSION(session)->type = SESSION_NEWS; + SESSION(session)->server = g_strdup(server); + SESSION(session)->sock = sock; + SESSION(session)->last_access_time = time(NULL); + SESSION(session)->data = NULL; + + SESSION(session)->destroy = nntp_session_destroy; + + session->group = NULL; + + if (userid && passwd) { + gint ok; + + session->userid = g_strdup(userid); + session->passwd = g_strdup(passwd); + + ok = nntp_gen_send(sock, "AUTHINFO USER %s", session->userid); + if (ok != NN_SUCCESS) { + session_destroy(SESSION(session)); + return NULL; + } + ok = nntp_ok(sock, NULL); + if (ok == NN_AUTHCONT) { + ok = nntp_gen_send(sock, "AUTHINFO PASS %s", + session->passwd); + if (ok != NN_SUCCESS) { + session_destroy(SESSION(session)); + return NULL; + } + ok = nntp_ok(sock, NULL); + if (ok != NN_SUCCESS) + session->auth_failed = TRUE; + } + if (ok == NN_SOCKET) { + session_destroy(SESSION(session)); + return NULL; + } + } + + session_set_access_time(SESSION(session)); + + return SESSION(session); +} + +#if USE_SSL +Session *nntp_session_new(const gchar *server, gushort port, gchar *buf, + const gchar *userid, const gchar *passwd, + SSLType ssl_type) +{ + return nntp_session_new_full(server, port, NULL, buf, userid, passwd, + ssl_type); +} +#else +Session *nntp_session_new(const gchar *server, gushort port, gchar *buf, + const gchar *userid, const gchar *passwd) +{ + return nntp_session_new_full(server, port, NULL, buf, userid, passwd); +} +#endif + +static void nntp_session_destroy(Session *session) +{ + NNTPSession *nntp_session = NNTP_SESSION(session); + + g_return_if_fail(session != NULL); + + g_free(nntp_session->group); + g_free(nntp_session->userid); + g_free(nntp_session->passwd); +} + +gint nntp_group(NNTPSession *session, const gchar *group, + gint *num, gint *first, gint *last) +{ + gint ok; + gint resp; + gchar buf[NNTPBUFSIZE]; + + ok = nntp_gen_command(session, buf, "GROUP %s", group); + + if (ok != NN_SUCCESS && ok != NN_SOCKET && ok != NN_AUTHREQ) { + ok = nntp_mode(session, FALSE); + if (ok == NN_SUCCESS) + ok = nntp_gen_command(session, buf, "GROUP %s", group); + } + + if (ok != NN_SUCCESS) + return ok; + + if (sscanf(buf, "%d %d %d %d", &resp, num, first, last) + != 4) { + log_warning(_("protocol error: %s\n"), buf); + return NN_PROTOCOL; + } + + return NN_SUCCESS; +} + +gint nntp_get_article(NNTPSession *session, const gchar *cmd, gint num, + gchar **msgid) +{ + gint ok; + gchar buf[NNTPBUFSIZE]; + + if (num > 0) + ok = nntp_gen_command(session, buf, "%s %d", cmd, num); + else + ok = nntp_gen_command(session, buf, cmd); + + if (ok != NN_SUCCESS) + return ok; + + extract_parenthesis(buf, '<', '>'); + if (buf[0] == '\0') { + log_warning(_("protocol error\n")); + *msgid = g_strdup("0"); + } else + *msgid = g_strdup(buf); + + return NN_SUCCESS; +} + +gint nntp_article(NNTPSession *session, gint num, gchar **msgid) +{ + return nntp_get_article(session, "ARTICLE", num, msgid); +} + +gint nntp_body(NNTPSession *session, gint num, gchar **msgid) +{ + return nntp_get_article(session, "BODY", num, msgid); +} + +gint nntp_head(NNTPSession *session, gint num, gchar **msgid) +{ + return nntp_get_article(session, "HEAD", num, msgid); +} + +gint nntp_stat(NNTPSession *session, gint num, gchar **msgid) +{ + return nntp_get_article(session, "STAT", num, msgid); +} + +gint nntp_next(NNTPSession *session, gint *num, gchar **msgid) +{ + gint ok; + gint resp; + gchar buf[NNTPBUFSIZE]; + + ok = nntp_gen_command(session, buf, "NEXT"); + + if (ok != NN_SUCCESS) + return ok; + + if (sscanf(buf, "%d %d", &resp, num) != 2) { + log_warning(_("protocol error: %s\n"), buf); + return NN_PROTOCOL; + } + + extract_parenthesis(buf, '<', '>'); + if (buf[0] == '\0') { + log_warning(_("protocol error\n")); + return NN_PROTOCOL; + } + *msgid = g_strdup(buf); + + return NN_SUCCESS; +} + +gint nntp_xover(NNTPSession *session, gint first, gint last) +{ + gint ok; + gchar buf[NNTPBUFSIZE]; + + ok = nntp_gen_command(session, buf, "XOVER %d-%d", first, last); + if (ok != NN_SUCCESS) + return ok; + + return NN_SUCCESS; +} + +gint nntp_xhdr(NNTPSession *session, const gchar *header, gint first, gint last) +{ + gint ok; + gchar buf[NNTPBUFSIZE]; + + ok = nntp_gen_command(session, buf, "XHDR %s %d-%d", + header, first, last); + if (ok != NN_SUCCESS) + return ok; + + return NN_SUCCESS; +} + +gint nntp_list(NNTPSession *session) +{ + return nntp_gen_command(session, NULL, "LIST"); +} + +gint nntp_post(NNTPSession *session, FILE *fp) +{ + gint ok; + gchar buf[NNTPBUFSIZE]; + gchar *msg; + + ok = nntp_gen_command(session, buf, "POST"); + if (ok != NN_SUCCESS) + return ok; + + msg = get_outgoing_rfc2822_str(fp); + if (sock_write_all(SESSION(session)->sock, msg, strlen(msg)) < 0) { + log_warning(_("Error occurred while posting\n")); + g_free(msg); + return NN_SOCKET; + } + g_free(msg); + + sock_write_all(SESSION(session)->sock, ".\r\n", 3); + if ((ok = nntp_ok(SESSION(session)->sock, buf)) != NN_SUCCESS) + return ok; + + session_set_access_time(SESSION(session)); + + return NN_SUCCESS; +} + +gint nntp_newgroups(NNTPSession *session) +{ + return NN_SUCCESS; +} + +gint nntp_newnews(NNTPSession *session) +{ + return NN_SUCCESS; +} + +gint nntp_mode(NNTPSession *session, gboolean stream) +{ + gint ok; + + ok = nntp_gen_command(session, NULL, "MODE %s", + stream ? "STREAM" : "READER"); + + return ok; +} + +static gint nntp_ok(SockInfo *sock, gchar *argbuf) +{ + gint ok; + gchar buf[NNTPBUFSIZE]; + + if ((ok = nntp_gen_recv(sock, buf, sizeof(buf))) == NN_SUCCESS) { + if (strlen(buf) < 3) + return NN_ERROR; + + if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') && + (buf[3] == ' ' || buf[3] == '\0')) { + if (argbuf) + strcpy(argbuf, buf); + + if (!strncmp(buf, "381", 3)) + return NN_AUTHCONT; + + return NN_SUCCESS; + } else if (!strncmp(buf, "480", 3)) + return NN_AUTHREQ; + else + return NN_ERROR; + } + + return ok; +} + +static gint nntp_gen_send(SockInfo *sock, const gchar *format, ...) +{ + gchar buf[NNTPBUFSIZE]; + va_list args; + + va_start(args, format); + g_vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + + if (verbose) { + if (!g_ascii_strncasecmp(buf, "AUTHINFO PASS", 13)) + log_print("NNTP> AUTHINFO PASS ********\n"); + else + log_print("NNTP> %s\n", buf); + } + + strcat(buf, "\r\n"); + if (sock_write_all(sock, buf, strlen(buf)) < 0) { + log_warning(_("Error occurred while sending command\n")); + return NN_SOCKET; + } + + return NN_SUCCESS; +} + +static gint nntp_gen_recv(SockInfo *sock, gchar *buf, gint size) +{ + if (sock_gets(sock, buf, size) == -1) + return NN_SOCKET; + + strretchomp(buf); + + if (verbose) + log_print("NNTP< %s\n", buf); + + return NN_SUCCESS; +} + +static gint nntp_gen_command(NNTPSession *session, gchar *argbuf, + const gchar *format, ...) +{ + gchar buf[NNTPBUFSIZE]; + va_list args; + gint ok; + SockInfo *sock; + + va_start(args, format); + g_vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + + sock = SESSION(session)->sock; + ok = nntp_gen_send(sock, "%s", buf); + if (ok != NN_SUCCESS) + return ok; + ok = nntp_ok(sock, argbuf); + if (ok == NN_AUTHREQ) { + if (!session->userid || !session->passwd) { + session->auth_failed = TRUE; + return ok; + } + + ok = nntp_gen_send(sock, "AUTHINFO USER %s", session->userid); + if (ok != NN_SUCCESS) + return ok; + ok = nntp_ok(sock, NULL); + if (ok == NN_AUTHCONT) { + ok = nntp_gen_send(sock, "AUTHINFO PASS %s", + session->passwd); + if (ok != NN_SUCCESS) + return ok; + ok = nntp_ok(sock, NULL); + } + if (ok != NN_SUCCESS) { + session->auth_failed = TRUE; + return ok; + } + + ok = nntp_gen_send(sock, "%s", buf); + if (ok != NN_SUCCESS) + return ok; + ok = nntp_ok(sock, argbuf); + } + + session_set_access_time(SESSION(session)); + + return ok; +} -- cgit v1.3