Back to index

courier  0.68.2
Classes | Functions
thread.c File Reference
#include "config.h"
#include "imapd.h"
#include "thread.h"
#include "searchinfo.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "imapwrite.h"
#include "imaptoken.h"
#include "imapscanclient.h"
#include "rfc822/rfc822.h"
#include "rfc822/rfc2047.h"
#include "rfc822/imaprefs.h"
#include "unicode/unicode.h"

Go to the source code of this file.

Classes

struct  os_threadinfo
struct  os_threadinfo_list
struct  os_struct
struct  sortmsginfo
struct  sortmsgs

Functions

static void thread_os_callback (struct searchinfo *, struct searchinfo *, int, unsigned long, void *)
static void thread_ref_callback (struct searchinfo *, struct searchinfo *, int, unsigned long, void *)
static void os_init (struct os_struct *os)
static void os_add (struct os_struct *os, unsigned long n, const char *s, time_t sent_date)
static void os_free (struct os_struct *os)
static int cmpsubjs (const void *a, const void *b)
static void printos (struct os_threadinfo **array, size_t cnt)
void dothreadorderedsubj (struct searchinfo *si, struct searchinfo *sihead, const char *charset, int isuid)
static void printthread (struct imap_refmsg *, int)
void dothreadreferences (struct searchinfo *si, struct searchinfo *sihead, const char *charset, int isuid)
void free_temp_sort_stack (struct temp_sort_stack *t)
static void free_sortmsgs (struct sortmsgs *p)
static void sort_callback (struct searchinfo *, struct searchinfo *, int, unsigned long, void *)
static int cmpsort (const void *a, const void *b)
void dosortmsgs (struct searchinfo *si, struct searchinfo *sihead, const char *charset, int isuid)

Class Documentation

struct os_threadinfo

Definition at line 30 of file thread.c.

Collaboration diagram for os_threadinfo:
Class Members
unsigned long n
struct os_threadinfo * next
time_t sent_date
char * subj
struct os_threadinfo_list

Definition at line 37 of file thread.c.

Collaboration diagram for os_threadinfo_list:
Class Members
struct os_threadinfo_list * next
size_t thread_start
struct os_struct

Definition at line 42 of file thread.c.

Collaboration diagram for os_struct:
Class Members
struct os_threadinfo * list
struct os_threadinfo ** msgs
unsigned nmsgs
struct sortmsginfo

Definition at line 329 of file thread.c.

Collaboration diagram for sortmsginfo:
Class Members
unsigned long n
struct sortmsginfo * next
size_t nfields
char ** sortfields
char * sortorder
struct sortmsgs

Definition at line 337 of file thread.c.

Collaboration diagram for sortmsgs:
Class Members
struct sortmsginfo ** array
struct sortmsginfo * list
size_t nfields
size_t nmsgs

Function Documentation

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

Definition at line 366 of file thread.c.

{
const struct sortmsginfo *ap=*(const struct sortmsginfo **)a;
const struct sortmsginfo *bp=*(const struct sortmsginfo **)b;
size_t i;

       for (i=0; i<ap->nfields; i++)
       {
       int    n=strcmp(ap->sortfields[i], bp->sortfields[i]);

              if (n < 0)
                     return (ap->sortorder[i] ? 1:-1);
              if (n > 0)
                     return (ap->sortorder[i] ? -1:1);
       }
       return (0);
}

Here is the caller graph for this function:

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

Definition at line 83 of file thread.c.

{
       const struct os_threadinfo *ap=*(const struct os_threadinfo **)a;
       const struct os_threadinfo *bp=*(const struct os_threadinfo **)b;
       int rc=strcmp( ap->subj, bp->subj);

       if (rc)       return (rc);

       return (ap->sent_date < bp->sent_date ? -1:
              ap->sent_date > bp->sent_date ? 1:0);
}

Here is the caller graph for this function:

void dosortmsgs ( struct searchinfo si,
struct searchinfo sihead,
const char *  charset,
int  isuid 
)

Definition at line 384 of file thread.c.

{
struct sortmsgs sm;
struct searchinfo *p;

       memset(&sm, 0, sizeof(sm));
       for (p=sihead; p; p=p->a)
              switch (p->type)     {
              case search_orderedsubj:
              case search_arrival:
              case search_cc:
              case search_date:
              case search_from:
              case search_size:
              case search_to:
                     ++sm.nfields;
                     break;
              default:
                     break;
              }
       search_internal(si, sihead, charset, isuid, sort_callback, &sm);
       if (sm.nmsgs > 0)
       {
       size_t i;
       struct sortmsginfo *o;

              /* Convert it to an array */

              sm.array= (struct sortmsginfo **)
                     malloc(sm.nmsgs * sizeof(struct sortmsginfo *));
              if (!sm.array)       write_error_exit(0);
              for (o=sm.list, i=0; o; o=o->next, i++)
                     sm.array[i]=o;

              /* Sort the array */

              qsort(sm.array, sm.nmsgs, sizeof(*sm.array), cmpsort);

              /* Print the array */

              for (i=0; i<sm.nmsgs; i++)
              {
                     writes(" ");
                     writen(sm.array[i]->n);
              }
       }
       free_sortmsgs(&sm);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dothreadorderedsubj ( struct searchinfo si,
struct searchinfo sihead,
const char *  charset,
int  isuid 
)

Definition at line 158 of file thread.c.

{
struct os_struct     os;

       os_init(&os);
       search_internal(si, sihead, charset, isuid, thread_os_callback, &os);

       if (os.nmsgs > 0)    /* Found some messages */
       {
       size_t i;
       struct os_threadinfo *o;

              /* Convert it to an array */

              os.msgs= (struct os_threadinfo **)
                     malloc(os.nmsgs * sizeof(struct os_threadinfo *));
              if (!os.msgs) write_error_exit(0);
              for (o=os.list, i=0; o; o=o->next, i++)
                     os.msgs[i]=o;

              /* Sort the array */

              qsort(os.msgs, os.nmsgs, sizeof(*os.msgs), cmpsubjs);

              /* Print the array */

              printos(os.msgs, os.nmsgs);
       }
       os_free(&os);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dothreadreferences ( struct searchinfo si,
struct searchinfo sihead,
const char *  charset,
int  isuid 
)

Definition at line 210 of file thread.c.

{
       struct imap_refmsgtable *reftable;
       struct imap_refmsg *root;

       if (!(reftable=rfc822_threadalloc()))
       {
              write_error_exit(0);
              return;
       }

       search_internal(si, sihead, charset, 0,
                     thread_ref_callback, reftable);

       root=rfc822_thread(reftable);
       printthread(root, isuid);
       rfc822_threadfree(reftable);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void free_sortmsgs ( struct sortmsgs p) [static]

Definition at line 344 of file thread.c.

{
struct sortmsginfo *q;

       if (p->array) free(p->array);
       while ((q=p->list) != 0)
       {
       size_t i;

              p->list=q->next;
              for (i=0; i<p->nfields; i++)
                     if (q->sortfields[i])
                            free(q->sortfields[i]);
              if (q->sortfields)   free(q->sortfields);
              if (q->sortorder)    free(q->sortorder);
              free(q);
       }
}

Here is the caller graph for this function:

void free_temp_sort_stack ( struct temp_sort_stack t)

Definition at line 314 of file thread.c.

{
       while (t)
       {
       struct temp_sort_stack *u=t->next;

              free(t);
              t=u;
       }
}

Here is the caller graph for this function:

static void os_add ( struct os_struct os,
unsigned long  n,
const char *  s,
time_t  sent_date 
) [static]

Definition at line 53 of file thread.c.

{
struct os_threadinfo *osi=(struct os_threadinfo *)
       malloc(sizeof(struct os_threadinfo));

       if (!osi)     write_error_exit(0);
       osi->subj=strdup(s);
                     /* This decodes the MIME encoding */
       if (!osi->subj)      write_error_exit(0);
       osi->sent_date=sent_date;
       osi->n=n;
       osi->next=os->list;
       os->list=osi;
       ++os->nmsgs;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void os_free ( struct os_struct os) [static]

Definition at line 70 of file thread.c.

{
struct os_threadinfo *p;

       while ((p=os->list) != 0)
       {
              os->list=p->next;
              free(p->subj);
              free(p);
       }
       if (os->msgs) free(os->msgs);
}

Here is the caller graph for this function:

static void os_init ( struct os_struct os) [static]

Definition at line 48 of file thread.c.

{
       memset(os, 0, sizeof(*os));
}

Here is the caller graph for this function:

static void printos ( struct os_threadinfo **  array,
size_t  cnt 
) [static]

Definition at line 97 of file thread.c.

{
       size_t i;
       struct os_threadinfo_list *thread_list=NULL, *threadptr, **tptr;

       /*
       ** thread_list - indexes to start of each thread, sort indexes by
       ** sent_date
       */

       for (i=0; i<cnt; i++)
       {
              /* Find start of next thread */

              if (i > 0 && strcmp(array[i-1]->subj, array[i]->subj) == 0)
                     continue;

              threadptr=malloc(sizeof(struct os_threadinfo_list));
              if (!threadptr)
                     write_error_exit(0);
              threadptr->thread_start=i;

              /* Insert into the list, sorted by sent date */

              for (tptr= &thread_list; *tptr; tptr=&(*tptr)->next)
                     if ( array[(*tptr)->thread_start]->sent_date
                          > array[i]->sent_date)
                            break;

              threadptr->next= *tptr;
              *tptr=threadptr;
       }

       while ( (threadptr=thread_list) != NULL)
       {
              size_t i, j;
              const char *p;

              thread_list=threadptr->next;

              i=threadptr->thread_start;
              free(threadptr);

              for (j=i+1; j<cnt; j++)
              {
                     if (strcmp(array[i]->subj, array[j]->subj))
                            break;
              }

              p="(";
              while (i < j)
              {
                     writes(p);
                     p=" ";
                     writen(array[i]->n);
                     ++i;
              }
              writes(")");
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void printthread ( struct imap_refmsg msg,
int  isuid 
) [static]

Definition at line 265 of file thread.c.

{
       const char *pfix="";

       while (msg)
       {
              if (!msg->isdummy)
              {
                     writes(pfix);
                     writen(isuid ?
                            current_maildir_info.msgs[msg->seqnum].uid:
                            msg->seqnum+1);
                     pfix=" ";
              }

              if (msg->firstchild && (msg->firstchild->nextsib
                                   || msg->firstchild->isdummy
                                   || msg->parent == NULL))
              {
                     writes(pfix);
                     for (msg=msg->firstchild; msg; msg=msg->nextsib)
                     {
                            struct imap_refmsg *msg2;

                            msg2=msg;

                            if (msg2->isdummy)
                                   msg2=msg2->firstchild;

                            for (; msg2; msg2=msg2->firstchild)
                            {
                                   if (!msg2->isdummy ||
                                       msg2->nextsib)
                                          break;
                            }

                            if (msg2)
                            {
                                   writes("(");
                                   printthread(msg, isuid);
                                   writes(")");
                            }
                     }
                     break;
              }
              msg=msg->firstchild;
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sort_callback ( struct searchinfo si,
struct searchinfo sihead,
int  isuid,
unsigned long  n,
void *  voidarg 
) [static]

Definition at line 434 of file thread.c.

{
struct sortmsgs *sm=(struct sortmsgs *)voidarg;
struct sortmsginfo *msg=(struct sortmsginfo *)
              malloc(sizeof(struct sortmsginfo));
struct searchinfo *ss;
int rev;
size_t i;

       if (msg)      memset(msg, 0, sizeof(*msg));
       if (!msg || (sm->nfields && ((msg->sortfields=(char **)
                            malloc(sizeof(char *)*sm->nfields)) == 0 ||
                                   (msg->sortorder=(char *)
                            malloc(sm->nfields)) == 0)))
              write_error_exit(0);

       if (sm->nfields)
       {
              memset(msg->sortfields, 0, sizeof(char *)*sm->nfields);
              memset(msg->sortorder, 0, sm->nfields);
       }

       rev=0;
       i=0;

/* fprintf(stderr, "--\n"); */

       for (ss=sihead; ss; ss=ss->a)
       {
       char   *p;

              if (i >= sm->nfields)
                     break; /* Something's fucked up, better handle it
                            ** gracefully, instead of dumping core.
                            */
              switch (ss->type)    {
              case search_reverse:
                     rev=1-rev;
                     continue;
              case search_orderedsubj:
              case search_arrival:
              case search_cc:
              case search_date:
              case search_from:
              case search_size:
              case search_to:
                     p=ss->as;
                     if (!p)       p="";
                     msg->sortfields[i]=my_strdup(p);
                     msg->sortorder[i]=rev;
                     /* fprintf(stderr, "%d %s\n", msg->sortorder[i], msg->sortfields[i]); */
                     ++i;
                     rev=0;
                     continue;
              default:
                     break;
              }
              break;
       }

       msg->nfields=sm->nfields;
       msg->n=isuid ? current_maildir_info.msgs[n].uid:n+1;
       msg->next=sm->list;
       sm->list=msg;
       ++sm->nmsgs;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void thread_os_callback ( struct searchinfo si,
struct searchinfo sihead,
int  isuid,
unsigned long  i,
void *  voidarg 
) [static]

Definition at line 195 of file thread.c.

{
       if (sihead->type == search_orderedsubj)
              /* SHOULD BE ALWAYS TRUE */
              os_add( (struct os_struct *)voidarg,
                     isuid ? current_maildir_info.msgs[i].uid:i+1,
                     sihead->as ? sihead->as:"",
                     sihead->bs ? rfc822_parsedt(sihead->bs):0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void thread_ref_callback ( struct searchinfo si,
struct searchinfo sihead,
int  isuid,
unsigned long  i,
void *  voidarg 
) [static]

Definition at line 231 of file thread.c.

{
       if (sihead->type == search_references1 && sihead->a &&
           sihead->a->type == search_references2 && sihead->a->a &&
           sihead->a->a->type == search_references3 && sihead->a->a->a &&
           sihead->a->a->a->type == search_references4)
       {
              const char *ref, *inreplyto, *subject, *date, *msgid;

              ref=sihead->as;
              inreplyto=sihead->bs;
              date=sihead->a->as;
              subject=sihead->a->a->as;
              msgid=sihead->a->a->a->as;

#if 0
              fprintf(stderr, "REFERENCES: ref=%s, inreplyto=%s, subject=%s, date=%s, msgid=%s\n",
                     ref ? ref:"",
                     inreplyto ? inreplyto:"",
                     subject ? subject:"",
                     date ? date:"",
                     msgid ? msgid:"");
#endif

              if (!rfc822_threadmsg( (struct imap_refmsgtable *)voidarg,
                                   msgid, ref && *ref ? ref:inreplyto,
                                   subject, date, 0, i))
                     write_error_exit(0);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function: