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 librararies 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: MsgScrollingList.C /main/38 1998/12/10 19:08:02 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.
43 #include <EUSCompat.h>
49 #include <DtMail/DtMailError.hh>
50 #include <DtMail/IO.hh>
51 #include "DtMailGenDialog.hh"
52 #include "DtMailHelp.hh"
53 #include "Help.hh" // Remove after fixing problem with empty time headers
55 #include "MemUtils.hh"
56 #include "MsgHndArray.hh"
57 #include "MsgScrollingList.hh"
59 #include "QueryDialogManager.hh"
60 #endif /* DEAD_WOOD */
62 #include "RoamMenuWindow.h"
66 #include <X11/IntrinsicP.h> // Include for moving X location of titles
68 extern force( Widget );
70 MsgScrollingList::MsgScrollingList(
71 RoamMenuWindow *menuwindow,
81 _numbered = DTM_FALSE;
82 _selected_item_position=-1;
83 _displayed_item_position=-1;
84 _selection_on = FALSE;
85 _xmstr_collector = NULL;
86 _xtarg_collector = NULL;
87 _selected_items = NULL;
88 _sorter = new Sort ();
91 XmNextendedSelectionCallback,
93 &MsgScrollingList::extendedSelectionCallback,
96 _msgs = new MsgHndArray(1024);
97 _deleted_messages = new MsgHndArray(1024);
99 num_deleted_messages = 0;
100 session_message_number = 0;
102 // Can later initialize these from the last use of the session.
103 // Each folder will have some idea of which message was last
104 // read. We should select and display it at next load, no?
106 _selected_item_position = 0;
107 _displayed_item_position = 0;
109 DtMailEnv mail_error;
110 // Initialize the mail_error.
112 DtMail::Session * d_session = theRoamApp.session()->session();
113 DtMail::MailRc * mailrc = d_session->mailRc(mail_error);
116 const char * value = NULL;
117 mailrc->getValue(mail_error, "showto", &value);
118 if (mail_error.isNotSet())
119 _header_info.number_of_names = 5;
121 _header_info.number_of_names = 4;
126 _header_info.number_of_names = 4;
128 // Set up array for 5 items. The DtMailMessageTo is used only
129 // if showto is set, but create placeholder for 5th item in case
130 // they apply props in this same session. Then we just have to
131 // toggle between 4 or 5 number_of_nanes.
133 _header_info.header_name = new (char* [5]);
135 _header_info.header_name[0] = NULL;
136 _header_info.header_name[1] = NULL;
137 _header_info.header_name[2] = NULL;
138 _header_info.header_name[3] = NULL;
139 _header_info.header_name[4] = NULL;
141 _header_info.header_name[0] = strdup(DtMailMessageSender);
142 _header_info.header_name[1] = strdup(DtMailMessageReceivedTime);
143 _header_info.header_name[2] = strdup(DtMailMessageContentLength);
144 _header_info.header_name[3] = strdup(DtMailMessageSubject);
145 _header_info.header_name[4] = strdup(DtMailMessageTo);
148 MsgScrollingList::~MsgScrollingList()
155 if (_header_info.header_name[i])
157 free(_header_info.header_name[i]);
158 _header_info.header_name[i] = NULL;
161 delete _header_info.header_name;
163 for (i=0, length=_deleted_messages->length(); i<length; i++)
165 ms = _deleted_messages->at(i);
168 _deleted_messages->clear();
169 delete _deleted_messages;
171 for (i=0, length=_msgs->length(); i<length; i++)
183 MsgScrollingList::get_scrolling_list()
189 MsgScrollingList::items(
201 MsgScrollingList::addChooseCommand(
209 MsgScrollingList::addDeleteCommand(
215 #endif /* DEAD_WOOD */
219 MsgScrollingList::select_next_item()
223 FORCE_SEGV_DECL(MsgStruct, tmpMS);
224 DtMailEnv mail_error;
226 // Initialize the mail_error.
230 XmNitemCount, &num_msgs,
233 _selected_item_position = _displayed_item_position + 1;
235 if (_selected_item_position <= num_msgs &&
236 _selected_item_position > 0 ) {
238 tmpMS = get_message_struct(_selected_item_position);
243 // Deselect all items currently selected.
244 // display_and_select_message() will select, highlight
245 // and display the "next" message.
247 XmListDeselectAllItems(_w);
249 this->display_and_select_message(mail_error,
250 tmpMS->message_handle);
251 if (mail_error.isSet()) {
252 // Post an exception here...
262 MsgScrollingList::select_prev_item()
266 FORCE_SEGV_DECL(MsgStruct, tmpMS);
267 DtMailEnv mail_error;
269 // Initialize the mail_error.
273 XmNitemCount, &num_msgs,
276 if( _displayed_item_position != 1 )
277 _selected_item_position = _displayed_item_position - 1 ;
279 _selected_item_position = _displayed_item_position ;
281 if (_selected_item_position >= 1) {
282 tmpMS = get_message_struct(_selected_item_position);
287 // Deselect all items currently selected.
288 // display_and_select_message() will select, highlight
289 // and display the "previous" message.
291 XmListDeselectAllItems(_w);
293 this->display_and_select_message(mail_error,
294 tmpMS->message_handle);
295 if (mail_error.isSet()) {
296 // Post an exception here...
306 MsgScrollingList::msgno(
314 return _msgs->at(index-1)->message_handle;
319 MsgScrollingList::get_message_struct(
327 return(_msgs->at(index-1));
332 MsgScrollingList::position(
333 DtMailMessageHandle msgno
336 return (_msgs->indexof(msgno))+1;
341 MsgScrollingList::position(
342 MsgStruct *a_msg_struct
345 return (_msgs->indexof(a_msg_struct))+1;
349 MsgScrollingList::appendMsg(
350 DtMailMessageHandle msg_hndl
355 // A new message has come in.
356 // Increase the session_message_number which keeps track of the
357 // number of messages in this session for this folder (scrolling list).
360 newMS = new MsgStruct();
361 newMS->message_handle = msg_hndl;
362 newMS->indexNumber = session_message_number-num_deleted_messages;
363 newMS->sessionNumber = session_message_number;
364 newMS->is_deleted = FALSE;
365 _msgs->append(newMS);
366 session_message_number++;
369 #endif /* DEAD_WOOD */
373 MsgScrollingList::insertMsg(
374 DtMailMessageHandle msg_hndl
379 // A new message has come in.
380 // Increase the session_message_number which keeps track of the
381 // number of messages in this session for this folder (scrolling list).
384 newMS = new MsgStruct();
385 newMS->message_handle = msg_hndl;
386 newMS->indexNumber = session_message_number-num_deleted_messages;
387 newMS->sessionNumber = session_message_number;
388 newMS->is_deleted = FALSE;
389 _msgs->append(newMS);
391 session_message_number++;
395 MsgScrollingList::insertDeletedMsg(DtMailMessageHandle msg_hndl)
399 // A new message has come in.
400 // Increase the session_message_number which keeps track of the
401 // number of messages in this session for this folder (scrolling list).
404 newMS = new MsgStruct();
405 newMS->message_handle = msg_hndl;
406 newMS->indexNumber = num_deleted_messages;
407 newMS->sessionNumber = session_message_number;
408 newMS->is_deleted = FALSE;
409 _deleted_messages->append(newMS);
411 session_message_number++;
412 num_deleted_messages++;
416 MsgScrollingList::load_headers(
417 DtMailEnv &mail_error
421 DtMailMessageHandle tmpMH;
423 XmString new_status, read_status;
425 XmString complete_header; // text of header w/ glyphs
428 DtMailHeaderLine info;
429 DtMail::MailBox * mbox = this->parent()->mailbox();
431 DtMailBoolean first_new = DTM_TRUE;
433 // Create a class to collect the mail header XmStrings
434 // then get all the items from the current list.
435 _xmstr_collector = new XmStrCollector();
439 * In a mailer container window's message scrolling list, a "N" appears
440 * to the left of a mail message header indicating that the mail message
441 * is "new" (just arrived and not yet viewed by the user).
442 * There is only space to display 1 character. If "N" needs to be translated,
443 * please make sure the translation is only 1 character.
445 new_status = XmStringCreateLocalized(GETMSG(DT_catd, 1, 110, "N"));
446 read_status = XmStringCreateLocalized(" ");
449 // Allocate memory for the XmString array and initialize it.
452 XtVaGetValues(_w, XmNvisibleItemCount, &visible, NULL);
454 // Retrieve the message_handles, and from them their headers.
455 // Create an XmString and toss it into the XmStrCollector.
461 for (tmpMH = mbox->getFirstMessageSummary(error, _header_info, info);
462 tmpMH && !error.isSet();
463 tmpMH = mbox->getNextMessageSummary(error, tmpMH, _header_info, info),
466 DtMail::Message * msg = mbox->getMessage(error, tmpMH);
467 if (msg->flagIsSet(error, DtMailMessageDeletePending) == DTM_TRUE) {
468 insertDeletedMsg(tmpMH);
476 ms = get_message_struct(get_num_messages());
477 complete_header = formatHeader(
480 show_with_attachments(msg),
481 msg->flagIsSet(error, DtMailMessageNew));
484 if (msg->flagIsSet(error, DtMailMessageNew) == DTM_TRUE) {
487 // We want to select the last read message before the
488 // first new message. We will select the first new
489 // message if it is the first message.
492 first_new = DTM_FALSE;
494 select_item = num_items - 1;
500 // Insert the XmString into the array.
501 _xmstr_collector->AddItemToList (complete_header);
503 // Free the space allocated for info
504 // delete []info.header_values;
505 mbox->clearMessageSummary(info);
508 // If there were no new messages, select and display the last message.
510 select_item = num_items - 1;
513 select_item += 1; // Message slots start at 1.
515 select_item -= num_deleted_messages; // List does not have deleted msgs.
517 // Add the items to the XmList.
518 // All XmStrings are freed in the XmStrCollector destructor.
519 _xtarg_collector = new XtArgCollector;
521 // The first time the headers are loaded, they should all be loaded
522 // at the same time. XtVaSetValues is used for this rather than
523 // XmListAddItems so that all the other resource will be set at
524 // the same time. This prevents multiple repaints.
526 // However, in the case where only an item or two are being added,
527 // XmListAddItems should be used. This prevents an unnecessary
528 // repaint in this case.
529 XmListAddItems (_w, _xmstr_collector->GetItems(),
530 _xmstr_collector->GetNumItems(), 0);
532 display_message_summary();
533 display_message(mail_error, select_item);
535 _xtarg_collector->SetValues(_w);
538 XmStringFree (_selected_items);
539 _selected_items = NULL;
542 delete _xtarg_collector;
543 delete _xmstr_collector;
544 _xtarg_collector = NULL;
545 _xmstr_collector = NULL;
551 MsgScrollingList::load_headers(
552 DtMailEnv &mail_error,
553 DtMailMessageHandle last
556 DtMailMessageHandle tmpMH;
558 XmString read_status, new_status;
560 XmString complete_header; // read status + attach + header_text.
562 int num_new = 0, num_vis = 0;
563 DtMailHeaderLine info;
565 DtMail::MailBox * mbox = this->parent()->mailbox();
568 // Create a class to collect the mail header XmStrings
569 // then get all the items from the current list.
570 _xmstr_collector = new XmStrCollector();
576 * In a mailer container window's message scrolling list, a "N" appears
577 * to the left of a mail message header indicating that the mail message
578 * is "new" (just arrived and not yet viewed by the user).
579 * There is only space to display 1 character. If "N" needs to be translated,
580 * please make sure the translation is only 1 character.
582 new_status = XmStringCreateLocalized(GETMSG(DT_catd, 1, 111, "N"));
583 read_status = XmStringCreateLocalized(" ");
586 // Allocate memory for the XmString array and initialize it.
588 XtVaGetValues(_w, XmNvisibleItemCount, &num_items, NULL);
592 for (tmpMH = mbox->getNextMessageSummary(error, last, _header_info, info);
593 tmpMH && !error.isSet();
594 tmpMH = mbox->getNextMessageSummary(error, tmpMH, _header_info, info),
597 DtMail::Message * msg = mbox->getMessage(error, tmpMH);
598 if (msg->flagIsSet(error, DtMailMessageDeletePending) == DTM_TRUE) {
599 insertDeletedMsg(tmpMH);
607 ms = get_message_struct(get_num_messages());
608 complete_header = formatHeader(
611 show_with_attachments(msg),
612 msg->flagIsSet(error, DtMailMessageNew));
614 if (msg->flagIsSet(error, DtMailMessageNew) == DTM_TRUE) {
618 // Insert the XmString into the array.
619 _xmstr_collector->AddItemToList (complete_header);
621 // Free the space allocated for info
622 // delete []info.header_values;
623 mbox->clearMessageSummary(info);
626 // Add the items to the XmList.
627 // All XmStrings are freed in the XmStrCollector destructor.
628 _xtarg_collector = new XtArgCollector;
630 // The first time the headers are loaded, they should all be loaded
631 // at the same time. XtVaSetValues is used for this rather than
632 // XmListAddItems so that all the other resource will be set at
633 // the same time. This prevents multiple repaints.
635 // However, in the case where only an item or two are being added,
636 // XmListAddItems should be used. This prevents an unnecessary
637 // repaint in this case.
638 XmListAddItems (_w, _xmstr_collector->GetItems(),
639 _xmstr_collector->GetNumItems(), 0);
641 do_list_vis_adjustment();
643 display_message_summary();
645 _xtarg_collector->SetValues(_w);
648 XmStringFree (_selected_items);
649 _selected_items = NULL;
652 delete _xtarg_collector;
653 delete _xmstr_collector;
654 _xtarg_collector = NULL;
655 _xmstr_collector = NULL;
658 void MsgScrollingList::do_list_vis_adjustment()
661 int numNew = _xmstr_collector->GetNumItems();
662 int focItm = _selected_item_position;
665 int cItmCnt, pItmCnt, sItmCnt;
666 int cFocItm, cTopItm, cBotItm, cInvItm;
668 XtVaGetValues(list, XmNvisibleItemCount, &numItems, NULL);
669 XtVaGetValues(list, XmNitemCount, &cItmCnt, NULL);
670 XtVaGetValues(list, XmNselectedItemCount, &sItmCnt, NULL);
671 XtVaGetValues(list, XmNtopItemPosition, &cTopItm, NULL);
672 pItmCnt = cItmCnt - numNew;
674 cBotItm = cTopItm + numItems - 1; //[cTopItm...cBotItm is our window
676 //[User has chosen to view some messages and that view needs to be
678 if (cBotItm != pItmCnt)
681 //[If Brand New Mailbox
682 if (cItmCnt <= numItems)
685 //[If no items selected, simply synch right till bottom
687 XmListSetBottomPos(list, cItmCnt);
691 // assert(cFocItm != -1);
694 cInvItm = pItmCnt - cBotItm; //[Num below bottom-most, or hidden
696 if ((cFocItm <= cBotItm) && (cFocItm >= cTopItm)) {
697 int winM = cFocItm - cTopItm - cInvItm;
698 if (winM <= 0) { //[There is no scope of adjustment
701 //[All the new messages can be accomodated w/o scrolling curr selection
702 if (numNew <= winM) {
703 XmListSetBottomPos(list, cItmCnt);
706 //[All the new messages cannot be accomodated, but we will do best fit
708 int numNotShow = numNew - winM;
709 XmListSetBottomPos(list, cItmCnt - numNotShow);
714 XmListSetBottomPos(list, cItmCnt);
720 MsgScrollingList::deleteSelected(Boolean silent)
722 // SR - Added stuff below. Made code more efficient also.
723 FORCE_SEGV_DECL(MsgStruct, a_del_msg_struct);
724 FORCE_SEGV_DECL(MsgStruct, tmpMS);
725 FORCE_SEGV_DECL(ViewMsgDialog, tmpView);
726 DtMailMessageHandle tmpMH;
727 int position_in_list, i;
728 FORCE_SEGV_DECL(int, position_list);
730 Boolean any_selected;
732 UndelFromListDialog *undel_dialog;
733 int first_selected_pos;
734 DtMailEnv mail_error, error;
735 DtMailBoolean cur_state;
736 char *status_message, *str;
738 // Initialize the mail_error.
741 XtVaGetValues( _w, XmNitemCount, &num_msgs, NULL );
742 any_selected = XmListGetSelectedPos(_w, &position_list, &position_count);
743 if (!any_selected) return;
746 // Of the items in the list, potentially many could be selected
747 // for delete. And those selected for deleted need not be
748 // contiguous necessarily. Note the position of the item that
749 // appears first in the list. When the items are deleted, other
750 // items if any exist will shift up to take the places of the
751 // deleted items. You want to display the corresponding item that
752 // takes the "first position".
754 // Say, if you have messages A, B, C, D, Evisible in that order.
755 // You select B and C for delete.
756 // The first selected pos is 2.
757 // When B and C are deleted, D (and E...) move up.
758 // The new order is A, D, E...
759 // You want to display the second message which is D.
761 first_selected_pos = *position_list;
762 undel_dialog = parent()->get_undel_dialog();
764 for (i=0; i < position_count; i++ )
766 position_in_list = *(position_list + i);
767 a_del_msg_struct = get_message_struct(position_in_list);
768 _msgs->mark_for_delete(position_in_list - 1);
769 _deleted_messages->append(a_del_msg_struct);
771 undel_dialog->insertMsg(mail_error, a_del_msg_struct);
772 if (mail_error.isSet()) parent()->postErrorDialog(mail_error);
774 // See if there is a standalone view of the message.
775 // If there is, quit it.
777 tmpMH = a_del_msg_struct->message_handle;
778 tmpView = parent()->ifViewExists(tmpMH);
779 if (tmpView) tmpView->quit();
781 // Update the status of the message in the persistent store.
783 DtMail::Message * msg = _parent->mailbox()->getMessage(
785 a_del_msg_struct->message_handle);
786 msg->setFlag(error, DtMailMessageDeletePending);
788 // Check if message is new. If new and it is being deleted,
789 // reduce the new messages count.
791 cur_state = msg->flagIsSet(error, DtMailMessageNew);
793 if (cur_state == DTM_TRUE) num_new_messages--;
798 // Delete the items from the scrolling list
800 XmListDeletePositions(_w, position_list, position_count);
801 num_deleted_messages += position_count;
803 // XnListGetSelectedPos allocated memory for the array and
804 // wants us to free it. See documentation.
806 num_msgs = _msgs->length();
808 // Always remove the current attachments from the attachment area
809 // regardless of whether this is the last message in the list or not
810 // We call clearAttachArea if there are any other messages in the folder
811 // as parseAttachments will be called which will clean up the attachment
812 // status window. In the case of deleting the last message we must call
813 // removeCurrentAttachments which cleans up the status window as well.
816 parent()->get_editor()->attachArea()->removeCurrentAttachments();
818 parent()->get_editor()->attachArea()->clearAttachArea();
822 //No more messages left; clear the editor.
823 parent()->get_editor()->textEditor()->set_contents("", 1);
825 // NOTE: Need to obtain the attachArea and clear it up too
827 _displayed_item_position = 0; // Not displaying any.
828 _selected_item_position = 0; // Reset...
830 display_message_summary();
834 // If there are messages 1, 2 and 3 and 2 is selected and deleted
835 // first_selected_pos will be 2;
836 // after removing it, will need to display the 2nd message
837 // (which will now be 3)
838 // If 2 and 3 have been deleted, and there is no 2nd message,
839 // display the nth message (in our example, n = 1)
841 _selected_item_position = first_selected_pos;
842 if (_selected_item_position > num_msgs)
843 _selected_item_position = num_msgs;
845 // Having determined which message to display, confirm that it is
846 // within the bounds. Call display_message().
847 // FYI, display_message() sets the _displayed_item_position.
849 if ((_selected_item_position > 0) &&
850 (_selected_item_position <= num_msgs))
852 XmListSelectPos(_w, _selected_item_position, FALSE);
853 tmpMS = this->get_message_struct(_selected_item_position);
861 this->display_message(mail_error, tmpMS->message_handle);
862 if (mail_error.isSet()) parent()->postErrorDialog(mail_error);
868 if (position_count > 1)
871 * The following sentence means %d number of mail messages have
872 * been deleted from the mail folder. This is the plural form
873 * of the message that gets printed if more than one message
876 str = GETMSG(DT_catd, 3, 84, "%d messages deleted");
881 * The following sentence means %d number of mail messages have
882 * been deleted from the mail folder. This is the singular
883 * form of the message that gets printed if only one message
886 str = GETMSG(DT_catd, 3, 85, "%d message deleted");
888 status_message = new char[strlen(str) + 10];
889 sprintf(status_message, str, position_count);
890 parent()->message(status_message);
891 delete [] status_message;
894 updateListItems(-1, TRUE, NULL);
895 display_message_summary();
897 XtFree((char*) position_list);
912 // copySelected() will either copy or move the selected messages
913 // into the container called destname. If the delete_after_copy
914 // flag is set to TRUE, it is effectively a move; otherwise, it
915 // is a copy. If the container named by destname is a relative
916 // path, but it isn't prefixed with a '+', then a '+' will be
917 // prepended to the name so that the open() call will "do the
919 // If silent is TRUE then no status messages are displayed and the
920 // destname is not added to the copy/move cache.
923 MsgScrollingList::copySelected(
924 DtMailEnv &mail_error,
926 int delete_after_copy,
930 FORCE_SEGV_DECL(DtMail::MailBox, mbox);
931 FORCE_SEGV_DECL(int, position_list);
932 FORCE_SEGV_DECL(DtMail::MailBox, target);
933 DtMail::MailRc * mailrc;
934 DtMail::Session * d_session = theRoamApp.session()->session();
935 int position_count, position, i;
936 Boolean any_selected = FALSE;
937 DtMailMessageHandle msg;
938 char *status_message, *str;
943 any_selected = XmListGetSelectedPos(_w,
946 // If there aren't any selected messages, then there isn't
947 // anything for us to do.
950 display_no_message();
953 char * helpId = NULL;
954 DtMailGenDialog *dialog = _parent->genDialog();
956 dialog->setToErrorDialog(
957 GETMSG(DT_catd, 3, 50, "Mailer"),
958 GETMSG(DT_catd, 2, 16, "No message selected."));
959 dialog->post_and_return(helpId);
964 mbox = parent()->mailbox();
965 mailrc = mbox->session()->mailRc(mail_error);
968 // The following is an error message. "mailrc" is the name of the
969 // mail resource file. Translate as appropriate.
971 parent()->message(GETMSG(DT_catd, 2, 15,"Error - Unable to get mailrc."));
975 // If the first character of destname is alphanumeric, we can
976 // safely assume that it is a relative path, so we prepend a
978 if (isalnum(destname[0])) {
979 // Make sure we allocate enough for the name + '+' + null terminator.
980 newdestname = (char *) malloc(strlen(destname) + 2);
981 memset(newdestname, 0, strlen(destname) + 2);
982 sprintf(newdestname, "+%s", destname);
983 char *path = d_session->expandPath(mail_error, newdestname);
984 target = theRoamApp.session()->open(mail_error,
995 target = theRoamApp.session()->open(mail_error,
1003 if (mail_error.isSet()) {
1004 // if the error is DTME_AlreadyOpened, we don't care.
1005 // go ahead to clear the error
1007 // We couldn't open the container, so we want to post an
1009 if ((DTMailError_t)mail_error == DTME_AlreadyOpened)
1013 parent()->postErrorDialog(mail_error);
1018 // Go through the selected messages and copy them to the
1019 // specified container.
1021 if ( position_count > 0 )
1022 parent()->busyCursor() ;
1024 for (i=0; i < position_count; i++) {
1025 position = *(position_list + i);
1026 msg = msgno(position);
1027 DtMail::Message * dtmsg = mbox->getMessage(mail_error, msg);
1028 if (mail_error.isSet()) {
1029 parent()->normalCursor() ;
1030 parent()->postErrorDialog(mail_error);
1031 theRoamApp.session()->close(mail_error, target);
1036 target->copyMessage(mail_error, dtmsg);
1037 if (mail_error.isSet()) {
1038 parent()->normalCursor() ;
1039 parent()->postErrorDialog(mail_error);
1040 theRoamApp.session()->close(mail_error, target);
1044 parent()->normalCursor() ;
1049 rmw = theRoamApp.session()->getRMW(target);
1051 if (rmw) rmw->checkForMail(mail_error);
1053 if (delete_after_copy) {
1058 // The following sentence means %d number of mail messages have
1059 // been moved to the %s mail folder. The %s is the name of a
1060 // mail folder. This is the plural form of the message that gets
1061 // printed if more than one message is moved.
1063 str = GETMSG(DT_catd, 3, 65, "%d messages moved to %s");
1066 // The following sentence means %d number of mail messages have
1067 // been moved to the %s mail folder. The %s is the name of a
1068 // mail folder. This is the singular form of the message that
1069 // gets printed if only one message is moved.
1071 str = GETMSG(DT_catd, 3, 66, "%d message moved to %s");
1077 // The following sentence means %d number of mail messages have been
1078 // copied to the %s mail folder. This is the plural form of the
1079 // message that gets printed if more than one message is copied.
1081 str = GETMSG(DT_catd, 3, 67, "%d messages copied to %s");
1084 // The following sentence means %d number of mail messages have been
1085 // copied to the %s mail folder. This is the singular form of the
1086 // message that gets printed if only one message is copied.
1088 str = GETMSG(DT_catd, 3, 68, "%d message copied to %s");
1092 newdestname = d_session->getRelativePath(mail_error, destname);
1093 status_message = new char[strlen(str) + strlen(newdestname) + 10];
1094 sprintf(status_message, str, i, newdestname);
1097 theRoamApp.globalAddToCachedContainerList(newdestname);
1098 parent()->message(status_message);
1103 theRoamApp.session()->close(mail_error, target);
1105 delete [] status_message;
1110 //-----------------------------------------------------------------------------
1111 // This method returns a list of the currently selected messages. This list
1112 // must be deleted by the calling method.
1113 //-----------------------------------------------------------------------------
1116 MsgScrollingList::selected()
1118 FORCE_SEGV_DECL(MsgStruct, a_msg_struct);
1119 FORCE_SEGV_DECL(int, position_list);
1120 int position_in_list, i;
1122 Boolean any_selected;
1124 // Find out first if any have been selected.
1125 // If i has been selected, how many?
1126 // We need the number selected so that we can allocate
1127 // space for that many mesasgeStructs to be returned.
1129 any_selected = XmListGetSelectedPos(_w,
1133 // If nothing selected, return
1135 if (!any_selected) return NULL;
1137 // Allocate memory for position_count number of messageStructs
1140 MsgHndArray *msgList = new MsgHndArray(position_count);
1142 for (i=0; i < position_count; i++ ) {
1143 position_in_list = *(position_list + i);
1144 a_msg_struct = get_message_struct(position_in_list);
1145 msgList->append(a_msg_struct);
1151 MsgScrollingList::show_with_attachments(DtMailMessageHandle msg_num)
1153 DtMailBoolean has_attachments = DTM_FALSE;
1154 DtMailEnv mail_error;
1155 DtMail::MailBox *mbox=parent()->mailbox();
1156 DtMail::Message *msg = mbox->getMessage(mail_error, msg_num);
1158 has_attachments = show_with_attachments(msg);
1159 return has_attachments;
1164 MsgScrollingList::show_with_attachments(DtMail::Message * msg)
1166 DtMail::BodyPart *bp;
1168 DtMailBoolean has_attachments = DTM_FALSE;
1169 DtMailBoolean is_multipart = DTM_FALSE;
1173 is_multipart = msg->flagIsSet(error, DtMailMessageMultipart);
1177 num_bodyParts = msg->getBodyCount(error);
1178 if (num_bodyParts > 1)
1181 bp = msg->getFirstBodyPart(error);
1182 bp->getContents(error, NULL, NULL, &type, NULL, NULL, NULL);
1187 attr = DtDtsDataTypeToAttributeValue(type, DtDTS_DA_IS_TEXT, NULL);
1188 if (attr && strcasecmp(attr, "true") != 0)
1189 has_attachments = DTM_TRUE;
1194 DtDtsFreeAttributeValue(attr);
1196 return has_attachments;
1201 MsgScrollingList::display_message(
1202 DtMailEnv &mail_error,
1203 DtMailMessageHandle msg_num
1207 DtMail::MailBox *mbox=parent()->mailbox();
1209 DtMailBoolean cur_state;
1213 // If there is a status message displayed, clear it first.
1214 parent()->clear_message();
1217 // We could have called display_msg from anywhere.
1218 // Need to calculate what is the position of that item
1219 // in the scrolling list, given the DtMailMessageHandle.
1220 // Determine the index at the _msgs array; increment by 1
1221 // since array begins at 0 and XmList begins at 1.
1223 item_index = _msgs->indexof(msg_num);
1224 if (item_index < 0) return;
1226 _displayed_item_position = item_index + 1;
1228 // Make sure the header is visible in the scrolling list.
1229 this->scroll_to_position(_displayed_item_position);
1231 // Retrieve the header text and insert it. We need to retrieve
1232 // message from the handle and inset the headers.
1235 DtMail::Message * msg = mbox->getMessage(mail_error, msg_num);
1236 DtMail::Envelope * env = msg->getEnvelope(mail_error);
1239 // There are multiple paths to this place:
1240 // 1) user has already read this message but is re-reading it;
1241 // 2) user has undeleted this message (implicitly, they have
1242 // read this message);
1243 // 3) user has not read this message yet.
1245 // For (1), we don't need to do anything fancy.
1246 // For (2), we have already reset the IsDeleted flag while
1248 // For (3), we need to reset the flag in store to indicate
1251 cur_state = msg->flagIsSet(mail_error, DtMailMessageNew);
1253 // If the message was previously new, we need to reset the list
1254 // item to remove the "N" on the item. We do this by reconstructing
1255 // the header line without the "N".
1257 if (cur_state == DTM_TRUE) {
1258 DtMailHeaderLine info;
1260 msg->resetFlag(mail_error, DtMailMessageNew);
1262 mbox->getMessageSummary(mail_error, msg_num, _header_info, info);
1265 ms = get_message_struct(_displayed_item_position);
1267 XmString complete_header;
1268 complete_header = formatHeader(
1271 show_with_attachments(msg),
1272 msg->flagIsSet(mail_error, DtMailMessageNew));
1274 mbox->clearMessageSummary(info);
1276 XmListReplaceItemsPos(_w, &complete_header,1, _displayed_item_position);
1277 XmStringFree(complete_header);
1279 // The default selection policy is extended_select.
1281 // User extend selects multiple items
1282 // The last item selected is a "N" message
1283 // We display the "N" message and have to replace it without
1285 // There is no way to replace with something else and select at
1287 // Therefre, we need to explicitly select the replacement.
1288 // The problem is: selecting the replacement deselects the other
1290 // To work around this, we switch temporarily to MULTIPLE_SELECT,
1291 // select the replacement, and switch back to extend_select.
1292 // This will select the replacement and *not* drop the
1293 // selection on the other selected items.
1294 // Say "Amen" to OSF for such convoluted thinking!
1297 XmNselectedItemCount, &num_selected,
1300 if (num_selected > 1) {
1301 // Change to MULTIPLE_SELECT.
1303 // Change back to EXTEND_SELECT
1305 XmNselectionPolicy, XmMULTIPLE_SELECT,
1306 XmNselectionMode, XmNORMAL_MODE,
1309 // When loading mail headers, we need to make sure that
1310 // the XmList resources are all set at the same time to
1311 // avoid painting multiple times. So here we collect
1313 if (_xtarg_collector && _xmstr_collector)
1315 XmString *items = _xmstr_collector->GetItems();
1317 // Keep a handle to the malloced string copy so that
1318 // we can free it after the XtSetValues
1320 = XmStringCopy (items[_displayed_item_position - 1]);
1322 _xtarg_collector->AddItemToList (XmNselectedItems,
1323 (XtArgVal) &_selected_items);
1324 _xtarg_collector->AddItemToList (
1325 XmNselectedItemCount, 1);
1326 _xtarg_collector->AddItemToList (
1327 XmNselectionPolicy, XmEXTENDED_SELECT);
1331 XmListSelectPos(_w, _displayed_item_position, FALSE);
1334 XmNselectionPolicy, XmEXTENDED_SELECT,
1335 XmNselectionMode, XmNORMAL_MODE,
1340 if (_xtarg_collector && _xmstr_collector)
1342 XmString *items = _xmstr_collector->GetItems();
1345 = XmStringCopy (items[_displayed_item_position - 1]);
1347 _xtarg_collector->AddItemToList (XmNselectedItems,
1348 (XtArgVal) &_selected_items);
1349 _xtarg_collector->AddItemToList (
1350 XmNselectedItemCount, 1);
1354 XmListSelectPos(_w, _displayed_item_position, FALSE);
1361 display_message_summary();
1363 // Display the message now.
1364 rmw_editor = parent()->get_editor()->textEditor();
1365 rmw_editor->disable_redisplay();
1366 rmw_editor->auto_show_cursor_off();
1367 rmw_editor->clear_contents();
1369 num_bodyParts = msg->getBodyCount(mail_error);
1371 char * status_string;
1372 DtMailBoolean firstBPHandled;
1374 // Turn on the busy Cursor
1376 parent()->busyCursor();
1378 if (parent()->fullHeader())
1380 rmw_editor->set_message(msg, &status_string, Editor::HF_FULL);
1383 rmw_editor->set_message(msg, &status_string, Editor::HF_ABBREV);
1385 if (status_string) parent()->message(status_string);
1386 if (mail_error.isSet()) {} // do something
1388 if ((num_bodyParts > 1) || (!firstBPHandled))
1390 // If the message has attachments, then let the attach pane
1391 // handle attachments but not the first bodyPart (which has
1392 // already been handled here).
1394 if (firstBPHandled) {
1396 // The first bodyPart has already been handled.
1397 // The others, beginning from the second, need to be parsed
1398 // and put into the attachPane.
1400 parent()->get_editor()->attachArea()->parseAttachments(
1407 // The first bodyPart was not handled.
1408 // It may not have been of type text.
1409 // The attachment pane needs to handle all the bodyParts
1410 // beginning with the first.
1412 parent()->get_editor()->attachArea()->parseAttachments(
1419 // Check for errors.
1420 // Manage the attach area to display attachments.
1421 if (mail_error.isSet()) {} // do something
1423 parent()->get_editor()->manageAttachArea();
1424 parent()->activate_default_attach_menu();
1428 parent()->deactivate_default_attach_menu();
1429 parent()->get_editor()->unmanageAttachArea();
1432 parent()->sync_work_area_size();
1433 rmw_editor->auto_show_cursor_restore();
1435 // Turn on text editor and manage attachPane
1436 rmw_editor->set_to_top();
1437 rmw_editor->enable_redisplay();
1439 parent()->normalCursor();
1443 MsgScrollingList::display_and_select_message(
1444 DtMailEnv &mail_error,
1445 DtMailMessageHandle msg_num
1450 // Need to calculate what is the position of that item
1451 // in the scrolling list, given the DtMailMessageHandle.
1452 // Determine the index at the _msgs array; increment by 1
1453 // since array begins at 0 and XmList begins at 1.
1457 item_index = _msgs->indexof(msg_num);
1458 if (item_index < 0) return;
1460 _displayed_item_position = item_index + 1;
1461 _selected_item_position = _displayed_item_position;
1463 // Select this message in the scrolling list and display
1466 // When loading mail headers, we need to make sure that
1467 // the XmList resources are all set at the same time to
1468 // avoid painting multiple times. So here we collect
1470 if (_xtarg_collector && _xmstr_collector)
1472 XmString *items = _xmstr_collector->GetItems();
1474 // Keep a handle to the malloced string copy so that
1475 // we can free it after the XtSetValues
1477 = XmStringCopy (items[_displayed_item_position - 1]);
1479 _xtarg_collector->AddItemToList (XmNselectedItems,
1480 (XtArgVal) &_selected_items);
1481 _xtarg_collector->AddItemToList (
1482 XmNselectedItemCount, 1);
1486 XmListSelectPos(_w, _displayed_item_position, FALSE);
1488 this->display_message(mail_error, msg_num);
1494 MsgScrollingList::select_all_and_display_last(
1499 register int item_pos;
1501 MsgHndArray * msgHandles = get_messages();
1505 if (this->get_num_messages() == 0) return;
1507 // If no message selected, return.
1509 if (this->get_selected_item() == 0) return;
1511 XtVaSetValues (_w, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);
1513 // We have to go to the end of the list and go backwards.
1514 // We display the last one, and select the rest.
1516 // A NULL terminated list.
1519 XmListDeselectAllItems(baseWidget());
1520 XtVaGetValues(baseWidget(), XmNitemCount, &num_items, NULL);
1522 for (item_pos = 1; item_pos < num_items; item_pos++) {
1523 XmListSelectPos(baseWidget(), item_pos, FALSE);
1526 // Invoke the selection callback on the last item.
1527 display_and_select_message(error,
1528 msgHandles->at(item_pos-1)->message_handle);
1529 XtVaSetValues (_w, XmNselectionPolicy, XmEXTENDED_SELECT, NULL);
1530 XtVaSetValues (_w, XmNselectionMode, XmNORMAL_MODE, NULL);
1534 MsgScrollingList::select_all_and_display_last(
1536 DtMailMessageHandle *handleArray,
1537 unsigned int elements
1540 register int handleOffset = 0;
1541 register int item_pos;
1545 XtVaSetValues (_w, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);
1547 // We have to go to the end of the list and go backwards.
1548 // We display the last one, and select the rest.
1550 // A NULL terminated list.
1552 handleOffset = elements;
1554 XmListDeselectAllItems(baseWidget());
1556 while (--handleOffset >= 0 && error.isNotSet()) {
1558 item_pos = _msgs->indexof(handleArray[handleOffset]); // Get position
1564 // Select this message in the scrolling list and IF
1565 // it is the last message, display it.
1567 if (handleOffset == elements - 1) {
1568 display_and_select_message(error, handleArray[handleOffset]);
1570 XmListSelectPos(_w, item_pos + 1, FALSE);
1573 XtVaSetValues (_w, XmNselectionPolicy, XmEXTENDED_SELECT, NULL);
1574 XtVaSetValues (_w, XmNselectionMode, XmNORMAL_MODE, NULL);
1580 MsgScrollingList::display_no_message()
1584 * No mail message has been selected by the user.
1587 parent()->message(GETMSG(DT_catd, 2, 16, "No message selected."));
1588 _displayed_item_position = 0;
1589 _selected_item_position = 0;
1591 parent()->get_editor()->textEditor()->clear_contents();
1592 parent()->get_editor()->attachArea()->removeCurrentAttachments();
1595 // In need of a simple but useful optimization here.
1596 // By the time we get to this method, we already have displayed
1597 // the selected message in the lower section of the combo window.
1598 // Instead of having to parse the messageHandle and construct the
1599 // text buffer to display, we can just get the parsed-and-formatted
1600 // text from the lower section of the combo window and stick it into
1601 // the VMD's editor.
1602 // This will save us the effort of parsing and formatting a message
1606 MsgScrollingList::viewInSeparateWindow(DtMailEnv &mail_error)
1608 FORCE_SEGV_DECL(const char, title);
1609 FORCE_SEGV_DECL(char, header_txt);
1610 FORCE_SEGV_DECL(MsgStruct, tmpMS);
1611 DtMailMessageHandle msgHandle;
1612 DtMail::MailBox *mbox=parent()->mailbox();
1613 ViewMsgDialog *newview;
1618 DtMail::Session *d_session = theRoamApp.session()->session();
1619 DtMail::MailRc *mail_rc = d_session->mailRc(error);
1620 const char *value = NULL;
1622 // If no message selected, return.
1623 if (this->get_selected_item() <= 0) return;
1625 // Double-check. If none selected, return
1626 MsgHndArray *selected_msgs = this->selected();
1627 if (!selected_msgs) return;
1629 for (int a_msg_num = 0; a_msg_num < selected_msgs->length(); a_msg_num++)
1631 tmpMS = selected_msgs->at(a_msg_num);
1632 if (tmpMS == NULL) return;
1634 msgHandle = tmpMS->message_handle;
1635 newview = parent()->ifViewExists(msgHandle);
1637 if (newview != NULL)
1640 * The current mail message selected is already displayed in a
1641 * separate window. Therefore this 'separate' window will be
1642 * raised in front of existing windows so the user can see it.
1647 "View already exists. Raising it."));
1648 newview->displayInCurrentWorkspace();
1652 // No view exists. Display it. For feedback, set busyCursor().
1653 parent()->busyCursor();
1654 mail_rc->getValue(error, "separatemessageviewer", &value);
1656 newview = new ViewMsgDialog(parent(), xmDialogShellWidgetClass);
1659 if (value) free((void*) value);
1660 newview = new ViewMsgDialog(parent(), topLevelShellWidgetClass);
1662 parent()->registerDialog(newview);
1663 newview->initialize();
1664 vmd_editor = newview->get_editor()->textEditor();
1666 // Set the VMD's msgHandle. This unique handle is what is
1667 // used to raise the VMD when the same message is double
1668 // clicked on later.
1669 newview->msgno(msgHandle);
1672 DtMail::Message * msg = mbox->getMessage(error, msgHandle);
1673 DtMail::Envelope * env = msg->getEnvelope(error);
1675 DtMailValueSeq title_value;
1676 env->getHeader(error, DtMailMessageSubject, DTM_TRUE, title_value);
1678 title = "NO SUBJECT!";
1680 title = *(title_value[0]);
1682 newview->title((char *)title);
1683 newview->auto_show_cursor_off();
1685 // Unset the error produced when obtaining title...
1687 vmd_editor->disable_redisplay();
1689 char * status_string;
1690 DtMailBoolean firstBPHandled;
1692 if (parent()->fullHeader())
1693 firstBPHandled = newview->get_editor()->textEditor()->set_message(
1694 msg, &status_string, Editor::HF_FULL);
1696 firstBPHandled = newview->get_editor()->textEditor()->set_message(
1697 msg, &status_string, Editor::HF_ABBREV);
1699 // If the message has attachments, then let the attach pane
1700 // handle attachments but not the first bodyPart (which has
1701 // already been handled here).
1702 num_bodyParts = msg->getBodyCount(mail_error);
1703 if (mail_error.isSet()) {} // do something
1705 if ((num_bodyParts == 1) && firstBPHandled)
1707 newview->get_editor()->unmanageAttachArea();
1708 newview->deactivate_default_attach_menu();
1710 else if ((num_bodyParts > 1) || (!firstBPHandled))
1712 // If the message has attachments, then let the attach pane
1713 // handle attachments but not the first bodyPart (which has
1714 // already been handled here).
1718 // The first bodyPart has already been handled.
1719 // The others, beginning from the second, need to be parsed
1720 // and put into the attachPane.
1721 newview->get_editor()->attachArea()->parseAttachments(
1722 mail_error, msg, TRUE, 2);
1726 // The first bodyPart was not handled.
1727 // It may not have been of type text.
1728 // The attachment pane needs to handle all the bodyParts
1729 // beginning with the first.
1730 newview->get_editor()->attachArea()->parseAttachments(
1731 mail_error, msg, TRUE, 1);
1734 // Check for errors.
1735 // Manage the attach area to display attachments.
1736 if (mail_error.isSet()) {} // do something
1737 newview->get_editor()->manageAttachArea();
1738 newview->activate_default_attach_menu();
1741 newview->set_to_top();
1742 newview->auto_show_cursor_restore();
1743 vmd_editor->enable_redisplay();
1747 parent()->normalCursor();
1750 // defaultAction() gets called *after* extendedSelectionCallback() is
1752 // Display the message in extendedSelectionCallback().
1753 // viewInSeparateWindow() in defaultAction().
1756 MsgScrollingList::defaultAction(Widget, XtPointer, XmListCallbackStruct *cbs)
1758 FORCE_SEGV_DECL(MsgStruct, tmpMS);
1759 DtMailEnv mail_error;
1761 // Initialize the mail_error.
1763 _selected_item_position = cbs->item_position;
1765 tmpMS = get_message_struct(_selected_item_position);
1770 this->viewInSeparateWindow(mail_error);
1771 if (mail_error.isSet()) {} // Post dialog indicating error
1777 MsgScrollingList::extendedSelectionCallback(
1779 XtPointer clientData,
1780 XmListCallbackStruct *cbs
1783 int last_clicked_on_pos;
1784 int above_selected_pos;
1785 int tmp_selected_pos;
1786 int i, num_selected;
1787 DtMailEnv mail_error;
1789 // Initialize the mail_error.
1793 Boolean IS_SELECTION = FALSE;
1794 Boolean SELECTION_MADE = FALSE;
1796 MsgScrollingList *obj=(MsgScrollingList *) clientData;
1798 // If all items have been deselected
1799 if (cbs->selected_item_count == 0) {
1800 obj->extended_selection(mail_error, 0);
1801 if (mail_error.isSet()) {
1804 SELECTION_MADE = TRUE;
1808 last_clicked_on_pos = cbs->item_position;
1810 // Check to see if this was a selection or deselection
1811 // We do that by seeing if last_clicked_on_pos is in the
1812 // selected_item_positions array. If it is, then it is a
1813 // selection; if its not there, then its a deselection.
1815 num_selected = cbs->selected_item_count;
1817 for (i = 0; i < num_selected; i++) {
1818 if (last_clicked_on_pos == cbs->selected_item_positions[i]) {
1819 // Yes, it was a selection
1821 IS_SELECTION = TRUE;
1822 obj->extended_selection(mail_error, last_clicked_on_pos);
1823 if (mail_error.isSet()) {
1827 SELECTION_MADE = TRUE;
1831 // If it was not a selection, then we need to find the selected
1832 // item nearest to the deselected item. We have a choice there -
1833 // we can find the nearest one above, or the nearest one below
1834 // the deselected item. Let's find the nearest one above.
1835 // We do that by cruising through the selected_item_positions array.
1836 // Motif arranges the array in ascending order, no matter what order
1837 // you selected the items! If you deselect an item, the items on
1838 // either side of it are the ones above and below it. We use that
1839 // ordering to now select and display the one above it.
1842 if (!IS_SELECTION) {
1844 // If the first selected item is below the deselected item,
1845 // it follows that all selected items are below the deselected
1846 // item. Display the first selected item and be done.
1848 if (cbs->selected_item_positions[0] > last_clicked_on_pos) {
1849 obj->extended_selection(mail_error,
1850 cbs->selected_item_positions[0]);
1851 if (mail_error.isSet()) {
1854 SELECTION_MADE = TRUE;
1856 // If the last selected item is above the deselected item,
1857 // it follows that all selected items are above the deselected
1858 // item. Display the last selected item and be done.
1859 else if (cbs->selected_item_positions[num_selected - 1] <
1860 last_clicked_on_pos) {
1861 obj->extended_selection(mail_error,
1862 cbs->selected_item_positions[num_selected - 1]);
1863 if (mail_error.isSet()) {
1866 SELECTION_MADE = TRUE;
1868 // Otherwise, the deselected item must lie in between other
1869 // selected items. We choose to find the closest selected
1870 // item above the deselected item.
1872 // There are selected items that are above the deselected
1874 // Need to find the one that is both above the deselected
1875 // item and closest to it.
1876 // Iterate until you find the nearest above; select it and
1877 // drop out of loop when after selection.
1879 for (i = 0; i < (num_selected - 1) && !SELECTION_MADE; i++) {
1880 above_selected_pos = cbs->selected_item_positions[i];
1881 tmp_selected_pos = cbs->selected_item_positions[i + 1];
1882 if (tmp_selected_pos > last_clicked_on_pos) {
1883 obj->extended_selection(mail_error,
1884 above_selected_pos);
1885 if (mail_error.isSet()) {
1888 SELECTION_MADE = TRUE;
1898 MsgScrollingList::extended_selection(
1899 DtMailEnv &mail_error,
1903 FORCE_SEGV_DECL(MsgStruct, tmpMS);
1905 // Disable the SaveAttachments menu item first.
1906 // It gets enabled when an attachment is selected.
1908 _parent->all_attachments_deselected();
1910 if (position == 0) { // all items deselected.
1911 _parent->hideAttachArea();
1912 this->display_no_message();
1913 _selection_on = FALSE;
1914 _parent->deactivate_default_message_menu();
1918 // if there were no selected item(s) before and now we
1919 // have one/some, we need to turn on the message menu at
1920 // the parent level.
1922 if (!_selection_on) {
1923 _selection_on = TRUE;
1924 _parent->activate_default_message_menu();
1927 // If selected message is the displayed message, return.
1928 // No need to redisplay the same message.
1930 if (position == _selected_item_position) return;
1932 // Retrieve message...
1933 // Display the selected message...
1934 _selected_item_position = position;
1936 tmpMS = get_message_struct(_selected_item_position);
1937 if (tmpMS == NULL) {
1941 display_message_summary();
1942 this->display_message(mail_error, tmpMS->message_handle);
1943 if (mail_error.isSet()) {
1951 MsgScrollingList::get_selected_item()
1953 return(_selected_item_position);
1957 MsgScrollingList::get_displayed_item()
1959 return(_displayed_item_position);
1963 MsgScrollingList::scroll_to_bottom()
1965 XmListSetBottomPos( this->baseWidget() , 0 );
1968 // Scroll the list so that the item at position is in the
1969 // middle of the scrolling list. If the number of items
1970 // that the scrolling list can display at one time is greater
1971 // than the total number of items, then display them all.
1972 // If the item at position is close to the bottom of the list
1973 // make sure we make as many items visible as possible.
1975 // If the item at position is already visible, then don't
1979 MsgScrollingList::scroll_to_position(
1983 int top, visible, total;
1986 // Determine the position of the header that we want to select.
1987 // If the XtArgCollector exists, then add
1988 // the resources to the XtArgCollector so that we can prevent
1989 // multiple redisplays in the XmList widget.
1990 if (_xmstr_collector)
1993 XmNtopItemPosition, &top,
1994 XmNvisibleItemCount, &visible,
1996 total = _xmstr_collector->GetNumItems();
2001 XmNtopItemPosition, &top,
2002 XmNvisibleItemCount, &visible,
2003 XmNitemCount, &total,
2007 if (( position < top ) || ( position >= top+visible )) {
2009 if ((total <= visible) || (position <= visible/2)) {
2010 // If we can display them all, make the first item appear
2011 // at the top of the list.
2013 } else if (position > (total-(visible/2))) {
2014 top_pos = total - visible + 1;
2016 top_pos = position - visible/2 + 1;
2019 // Determine the position of the header that we want to select.
2020 // If the XtArgCollector exists, then add
2021 // the resources to the XtArgCollector so that we can prevent
2022 // multiple redisplays in the XmList widget.
2023 if (_xtarg_collector)
2024 _xtarg_collector->AddItemToList (
2025 XmNtopItemPosition, top_pos);
2027 XmListSetPos (_w, top_pos);
2032 MsgScrollingList::undelete_messages(MsgHndArray *tmpMHlist)
2034 FORCE_SEGV_DECL(MsgStruct, tmpMS);
2035 FORCE_SEGV_DECL(XmString, deleted_headers);
2036 int i, num_entries, entry_position, del_pos;
2037 int whichToSelectDisplay = 0;
2038 DtMail::MailBox *mbox=parent()->mailbox();
2039 DtMail::Message * tmpMsg;
2040 DtMailEnv mail_error;
2041 DtMailMessageHandle tmpMH;
2043 XmString read_status, new_status;
2045 XmString complete_header; // read status + glyph + header_text.
2049 * In a mailer container window's message scrolling list, a "N" appears
2050 * to the left of a mail message header indicating that the mail message
2051 * is "new" (just arrived and not yet viewed by the user).
2052 * There is only space to display 1 character. If "N" needs to be translated,
2053 * please make sure the translation is only 1 character.
2056 // gregl - new_status and read_status are not used in this function.
2057 // either comment them out (like I'm doing) or free them.
2059 new_status = XmStringCreateLocalized(GETMSG(DT_catd, 1, 112, "N"));
2060 read_status = XmStringCreateLocalized(" ");
2063 // Initialize the mail_error.
2065 num_entries = tmpMHlist->length();
2066 if (num_entries == 0) return;
2068 // Deselect all items currently selected.
2069 // display_and_select_message() will select, highlight
2070 // and display the last "undeleted" message.
2072 XmListDeselectAllItems(_w);
2074 XtVaSetValues (_w, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);
2076 for (i = 0; i < num_entries; i++)
2078 DtMailHeaderLine info;
2080 tmpMS = tmpMHlist->at(i);
2081 tmpMS->is_deleted = FALSE;
2083 // Reset the flag of the message in message store so that the
2084 // message will not be expunged when the folder is quit.
2087 tmpMsg = mbox->getMessage(mail_error, tmpMS->message_handle);
2088 tmpMsg->resetFlag(mail_error, DtMailMessageDeletePending);
2089 tmpMH = tmpMS->message_handle;
2091 // Remove chosen item from list of deleted messages;
2092 // insert it back into _msgs at the right place (which is
2093 // determined by session_number of retrieved MsgStruct).
2094 // Insert back into scrolling list for visual display
2095 // at the position session_number.
2097 entry_position = _msgs->insert(tmpMS);
2099 // Increment by one, because the index into the scrolling
2100 // list is always one greater than the index into the
2101 // message handle array that we got the index from.
2103 entry_position = entry_position + 1;
2105 // Maintain the assumption that the item at entry_position
2106 // is the selected item
2108 _selected_item_position = entry_position;
2110 mbox->getMessageSummary(mail_error, tmpMS->message_handle,
2111 _header_info, info);
2112 DtMail::Message * msg = mbox->getMessage(mail_error, tmpMH);
2113 complete_header = formatHeader(
2116 show_with_attachments(msg),
2117 msg->flagIsSet(mail_error, DtMailMessageNew));
2119 mbox->clearMessageSummary(info);
2121 if (msg->flagIsSet(mail_error, DtMailMessageNew) == DTM_TRUE)
2124 XmListAddItem(_w, complete_header, entry_position);
2125 XmListSelectItem(_w, complete_header, FALSE);
2126 XmStringFree(complete_header);
2128 // Get position of undeleted message structure in _deleted_messages
2129 // and remove the entry from _deleted_messages
2131 del_pos = _deleted_messages->indexof(tmpMS);
2132 _deleted_messages->remove_entry(del_pos);
2135 // Display this message and select it.
2137 this->display_message(mail_error, tmpMS->message_handle);
2138 XtVaSetValues (_w, XmNselectionPolicy, XmEXTENDED_SELECT, NULL);
2139 XtVaSetValues (_w, XmNselectionMode, XmNORMAL_MODE, NULL);
2141 if (mail_error.isSet()) return;
2143 num_deleted_messages -= num_entries;
2145 MsgHndArray *selected_messages = selected();
2146 updateListItems(-1, TRUE, selected_messages);
2147 delete selected_messages;
2149 display_message_summary();
2153 MsgScrollingList::undelete_last_deleted()
2155 FORCE_SEGV_DECL(MsgStruct, tmpMS);
2158 DtMail::MailBox *mbox=parent()->mailbox();
2159 UndelFromListDialog *undel_dialog;
2160 DtMailEnv mail_error;
2161 DtMailHeaderLine info;
2162 DtMail::Message * tmpMsg;
2163 DtMailMessageHandle tmpMH;
2165 XmString read_status, new_status;
2167 XmString complete_header; // read status + glyph + header_text.
2171 * In a mailer container window's message scrolling list, a "N" appears
2172 * to the left of a mail message header indicating that the mail message
2173 * is "new" (just arrived and not yet viewed by the user).
2174 * There is only space to display 1 character. If "N" needs to be translated,
2175 * please make sure the translation is only 1 character.
2177 new_status = XmStringCreateLocalized(GETMSG(DT_catd, 1, 113, "N"));
2178 read_status = XmStringCreateLocalized(" ");
2182 if (num_deleted_messages == 0) return;
2184 // Initialize the mail_error.
2188 // Delete the message from the Deleted Messages Dialog.
2189 undel_dialog = parent()->get_undel_dialog();
2191 undel_dialog->undelLast();
2193 // Restore the message in RoamMenuWindow:MessageScrollingList.
2194 len = _deleted_messages->length();
2196 tmpMS = _deleted_messages->at(len - 1);
2197 tmpMS->is_deleted = FALSE;
2199 // Reset the flag of the message in message store so that the
2200 // message will not be expunged when the folder is quit.
2203 tmpMsg = mbox->getMessage(mail_error, tmpMS->message_handle);
2204 tmpMsg->resetFlag(mail_error, DtMailMessageDeletePending);
2205 tmpMH = tmpMS->message_handle;
2207 // Remove chosen item from list of deleted messages;
2208 // insert it back into _msgs at the right place (which is
2209 // determined by session_number of retrieved MsgStruct).
2210 // Insert back into scrolling list for visual display
2211 // at the position session_number.
2213 entry_position = _msgs->insert(tmpMS);
2215 // Increment by one, because the index into the scrolling
2216 // list is always greater than the index into the
2217 // message handle array that we got the index from.
2219 entry_position = entry_position + 1;
2221 mbox->getMessageSummary(mail_error, tmpMS->message_handle,
2222 _header_info, info);
2223 DtMail::Message * msg = mbox->getMessage(mail_error, tmpMH);
2225 complete_header = formatHeader(
2228 show_with_attachments(msg),
2229 msg->flagIsSet(mail_error, DtMailMessageNew));
2231 mbox->clearMessageSummary(info);
2233 if (msg->flagIsSet(mail_error, DtMailMessageNew) == DTM_TRUE) {
2237 _deleted_messages->remove_entry(len - 1);
2238 num_deleted_messages--;
2239 XmListAddItemUnselected(_w, complete_header, entry_position);
2240 XmStringFree(complete_header);
2243 // If the undeleted message is before the currently viewed message,
2244 // then need to readjust our numbers by adding one to them -- there
2245 // is one more message above the currently-viewed message.
2246 // Don't need to do anything if the undeleted message is after the
2247 // currently-viewed message.
2250 // Deselect all items currently selected.
2251 // display_and_select_message() will select, highlight
2252 // and display the last "undeleted" message.
2254 XmListDeselectAllItems(_w);
2256 _selected_item_position = entry_position;
2257 this->display_and_select_message(mail_error, tmpMS->message_handle);
2258 if (mail_error.isSet()) return;
2260 updateListItems(-1, TRUE, NULL);
2261 display_message_summary();
2265 MsgScrollingList::senderIsToHeaderWhenMailFromMe(void)
2267 if (_header_info.number_of_names == 5)
2274 MsgScrollingList::checkDisplayProp(void)
2276 DtMail::MailBox * mbox;
2277 DtMail::MailRc * mailrc;
2278 DtMailEnv mail_error;
2279 Boolean state_changed = FALSE;
2281 mbox = parent()->mailbox();
2282 mailrc = mbox->session()->mailRc(mail_error);
2284 const char * value = NULL;
2285 mailrc->getValue(mail_error, "showto", &value);
2286 if (mail_error.isNotSet()) {
2287 // showto is set...if number_of_names is 4 then they
2288 // just applied props and the showto value
2289 if (_header_info.number_of_names == 4) {
2290 _header_info.number_of_names = 5;
2291 state_changed = TRUE;
2294 else if (_header_info.number_of_names == 5) {
2295 // They just applied props and changed the showto value
2296 _header_info.number_of_names = 4;
2297 state_changed = TRUE;
2300 free((void*) value);
2302 // Here we need to adjust the header labels to maintain them left
2303 // justified. It looks better than centered. We only whant to change
2304 // the labels if message numbering has been enabled. Otherwise we will
2305 // leave them alone. Note: The _numbered stores the previous state for
2306 // message numbering. Check the error return when getting the value uses
2307 // reverse logic. ugly...
2308 DtMailBoolean use_msg_numbers;
2312 mailrc->getValue(mail_error, "showmsgnum", &value);
2314 use_msg_numbers = (mail_error.isNotSet()) ? DTM_TRUE : DTM_FALSE;
2315 if (NULL != value) free((void*) value);
2317 if (use_msg_numbers != _numbered)
2319 _numbered = use_msg_numbers;
2320 layoutLabels(_sender_lbl, _subject_lbl, _date_lbl, _size_lbl);
2322 else if (!state_changed) return;
2324 // We have to build two lists from the current normal and deleted
2325 // lists. These will contain the new header lines.
2327 DtMailHeaderLine info;
2328 XmString * normal_list = new XmString[_msgs->length()];
2330 for (int m = 0; m < _msgs->length(); m++) {
2331 MsgStruct * ms = _msgs->at(m);
2333 DtMail::Message * msg =
2334 mbox->getMessage(mail_error, ms->message_handle);
2335 mbox->getMessageSummary(
2336 mail_error, ms->message_handle,
2337 _header_info, info);
2338 normal_list[m] = formatHeader(
2341 show_with_attachments(msg),
2342 msg->flagIsSet(mail_error, DtMailMessageNew));
2343 mbox->clearMessageSummary(info);
2346 XmListReplaceItemsPos(_w, normal_list, _msgs->length(), 1);
2347 for (int fr = 0; fr < _msgs->length(); fr++) {
2348 XmStringFree(normal_list[fr]);
2352 UndelFromListDialog * del_dialog = _parent->get_undel_dialog();
2354 XmString * del_list = new XmString[_deleted_messages->length()];
2356 for (int m2 = 0; m2 < _deleted_messages->length(); m2++) {
2357 MsgStruct * ms = _deleted_messages->at(m2);
2359 DtMail::Message * msg =
2360 mbox->getMessage(mail_error, ms->message_handle);
2361 mbox->getMessageSummary(
2362 mail_error, ms->message_handle,
2363 _header_info, info);
2364 del_list[m2] = formatHeader(
2367 show_with_attachments(msg),
2368 msg->flagIsSet(mail_error, DtMailMessageNew));
2369 mbox->clearMessageSummary(info);
2372 del_dialog->replaceItems(del_list, _deleted_messages->length());
2373 for (int fr2 = 0; fr2 < _deleted_messages->length(); fr2++) {
2374 XmStringFree(del_list[fr2]);
2381 // Update the scrolling list. Current is the index of the message
2382 // to position the scrolling list to. -1 to keep it as is.
2385 MsgScrollingList::updateListItems(int current,
2386 Boolean renumber_only,
2387 MsgHndArray *selected_messages)
2389 DtMail::MailBox * mbox = NULL;
2390 DtMail::MailRc * mailrc;
2391 DtMailEnv mail_error;
2392 const char * value = NULL;
2395 mbox = parent()->mailbox();
2396 mailrc = mbox->session()->mailRc(mail_error);
2398 if (current < 0) current = _displayed_item_position;
2401 mailrc->getValue(mail_error, "showmsgnum", &value);
2402 if (mail_error.isSet() && renumber_only) return;
2404 if (selected_messages)
2405 XtVaSetValues (_w, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);
2408 // We need to build a new list of strings to display
2409 // in the scrolling list. Initialize that now.
2411 DtMailHeaderLine info;
2415 nmsgs = _msgs->length();
2416 newList = new XmString[nmsgs];
2417 memset (newList, '0', nmsgs * sizeof (XmString *));
2419 // Loop through _msgs and create new strings to display in the
2420 // scrolling list. This is inefficient and dominates the time
2421 // spent in sort. It may be worth while finding a way to just
2422 // rearrange the existing strings.
2423 for (int m = 0; m < nmsgs; m++)
2425 DtMail::Message * msg = mbox->getMessage(mail_error,
2426 _msgs->at(m)->message_handle);
2428 if (mail_error.isSet())
2429 fprintf(stderr, "dtmail: getMessage: Couldn't get message #%d\n", m);
2431 mbox->getMessageSummary(
2432 mail_error, _msgs->at(m)->message_handle,
2433 _header_info, info);
2435 if (mail_error.isSet())
2437 "dtmail: getMessageSummary: Couldn't get summary for msg # %d\n", m);
2439 if ((msg == NULL) || (mbox == NULL))
2446 ms = get_message_struct(m + 1);
2451 show_with_attachments(msg),
2452 msg->flagIsSet(mail_error, DtMailMessageNew));
2455 // Free the space allocated for info
2456 // delete []info.header_values;
2457 mbox->clearMessageSummary(info);
2460 XmListReplaceItemsPos(_w, newList, session_message_number, 1);
2461 for (int fr = 0; fr < nmsgs; fr++)
2462 XmStringFree(newList[fr]);
2464 // Update current message
2465 _selected_item_position = current;
2466 _displayed_item_position = current;
2467 scroll_to_position(_displayed_item_position);
2469 if (selected_messages)
2471 XmListDeselectAllItems(_w);
2472 for (int m=0, nselected=selected_messages->length(); m<nmsgs; m++)
2474 MsgStruct *ms = get_message_struct(m+1);
2475 for (int s=0; s<nselected; s++)
2477 MsgStruct *sms = selected_messages->at(s);
2479 XmListSelectPos(_w, m+1, FALSE);
2482 XtVaSetValues (_w, XmNselectionPolicy, XmEXTENDED_SELECT, NULL);
2485 XmListSelectPos(_w, _displayed_item_position, FALSE);
2487 XtVaSetValues (_w, XmNselectionPolicy, XmEXTENDED_SELECT, NULL);
2488 XtVaSetValues (_w, XmNselectionMode, XmNORMAL_MODE, NULL);
2493 MsgScrollingList::formatHeader(DtMailHeaderLine & info,
2495 DtMailBoolean has_attachments,
2496 DtMailBoolean new_msg)
2498 char *buf = new char[BUFSIZ];
2499 memset(buf, 0, BUFSIZ);
2500 const char *from=NULL;
2503 char contentStr[20];
2504 char *date = new char[BUFSIZ];
2505 int msg_num = sess_num + 1;
2506 static XmString attachment_glyph = NULL;
2507 static XmString no_attachment_glyph = NULL;
2508 static XmString new_status = NULL;
2509 static XmString read_status = NULL;
2510 static unsigned char attach_symbol[16];
2511 Boolean showto = FALSE;
2513 if (!attachment_glyph) {
2514 attach_symbol[0] = 168;
2515 attach_symbol[1] = 0;
2516 attachment_glyph = XmStringCreate((char *)attach_symbol, "attach");
2517 no_attachment_glyph = XmStringCreateLocalized(" ");
2518 new_status = XmStringCreateLocalized(GETMSG(DT_catd, 1, 114, "N"));
2519 read_status = XmStringCreateLocalized(" ");
2522 // strip out the Name of sender and retain only the address.
2523 //Later, we will have separate entries for name and address
2524 //and this stripping will not need to be done.
2526 // IMAP is incapable of handling a message header that begins
2527 // with From (space) (NOTE: not a From:).
2528 // Thus, if a message has only a From but does not have a From:
2529 // or a Reply-To: or Received-From:, IMAP doesn't tell us who
2530 // it is from. In such cases, we set it to "???".
2532 DtMailAddressSeq * addr_seq = NULL;
2533 DtMailValueAddress * addr = NULL;
2535 if (info.header_values[0].length() != 0) {
2536 addr_seq = ((info.header_values[0])[0])->toAddress();
2537 addr = (*addr_seq)[0];
2538 if (_header_info.number_of_names == 5 && addr
2539 && addr->dtm_address && info.header_values[4].length() != 0) {
2540 // Check if mail is from me
2543 GetPasswordEntry(pw);
2544 if ((ptr = strchr(addr->dtm_address, '@')) != NULL) {
2545 if (strncmp(pw.pw_name, addr->dtm_address,
2546 ptr-addr->dtm_address) == 0) {
2547 from = *((info.header_values[4])[0]);
2552 if (strcmp(pw.pw_name, addr->dtm_address) == 0) {
2553 from = *((info.header_values[4])[0]);
2558 if (addr && addr->dtm_person)
2559 from = addr->dtm_person;
2560 else if (addr && addr->dtm_address)
2561 from = addr->dtm_address;
2568 // If the Subject is nil
2570 if (info.header_values[3].length() == 0) {
2571 subject = new char[1];
2574 // Get the BE store of header. It may contain newlines or
2575 // tab chars which can munge the scrolling list's display!
2577 const char *real_subj_header = *((info.header_values[3])[0]);
2582 // Check if BE store contains the funky chars.
2584 for (fc = 0, subj_len = strlen(real_subj_header),
2585 tmp_subj = (char *)real_subj_header;
2586 fc < subj_len; fc++, tmp_subj++) {
2596 subject = new char[fc+1];
2597 strncpy((char *)subject, real_subj_header, fc);
2602 // Skip the first (beginning) space in from; search for the next
2606 const char *dateformat;
2607 if (info.header_values[1].length() > 0)
2609 DtMailValueDate ds = ((info.header_values[1])[0])->toDate();
2611 if (ds.dtm_date && ds.dtm_tz_offset_secs)
2613 #define USE_YEAR_FORMAT_SECONDS (60 * 60 * 24 * 180)
2617 SafeLocaltime(&ds.dtm_date, tm_struct);
2619 // Refer to strftime man page for explanation of the date format.
2621 if (USE_YEAR_FORMAT_SECONDS < now - ds.dtm_date)
2622 dateformat = GETMSG(DT_catd, 1, 259, "%a %b %d %Y");
2627 dateformat = GETMSG(DT_catd, 1, 260, "%a %b %d %k:%M");
2629 dateformat = GETMSG(DT_catd, 1, 261, "%a %b %d %H:%M");
2633 SafeStrftime(date, BUFSIZ, dateformat, &tm_struct);
2636 // Couldn't get Date string from Message. Make it empty.
2637 sprintf(date, "%s", " ");
2642 memset(&epoch, 0, sizeof(tm));
2644 /* Refer to strftime man page for explanation of the date format. */
2645 dateformat = GETMSG(DT_catd, 1, 259, "%a %b %d %Y");
2646 SafeStrftime(date, BUFSIZ, dateformat, &epoch);
2649 if (info.header_values[2].length() > 0) {
2650 contentLength = (int) strtol(*((info.header_values[2])[0]), NULL, 10);
2656 if (contentLength < 1000) {
2657 sprintf(contentStr, "%d", contentLength);
2659 else if (contentLength < 1000000) {
2660 sprintf(contentStr, "%dK", contentLength / 1000);
2663 sprintf(contentStr, "%dM", contentLength / 1000000);
2666 // If we are to print the message_number in the header_list,
2667 // use msg_num as the first element in the sprintf.
2668 // Introduce a %d at the beginning though.
2670 DtMail::MailBox * mbox;
2671 DtMail::MailRc * mailrc;
2672 DtMailEnv mail_error;
2674 mbox = parent()->mailbox();
2675 mailrc = mbox->session()->mailRc(mail_error);
2677 const char * value = NULL;
2678 mailrc->getValue(mail_error, "showmsgnum", &value);
2679 if (mail_error.isSet()) {
2680 // No message numbers ... keep usual "35" col. "Subject".
2682 sprintf(buf, " To %-15.15s %-35.35s %-17.17s %-5.5s",
2688 sprintf(buf, " %-18.18s %-35.35s %-17.17s %-5.5s",
2695 // To keep 80 column format use 5 less columns of
2696 // subject , when msg numbers are on.
2698 sprintf(buf, " To %-15.15s %-30.30s %-17.17s %-5.5s",
2704 sprintf(buf, " %-18.18s %-30.30s %-17.17s %-5.5s",
2711 free((void*) value);
2713 XmString header_text = XmStringCreateLocalized(buf);
2714 XmString item, item2, complete_header;
2716 if (has_attachments == DTM_TRUE) {
2717 item = XmStringConcat(attachment_glyph, header_text);
2718 XmStringFree(header_text);
2721 item = XmStringConcat(no_attachment_glyph, header_text);
2722 XmStringFree(header_text);
2725 if (new_msg == DTM_FALSE) {
2726 item2 = XmStringConcat(read_status, item);
2730 item2 = XmStringConcat(new_status, item);
2735 mailrc->getValue(mail_error, "showmsgnum", &value);
2736 if (mail_error.isSet()) {
2737 // complete_header = XmStringCopy(item2);
2738 complete_header = item2;
2739 _numbered = DTM_FALSE;
2745 free((void*) value);
2747 mailrc->getValue(mail_error, "nerdmode", &value);
2748 if (mail_error.isSet()) {
2749 sprintf(num_buf, "%4d ", msg_num);
2752 sprintf(num_buf, "%4x ", msg_num - 1);
2755 XmString num_str = XmStringCreateLocalized(num_buf);
2756 complete_header = XmStringConcat(num_str, item2);
2757 XmStringFree(item2);
2758 XmStringFree(num_str);
2759 _numbered = DTM_TRUE;
2762 free((void*) value);
2769 return(complete_header);
2773 MsgScrollingList::shutdown()
2776 FORCE_SEGV_DECL(MsgStruct, tmpMS);
2777 DtMailMessageHandle tmpMH;
2778 DtMail::MailBox *mbox=parent()->mailbox();
2779 DtMailEnv mail_error;
2781 // Initialize the mail_error.
2784 if (num_deleted_messages == 0) return;
2786 num_entries = _deleted_messages->length();
2788 for (i = 0; i < num_entries; i++) {
2789 tmpMS = _deleted_messages->at(i);
2790 tmpMH = tmpMS->message_handle;
2792 // mbox->deleteMsg(mail_error, tmpMH);
2799 MsgScrollingList::lastMsg()
2801 if (_msgs->length() > 0) {
2802 return((_msgs->at(_msgs->length() - 1))->message_handle);
2804 else { // Currently an empty folder
2808 #endif /* DEAD_WOOD */
2811 MsgScrollingList::clearMsgs()
2813 if ( _msgs->length() > 0 )
2819 MsgScrollingList::display_message_summary()
2821 parent()->message_summary(
2822 selected_item_position(),
2824 get_num_new_messages(),
2825 get_num_deleted_messages());
2829 MsgScrollingList::display_message(
2830 DtMailEnv &mail_error,
2834 if ((pos > 0) && (pos <= session_message_number)) {
2835 // When loading mail headers, we need to make sure that
2836 // the XmList resources are all set at the same time to
2837 // avoid painting multiple times. So here we collect
2839 if (_xtarg_collector && _xmstr_collector)
2841 XmString *items = _xmstr_collector->GetItems();
2843 // Keep a handle to the malloced string copy so that
2844 // we can free it after the XtSetValues
2845 _selected_items = XmStringCopy (items[pos-1]);
2847 _xtarg_collector->AddItemToList (XmNselectedItems,
2848 (XtArgVal) &_selected_items);
2849 _xtarg_collector->AddItemToList (
2850 XmNselectedItemCount, 1);
2854 XmListSelectPos(_w, pos, FALSE);
2857 this->extended_selection(mail_error, pos);
2858 if (mail_error.isSet()) {
2859 // Return whatever error mailbox->get_next_msg() returned.
2867 MsgScrollingList::current_msg_handle()
2869 DtMailMessageHandle msg_number;
2871 if ( _displayed_item_position > 0 )
2872 msg_number=msgno( _displayed_item_position );
2880 MsgScrollingList::expunge(void)
2882 for (int i = _deleted_messages->length() - 1; i >= 0; i--) {
2883 _deleted_messages->remove_entry(i);
2887 num_deleted_messages = 0;
2888 display_message_summary();
2892 MsgScrollingList::resetIndexNums(void)
2895 int length = _msgs->length();
2898 for (m = 0; m < length; m++)
2901 ms->indexNumber = m;
2904 length = _deleted_messages->length();
2905 for (m = 0; m < length; m++)
2907 ms = _deleted_messages->at(m);
2908 ms->indexNumber = m;
2915 MsgScrollingList::resetSessionNums(void)
2918 int length = _msgs->length();
2921 for (m = 0; m < length; m++)
2924 ms->sessionNumber = m;
2926 session_message_number = m;
2927 return session_message_number;
2931 MsgScrollingList::sort_messages(void)
2933 DtMail::MailBox *mbox;
2937 MsgHndArray *selected_messages = selected();
2939 mbox = _parent->mailbox();
2940 sortby = _parent->last_sorted_by();
2942 // Sort array of message handles
2943 current_msg = _sorter->sortMessages(this, mbox, sortby);
2945 // The array of message handles is sorted. Now we need to update
2946 // the display preserving the selected state of the messages.
2947 updateListItems(current_msg, FALSE, selected_messages);
2949 delete selected_messages;
2951 _parent->last_sorted_by(sortby);
2952 display_message_summary();
2956 // Layout out the row of labels above the scrolling list
2959 MsgScrollingList::layoutLabels(
2965 // Save the input values
2966 _sender_lbl = sender;
2967 _subject_lbl = subject;
2975 // Layout out the row of labels above the scrolling list
2978 MsgScrollingList::layoutLabels()
2980 // Width of fields. +1 for spaces
2982 sender_width = 18 + 1,
2983 subject_width = 35 + 1,
2984 date_width = 3+1 + 3+1 + 2+1 + 5 + 2; // DDD mmm dd hh:mm 2spaces
2985 int char_width; // Width of a single character
2988 XmFontList font_list;
2990 // Calculate the width of date format to allocate the label
2991 // width dynamically
2996 clock = time((time_t *) 0);
2997 tm = localtime(&clock);
3001 GETMSG(DT_catd, 1, 222, "%a %b %d %k:%M"),
3006 GETMSG(DT_catd, 1, 223, "%a %b %d %H:%M"),
3011 // List uses a fixed width font. Therefore all characters are the
3012 // same size. So we use a space to determine the width of a char
3013 xmstr = XmStringCreateLocalized(" ");
3014 XtVaGetValues(_w, XmNfontList, &font_list, NULL);
3015 char_width = XmStringWidth(font_list, xmstr);
3020 subject_width -= num_width;
3025 // XXX dipol: Need to take into account if the scrollbar is on the
3029 XtWidgetGeometry geom;
3030 geom.request_mode = CWX;
3031 XtQueryGeometry(_sender_lbl, NULL, &geom);
3032 if (geom.x != (n * char_width)) {
3033 geom.x = (n * char_width);
3034 XtMoveWidget(_sender_lbl, geom.x, geom.y);
3035 } // Move the X location of the sender title
3037 XtVaSetValues(_sender_lbl, XmNx, n * char_width, NULL);
3040 XtQueryGeometry(_subject_lbl, NULL, &geom);
3041 if (geom.x != (n * char_width)) {
3042 geom.x = (n * char_width);
3043 XtMoveWidget(_subject_lbl, geom.x, geom.y);
3044 } // Move the X location of the subject title
3046 XtVaSetValues(_subject_lbl, XmNx, n * char_width, NULL);
3048 XtVaSetValues(_date_lbl, XmNx, n * char_width, NULL);
3050 XtVaSetValues(_size_lbl, XmNx, n * char_width, NULL);
3052 XmStringFree(xmstr);