diff --git a/src/imap.c b/src/imap.c index ade7dc9..9c2ccfe 100644 --- a/src/imap.c +++ b/src/imap.c @@ -38,16 +38,58 @@ } -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 @@ 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 @@ 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 @@ } n = recvtimeout(sd, buf, MAXBUFSIZE, 10); - //printf("connected...\n"); /* @@ -209,8 +241,6 @@ return ERR; } - //printf("logged in...\n"); - return OK; } @@ -219,11 +249,9 @@ 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 @@ 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(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); - } + if(q[strlen(q)-1] == '"') q[strlen(q)-1] = '\0'; + + strncat(folders, "\n", foldersize-1); + strncat(folders, q, foldersize-1); } } @@ -254,7 +284,6 @@ } while(p); - return 0; } diff --git a/src/pilerimport.c b/src/pilerimport.c index ac77cef..6ebbcb5 100644 --- a/src/pilerimport.c +++ b/src/pilerimport.c @@ -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,11 +124,12 @@ } -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){ printf("cannot create socket\n"); return ERR; @@ -147,6 +149,27 @@ 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 @@ 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 @@ password = optarg; break; + case 'x' : + skiplist = optarg; + break; + case 'h' : case '?' : usage(); @@ -253,7 +280,7 @@ 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);