From 69ccc9f8610694134a3a33206f86d14c0f4a2bf9 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Sun, 28 Mar 2010 23:49:00 +0200 Subject: [PATCH] pop3: Get message listing if no mailbox in URL If you pass a URL to pop3 that does not contain a message ID as part of the URL, it will currently ask for 'INBOX' which just causes the pop3 server to return an error. The change makes libcurl treat en empty message ID as a request for LIST (list of pop3 message IDs). User's code could then parse this and download individual messages as desired. --- lib/pop3.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++---- lib/pop3.h | 1 + 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/lib/pop3.c b/lib/pop3.c index 320f75644..ff929b09c 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -232,6 +232,7 @@ static void state(struct connectdata *conn, "USER", "PASS", "STARTTLS", + "LIST", "RETR", "QUIT", /* LAST */ @@ -382,7 +383,49 @@ static CURLcode pop3_state_retr_resp(struct connectdata *conn, return result; } -/* start the DO phase */ + +/* for the list response */ +static CURLcode pop3_state_list_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct FTP *pop3 = data->state.proto.pop3; + struct pop3_conn *pop3c = &conn->proto.pop3c; + struct pingpong *pp = &pop3c->pp; + + (void)instate; /* no use for this yet */ + + if('O' != pop3code) { + state(conn, POP3_STOP); + return CURLE_RECV_ERROR; + } + + /* POP3 download */ + result=Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, + pop3->bytecountp, + -1, NULL); /* no upload here */ + + if(pp->cache) { + /* cache holds the email ID listing */ + + /* we may get the EOB already here! */ + result = Curl_pop3_write(conn, pp->cache, pp->cache_size); + if(result) + return result; + + /* cache is drained */ + free(pp->cache); + pp->cache = NULL; + pp->cache_size = 0; + } + + state(conn, POP3_STOP); + return result; +} + +/* start the DO phase for RETR */ static CURLcode pop3_retr(struct connectdata *conn) { CURLcode result = CURLE_OK; @@ -396,6 +439,20 @@ static CURLcode pop3_retr(struct connectdata *conn) return result; } +/* start the DO phase for LIST */ +static CURLcode pop3_list(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST %s", pop3c->mailbox); + if(result) + return result; + + state(conn, POP3_LIST); + return result; +} + static CURLcode pop3_statemach_act(struct connectdata *conn) { CURLcode result; @@ -451,6 +508,10 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_retr_resp(conn, pop3code, pop3c->state); break; + case POP3_LIST: + result = pop3_state_list_resp(conn, pop3code, pop3c->state); + break; + case POP3_QUIT: /* fallthrough, just stop! */ default: @@ -655,6 +716,7 @@ CURLcode pop3_perform(struct connectdata *conn, { /* this is POP3 and no proxy */ CURLcode result=CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; DEBUGF(infof(conn->data, "DO phase starts\n")); @@ -667,7 +729,13 @@ CURLcode pop3_perform(struct connectdata *conn, *dophase_done = FALSE; /* not done yet */ /* start the first command in the DO phase */ - result = pop3_retr(conn); + /* If mailbox is empty, then assume user wants listing for mail IDs, + * otherwise, attempt to retrieve the mail-id stored in mailbox + */ + if (strlen(pop3c->mailbox)) + result = pop3_retr(conn); + else + result = pop3_list(conn); if(result) return result; @@ -785,9 +853,6 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn) const char *path = data->state.path; int len; - if(!*path) - path = "INBOX"; - /* url decode the path and use this mailbox */ pop3c->mailbox = curl_easy_unescape(data, path, 0, &len); diff --git a/lib/pop3.h b/lib/pop3.h index 3076287fd..20a226985 100644 --- a/lib/pop3.h +++ b/lib/pop3.h @@ -32,6 +32,7 @@ typedef enum { POP3_USER, POP3_PASS, POP3_STARTTLS, + POP3_LIST, POP3_RETR, POP3_QUIT, POP3_LAST /* never used */