Add disk_applet executable to the ignore list
[rmail.git] / src / network / pop3.c
blob2d5c71780803c5d6014b7e7ec5ad8a5f11d18a73
1 /**
2 * Copyright (C) 2011 - Roberto Branciforti
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 /* POP3 functions (See RFC 1939) */
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
25 #include "socket.h"
26 #include "socket_io.h"
27 #include "socket_ssl.h"
29 #include "pop3.h"
31 #if 0
32 #define POP3_DEBUG
33 #define DEBUG_ERROR fprintf(stderr, "%s:%d - %s\n", __FILE__, __LINE__, __func__)
34 #endif
36 #define POP3_TIMEOUT 3 /* seconds */
38 static void print_server_response(const char *buf)
40 size_t i;
41 for (i = 0; i < strlen(buf); i++) {
42 if (buf[i] == '\r')
43 fprintf(stderr, "\\r");
44 else if (buf[i] == '\n')
45 fprintf(stderr, "\\n");
46 else if (buf[i] == '\t')
47 fprintf(stderr, "\\t");
48 else if ((buf[i] < ' ') || (buf[i] > 0x7E))
49 fprintf(stderr, "0x%02X ", buf[i]);
50 else
51 fprintf(stderr, "%c", buf[i]);
53 fprintf(stderr, "\n");
56 /**
57 * Test for an OK response
59 * @param[in] buf server response line buffer
61 * @retval 1 +OK, 0 on -ERR response
63 static int pop3_command_success(const char *buf)
65 #ifdef POP3_DEBUG
66 print_server_response(buf);
67 #endif
68 if (strstr(buf, "+OK") != NULL)
69 return 1;
71 return 0;
74 static int pop3_send_command(struct pop3_mailbox *mbox, const char *cmd, size_t cmd_size)
76 ssize_t rc;
78 if (POP3_AUTH_SSL == mbox->auth.type) {
79 rc = socket_ssl_write(&mbox->auth.ssl.ctx, cmd, cmd_size);
80 } else {
81 rc = socket_write(mbox->host.sockfd, cmd, cmd_size);
84 if (rc < 0)
85 return -1;
87 /* Now wr >= 0 and it's safe to cast it to size_t */
88 if (cmd_size != (size_t) rc)
89 return -1;
91 return 0;
94 static int pop3_get_reply(struct pop3_mailbox *mbox, char *line, size_t lsize)
96 if (POP3_AUTH_SSL == mbox->auth.type) {
97 return socket_ssl_read_line(&mbox->auth.ssl.ctx, line, lsize);
100 return socket_read_line(mbox->host.sockfd, line, lsize, POP3_TIMEOUT);
103 static int pop3_command(struct pop3_mailbox *mbox, const char *cmd, size_t csize)
105 char line[POP3_BUFSIZE];
107 if (pop3_send_command(mbox, cmd, csize) < 0) {
108 fprintf(stderr, "%s - line %d\n", __func__, __LINE__);
109 return -1;
112 if (pop3_get_reply(mbox, line, POP3_BUFSIZE) < 0) {
113 fprintf(stderr, "%s - line %d\n", __func__, __LINE__);
114 return -1;
117 if (strstr(line, "+OK") == NULL) {
118 fprintf(stderr, "%s - line %d\n", __func__, __LINE__);
119 return -1;
122 return 0;
126 * Test the end of pop3
128 * @param[in] buf server response line buffer
130 * @retval 1 if EOS, 0 otherwise
132 static int pop3_end_scan(const char *buf)
134 if ((buf[0] == '.') && ((buf[1] == '\r') || (buf[1] == '\n')))
135 return 1;
137 return 0;
140 int pop3_connect(struct pop3_mailbox *mbox)
142 struct pop3_auth_ssl *ssl;
144 int sockfd;
145 int rc;
147 char buf[POP3_BUFSIZE];
149 sockfd = connect_to_tcp_server(mbox->host.name, mbox->host.port);
150 if (sockfd < 0) {
151 return -1;
154 mbox->host.sockfd = sockfd;
156 #ifdef POP3_DEBUG
157 fprintf(stderr, "%s sockfd %d\n", __func__, sockfd);
158 #endif
160 ssl = &mbox->auth.ssl;
162 if (POP3_AUTH_SSL == mbox->auth.type) {
163 if (socket_ssl_init(&mbox->host.sockfd, &ssl->ctx, &ssl->ssn, &ssl->hs, &ssl->cert, NULL)) {
164 return -1;
167 rc = socket_ssl_read_line(&mbox->auth.ssl.ctx, buf, POP3_BUFSIZE);
168 } else {
169 /* !SSL */
170 rc = socket_read_line(sockfd, buf, sizeof(buf), POP3_TIMEOUT);
173 /* Once the TCP connection has been opened by a POP3 client,
174 * the POP3 server issues a one line greeting.
176 #ifdef POP3_DEBUG
177 print_server_response(buf);
178 #endif
179 if (rc < 0) {
180 return -1;
183 if (!pop3_command_success(buf)) {
184 return -1;
187 return 0;
190 int pop3_disconnect(struct pop3_mailbox *mbox)
192 (void) pop3_command(mbox, "QUIT\r\n", 6);
194 if (POP3_AUTH_SSL == mbox->auth.type) {
195 return socket_ssl_close(mbox->host.sockfd,
196 &mbox->auth.ssl.ctx,
197 &mbox->auth.ssl.cert);
200 return socket_close(mbox->host.sockfd);
203 int pop3_authenticate(struct pop3_mailbox *mbox)
205 int n;
206 char line[POP3_BUFSIZE];
208 if ((mbox->auth.type != POP3_AUTH_USERPASS) &&
209 (mbox->auth.type != POP3_AUTH_SSL)) {
211 fprintf(stderr, "%s - Invalid POP3_AUTH_TYPE %d\n",
212 __func__, mbox->auth.type);
213 return -1;
216 n = snprintf(line, POP3_BUFSIZE, "USER %s\r\n", mbox->auth.user);
217 if (pop3_command(mbox, line, n)) {
218 fprintf(stderr, "%s - Invalid user\n", __func__);
219 return -1;
222 n = snprintf(line, POP3_BUFSIZE, "PASS %s\r\n", mbox->auth.pass);
223 if (pop3_command(mbox, line, n)) {
224 fprintf(stderr, "%s - Invalid password\n", __func__);
225 return -1;
228 return 0;
231 int pop3_capa(struct pop3_mailbox *mbox)
233 char line[POP3_BUFSIZE];
234 int scan_end;
236 if (pop3_command(mbox, "CAPA\r\n", 6)) {
237 return -1;
240 scan_end = 0;
241 while (!scan_end) {
242 if (pop3_get_reply(mbox, line, POP3_BUFSIZE) < 0) {
243 fprintf(stderr, "%s - line %d\n", __func__, __LINE__);
244 return -1;
245 } else {
246 fprintf(stderr, "%s - line %s\n", __func__, line);
249 scan_end = pop3_end_scan(line);
251 /* Prints the scan-list entry */
252 print_server_response(line);
255 return 0;
258 int pop3_stat(struct pop3_mailbox *mbox)
260 int n;
261 unsigned int msgs;
262 unsigned long octets = 0;
264 char line[POP3_BUFSIZE];
266 if (pop3_send_command(mbox, "STAT\r\n", 6)) {
267 fprintf(stderr, "%s - line %d\n", __func__, __LINE__);
268 return -1;
271 if (pop3_get_reply(mbox, line, POP3_BUFSIZE) < 0) {
272 fprintf(stderr, "%s - line %d\n", __func__, __LINE__);
273 return -1;
276 /* Reset message counter */
277 mbox->messages = 0;
278 /* [RFC 1939]...
279 * The positive response consists of "+OK" followed by a single space,
280 * the number of messages in the maildrop, a single space, and the
281 * size of the maildrop in octets.
283 n = sscanf(line, "+OK %u %lu", &msgs, &octets);
284 if (n >= 0) {
285 mbox->messages = msgs;
286 } else {
287 fprintf(stderr, "%s - Error parsing %s\n", __func__, line);
288 return -1;
291 return 0;
294 int pop3_list(struct pop3_mailbox *mbox)
296 char line[POP3_BUFSIZE];
297 int scan_end;
299 if (pop3_command(mbox, "LIST\r\n", 6)) {
300 return -1;
303 scan_end = 0;
304 while (!scan_end) {
305 if (pop3_get_reply(mbox, line, POP3_BUFSIZE) < 0) {
306 return -1;
309 scan_end = pop3_end_scan(line);
311 /* Prints the scan-list entry */
312 print_server_response(line);
315 return 0;
318 int pop3_top(struct pop3_mailbox *mbox, unsigned int msg_num)
320 char snd[POP3_BUFSIZE];
321 char buf[POP3_BUFSIZE];
323 int scan_end;
324 int n;
326 if (msg_num > mbox->messages) {
327 fprintf(stderr, "%s - BUG: msg_num %u > mbox.messages %u",
328 __func__, msg_num, mbox->messages);
329 return -1;
332 n = snprintf(snd, POP3_BUFSIZE, "TOP %u 0\r\n", msg_num);
334 if (pop3_send_command(mbox, snd, n)) {
335 return -1;
338 scan_end = 0;
339 while (!scan_end) {
340 if (socket_read_line(mbox->host.sockfd, buf, POP3_BUFSIZE, POP3_TIMEOUT) < 0)
341 return -1;
343 scan_end = pop3_end_scan(buf);
345 /* Prints the scan-list entry */
346 print_server_response(buf);
348 return 0;
351 int pop3_retr(struct pop3_mailbox *mbox, unsigned int msg_num)
353 char snd[POP3_BUFSIZE];
354 char buf[POP3_BUFSIZE];
355 int scan_end;
356 int n;
358 if (msg_num > mbox->messages) {
359 fprintf(stderr, "%s - BUG: msg_num %u > mbox.messages %u",
360 __func__, msg_num, mbox->messages);
361 return -1;
364 n = snprintf(snd, POP3_BUFSIZE, "RETR %u\r\n", msg_num);
366 if (pop3_send_command(mbox, snd, n)) {
367 return -1;
370 scan_end = 0;
371 while (!scan_end) {
372 if (socket_read_line(mbox->host.sockfd, buf, POP3_BUFSIZE, POP3_TIMEOUT) < 0)
373 return -1;
375 scan_end = pop3_end_scan(buf);
377 /* Prints the scan-list entry */
378 print_server_response(buf);
380 return 0;