2 * Copyright notice from original mutt:
3 * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
5 * This file is part of mutt-ng, see http://www.muttng.org/.
6 * It's licensed under the GNU General Public License,
7 * please see the file GPL in the top level source directory.
10 #include <lib-lib/lib-lib.h>
12 #include <lib-ui/lib-ui.h>
19 #include "mutt_idna.h"
21 #define SORTCODE(x) (Sort & SORT_REVERSE) ? -(x) : x
23 /* function to use as discriminator when normal sort method is equal */
24 static sort_t *AuxSort = NULL;
26 #define AUXSORT(code,a,b) if (!code && AuxSort && !option(OPTAUXSORT)) { \
27 set_option(OPTAUXSORT); \
28 code = AuxSort(a,b); \
29 unset_option(OPTAUXSORT); \
32 code = (*((HEADER **)a))->index - (*((HEADER **)b))->index;
34 static int compare_score (const void *a, const void *b)
36 HEADER **pa = (HEADER **) a;
37 HEADER **pb = (HEADER **) b;
38 int result = (*pb)->score - (*pa)->score; /* note that this is reverse */
40 AUXSORT (result, a, b);
41 return SORTCODE (result);
44 static int compare_size (const void *a, const void *b)
46 HEADER **pa = (HEADER **) a;
47 HEADER **pb = (HEADER **) b;
48 int result = (*pa)->content->length - (*pb)->content->length;
50 AUXSORT (result, a, b);
51 return SORTCODE (result);
54 static int compare_date_sent (const void *a, const void *b)
56 HEADER **pa = (HEADER **) a;
57 HEADER **pb = (HEADER **) b;
58 int result = (*pa)->date_sent - (*pb)->date_sent;
60 AUXSORT (result, a, b);
61 return SORTCODE (result);
64 static int compare_subject (const void *a, const void *b)
66 HEADER **pa = (HEADER **) a;
67 HEADER **pb = (HEADER **) b;
70 if (!(*pa)->env->real_subj) {
71 if (!(*pb)->env->real_subj)
72 rc = compare_date_sent (pa, pb);
76 else if (!(*pb)->env->real_subj)
79 rc = m_strcasecmp((*pa)->env->real_subj, (*pb)->env->real_subj);
84 const char *mutt_get_name (address_t * a)
87 const char *name = "";
90 if (option (OPTREVALIAS) && (ali = alias_reverse_lookup(a))
96 name = (mutt_addr_for_display (a));
98 /* don't return NULL to avoid segfault when printing/comparing */
102 static int compare_to (const void *a, const void *b)
104 HEADER **ppa = (HEADER **) a;
105 HEADER **ppb = (HEADER **) b;
110 /* mutt_get_name() will sometimes return a pointer to a static buffer.
111 * On the next call that pointer may get smashed so we copy the return value
112 * to our own memory space. */
114 m_strcpy(fa, sizeof(fa), mutt_get_name((*ppa)->env->to));
115 m_strcpy(fb, sizeof(fb), mutt_get_name((*ppb)->env->to));
117 result = m_strcasecmp(fa, fb);
118 AUXSORT (result, a, b);
119 return SORTCODE (result);
122 static int compare_from (const void *a, const void *b)
124 HEADER **ppa = (HEADER **) a;
125 HEADER **ppb = (HEADER **) b;
130 /* mutt_get_name() will sometimes return a pointer to a static buffer.
131 * On the next call that pointer may get smashed so we copy the return value
132 * to our own memory space. */
134 m_strcpy(fa, sizeof(fa), mutt_get_name((*ppa)->env->from));
135 m_strcpy(fb, sizeof(fb), mutt_get_name((*ppb)->env->from));
137 result = m_strcasecmp(fa, fb);
138 AUXSORT (result, a, b);
139 return SORTCODE (result);
142 static int compare_date_received (const void *a, const void *b)
144 HEADER **pa = (HEADER **) a;
145 HEADER **pb = (HEADER **) b;
146 int result = (*pa)->received - (*pb)->received;
148 AUXSORT (result, a, b);
149 return SORTCODE (result);
152 static int compare_order (const void *a, const void *b)
154 HEADER **ha = (HEADER **) a;
155 HEADER **hb = (HEADER **) b;
156 /* no need to auxsort because you will never have equality here */
157 return SORTCODE ((*ha)->index - (*hb)->index);
160 static int compare_spam (const void *a, const void *b)
162 HEADER **ppa = (HEADER **) a;
163 HEADER **ppb = (HEADER **) b;
168 /* Firstly, require spam attributes for both msgs */
169 /* to compare. Determine which msgs have one. */
170 ahas = (*ppa)->env && (*ppa)->env->spam;
171 bhas = (*ppb)->env && (*ppb)->env->spam;
173 /* If one msg has spam attr but other does not, sort the one with first. */
177 return SORTCODE (-1);
179 /* Else, if neither has a spam attr, presume equality. Fall back on aux. */
180 if (!ahas && !bhas) {
181 AUXSORT (result, a, b);
182 return SORTCODE (result);
186 /* Both have spam attrs. */
188 /* preliminary numeric examination */
189 result = (strtoul ((*ppa)->env->spam->data, &aptr, 10) -
190 strtoul ((*ppb)->env->spam->data, &bptr, 10));
192 /* If either aptr or bptr is equal to data, there is no numeric */
193 /* value for that spam attribute. In this case, compare lexically. */
194 if ((aptr == (*ppa)->env->spam->data) || (bptr == (*ppb)->env->spam->data))
195 return SORTCODE (m_strcmp(aptr, bptr));
197 /* Otherwise, we have numeric value for both attrs. If these values */
198 /* are equal, then we first fall back upon string comparison, then */
199 /* upon auxiliary sort. */
201 result = m_strcmp(aptr, bptr);
203 AUXSORT (result, a, b);
206 return SORTCODE (result);
209 sort_t *mutt_get_sort_func (int method)
211 switch (method & SORT_MASK) {
213 return compare_date_received;
215 return compare_order;
217 return compare_date_sent;
219 return compare_subject;
227 return compare_score;
236 void mutt_sort_headers (CONTEXT * ctx, int init)
240 THREAD *thread, *top;
243 unset_option (OPTNEEDRESORT);
248 if (!ctx->msgcount) {
249 /* this function gets called by mutt_sync_mailbox(), which may have just
250 * deleted all the messages. the virtual message numbers are not updated
251 * in that routine, so we must make sure to zero the vcount member.
254 mutt_clear_threads (ctx);
255 return; /* nothing to do! */
259 mutt_message _("Sorting mailbox...");
261 if (option (OPTNEEDRESCORE) && mod_score.enable) {
262 for (i = 0; i < ctx->msgcount; i++)
263 mutt_score_message (ctx, ctx->hdrs[i], 1);
265 unset_option (OPTNEEDRESCORE);
267 if (option (OPTRESORTINIT)) {
268 unset_option (OPTRESORTINIT);
272 if (init && ctx->tree)
273 mutt_clear_threads (ctx);
275 if ((Sort & SORT_MASK) == SORT_THREADS) {
277 /* if $sort_aux changed after the mailbox is sorted, then all the
278 subthreads need to be resorted */
279 if (option (OPTSORTSUBTHREADS)) {
283 ctx->tree = mutt_sort_subthreads (ctx->tree, 1);
285 unset_option (OPTSORTSUBTHREADS);
287 mutt_sort_threads (ctx, init);
289 else if ((sortfunc = mutt_get_sort_func (Sort)) == NULL ||
290 (AuxSort = mutt_get_sort_func (SortAux)) == NULL) {
291 mutt_error _("Could not find sorting function! [report this bug]");
297 qsort ((void *) ctx->hdrs, ctx->msgcount, sizeof (HEADER *), sortfunc);
299 /* adjust the virtual message numbers */
301 for (i = 0; i < ctx->msgcount; i++) {
302 HEADER *cur = ctx->hdrs[i];
304 if (cur->virtual != -1
305 || (cur->collapsed && (!ctx->pattern || cur->limited))) {
306 cur->virtual = ctx->vcount;
307 ctx->v2r[ctx->vcount] = i;
313 /* re-collapse threads marked as collapsed */
314 if ((Sort & SORT_MASK) == SORT_THREADS) {
316 while ((thread = top) != NULL) {
317 while (!thread->message)
318 thread = thread->child;
322 mutt_collapse_thread (ctx, h);
325 mutt_set_virtual (ctx);