Integrate test_header in test_view_mail and various coding style modifications
[rmail.git] / src / network / pop3.c
blob0f97a924b32fa6b7f8f534c87a0eeeaa48f4ee30
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 fprintf(stderr, "%s sockfd %d\n", __func__, sockfd);
158 ssl = &mbox->auth.ssl;
160 if (POP3_AUTH_SSL == mbox->auth.type) {
161 if (socket_ssl_init(&mbox->host.sockfd, &ssl->ctx, &ssl->ssn, &ssl->hs, &ssl->cert, NULL)) {
162 return -1;
165 rc = socket_ssl_read_line(&mbox->auth.ssl.ctx, buf, POP3_BUFSIZE);
166 } else {
167 /* !SSL */
168 rc = socket_read_line(sockfd, buf, sizeof(buf), POP3_TIMEOUT);
171 /* Once the TCP connection has been opened by a POP3 client,
172 * the POP3 server issues a one line greeting.
174 #ifdef POP3_DEBUG
175 print_server_response(buf);
176 #endif
177 if (rc < 0) {
178 return -1;
181 if (!pop3_command_success(buf)) {
182 return -1;
185 return 0;
188 int pop3_disconnect(struct pop3_mailbox *mbox)
190 (void) pop3_command(mbox, "QUIT\r\n", 6);
192 if (POP3_AUTH_SSL == mbox->auth.type) {
193 return socket_ssl_close(mbox->host.sockfd,
194 &mbox->auth.ssl.ctx,
195 &mbox->auth.ssl.cert);
198 return socket_close(mbox->host.sockfd);
201 int pop3_authenticate(struct pop3_mailbox *mbox)
203 int n;
204 char line[POP3_BUFSIZE];
206 if ((mbox->auth.type != POP3_AUTH_USERPASS) &&
207 (mbox->auth.type != POP3_AUTH_SSL)) {
209 fprintf(stderr, "%s - Invalid POP3_AUTH_TYPE %d\n",
210 __func__, mbox->auth.type);
211 return -1;
214 n = snprintf(line, POP3_BUFSIZE, "USER %s\r\n", mbox->auth.user);
215 if (pop3_command(mbox, line, n)) {
216 fprintf(stderr, "%s - Invalid user\n", __func__);
217 return -1;
220 n = snprintf(line, POP3_BUFSIZE, "PASS %s\r\n", mbox->auth.pass);
221 if (pop3_command(mbox, line, n)) {
222 fprintf(stderr, "%s - Invalid password\n", __func__);
223 return -1;
226 return 0;
229 int pop3_capa(struct pop3_mailbox *mbox)
231 char line[POP3_BUFSIZE];
232 int scan_end;
234 if (pop3_command(mbox, "CAPA\r\n", 6)) {
235 return -1;
238 scan_end = 0;
239 while (!scan_end) {
240 if (pop3_get_reply(mbox, line, POP3_BUFSIZE) < 0) {
241 fprintf(stderr, "%s - line %d\n", __func__, __LINE__);
242 return -1;
243 } else {
244 fprintf(stderr, "%s - line %s\n", __func__, line);
247 scan_end = pop3_end_scan(line);
249 /* Prints the scan-list entry */
250 print_server_response(line);
253 return 0;
256 int pop3_stat(struct pop3_mailbox *mbox)
258 int n;
259 unsigned int msgs;
260 unsigned long octets = 0;
262 char line[POP3_BUFSIZE];
264 if (pop3_send_command(mbox, "STAT\r\n", 6)) {
265 fprintf(stderr, "%s - line %d\n", __func__, __LINE__);
266 return -1;
269 if (pop3_get_reply(mbox, line, POP3_BUFSIZE) < 0) {
270 fprintf(stderr, "%s - line %d\n", __func__, __LINE__);
271 return -1;
274 /* Reset message counter */
275 mbox->messages = 0;
276 /* [RFC 1939]...
277 * The positive response consists of "+OK" followed by a single space,
278 * the number of messages in the maildrop, a single space, and the
279 * size of the maildrop in octets.
281 n = sscanf(line, "+OK %u %lu", &msgs, &octets);
282 if (n >= 0) {
283 mbox->messages = msgs;
284 } else {
285 fprintf(stderr, "%s - Error parsing %s\n", __func__, line);
286 return -1;
289 return 0;
292 int pop3_list(struct pop3_mailbox *mbox)
294 char line[POP3_BUFSIZE];
295 int scan_end;
297 if (pop3_command(mbox, "LIST\r\n", 6)) {
298 return -1;
301 scan_end = 0;
302 while (!scan_end) {
303 if (pop3_get_reply(mbox, line, POP3_BUFSIZE) < 0) {
304 return -1;
307 scan_end = pop3_end_scan(line);
309 /* Prints the scan-list entry */
310 print_server_response(line);
313 return 0;
316 int pop3_top(struct pop3_mailbox *mbox, unsigned int msg_num)
318 char snd[POP3_BUFSIZE];
319 char buf[POP3_BUFSIZE];
321 int scan_end;
322 int n;
324 if (msg_num > mbox->messages) {
325 fprintf(stderr, "%s - BUG: msg_num %u > mbox.messages %u",
326 __func__, msg_num, mbox->messages);
327 return -1;
330 n = snprintf(snd, POP3_BUFSIZE, "TOP %u 0\r\n", msg_num);
332 if (pop3_send_command(mbox, snd, n)) {
333 return -1;
336 scan_end = 0;
337 while (!scan_end) {
338 if (socket_read_line(mbox->host.sockfd, buf, POP3_BUFSIZE, POP3_TIMEOUT) < 0)
339 return -1;
341 scan_end = pop3_end_scan(buf);
343 /* Prints the scan-list entry */
344 print_server_response(buf);
346 return 0;
349 int pop3_retr(struct pop3_mailbox *mbox, unsigned int msg_num)
351 char snd[POP3_BUFSIZE];
352 char buf[POP3_BUFSIZE];
353 int scan_end;
354 int n;
356 if (msg_num > mbox->messages) {
357 fprintf(stderr, "%s - BUG: msg_num %u > mbox.messages %u",
358 __func__, msg_num, mbox->messages);
359 return -1;
362 n = snprintf(snd, POP3_BUFSIZE, "RETR %u\r\n", msg_num);
364 if (pop3_send_command(mbox, snd, n)) {
365 return -1;
368 scan_end = 0;
369 while (!scan_end) {
370 if (socket_read_line(mbox->host.sockfd, buf, POP3_BUFSIZE, POP3_TIMEOUT) < 0)
371 return -1;
373 scan_end = pop3_end_scan(buf);
375 /* Prints the scan-list entry */
376 print_server_response(buf);
378 return 0;