From c0420fed0a3b56ebba3e695927439a58642500d3 Mon Sep 17 00:00:00 2001 From: SJ Date: Sat, 24 Nov 2012 23:02:08 +0100 Subject: [PATCH] added pop3 support for pilerimport --- configure | 2 +- configure.in | 2 +- src/config.h | 2 +- src/imap.c | 24 +---- src/misc.c | 16 ++++ src/misc.h | 5 ++ src/pilerimport.c | 51 +++++++++-- src/pop3.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 289 insertions(+), 34 deletions(-) create mode 100644 src/pop3.c diff --git a/configure b/configure index 5a9e6960..14759fed 100755 --- a/configure +++ b/configure @@ -4590,7 +4590,7 @@ echo; echo CFLAGS="$static -O2 -Wall -g" LIBS="$antispam_libs $sunos_libs " -OBJS="dirs.o base64.o misc.o counters.o cfg.o sig.o decoder.o list.o parser.o parser_utils.o rules.o session.o message.o attachment.o digest.o store.o archive.o tai.o import.o imap.o extract.o $objs" +OBJS="dirs.o base64.o misc.o counters.o cfg.o sig.o decoder.o list.o parser.o parser_utils.o rules.o session.o message.o attachment.o digest.o store.o archive.o tai.o import.o imap.o pop3.o extract.o $objs" ac_config_files="$ac_config_files Makefile src/Makefile etc/Makefile util/Makefile init.d/Makefile test/Makefile contrib/imap/Makefile" diff --git a/configure.in b/configure.in index 1b308013..3d8a369d 100644 --- a/configure.in +++ b/configure.in @@ -390,7 +390,7 @@ echo; echo CFLAGS="$static -O2 -Wall -g" LIBS="$antispam_libs $sunos_libs " -OBJS="dirs.o base64.o misc.o counters.o cfg.o sig.o decoder.o list.o parser.o parser_utils.o rules.o session.o message.o attachment.o digest.o store.o archive.o tai.o import.o imap.o extract.o $objs" +OBJS="dirs.o base64.o misc.o counters.o cfg.o sig.o decoder.o list.o parser.o parser_utils.o rules.o session.o message.o attachment.o digest.o store.o archive.o tai.o import.o imap.o pop3.o extract.o $objs" AC_CONFIG_FILES([Makefile src/Makefile etc/Makefile util/Makefile init.d/Makefile test/Makefile contrib/imap/Makefile]) AC_OUTPUT diff --git a/src/config.h b/src/config.h index 24277b08..495a128d 100644 --- a/src/config.h +++ b/src/config.h @@ -13,7 +13,7 @@ #define VERSION "0.1.22" -#define BUILD 724 +#define BUILD 727 #define HOSTID "mailarchiver" diff --git a/src/imap.c b/src/imap.c index 93fa6786..c6ab4ca4 100644 --- a/src/imap.c +++ b/src/imap.c @@ -23,26 +23,6 @@ #include -#define CHK_NULL(x, errmsg) if ((x)==NULL) { printf("error: %s\n", errmsg); return ERR; } -#define CHK_SSL(err, msg) if ((err)==-1) { printf("ssl error: %s\n", msg); return ERR; } - - -unsigned long resolve_host(char *host){ - struct hostent *h; - struct in_addr addr; - - if(!host) return 0; - - if((addr.s_addr = inet_addr(host)) == -1){ - if((h = gethostbyname(host)) == NULL){ - return 0; - } - else return *(unsigned long*)h->h_addr; - } - else return addr.s_addr; -} - - int get_message_length_from_imap_answer(char *s, int *_1st_line_bytes){ char *p, *q; int len=0; @@ -210,7 +190,7 @@ int process_imap_folder(int sd, int *seq, char *folder, struct session_data *sda } -int connect_to_imap_server(int sd, int *seq, char *imapserver, char *username, char *password, int port, struct __data *data, int use_ssl){ +int connect_to_imap_server(int sd, int *seq, char *server, char *username, char *password, int port, struct __data *data, int use_ssl){ int n; char tag[SMALLBUFSIZE], tagok[SMALLBUFSIZE], buf[MAXBUFSIZE]; unsigned long host=0; @@ -219,7 +199,7 @@ int connect_to_imap_server(int sd, int *seq, char *imapserver, char *username, c char *str; - host = resolve_host(imapserver); + host = resolve_host(server); remote_addr.sin_family = AF_INET; remote_addr.sin_port = htons(port); diff --git a/src/misc.c b/src/misc.c index a41707d2..0927f2b6 100644 --- a/src/misc.c +++ b/src/misc.c @@ -538,6 +538,22 @@ void strtolower(char *s){ } +unsigned long resolve_host(char *host){ + struct hostent *h; + struct in_addr addr; + + if(!host) return 0; + + if((addr.s_addr = inet_addr(host)) == -1){ + if((h = gethostbyname(host)) == NULL){ + return 0; + } + else return *(unsigned long*)h->h_addr; + } + else return addr.s_addr; +} + + #ifndef _GNU_SOURCE char *strcasestr(const char *s, const char *find){ char c, sc; diff --git a/src/misc.h b/src/misc.h index 3798a9cc..28167bbf 100644 --- a/src/misc.h +++ b/src/misc.h @@ -11,6 +11,9 @@ #include #include "defs.h" +#define CHK_NULL(x, errmsg) if ((x)==NULL) { printf("error: %s\n", errmsg); return ERR; } +#define CHK_SSL(err, msg) if ((err)==-1) { printf("ssl error: %s\n", msg); return ERR; } + int get_build(); void __fatal(char *s); long tvdiff(struct timeval a, struct timeval b); @@ -36,6 +39,8 @@ void init_session_data(struct session_data *sdata); int read_from_stdin(struct session_data *sdata); void strtolower(char *s); +unsigned long resolve_host(char *host); + #ifndef _GNU_SOURCE char *strcasestr(const char *s, const char *find); #endif diff --git a/src/pilerimport.c b/src/pilerimport.c index ac606aea..b0016491 100644 --- a/src/pilerimport.c +++ b/src/pilerimport.c @@ -31,10 +31,12 @@ int quiet=0; int remove_after_successful_import = 0; -int connect_to_imap_server(int sd, int *seq, char *imapserver, char *username, char *password, int port, struct __data *data, int use_ssl); -void close_connection(int sd, struct __data *data, int use_ssl); +int connect_to_imap_server(int sd, int *seq, char *server, char *username, char *password, int port, struct __data *data, int use_ssl); int list_folders(int sd, int *seq, char *folders, int foldersize, int use_ssl, struct __data *data); int process_imap_folder(int sd, int *seq, char *folder, struct session_data *sdata, struct __data *data, int use_ssl, struct __config *cfg); +int connect_to_pop3_server(int sd, char *server, char *username, char *password, int port, struct __data *data, int use_ssl); +int process_pop3_emails(int sd, struct session_data *sdata, struct __data *data, int use_ssl, struct __config *cfg); +void close_connection(int sd, struct __data *data, int use_ssl); int import_from_mailbox(char *mailbox, struct session_data *sdata, struct __data *data, struct __config *cfg){ @@ -237,7 +239,7 @@ int import_from_maildir(char *directory, struct session_data *sdata, struct __da } -int import_from_imap_server(char *imapserver, char *username, char *password, int port, struct session_data *sdata, struct __data *data, char *skiplist, struct __config *cfg){ +int import_from_imap_server(char *server, char *username, char *password, int port, struct session_data *sdata, struct __data *data, char *skiplist, struct __config *cfg){ int rc=ERR, ret=OK, sd, seq=1, skipmatch, use_ssl=0; char *p, puf[SMALLBUFSIZE]; char *q, muf[SMALLBUFSIZE]; @@ -252,7 +254,7 @@ int import_from_imap_server(char *imapserver, char *username, char *password, in return ERR; } - if(connect_to_imap_server(sd, &seq, imapserver, username, password, port, data, use_ssl) == ERR){ + if(connect_to_imap_server(sd, &seq, server, username, password, port, data, use_ssl) == ERR){ close(sd); return ERR; } @@ -301,8 +303,32 @@ int import_from_imap_server(char *imapserver, char *username, char *password, in } +int import_from_pop3_server(char *server, char *username, char *password, int port, struct session_data *sdata, struct __data *data, struct __config *cfg){ + int rc=ERR, ret=OK, sd, use_ssl=0; + + if(port == 995) use_ssl = 1; + + if((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1){ + printf("cannot create socket\n"); + return ERR; + } + + if(connect_to_pop3_server(sd, server, username, password, port, data, use_ssl) == ERR){ + close(sd); + return ERR; + } + + rc = process_pop3_emails(sd, sdata, data, use_ssl, cfg); + if(rc == ERR) ret = ERR; + + close_connection(sd, data, use_ssl); + + return ret; +} + + void usage(){ - printf("usage: pilerimport [-c ] -e | -m | -d | -i -u -p -P [-F ] [-R] [-r] [-q]\n"); + printf("usage: pilerimport [-c ] -e | -m | -d | -i | -K | -u -p -P [-F ] [-R] [-r] [-q]\n"); exit(0); } @@ -310,7 +336,7 @@ void usage(){ int main(int argc, char **argv){ int i, c, rc=0, n_mbox=0, tot_msgs=0, port=143; char *configfile=CONFIG_FILE, *emlfile=NULL, *mboxdir=NULL, *mbox[MBOX_ARGS], *directory=NULL; - char *imapserver=NULL, *username=NULL, *password=NULL, *skiplist=SKIPLIST, *folder=NULL; + char *imapserver=NULL, *pop3server=NULL, *username=NULL, *password=NULL, *skiplist=SKIPLIST, *folder=NULL; struct session_data sdata; struct __config cfg; struct __data data; @@ -333,6 +359,7 @@ int main(int argc, char **argv){ {"mbox", required_argument, 0, 'm' }, {"mboxdir", required_argument, 0, 'M' }, {"imapserver", required_argument, 0, 'i' }, + {"pop3server", required_argument, 0, 'K' }, {"username", required_argument, 0, 'u' }, {"password", required_argument, 0, 'p' }, {"port", required_argument, 0, 'P' }, @@ -347,9 +374,9 @@ int main(int argc, char **argv){ int option_index = 0; - c = getopt_long(argc, argv, "c:m:M:e:d:i:u:p:P:x:F:Rrqh?", long_options, &option_index); + c = getopt_long(argc, argv, "c:m:M:e:d:i:K:u:p:P:x:F:Rrqh?", long_options, &option_index); #else - c = getopt(argc, argv, "c:m:M:e:d:i:u:p:P:x:F:Rrqh?"); + c = getopt(argc, argv, "c:m:M:e:d:i:K:u:p:P:x:F:Rrqh?"); #endif if(c == -1) break; @@ -385,6 +412,11 @@ int main(int argc, char **argv){ imapserver = optarg; break; + case 'K' : + pop3server = optarg; + if(port == 143) port = 110; + break; + case 'u' : username = optarg; break; @@ -430,7 +462,7 @@ int main(int argc, char **argv){ - if(!mbox[0] && !mboxdir && !emlfile && !directory && !imapserver) usage(); + if(!mbox[0] && !mboxdir && !emlfile && !directory && !imapserver && !pop3server) usage(); cfg = read_config(configfile); @@ -481,6 +513,7 @@ int main(int argc, char **argv){ if(mboxdir) rc = import_mbox_from_dir(mboxdir, &sdata, &data, &tot_msgs, &cfg); if(directory) rc = import_from_maildir(directory, &sdata, &data, &tot_msgs, &cfg); if(imapserver && username && password) rc = import_from_imap_server(imapserver, username, password, port, &sdata, &data, skiplist, &cfg); + if(pop3server && username && password) rc = import_from_pop3_server(pop3server, username, password, port, &sdata, &data, &cfg); free_rule(data.archiving_rules); diff --git a/src/pop3.c b/src/pop3.c new file mode 100644 index 00000000..e5f4163b --- /dev/null +++ b/src/pop3.c @@ -0,0 +1,221 @@ +/* + * pop3.c, SJ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int is_last_complete_pop3_packet(char *s, int len){ + + if(*(s+len-5) == '\r' && *(s+len-4) == '\n' && *(s+len-3) == '.' && *(s+len-2) == '\r' && *(s+len-1) == '\n'){ + return 1; + } + + return 0; +} + + +int connect_to_pop3_server(int sd, char *server, char *username, char *password, int port, struct __data *data, int use_ssl){ + int n; + char buf[MAXBUFSIZE]; + unsigned long host=0; + struct sockaddr_in remote_addr; + X509* server_cert; + char *str; + + host = resolve_host(server); + + remote_addr.sin_family = AF_INET; + remote_addr.sin_port = htons(port); + remote_addr.sin_addr.s_addr = host; + bzero(&(remote_addr.sin_zero),8); + + if(connect(sd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1){ + printf("connect()\n"); + return ERR; + } + + + if(use_ssl == 1){ + + SSL_library_init(); + SSL_load_error_strings(); + + data->ctx = SSL_CTX_new(SSLv3_client_method()); + CHK_NULL(data->ctx, "internal SSL error"); + + data->ssl = SSL_new(data->ctx); + CHK_NULL(data->ssl, "internal ssl error"); + + SSL_set_fd(data->ssl, sd); + n = SSL_connect(data->ssl); + CHK_SSL(n, "internal ssl error"); + + server_cert = SSL_get_peer_certificate(data->ssl); + CHK_NULL(server_cert, "server cert error"); + + str = X509_NAME_oneline(X509_get_subject_name(server_cert), 0, 0); + CHK_NULL(str, "error in server cert"); + OPENSSL_free(str); + + str = X509_NAME_oneline(X509_get_issuer_name(server_cert), 0, 0); + CHK_NULL(str, "error in server cert"); + OPENSSL_free(str); + + X509_free(server_cert); + } + + + n = recvtimeoutssl(sd, buf, sizeof(buf), 10, use_ssl, data->ssl); + + + snprintf(buf, sizeof(buf)-1, "USER %s\r\n", username); + + write1(sd, buf, use_ssl, data->ssl); + n = recvtimeoutssl(sd, buf, sizeof(buf), 10, use_ssl, data->ssl); + + + snprintf(buf, sizeof(buf)-1, "PASS %s\r\n", password); + + write1(sd, buf, use_ssl, data->ssl); + n = recvtimeoutssl(sd, buf, sizeof(buf), 10, use_ssl, data->ssl); + + if(strncmp(buf, "+OK", 3) == 0) return OK; + + return OK; +} + + +int process_pop3_emails(int sd, struct session_data *sdata, struct __data *data, int use_ssl, struct __config *cfg){ + int i, rc=ERR, n, messages=0, processed_messages=0, pos, endpos, len, readlen, fd, lastpos, nreads; + char *p, buf[MAXBUFSIZE], filename[SMALLBUFSIZE]; + char aggrbuf[3*MAXBUFSIZE]; + + snprintf(buf, sizeof(buf)-1, "STAT\r\n"); + n = write1(sd, buf, use_ssl, data->ssl); + + n = recvtimeoutssl(sd, buf, sizeof(buf), 10, use_ssl, data->ssl); + + if(strncmp(buf, "+OK ", 4) == 0){ + p = strchr(&buf[4], ' '); + if(p){ + *p = '\0'; + messages = atoi(&buf[4]); + } + } + else return ERR; + + + printf("found %d messages\n", messages); + + if(messages <= 0) return rc; + + for(i=1; i<=messages; i++){ + processed_messages++; + printf("processed: %7d\r", processed_messages); fflush(stdout); + + + snprintf(buf, sizeof(buf)-1, "RETR %d\r\n", i); + + snprintf(filename, sizeof(filename)-1, "pop3-tmp-%d.txt", i); + unlink(filename); + + fd = open(filename, O_CREAT|O_EXCL|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR); + if(fd == -1){ + printf("cannot open: %s\n", filename); + return rc; + } + + n = write1(sd, buf, use_ssl, data->ssl); + + readlen = 0; + pos = 0; + len = 0; + nreads = 0; + endpos = 0; + + memset(aggrbuf, 0, sizeof(aggrbuf)); + lastpos = 0; + + + while((n = recvtimeoutssl(sd, buf, sizeof(buf), 15, use_ssl, data->ssl)) > 0){ + nreads++; + readlen += n; + + if(nreads == 1){ + + if(strncmp(buf, "+OK ", 4) == 0){ + p = strchr(&buf[4], '\n'); + if(p){ + *p = '\0'; + pos = strlen(buf)+1; + *p = '\n'; + } + } + else { printf("error: %s", buf); return ERR; } + + } + + if(lastpos + 1 + n < sizeof(aggrbuf)){ + + if(nreads == 1){ + memcpy(aggrbuf+lastpos, buf+pos, n-pos); + lastpos += n-pos; + } + else { + memcpy(aggrbuf+lastpos, buf, n); + lastpos += n; + } + } + else { + write(fd, aggrbuf, sizeof(buf)); + + memmove(aggrbuf, aggrbuf+sizeof(buf), lastpos-sizeof(buf)); + lastpos -= sizeof(buf); + + memcpy(aggrbuf+lastpos, buf, n); + lastpos += n; + } + + if(is_last_complete_pop3_packet(aggrbuf, lastpos) == 1){ + write(fd, aggrbuf, lastpos-3); + break; + } + + } + + close(fd); + + rc = import_message(filename, sdata, data, cfg); + + unlink(filename); + } + + + snprintf(buf, sizeof(buf)-1, "QUIT\r\n"); + n = write1(sd, buf, use_ssl, data->ssl); + + printf("\n"); + + return OK; +} + +