2 * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
25 #include "mutt_idna.h"
32 #define SORTCODE(x) (Sort & SORT_REVERSE) ? -(x) : x
34 /* function to use as discriminator when normal sort method is equal */
35 static sort_t *AuxSort = NULL;
37 #define AUXSORT(code,a,b) if (!code && AuxSort && !option(OPTAUXSORT)) { \
38 set_option(OPTAUXSORT); \
39 code = AuxSort(a,b); \
40 unset_option(OPTAUXSORT); \
43 code = (*((HEADER **)a))->index - (*((HEADER **)b))->index;
45 int compare_score (const void *a, const void *b)
47 HEADER **pa = (HEADER **) a;
48 HEADER **pb = (HEADER **) b;
49 int result = (*pb)->score - (*pa)->score; /* note that this is reverse */
51 AUXSORT (result, a, b);
52 return (SORTCODE (result));
55 int compare_size (const void *a, const void *b)
57 HEADER **pa = (HEADER **) a;
58 HEADER **pb = (HEADER **) b;
59 int result = (*pa)->content->length - (*pb)->content->length;
61 AUXSORT (result, a, b);
62 return (SORTCODE (result));
65 int compare_date_sent (const void *a, const void *b)
67 HEADER **pa = (HEADER **) a;
68 HEADER **pb = (HEADER **) b;
69 int result = (*pa)->date_sent - (*pb)->date_sent;
71 AUXSORT (result, a, b);
72 return (SORTCODE (result));
75 int compare_subject (const void *a, const void *b)
77 HEADER **pa = (HEADER **) a;
78 HEADER **pb = (HEADER **) b;
81 if (!(*pa)->env->real_subj) {
82 if (!(*pb)->env->real_subj)
83 rc = compare_date_sent (pa, pb);
87 else if (!(*pb)->env->real_subj)
90 rc = mutt_strcasecmp ((*pa)->env->real_subj, (*pb)->env->real_subj);
92 return (SORTCODE (rc));
95 const char *mutt_get_name (ADDRESS * a)
98 const char *name = "";
101 if (option (OPTREVALIAS) && (ali = alias_reverse_lookup (a))
103 name = ali->personal;
104 else if (a->personal)
107 name = (mutt_addr_for_display (a));
109 /* don't return NULL to avoid segfault when printing/comparing */
113 int compare_to (const void *a, const void *b)
115 HEADER **ppa = (HEADER **) a;
116 HEADER **ppb = (HEADER **) b;
121 /* mutt_get_name() will sometimes return a pointer to a static buffer.
122 * On the next call that pointer may get smashed so we copy the return value
123 * to our own memory space. */
125 strncpy (fa, mutt_get_name ((*ppa)->env->to), sizeof (fa));
126 fa[sizeof (fa) - 1] = '\0';
128 strncpy (fb, mutt_get_name ((*ppb)->env->to), sizeof (fb));
129 fb[sizeof (fb) - 1] = '\0';
131 result = mutt_strcasecmp (fa, fb);
132 AUXSORT (result, a, b);
133 return (SORTCODE (result));
136 int compare_from (const void *a, const void *b)
138 HEADER **ppa = (HEADER **) a;
139 HEADER **ppb = (HEADER **) b;
144 /* mutt_get_name() will sometimes return a pointer to a static buffer.
145 * On the next call that pointer may get smashed so we copy the return value
146 * to our own memory space. */
148 strncpy (fa, mutt_get_name ((*ppa)->env->from), sizeof (fa));
149 fa[sizeof (fa) - 1] = '\0';
151 strncpy (fb, mutt_get_name ((*ppb)->env->from), sizeof (fb));
152 fb[sizeof (fb) - 1] = '\0';
154 result = mutt_strcasecmp (fa, fb);
155 AUXSORT (result, a, b);
156 return (SORTCODE (result));
159 int compare_date_received (const void *a, const void *b)
161 HEADER **pa = (HEADER **) a;
162 HEADER **pb = (HEADER **) b;
163 int result = (*pa)->received - (*pb)->received;
165 AUXSORT (result, a, b);
166 return (SORTCODE (result));
169 int compare_order (const void *a, const void *b)
171 HEADER **ha = (HEADER **) a;
172 HEADER **hb = (HEADER **) b;
175 if ((*ha)->article_num && (*hb)->article_num) {
176 int result = (*ha)->article_num - (*hb)->article_num;
178 AUXSORT (result, a, b);
179 return (SORTCODE (result));
183 /* no need to auxsort because you will never have equality here */
184 return (SORTCODE ((*ha)->index - (*hb)->index));
187 int compare_spam (const void *a, const void *b)
189 HEADER **ppa = (HEADER **) a;
190 HEADER **ppb = (HEADER **) b;
195 /* Firstly, require spam attributes for both msgs */
196 /* to compare. Determine which msgs have one. */
197 ahas = (*ppa)->env && (*ppa)->env->spam;
198 bhas = (*ppb)->env && (*ppb)->env->spam;
200 /* If one msg has spam attr but other does not, sort the one with first. */
202 return (SORTCODE (1));
204 return (SORTCODE (-1));
206 /* Else, if neither has a spam attr, presume equality. Fall back on aux. */
207 if (!ahas && !bhas) {
208 AUXSORT (result, a, b);
209 return (SORTCODE (result));
213 /* Both have spam attrs. */
215 /* preliminary numeric examination */
216 result = (strtoul ((*ppa)->env->spam->data, &aptr, 10) -
217 strtoul ((*ppb)->env->spam->data, &bptr, 10));
219 /* If either aptr or bptr is equal to data, there is no numeric */
220 /* value for that spam attribute. In this case, compare lexically. */
221 if ((aptr == (*ppa)->env->spam->data) || (bptr == (*ppb)->env->spam->data))
222 return (SORTCODE (strcmp (aptr, bptr)));
224 /* Otherwise, we have numeric value for both attrs. If these values */
225 /* are equal, then we first fall back upon string comparison, then */
226 /* upon auxiliary sort. */
228 result = strcmp (aptr, bptr);
230 AUXSORT (result, a, b);
233 return (SORTCODE (result));
236 sort_t *mutt_get_sort_func (int method)
238 switch (method & SORT_MASK) {
240 return (compare_date_received);
242 return (compare_order);
244 return (compare_date_sent);
246 return (compare_subject);
248 return (compare_from);
250 return (compare_size);
254 return (compare_score);
256 return (compare_spam);
263 void mutt_sort_headers (CONTEXT * ctx, int init)
267 THREAD *thread, *top;
270 unset_option (OPTNEEDRESORT);
275 if (!ctx->msgcount) {
276 /* this function gets called by mutt_sync_mailbox(), which may have just
277 * deleted all the messages. the virtual message numbers are not updated
278 * in that routine, so we must make sure to zero the vcount member.
281 mutt_clear_threads (ctx);
282 return; /* nothing to do! */
286 mutt_message _("Sorting mailbox...");
288 if (option (OPTNEEDRESCORE) && option (OPTSCORE)) {
289 for (i = 0; i < ctx->msgcount; i++)
290 mutt_score_message (ctx, ctx->hdrs[i], 1);
292 unset_option (OPTNEEDRESCORE);
294 if (option (OPTRESORTINIT)) {
295 unset_option (OPTRESORTINIT);
299 if (init && ctx->tree)
300 mutt_clear_threads (ctx);
302 if ((Sort & SORT_MASK) == SORT_THREADS) {
304 /* if $sort_aux changed after the mailbox is sorted, then all the
305 subthreads need to be resorted */
306 if (option (OPTSORTSUBTHREADS)) {
310 ctx->tree = mutt_sort_subthreads (ctx->tree, 1);
312 unset_option (OPTSORTSUBTHREADS);
314 mutt_sort_threads (ctx, init);
316 else if ((sortfunc = mutt_get_sort_func (Sort)) == NULL ||
317 (AuxSort = mutt_get_sort_func (SortAux)) == NULL) {
318 mutt_error _("Could not find sorting function! [report this bug]");
324 qsort ((void *) ctx->hdrs, ctx->msgcount, sizeof (HEADER *), sortfunc);
326 /* adjust the virtual message numbers */
328 for (i = 0; i < ctx->msgcount; i++) {
329 HEADER *cur = ctx->hdrs[i];
331 if (cur->virtual != -1
332 || (cur->collapsed && (!ctx->pattern || cur->limited))) {
333 cur->virtual = ctx->vcount;
334 ctx->v2r[ctx->vcount] = i;
340 /* re-collapse threads marked as collapsed */
341 if ((Sort & SORT_MASK) == SORT_THREADS) {
343 while ((thread = top) != NULL) {
344 while (!thread->message)
345 thread = thread->child;
349 mutt_collapse_thread (ctx, h);
352 mutt_set_virtual (ctx);