id_hash = hash_create (ctx->msgcount * 2); ctx->tree = safe_calloc (1, sizeof (THREAD));
if (!ctx->thread_hash) init = 1;  if (init) { mutt_clear_threads (ctx); ctx->thread_hash = hash_create (ctx->msgcount * 2); }   top.parent = top.next = top.prev = NULL; top.child = ctx->tree; for (thread = ctx->tree; thread; thread = thread->next) thread->parent = &top;
void mutt_sort_threads (CONTEXT *ctx, int init){  HEADER *cur;  int i, oldsort, using_refs = 0;  HASH *id_hash;  THREAD *thread, *new, *tmp;  LIST *ref = NULL;    /* set Sort to the secondary method to support the set sort_aux=reverse-*   * settings.  The sorting functions just look at the value of   * SORT_REVERSE   */  oldsort = Sort;  Sort = SortAux;    id_hash = hash_create (ctx->msgcount * 2);  ctx->tree = safe_calloc (1, sizeof (THREAD));  for (i = 0; i < ctx->msgcount; i++)  {    cur = ctx->hdrs[i];    thread = safe_calloc (1, sizeof (THREAD));    thread->message = cur;    cur->thread = thread;    hash_insert (id_hash, cur->env->message_id ? cur->env->message_id : "", thread, 1);  }  for (i = 0; i < ctx->msgcount; i++)  {    cur = ctx->hdrs[i];    thread = cur->thread;    using_refs = 0;    while (1)    {      if (using_refs == 0)      {	/* look at the beginning of in-reply-to: */	if ((ref = cur->env->in_reply_to) != NULL)	{	  using_refs = 1;	}	else	{	  ref = cur->env->references;	  using_refs = 2;	}      }      else if (using_refs == 1)      {	/* if there's no references header, use all the in-reply-to:	 * data that we have.  otherwise, use the first reference	 * if it's different than the first in-reply-to, otherwise use	 * the second reference (since at least eudora puts the most	 * recent reference in in-reply-to and the rest in references	 */	if (!cur->env->references)	  ref = ref->next;	else	{	  if (mutt_strcmp (ref->data, cur->env->references->data))	    ref = cur->env->references;	  else	    ref = cur->env->references->next;	  	  using_refs = 2;	}      }      else	ref = ref->next;            if (!ref)	break;      if ((new = hash_find (id_hash, ref->data)) == NULL)      {	new = safe_calloc (1, sizeof (THREAD));	hash_insert (id_hash, ref->data, new, 1);      }      else if (is_descendant (new, thread)) /* no loops! */	break;      /* make new the parent of thread */      if (thread->parent)      {	/* this can only happen if thread is attached directly to ctx->tree.	 * detach it.	 */	if (thread->prev)	  thread->prev->next = thread->next;	if (thread->next)	  thread->next->prev = thread->prev;	if (thread->parent->child == thread)	  thread->parent->child = thread->next;      }      thread->parent = new;      thread->prev = NULL;      if ((thread->next = new->child) != NULL)	thread->next->prev = thread;      new->child = thread;      thread = new;      if (thread->message || (thread->parent && thread->parent != ctx->tree))	break;    }    if (!thread->parent)    {      if ((thread->next = ctx->tree->child) != NULL)      {	thread->next->prev = thread;      }      ctx->tree->child = thread;      thread->parent = ctx->tree;    }  }  for (thread = ctx->tree->child; thread; thread = thread->next)  {    thread->parent = NULL;  }    tmp = ctx->tree;  ctx->tree = ctx->tree->child;  safe_free ((void **) &tmp);  for (i = 0; i < ctx->msgcount; i++)  {    cur = ctx->hdrs[i];    tmp = cur->thread->parent;    while (tmp && !tmp->message)    {      tmp = tmp->parent;    }    if (!tmp)      cur->subject_changed = 1;    else if (cur->env->real_subj && tmp->message->env->real_subj)      cur->subject_changed = mutt_strcmp (cur->env->real_subj, tmp->message->env->real_subj) ? 1 : 0;    else      cur->subject_changed = (cur->env->real_subj || tmp->message->env->real_subj) ? 1 : 0;  }  if (!option (OPTSTRICTTHREADS))    pseudo_threads (ctx);  ctx->tree = mutt_sort_subthreads (ctx->tree);  /* restore the oldsort order. */  Sort = oldsort;  /* Put the list into an array. */  mutt_linearize_tree (ctx, 1);  ctx->thread_hash = id_hash;}