static char rcsid[] = "@(#)$Id: sort.c,v 1.33 2006/04/09 07:37:19 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.33 $ $State: Exp $
*
* Modified by: Kari Hurtta <hurtta+elm@posti.FMI.FI>
* (was hurtta+elm@ozone.FMI.FI)
******************************************************************************
* The Elm Mail System
*
* Copyright (c) 1988-1992 USENET Community Trust
* Copyright (c) 1986,1987 Dave Taylor
*****************************************************************************/
/** Sort folder header table by the field specified in the global
variable "sortby"...if we're sorting by something other than
the default SENT_DATE, also put some sort of indicator on the
screen.
**/
#include "def_elm.h"
#include "s_elm.h"
DEBUG_VAR(Debug,__FILE__,"misc");
static unsigned char *s2us P_((char *str));
static unsigned char *s2us(str)
char *str;
{
return (unsigned char *)str;
}
static void find_old_current P_((struct folder_view * iindex,
struct MailboxView *mailbox));
static void find_old_current(iindex, mailbox)
struct folder_view * iindex;
struct MailboxView *mailbox;
{
/** Set current to the message that has "index" as it's
index number. This is to track the current message
when we resync... **/
int i,mc;
DPRINT(Debug,4,(&Debug,
"find-old-current(%d/%d)\n",
iindex->mailbox_number,iindex->index));
if (!mailbox)
return;
mc = get_message_count(mailbox);
for (i = 0; i < mc; i++) {
struct folder_view I;
give_index_number(mailbox,i,&I);
if (I.mailbox_number == iindex->mailbox_number &&
I.index == iindex->index) {
int current = i+1;
set_current(mailbox,current);
DPRINT(Debug,4,(&Debug, "\tset current to %d!\n", current));
return;
}
}
DPRINT(Debug,4,(&Debug,
"\tcouldn't find current index. Current left as %d\n",
get_current(mailbox)));
return; /* can't be found. Leave it alone, then */
}
/* Prototype */
static int subject_compare_1 P_((struct header_rec *h1,
struct header_rec *h2));
static int compare_headers P_((struct sort_data *p1, struct sort_data *p2));
static int compare_thread P_((struct sort_data *p1, struct sort_data *p2));
static int compare_thread(p1,p2)
struct sort_data *p1;
struct sort_data *p2;
{
int ret = 0;
struct folder_view i1;
struct folder_view i2;
give_index_number_s(p1,&i1);
give_index_number_s(p2,&i2);
/* Same thread */
if (i1.thread_number == i2.thread_number) {
struct header_rec *h1 = give_header_s(p1);
struct header_rec *h2 = give_header_s(p2);
int diff = h1->time_sent - h2->time_sent;
if ( diff < 0 ) ret = -1;
else if ( diff > 0 ) ret = 1;
else ret = 0;
} else if (-1 == i1.thread_number ||
-1 == i2.thread_number) {
/* Arbitary */
if (-1 == i1.thread_number)
ret = 1;
else if (-1 == i2.thread_number)
ret = -1;
else
panic("SORT PANIC",__FILE__,__LINE__,"compare_thread",
"Something wrong",0);
} else {
/* mailbox is not available on here ... */
CONST struct thread_info *T1 = give_thread_info_s(p1);
CONST struct thread_info *T2 = give_thread_info_s(p2);
switch (give_dt_sort_as_int(&sortby)) {
int diff;
case THREAD:
diff = T1->time_sent_first - T2 -> time_sent_first;
if ( diff < 0 ) ret = -1;
else if ( diff > 0 ) ret = 1;
else ret = 0;
return ret;
case REVERSE THREAD:
if (unstable_reverse_thread) {
/* Move thread new location when new mail arrives,
therfore use newest sent time
*/
diff = T1->time_sent_last - T2 -> time_sent_last;
if ( diff < 0 ) ret = -1;
else if ( diff > 0 ) ret = 1;
else ret = 0;
return -ret;
} else {
diff = T1->time_sent_first - T2 -> time_sent_first;
if ( diff < 0 ) ret = -1;
else if ( diff > 0 ) ret = 1;
else ret = 0;
return -ret;
}
}
}
if (give_dt_sort_as_int(&sortby) < 0)
ret = -ret;
return ret;
}
void sort_mailbox(entries, visible, mailbox)
int entries, visible;
struct MailboxView *mailbox;
{
/** Sort the header_table definitions... If 'visible', then
put the status lines etc **/
struct folder_view last_index;
int current;
last_index.mailbox_number = 0;
last_index.index =-1;
DPRINT(Debug,2,(&Debug, "\n** sorting folder by %s **\n\n",
sort_name(FULL)));
if (!mailbox)
return;
current = get_current(mailbox);
/* Don't get last_index if no entries or no current. */
/* There would be no current if we are sorting a new mail file. */
if (entries > 0 && current > 0) {
give_index_number(mailbox,current-1, &last_index);
}
if (entries > 30 && visible)
lib_transient(CATGETS(elm_msg_cat, ElmSet, ElmSortingMessagesBy,
"Sorting messages by %s..."),
sort_name(FULL));
if (entries > 1) {
switch (give_dt_sort_as_int(&sortby)) {
int i;
struct header_rec * hdr;
case THREAD:
case REVERSE THREAD:
update_mailbox_threads(mailbox);
sort_mailbox_view(mailbox,compare_thread);
break;
default:
sort_mailbox_view(mailbox,compare_headers);
break;
}
}
if (last_index.index > -1)
find_old_current(&last_index, mailbox);
clear_error();
}
static int subject_compare_1(first, second)
struct header_rec *first, *second;
{
struct string * from1, * from2;
int ret;
if (!first || !second)
return 0;
/* Make sure that both subjects exists */
if (!first->subject && second->subject)
return -1;
if (first->subject && !second->subject)
return 1;
if (!first->subject && !second->subject)
return 0;
from1 = skip_ascii_head_from_string(first->subject, s2us("Re: "),1);
from2 = skip_ascii_head_from_string(second->subject,s2us("Re: "),1);
ret = string_cmp(from1,from2,
0 /* == Values not comparable */ );
free_string(&from1);
free_string(&from2);
return ret;
}
static int compare_headers_1 P_((struct header_rec *first,
struct header_rec *second));
static int compare_headers_1(first, second)
struct header_rec *first, *second;
{
/** compare two headers according to the sortby value.
Sent Date uses a routine to compare two dates,
Received date is keyed on the file offsets (think about it)
Sender uses the truncated from line, same as "build headers",
and size and subject are trivially obvious!!
(actually, subject has been modified to ignore any leading
patterns [rR][eE]*:[ \t] so that replies to messages are
sorted with the message (though a reply will always sort to
be 'greater' than the basenote)
**/
int ret;
long diff;
if (!first || !second)
return 0;
switch (abs(give_dt_sort_as_int(&sortby))) {
case SENT_DATE:
diff = first->time_sent - second->time_sent;
if ( diff < 0 ) ret = -1;
else if ( diff > 0 ) ret = 1;
else ret = 0;
break;
case RECEIVED_DATE:
diff = first->received_time - second->received_time;
if ( diff < 0 ) ret = -1;
else if ( diff > 0 ) ret = 1;
else ret = 0;
break;
case SENDER:
ret = strcmp(first->env_from,second->env_from);
if (0 == ret) {
struct addr_item *p, *p1;
for (p = first->from, p1 = second->from;
0 == ret;
p++, p1++) {
int is_f = p && p->fullname && p->addr;
int is_f1 = p1 && p1->fullname && p1->addr;
if (!is_f && !is_f1)
break;
if (!is_f) {
ret = -1;
break;
}
if (!is_f1) {
ret = 1;
break;
}
ret = string_cmp(p->fullname,p1->fullname,
0 /* == Values not comparable */ );
if (0 == ret)
ret = strcmp(p->addr,p1->addr);
}
}
break;
case SIZE:
ret = (first->lines - second->lines);
break;
case MAILBOX_ORDER: /* NOT USED */
ret = (first->index_number_X - second->index_number_X);
break;
case SUBJECT:
ret = subject_compare_1(first,second);
break;
case STATUS:
ret = (first->status - second->status);
break;
default:
/* never get this! */
ret = 0;
break;
}
/* on equal status, use sent date as second sort param. */
if (ret == 0) {
diff = first->time_sent - second->time_sent;
if ( diff < 0 ) ret = -1;
else if ( diff > 0 ) ret = 1;
else ret = 0;
}
if (give_dt_sort_as_int(&sortby) < 0)
ret = -ret;
return ret;
}
static int compare_headers(p1,p2)
struct sort_data *p1;
struct sort_data *p2;
{
int ret = 0;
struct header_rec *h1 = give_header_s(p1);
struct header_rec *h2 = give_header_s(p2);
switch (abs(give_dt_sort_as_int(&sortby))) {
struct folder_view i1,i2;
default:
ret = compare_headers_1(h1,h2);
/* NOTE: compare_headers already reserves return for
reverse sorting orders
*/
/* Is compare result is same, then use mailbox order */
if (0 != ret)
break;
case MAILBOX_ORDER:
give_index_number_s(p1,&i1);
give_index_number_s(p2,&i2);
ret = i1.mailbox_number - i2.mailbox_number;
if (0 == ret)
ret = i1.index - i2.index;
if (give_dt_sort_as_int(&sortby) < 0)
ret = -ret;
break;
}
return ret;
}
char *sort_name(type)
int type;
{
/** return the name of the current sort option...
type can be "FULL", "SHORT" or "PAD"
**/
int pad, abr;
pad = (type == PAD);
abr = (type == SHORT);
if (give_dt_sort_as_int(&sortby) < 0) {
switch (- give_dt_sort_as_int(&sortby)) {
case SENT_DATE : return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadRevDateMailSent, "Reverse Date Mail Sent ") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrtRevDateMailSent, "Reverse-Sent") :
catgets(elm_msg_cat, ElmSet, ElmLongRevDateMailSent, "Reverse Date Mail Sent"));
case THREAD :
if (unstable_reverse_thread) { /* HACK */
return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadUnsThread, "Unstable Reverse Thread ") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrUnsThread, "(Unstable) Reverse-Thread") :
catgets(elm_msg_cat, ElmSet, ElmLongUnsThread, "Unstable Reverse Thread"));
}
return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadRevThread, "Reverse Thread ") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrRevThread, "Reverse-Thread") :
catgets(elm_msg_cat, ElmSet, ElmLongRevThread, "Reverse Thread"));
case RECEIVED_DATE: return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadRevRecv, "Reverse Date Mail Rec'vd") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrRevRecv, "Reverse-Received"):
catgets(elm_msg_cat, ElmSet, ElmLongRevRecv, "Reverse Date Mail Rec'vd"));
case MAILBOX_ORDER: return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadRevMailbox, "Reverse Mailbox Order ") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrRevMailbox, "Reverse-Mailbox"):
catgets(elm_msg_cat, ElmSet, ElmLongRevMailbox, "Reverse Mailbox Order"));
case SENDER : return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadRevSender, "Reverse Message Sender ") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrRevSender, "Reverse-From"):
catgets(elm_msg_cat, ElmSet, ElmLongRevSender, "Reverse Message Sender"));
case SIZE : return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadRevLines, "Reverse Lines in Message") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrRevLines, "Reverse-Lines") :
catgets(elm_msg_cat, ElmSet, ElmLongRevLines, "Reverse Lines in Message"));
case SUBJECT : return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadRevSubject, "Reverse Message Subject ") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrRevSubject, "Reverse-Subject") :
catgets(elm_msg_cat, ElmSet, ElmLongRevSubject, "Reverse Message Subject"));
case STATUS : return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadRevStatus, "Reverse Message Status ") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrRevStatus, "Reverse-Status"):
catgets(elm_msg_cat, ElmSet, ElmLongRevStatus, "Reverse Message Status"));
}
}
else {
switch (give_dt_sort_as_int(&sortby)) {
case SENT_DATE : return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadMailSent, "Date Mail Sent ") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrMailSent, "Sent") :
catgets(elm_msg_cat, ElmSet, ElmLongMailSent, "Date Mail Sent"));
case THREAD : return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadThread, "Thread ") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrThread, "Thread") :
catgets(elm_msg_cat, ElmSet, ElmLongThread, "Thread"));
case RECEIVED_DATE: return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadMailRecv, "Date Mail Rec'vd ") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrMailRecv, "Received") :
catgets(elm_msg_cat, ElmSet, ElmLongMailRecv, "Date Mail Rec'vd"));
case MAILBOX_ORDER: return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadMailbox, "Mailbox Order ") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrMailbox, "Mailbox") :
catgets(elm_msg_cat, ElmSet, ElmLongMailbox, "Mailbox Order"));
case SENDER : return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadSender, "Message Sender ") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrSender, "From") :
catgets(elm_msg_cat, ElmSet, ElmLongSender, "Message Sender"));
case SIZE : return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadLines, "Lines in Message ") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrLines, "Lines") :
catgets(elm_msg_cat, ElmSet, ElmLongLines, "Lines in Message"));
case SUBJECT : return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadSubject, "Message Subject ") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrSubject, "Subject") :
catgets(elm_msg_cat, ElmSet, ElmLongSubject, "Message Subject"));
case STATUS : return(
pad? catgets(elm_msg_cat, ElmSet, ElmPadStatus, "Message Status ") :
abr? catgets(elm_msg_cat, ElmSet, ElmAbrStatus, "Status") :
catgets(elm_msg_cat, ElmSet, ElmLongStatus, "Message Status"));
}
}
return(catgets(elm_msg_cat, ElmSet, ElmSortUnknown, "*UNKNOWN-SORT-PARAMETER*"));
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1