reset nmails in fetch()
[pop3.git] / pop3.c
blob3da801ebbabc1625bf2dd6642f73f6e115416031
1 /*
2 * pop3 - a simple pop3 mail client
4 * Copyright (C) 2010 Ali Gholami Rudi
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License, as published by the
8 * Free Software Foundation.
9 */
10 #include <arpa/inet.h>
11 #include <ctype.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <netdb.h>
15 #include <netinet/in.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/socket.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <time.h>
23 #include <unistd.h>
24 #include "config.h"
26 #define BUFFSIZE (1 << 12)
27 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
28 #define MIN(a, b) ((a) < (b) ? (a) : (b))
30 struct mailinfo {
31 char name[1 << 4];
32 int size;
33 } mails[MAXMAILS];
34 int nmails;
36 static int fd;
37 static char buf[BUFFSIZE];
38 static char *buf_cur;
39 static char *buf_end;
41 #ifdef SSL
42 #include <polarssl/ssl.h>
43 #include <polarssl/havege.h>
45 static ssl_context ssl;
46 static ssl_session ssn;
47 static havege_state hs;
49 static int ps_send(void *ctx, unsigned char *buf, int len)
51 return write(*(int *) ctx, buf, len);
54 static int ps_recv(void *ctx, unsigned char *buf, int len)
56 return read(*(int *) ctx, buf, len);
59 #endif
61 static int pop3_connect(char *addr, char *port)
63 struct addrinfo hints, *addrinfo;
64 int fd;
66 memset(&hints, 0, sizeof(hints));
67 hints.ai_family = AF_UNSPEC;
68 hints.ai_socktype = SOCK_STREAM;
69 hints.ai_flags = AI_PASSIVE;
71 getaddrinfo(addr, port, &hints, &addrinfo);
72 fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
73 addrinfo->ai_protocol);
75 if (connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) == -1) {
76 close(fd);
77 freeaddrinfo(addrinfo);
78 return -1;
80 freeaddrinfo(addrinfo);
81 return fd;
84 static void print(char *buf, int len)
86 write(STDOUT_FILENO, buf, len);
89 static int reply_line(char *dst, int len)
91 int nr = 0;
92 char *nl;
93 while (nr < len) {
94 int ml;
95 if (!buf_cur || buf_cur >= buf_end) {
96 #ifdef SSL
97 int buf_len = ssl_read(&ssl, (unsigned char *) buf,
98 sizeof(buf));
99 #else
100 int buf_len = read(fd, buf, sizeof(buf));
101 #endif
102 if (buf_len <= 0)
103 return -1;
104 #ifdef DEBUG
105 print(buf, buf_len);
106 #endif
107 buf_cur = buf;
108 buf_end = buf + buf_len;
110 ml = MIN(buf_end - buf_cur, len - nr);
111 if ((nl = memchr(buf_cur, '\n', ml))) {
112 nl++;
113 memcpy(dst + nr, buf_cur, nl - buf_cur);
114 nr += nl - buf_cur;
115 buf_cur = nl;
116 return nr;
118 memcpy(dst + nr, buf_cur, ml);
119 nr += ml;
120 buf_cur += ml;
122 return nr;
125 static void send_cmd(char *cmd)
127 #ifdef SSL
128 ssl_write(&ssl, (unsigned char *) cmd, strlen(cmd));
129 #else
130 write(fd, cmd, strlen(cmd));
131 #endif
132 fsync(fd);
133 #ifdef DEBUG
134 print(cmd, strlen(cmd));
135 #endif
138 static int is_eoc(char *line, int len)
140 return len < 4 && line[0] == '.' &&
141 (line[1] == '\r' || line[1] == '\n');
144 static char *putmem(char *dst, char *src, int len)
146 memcpy(dst, src, len);
147 return dst + len;
150 static char *cutword(char *dst, char *s)
152 while (*s && isspace(*s))
153 s++;
154 while (*s && !isspace(*s))
155 *dst++ = *s++;
156 *dst = '\0';
157 return s;
160 static char *putstr(char *dst, char *src)
162 int len = strchr(src, '\0') - src;
163 memcpy(dst, src, len + 1);
164 return dst + len;
167 static void login(char *user, char *pass)
169 char line[BUFFSIZE];
170 int len;
171 char *s = line;
172 s = putstr(s, "USER ");
173 s = putstr(s, user);
174 s = putstr(s, "\n");
175 send_cmd(line);
176 len = reply_line(line, sizeof(line));
177 s = line;
178 s = putstr(s, "PASS ");
179 s = putstr(s, pass);
180 s = putstr(s, "\n");
181 send_cmd(line);
182 len = reply_line(line, sizeof(line));
185 static void mail_stat(void)
187 char line[BUFFSIZE];
188 int len;
189 send_cmd("STAT\n");
190 len = reply_line(line, sizeof(line));
191 print(line, len);
192 send_cmd("LIST\n");
193 len = reply_line(line, sizeof(line));
194 while ((len = reply_line(line, sizeof(line))) != -1) {
195 struct mailinfo *mail;
196 char *s = line;
197 if (is_eoc(line, len))
198 break;
199 mail = &mails[nmails++];
200 s = cutword(mail->name, s);
201 mail->size = atoi(s);
205 static void req_mail(int i)
207 char cmd[100];
208 char *s = cmd;
209 s = putstr(s, "RETR ");
210 s = putstr(s, mails[i].name);
211 s = putstr(s, "\n");
212 send_cmd(cmd);
215 static char *mail_dst(char *line, int len)
217 int i;
218 line[len] = '\0';
219 for (i = 0; i < ARRAY_SIZE(filters); i++) {
220 char *hdr = filters[i].hdr;
221 if (!strncmp(hdr, line, strlen(hdr)) &&
222 strstr(line, filters[i].val))
223 return filters[i].dst;
225 return NULL;
228 int xwrite(int fd, char *buf, int len)
230 int nw = 0;
231 while (nw < len) {
232 int ret = write(fd, buf + nw, len - nw);
233 if (ret == -1 && (errno == EAGAIN || errno == EINTR))
234 continue;
235 if (ret < 0)
236 break;
237 nw += ret;
239 return nw;
242 static int mail_write(char *dst, char *mail, int len)
244 int fd = open(dst, O_WRONLY | O_APPEND | O_CREAT, 0600);
245 if (fd == -1)
246 return -1;
247 if (xwrite(fd, mail, len) != len)
248 return -1;
249 close(fd);
250 return 0;
253 static char *put_from_(char *s)
255 time_t t;
256 time(&t);
257 s = putstr(s, "From ");
258 s = putstr(s, getlogin());
259 s += strftime(s, MAXSIZE, " %a %b %d %H:%M:%S %Y\n", localtime(&t));
260 return s;
263 static int ret_mail(int i)
265 char mail[MAXSIZE];
266 char line[BUFFSIZE];
267 char *s = mail;
268 int len = reply_line(line, sizeof(line));
269 char *dst = NULL;
270 int hdr = 1;
271 int ret;
272 if (mails[i].size + 100 > sizeof(mail))
273 return -1;
274 print(mails[i].name, strlen(mails[i].name));
275 s = put_from_(s);
276 while ((len = reply_line(line, sizeof(line))) != -1) {
277 if (is_eoc(line, len))
278 break;
279 if (len > 1 && line[len - 2] == '\r')
280 line[len-- - 2] = '\n';
281 if (line[0] == '\n')
282 hdr = 0;
283 if (hdr && !dst)
284 dst = mail_dst(line, len);
285 s = putmem(s, line, len);
287 *s++ = '\n';
288 if (!dst)
289 dst = SPOOL;
290 ret = mail_write(dst, mail, s - mail);
291 s = line;
292 s = putstr(s, " -> ");
293 s = putstr(s, dst);
294 s = putstr(s, "\n");
295 print(line, s - line);
296 return ret;
299 static void del_mail(int i)
301 char cmd[100];
302 char *s = cmd;
303 s = putstr(s, "DELE ");
304 s = putstr(s, mails[i].name);
305 s = putstr(s, "\n");
306 send_cmd(cmd);
309 static int fetch(struct account *account)
311 char line[BUFFSIZE];
312 int len;
313 int i;
314 char *s = line;
315 nmails = 0;
316 fd = pop3_connect(account->server, account->port);
317 if (fd == -1)
318 return 1;
319 s = putstr(s, "fetching ");
320 s = putstr(s, account->user);
321 s = putstr(s, "@");
322 s = putstr(s, account->server);
323 s = putstr(s, "\n");
324 print(line, s - line);
325 #ifdef SSL
326 havege_init(&hs);
327 memset(&ssn, 0, sizeof(ssn));
328 if (ssl_init(&ssl))
329 return 1;
330 ssl_set_endpoint(&ssl, SSL_IS_CLIENT);
331 ssl_set_authmode(&ssl, SSL_VERIFY_NONE);
332 ssl_set_rng(&ssl, havege_rand, &hs);
333 ssl_set_bio(&ssl, ps_recv, &fd, ps_send, &fd);
334 ssl_set_ciphers(&ssl, ssl_default_ciphers);
335 ssl_set_session(&ssl, 1, 600, &ssn);
336 #endif
337 len = reply_line(line, sizeof(line));
338 login(account->user, account->pass);
339 mail_stat();
340 for (i = 0; i < nmails; i++)
341 req_mail(i);
342 for (i = 0; i < nmails; i++)
343 if (ret_mail(i) == -1)
344 return 1;
345 if (DELMAILS) {
346 for (i = 0; i < nmails; i++)
347 del_mail(i);
348 for (i = 0; i < nmails; i++)
349 len = reply_line(line, sizeof(line));
351 send_cmd("QUIT\n");
352 len = reply_line(line, sizeof(line));
353 #ifdef SSL
354 ssl_close_notify(&ssl);
355 #endif
356 close(fd);
357 #ifdef SSL
358 ssl_free(&ssl);
359 #endif
360 return 0;
363 int main(int argc, char *argv[])
365 int i;
366 for (i = 0; i < ARRAY_SIZE(accounts); i++)
367 if (fetch(&accounts[i]) == -1)
368 return 1;
369 return 0;