2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
26 * $TOG: Sort.C /main/10 1998/10/22 11:25:16 mgreess $
28 * RESTRICTED CONFIDENTIAL INFORMATION:
30 * The information in this document is subject to special
31 * restrictions in a confidential disclosure agreement between
32 * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
33 * document outside HP, IBM, Sun, USL, SCO, or Univel without
34 * Sun's specific written approval. This document and all copies
35 * and derivative works thereof must be returned or destroyed at
38 * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
45 #include <EUSCompat.h>
46 #include <DtMail/IO.hh>
48 #include "str_utils.h"
51 // Sort the mailbox according to 'howToSort'.
54 // The location of the displayed message after the sort.
57 Sort::sortMessages(MsgScrollingList *displayList,
58 DtMail::MailBox *mbox,
61 // TODO - CHECK ERROR !!!
63 char *primary_key_str;
65 int secondary_key_int;
68 MsgHndArray *msgHandles;
69 MsgHndArray *deletedMsgHandles;
71 MsgStruct *displayed_ms;
72 DtMailBoolean useToHeaderWhenMailIsFromMe = DTM_FALSE;
76 // Remember the displayed_ms message.
78 displayed = displayList->get_displayed_item();
79 displayed_ms = displayList->get_message_struct(displayed);
81 msgHandles = displayList->get_messages();
82 deletedMsgHandles = displayList->get_deleted_messages();
83 if (howToSort == SortSender)
85 useToHeaderWhenMailIsFromMe =
86 displayList->senderIsToHeaderWhenMailFromMe();
90 if (msgHandles != NULL && mbox != NULL)
93 // Add in the deleted messages for the purpose of sorting.
95 if (NULL != deletedMsgHandles)
97 numberMessages = deletedMsgHandles->length();
98 for (int i = 0; i < numberMessages; i++)
100 MsgStruct *ms = deletedMsgHandles->at(i);
101 msgHandles->insert(ms);
105 numberMessages = msgHandles->length();
106 if (numberMessages > 0)
109 // Need list for all of the messages.
110 // +2 for 2 artificial records R(0) and R(n+1). See Knuth (5.2.4)
112 // In addition, the data must be placed in the array with the
113 // dummy records at the beginning and end of the array.
115 messageRecord * messages = new messageRecord[numberMessages +2];
119 DtMail::Message * msg = NULL;
120 DtMail::Envelope * envelope = NULL;
123 // Get the messages from the list.
125 for(msgno=0 ; msgno<numberMessages; msgno++)
130 // Get the handle and envelope and header.
132 messages[offset].msg_struct = msgHandles->at(msgno);
134 if (howToSort != SortMsgNum)
136 // Don't need envelope to sort by MsgNum since that is
137 // a front end concept
138 msg = mbox->getMessage(error,
139 messages[offset].msg_struct->message_handle);
144 "dtmail: getMessage: Could not get message # %d: %s\n",
145 msgno, (const char *)error);
150 envelope = msg->getEnvelope(error);
154 "dtmail: getEnvelope: Could not get envelope for # %d: %s\n",
155 msgno, (const char *)error);
158 if (msg == NULL || envelope == NULL) continue;
161 primary_key_str = NULL;
164 // Set up the secondary sort key using the received timestamp.
165 envelope->getHeader(error, DtMailMessageReceivedTime, DTM_TRUE, value);
167 secondary_key_int = 0;
171 ds = (*(value[0])).toDate();
172 secondary_key_int = (int)ds.dtm_date;
177 // The header that we will sort on depends on how we were
184 envelope->getHeader(error, DtMailMessageSender, DTM_TRUE, value);
186 primary_key_str = strdup("");
189 // Stole from MsgScrollingList
190 DtMailAddressSeq *addr_seq = (value[0])->toAddress();
191 DtMailValueAddress *addr = (*addr_seq)[0];
194 // If we are displaying the To: header when mail is from me,
195 // check to see if I sent this mail and use to contents of the
196 // To: header in place of the Sender (aka From: header).
198 if (DTM_TRUE == useToHeaderWhenMailIsFromMe)
202 DtMailValueSeq tovalue;
206 ptr = strchr(addr->dtm_address, '@');
208 len = ptr - addr->dtm_address;
210 len = strlen(addr->dtm_address);
212 if (strncmp(pw.pw_name, addr->dtm_address, len) == 0)
215 error, DtMailMessageTo,
217 if (error.isNotSet())
219 addr_seq = (tovalue[0])->toAddress();
220 addr = (*addr_seq)[0];
227 primary_key_str = strdup("");
228 else if (addr->dtm_person)
229 primary_key_str = strdup(addr->dtm_person);
233 if (NULL != addr->dtm_address)
234 str = strdup(addr->dtm_address);
237 primary_key_str = strdup(str);
243 envelope->getHeader(error, DtMailMessageSubject, DTM_TRUE, value);
245 primary_key_str = strdup("");
248 // Skip over "Re:, Re[n]:"
252 if (strncasecmp(p, "Re", 2) == 0)
255 while (isspace(*p)) p++;
259 while (isspace(*p)) p++;
260 while (isalnum(*p)) p++;
261 while (isspace(*p)) p++;
263 while (isspace(*p)) p++;
268 primary_key_str = strdup(p);
275 DtMailMessageContentLength,
278 if (error.isNotSet())
279 primary_key_int = (int) strtol(*(value[0]), NULL, 10);
283 envelope->getHeader(error, DtMailMessageStatus, DTM_TRUE, value);
285 // Want sort order to be Read, Unread, New
288 // No Status means New
299 } else if (strcmp(s, "RO") == 0) {
310 primary_key_int = messages[offset].msg_struct->sessionNumber;
316 // Default is to use the time received timestamp setup above.
317 primary_key_int = secondary_key_int;
320 messages[offset].primary_key_str = primary_key_str;
321 messages[offset].primary_key_int = primary_key_int;
322 messages[offset].secondary_key_int = secondary_key_int;
330 _msort((char *)messages,
332 sizeof(messageRecord),
333 0, // Link (offset) is at ZERO.
337 // Rearrange the pointers to msg_structs in the original MsgHndArray.
341 i = messages[0].link;
342 for (offset = 0; offset < numberMessages ; offset++)
344 msgHandles->replace(offset, messages[i].msg_struct);
345 if (messages[i].primary_key_str != NULL)
346 free(messages[i].primary_key_str);
347 i = messages[i].link;
350 // Renumber the session numbers.
351 for(msgno=0 ; msgno<numberMessages; msgno++)
353 MsgStruct *ms = msgHandles->at(msgno);
354 ms->sessionNumber = msgno;
362 // Remove the deleted messages.
364 if (NULL != deletedMsgHandles)
366 numberMessages = deletedMsgHandles->length();
367 for (int i = 0; i < numberMessages; i++)
369 MsgStruct *ms = deletedMsgHandles->at(i);
370 msgHandles->remove_entry(ms);
375 // Figure out the new offset for displayed_ms message
377 numberMessages = msgHandles->length();
378 for (int i = 0; i < numberMessages; i++)
380 MsgStruct *ms = msgHandles->at(i);
381 if (ms == displayed_ms) displayed = i + 1;
389 // msort() is a list-merge sort routine generalized from Knuth (5.2.4)
390 // Algorithm L. This routine requires 2 artificial records: R0 and
391 // Rn+1 where n = number of elements "nel". "offset" is the byte-offset
392 // of the "link" field. "width" is the size of each record. "base" is
393 // the base address of the starting record (i.e. R0.)
395 // (Code lifted from msort.c in the original mailtool).
398 #define Record(i) (base + (width * (i)))
399 #define Link(i) (*((int *) (Record(i) + offset)))
402 Sort::_msort (char * base,
406 int (*compar)(char **one,
422 /* Prepare two lists. */
425 for (i = nel - 2; i >= 1; i--) {
447 if ((*compar)(&k1, &k2) <= 0) {
450 Link(s) = (Link(s) < 0) ? -i : i;
457 /* Complete the sublist */
467 Link(s) = (Link(s) < 0) ? -i : i;
474 /* Complete the sublist */
488 Link(s) = (Link(s) < 0) ? -i : i;
497 // These were used in msort() only. They are #undef'ed as a precaution only.
503 // Sort the two records.
506 Sort::_sortCmp(char ** one, char ** two)
509 // Cast the pointers to the known type.
511 messageRecord * first = (messageRecord *) *one;
512 messageRecord * second = (messageRecord *) *two;
514 if (first->primary_key_str == NULL)
516 if (first->primary_key_int < second->primary_key_int)
518 else if (first->primary_key_int > second->primary_key_int)
520 else if (first->secondary_key_int < second->secondary_key_int)
522 else if (first->secondary_key_int > second->secondary_key_int)
529 int retval = strcmp(first->primary_key_str, second->primary_key_str);
532 else if (first->secondary_key_int < second->secondary_key_int)
534 else if (first->secondary_key_int > second->secondary_key_int)