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/curses.h>
18 #include "mutt_idna.h"
20 #define SORTCODE(x) (Sort & SORT_REVERSE) ? -(x) : x
22 /* function to use as discriminator when normal sort method is equal */
23 static sort_t *AuxSort = NULL;
25 #define AUXSORT(code,a,b) if (!code && AuxSort && !option(OPTAUXSORT)) { \
26 set_option(OPTAUXSORT); \
27 code = AuxSort(a,b); \
28 unset_option(OPTAUXSORT); \
31 code = (*((HEADER **)a))->index - (*((HEADER **)b))->index;
33 static int compare_score (const void *a, const void *b)
35 HEADER **pa = (HEADER **) a;
36 HEADER **pb = (HEADER **) b;
37 int result = (*pb)->score - (*pa)->score; /* note that this is reverse */
39 AUXSORT (result, a, b);
40 return (SORTCODE (result));
43 static int compare_size (const void *a, const void *b)
45 HEADER **pa = (HEADER **) a;
46 HEADER **pb = (HEADER **) b;
47 int result = (*pa)->content->length - (*pb)->content->length;
49 AUXSORT (result, a, b);
50 return (SORTCODE (result));
53 static int compare_date_sent (const void *a, const void *b)
55 HEADER **pa = (HEADER **) a;
56 HEADER **pb = (HEADER **) b;
57 int result = (*pa)->date_sent - (*pb)->date_sent;
59 AUXSORT (result, a, b);
60 return (SORTCODE (result));
63 static int compare_subject (const void *a, const void *b)
65 HEADER **pa = (HEADER **) a;
66 HEADER **pb = (HEADER **) b;
69 if (!(*pa)->env->real_subj) {
70 if (!(*pb)->env->real_subj)
71 rc = compare_date_sent (pa, pb);
75 else if (!(*pb)->env->real_subj)
78 rc = m_strcasecmp((*pa)->env->real_subj, (*pb)->env->real_subj);
80 return (SORTCODE (rc));
83 const char *mutt_get_name (address_t * a)
86 const char *name = "";
89 if (option (OPTREVALIAS) && (ali = alias_reverse_lookup(a))
95 name = (mutt_addr_for_display (a));
97 /* don't return NULL to avoid segfault when printing/comparing */
101 static int compare_to (const void *a, const void *b)
103 HEADER **ppa = (HEADER **) a;
104 HEADER **ppb = (HEADER **) b;
109 /* mutt_get_name() will sometimes return a pointer to a static buffer.
110 * On the next call that pointer may get smashed so we copy the return value
111 * to our own memory space. */
113 m_strcpy(fa, sizeof(fa), mutt_get_name((*ppa)->env->to));
114 m_strcpy(fb, sizeof(fb), mutt_get_name((*ppb)->env->to));
116 result = m_strcasecmp(fa, fb);
117 AUXSORT (result, a, b);
118 return (SORTCODE (result));
121 static int compare_from (const void *a, const void *b)
123 HEADER **ppa = (HEADER **) a;
124 HEADER **ppb = (HEADER **) b;
129 /* mutt_get_name() will sometimes return a pointer to a static buffer.
130 * On the next call that pointer may get smashed so we copy the return value
131 * to our own memory space. */
133 m_strcpy(fa, sizeof(fa), mutt_get_name((*ppa)->env->from));
134 m_strcpy(fb, sizeof(fb), mutt_get_name((*ppb)->env->from));
136 result = m_strcasecmp(fa, fb);
137 AUXSORT (result, a, b);
138 return (SORTCODE (result));
141 static int compare_date_received (const void *a, const void *b)
143 HEADER **pa = (HEADER **) a;
144 HEADER **pb = (HEADER **) b;
145 int result = (*pa)->received - (*pb)->received;
147 AUXSORT (result, a, b);
148 return (SORTCODE (result));
151 static int compare_order (const void *a, const void *b)
153 HEADER **ha = (HEADER **) a;
154 HEADER **hb = (HEADER **) b;
157 if ((*ha)->article_num && (*hb)->article_num) {
158 int result = (*ha)->article_num - (*hb)->article_num;
160 AUXSORT (result, a, b);
161 return (SORTCODE (result));
165 /* no need to auxsort because you will never have equality here */
166 return (SORTCODE ((*ha)->index - (*hb)->index));
169 static int compare_spam (const void *a, const void *b)
171 HEADER **ppa = (HEADER **) a;
172 HEADER **ppb = (HEADER **) b;
177 /* Firstly, require spam attributes for both msgs */
178 /* to compare. Determine which msgs have one. */
179 ahas = (*ppa)->env && (*ppa)->env->spam;
180 bhas = (*ppb)->env && (*ppb)->env->spam;
182 /* If one msg has spam attr but other does not, sort the one with first. */
184 return (SORTCODE (1));
186 return (SORTCODE (-1));
188 /* Else, if neither has a spam attr, presume equality. Fall back on aux. */
189 if (!ahas && !bhas) {
190 AUXSORT (result, a, b);
191 return (SORTCODE (result));
195 /* Both have spam attrs. */
197 /* preliminary numeric examination */
198 result = (strtoul ((*ppa)->env->spam->data, &aptr, 10) -
199 strtoul ((*ppb)->env->spam->data, &bptr, 10));
201 /* If either aptr or bptr is equal to data, there is no numeric */
202 /* value for that spam attribute. In this case, compare lexically. */
203 if ((aptr == (*ppa)->env->spam->data) || (bptr == (*ppb)->env->spam->data))
204 return (SORTCODE (m_strcmp(aptr, bptr)));
206 /* Otherwise, we have numeric value for both attrs. If these values */
207 /* are equal, then we first fall back upon string comparison, then */
208 /* upon auxiliary sort. */
210 result = m_strcmp(aptr, bptr);
212 AUXSORT (result, a, b);
215 return (SORTCODE (result));
218 sort_t *mutt_get_sort_func (int method)
220 switch (method & SORT_MASK) {
222 return (compare_date_received);
224 return (compare_order);
226 return (compare_date_sent);
228 return (compare_subject);
230 return (compare_from);
232 return (compare_size);
236 return (compare_score);
238 return (compare_spam);
245 void mutt_sort_headers (CONTEXT * ctx, int init)
249 THREAD *thread, *top;
252 unset_option (OPTNEEDRESORT);
257 if (!ctx->msgcount) {
258 /* this function gets called by mutt_sync_mailbox(), which may have just
259 * deleted all the messages. the virtual message numbers are not updated
260 * in that routine, so we must make sure to zero the vcount member.
263 mutt_clear_threads (ctx);
264 return; /* nothing to do! */
268 mutt_message _("Sorting mailbox...");
270 if (option (OPTNEEDRESCORE) && option (OPTSCORE)) {
271 for (i = 0; i < ctx->msgcount; i++)
272 mutt_score_message (ctx, ctx->hdrs[i], 1);
274 unset_option (OPTNEEDRESCORE);
276 if (option (OPTRESORTINIT)) {
277 unset_option (OPTRESORTINIT);
281 if (init && ctx->tree)
282 mutt_clear_threads (ctx);
284 if ((Sort & SORT_MASK) == SORT_THREADS) {
286 /* if $sort_aux changed after the mailbox is sorted, then all the
287 subthreads need to be resorted */
288 if (option (OPTSORTSUBTHREADS)) {
292 ctx->tree = mutt_sort_subthreads (ctx->tree, 1);
294 unset_option (OPTSORTSUBTHREADS);
296 mutt_sort_threads (ctx, init);
298 else if ((sortfunc = mutt_get_sort_func (Sort)) == NULL ||
299 (AuxSort = mutt_get_sort_func (SortAux)) == NULL) {
300 mutt_error _("Could not find sorting function! [report this bug]");
306 qsort ((void *) ctx->hdrs, ctx->msgcount, sizeof (HEADER *), sortfunc);
308 /* adjust the virtual message numbers */
310 for (i = 0; i < ctx->msgcount; i++) {
311 HEADER *cur = ctx->hdrs[i];
313 if (cur->virtual != -1
314 || (cur->collapsed && (!ctx->pattern || cur->limited))) {
315 cur->virtual = ctx->vcount;
316 ctx->v2r[ctx->vcount] = i;
322 /* re-collapse threads marked as collapsed */
323 if ((Sort & SORT_MASK) == SORT_THREADS) {
325 while ((thread = top) != NULL) {
326 while (!thread->message)
327 thread = thread->child;
331 mutt_collapse_thread (ctx, h);
334 mutt_set_virtual (ctx);