aboutsummaryrefslogtreecommitdiffstats
path: root/pop3.c
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>1997-08-16 00:02:36 +0000
committerEric S. Raymond <esr@thyrsus.com>1997-08-16 00:02:36 +0000
commita755ecd2b0a3c8e800feeeae5fb8d6212d065266 (patch)
tree980843273f37ef8da2f2f0a67308cc0d5a084b26 /pop3.c
parent31593524646b3495fb82500528bf935b181d454b (diff)
downloadfetchmail-a755ecd2b0a3c8e800feeeae5fb8d6212d065266.tar.gz
fetchmail-a755ecd2b0a3c8e800feeeae5fb8d6212d065266.tar.bz2
fetchmail-a755ecd2b0a3c8e800feeeae5fb8d6212d065266.zip
Wolfgang Wander's patch for better UIDL-only support.
svn path=/trunk/; revision=1272
Diffstat (limited to 'pop3.c')
-rw-r--r--pop3.c117
1 files changed, 114 insertions, 3 deletions
diff --git a/pop3.c b/pop3.c
index e5e26299..5b8f53b9 100644
--- a/pop3.c
+++ b/pop3.c
@@ -199,6 +199,113 @@ int pop3_getauth(int sock, struct query *ctl, char *greeting)
return(0);
}
+static int
+pop3_gettopid( int sock, int num , char *id)
+{
+ int ok;
+ int got_it;
+ char buf [POPBUFSIZE+1];
+ sprintf( buf, "TOP %d 1", num );
+ if( (ok = gen_transact(sock, buf ) ) != 0 )
+ return ok;
+ got_it = 0;
+ while((ok = gen_recv(sock, buf, sizeof(buf))) == 0) {
+ if( buf[0] == '.' )
+ break;
+ if( ! got_it && ! strncasecmp("Message-Id:", buf, 11 )) {
+ got_it = 1;
+ sscanf( buf+12, "%s", id);
+ }
+ }
+ return 0;
+}
+
+static int
+pop3_slowuidl( int sock, struct query *ctl, int *countp, int *newp)
+{
+ /* This approach tries to get the message headers from the
+ * remote hosts and compares the message-id to the already known
+ * ones:
+ * + if the first message containes a new id, all messages on
+ * the server will be new
+ * + if the first is known, try to estimate the last known message
+ * on the server and check. If this works you know the total number
+ * of messages to get.
+ * + Otherwise run a binary search to determine the last known message
+ */
+ int ok, nolinear = 0;
+ int first_nr, list_len, try_id, try_nr, hop_id, add_id;
+ int num;
+ char id [IDLEN+1];
+
+ if( (ok = pop3_gettopid( sock, 1, id )) != 0 )
+ return ok;
+
+ if( ( first_nr = str_nr_in_list(&ctl->oldsaved, id) ) == -1 ) {
+ /* the first message is unknown -> all messages are new */
+ *newp = *countp;
+ return 0;
+ }
+
+ /* check where we expect the latest known message */
+ list_len = count_list( &ctl->oldsaved );
+ try_id = list_len - first_nr; /* -1 + 1 */
+ if( try_id > 1 ) {
+ if( try_id <= *countp ) {
+ if( (ok = pop3_gettopid( sock, try_id, id )) != 0 )
+ return ok;
+
+ try_nr = str_nr_in_list(&ctl->oldsaved, id);
+ } else {
+ try_id = *countp+1;
+ try_nr = -1;
+ }
+ if( try_nr != list_len -1 ) {
+ /* some messages inbetween have been deleted... */
+ if( try_nr == -1 ) {
+ nolinear = 1;
+
+ for( add_id = 1<<30; add_id > try_id-1; add_id >>= 1 )
+ ;
+ for( ; add_id; add_id >>= 1 ) {
+ if( try_nr == -1 ) {
+ if( try_id - add_id <= 1 ) {
+ continue;
+ }
+ try_id -= add_id;
+ } else
+ try_id += add_id;
+
+ if( (ok = pop3_gettopid( sock, try_id, id )) != 0 )
+ return ok;
+ try_nr = str_nr_in_list(&ctl->oldsaved, id);
+ }
+ if( try_nr == -1 ) {
+ try_id--;
+ }
+ } else {
+ error(0,0,"Messages inserted into list on server. "
+ "Cannot handle this.");
+ return -1;
+ }
+ }
+ }
+ /* The first try_id messages are known -> copy them to
+ the newsaved list */
+ for( num = first_nr; num < list_len; num++ )
+ save_str(&ctl->newsaved, num-first_nr + 1,
+ str_from_nr_list( &ctl->oldsaved, num ));
+
+ if( nolinear ) {
+ free_str_list(&ctl->oldsaved);
+ ctl->oldsaved = 0;
+ last = try_id;
+ }
+
+ *newp = *countp - try_id;
+ return 0;
+}
+
static int pop3_getrange(int sock,
struct query *ctl,
const char *folder,
@@ -243,9 +350,13 @@ static int pop3_getrange(int sock,
}
else
{
- /* grab the mailbox's UID list */
- if ((ok = gen_transact(sock, "UIDL")) != 0)
- PROTOCOL_ERROR
+ /* grab the mailbox's UID list */
+ if ((ok = gen_transact(sock, "UIDL")) != 0)
+ {
+ /* don't worry, yet! do it the slow way */
+ if((ok = pop3_slowuidl( sock, ctl, countp, newp))!=0)
+ PROTOCOL_ERROR
+ }
else
{
int num;