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.
16 #include "mutt_idna.h"
23 #define SORTCODE(x) (Sort & SORT_REVERSE) ? -(x) : x
25 /* function to use as discriminator when normal sort method is equal */
26 static sort_t *AuxSort = NULL;
28 #define AUXSORT(code,a,b) if (!code && AuxSort && !option(OPTAUXSORT)) { \
29 set_option(OPTAUXSORT); \
30 code = AuxSort(a,b); \
31 unset_option(OPTAUXSORT); \
34 code = (*((HEADER **)a))->index - (*((HEADER **)b))->index;
36 int compare_score (const void *a, const void *b)
38 HEADER **pa = (HEADER **) a;
39 HEADER **pb = (HEADER **) b;
40 int result = (*pb)->score - (*pa)->score; /* note that this is reverse */
42 AUXSORT (result, a, b);
43 return (SORTCODE (result));
46 int compare_size (const void *a, const void *b)
48 HEADER **pa = (HEADER **) a;
49 HEADER **pb = (HEADER **) b;
50 int result = (*pa)->content->length - (*pb)->content->length;
52 AUXSORT (result, a, b);
53 return (SORTCODE (result));
56 int compare_date_sent (const void *a, const void *b)
58 HEADER **pa = (HEADER **) a;
59 HEADER **pb = (HEADER **) b;
60 int result = (*pa)->date_sent - (*pb)->date_sent;
62 AUXSORT (result, a, b);
63 return (SORTCODE (result));
66 int compare_subject (const void *a, const void *b)
68 HEADER **pa = (HEADER **) a;
69 HEADER **pb = (HEADER **) b;
72 if (!(*pa)->env->real_subj) {
73 if (!(*pb)->env->real_subj)
74 rc = compare_date_sent (pa, pb);
78 else if (!(*pb)->env->real_subj)
81 rc = mutt_strcasecmp ((*pa)->env->real_subj, (*pb)->env->real_subj);
83 return (SORTCODE (rc));
86 const char *mutt_get_name (ADDRESS * a)
89 const char *name = "";
92 if (option (OPTREVALIAS) && (ali = alias_reverse_lookup (a))
98 name = (mutt_addr_for_display (a));
100 /* don't return NULL to avoid segfault when printing/comparing */
104 int compare_to (const void *a, const void *b)
106 HEADER **ppa = (HEADER **) a;
107 HEADER **ppb = (HEADER **) b;
112 /* mutt_get_name() will sometimes return a pointer to a static buffer.
113 * On the next call that pointer may get smashed so we copy the return value
114 * to our own memory space. */
116 strncpy (fa, mutt_get_name ((*ppa)->env->to), sizeof (fa));
117 fa[sizeof (fa) - 1] = '\0';
119 strncpy (fb, mutt_get_name ((*ppb)->env->to), sizeof (fb));
120 fb[sizeof (fb) - 1] = '\0';
122 result = mutt_strcasecmp (fa, fb);
123 AUXSORT (result, a, b);
124 return (SORTCODE (result));
127 int compare_from (const void *a, const void *b)
129 HEADER **ppa = (HEADER **) a;
130 HEADER **ppb = (HEADER **) b;
135 /* mutt_get_name() will sometimes return a pointer to a static buffer.
136 * On the next call that pointer may get smashed so we copy the return value
137 * to our own memory space. */
139 strncpy (fa, mutt_get_name ((*ppa)->env->from), sizeof (fa));
140 fa[sizeof (fa) - 1] = '\0';
142 strncpy (fb, mutt_get_name ((*ppb)->env->from), sizeof (fb));
143 fb[sizeof (fb) - 1] = '\0';
145 result = mutt_strcasecmp (fa, fb);
146 AUXSORT (result, a, b);
147 return (SORTCODE (result));
150 int compare_date_received (const void *a, const void *b)
152 HEADER **pa = (HEADER **) a;
153 HEADER **pb = (HEADER **) b;
154 int result = (*pa)->received - (*pb)->received;
156 AUXSORT (result, a, b);
157 return (SORTCODE (result));
160 int compare_order (const void *a, const void *b)
162 HEADER **ha = (HEADER **) a;
163 HEADER **hb = (HEADER **) b;
166 if ((*ha)->article_num && (*hb)->article_num) {
167 int result = (*ha)->article_num - (*hb)->article_num;
169 AUXSORT (result, a, b);
170 return (SORTCODE (result));
174 /* no need to auxsort because you will never have equality here */
175 return (SORTCODE ((*ha)->index - (*hb)->index));
178 int compare_spam (const void *a, const void *b)
180 HEADER **ppa = (HEADER **) a;
181 HEADER **ppb = (HEADER **) b;
186 /* Firstly, require spam attributes for both msgs */
187 /* to compare. Determine which msgs have one. */
188 ahas = (*ppa)->env && (*ppa)->env->spam;
189 bhas = (*ppb)->env && (*ppb)->env->spam;
191 /* If one msg has spam attr but other does not, sort the one with first. */
193 return (SORTCODE (1));
195 return (SORTCODE (-1));
197 /* Else, if neither has a spam attr, presume equality. Fall back on aux. */
198 if (!ahas && !bhas) {
199 AUXSORT (result, a, b);
200 return (SORTCODE (result));
204 /* Both have spam attrs. */
206 /* preliminary numeric examination */
207 result = (strtoul ((*ppa)->env->spam->data, &aptr, 10) -
208 strtoul ((*ppb)->env->spam->data, &bptr, 10));
210 /* If either aptr or bptr is equal to data, there is no numeric */
211 /* value for that spam attribute. In this case, compare lexically. */
212 if ((aptr == (*ppa)->env->spam->data) || (bptr == (*ppb)->env->spam->data))
213 return (SORTCODE (strcmp (aptr, bptr)));
215 /* Otherwise, we have numeric value for both attrs. If these values */
216 /* are equal, then we first fall back upon string comparison, then */
217 /* upon auxiliary sort. */
219 result = strcmp (aptr, bptr);
221 AUXSORT (result, a, b);
224 return (SORTCODE (result));
227 sort_t *mutt_get_sort_func (int method)
229 switch (method & SORT_MASK) {
231 return (compare_date_received);
233 return (compare_order);
235 return (compare_date_sent);
237 return (compare_subject);
239 return (compare_from);
241 return (compare_size);
245 return (compare_score);
247 return (compare_spam);
254 void mutt_sort_headers (CONTEXT * ctx, int init)
258 THREAD *thread, *top;
261 unset_option (OPTNEEDRESORT);
266 if (!ctx->msgcount) {
267 /* this function gets called by mutt_sync_mailbox(), which may have just
268 * deleted all the messages. the virtual message numbers are not updated
269 * in that routine, so we must make sure to zero the vcount member.
272 mutt_clear_threads (ctx);
273 return; /* nothing to do! */
277 mutt_message _("Sorting mailbox...");
279 if (option (OPTNEEDRESCORE) && option (OPTSCORE)) {
280 for (i = 0; i < ctx->msgcount; i++)
281 mutt_score_message (ctx, ctx->hdrs[i], 1);
283 unset_option (OPTNEEDRESCORE);
285 if (option (OPTRESORTINIT)) {
286 unset_option (OPTRESORTINIT);
290 if (init && ctx->tree)
291 mutt_clear_threads (ctx);
293 if ((Sort & SORT_MASK) == SORT_THREADS) {
295 /* if $sort_aux changed after the mailbox is sorted, then all the
296 subthreads need to be resorted */
297 if (option (OPTSORTSUBTHREADS)) {
301 ctx->tree = mutt_sort_subthreads (ctx->tree, 1);
303 unset_option (OPTSORTSUBTHREADS);
305 mutt_sort_threads (ctx, init);
307 else if ((sortfunc = mutt_get_sort_func (Sort)) == NULL ||
308 (AuxSort = mutt_get_sort_func (SortAux)) == NULL) {
309 mutt_error _("Could not find sorting function! [report this bug]");
315 qsort ((void *) ctx->hdrs, ctx->msgcount, sizeof (HEADER *), sortfunc);
317 /* adjust the virtual message numbers */
319 for (i = 0; i < ctx->msgcount; i++) {
320 HEADER *cur = ctx->hdrs[i];
322 if (cur->virtual != -1
323 || (cur->collapsed && (!ctx->pattern || cur->limited))) {
324 cur->virtual = ctx->vcount;
325 ctx->v2r[ctx->vcount] = i;
331 /* re-collapse threads marked as collapsed */
332 if ((Sort & SORT_MASK) == SORT_THREADS) {
334 while ((thread = top) != NULL) {
335 while (!thread->message)
336 thread = thread->child;
340 mutt_collapse_thread (ctx, h);
343 mutt_set_virtual (ctx);