1
2 static char rcsid[] = "@(#)$Id: sort.c,v 1.3 1996/03/14 17:29:58 wfp5p Exp $";
3
4 /*******************************************************************************
5 * The Elm Mail System - $Revision: 1.3 $ $State: Exp $
6 *
7 * Copyright (c) 1988-1995 USENET Community Trust
8 * Copyright (c) 1986,1987 Dave Taylor
9 *******************************************************************************
10 * Bug reports, patches, comments, suggestions should be sent to:
11 *
12 * Bill Pemberton, Elm Coordinator
13 * flash@virginia.edu
14 *
15 *******************************************************************************
16 * $Log: sort.c,v $
17 * Revision 1.3 1996/03/14 17:29:58 wfp5p
18 * Alpha 9
19 *
20 * Revision 1.2 1995/09/29 17:42:33 wfp5p
21 * Alpha 8 (Chip's big changes)
22 *
23 * Revision 1.1.1.1 1995/04/19 20:38:39 wfp5p
24 * Initial import of elm 2.4 PL0 as base for elm 2.5.
25 *
26 ******************************************************************************/
27
28 /** Sort folder header table by the field specified in the global
29 variable "sortby"...if we're sorting by something other than
30 the default SENT_DATE, also put some sort of indicator on the
31 screen.
32
33 **/
34
35 #include "elm_defs.h"
36 #include "elm_globals.h"
37 #include "s_elm.h"
38
39 char *sort_name(), *skip_re();
40
41 void
find_old_current(iindex)42 find_old_current(iindex)
43 int iindex;
44 {
45 /** Set current to the message that has "index" as it's
46 index number. This is to track the current message
47 when we resync... **/
48
49 register int i;
50
51 dprint(4, (debugfile, "find-old-current(%d)\n", iindex));
52
53 for (i = 0; i < curr_folder.num_mssgs; i++)
54 if (curr_folder.headers[i]->index_number == iindex) {
55 dprint(4, (debugfile, "\tset current to %d!\n", i+1));
56 if (inalias)
57 curr_alias = i+1;
58 else
59 curr_folder.curr_mssg = i+1;
60 return;
61 }
62
63 return; /* can't be found. Leave it alone, then */
64 }
65
sort_mailbox(entries,visible)66 sort_mailbox(entries, visible)
67 int entries, visible;
68 {
69 /** Sort the header_table definitions... If 'visible', then
70 put the status lines etc **/
71
72 int last_index = -1;
73 int compare_headers(); /* for sorting */
74
75 dprint(2, (debugfile, "\n** sorting folder by %s **\n\n",
76 sort_name(TRUE)));
77
78 /* Don't get last_index if no entries or no current. */
79 /* There would be no current if we are sorting a new mail file. */
80 if (entries > 0 && curr_folder.curr_mssg > 0)
81 last_index = curr_folder.headers[curr_folder.curr_mssg-1]->index_number;
82
83 if (entries > 30 && visible)
84 error1(catgets(elm_msg_cat, ElmSet, ElmSortingMessagesBy,
85 "Sorting messages by %s..."), sort_name(TRUE));
86
87 if (entries > 1)
88 qsort((char *) curr_folder.headers, (unsigned) entries,
89 sizeof (struct header_rec *) , compare_headers);
90
91 if (last_index > -1)
92 find_old_current(last_index);
93
94 clear_error();
95 }
96
97 int
compare_headers(p1,p2)98 compare_headers(p1, p2)
99 struct header_rec **p1, **p2;
100 {
101 /** compare two headers according to the sortby value.
102
103 Sent Date uses a routine to compare two dates,
104 Received date is keyed on the file offsets (think about it)
105 Sender uses the truncated from line, same as "build headers",
106 and size and subject are trivially obvious!!
107 (actually, subject has been modified to ignore any leading
108 patterns [rR][eE]*:[ \t] so that replies to messages are
109 sorted with the message (though a reply will always sort to
110 be 'greater' than the basenote)
111 **/
112
113 char from1[SLEN], from2[SLEN]; /* sorting buffers... */
114 struct header_rec *first, *second;
115 int ret;
116 long diff;
117
118 first = *p1;
119 second = *p2;
120
121 switch (abs(sortby)) {
122 case SENT_DATE:
123 diff = first->time_sent - second->time_sent;
124 if ( diff < 0 ) ret = -1;
125 else if ( diff > 0 ) ret = 1;
126 else ret = 0;
127 break;
128
129 case RECEIVED_DATE:
130 diff = first->received_time - second->received_time;
131 if ( diff < 0 ) ret = -1;
132 else if ( diff > 0 ) ret = 1;
133 else ret = 0;
134 break;
135
136 case SENDER:
137 tail_of(first->from, from1, first->to);
138 tail_of(second->from, from2, second->to);
139 ret = strcmp(from1, from2);
140 break;
141
142 case SIZE:
143 ret = (first->lines - second->lines);
144 break;
145
146 case MAILBOX_ORDER:
147 ret = (first->index_number - second->index_number);
148 break;
149
150 case SUBJECT:
151 /* need some extra work 'cause of STATIC buffers */
152 strcpy(from1, skip_re(shift_lower(first->subject)));
153 ret = strcmp(from1, skip_re(shift_lower(second->subject)));
154 break;
155
156 case STATUS:
157 ret = (first->status - second->status);
158 break;
159
160 default:
161 /* never get this! */
162 ret = 0;
163 break;
164 }
165
166 /* on equal status, use sent date as second sort param. */
167 if (ret == 0) {
168 diff = first->time_sent - second->time_sent;
169 if ( diff < 0 ) ret = -1;
170 else if ( diff > 0 ) ret = 1;
171 else ret = 0;
172 }
173
174 if (sortby < 0)
175 ret = -ret;
176
177 return ret;
178 }
179
sort_name(longname)180 char *sort_name(longname)
181 int longname;
182 {
183 if (sortby < 0) {
184 switch (-sortby) {
185 case SENT_DATE: return (longname
186 ? catgets(elm_msg_cat, ElmSet, ElmLongRevDateMailSent,
187 "Reverse Date Mail Sent")
188 : catgets(elm_msg_cat, ElmSet, ElmAbrtRevDateMailSent,
189 "Reverse-Sent"));
190 case RECEIVED_DATE: return (longname
191 ? catgets(elm_msg_cat, ElmSet, ElmLongRevRecv,
192 "Reverse Date Mail Rec'vd")
193 : catgets(elm_msg_cat, ElmSet, ElmAbrRevRecv,
194 "Reverse-Received"));
195 case MAILBOX_ORDER: return (longname
196 ? catgets(elm_msg_cat, ElmSet, ElmLongRevMailbox,
197 "Reverse Mailbox Order")
198 : catgets(elm_msg_cat, ElmSet, ElmAbrRevMailbox,
199 "Reverse-Mailbox"));
200 case SENDER: return (longname
201 ? catgets(elm_msg_cat, ElmSet, ElmLongRevSender,
202 "Reverse Message Sender")
203 : catgets(elm_msg_cat, ElmSet, ElmAbrRevSender,
204 "Reverse-From"));
205 case SIZE: return (longname
206 ? catgets(elm_msg_cat, ElmSet, ElmLongRevLines,
207 "Reverse Lines in Message")
208 : catgets(elm_msg_cat, ElmSet, ElmAbrRevLines,
209 "Reverse-Lines"));
210 case SUBJECT: return (longname
211 ? catgets(elm_msg_cat, ElmSet, ElmLongRevSubject,
212 "Reverse Message Subject")
213 : catgets(elm_msg_cat, ElmSet, ElmAbrRevSubject,
214 "Reverse-Subject"));
215 case STATUS: return (longname
216 ? catgets(elm_msg_cat, ElmSet, ElmLongRevStatus,
217 "Reverse Message Status")
218 : catgets(elm_msg_cat, ElmSet, ElmAbrRevStatus,
219 "Reverse-Status"));
220 }
221 } else {
222 switch (sortby) {
223 case SENT_DATE: return (longname
224 ? catgets(elm_msg_cat, ElmSet, ElmLongMailSent,
225 "Date Mail Sent")
226 : catgets(elm_msg_cat, ElmSet, ElmAbrMailSent,
227 "Sent"));
228 case RECEIVED_DATE: return (longname
229 ? catgets(elm_msg_cat, ElmSet, ElmLongMailRecv,
230 "Date Mail Rec'vd")
231 : catgets(elm_msg_cat, ElmSet, ElmAbrMailRecv,
232 "Received"));
233 case MAILBOX_ORDER: return (longname
234 ? catgets(elm_msg_cat, ElmSet, ElmLongMailbox,
235 "Mailbox Order")
236 : catgets(elm_msg_cat, ElmSet, ElmAbrMailbox,
237 "Mailbox"));
238 case SENDER: return (longname
239 ? catgets(elm_msg_cat, ElmSet, ElmLongSender,
240 "Message Sender")
241 : catgets(elm_msg_cat, ElmSet, ElmAbrSender,
242 "From"));
243 case SIZE: return (longname
244 ? catgets(elm_msg_cat, ElmSet, ElmLongLines,
245 "Lines in Message")
246 : catgets(elm_msg_cat, ElmSet, ElmAbrLines,
247 "Lines"));
248 case SUBJECT: return (longname
249 ? catgets(elm_msg_cat, ElmSet, ElmLongSubject,
250 "Message Subject")
251 : catgets(elm_msg_cat, ElmSet, ElmAbrSubject,
252 "Subject"));
253 case STATUS: return (longname
254 ? catgets(elm_msg_cat, ElmSet, ElmLongStatus,
255 "Message Status")
256 : catgets(elm_msg_cat, ElmSet, ElmAbrStatus,
257 "Status"));
258 }
259 }
260
261 return catgets(elm_msg_cat, ElmSet, ElmSortUnknown,
262 "*UNKNOWN-SORT-PARAMETER*");
263 }
264
skip_re(string)265 char *skip_re(string)
266 char *string;
267 {
268 /** this routine returns the given string minus any sort of
269 "re:" prefix. specifically, it looks for, and will
270 remove, any of the pattern:
271
272 ( [Rr][Ee][^:]:[ ] ) *
273
274 If it doesn't find a ':' in the line it will return it
275 intact, just in case!
276 **/
277
278 static char buffer[SLEN];
279 register int i=0;
280
281 while (whitespace(string[i])) i++;
282
283 /* Initialize buffer */
284 strcpy(buffer, (char *) string);
285
286 do {
287 if (string[i] == '\0') return( (char *) buffer); /* forget it */
288
289 if (string[i] != 'r' || string[i+1] != 'e')
290 return( (char *) buffer); /* ditto */
291
292 i += 2; /* skip the "re" */
293
294 while (string[i] != ':')
295 if (string[i] == '\0')
296 return( (char *) buffer); /* no colon in string! */
297 else
298 i++;
299
300 /* now we've gotten to the colon, skip to the next non-whitespace */
301
302 i++; /* past the colon */
303
304 while (whitespace(string[i])) i++;
305
306 /* Now save the resulting subject for return purposes */
307 strcpy(buffer, (char *) string + i);
308
309 } while (string[i] == 'r' && string[i+1] == 'e');
310
311 return( (char *) buffer);
312 }
313