]> Pileus Git - ~andy/fetchmail/commitdiff
Re-engineer the UIDL stuff to avoid having the status flag collide
authorEric S. Raymond <esr@thyrsus.com>
Fri, 13 Mar 1998 20:20:19 +0000 (20:20 -0000)
committerEric S. Raymond <esr@thyrsus.com>
Fri, 13 Mar 1998 20:20:19 +0000 (20:20 -0000)
with message numbers.

svn path=/trunk/; revision=1699

NEWS
driver.c
fetchmail.c
fetchmail.h
options.c
pop3.c
rcfile_y.y
uid.c

diff --git a/NEWS b/NEWS
index 6a19dbc4856e719405af4f7437a0bfc3bdf7f33e..e78cf49680efac3719034db1cd3543d1937f7108 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -20,6 +20,7 @@ fetchmail-4.4.0 ():
 * Fix bug that prevented graceful exit from POP3 validation on wrong password.
 * Dominique Unruh's patch that copes gracefully with bodiless messages.
 * Fix timer-leak problem pointed ouit by Dave Bodenstab.
+* Improvements in UID handling; should be a cleaner fix for Dick van den Burg.
 
 There are 268 people on fetchmail-friends and 160 on fetchmail-announce.
 
index b14d9a61e024a176e1b98389b100747ca4ca1597..018b17ccf3ce7b4f9ec30fe261e1aedb30581d74 100644 (file)
--- a/driver.c
+++ b/driver.c
@@ -248,7 +248,7 @@ static int is_host_alias(const char *name, struct query *ctl)
     }
 
     /* add this name to relevant server's `also known as' list */
-    save_str(&lead_server->akalist, -1, name);
+    save_str(&lead_server->akalist, name, 0);
     return(TRUE);
 #endif /* HAVE_RES_SEARCH */
 }
@@ -281,7 +281,7 @@ struct idlist **xmit_names; /* list of recipient names parsed out */
        }
        if (outlevel == O_VERBOSE)
            error(0, 0, "mapped %s to local %s", name, lname+off);
-       save_str(xmit_names, XMIT_ACCEPT, lname+off);
+       save_str(xmit_names, lname+off, XMIT_ACCEPT);
        accept_count++;
     }
 }
@@ -323,7 +323,7 @@ struct idlist **xmit_names; /* list of recipient names parsed out */
                        if (outlevel == O_VERBOSE)
                            error(0, 0, "passed through %s matching %s", 
                                  cp, idp->id);
-                       save_str(xmit_names, XMIT_ACCEPT, cp);
+                       save_str(xmit_names, cp, XMIT_ACCEPT);
                        accept_count++;
                        break;
                    }
@@ -339,7 +339,7 @@ struct idlist **xmit_names; /* list of recipient names parsed out */
                 */
                if (!is_host_alias(atsign+1, ctl))
                {
-                   save_str(xmit_names, XMIT_REJECT, cp);
+                   save_str(xmit_names, cp, XMIT_REJECT);
                    reject_count++;
                    continue;
                }
@@ -879,16 +879,19 @@ int num;          /* index of message */
 
        else if (!strncasecmp("Content-Transfer-Encoding:", line, 26))
            ctt_offs = (line - headers);
-       else if (!strncasecmp("Message-Id:", buf, 11 ))
+       else if (!strncasecmp("Message-Id:", buf, 11))
        {
-           if( ctl->server.uidl )
+           if (ctl->server.uidl)
            {
                char id[IDLEN+1];
-               /* prevent stack overflows */
-               buf[IDLEN+12] = 0;
-               sscanf( buf+12, "%s", id);
-               if( !str_find( &ctl->newsaved, num ) )
-                   save_str(&ctl->newsaved, num, id );
+
+               buf[IDLEN+12] = 0;              /* prevent stack overflow */
+               sscanf(buf+12, "%s", id);
+               if (!str_find( &ctl->newsaved, num))
+               {
+                   struct idlist *new = save_str(&ctl->newsaved,id,UID_SEEN);
+                   new->val.status.num = num;
+               }
            }
        }
 
@@ -1050,7 +1053,7 @@ int num;          /* index of message */
        if (!accept_count)
        {
            no_local_matches = TRUE;
-           save_str(&xmit_names, XMIT_ACCEPT, user);
+           save_str(&xmit_names, user, XMIT_ACCEPT);
            if (outlevel == O_VERBOSE)
                error(0, 0, 
                      "no local matches, forwarding to %s",
@@ -1058,7 +1061,7 @@ int num;          /* index of message */
        }
     }
     else       /* it's a single-drop box, use first localname */
-       save_str(&xmit_names, XMIT_ACCEPT, ctl->localnames->id);
+       save_str(&xmit_names, ctl->localnames->id, XMIT_ACCEPT);
 
 
     /*
@@ -1078,7 +1081,7 @@ int num;          /* index of message */
        char    *names, *before, *after;
 
        for (idp = xmit_names; idp; idp = idp->next)
-           if (idp->val.num == XMIT_ACCEPT)
+           if (idp->val.status.mark == XMIT_ACCEPT)
                good_addresses++;
 
        destaddr = "localhost";
@@ -1105,13 +1108,13 @@ int num;                /* index of message */
             * long lists of users and (re)implement %s.
             */
            for (idp = xmit_names; idp; idp = idp->next)
-               if (idp->val.num == XMIT_ACCEPT)
+               if (idp->val.status.mark == XMIT_ACCEPT)
                    length += (strlen(idp->id) + 1);
 
            names = (char *)xmalloc(++length);
            names[0] = '\0';
            for (idp = xmit_names; idp; idp = idp->next)
-               if (idp->val.num == XMIT_ACCEPT)
+               if (idp->val.status.mark == XMIT_ACCEPT)
                {
                    strcat(names, idp->id);
                    strcat(names, " ");
@@ -1318,7 +1321,7 @@ int num;          /* index of message */
        destaddr = ctl->smtpaddress ? ctl->smtpaddress : ( ctl->smtphost ? ctl->smtphost : "localhost");
        
        for (idp = xmit_names; idp; idp = idp->next)
-           if (idp->val.num == XMIT_ACCEPT)
+           if (idp->val.status.mark == XMIT_ACCEPT)
            {
                if (strchr(idp->id, '@'))
                    strcpy(addr, idp->id);
@@ -1334,7 +1337,7 @@ int num;          /* index of message */
                else
                {
                    bad_addresses++;
-                   idp->val.num = XMIT_ANTISPAM;
+                   idp->val.status.mark = XMIT_ANTISPAM;
                    error(0, 0, 
                          "SMTP listener doesn't like recipient address `%s'",
                          addr);
@@ -1406,7 +1409,7 @@ int num;          /* index of message */
                else if (good_addresses == 1)
                {
                    for (idp = xmit_names; idp; idp = idp->next)
-                       if (idp->val.num == XMIT_ACCEPT)
+                       if (idp->val.status.mark == XMIT_ACCEPT)
                            break;      /* only report first address */
                    if (strchr(idp->id, '@'))
                        sprintf(buf+1, "for <%s>", idp->id);
@@ -1475,7 +1478,7 @@ int num;          /* index of message */
            else
            {
                for (idp = xmit_names; idp; idp = idp->next)
-                   if (idp->val.num == XMIT_REJECT)
+                   if (idp->val.status.mark == XMIT_REJECT)
                        break;
                sprintf(errhd+strlen(errhd), "recipient address %s didn't match any local name", idp->id);
            }
@@ -1495,13 +1498,13 @@ int num;                /* index of message */
            strcat(errhd, "SMTP listener rejected local recipient addresses: ");
            errlen = strlen(errhd);
            for (idp = xmit_names; idp; idp = idp->next)
-               if (idp->val.num == XMIT_ANTISPAM)
+               if (idp->val.status.mark == XMIT_ANTISPAM)
                    errlen += strlen(idp->id) + 2;
 
            errmsg = alloca(errlen+3);
            (void) strcpy(errmsg, errhd);
            for (idp = xmit_names; idp; idp = idp->next)
-               if (idp->val.num == XMIT_ANTISPAM)
+               if (idp->val.status.mark == XMIT_ANTISPAM)
                {
                    strcat(errmsg, idp->id);
                    if (idp->next)
@@ -2248,8 +2251,8 @@ const struct method *proto;       /* protocol method table */
                            struct idlist       *sdp;
 
                            for (sdp = ctl->newsaved; sdp; sdp = sdp->next)
-                               if (sdp->val.num == num)
-                                   MARK_SEEN(sdp->val.num);
+                               if (sdp->val.status.num == num)
+                                   sdp->val.status.mark = UID_SEEN;
                        }
 
                        /* maybe we delete this message now? */
index da259b05a86fe366d142c9784114c2d06379dfbc..52ffa5f33d76810c1671ce85b53866deed7e85b1 100644 (file)
@@ -719,7 +719,7 @@ static int load_params(int argc, char **argv, int optind)
 
            /* make sure we have a nonempty host list to forward to */
            if (!ctl->smtphunt)
-               save_str(&ctl->smtphunt, FALSE, fetchmailhost);
+               save_str(&ctl->smtphunt, fetchmailhost, FALSE);
 
            /* keep lusers from shooting themselves in the foot :-) */
            if (poll_interval && ctl->limit)
@@ -792,7 +792,7 @@ static int load_params(int argc, char **argv, int optind)
 
            /* if no folders were specified, set up the null one as default */
            if (!ctl->mailboxes)
-               save_str(&ctl->mailboxes, -1, (char *)NULL);
+               save_str(&ctl->mailboxes, (char *)NULL, 0);
 
            /* maybe user overrode timeout on command line? */
            if (ctl->server.timeout == -1)      
@@ -1102,10 +1102,10 @@ void dump_params (struct query *ctl)
 
        printf("  Messages will be SMTP-forwarded to:");
        for (idp = ctl->smtphunt; idp; idp = idp->next)
-           if (ctl->server.protocol != P_ETRN || idp->val.num)
+           if (ctl->server.protocol != P_ETRN || idp->val.status.mark)
            {
                printf(" %s", idp->id);
-               if (!idp->val.num)
+               if (!idp->val.status.mark)
                    printf(" (default)");
            }
        printf("\n");
index 259add67de90c42b5b92a0c89308e830dcf0bd29..9480ddb06505da55c80dabbd52217606ffa394f2 100644 (file)
 
 #define                SIZETICKER      1024    /* print 1 dot per this many bytes */
 
+/*
+ * We #ifdef this and use flag rather than bool
+ * to avoid a type clash with curses.h
+ */
+#ifndef TRUE
+#define FALSE  0
+#define TRUE   1
+#endif /* TRUE */
+typedef        char    flag;
+
 /* we need to use zero as a flag-uninitialized value */
 #define FLAG_TRUE      2
 #define FLAG_FALSE     1
@@ -75,22 +85,21 @@ struct idlist
     char *id;
     union
     {
-       int num;
+       struct
+       {
+           short       num;
+           flag        mark;           /* UID-index information */
+#define UID_UNSEEN     0               /* hasn't been seen */
+#define UID_SEEN       1               /* seen, but not deleted */
+#define UID_DELETED    2               /* this message has been deleted */
+#define UID_EXPUNGED   3               /* this message has been expunged */ 
+        }
+       status;
        char *id2;
     } val;
     struct idlist *next;
 };
 
-/*
- * We #ifdef this and use flag rather than bool
- * to avoid a type clash with curses.h
- */
-#ifndef TRUE
-#define FALSE  0
-#define TRUE   1
-#endif /* TRUE */
-typedef        char    flag;
-
 struct hostdata                /* shared among all user connections to given server */
 {
     /* rc file data */
@@ -174,17 +183,6 @@ struct query
     struct query *next;                /* next query control block in chain */
 };
 
-/*
- * UID-index information.  If the sign bit is on, this means the 
- * message UID has been seen or expunged and should be written
- * out to .fetchids at end of run.
- */
-#define UID_KEPT       0               /* remembered from a previous run */
-#define UID_DELETED    INT_MIN         /* this message has been deleted */
-#define UID_EXPUNGED   INT_MAX         /* this message has been expunged */ 
-#define SAVE_UID(n)    ((n) <= 0)      /* must this UID be saved? */
-#define MARK_SEEN(n)   n *= -1         /* mark a UID seen */
-
 /*
  * Numeric option handling.  Numeric option value of zero actually means
  * it's unspecified.  Value less than zero is zero.
@@ -299,7 +297,7 @@ char *nxtaddr(const char *);
 
 /* uid.c: UID support */
 void initialize_saved_lists(struct query *, const char *);
-struct idlist *save_str(struct idlist **, int, const char *);
+struct idlist *save_str(struct idlist **, const char *, flag);
 void free_str_list(struct idlist **);
 void save_str_pair(struct idlist **, const char *, const char *);
 void free_str_pair_list(struct idlist **);
index f104c1a256aceca2095af06049ec0217ebdfd0f9..ffa50e4769834cf0c34941a2b21fcf5a93ed421b 100644 (file)
--- a/options.c
+++ b/options.c
@@ -312,7 +312,7 @@ struct query *ctl;  /* option record to be initialized */
            strcpy(buf, optarg);
            cp = strtok(buf, ",");
            do {
-               save_str(&ctl->mailboxes, -1, cp);
+               save_str(&ctl->mailboxes, cp, 0);
            } while
                ((cp = strtok((char *)NULL, ",")));
            break;
@@ -321,7 +321,7 @@ struct query *ctl;  /* option record to be initialized */
            strcpy(buf, optarg);
            cp = strtok(buf, ",");
            do {
-               save_str(&ctl->smtphunt, TRUE, cp);
+               save_str(&ctl->smtphunt, cp, TRUE);
            } while
                ((cp = strtok((char *)NULL, ",")));
            ocount++;
diff --git a/pop3.c b/pop3.c
index 3004e747d3b84e9260e2e7db173b693aa7b610ac..1634755b624df7bde8ff94601b1cf7b05ca4f96f 100644 (file)
--- a/pop3.c
+++ b/pop3.c
@@ -331,11 +331,14 @@ pop3_slowuidl( int sock,  struct query *ctl, int *countp, int *newp)
            }
        } 
     }
