mutt stable branch with some hacks
at master 342 lines 8.9 kB view raw
1/* 2 * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org> 3 * 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. 8 * 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. 13 * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 */ 18 19#if HAVE_CONFIG_H 20# include "config.h" 21#endif 22 23#include "mutt.h" 24#include "sort.h" 25#include "mutt_idna.h" 26 27#include <stdlib.h> 28#include <string.h> 29#include <ctype.h> 30#include <unistd.h> 31 32#define SORTCODE(x) (Sort & SORT_REVERSE) ? -(x) : x 33 34/* function to use as discriminator when normal sort method is equal */ 35static sort_t *AuxSort = NULL; 36 37#define AUXSORT(code,a,b) if (!code && AuxSort && !option(OPTAUXSORT)) { \ 38 set_option(OPTAUXSORT); \ 39 code = AuxSort(a,b); \ 40 unset_option(OPTAUXSORT); \ 41} \ 42if (!code) \ 43 code = (*((HEADER **)a))->index - (*((HEADER **)b))->index; 44 45static int compare_score (const void *a, const void *b) 46{ 47 HEADER **pa = (HEADER **) a; 48 HEADER **pb = (HEADER **) b; 49 int result = (*pb)->score - (*pa)->score; /* note that this is reverse */ 50 AUXSORT(result,a,b); 51 return (SORTCODE (result)); 52} 53 54static int compare_size (const void *a, const void *b) 55{ 56 HEADER **pa = (HEADER **) a; 57 HEADER **pb = (HEADER **) b; 58 int result = (*pa)->content->length - (*pb)->content->length; 59 AUXSORT(result,a,b); 60 return (SORTCODE (result)); 61} 62 63static int compare_date_sent (const void *a, const void *b) 64{ 65 HEADER **pa = (HEADER **) a; 66 HEADER **pb = (HEADER **) b; 67 int result = (*pa)->date_sent - (*pb)->date_sent; 68 AUXSORT(result,a,b); 69 return (SORTCODE (result)); 70} 71 72static int compare_subject (const void *a, const void *b) 73{ 74 HEADER **pa = (HEADER **) a; 75 HEADER **pb = (HEADER **) b; 76 int rc; 77 78 if (!(*pa)->env->real_subj) 79 { 80 if (!(*pb)->env->real_subj) 81 rc = compare_date_sent (pa, pb); 82 else 83 rc = -1; 84 } 85 else if (!(*pb)->env->real_subj) 86 rc = 1; 87 else 88 rc = mutt_strcasecmp ((*pa)->env->real_subj, (*pb)->env->real_subj); 89 AUXSORT(rc,a,b); 90 return (SORTCODE (rc)); 91} 92 93const char *mutt_get_name (ADDRESS *a) 94{ 95 ADDRESS *ali; 96 97 if (a) 98 { 99 if (option (OPTREVALIAS) && (ali = alias_reverse_lookup (a)) && ali->personal) 100 return ali->personal; 101 else if (a->personal) 102 return a->personal; 103 else if (a->mailbox) 104 return (mutt_addr_for_display (a)); 105 } 106 /* don't return NULL to avoid segfault when printing/comparing */ 107 return (""); 108} 109 110static int compare_to (const void *a, const void *b) 111{ 112 HEADER **ppa = (HEADER **) a; 113 HEADER **ppb = (HEADER **) b; 114 char fa[SHORT_STRING]; 115 const char *fb; 116 int result; 117 118 strfcpy (fa, mutt_get_name ((*ppa)->env->to), SHORT_STRING); 119 fb = mutt_get_name ((*ppb)->env->to); 120 result = mutt_strncasecmp (fa, fb, SHORT_STRING); 121 AUXSORT(result,a,b); 122 return (SORTCODE (result)); 123} 124 125static int compare_from (const void *a, const void *b) 126{ 127 HEADER **ppa = (HEADER **) a; 128 HEADER **ppb = (HEADER **) b; 129 char fa[SHORT_STRING]; 130 const char *fb; 131 int result; 132 133 strfcpy (fa, mutt_get_name ((*ppa)->env->from), SHORT_STRING); 134 fb = mutt_get_name ((*ppb)->env->from); 135 result = mutt_strncasecmp (fa, fb, SHORT_STRING); 136 AUXSORT(result,a,b); 137 return (SORTCODE (result)); 138} 139 140static int compare_date_received (const void *a, const void *b) 141{ 142 HEADER **pa = (HEADER **) a; 143 HEADER **pb = (HEADER **) b; 144 int result = (*pa)->received - (*pb)->received; 145 AUXSORT(result,a,b); 146 return (SORTCODE (result)); 147} 148 149static int compare_order (const void *a, const void *b) 150{ 151 HEADER **ha = (HEADER **) a; 152 HEADER **hb = (HEADER **) b; 153 154 /* no need to auxsort because you will never have equality here */ 155 return (SORTCODE ((*ha)->index - (*hb)->index)); 156} 157 158static int compare_spam (const void *a, const void *b) 159{ 160 HEADER **ppa = (HEADER **) a; 161 HEADER **ppb = (HEADER **) b; 162 char *aptr, *bptr; 163 int ahas, bhas; 164 int result = 0; 165 double difference; 166 167 /* Firstly, require spam attributes for both msgs */ 168 /* to compare. Determine which msgs have one. */ 169 ahas = (*ppa)->env && (*ppa)->env->spam; 170 bhas = (*ppb)->env && (*ppb)->env->spam; 171 172 /* If one msg has spam attr but other does not, sort the one with first. */ 173 if (ahas && !bhas) 174 return (SORTCODE(1)); 175 if (!ahas && bhas) 176 return (SORTCODE(-1)); 177 178 /* Else, if neither has a spam attr, presume equality. Fall back on aux. */ 179 if (!ahas && !bhas) 180 { 181 AUXSORT(result, a, b); 182 return (SORTCODE(result)); 183 } 184 185 186 /* Both have spam attrs. */ 187 188 /* preliminary numeric examination */ 189 difference = (strtod((*ppa)->env->spam->data, &aptr) - 190 strtod((*ppb)->env->spam->data, &bptr)); 191 192 /* map double into comparison (-1, 0, or 1) */ 193 result = (difference < 0.0 ? -1 : difference > 0.0 ? 1 : 0); 194 195 /* If either aptr or bptr is equal to data, there is no numeric */ 196 /* value for that spam attribute. In this case, compare lexically. */ 197 if ((aptr == (*ppa)->env->spam->data) || (bptr == (*ppb)->env->spam->data)) 198 return (SORTCODE(strcmp(aptr, bptr))); 199 200 /* Otherwise, we have numeric value for both attrs. If these values */ 201 /* are equal, then we first fall back upon string comparison, then */ 202 /* upon auxiliary sort. */ 203 if (result == 0) 204 { 205 result = strcmp(aptr, bptr); 206 if (result == 0) 207 AUXSORT(result, a, b); 208 } 209 210 return (SORTCODE(result)); 211} 212 213sort_t *mutt_get_sort_func (int method) 214{ 215 switch (method & SORT_MASK) 216 { 217 case SORT_RECEIVED: 218 return (compare_date_received); 219 case SORT_ORDER: 220 return (compare_order); 221 case SORT_DATE: 222 return (compare_date_sent); 223 case SORT_SUBJECT: 224 return (compare_subject); 225 case SORT_FROM: 226 return (compare_from); 227 case SORT_SIZE: 228 return (compare_size); 229 case SORT_TO: 230 return (compare_to); 231 case SORT_SCORE: 232 return (compare_score); 233 case SORT_SPAM: 234 return (compare_spam); 235 default: 236 return (NULL); 237 } 238 /* not reached */ 239} 240 241void mutt_sort_headers (CONTEXT *ctx, int init) 242{ 243 int i; 244 HEADER *h; 245 THREAD *thread, *top; 246 sort_t *sortfunc; 247 248 unset_option (OPTNEEDRESORT); 249 250 if (!ctx) 251 return; 252 253 if (!ctx->msgcount) 254 { 255 /* this function gets called by mutt_sync_mailbox(), which may have just 256 * deleted all the messages. the virtual message numbers are not updated 257 * in that routine, so we must make sure to zero the vcount member. 258 */ 259 ctx->vcount = 0; 260 mutt_clear_threads (ctx); 261 return; /* nothing to do! */ 262 } 263 264 if (!ctx->quiet) 265 mutt_message _("Sorting mailbox..."); 266 267 if (option (OPTNEEDRESCORE) && option (OPTSCORE)) 268 { 269 for (i = 0; i < ctx->msgcount; i++) 270 mutt_score_message (ctx, ctx->hdrs[i], 1); 271 } 272 unset_option (OPTNEEDRESCORE); 273 274 if (option (OPTRESORTINIT)) 275 { 276 unset_option (OPTRESORTINIT); 277 init = 1; 278 } 279 280 if (init && ctx->tree) 281 mutt_clear_threads (ctx); 282 283 if ((Sort & SORT_MASK) == SORT_THREADS) 284 { 285 AuxSort = NULL; 286 /* if $sort_aux changed after the mailbox is sorted, then all the 287 subthreads need to be resorted */ 288 if (option (OPTSORTSUBTHREADS)) 289 { 290 i = Sort; 291 Sort = SortAux; 292 if (ctx->tree) 293 ctx->tree = mutt_sort_subthreads (ctx->tree, 1); 294 Sort = i; 295 unset_option (OPTSORTSUBTHREADS); 296 } 297 mutt_sort_threads (ctx, init); 298 } 299 else if ((sortfunc = mutt_get_sort_func (Sort)) == NULL || 300 (AuxSort = mutt_get_sort_func (SortAux)) == NULL) 301 { 302 mutt_error _("Could not find sorting function! [report this bug]"); 303 mutt_sleep (1); 304 return; 305 } 306 else 307 qsort ((void *) ctx->hdrs, ctx->msgcount, sizeof (HEADER *), sortfunc); 308 309 /* adjust the virtual message numbers */ 310 ctx->vcount = 0; 311 for (i = 0; i < ctx->msgcount; i++) 312 { 313 HEADER *cur = ctx->hdrs[i]; 314 if (cur->virtual != -1 || (cur->collapsed && (!ctx->pattern || cur->limited))) 315 { 316 cur->virtual = ctx->vcount; 317 ctx->v2r[ctx->vcount] = i; 318 ctx->vcount++; 319 } 320 cur->msgno = i; 321 } 322 323 /* re-collapse threads marked as collapsed */ 324 if ((Sort & SORT_MASK) == SORT_THREADS) 325 { 326 top = ctx->tree; 327 while ((thread = top) != NULL) 328 { 329 while (!thread->message) 330 thread = thread->child; 331 h = thread->message; 332 333 if (h->collapsed) 334 mutt_collapse_thread (ctx, h); 335 top = top->next; 336 } 337 mutt_set_virtual (ctx); 338 } 339 340 if (!ctx->quiet) 341 mutt_clear_error (); 342}