piler/src/pop3.c

245 lines
6.0 KiB
C
Raw Normal View History

2012-11-24 23:02:08 +01:00
/*
* pop3.c, SJ
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/time.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <fcntl.h>
#include <ctype.h>
#include <syslog.h>
#include <unistd.h>
#include <limits.h>
#include <piler.h>
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(struct data *data){
2012-11-24 23:02:08 +01:00
int n;
char buf[MAXBUFSIZE];
X509* server_cert;
char *str;
if(data->net->use_ssl == 1){
2012-11-24 23:02:08 +01:00
SSL_library_init();
SSL_load_error_strings();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
data->net->ctx = SSL_CTX_new(TLSv1_client_method());
#else
data->net->ctx = SSL_CTX_new(TLS_client_method());
#endif
CHK_NULL(data->net->ctx, "internal SSL error");
2012-11-24 23:02:08 +01:00
data->net->ssl = SSL_new(data->net->ctx);
CHK_NULL(data->net->ssl, "internal ssl error");
2012-11-24 23:02:08 +01:00
SSL_set_fd(data->net->ssl, data->net->socket);
n = SSL_connect(data->net->ssl);
2012-11-24 23:02:08 +01:00
CHK_SSL(n, "internal ssl error");
printf("Cipher: %s\n", SSL_get_cipher(data->net->ssl));
2014-10-15 23:22:36 +02:00
server_cert = SSL_get_peer_certificate(data->net->ssl);
2012-11-24 23:02:08 +01:00
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);
}
recvtimeoutssl(data->net, buf, sizeof(buf));
2012-11-24 23:02:08 +01:00
snprintf(buf, sizeof(buf)-1, "USER %s\r\n", data->import->username);
2012-11-24 23:02:08 +01:00
write1(data->net, buf, strlen(buf));
recvtimeoutssl(data->net, buf, sizeof(buf));
2012-11-24 23:02:08 +01:00
snprintf(buf, sizeof(buf)-1, "PASS %s\r\n", data->import->password);
2012-11-24 23:02:08 +01:00
write1(data->net, buf, strlen(buf));
recvtimeoutssl(data->net, buf, sizeof(buf));
2012-11-24 23:02:08 +01:00
if(strncmp(buf, "+OK", 3) == 0) return OK;
printf("error: %s", buf);
2013-08-23 13:46:27 +02:00
return ERR;
2012-11-24 23:02:08 +01:00
}
void get_number_of_total_messages(struct data *data){
char *p, buf[MAXBUFSIZE];
2012-11-24 23:02:08 +01:00
2013-08-23 13:02:51 +02:00
data->import->total_messages = 0;
2012-11-24 23:02:08 +01:00
snprintf(buf, sizeof(buf)-1, "STAT\r\n");
write1(data->net, buf, strlen(buf));
2012-11-24 23:02:08 +01:00
recvtimeoutssl(data->net, buf, sizeof(buf));
2012-11-24 23:02:08 +01:00
if(strncmp(buf, "+OK ", 4) == 0){
p = strchr(&buf[4], ' ');
if(p){
*p = '\0';
2013-08-23 13:02:51 +02:00
data->import->total_messages = atoi(&buf[4]);
2012-11-24 23:02:08 +01:00
}
}
else {
printf("ERROR: '%s'", buf);
}
}
2012-11-24 23:02:08 +01:00
int pop3_download_email(struct data *data, int i){
int n, fd, pos=0, readlen=0, lastpos=0, nreads=0;
char *p, buf[MAXBUFSIZE];
char aggrbuf[3*MAXBUFSIZE];
2012-11-24 23:02:08 +01:00
data->import->processed_messages++;
2012-11-24 23:02:08 +01:00
snprintf(data->import->filename, SMALLBUFSIZE-1, "pop3-tmp-%d-%d.txt", getpid(), i);
unlink(data->import->filename);
fd = open(data->import->filename, O_CREAT|O_EXCL|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR);
if(fd == -1){
printf("cannot open: %s\n", data->import->filename);
return ERR;
}
2012-11-24 23:02:08 +01:00
snprintf(buf, sizeof(buf)-1, "RETR %d\r\n", i);
write1(data->net, buf, strlen(buf));
2012-11-24 23:02:08 +01:00
memset(aggrbuf, 0, sizeof(aggrbuf));
2012-11-24 23:02:08 +01:00
while((n = recvtimeoutssl(data->net, buf, sizeof(buf))) > 0){
nreads++;
readlen += n;
if(nreads == 1){
if(strncmp(buf, "+OK", 3) == 0){
p = strchr(&buf[3], '\n');
if(p){
*p = '\0';
pos = strlen(buf)+1;
*p = '\n';
}
}
else { printf("error: %s", buf); return ERR; }
2012-11-24 23:02:08 +01:00
}
if((uint)(lastpos + 1 + n) < sizeof(aggrbuf)){
2012-11-24 23:02:08 +01:00
if(nreads == 1){
memcpy(aggrbuf+lastpos, buf+pos, n-pos);
lastpos += n-pos;
}
else {
memcpy(aggrbuf+lastpos, buf, n);
lastpos += n;
}
}
else {
if(write(fd, aggrbuf, sizeof(buf)) == -1) printf("ERROR: writing to fd\n");
2012-11-24 23:02:08 +01:00
memmove(aggrbuf, aggrbuf+sizeof(buf), lastpos-sizeof(buf));
lastpos -= sizeof(buf);
2012-11-24 23:02:08 +01:00
memcpy(aggrbuf+lastpos, buf, n);
lastpos += n;
}
2012-11-24 23:02:08 +01:00
if(is_last_complete_pop3_packet(aggrbuf, lastpos) == 1){
if(write(fd, aggrbuf, lastpos-3) == -1) printf("ERROR: writing to fd\n");
break;
}
}
2012-11-24 23:02:08 +01:00
close(fd);
2012-11-24 23:02:08 +01:00
return OK;
}
2012-11-24 23:02:08 +01:00
void pop3_delete_message(struct data *data, int i){
char buf[SMALLBUFSIZE];
2012-11-24 23:02:08 +01:00
snprintf(buf, sizeof(buf)-1, "DELE %d\r\n", i);
write1(data->net, buf, strlen(buf));
recvtimeoutssl(data->net, buf, sizeof(buf));
}
2012-11-24 23:02:08 +01:00
void process_pop3_emails(struct session_data *sdata, struct data *data, struct config *cfg){
int i=0, rc=ERR;
char buf[MAXBUFSIZE];
2012-11-24 23:02:08 +01:00
data->import->processed_messages = 0;
2012-11-24 23:02:08 +01:00
get_number_of_total_messages(data);
2012-11-24 23:02:08 +01:00
if(data->quiet == 0) printf("found %d messages\n", data->import->total_messages);
2012-11-24 23:02:08 +01:00
if(data->import->total_messages <= 0) return;
2013-08-23 13:02:51 +02:00
for(i=data->import->start_position; i<=data->import->total_messages; i++){
if(pop3_download_email(data, i) == OK){
if(data->quiet == 0){ printf("processed: %7d [%3d%%]\r", data->import->processed_messages, 100*i/data->import->total_messages); fflush(stdout); }
if(data->import->dryrun == 0){
rc = import_message(sdata, data, cfg);
2012-11-24 23:02:08 +01:00
if(data->import->remove_after_import == 1 && rc == OK){
pop3_delete_message(data, i);
}
}
}
if(data->import->download_only == 0) unlink(data->import->filename);
/* whether to quit after processing a batch of messages */
if(data->import->batch_processing_limit > 0 && data->import->processed_messages >= data->import->batch_processing_limit){
break;
}
2012-11-24 23:02:08 +01:00
}
snprintf(buf, sizeof(buf)-1, "QUIT\r\n");
write1(data->net, buf, strlen(buf));
2012-11-24 23:02:08 +01:00
2014-09-04 14:57:23 +02:00
if(data->quiet == 0) printf("\n");
2012-11-24 23:02:08 +01:00
}