-    /* The first try_id messages are known -> copy them to
-       the newsaved list */
+    /* 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 ));
+    {
+       struct idlist   *new = save_str(&ctl->newsaved, 
+                               str_from_nr_list(&ctl->oldsaved, num),
+                               UID_UNSEEN);
+       new->val.status.num = num - first_nr + 1;
+    }
 
     if( nolinear ) {
        free_str_list(&ctl->oldsaved);
@@ -424,10 +427,15 @@ static int pop3_getrange(int sock,
                        break;
                    else if (sscanf(buf, "%d %s", &num, id) == 2)
                    {
-                       save_str(&ctl->newsaved, num, id);
+                       struct idlist   *new;
+
+                       new = save_str(&ctl->newsaved, id, UID_UNSEEN);
+                       new->val.status.num = num;
 
                        /* note: ID comparison is caseblind */
-                       if (!str_in_list(&ctl->oldsaved, id))
+                       if (str_in_list(&ctl->oldsaved, id))
+                           new->val.status.mark = UID_SEEN;
+                       else
                            (*newp)++;
                    }
                }
index 68d61c7ebdf8ddb8bd8d2061ad62ade5ab2a582b..9c536bdf77543e101c2a9515d532a362ae581087 100644 (file)
@@ -115,12 +115,12 @@ serverspecs       : /* EMPTY */
                | serverspecs serv_option
                ;
 
