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) */
26 #include "socket_io.h"
27 #include "socket_ssl.h"
33 #define DEBUG_ERROR fprintf(stderr, "%s:%d - %s\n", __FILE__, __LINE__, __func__)
36 #define POP3_TIMEOUT 3 /* seconds */
38 static void print_server_response(const char *buf
)
41 for (i
= 0; i
< strlen(buf
); i
++) {
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
]);
51 fprintf(stderr
, "%c", buf
[i
]);
53 fprintf(stderr
, "\n");
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
)
66 print_server_response(buf
);
68 if (strstr(buf
, "+OK") != NULL
)
74 static int pop3_send_command(struct pop3_mailbox
*mbox
, const char *cmd
, size_t cmd_size
)
78 if (POP3_AUTH_SSL
== mbox
->auth
.type
) {
79 rc
= socket_ssl_write(&mbox
->auth
.ssl
.ctx
, cmd
, cmd_size
);
81 rc
= socket_write(mbox
->host
.sockfd
, cmd
, cmd_size
);
87 /* Now wr >= 0 and it's safe to cast it to size_t */
88 if (cmd_size
!= (size_t) rc
)
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__
);
112 if (pop3_get_reply(mbox
, line
, POP3_BUFSIZE
) < 0) {
113 fprintf(stderr
, "%s - line %d\n", __func__
, __LINE__
);
117 if (strstr(line
, "+OK") == NULL
) {
118 fprintf(stderr
, "%s - line %d\n", __func__
, __LINE__
);
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')))
140 int pop3_connect(struct pop3_mailbox
*mbox
)
142 struct pop3_auth_ssl
*ssl
;
147 char buf
[POP3_BUFSIZE
];
149 sockfd
= connect_to_tcp_server(mbox
->host
.name
, mbox
->host
.port
);
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
)) {
165 rc
= socket_ssl_read_line(&mbox
->auth
.ssl
.ctx
, buf
, POP3_BUFSIZE
);
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.
175 print_server_response(buf
);
181 if (!pop3_command_success(buf
)) {
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
,
195 &mbox
->auth
.ssl
.cert
);
198 return socket_close(mbox
->host
.sockfd
);
201 int pop3_authenticate(struct pop3_mailbox
*mbox
)
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
);
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__
);
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__
);
229 int pop3_capa(struct pop3_mailbox
*mbox
)
231 char line
[POP3_BUFSIZE
];
234 if (pop3_command(mbox
, "CAPA\r\n", 6)) {
240 if (pop3_get_reply(mbox
, line
, POP3_BUFSIZE
) < 0) {
241 fprintf(stderr
, "%s - line %d\n", __func__
, __LINE__
);
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
);
256 int pop3_stat(struct pop3_mailbox
*mbox
)
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__
);
269 if (pop3_get_reply(mbox
, line
, POP3_BUFSIZE
) < 0) {
270 fprintf(stderr
, "%s - line %d\n", __func__
, __LINE__
);
274 /* Reset message counter */
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
);
283 mbox
->messages
= msgs
;
285 fprintf(stderr
, "%s - Error parsing %s\n", __func__
, line
);
292 int pop3_list(struct pop3_mailbox
*mbox
)
294 char line
[POP3_BUFSIZE
];
297 if (pop3_command(mbox
, "LIST\r\n", 6)) {
303 if (pop3_get_reply(mbox
, line
, POP3_BUFSIZE
) < 0) {
307 scan_end
= pop3_end_scan(line
);
309 /* Prints the scan-list entry */
310 print_server_response(line
);
316 int pop3_top(struct pop3_mailbox
*mbox
, unsigned int msg_num
)
318 char snd
[POP3_BUFSIZE
];
319 char buf
[POP3_BUFSIZE
];
324 if (msg_num
> mbox
->messages
) {
325 fprintf(stderr
, "%s - BUG: msg_num %u > mbox.messages %u",
326 __func__
, msg_num
, mbox
->messages
);
330 n
= snprintf(snd
, POP3_BUFSIZE
, "TOP %u 0\r\n", msg_num
);
332 if (pop3_send_command(mbox
, snd
, n
)) {
338 if (socket_read_line(mbox
->host
.sockfd
, buf
, POP3_BUFSIZE
, POP3_TIMEOUT
) < 0)
341 scan_end
= pop3_end_scan(buf
);
343 /* Prints the scan-list entry */
344 print_server_response(buf
);
349 int pop3_retr(struct pop3_mailbox
*mbox
, unsigned int msg_num
)
351 char snd
[POP3_BUFSIZE
];
352 char buf
[POP3_BUFSIZE
];
356 if (msg_num
> mbox
->messages
) {
357 fprintf(stderr
, "%s - BUG: msg_num %u > mbox.messages %u",
358 __func__
, msg_num
, mbox
->messages
);
362 n
= snprintf(snd
, POP3_BUFSIZE
, "RETR %u\r\n", msg_num
);
364 if (pop3_send_command(mbox
, snd
, n
)) {
370 if (socket_read_line(mbox
->host
.sockfd
, buf
, POP3_BUFSIZE
, POP3_TIMEOUT
) < 0)
373 scan_end
= pop3_end_scan(buf
);
375 /* Prints the scan-list entry */
376 print_server_response(buf
);