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