fixing a parser bug in process_imap_folder()

This commit is contained in:
SJ 2012-08-06 12:42:35 +02:00
parent 5ee5644ae7
commit ec0f324601
2 changed files with 147 additions and 91 deletions

View File

@ -38,16 +38,58 @@ unsigned long resolve_host(char *host){
}
int process_imap_folder(int sd, int *seq, char *folder, struct session_data *sdata, struct __data *data, struct __config *cfg){
int rc=ERR, i, n, pos, messages=0, len, readlen, fd;
char *p, *q, tag[SMALLBUFSIZE], tagok[SMALLBUFSIZE], buf[MAXBUFSIZE], puf[MAXBUFSIZE], filename[SMALLBUFSIZE];
int get_message_length_from_imap_answer(char *s, int *_1st_line_bytes){
char *p, *q;
int len=0;
p = strstr(s, "\r\n");
if(!p){
printf("invalid reply: %s", s);
return len;
}
*p = '\0';
*_1st_line_bytes = strlen(s)+2;
if(*(p-1) == '}') *(p-1) = '\0';
q = strchr(s, '{');
if(q){
q++;
len = atoi(q);
}
*(p-1) = '}';
*p = '\r';
return len;
}
int is_last_complete_packet(char *s, int len, char *tagok, char *tagbad){
if(*(s+len-2) == '\r' && *(s+len-1) == '\n'){
if(strstr(s, tagok)) return 1;
if(strstr(s, tagbad)) return 1;
}
return 0;
}
int process_imap_folder(int sd, int *seq, char *folder, struct session_data *sdata, struct __data *data, struct __config *cfg){
int rc=ERR, i, n, pos, messages=0, len, readlen, fd, lastpos, nreads, processed_messages=0;
char *p, tag[SMALLBUFSIZE], tagok[SMALLBUFSIZE], tagbad[SMALLBUFSIZE], buf[MAXBUFSIZE], filename[SMALLBUFSIZE];
char aggrbuf[3*MAXBUFSIZE];
snprintf(tag, sizeof(tag)-1, "A%d", *seq); snprintf(tagok, sizeof(tagok)-1, "\r\nA%d OK", (*seq)++);
snprintf(buf, sizeof(buf)-1, "%s SELECT %s\r\n", tag, folder);
snprintf(buf, sizeof(buf)-1, "%s SELECT \"%s\"\r\n", tag, folder);
send(sd, buf, strlen(buf), 0);
n = recvtimeout(sd, buf, MAXBUFSIZE, 10);
n = recvtimeout(sd, buf, MAXBUFSIZE, 10);
if(!strstr(buf, tagok)){
trimBuffer(buf);
@ -55,27 +97,28 @@ int process_imap_folder(int sd, int *seq, char *folder, struct session_data *sda
return rc;
}
p = &buf[0];
do {
memset(puf, 0, sizeof(puf));
p = split(p, '\n', puf, sizeof(puf)-1);
q = strstr(puf, " EXISTS");
if(q){
*q = '\0';
messages = atoi(puf+2);
p = strstr(buf, " EXISTS");
if(p){
*p = '\0';
p = strrchr(buf, '\n');
if(p){
while(!isdigit(*p)){ p++; }
messages = atoi(p);
}
}
} while(p);
printf("found %d messages\n", messages);
if(messages <= 0) return rc;
for(i=1; i<=messages; i++){
snprintf(tag, sizeof(tag)-1, "A%d", *seq); snprintf(tagok, sizeof(tagok)-1, "\r\nA%d OK", (*seq)++);
for(i=1; i<=messages; i++){
printf("processed: %7d\r", processed_messages); fflush(stdout);
processed_messages++;
snprintf(tag, sizeof(tag)-1, "A%d", *seq);
snprintf(tagok, sizeof(tagok)-1, "\r\nA%d OK", (*seq)++);
snprintf(tagbad, sizeof(tagbad)-1, "\r\n%s BAD", tag);
snprintf(buf, sizeof(buf)-1, "%s FETCH %d (BODY.PEEK[])\r\n", tag, i);
snprintf(filename, sizeof(filename)-1, "%s-%d.txt", folder, i);
@ -89,69 +132,59 @@ int process_imap_folder(int sd, int *seq, char *folder, struct session_data *sda
send(sd, buf, strlen(buf), 0);
memset(buf, 0, sizeof(buf));
n = recvtimeout(sd, buf, MAXBUFSIZE, 10);
readlen = 0;
pos = 0;
len = 0;
nreads = 0;
memset(aggrbuf, 0, sizeof(aggrbuf));
lastpos = 0;
len = 0; readlen = n;
p = strstr(buf, "\r\n");
if(!p){
printf("invalid reply: %s", buf);
continue;
}
*p = '\0';
pos = strlen(buf) + 2;
if(*(p-1) == '}') *(p-1) = '\0';
q = strchr(buf, '{');
if(q){
q++;
len = atoi(q);
}
if(len < 10){
printf("too short message: %s\n", buf);
continue;
}
n -= pos;
q = strstr(p+2, tagok);
if(q){
n -= strlen(q) + 1;
}
write(fd, p+2, n);
while(readlen < len){
memset(buf, 0, sizeof(buf));
n = recvtimeout(sd, buf, MAXBUFSIZE, 3);
while((n = recvtimeout(sd, buf, sizeof(buf), 15)) > 0){
nreads++;
readlen += n;
p = strstr(buf, tagok);
if(p){
n -= strlen(p)+1;
if(nreads == 1){
len = get_message_length_from_imap_answer(buf, &pos);
if(len < 10){
printf("%d: too short message! %s\n", i, buf);
break;
}
}
write(fd, buf, n);
if(lastpos + n + sizeof(buf) > sizeof(aggrbuf)){
write(fd, aggrbuf, lastpos);
memset(aggrbuf, 0, sizeof(aggrbuf));
lastpos = 0;
}
memcpy(aggrbuf+lastpos, buf, n);
lastpos += n;
if(is_last_complete_packet(aggrbuf, lastpos, tagok, tagbad) == 1){
write(fd, aggrbuf, lastpos);
break;
}
else {
write(fd, aggrbuf, lastpos-n);
memmove(aggrbuf, aggrbuf+lastpos-n, n);
lastpos = n;
memset(aggrbuf+lastpos, 0, sizeof(aggrbuf)-lastpos);
}
}
close(fd);
rc = import_message(filename, sdata, data, cfg);
unlink(filename);
}
printf("\n");
return OK;
}
@ -180,7 +213,6 @@ int connect_to_imap_server(int sd, int *seq, char *imapserver, char *username, c
}
n = recvtimeout(sd, buf, MAXBUFSIZE, 10);
//printf("connected...\n");
/*
@ -209,8 +241,6 @@ int connect_to_imap_server(int sd, int *seq, char *imapserver, char *username, c
return ERR;
}
//printf("logged in...\n");
return OK;
}
@ -219,11 +249,9 @@ int list_folders(int sd, int *seq, char *folders, int foldersize){
int n;
char *p, *q, tag[SMALLBUFSIZE], tagok[SMALLBUFSIZE], buf[MAXBUFSIZE], puf[MAXBUFSIZE];
snprintf(folders, foldersize-1, "INBOX");
snprintf(tag, sizeof(tag)-1, "A%d", *seq); snprintf(tagok, sizeof(tagok)-1, "A%d OK", (*seq)++);
snprintf(buf, sizeof(buf)-1, "%s LIST \"\" %%\r\n", tag);
//snprintf(buf, sizeof(buf)-1, "%s LIST \"\" %%\r\n", tag);
snprintf(buf, sizeof(buf)-1, "%s LIST \"\" \"*\"\r\n", tag);
send(sd, buf, strlen(buf), 0);
@ -236,15 +264,17 @@ int list_folders(int sd, int *seq, char *folders, int foldersize){
trimBuffer(puf);
if(strncmp(puf, "* LIST ", 7) == 0){
q = strrchr(puf, ' ');
q = strstr(puf, "\".\"");
if(q){
if(*(q+1) == '"') q += 2;
if(puf[strlen(puf)-1] == '"') puf[strlen(puf)-1] = '\0';
q += 3;
if(*q == ' ') q++;
if(*q == '"') q++;
if(q[strlen(q)-1] == '"') q[strlen(q)-1] = '\0';
if(strncasecmp(q, "junk", 4) && strncasecmp(q, "trash", 5) && strncasecmp(q, "spam", 4) && strncasecmp(q, "draft", 5)){
strncat(folders, "\n", foldersize-1);
strncat(folders, q, foldersize-1);
}
}
}
@ -254,7 +284,6 @@ int list_folders(int sd, int *seq, char *folders, int foldersize){
} while(p);
return 0;
}

View File

@ -21,6 +21,7 @@
extern char *optarg;
extern int optind;
#define SKIPLIST "junk,trash,spam,draft"
int connect_to_imap_server(int sd, int *seq, char *imapserver, char *username, char *password);
int list_folders(int sd, int *seq, char *folders, int foldersize);
@ -123,9 +124,10 @@ int import_from_maildir(char *directory, struct session_data *sdata, struct __da
}
int import_from_imap_server(char *imapserver, char *username, char *password, struct session_data *sdata, struct __data *data, struct __config *cfg){
int rc=ERR, ret=OK, sd, seq=1;
char *p, puf[MAXBUFSIZE];
int import_from_imap_server(char *imapserver, char *username, char *password, struct session_data *sdata, struct __data *data, char *skiplist, struct __config *cfg){
int rc=ERR, ret=OK, sd, seq=1, skipmatch;
char *p, puf[SMALLBUFSIZE];
char *q, muf[SMALLBUFSIZE];
char folders[MAXBUFSIZE];
if((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
@ -147,6 +149,27 @@ int import_from_imap_server(char *imapserver, char *username, char *password, st
memset(puf, 0, sizeof(puf));
p = split(p, '\n', puf, sizeof(puf)-1);
if(strlen(puf) < 1) continue;
skipmatch = 0;
if(skiplist && strlen(skiplist) > 0){
q = skiplist;
do {
memset(muf, 0, sizeof(muf));
q = split(q, ',', muf, sizeof(muf)-1);
if(strncasecmp(puf, muf, strlen(muf)) == 0){
skipmatch = 1;
break;
}
} while(q);
}
if(skipmatch == 1){
printf("SKIPPING FOLDER: %s\n", puf);
continue;
}
printf("processing folder: %s... ", puf);
rc = process_imap_folder(sd, &seq, puf, sdata, data, cfg);
@ -170,13 +193,13 @@ void usage(){
int main(int argc, char **argv){
int i, rc=0;
char *configfile=CONFIG_FILE, *mailbox=NULL, *emlfile=NULL, *directory=NULL;
char *imapserver=NULL, *username=NULL, *password=NULL;
char *imapserver=NULL, *username=NULL, *password=NULL, *skiplist=SKIPLIST;
struct session_data sdata;
struct __config cfg;
struct __data data;
while((i = getopt(argc, argv, "c:m:e:d:i:u:p:h?")) > 0){
while((i = getopt(argc, argv, "c:m:e:d:i:u:p:x:h?")) > 0){
switch(i){
case 'c' :
@ -207,6 +230,10 @@ int main(int argc, char **argv){
password = optarg;
break;
case 'x' :
skiplist = optarg;
break;
case 'h' :
case '?' :
usage();
@ -253,7 +280,7 @@ int main(int argc, char **argv){
if(emlfile) rc = import_message(emlfile, &sdata, &data, &cfg);
if(mailbox) rc = import_from_mailbox(mailbox, &sdata, &data, &cfg);
if(directory) rc = import_from_maildir(directory, &sdata, &data, &cfg);
if(imapserver && username && password) rc = import_from_imap_server(imapserver, username, password, &sdata, &data, &cfg);
if(imapserver && username && password) rc = import_from_imap_server(imapserver, username, password, &sdata, &data, skiplist, &cfg);