-alias_list     : STRING                {save_str(&current.server.akalist,-1,$1);}
-               | alias_list STRING     {save_str(&current.server.akalist,-1,$2);}
+alias_list     : STRING                {save_str(&current.server.akalist,$1,0);}
+               | alias_list STRING     {save_str(&current.server.akalist,$2,0);}
                ;
 
-domain_list    : STRING                {save_str(&current.server.localdomains,-1,$1);}
-               | domain_list STRING    {save_str(&current.server.localdomains,-1,$2);}
+domain_list    : STRING                {save_str(&current.server.localdomains,$1,0);}
+               | domain_list STRING    {save_str(&current.server.localdomains,$2,0);}
                ;
 
 serv_option    : AKA alias_list
@@ -252,12 +252,12 @@ mapping           : STRING
                                {save_str_pair(&current.localnames, $1, $3);}
                ;
 
-folder_list    : STRING                {save_str(&current.mailboxes,-1,$1);}
-               | folder_list STRING    {save_str(&current.mailboxes,-1,$2);}
+folder_list    : STRING                {save_str(&current.mailboxes,$1,0);}
+               | folder_list STRING    {save_str(&current.mailboxes,$2,0);}
                ;
 
-smtp_list      : STRING                {save_str(&current.smtphunt, TRUE,$1);}
-               | smtp_list STRING      {save_str(&current.smtphunt, TRUE,$2);}
+smtp_list      : STRING                {save_str(&current.smtphunt, $1,TRUE);}
+               | smtp_list STRING      {save_str(&current.smtphunt, $2,TRUE);}
                ;
 
 user_option    : TO localnames HERE
diff --git a/uid.c b/uid.c
index 1a9046563040d0caa29ed0f7a5524f5c1130ceda..ecc6b0b46dcfce1307777ef7aa9e729404172e50 100644 (file)
--- a/uid.c
+++ b/uid.c
@@ -93,14 +93,14 @@ void initialize_saved_lists(struct query *hostlist, const char *idfile)
                        strcasecmp(host, ctl->server.truename) == 0
                                && strcasecmp(user, ctl->remotename) == 0)
                    {
-                       save_str(&ctl->oldsaved, UID_KEPT, id);
+                       save_str(&ctl->oldsaved, id, UID_SEEN);
                        break;
                    }
                }
 
                /* if it's not in a host we're querying, save it anyway */
                if (ctl == (struct query *)NULL)
-                   save_str(&scratchlist, UID_KEPT, buf);
+                   save_str(&scratchlist, buf, UID_SEEN);
            }
        }
        fclose(tmpfp);
@@ -108,7 +108,7 @@ void initialize_saved_lists(struct query *hostlist, const char *idfile)
 }
 #endif /* POP3_ENABLE */
 
-struct idlist *save_str(struct idlist **idl, int num, const char *str)
+struct idlist *save_str(struct idlist **idl, const char *str, flag status)
 /* save a number/UID pair on the given UID list */
 {
     struct idlist **end;
@@ -118,7 +118,7 @@ struct idlist *save_str(struct idlist **idl, int num, const char *str)
        continue;
 
     *end = (struct idlist *)xmalloc(sizeof(struct idlist));
-    (*end)->val.num = num;
+    (*end)->val.status.mark = status;
     (*end)->id = str ? xstrdup(str) : (char *)NULL;
     (*end)->next = NULL;
 
@@ -231,7 +231,7 @@ char *str_find(struct idlist **idl, int number)
 {
     if (*idl == (struct idlist *) 0)
        return((char *) 0);
-    else if (number == (*idl)->val.num)
+    else if (number == (*idl)->val.status.num)
        return((*idl)->id);
     else
        return(str_find(&(*idl)->next, number));
@@ -251,31 +251,15 @@ char *idpair_find(struct idlist **idl, const char *id)
 int delete_str(struct idlist **idl, int num)
 /* delete given message from given list */
 {
-#ifdef HARD_DELETE     /* not used */
-    if (*idl == (struct idlist *)NULL)
-       return(0);
-    else if ((*idl)->val.num == num)
-    {
-       struct idlist   *next = (*idl)->next;
-
-       free ((*idl)->id);
-       free(*idl);
-       *idl = next;
-       return(1);
-    }
-    else
-       return(delete_str(&(*idl)->next, num));
-#else
     struct idlist      *idp;
 
     for (idp = *idl; idp; idp = idp->next)
-       if (idp->val.num == num)
+       if (idp->val.status.num == num)
        {
-           idp->val.num = UID_DELETED;
+           idp->val.status.mark = UID_DELETED;
            return(1);
        }
     return(0);
-#endif /* HARD_DELETE */
 }
 
 void append_str_list(struct idlist **idl, struct idlist **nidl)
@@ -296,8 +280,8 @@ void expunge_uids(struct query *ctl)
     struct idlist *idl;
 
     for (idl = ctl->newsaved; idl; idl = idl->next)
-       if (idl->val.num == UID_DELETED)
-           idl->val.num = UID_EXPUNGED;
+       if (idl->val.status.mark == UID_DELETED)
+           idl->val.status.mark = UID_EXPUNGED;
 }
 
 void update_str_lists(struct query *ctl)
@@ -330,7 +314,8 @@ void write_saved_lists(struct query *hostlist, const char *idfile)
        if ((tmpfp = fopen(idfile, "w")) != (FILE *)NULL) {
            for (ctl = hostlist; ctl; ctl = ctl->next) {
                for (idp = ctl->oldsaved; idp; idp = idp->next)
-                   if (SAVE_UID(idp->val.num))
+                   if (idp->val.status.mark == UID_SEEN
+                               || idp->val.status.mark == UID_DELETED)
                        fprintf(tmpfp, "%s@%s %s\n", 
                            ctl->remotename, ctl->server.truename, idp->id);
            }