Back to index

courier  0.68.2
Classes | Defines | Functions
imaprefs.c File Reference
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "rfc822.h"
#include "imaprefs.h"

Go to the source code of this file.

Classes

struct  imap_threadsortinfo

Defines

#define swap(a, b, tmp)   (tmp)=(a); (a)=(b); (b)=(tmp);
#define HMIDS   (((struct imap_refmsgtable *)0)->hashtable)
#define HHMIDSS   ( sizeof(HMIDS) / sizeof( HMIDS[0] ))

Functions

static void swapmsgdata (struct imap_refmsg *a, struct imap_refmsg *b)
struct imap_refmsgtablerfc822_threadalloc ()
void rfc822_threadfree (struct imap_refmsgtable *p)
static int hashmsgid (const char *msgid)
struct imap_refmsgrfc822_threadallocmsg (struct imap_refmsgtable *mt, const char *msgid)
struct imap_refmsgrfc822_threadsearchmsg (struct imap_refmsgtable *mt, const char *msgid)
static int findsubj (struct imap_refmsgtable *mt, const char *s, int *isrefwd, int create, struct imap_subjlookup **ptr)
static void linkparent (struct imap_refmsg *msg, struct imap_refmsg *lastmsg)
static void breakparent (struct imap_refmsg *m)
static struct imap_refmsgdorefcreate (struct imap_refmsgtable *mt, const char *newmsgid, struct rfc822a *a)
static struct imap_refmsgthreadmsg_common (struct imap_refmsg *m, const char *subjheader, const char *dateheader, time_t dateheader_tm, unsigned long seqnum)
static struct imap_refmsgrfc822_threadmsgaref (struct imap_refmsgtable *mt, const char *msgidhdr, struct rfc822a *refhdr, const char *subjheader, const char *dateheader, time_t dateheader_tm, unsigned long seqnum)
struct imap_refmsgrfc822_threadmsg (struct imap_refmsgtable *mt, const char *msgidhdr, const char *refhdr, const char *subjheader, const char *dateheader, time_t dateheader_tm, unsigned long seqnum)
struct imap_refmsgrfc822_threadmsgrefs (struct imap_refmsgtable *mt, const char *msgid_s, const char *const *msgidList, const char *subjheader, const char *dateheader, time_t dateheader_tm, unsigned long seqnum)
struct imap_refmsgrfc822_threadgetroot (struct imap_refmsgtable *mt)
void rfc822_threadprune (struct imap_refmsgtable *mt)
static int cmp_msgs (const void *, const void *)
int rfc822_threadsortsubj (struct imap_refmsg *root)
int rfc822_threadgathersubj (struct imap_refmsgtable *mt, struct imap_refmsg *root)
int rfc822_threadmergesubj (struct imap_refmsgtable *mt, struct imap_refmsg *root)
static int dothreadsort (struct imap_threadsortinfo *, struct imap_refmsg *)
int rfc822_threadsortbydate (struct imap_refmsgtable *mt)
struct imap_refmsgrfc822_thread (struct imap_refmsgtable *mt)

Class Documentation

struct imap_threadsortinfo

Definition at line 974 of file imaprefs.c.

Collaboration diagram for imap_threadsortinfo:
Class Members
struct imap_refmsgtable * mt
struct imap_refmsg ** sort_table
size_t sort_table_cnt

Define Documentation

#define HHMIDSS   ( sizeof(HMIDS) / sizeof( HMIDS[0] ))
#define HMIDS   (((struct imap_refmsgtable *)0)->hashtable)
#define swap (   a,
  b,
  tmp 
)    (tmp)=(a); (a)=(b); (b)=(tmp);

Function Documentation

static void breakparent ( struct imap_refmsg m) [static]

Definition at line 217 of file imaprefs.c.

{
       if (!m->parent)      return;

       if (m->prevsib)      m->prevsib->nextsib=m->nextsib;
       else          m->parent->firstchild=m->nextsib;

       if (m->nextsib)      m->nextsib->prevsib=m->prevsib;
       else          m->parent->lastchild=m->prevsib;
       m->parent=0;
}

Here is the caller graph for this function:

static int cmp_msgs ( const void *  a,
const void *  b 
) [static]

Definition at line 944 of file imaprefs.c.

{
       struct imap_refmsg *ma=*(struct imap_refmsg **)a;
       struct imap_refmsg *mb=*(struct imap_refmsg **)b;
       time_t ta, tb;
       unsigned long na, nb;

       while (ma && ma->isdummy)
              ma=ma->firstchild;

       while (mb && mb->isdummy)
              mb=mb->firstchild;

       ta=tb=0;
       na=nb=0;
       if (ma)
       {
              ta=ma->timestamp;
              na=ma->seqnum;
       }
       if (mb)
       {
              tb=mb->timestamp;
              nb=mb->seqnum;
       }

       return (ta && tb && ta != tb ? ta < tb ? -1: 1:
              na < nb ? -1: na > nb ? 1:0);
}

Here is the caller graph for this function:

static struct imap_refmsg* dorefcreate ( struct imap_refmsgtable mt,
const char *  newmsgid,
struct rfc822a a 
) [static, read]

Definition at line 229 of file imaprefs.c.

{
struct imap_refmsg *lastmsg=0, *m;
struct imap_refmsg *msg;
int n;

/*
            (A) Using the Message-IDs in the message's references, link
            the corresponding messages together as parent/child.  Make
            the first reference the parent of the second (and the second
            a child of the first), the second the parent of the third
            (and the third a child of the second), etc.  The following
            rules govern the creation of these links:

               If no reference message can be found with a given
               Message-ID, create a dummy message with this ID.  Use
               this dummy message for all subsequent references to this
               ID.
*/

       for (n=0; n<a->naddrs; n++)
       {
              char *msgid=a->addrs[n].tokens ? rfc822_getaddr(a, n):NULL;

              msg=msgid ? rfc822_threadsearchmsg(mt, msgid):0;
              if (!msg)
              {
                     msg=rfc822_threadallocmsg(mt, msgid ? msgid:"");
                     if (!msg)
                     {
                            if (msgid)
                                   free(msgid);

                            return (0);
                     }
                     msg->isdummy=1;
              }

              if (msgid)
                     free(msgid);

/*
               If a reference message already has a parent, don't change
               the existing link.
*/

              if (lastmsg == 0 || msg->parent)
              {
                     lastmsg=msg;
                     continue;
              }

/*
               Do not create a parent/child link if creating that link
               would introduce a loop.  For example, before making
               message A the parent of B, make sure that A is not a
               descendent of B.

*/

              for (m=lastmsg; m; m=m->parent)
                     if (strcmp(m->msgid, msg->msgid) == 0)
                            break;
              if (m)
              {
                     lastmsg=msg;
                     continue;
              }

              linkparent(msg, lastmsg);

              lastmsg=msg;
       }

/*
            (B) Create a parent/child link between the last reference
            (or NIL if there are no references) and the current message.
            If the current message has a parent already, break the
            current parent/child link before creating the new one.  Note
            that if this message has no references, that it will now
            have no parent.

               NOTE: The parent/child links MUST be kept consistent with
               one another at ALL times.

*/

       msg=*newmsgid ? rfc822_threadsearchmsg(mt, newmsgid):0;

       /*
              If a message does not contain a Message-ID header line,
              or the Message-ID header line does not contain a valid
              Message ID, then assign a unique Message ID to this
              message.

              Implementation note: empty msgid, plus dupe check below,
              implements that.
       */

       if (msg && msg->isdummy)
       {
              msg->isdummy=0;
              if (msg->parent)
                     breakparent(msg);
       }
       else
       {
#if 1
              /*
              ** If two or more messages have the same Message ID, assign
              ** a unique Message ID to each of the duplicates.
              **
              ** Implementation note: just unlink the existing message from
              ** it's parents/children.
              */
              if (msg)
              {
                     while (msg->firstchild)
                            breakparent(msg->firstchild);
                     breakparent(msg);
                     newmsgid="";

                     /* Create new entry with an empty msgid, if any more
                     ** msgids come, they'll hit the dupe check again.
                     */

              }
#endif
              msg=rfc822_threadallocmsg(mt, newmsgid);
              if (!msg)     return (0);
       }

       if (lastmsg)
       {
              for (m=lastmsg; m; m=m->parent)
                     if (strcmp(m->msgid, msg->msgid) == 0)
                            break;
              if (!m)
                     linkparent(msg, lastmsg);
       }
       return (msg);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int dothreadsort ( struct imap_threadsortinfo itsi,
struct imap_refmsg p 
) [static]

Definition at line 999 of file imaprefs.c.

{
       struct imap_refmsg *q;
       size_t i, n;

       for (q=p->firstchild; q; q=q->nextsib)
              dothreadsort(itsi, q);

       n=0;
       for (q=p->firstchild; q; q=q->nextsib)
              ++n;

       if (n > itsi->sort_table_cnt)
       {
              struct imap_refmsg **new_array=(struct imap_refmsg **)
                     (itsi->sort_table ?
                      realloc(itsi->sort_table,
                             sizeof(struct imap_refmsg *)*n)
                      :malloc(sizeof(struct imap_refmsg *)*n));

              if (!new_array)
                     return (-1);

              itsi->sort_table=new_array;
              itsi->sort_table_cnt=n;
       }

       n=0;
       while ((q=p->firstchild) != 0)
       {
              breakparent(q);
              itsi->sort_table[n++]=q;
       }

       qsort(itsi->sort_table, n, sizeof(struct imap_refmsg *), cmp_msgs);

       for (i=0; i<n; i++)
              linkparent(itsi->sort_table[i], p);
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int findsubj ( struct imap_refmsgtable mt,
const char *  s,
int *  isrefwd,
int  create,
struct imap_subjlookup **  ptr 
) [static]

Definition at line 157 of file imaprefs.c.

{
       char *ss=rfc822_coresubj(s, isrefwd);
       int n;
       struct imap_subjlookup **h;
       struct imap_subjlookup *newsubj;

       if (!ss)      return (-1);
       n=hashmsgid(ss);

       for (h= &mt->subjtable[n]; *h; h= &(*h)->nextsubj)
       {
       int    rc=strcmp((*h)->subj, ss);

              if (rc == 0)
              {
                     free(ss);
                     *ptr= *h;
                     return (0);
              }
              if (rc > 0)
                     break;
       }
       if (!create)
       {
              free(ss);
              *ptr=0;
              return (0);
       }

       newsubj=malloc(sizeof(struct imap_subjlookup));
       if (!newsubj)
       {
              free(ss);
              return (-1);
       }
       memset(newsubj, 0, sizeof(*newsubj));
       newsubj->subj=ss;
       newsubj->nextsubj= *h;
       newsubj->msgisrefwd= *isrefwd;
       *h=newsubj;
       *ptr=newsubj;
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int hashmsgid ( const char *  msgid) [static]

Definition at line 80 of file imaprefs.c.

{
unsigned long hashno=0;

       while (*msgid)
       {
       unsigned long n= (hashno << 1);

#define       HMIDS  (((struct imap_refmsgtable *)0)->hashtable)
#define       HHMIDSS       ( sizeof(HMIDS) / sizeof( HMIDS[0] ))

              if (hashno & HHMIDSS )
                     n ^= 1;

              hashno= n ^ (unsigned char)*msgid++;
       }

       return (hashno % HHMIDSS);
}

Here is the caller graph for this function:

static void linkparent ( struct imap_refmsg msg,
struct imap_refmsg lastmsg 
) [static]

Definition at line 203 of file imaprefs.c.

{
       msg->parent=lastmsg;
       msg->prevsib=lastmsg->lastchild;
       if (msg->prevsib)
              msg->prevsib->nextsib=msg;
       else
              lastmsg->firstchild=msg;

       lastmsg->lastchild=msg;
       msg->nextsib=0;
}

Here is the caller graph for this function:

struct imap_refmsg* rfc822_thread ( struct imap_refmsgtable mt) [read]

Definition at line 1041 of file imaprefs.c.

{
       if (!mt->rootptr)
       {
              rfc822_threadprune(mt);
              if ((mt->rootptr=rfc822_threadgetroot(mt)) == 0)
                     return (0);
              if (rfc822_threadsortsubj(mt->rootptr) ||
                  rfc822_threadgathersubj(mt, mt->rootptr) ||
                  rfc822_threadmergesubj(mt, mt->rootptr) ||
                  rfc822_threadsortbydate(mt))
              {
                     mt->rootptr=0;
                     return (0);
              }
       }

       return (mt->rootptr);
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct imap_refmsgtable* rfc822_threadalloc ( void  ) [read]

Definition at line 38 of file imaprefs.c.

{
struct imap_refmsgtable *p;

       p=(struct imap_refmsgtable *)malloc(sizeof(struct imap_refmsgtable));
       if (p)
              memset(p, 0, sizeof(*p));
       return (p);
}

Here is the caller graph for this function:

struct imap_refmsg* rfc822_threadallocmsg ( struct imap_refmsgtable mt,
const char *  msgid 
) [read]

Definition at line 100 of file imaprefs.c.

{
int n=hashmsgid(msgid);
struct imap_refmsg *msgp= (struct imap_refmsg *)
       malloc(sizeof(struct imap_refmsg)+1+strlen(msgid));
struct imap_refmsghash *h, **hp;

       if (!msgp)    return (0);
       memset(msgp, 0, sizeof(*msgp));
       strcpy ((msgp->msgid=(char *)(msgp+1)), msgid);

       h=(struct imap_refmsghash *)malloc(sizeof(struct imap_refmsghash));
       if (!h)
       {
              free(msgp);
              return (0);
       }

       for (hp= &mt->hashtable[n]; *hp; hp= & (*hp)->nexthash)
       {
              if (strcmp( (*hp)->msg->msgid, msgp->msgid) > 0)
                     break;
       }

       h->nexthash= *hp;
       *hp=h;
       h->msg=msgp;

       msgp->last=mt->lastmsg;

       if (mt->lastmsg)
              mt->lastmsg->next=msgp;
       else
              mt->firstmsg=msgp;

       mt->lastmsg=msgp;
       return (msgp);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rfc822_threadfree ( struct imap_refmsgtable p)

Definition at line 48 of file imaprefs.c.

{
int i;
struct imap_refmsghash *h;
struct imap_subjlookup *s;
struct imap_refmsg *m;

       for (i=0; i<sizeof(p->hashtable)/sizeof(p->hashtable[0]); i++)
              while ((h=p->hashtable[i]) != 0)
              {
                     p->hashtable[i]=h->nexthash;
                     free(h);
              }

       for (i=0; i<sizeof(p->subjtable)/sizeof(p->subjtable[0]); i++)
              while ((s=p->subjtable[i]) != 0)
              {
                     p->subjtable[i]=s->nextsubj;
                     free(s->subj);
                     free(s);
              }

       while ((m=p->firstmsg) != 0)
       {
              p->firstmsg=m->next;
              if (m->subj)
                     free(m->subj);
              free(m);
       }
       free(p);
}

Here is the caller graph for this function:

int rfc822_threadgathersubj ( struct imap_refmsgtable mt,
struct imap_refmsg root 
)

Definition at line 671 of file imaprefs.c.

{
       struct imap_refmsg *toproot, *p;

/*
** (5) Gather together messages under the root that have the same
** extracted subject text.
**
** (A) Create a table for associating extracted subjects with
** messages.
**
** (B) Populate the subject table with one message per
** extracted subject.  For each message under the root:
*/

       for (toproot=root->firstchild; toproot; toproot=toproot->nextsib)
       {
              const char *subj;
              struct imap_subjlookup *subjtop;
              int isrefwd;

              /*
              ** (i) Find the subject of this thread by extracting the
              ** base subject from the current message, or its first child
              ** if the current message is a dummy.
              */

              p=toproot;
              if (p->isdummy)
                     p=p->firstchild;

              subj=p->subj ? p->subj:"";


              /*
              ** (ii) If the extracted subject is empty, skip this
              ** message.
              */

              if (*subj == 0)
                     continue;

              /*
              ** (iii) Lookup the message associated with this extracted
              ** subject in the table.
              */

              if (findsubj(mt, subj, &isrefwd, 1, &subjtop))
                     return (-1);

              /*
              **
              ** (iv) If there is no message in the table with this
              ** subject, add the current message and the extracted
              ** subject to the subject table.
              */

              if (subjtop->msg == 0)
              {
                     subjtop->msg=toproot;
                     subjtop->msgisrefwd=isrefwd;
                     continue;
              }

              /*
              ** Otherwise, replace the message in the table with the
              ** current message if the message in the table is not a
              ** dummy AND either of the following criteria are true:
              */

              if (!subjtop->msg->isdummy)
              {
                     /*
                     ** The current message is a dummy
                     **
                     */

                     if (toproot->isdummy)
                     {
                            subjtop->msg=toproot;
                            subjtop->msgisrefwd=isrefwd;
                            continue;
                     }

                     /*
                     ** The message in the table is a reply or forward (its
                     ** original subject contains a subj-refwd part and/or a
                     ** "(fwd)" subj-trailer) and the current message is
                     not.
                     */

                     if (subjtop->msgisrefwd && !isrefwd)
                     {
                            subjtop->msg=toproot;
                            subjtop->msgisrefwd=isrefwd;
                     }
              }
       }
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct imap_refmsg* rfc822_threadgetroot ( struct imap_refmsgtable mt) [read]

Definition at line 543 of file imaprefs.c.

{
       struct imap_refmsg *root, *m;

       if (mt->rootptr)
              return (mt->rootptr);

       root=rfc822_threadallocmsg(mt, "(root)");

       if (!root)    return (0);

       root->parent=root;   /* Temporary */
       root->isdummy=1;

       for (m=mt->firstmsg; m; m=m->next)
              if (!m->parent)
              {
                     if (m->isdummy && m->firstchild == 0)
                            continue; /* Can happen in reference creation */

                     linkparent(m, root);
              }
       root->parent=NULL;
       return (mt->rootptr=root);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int rfc822_threadmergesubj ( struct imap_refmsgtable mt,
struct imap_refmsg root 
)

Definition at line 778 of file imaprefs.c.

{
       struct imap_refmsg *toproot, *p, *q, *nextroot;
       char *str;

       for (toproot=root->firstchild; toproot; toproot=nextroot)
       {
              const char *subj;
              struct imap_subjlookup *subjtop;
              int isrefwd;

              nextroot=toproot->nextsib;

              /*
              ** (i) Find the subject of this thread as in step 4.B.i
              ** above.
              */

              p=toproot;
              if (p->isdummy)
                     p=p->firstchild;

              subj=p->subj ? p->subj:"";

              /*
              ** (ii) If the extracted subject is empty, skip this
              ** message.
              */

              if (*subj == 0)
                     continue;

              /*
              ** (iii) Lookup the message associated with this extracted
              ** subject in the table.
              */

              if (findsubj(mt, subj, &isrefwd, 0, &subjtop) || subjtop == 0)
                     return (-1);

              /*
              ** (iv) If the message in the table is the current message,
              ** skip it.
              */

              /* NOTE - ptr comparison IS NOT LEGAL */

              subjtop->msg->flag2=1;
              if (toproot->flag2)
              {
                     toproot->flag2=0;
                     continue;
              }
              subjtop->msg->flag2=0;

              /*
              ** Otherwise, merge the current message with the one in the
              ** table using the following rules:
              **
              ** If both messages are dummies, append the current
              ** message's children to the children of the message in
              ** the table (the children of both messages become
              ** siblings), and then delete the current message.
              */

              if (subjtop->msg->isdummy && toproot->isdummy)
              {
                     while ((p=toproot->firstchild) != 0)
                     {
                            breakparent(p);
                            linkparent(p, subjtop->msg);
                     }
                     breakparent(toproot);
                     continue;
              }

              /*
              ** If the message in the table is a dummy and the current
              ** message is not, make the current message a child of
              ** the message in the table (a sibling of it's children).
              */

              if (subjtop->msg->isdummy)
              {
                     breakparent(toproot);
                     linkparent(toproot, subjtop->msg);
                     continue;
              }

              /*
              ** If the current message is a reply or forward and the
              ** message in the table is not, make the current message
              ** a child of the message in the table (a sibling of it's
              ** children).
              */

              if (isrefwd)
              {
                     p=subjtop->msg;
                     if (p->isdummy)
                            p=p->firstchild;

                     subj=p->subj ? p->subj:"";

                     str=rfc822_coresubj(subj, &isrefwd);

                     if (!str)
                            return (-1);
                     free(str);    /* Don't really care */

                     if (!isrefwd)
                     {
                            breakparent(toproot);
                            linkparent(toproot, subjtop->msg);
                            continue;
                     }
              }

              /*
              ** Otherwise, create a new dummy container and make both
              ** messages children of the dummy, and replace the
              ** message in the table with the dummy message.
              */

              /* What we do is create a new message, then move the
              ** contents of subjtop->msg (including its children)
              ** to the new message, then make the new message a child
              ** of subjtop->msg, and mark subjtop->msg as a dummy msg.
              */

              q=rfc822_threadallocmsg(mt, "(dummy)");
              if (!q)
                     return (-1);

              q->isdummy=1;

              swapmsgdata(q, subjtop->msg);

              while ((p=subjtop->msg->firstchild) != 0)
              {
                     breakparent(p);
                     linkparent(p, q);
              }
              linkparent(q, subjtop->msg);

              breakparent(toproot);
              linkparent(toproot, subjtop->msg);
       }
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct imap_refmsg* rfc822_threadmsg ( struct imap_refmsgtable mt,
const char *  msgidhdr,
const char *  refhdr,
const char *  subjheader,
const char *  dateheader,
time_t  dateheader_tm,
unsigned long  seqnum 
) [read]

Definition at line 389 of file imaprefs.c.

{
       struct rfc822t *t;
       struct rfc822a *a;
       struct imap_refmsg *m;

       t=rfc822t_alloc_new(refhdr ? refhdr:"", NULL, NULL);
       if (!t)
       {
              return (0);
       }

       a=rfc822a_alloc(t);
       if (!a)
       {
              rfc822t_free(t);
              return (0);
       }

       m=rfc822_threadmsgaref(mt, msgidhdr, a, subjheader, dateheader,
                            dateheader_tm, seqnum);

       rfc822a_free(a);
       rfc822t_free(t);
       return m;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct imap_refmsg * rfc822_threadmsgaref ( struct imap_refmsgtable mt,
const char *  msgidhdr,
struct rfc822a refhdr,
const char *  subjheader,
const char *  dateheader,
time_t  dateheader_tm,
unsigned long  seqnum 
) [static, read]

Definition at line 472 of file imaprefs.c.

{
       struct rfc822t *t;
       struct rfc822a *a;
       struct imap_refmsg *m;

       char *msgid_s;

       t=rfc822t_alloc_new(msgidhdr ? msgidhdr:"", NULL, NULL);
       if (!t)
              return (0);
       a=rfc822a_alloc(t);
       if (!a)
       {
              rfc822t_free(t);
              return (0);
       }

       msgid_s=a->naddrs > 0 ? rfc822_getaddr(a, 0):strdup("");

       rfc822a_free(a);
       rfc822t_free(t);

       if (!msgid_s)
              return (0);

       m=dorefcreate(mt, msgid_s, refhdr);

       free(msgid_s);

       if (!m)
              return (0);


       return threadmsg_common(m, subjheader, dateheader,
                            dateheader_tm, seqnum);
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct imap_refmsg* rfc822_threadmsgrefs ( struct imap_refmsgtable mt,
const char *  msgid_s,
const char *const *  msgidList,
const char *  subjheader,
const char *  dateheader,
time_t  dateheader_tm,
unsigned long  seqnum 
) [read]

Definition at line 423 of file imaprefs.c.

{
       struct imap_refmsg *m;
       struct rfc822token *tArray;
       struct rfc822addr *aArray;

       struct rfc822a a;
       size_t n, i;

       for (n=0; msgidList[n]; n++)
              ;

       if ((tArray=malloc((n+1) * sizeof(*tArray))) == NULL)
              return NULL;

       if ((aArray=malloc((n+1) * sizeof(*aArray))) == NULL)
       {
              free(tArray);
              return NULL;
       }

       for (i=0; i<n; i++)
       {
              tArray[i].next=NULL;
              tArray[i].token=0;
              tArray[i].ptr=msgidList[i];
              tArray[i].len=strlen(msgidList[i]);

              aArray[i].name=NULL;
              aArray[i].tokens=&tArray[i];
       }

       a.naddrs=n;
       a.addrs=aArray;

       m=rfc822_threadmsgaref(mt, msgid_s, &a, subjheader, dateheader,
                            dateheader_tm, seqnum);

       free(tArray);
       free(aArray);
       return m;
}

Here is the call graph for this function:

void rfc822_threadprune ( struct imap_refmsgtable mt)

Definition at line 575 of file imaprefs.c.

{
       struct imap_refmsg *msg;

       for (msg=mt->firstmsg; msg; msg=msg->next)
       {
              struct imap_refmsg *saveparent, *m;

              if (!msg->parent)
                     continue;     /* The root, need it later. */

              if (!msg->isdummy)
                     continue;

              /*
              **
              ** If it is a dummy message with NO children, delete it.
              */

              if (msg->firstchild == 0)
              {
                     breakparent(msg);
                     /*
                     ** Don't free the node, it'll be done on msgtable
                     ** purge.
                     */
                     continue;
              }

              /*
              ** If it is a dummy message with children, delete it, but
              ** promote its children to the current level.  In other words,
              ** splice them in with the dummy's siblings.
              **
              ** Do not promote the children if doing so would make them
              ** children of the root, unless there is only one child.
              */

              if (msg->firstchild->nextsib &&
                  msg->parent->parent)
                     continue;

              saveparent=msg->parent;
              breakparent(msg);

              while ((m=msg->firstchild) != 0)
              {
                     breakparent(m);
                     linkparent(m, saveparent);
              }
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct imap_refmsg* rfc822_threadsearchmsg ( struct imap_refmsgtable mt,
const char *  msgid 
) [read]

Definition at line 140 of file imaprefs.c.

{
int n=hashmsgid(msgid);
struct imap_refmsghash *h;

       for (h= mt->hashtable[n]; h; h= h->nexthash)
       {
       int    rc=strcmp(h->msg->msgid, msgid);

              if (rc == 0)  return (h->msg);
              if (rc > 0)
                     break;
       }
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 983 of file imaprefs.c.

{
       struct imap_threadsortinfo itsi;
       int rc;

       itsi.mt=mt;
       itsi.sort_table=0;
       itsi.sort_table_cnt=0;

       rc=dothreadsort(&itsi, mt->rootptr);

       if (itsi.sort_table)
              free(itsi.sort_table);
       return (rc);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int rfc822_threadsortsubj ( struct imap_refmsg root)

Definition at line 630 of file imaprefs.c.

{
       struct imap_refmsg *toproot;

/*
** (4) Sort the messages under the root (top-level siblings only)
** by sent date.  In the case of an exact match on sent date or if
** either of the Date: headers used in a comparison can not be
** parsed, use the order in which the messages appear in the
** mailbox (that is, by sequence number) to determine the order.
** In the case of a dummy message, sort its children by sent date
** and then use the first child for the top-level sort.
*/
       size_t cnt, i;
       struct imap_refmsg **sortarray;

       for (cnt=0, toproot=root->firstchild; toproot;
            toproot=toproot->nextsib)
       {
              if (toproot->isdummy)
                     rfc822_threadsortsubj(toproot);
              ++cnt;
       }

       if ((sortarray=malloc(sizeof(struct imap_refmsg *)*(cnt+1))) == 0)
              return (-1);

       for (cnt=0; (toproot=root->firstchild) != NULL; ++cnt)
       {
              sortarray[cnt]=toproot;
              breakparent(toproot);
       }

       qsort(sortarray, cnt, sizeof(*sortarray), cmp_msgs);

       for (i=0; i<cnt; i++)
              linkparent(sortarray[i], root);
       free(sortarray);
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void swapmsgdata ( struct imap_refmsg a,
struct imap_refmsg b 
) [static]

Definition at line 19 of file imaprefs.c.

{
       char *cp;
       char c;
       time_t t;
       unsigned long ul;

#define swap(a,b,tmp) (tmp)=(a); (a)=(b); (b)=(tmp);

       swap(a->msgid, b->msgid, cp);
       swap(a->isdummy, b->isdummy, c);
       swap(a->flag2, b->flag2, c);

       swap(a->timestamp, b->timestamp, t);
       swap(a->seqnum, b->seqnum, ul);

#undef swap
}

Here is the caller graph for this function:

static struct imap_refmsg * threadmsg_common ( struct imap_refmsg m,
const char *  subjheader,
const char *  dateheader,
time_t  dateheader_tm,
unsigned long  seqnum 
) [static, read]

Definition at line 516 of file imaprefs.c.

{
       if (subjheader && (m->subj=strdup(subjheader)) == 0)
              return (0);   /* Cleanup in rfc822_threadfree() */

       if (dateheader)
              dateheader_tm=rfc822_parsedt(dateheader);

       m->timestamp=dateheader_tm;

       m->seqnum=seqnum;

       return (m);
}

Here is the call graph for this function:

Here is the caller graph for this function: