⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 thread.c

📁 mutt-1.5.12 源代码。linux 下邮件接受的工具。
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (C) 1996-2002 Michael R. Elkins <me@mutt.org> * *     This program is free software; you can redistribute it and/or modify *     it under the terms of the GNU General Public License as published by *     the Free Software Foundation; either version 2 of the License, or *     (at your option) any later version. *  *     This program is distributed in the hope that it will be useful, *     but WITHOUT ANY WARRANTY; without even the implied warranty of *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *     GNU General Public License for more details. *  *     You should have received a copy of the GNU General Public License *     along with this program; if not, write to the Free Software *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. */ #if HAVE_CONFIG_H# include "config.h"#endif#include "mutt.h"#include "sort.h"#include <string.h>#include <ctype.h>#define VISIBLE(hdr, ctx) (hdr->virtual >= 0 || (hdr->collapsed && (!ctx->pattern || hdr->limited)))/* determine whether a is a descendant of b */static int is_descendant (THREAD *a, THREAD *b){  while (a)  {    if (a == b)      return (1);    a = a->parent;  }  return (0);}/* Determines whether to display a message's subject. */static int need_display_subject (CONTEXT *ctx, HEADER *hdr){  THREAD *tmp, *tree = hdr->thread;  /* if the user disabled subject hiding, display it */  if (!option (OPTHIDETHREADSUBJECT))    return (1);  /* if our subject is different from our parent's, display it */  if (hdr->subject_changed)    return (1);  /* if our subject is different from that of our closest previously displayed   * sibling, display the subject */  for (tmp = tree->prev; tmp; tmp = tmp->prev)  {    hdr = tmp->message;    if (hdr && VISIBLE (hdr, ctx))    {      if (hdr->subject_changed)	return (1);      else	break;    }  }    /* if there is a parent-to-child subject change anywhere between us and our   * closest displayed ancestor, display the subject */  for (tmp = tree->parent; tmp; tmp = tmp->parent)  {    hdr = tmp->message;    if (hdr)    {      if (VISIBLE (hdr, ctx))	return (0);      else if (hdr->subject_changed)	return (1);    }  }  /* if we have no visible parent or previous sibling, display the subject */  return (1);}static void linearize_tree (CONTEXT *ctx){  THREAD *tree = ctx->tree;  HEADER **array = ctx->hdrs + (Sort & SORT_REVERSE ? ctx->msgcount - 1 : 0);  while (tree)  {    while (!tree->message)      tree = tree->child;    *array = tree->message;    array += Sort & SORT_REVERSE ? -1 : 1;    if (tree->child)      tree = tree->child;    else    {      while (tree)      {	if (tree->next)	{	  tree = tree->next;	  break;	}	else	  tree = tree->parent;      }    }  }}/* this calculates whether a node is the root of a subtree that has visible * nodes, whether a node itself is visible, whether, if invisible, it has * depth anyway, and whether any of its later siblings are roots of visible * subtrees.  while it's at it, it frees the old thread display, so we can * skip parts of the tree in mutt_draw_tree() if we've decided here that we * don't care about them any more. */static void calculate_visibility (CONTEXT *ctx, int *max_depth){  THREAD *tmp, *tree = ctx->tree;  int hide_top_missing = option (OPTHIDETOPMISSING) && !option (OPTHIDEMISSING);  int hide_top_limited = option (OPTHIDETOPLIMITED) && !option (OPTHIDELIMITED);  int depth = 0;  /* we walk each level backwards to make it easier to compute next_subtree_visible */  while (tree->next)    tree = tree->next;  *max_depth = 0;  FOREVER  {    if (depth > *max_depth)      *max_depth = depth;    tree->subtree_visible = 0;    if (tree->message)    {      FREE (&tree->message->tree);      if (VISIBLE (tree->message, ctx))      {	tree->deep = 1;	tree->visible = 1;	tree->message->display_subject = need_display_subject (ctx, tree->message);	for (tmp = tree; tmp; tmp = tmp->parent)	{	  if (tmp->subtree_visible)	  {	    tmp->deep = 1;	    tmp->subtree_visible = 2;	    break;	  }	  else	    tmp->subtree_visible = 1;	}      }      else      {	tree->visible = 0;	tree->deep = !option (OPTHIDELIMITED);      }    }    else    {      tree->visible = 0;      tree->deep = !option (OPTHIDEMISSING);    }    tree->next_subtree_visible = tree->next && (tree->next->next_subtree_visible						|| tree->next->subtree_visible);    if (tree->child)    {      depth++;      tree = tree->child;      while (tree->next)	tree = tree->next;    }    else if (tree->prev)      tree = tree->prev;    else    {      while (tree && !tree->prev)      {	depth--;	tree = tree->parent;      }      if (!tree)	break;      else	tree = tree->prev;    }  }    /* now fix up for the OPTHIDETOP* options if necessary */  if (hide_top_limited || hide_top_missing)  {    tree = ctx->tree;    FOREVER    {      if (!tree->visible && tree->deep && tree->subtree_visible < 2 	  && ((tree->message && hide_top_limited) || (!tree->message && hide_top_missing)))	tree->deep = 0;      if (!tree->deep && tree->child && tree->subtree_visible)	tree = tree->child;      else if (tree->next)	tree = tree->next;      else      {	while (tree && !tree->next)	  tree = tree->parent;	if (!tree)	  break;	else	  tree = tree->next;      }    }  }}/* Since the graphics characters have a value >255, I have to resort to * using escape sequences to pass the information to print_enriched_string(). * These are the macros M_TREE_* defined in mutt.h. * * ncurses should automatically use the default ASCII characters instead of * graphics chars on terminals which don't support them (see the man page * for curs_addch). */void mutt_draw_tree (CONTEXT *ctx){  char *pfx = NULL, *mypfx = NULL, *arrow = NULL, *myarrow = NULL, *new_tree;  char corner = (Sort & SORT_REVERSE) ? M_TREE_ULCORNER : M_TREE_LLCORNER;  char vtee = (Sort & SORT_REVERSE) ? M_TREE_BTEE : M_TREE_TTEE;  int depth = 0, start_depth = 0, max_depth = 0, width = option (OPTNARROWTREE) ? 1 : 2;  THREAD *nextdisp = NULL, *pseudo = NULL, *parent = NULL, *tree = ctx->tree;  /* Do the visibility calculations and free the old thread chars.   * From now on we can simply ignore invisible subtrees   */  calculate_visibility (ctx, &max_depth);  pfx = safe_malloc (width * max_depth + 2);  arrow = safe_malloc (width * max_depth + 2);  while (tree)  {    if (depth)    {      myarrow = arrow + (depth - start_depth - (start_depth ? 0 : 1)) * width;      if (depth && start_depth == depth)	myarrow[0] = nextdisp ? M_TREE_LTEE : corner;      else if (parent->message && !option (OPTHIDELIMITED))	myarrow[0] = M_TREE_HIDDEN;      else if (!parent->message && !option (OPTHIDEMISSING))	myarrow[0] = M_TREE_MISSING;      else	myarrow[0] = vtee;      if (width == 2)	myarrow[1] = pseudo ?  M_TREE_STAR	                     : (tree->duplicate_thread ? M_TREE_EQUALS : M_TREE_HLINE);      if (tree->visible)      {	myarrow[width] = M_TREE_RARROW;	myarrow[width + 1] = 0;	new_tree = safe_malloc ((2 + depth * width));	if (start_depth > 1)	{	  strncpy (new_tree, pfx, (start_depth - 1) * width);	  strfcpy (new_tree + (start_depth - 1) * width,		   arrow, (1 + depth - start_depth) * width + 2);	}	else	  strfcpy (new_tree, arrow, 2 + depth * width);	tree->message->tree = new_tree;      }    }    if (tree->child && depth)    {      mypfx = pfx + (depth - 1) * width;      mypfx[0] = nextdisp ? M_TREE_VLINE : M_TREE_SPACE;      if (width == 2)	mypfx[1] = M_TREE_SPACE;    }    parent = tree;    nextdisp = NULL;    pseudo = NULL;    do    {      if (tree->child && tree->subtree_visible)      {	if (tree->deep)	  depth++;	if (tree->visible)	  start_depth = depth;	tree = tree->child;	/* we do this here because we need to make sure that the first child thread	 * of the old tree that we deal with is actually displayed if any are,	 * or we might set the parent variable wrong while going through it. */	while (!tree->subtree_visible && tree->next)	  tree = tree->next;      }      else      {	while (!tree->next && tree->parent)	{	  if (tree == pseudo)	    pseudo = NULL;	  if (tree == nextdisp)	    nextdisp = NULL;	  if (tree->visible)	    start_depth = depth;	  tree = tree->parent;	  if (tree->deep)	  {	    if (start_depth == depth)	      start_depth--;	    depth--;	  }	}	if (tree == pseudo)	  pseudo = NULL;	if (tree == nextdisp)	  nextdisp = NULL;	if (tree->visible)	  start_depth = depth;	tree = tree->next;	if (!tree)	  break;      }      if (!pseudo && tree->fake_thread)	pseudo = tree;      if (!nextdisp && tree->next_subtree_visible)	nextdisp = tree;    }    while (!tree->deep);  }  FREE (&pfx);  FREE (&arrow);}/* since we may be trying to attach as a pseudo-thread a THREAD that * has no message, we have to make a list of all the subjects of its * most immediate existing descendants.  we also note the earliest * date on any of the parents and put it in *dateptr. */static LIST *make_subject_list (THREAD *cur, time_t *dateptr){  THREAD *start = cur;  ENVELOPE *env;  time_t thisdate;  LIST *curlist, *oldlist, *newlist, *subjects = NULL;  int rc = 0;    FOREVER  {    while (!cur->message)      cur = cur->child;    if (dateptr)    {      thisdate = option (OPTTHREADRECEIVED)	? cur->message->received : cur->message->date_sent;      if (!*dateptr || thisdate < *dateptr)	*dateptr = thisdate;    }    env = cur->message->env;    if (env->real_subj &&	((env->real_subj != env->subject) || (!option (OPTSORTRE))))    {      for (curlist = subjects, oldlist = NULL;	   curlist; oldlist = curlist, curlist = curlist->next)      {	rc = mutt_strcmp (env->real_subj, curlist->data);	if (rc >= 0)	  break;      }      if (!curlist || rc > 0)      {	newlist = safe_calloc (1, sizeof (LIST));	newlist->data = env->real_subj;	if (oldlist)	{	  newlist->next = oldlist->next;	  oldlist->next = newlist;	}	else	{	  newlist->next = subjects;	  subjects = newlist;	}      }    }    while (!cur->next && cur != start)    {      cur = cur->parent;    }    if (cur == start)      break;    cur = cur->next;  }  return (subjects);}/* find the best possible match for a parent mesage based upon subject. * if there are multiple matches, the one which was sent the latest, but * before the current message, is used.  */static THREAD *find_subject (CONTEXT *ctx, THREAD *cur){  struct hash_elem *ptr;  THREAD *tmp, *last = NULL;  int hash;  LIST *subjects = NULL, *oldlist;  time_t date = 0;    subjects = make_subject_list (cur, &date);  while (subjects)  {    hash = hash_string ((unsigned char *) subjects->data,			ctx->subj_hash->nelem);    for (ptr = ctx->subj_hash->table[hash]; ptr; ptr = ptr->next)    {      tmp = ((HEADER *) ptr->data)->thread;      if (tmp != cur &&			   /* don't match the same message */	  !tmp->fake_thread &&		   /* don't match pseudo threads */	  tmp->message->subject_changed && /* only match interesting replies */	  !is_descendant (tmp, cur) &&	   /* don't match in the same thread */	  (date >= (option (OPTTHREADRECEIVED) ?		    tmp->message->received :		    tmp->message->date_sent)) &&	  (!last ||	   (option (OPTTHREADRECEIVED) ?	    (last->message->received < tmp->message->received) :	    (last->message->date_sent < tmp->message->date_sent))) &&	  tmp->message->env->real_subj &&	  mutt_strcmp (subjects->data, tmp->message->env->real_subj) == 0)	last = tmp; /* best match so far */    }    oldlist = subjects;    subjects = subjects->next;    FREE (&oldlist);  }  return (last);}/* remove cur and its descendants from their current location. * also make sure ancestors of cur no longer are sorted by the * fact that cur is their descendant. */static void unlink_message (THREAD **old, THREAD *cur){  THREAD *tmp;  if (cur->prev)    cur->prev->next = cur->next;  else    *old = cur->next;  if (cur->next)    cur->next->prev = cur->prev;  if (cur->sort_key)  {    for (tmp = cur->parent; tmp && tmp->sort_key == cur->sort_key;	 tmp = tmp->parent)      tmp->sort_key = NULL;  }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -