Back to index

courier  0.68.2
Classes | Functions
imaprefs.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  imap_refmsg
struct  imap_refmsgtable
struct  imap_refmsghash
struct  imap_subjlookup

Functions

struct imap_refmsgtablerfc822_threadalloc (void)
void rfc822_threadfree (struct imap_refmsgtable *)
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_thread (struct imap_refmsgtable *mt)
struct imap_refmsgrfc822_threadallocmsg (struct imap_refmsgtable *mt, const char *msgid)
void rfc822_threadprune (struct imap_refmsgtable *mt)
struct imap_refmsgrfc822_threadgetroot (struct imap_refmsgtable *mt)
struct imap_refmsgrfc822_threadsearchmsg (struct imap_refmsgtable *mt, const char *msgid)
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)
int rfc822_threadsortbydate (struct imap_refmsgtable *mt)

Class Documentation

struct imap_refmsg

Definition at line 25 of file imaprefs.h.

Collaboration diagram for imap_refmsg:
Class Members
struct imap_refmsg * firstchild
char flag2
char isdummy
struct imap_refmsg * last
struct imap_refmsg * lastchild
char * msgid
struct imap_refmsg * next
struct imap_refmsg * nextsib
struct imap_refmsg * parent
struct imap_refmsg * prevsib
unsigned long seqnum
char * subj
time_t timestamp
struct imap_refmsgtable

Definition at line 41 of file imaprefs.h.

Collaboration diagram for imap_refmsgtable:
Class Members
struct imap_refmsg * firstmsg
struct imap_refmsghash * hashtable
struct imap_refmsg * lastmsg
struct imap_refmsg * rootptr
struct imap_subjlookup * subjtable
struct imap_refmsghash

Definition at line 79 of file imaprefs.h.

Collaboration diagram for imap_refmsghash:
Class Members
struct imap_refmsg * msg
struct imap_refmsghash * nexthash
struct imap_subjlookup

Definition at line 84 of file imaprefs.h.

Collaboration diagram for imap_subjlookup:
Class Members
struct imap_refmsg * msg
int msgisrefwd
struct imap_subjlookup * nextsubj
char * subj

Function Documentation

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 )

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:

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: