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: SendMsgDialog.C /main/43 1999/03/25 13:42:29 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, 1994, 1995 Sun Microsystems, Inc. All rights reserved.
43 #include <EUSCompat.h>
44 #include "AttachArea.h"
45 #include "Attachment.h"
47 #include "SendMsgDialog.h"
50 #include "ComposeCmds.hh"
53 #include "ButtonInterface.h"
54 #include "MemUtils.hh"
56 #include "DtMailHelp.hh"
57 #include "SelectFileCmd.h"
58 #include "DtMailGenDialog.hh"
59 #include "Application.h"
60 #include <X11/Intrinsic.h>
61 #include <X11/IntrinsicP.h>
62 #include <Xm/RepType.h>
63 #include <Xm/ScrolledW.h>
68 #include <Xm/RowColumn.h>
70 #include <Xm/CascadeB.h>
71 #include <Xm/SeparatoG.h>
72 #include <DtMail/IO.hh>
73 #include <DtMail/DtMailP.hh>
76 #include <sys/param.h>
82 #include "str_utils.h"
84 #define OFFSET 10 // Number of spaces from margin
86 #ifdef DTMAIL_TOOLTALK
87 // Time to self destruct
88 #define DESTRUCT_TIMEOUT 60000 // 1 minutes
91 // Pipe used between RFCTransport::childHandler and XtAppAddInput
92 static int _transfds[2];
94 static const char *ComposeIcon = "IcMcomp";
96 struct DefaultHeaders {
102 SendMsgDialog::ShowState show;
105 static int isInitializedDefaultHeaderList = 0;
106 static DefaultHeaders DefaultHeaderList[] = {
107 { 1, 241, "To", NULL, DtMailMessageTo, SendMsgDialog::SMD_ALWAYS },
108 { 1, 242, "Subject", NULL, DtMailMessageSubject, SendMsgDialog::SMD_ALWAYS },
109 { 1, 243, "Cc", NULL, DtMailMessageCc, SendMsgDialog::SMD_ALWAYS },
110 { 1, 244, "Bcc", NULL, DtMailMessageBcc, SendMsgDialog::SMD_HIDDEN },
111 { 0, 0, NULL, NULL, NULL, SendMsgDialog::SMD_NEVER }
114 // These headers can never be controlled by the user. They are generated
115 // by dtmail and the user is not allowed to override the values generated
116 // by the software. Besides, most users would not have a clue as to what
117 // a correct value would be.
119 static const char * BlockedHeaders[] = {
123 "Content-Transfer-Encoding",
131 block(const char * header)
133 for (const char ** test = BlockedHeaders; *test; test++) {
134 if (strcasecmp(header, *test) == 0) {
144 Compose theCompose; // Manages all compose windows.
146 SendMsgDialog::HeaderList::HeaderList(void)
157 SendMsgDialog::HeaderList::HeaderList(const HeaderList & other)
162 form_widget = other.form_widget;
163 label_widget = other.label_widget;
164 field_widget = other.field_widget;
167 label = strdup(other.label);
171 header = strdup(other.header);
175 value = strdup(other.value);
179 SendMsgDialog::HeaderList::~HeaderList(void)
193 Boolean SendMsgDialog::reservedHeader(const char *label)
195 for (DefaultHeaders * hl = DefaultHeaderList; hl->dflt_label; hl++)
196 if (strcmp(label, hl->label) == 0)
202 SendMsgDialog::SendMsgDialog()
203 : MenuWindow ( "ComposeDialog", True ),
210 _show_attach_area = FALSE;
213 _already_sending = FALSE;
219 _bccPopupCmdlist = NULL;
220 _bccPopupMenu = NULL;
221 _bccPopupMenuBar = NULL;
222 _ccPopupCmdlist = NULL;
224 _ccPopupMenuBar = NULL;
225 _toPopupCmdlist = NULL;
227 _toPopupMenuBar = NULL;
230 _attachmentActionsList = NULL;
231 _attachmentMenu = NULL;
232 _attachmentMenuList = NULL;
233 _attachmentPopupMenuList = NULL;
234 _textPopupMenuList = NULL;
236 _att_show_pane = NULL;
237 _att_select_all = NULL;
241 _att_undelete = NULL;
243 _att_select_all = NULL;
244 _auto_save_interval = 0;
245 _auto_save_path = NULL;
246 _auto_save_file = NULL;
247 _dead_letter_buf = NULL;
249 _file_include = NULL;
250 _file_save_as = NULL;
255 _format_word_wrap = NULL;
256 _format_settings = NULL;
257 _format_find_change = NULL;
258 _format_spell = NULL;
261 _format_cascade = NULL;
262 _format_separator = NULL;
263 _templateList = NULL;
265 // Now we need to get the additional headers from the property system.
268 DtMail::Session * d_session = theRoamApp.session()->session();
269 DtMail::MailRc * mail_rc = d_session->mailRc(error);
271 const char * value = NULL;
272 mail_rc->getValue(error, "additionalfields", &value);
274 DtVirtArray<PropStringPair *> results(8);
275 if (error.isNotSet()) {
276 _additionalfields = strdup(value);
277 parsePropString(value, results);
283 // Load the header list with the predefined/fixed headers.
285 if (! isInitializedDefaultHeaderList)
286 for (DefaultHeaders * hl = DefaultHeaderList; hl->dflt_label; hl++) {
288 GETMSG(DT_catd, hl->msg_set, hl->msg_number, hl->dflt_label);
290 isInitializedDefaultHeaderList = TRUE;
293 for (DefaultHeaders * hl = DefaultHeaderList; hl->dflt_label; hl++) {
294 HeaderList * copy_hl = new HeaderList;
295 copy_hl->label = strdup(hl->label);
296 copy_hl->value = getPropStringValue(results, hl->label);
297 copy_hl->header = strdup(hl->header);
298 copy_hl->show = hl->show;
299 _header_list.append(copy_hl);
302 if (error.isNotSet()) {
304 for (int mrc = 0; mrc < results.length(); mrc++) {
305 PropStringPair * psp = results[mrc];
307 if (!reservedHeader(psp->label)) {
308 HeaderList * copy_hl = new HeaderList;
309 copy_hl->label = strdup(psp->label);
310 copy_hl->header = strdup(psp->label);
312 copy_hl->value = strdup(psp->value);
313 copy_hl->show = SMD_HIDDEN;
314 _header_list.append(copy_hl);
318 while(results.length()) {
319 PropStringPair * psp = results[0];
325 _additionalfields = NULL;
329 SendMsgDialog::~SendMsgDialog()
337 delete _file_include;
338 delete _file_save_as;
351 delete _edit_select_all;
357 XtDestroyWidget(_ccPopupMenu);
358 delete _ccPopupMenuBar;
359 delete _ccPopupCmdlist;
361 XtDestroyWidget(_toPopupMenu);
362 delete _toPopupMenuBar;
363 delete _toPopupCmdlist;
365 XtDestroyWidget(_bccPopupMenu);
366 delete _bccPopupMenuBar;
367 delete _bccPopupCmdlist;
374 delete _att_undelete;
376 delete _att_select_all;
378 delete _attachmentActionsList;
382 delete _format_word_wrap;
383 delete _format_settings;
384 delete _format_find_change;
385 delete _format_spell;
386 delete _format_separator;
388 // Things created by createWorkArea()
391 delete _close_button;
394 // Allocated using 'malloc'.
395 // Purify requires us to free it using 'free'.
397 free(_auto_save_path);
398 if (_auto_save_file) {
399 delete _auto_save_file;
401 if (_dead_letter_buf) {
402 delete _dead_letter_buf;
405 delete _attachmentMenuList;
406 delete _attachmentPopupMenuList;
407 delete _textPopupMenuList;
411 // Callback for each header row
413 header_form_traverse(Widget w, XtPointer, XtPointer)
415 (void) XmProcessTraversal(w, XmTRAVERSE_NEXT_TAB_GROUP);
420 send_pushb_callback(Widget, XtPointer, XtPointer)
424 #endif /* DEAD_WOOD */
426 // Create Message Handle with empty first body part.
428 SendMsgDialog::makeMessage(void)
431 DtMail::Session * d_session = theRoamApp.session()->session();
437 DtMail::Message * msg = d_session->messageConstruct(error,
443 if (error.isSet() || !msg) {
447 DtMail::BodyPart * bp = msg->newBodyPart(error, NULL);
449 // For now, reserve the first body part for text.
450 setFirstBPHandled(TRUE);
455 // Before Submitting, call this routine.
456 // This routine does not save attachment(s).
457 // Check point routine should also call this routine.
459 SendMsgDialog::updateMsgHnd()
462 DtMail::Envelope * env;
465 env = _msgHandle->getEnvelope(error);
468 char * widget_text = this->text();
469 if (widget_text && *widget_text == '\0') {
475 textLen = strlen(widget_text);
477 // Even if textlen is 0 because user has cleared all previous text,
478 // need to setContents again to clear first BP. Otherwise, deleted
479 // text will show up.
481 // Get FirstBodyPart and fill it up.
482 DtMail::BodyPart *bp = _msgHandle->getFirstBodyPart(error);
483 bp->setContents(error, widget_text, textLen, NULL, NULL, 0, NULL);
484 setFirstBPHandled(TRUE);
486 if (NULL != widget_text)
490 // Before Submitting, also call this routine.
491 // This routine fills the message handle with attachment(s).
492 // The reason why we get attachment(s) from the Back End before submission
493 // is in case the attachment(s) are updated during the compose session.
494 // If changes are saved back, then the AttachArea class would register the
495 // update with Back End. So BE always has the latest attachments.
497 SendMsgDialog::updateMsgHndAtt()
499 if ( _inclMsgHandle == NULL )
500 return; // No attachments
503 DtMail::BodyPart *msgBP;
504 DtMail::BodyPart *inclBP = _inclMsgHandle->getFirstBodyPart(error);
505 const void *contents;
512 // If message handle to be copied, _inclMsgHandle, does not have its first
513 // body part as text, then get its first body part content and copy it.
514 // If it contains text, then skip it.
515 if ( !_inclMsgHasText ) {
516 inclBP->getContents(error, &contents, &len, &type, &name, &mode, &desc);
517 if ( _firstBPHandled ) {
518 msgBP = _msgHandle->newBodyPart(error, _lastAttBP);
520 msgBP = _msgHandle->getFirstBodyPart(error);
522 msgBP->setContents(error, contents, len, type, name, mode, desc);
528 // Continue to get the next body part and start copy.
529 while ((inclBP = _inclMsgHandle->getNextBodyPart(error, inclBP)) != NULL) {
530 inclBP->getContents(error, &contents, &len, &type, &name, &mode, &desc);
531 if ( _firstBPHandled ) {
532 msgBP = _msgHandle->newBodyPart(error, _lastAttBP);
534 msgBP = _msgHandle->getFirstBodyPart(error);
536 msgBP->setContents(error, contents, len, type, name, mode, desc);
540 } // end of while loop
543 // Update the _lastAttBP pointer so that subsequent newBodyPart() calls can
544 // return a message body part following the last body part.
546 SendMsgDialog::setLastAttBP()
549 _lastAttBP = _msgHandle->getNextBodyPart(error, _lastAttBP);
552 // This sister routine is needed when _lastAttBP has not been initialized.
554 SendMsgDialog::setLastAttBP(DtMail::BodyPart *bp)
559 // Initialize _msgHandle
561 SendMsgDialog::setMsgHnd()
563 _msgHandle = makeMessage();
564 _inclMsgHandle = NULL;
565 _inclMsgHasText = FALSE;
569 // Set timeout to ten minutes (as milliseconds)
572 SendMsgDialog::startAutoSave(void)
575 if(!_auto_save_path) return;
576 _auto_save_interval = XtAppAddTimeOut(theApplication->appContext(),
577 getAutoSaveInterval(),
583 SendMsgDialog::stopAutoSave(void)
585 if (!_auto_save_interval) {
589 XtRemoveTimeOut(_auto_save_interval);
590 _auto_save_interval = 0;
592 unlink(_auto_save_file);
593 free(_auto_save_file);
594 _auto_save_file = NULL;
597 static const char * DEAD_LETTER_DIR = "~/dead_letter";
598 static const char * BACKUP_DEAD_LETTER = "./dead_letter";
599 static const char * PREFIX = "mail.dead.letter";
602 SendMsgDialog::mkAutoSavePath(void)
604 // First, see if we need to set up the path.
607 if (!_auto_save_path) {
608 DtMail::Session * d_session = theRoamApp.session()->session();
610 const char *save_path = NULL;
612 d_session->mailRc(error)->getValue(error, "deaddir", &save_path);
613 if (error.isNotSet() && save_path != NULL && *save_path != '\0')
614 _auto_save_path = d_session->expandPath(error, save_path);
617 _auto_save_path = d_session->expandPath(error, DEAD_LETTER_DIR);
618 if (!_auto_save_path)
619 _auto_save_path = d_session->expandPath(error, BACKUP_DEAD_LETTER);
622 if (NULL != save_path)
623 free((void*) save_path);
626 // If we still have a path, punt.
628 if (!_auto_save_path) {
632 if (SafeAccess(_auto_save_path, W_OK) != 0) {
633 if (errno != ENOENT) {
634 // Not an error we can overcome here.
636 free(_auto_save_path);
637 _auto_save_path = NULL;
641 if (mkdir(_auto_save_path, 0700) < 0) {
642 free(_auto_save_path);
643 _auto_save_path = NULL;
648 // Now we run through the possible file names until we hit pay dirt.
650 _auto_save_file = (char*) malloc((size_t) strlen(_auto_save_path) + 100);
651 for (int suffix = 1; ; suffix++) {
652 sprintf(_auto_save_file, "%s/%s.%d", _auto_save_path, PREFIX, suffix);
653 if (SafeAccess(_auto_save_file, F_OK) != 0) {
660 SendMsgDialog::loadDeadLetter(const char * path)
662 _auto_save_file = strdup(path);
665 _auto_save_interval = XtAppAddTimeOut(theApplication->appContext(),
666 getAutoSaveInterval(),
672 SendMsgDialog::autoSaveCallback(XtPointer client_data, XtIntervalId * id)
674 SendMsgDialog * self = (SendMsgDialog *)client_data;
676 if (self->_auto_save_interval != *id) {
677 // Random noise. Ignore it.
683 self->_auto_save_interval = XtAppAddTimeOut(theApplication->appContext(),
684 self->getAutoSaveInterval(),
690 SendMsgDialog::doAutoSave(char *filename)
692 DtMail::Session * d_session = theRoamApp.session()->session();
696 setStatus(GETMSG(DT_catd, 3, 70, "Writing dead letter..."));
700 assert((NULL != filename));
701 RFCWriteMessage(error, d_session, filename, _msgHandle);
702 if((DTMailError_t) error == DTME_OutOfSpace )
704 RoamMenuWindow::ShowErrMsg((char *)error.getClient(),TRUE,this );
711 SendMsgDialog::doAutoSave(void)
713 doAutoSave(_auto_save_file);
717 SendMsgDialog::getAutoSaveInterval(void)
720 // Initialize the mail_error.
724 DtMail::Session * d_session = theRoamApp.session()->session();
725 DtMail::MailRc * mail_rc = d_session->mailRc(error);
728 const char * value = NULL;
729 mail_rc->getValue(error, "composeinterval", &value);
730 if (error.isSet() || value == NULL) {
731 save_interval = 10 * 60 * 1000; // 10 minutes
734 save_interval = (int) strtol(value, NULL, 10) * 60 * 1000;
735 save_interval = (save_interval <= 0) ? 10 * 60 * 1000 : save_interval;
740 return(save_interval);
744 SendMsgDialog::setInclMsgHnd(DtMail::Message *msg, Boolean text)
746 _inclMsgHandle = msg;
747 _inclMsgHasText = text;
751 SendMsgDialog::setFirstBPHandled(Boolean handle)
753 _firstBPHandled = handle;
757 SendMsgDialog::setHeader(const char * name, const char * value)
759 // See if this header is in the list. If so, set the widget for
762 int slot = lookupHeader(name);
767 HeaderList * hl = _header_list[slot];
768 if (hl->show == SMD_NEVER) {
769 // The user removed this header via props.
774 if (hl->field_widget) {
775 XtVaSetValues(hl->field_widget,
778 if (hl->show == SMD_HIDDEN) {
779 changeHeaderState(name);
785 SendMsgDialog::setHeader(const char * name, DtMailValueSeq & value)
787 if (value.length() == 0) {
791 if (value.length() == 1) {
792 setHeader(name, *(value[0]));
796 for (int slen = 0; slen < value.length(); slen++) {
797 max_len += strlen(*(value[slen]));
800 char * new_str = new char[max_len + (value.length() * 3)];
803 for (int copy = 0; copy < value.length(); copy++) {
805 strcat(new_str, " ");
808 strcat(new_str, *(value[copy]));
811 setHeader(name, new_str);
817 SendMsgDialog::loadHeaders(DtMail::Message * input,
818 DtMailBoolean load_all)
820 // We are going to go through every header in the message.
821 // If it is not one of the headers we block, then we will
822 // load it into the header pane, depending on the setting of
823 // load_all. If true, then we load every header we allow and
824 // create new dynamic headers as necessary. If load_all is false,
825 // then we only load headers that already are available in the
829 DtMail::Message * msg = (input ? input : _msgHandle);
830 DtMail::Envelope * env = msg->getEnvelope(error);
831 DtMailHeaderHandle hnd;
835 DtMailValueSeq value;
837 for (hnd = env->getFirstHeader(error, &name, value);
838 error.isNotSet() && hnd;
839 hnd = env->getNextHeader(error, hnd, &name, value)) {
841 // Always ignore the Unix from line.
844 strcmp(name, "From") == 0) {
853 // See if the name is one we always block.
861 int slot = lookupHeader(name);
863 // We dont have a place for this information. We may need
864 // to create a new header.
867 HeaderList *hl = new HeaderList;
868 hl->label = strdup(name);
869 hl->header = strdup(name);
870 hl->show = SMD_HIDDEN;
871 _header_list.append(hl);
872 createHeaders(_header_form);
873 doDynamicHeaderMenus();
882 setHeader(name, value);
889 SendMsgDialog::storeHeaders(DtMail::Message * input)
891 DtMail::Message * msg = (input ? input : _msgHandle);
893 DtMail::Envelope * env = msg->getEnvelope(error);
895 // Walk through the headers. Fetch the strings from the ones
896 // that are visible to the user and stuff them into the
899 for (int scan = 0; scan < _header_list.length(); scan++) {
900 HeaderList * hl = _header_list[scan];
901 if (hl->show != SMD_ALWAYS && hl->show != SMD_SHOWN) {
906 XtVaGetValues(hl->field_widget,
909 // If the header has a value, we want to set the value
910 // in the back end. Otherwise, we don't want to send
911 // out a blank header, so we remove it.
912 if (strlen(value) > 0) {
913 env->setHeader(error, hl->header, DTM_TRUE, value);
916 env->removeHeader(error, hl->header);
923 SendMsgDialog::changeHeaderState(const char * name)
925 int slot = lookupHeader(name);
930 HeaderList * hl = _header_list[slot];
931 if (hl->show == SMD_ALWAYS || hl->show == SMD_NEVER) {
935 // If the user is trying to remove a header with a value other than
936 // the default, we should at least ask.
938 if (hl->show == SMD_SHOWN) {
940 XtVaGetValues(hl->field_widget,
943 if (strlen(value) > 0) {
944 if (!hl->value || strcmp(value, hl->value) != 0) {
945 char *buf = new char[256];
947 GETMSG(DT_catd, 2, 17,
948 "You have edited \"%s\". Delete anyway?"),
950 _genDialog->setToWarningDialog(GETMSG(DT_catd, 3, 71,
953 char * helpId = DTMAILHELPERROR;
954 int answer = _genDialog->post_and_return(
955 GETMSG(DT_catd, 3, 72, "OK"),
956 GETMSG(DT_catd, 3, 73, "Cancel"),
969 // Now we need to toggle the current state of the header.
971 char *label = new char[100];
972 if (hl->show == SMD_SHOWN) {
973 XtUnmanageChild(hl->form_widget);
974 hl->show = SMD_HIDDEN;
975 sprintf(label, "%s ", GETMSG(DT_catd, 1, 228, "Add"));
979 XtManageChild(hl->form_widget);
980 hl->show = SMD_SHOWN;
981 sprintf(label, "%s ", GETMSG(DT_catd, 1, 229, "Delete"));
987 // Change the label on the menu item.
989 strcat(label, hl->label);
991 char *button_name = new char[100];
992 sprintf(button_name, "%s ", GETMSG(DT_catd, 1, 228, "Add"));
993 strcat(button_name, hl->label);
994 strcat(button_name, ":");
996 _menuBar->changeLabel(_format_menu, button_name, label);
998 delete [] button_name;
1002 SendMsgDialog::setStatus(const char * str)
1004 char *tmpstr = strdup(str);
1005 XmString label = XmStringCreateLocalized(tmpstr);
1007 XtVaSetValues(_status_text,
1008 XmNlabelString, label,
1011 XmUpdateDisplay(baseWidget());
1012 XmStringFree(label);
1017 SendMsgDialog::clearStatus(void)
1023 SendMsgDialog::isMsgValid(void)
1032 // Sendmail is exed'd and this parent process returns immediately. When
1033 // the sendmail child exits, this function is called with the pid of the
1034 // child and its status.
1036 SendMsgDialog::sendmailErrorProc (int, int status, void *data)
1038 SendMsgDialog *smd = (SendMsgDialog *)data;
1039 char *helpId = NULL;
1040 char *buf = new char[2048];
1042 smd->_first_time = TRUE;
1043 smd->_takeDown = FALSE;
1045 // pid is the child process (sendmail) id
1046 // status is the exit status of the child process
1047 // data is any extra data associated with the child process
1051 // The mail was successfully sent so return the compose
1052 // window to the cache and then return.
1053 smd->_send_button->activate();
1054 smd->_close_button->activate();
1058 case DTME_BadMailAddress:
1060 * There was an error in one or more of the email addresses.
1061 * Ask the user to type in a valid address and try again.
1063 sprintf(buf, "%s", GETMSG(DT_catd, 5, 5,
1064 "Some of the addresses in the message are incorrect,\n\
1065 and do not refer to any known users in the system.\n\
1066 Please make sure all of the addresses are valid and try again."));
1067 helpId = DTMAILHELPBADADDRESS;
1073 * Mailer ran out of memory. Ask the user to quit some other
1074 * applications so there will be more memory available.
1077 sprintf(buf, "%s", GETMSG(DT_catd, 5, 6,
1078 "Mailer does not have enough memory\n\
1079 available to send this message.\n\
1080 Try quitting other applications and\n\
1081 resend this message."));
1082 helpId = DTMAILHELPNOMEMORY;
1086 case DTME_TransportFailed:
1089 * There was an error from the mail transport (sendmail).
1092 sprintf(buf, "%s", GETMSG(DT_catd, 5, 7,
1093 "An error occurred while trying to send your message.\n\
1094 Check to make sure the message was received. If not,\n\
1095 you may have to resend this message."));
1096 helpId = DTMAILHELPTRANSPORTFAILED;
1099 // popup the compose window
1101 smd->_send_button->activate();
1102 smd->_close_button->activate();
1104 // popup the error dialog
1105 smd->_genDialog->setToErrorDialog(GETMSG(DT_catd, 2, 21, "Mailer"),
1107 smd->_genDialog->post_and_return(GETMSG(DT_catd, 3, 76, "OK"), helpId);
1113 SendMsgDialog::send_message(const char * trans_impl, int trans_type)
1115 DtMailEnv mail_exec_error;
1116 DtMailOperationId id;
1117 DtMail::Transport * mail_transport;
1118 DtMail::Session * d_session = theRoamApp.session()->session();
1119 DtMailEditor *editor = this->get_editor();
1120 AttachArea *attachArea = editor->attachArea();
1121 int numPendingActions, answer;
1122 char *helpId = NULL;
1123 char *buf = new char[2048];
1124 static int first_time = 1;
1127 // Check to see if we are already trying to send from this
1128 // SendMsgDialog. If we are, we don't want to do it again.
1129 if (_already_sending) {
1133 _already_sending = TRUE;
1136 // First remove (unmap) the window;
1137 // send the message.
1138 // If you do it in the reverse order, users get confused coz
1139 // the window remains behind for a couple seconds after hitting
1140 // "Send" and it ...
1142 _send_button->deactivate();
1143 _close_button->deactivate();
1145 mail_exec_error.clear();
1148 // Check if message has addressees. If it doesn't, what sense does
1149 // it make to Send it?
1151 if (!this->hasAddressee()) {
1152 // Message has no valid addressee. Pop up error dialog.
1154 sprintf(buf, "%s", GETMSG(DT_catd, 5, 8,
1155 "Try Send after specifying recipient(s) of the message in \nthe To:, Cc:, or Bcc: fields."));
1157 helpId = DTMAILHELPNEEDADDRESSEE;
1159 // Need help tag for above HelpID.
1161 // popup the compose window
1163 _send_button->activate();
1164 _close_button->activate();
1166 _genDialog->setToErrorDialog(GETMSG(DT_catd, 2, 21, "Mailer"),
1168 _genDialog->post_and_return(GETMSG(DT_catd, 3, 76, "OK"), helpId);
1170 // Reset the flag before we return.
1171 _already_sending = FALSE;
1177 // Since we are Send-ing, the SMD can be taken down later without
1178 // checking for dirty...
1185 // Just get text from text widget; attachment BPs are filled
1186 // already when they are included/forwarded/added.
1190 // Check if there are any pending attachments (open, print....)
1191 // If there are, pop up the dialog.
1192 // If the user wants to Send the message as is, continue with the
1193 // submission process.
1194 // If the user opted to Cancel, then return.
1197 numPendingActions = attachArea->getNumPendingActions();
1198 sprintf(buf, "%s", GETMSG(
1202 "You have an attachment open that may have unsaved changes.\nSending this message will break the connection to the open\n attachment. Any unsaved changes will not be part of the\n message. You can use Save As to save Changes after the\n connection is broken, but the changes will not be part of\n the attachment." ));
1204 while (numPendingActions != 0) {
1205 // popup the compose window
1207 _send_button->activate();
1208 _close_button->activate();
1211 * The user tried to send a messages without saving changes in
1212 * some open attachments. This warning makes sure that is what
1213 * the user intended.
1216 _genDialog->setToQuestionDialog(
1217 GETMSG(DT_catd, 5, 1, "Mailer"),
1219 helpId = DTMAILHELPPENDINGACTIONS;
1221 answer = _genDialog->post_and_return(helpId);
1225 numPendingActions = 0;
1227 _send_button->deactivate();
1228 _close_button->deactivate();
1230 else if (answer == 2) {
1232 // Reset the flag before we return.
1233 _already_sending = FALSE;
1239 // Determine which transport mechanism will be used.
1240 if ( trans_type ) { // Default
1241 // Only register XtAppAddInput once
1244 // Create the pipe between the RFCTransport::childHandler
1245 // and XtAppAddInput
1246 if (pipe(_transfds) < 0) {
1247 // If this failed, make sure we try to initialize again later.
1248 mail_exec_error.setError(DTME_NoMemory);
1249 popupMemoryError (mail_exec_error);
1251 // Reset the flag before we return.
1252 _already_sending = FALSE;
1257 // Call ourproc when input is available on _transfds[0]
1258 XtAppAddInput(XtWidgetToApplicationContext(this->_main_form),
1259 _transfds[0], (XtPointer)XtInputReadMask,
1260 (XtInputCallbackProc)
1261 (theRoamApp.default_transport()->getSendmailReturnProc()),
1266 // Tell the transport where the callback is
1267 theRoamApp.default_transport()->initTransportData( _transfds,
1268 &(SendMsgDialog::sendmailErrorProc), this);
1269 id = theRoamApp.default_transport()->submit(mail_exec_error,
1270 _msgHandle, _log_msg);
1273 // Construct transport
1274 mail_transport = d_session->transportConstruct(mail_exec_error,
1275 trans_impl, RoamApp::statusCallback, this);
1277 // Only register XtAppAddInput once
1280 // Create the pipe between the RFCTransport::childHandler
1281 // and XtAppAddInput
1282 if (pipe(_transfds) < 0) {
1283 // If this failed, make sure we try to initialize again later.
1284 mail_exec_error.setError(DTME_NoMemory);
1285 popupMemoryError (mail_exec_error);
1287 // Reset the flag before we return.
1288 _already_sending = FALSE;
1293 // Call ourproc when input is available on _transfds[0]
1294 XtAppAddInput(XtWidgetToApplicationContext(this->_main_form),
1295 _transfds[0], (XtPointer)XtInputReadMask,
1296 (XtInputCallbackProc)(mail_transport->getSendmailReturnProc()),
1301 // Tell the transport where the callback is
1302 mail_transport->initTransportData(_transfds,
1303 &(SendMsgDialog::sendmailErrorProc), this);
1304 id = mail_transport->submit(mail_exec_error, _msgHandle, _log_msg);
1307 popupMemoryError (mail_exec_error);
1309 // Reset the flag before we return.
1310 _already_sending = FALSE;
1316 SendMsgDialog::popupMemoryError(DtMailEnv &error)
1318 char *helpId = NULL;
1319 char *buf = new char[2048];
1323 // Popup an error dialog if necessary.
1324 if (error.isSet()) {
1325 if ((DTMailError_t)error == DTME_NoMemory) {
1328 * Mailer ran out of memory. Ask the user to quit some other
1329 * applications so there will be more memory available.
1331 sprintf(buf, "%s", GETMSG(DT_catd, 5, 6,
1332 "Mailer does not have enough memory\n\
1333 available to send this message.\n\
1334 Try quitting other applications and\n\
1335 resend this message."));
1336 helpId = DTMAILHELPNOMEMORY;
1340 * An unidentifiable error happened during mail transport
1341 * Pop it up *as is* (need to update this function if so)
1343 sprintf(buf, "%s", (const char *)error);
1344 helpId = DTMAILHELPERROR;
1347 // popup the compose window
1349 _send_button->activate();
1350 _close_button->activate();
1352 // popup the error dialog
1353 this->_genDialog->setToErrorDialog(GETMSG(DT_catd, 2, 21, "Mailer"),
1355 this->_genDialog->post_and_return(GETMSG(DT_catd, 3, 76, "OK"),
1363 SendMsgDialog::createWorkArea ( Widget parent )
1365 FORCE_SEGV_DECL(CmdInterface, ci);
1368 // Create the parent form
1370 _main_form = XmCreateForm( parent, "Work_Area", NULL, 0 );
1371 XtVaSetValues(_main_form, XmNresizePolicy, XmRESIZE_NONE, NULL);
1373 printHelpId("form", _main_form);
1374 /* add help callback */
1375 XtAddCallback(_main_form, XmNhelpCallback, HelpCB, (void *)DTMAILCOMPOSEWINDOW);
1376 XtVaSetValues(_main_form, XmNallowResize, True, NULL);
1379 // Create the area for status messages.
1381 _status_form = XtVaCreateManagedWidget("StatusForm",
1382 xmFormWidgetClass, _main_form,
1383 XmNtopAttachment, XmATTACH_FORM,
1384 XmNrightAttachment, XmATTACH_FORM,
1386 XmNleftAttachment, XmATTACH_FORM,
1390 _status_text = XtVaCreateManagedWidget("StatusLabel",
1391 xmLabelWidgetClass, _status_form,
1392 XmNtopAttachment, XmATTACH_FORM,
1393 XmNbottomAttachment, XmATTACH_FORM,
1394 XmNrightAttachment, XmATTACH_FORM,
1395 XmNleftAttachment, XmATTACH_FORM,
1396 XmNalignment, XmALIGNMENT_BEGINNING,
1401 Widget s_sep = XtVaCreateManagedWidget("StatusSep",
1402 xmSeparatorGadgetClass,
1404 XmNtopAttachment, XmATTACH_WIDGET,
1405 XmNtopWidget, _status_form,
1406 XmNleftAttachment, XmATTACH_FORM,
1407 XmNrightAttachment, XmATTACH_FORM,
1410 _header_form = XtVaCreateManagedWidget("HeaderArea",
1411 xmFormWidgetClass, _main_form,
1412 XmNtopAttachment, XmATTACH_WIDGET,
1413 XmNtopWidget, s_sep,
1414 XmNleftAttachment, XmATTACH_FORM,
1415 XmNrightAttachment, XmATTACH_FORM,
1417 printHelpId("header_form", _header_form);
1419 createHeaders(_header_form);
1421 Widget sep1 = XtVaCreateManagedWidget("Sep1",
1422 xmSeparatorGadgetClass,
1424 XmNtopAttachment, XmATTACH_WIDGET,
1425 XmNtopWidget, _header_form,
1427 XmNrightAttachment, XmATTACH_FORM,
1428 XmNleftAttachment, XmATTACH_FORM,
1431 // Create the editor and attach it to the header_form
1433 _my_editor = new DtMailEditor(_main_form, this);
1435 _my_editor->initialize();
1436 _my_editor->attachArea()->setOwnerShell(this);
1437 _my_editor->setEditable(TRUE);
1438 _my_editor->manageAttachArea();
1440 // Create a RowCol widget that contains buttons
1442 send_form = XtCreateManagedWidget("SendForm",
1443 xmFormWidgetClass, _main_form, NULL, 0);
1446 // Create the Send and Close buttons as children of rowCol
1448 _send_button = new SendCmd ( "Send",
1449 GETMSG(DT_catd, 1, 230, "Send"),
1453 ci = new ButtonInterface (send_form, _send_button);
1455 XtVaSetValues(ci->baseWidget(),
1456 XmNleftAttachment, XmATTACH_FORM,
1457 XmNleftOffset, OFFSET,
1458 XmNbottomAttachment, XmATTACH_FORM,
1462 Widget send_bw = ci->baseWidget();
1463 XtManageChild(send_bw);
1466 _close_button = new CloseCmd (
1468 GETMSG(DT_catd, 1, 118, "Close"),
1472 ci = new ButtonInterface (send_form, _close_button);
1473 XtVaSetValues(ci->baseWidget(),
1475 XmNleftAttachment, XmATTACH_WIDGET,
1476 XmNleftWidget, send_bw,
1477 XmNbottomAttachment, XmATTACH_FORM,
1481 XtManageChild(ci->baseWidget());
1484 // Now attach the editor to the form and to the rowCol
1485 // And the rowCol to the bottom of the form.
1486 // We need this attachment ordering so that resizes always
1487 // get transferred to the editor.
1489 Widget wid = _my_editor->container();
1491 XmNleftAttachment, XmATTACH_FORM,
1492 XmNrightAttachment, XmATTACH_FORM,
1493 XmNtopAttachment, XmATTACH_WIDGET,
1496 XmNbottomAttachment, XmATTACH_WIDGET,
1497 XmNbottomWidget, send_form,
1500 XtVaSetValues(send_form,
1501 XmNbottomAttachment, XmATTACH_FORM,
1506 HeaderList * hl = _header_list[0];
1507 (void) XmProcessTraversal(hl->field_widget, XmTRAVERSE_CURRENT);
1509 // Set the title to be New Message
1510 //char *ttl = GETMSG(DT_catd, 1, 119, "New Message");
1511 //this->setTitle(ttl);
1512 //this->setIconTitle(ttl);
1514 XtManageChild(_main_form);
1520 SendMsgDialog::createHeaders(Widget header_form)
1522 Widget previous_form = NULL;
1523 char *field_name = new char[50];
1525 for (int header = 0; header < _header_list.length(); header++) {
1526 HeaderList * hl = _header_list[header];
1528 // We use SMD_NEVER to indicate the header has disappeared from
1531 if (hl->show == SMD_NEVER) {
1535 // If the widgets already exist, then simply manage them.
1536 if (hl->form_widget) {
1537 previous_form = hl->form_widget;
1539 XtVaSetValues(hl->field_widget,
1540 XmNvalue, hl->value,
1543 XtVaSetValues(hl->field_widget,
1549 if (previous_form == NULL) {
1550 // Create a form, attaching it to the top. This is a special
1551 // case. Other lines are created attached to the form above
1553 strcpy(field_name, "form_");
1554 strncat(field_name, hl->label, 45);
1555 field_name[strlen(hl->label) + 5] = 0;
1557 XtVaCreateWidget(field_name,
1560 XmNtopAttachment, XmATTACH_FORM,
1562 XmNleftAttachment, XmATTACH_FORM,
1564 XmNrightAttachment, XmATTACH_FORM,
1570 strcpy(field_name, "form_");
1571 strncat(field_name, hl->label, 45);
1572 field_name[strlen(hl->label) + 5] = 0;
1574 XtVaCreateWidget(field_name,
1577 XmNtopAttachment, XmATTACH_WIDGET,
1578 XmNtopWidget, previous_form,
1579 XmNleftAttachment, XmATTACH_FORM,
1581 XmNrightAttachment, XmATTACH_FORM,
1587 // The label will be to the left of the form.
1589 strcpy(field_name, hl->label);
1590 strcat(field_name, ":");
1591 XmString label = XmStringCreateLocalized(field_name);
1593 XtVaCreateManagedWidget(hl->label,
1596 XmNtopAttachment, XmATTACH_FORM,
1597 XmNbottomAttachment, XmATTACH_FORM,
1598 XmNleftAttachment, XmATTACH_FORM,
1599 XmNlabelString, label,
1601 XmStringFree(label);
1603 strcpy(field_name, "field_");
1604 strncat(field_name, hl->label, 43);
1605 field_name[strlen(hl->label) + 6] = 0;
1608 XtVaCreateManagedWidget(field_name,
1609 xmTextFieldWidgetClass,
1611 XmNtraversalOn, True,
1612 XmNtopAttachment, XmATTACH_FORM,
1613 XmNrightAttachment, XmATTACH_FORM,
1614 XmNleftAttachment, XmATTACH_WIDGET,
1615 XmNleftWidget, hl->label_widget,
1618 if (hl->show != SMD_HIDDEN) {
1619 XtManageChild(hl->form_widget);
1622 XtVaSetValues(hl->form_widget,
1623 XmNtopAttachment, XmATTACH_NONE,
1627 XtAddCallback(hl->field_widget,
1628 XmNactivateCallback,
1629 header_form_traverse,
1632 XtAddCallback(hl->field_widget,
1633 XmNvalueChangedCallback,
1638 XtVaSetValues(hl->field_widget,
1639 XmNvalue, hl->value,
1643 previous_form = hl->form_widget;
1647 delete [] field_name;
1651 SendMsgDialog::doDynamicHeaderMenus(void)
1653 // This is really a pain, but we have to blow away the list to
1654 // build another one. This could probably be done more efficiently,
1655 // but we wont try to figure out how right now.
1658 _menuBar->removeOnlyCommands(_format_menu, _format_cmds);
1661 _format_cmds = new CmdList("DynamicFormatCommands", "DynamicFormatCommands");
1663 // Only put on commands that are shown or hidden. The items that
1664 // are always are never should not be presented to the user as
1665 // an option to change.
1667 char *label = new char[100];
1669 for (int h = 0; h < _header_list.length(); h++) {
1670 HeaderList * hl = _header_list[h];
1674 sprintf(label, "%s ", GETMSG(DT_catd, 1, 229, "Delete"));
1678 sprintf(label, "%s ", GETMSG(DT_catd, 1, 228, "Add"));
1685 strcat(label, hl->label);
1688 char * priv_label = strdup(label);
1690 Cmd * new_cmd = new HideShowCmd(priv_label, priv_label,
1691 1, this, hl->label);
1693 // Add the commands one at a time with addCommand() vs. all
1694 // at once with addCommands(). That way new commands will
1695 // be created instead of reusing old ones.
1696 _menuBar->addCommand(_format_menu, new_cmd);
1697 _format_cmds->add(new_cmd);
1705 // Should theInfoDialogManager be destroyed here ???
1710 SendMsgDialog::open_att_cb( void *clientData, char *selection )
1712 SendMsgDialog *obj = (SendMsgDialog *)clientData;
1714 obj->open_att(selection);
1718 SendMsgDialog::open_att( char *) // arg is char *selection
1721 #endif /* DEAD_WOOD */
1724 SendMsgDialog::include_file_cb( void *client_data, char *selection )
1726 SendMsgDialog *obj = (SendMsgDialog *)client_data;
1727 obj->include_file(selection);
1732 SendMsgDialog::include_file(
1737 char *buf = new char[MAXPATHLEN];
1739 // I don't need to open the file to see if it's readable if loadFile()
1740 // returns error status.
1741 if ( (fp = fopen(selection, "r")) == NULL ) {
1742 sprintf(buf, GETMSG(DT_catd, 2, 18, "Error: Cannot include file %s"),
1744 theInfoDialogManager->post(
1747 (void *)this->_file_include,
1751 this->_my_editor->textEditor()->append_to_contents("\n", 2);
1752 this->_my_editor->textEditor()->append_at_cursor(selection);
1753 this->_my_editor->textEditor()->append_to_contents("\n", 2);
1759 SendMsgDialog::get_confirm_attachment_threshold()
1762 DtMail::Session *m_session = theRoamApp.session()->session();
1763 const char *value = NULL;
1766 m_session->mailRc(error)->getValue(error, "confirmattachments", &value);
1767 if (error.isSet()) return 0;
1769 m_session->mailRc(error)->getValue(error, "confirmattachmentthreshold",
1771 if (error.isNotSet() && NULL!=value)
1772 threshold = 1024 * atoi(value);
1774 threshold = 1024 * 64;
1780 SendMsgDialog::confirm_add_attachment(char *file, int size)
1782 char *buf = new char[BUFSIZ];
1787 GETMSG(DT_catd, 1, 263,
1788 "The attachment '%s' is %d kilobytes.\nAdd as attachment?");
1789 sprintf(buf, format, file, size/1024);
1790 _genDialog->setToQuestionDialog(GETMSG(DT_catd, 5, 2, "Mailer"), buf);
1791 answer = _genDialog->post_and_return(NULL);
1796 SendMsgDialog::add_att_cb( void *client_data, char *selection )
1798 SendMsgDialog *obj = (SendMsgDialog *)client_data;
1799 obj->add_att(selection);
1800 if (NULL != selection)
1805 SendMsgDialog::add_att(char *file)
1807 struct stat statbuf;
1809 if (-1 != stat(file, &statbuf) && _confirm_attachment_threshold &&
1810 _confirm_attachment_threshold < statbuf.st_size)
1812 if (! confirm_add_attachment(file, statbuf.st_size)) return;
1815 // Activate Attachment menu???
1816 this->get_editor()->attachArea()->
1817 addAttachment(_msgHandle, _lastAttBP, file, NULL);
1818 this->setLastAttBP();
1819 this->activate_default_attach_menu();
1821 // This will manage the attach pane too.
1822 ((ToggleButtonCmd *)_att_show_pane)->setButtonState(TRUE, TRUE);
1826 SendMsgDialog::add_att(char *name, DtMailBuffer buf)
1828 if (_confirm_attachment_threshold &&
1829 _confirm_attachment_threshold < buf.size)
1831 if (! confirm_add_attachment("", buf.size)) return;
1834 this->get_editor()->attachArea()->
1835 addAttachment(_msgHandle, _lastAttBP, name, buf);
1836 this->setLastAttBP();
1837 this->activate_default_attach_menu();
1839 // This will manage the attach pane too.
1840 ((ToggleButtonCmd *)_att_show_pane)->setButtonState(TRUE, TRUE);
1844 SendMsgDialog::add_att(DtMailBuffer buf)
1851 SendMsgDialog::save_att_cb( void *client_data, char *selection )
1853 SendMsgDialog *obj = (SendMsgDialog *)client_data;
1855 obj->save_selected_attachment(selection);
1860 SendMsgDialog::save_selected_attachment(
1864 DtMailEnv mail_error;
1868 AttachArea *attarea = this->get_editor()->attachArea();
1869 Attachment *attachment = attarea->getSelectedAttachment();
1871 // Get selected attachment, if none selected, then return.
1872 if ( attachment == NULL ) {
1873 // Let User know that no attachment has been selected???
1875 char *helpId = NULL;
1878 _genDialog->setToErrorDialog(
1879 GETMSG(DT_catd, 1, 120, "Mailer"),
1880 GETMSG(DT_catd, 2, 19, "An attachment needs to be selected before issuing the\n\"Save As\" command to save to a file.") );
1881 helpId = DTMAILHELPSELECTATTACH;
1882 answer = _genDialog->post_and_return(
1883 GETMSG(DT_catd, 3, 74, "OK"), helpId );
1887 // Save selected attachments.
1888 attachment->saveToFile(mail_error, selection);
1889 if ( mail_error.isSet() ) {
1890 // Let User know error condition???
1896 SendMsgDialog::propsChanged(void)
1898 DtMail::Session *m_session = theRoamApp.session()->session();
1899 const char * value = NULL;
1902 enableWorkAreaResize();
1904 m_session->mailRc(error)->getValue(error, "hideattachments", &value);
1906 if (_show_attach_area) {
1907 _show_attach_area = FALSE;
1908 this->hideAttachArea();
1912 if (!_show_attach_area) {
1913 _show_attach_area = TRUE;
1914 this->showAttachArea();
1917 free((void*) value);
1919 _confirm_attachment_threshold = get_confirm_attachment_threshold();
1922 const char * logfile = NULL;
1923 m_session->mailRc(error)->getValue(error, "record", &logfile);
1924 if (logfile == NULL)
1925 _file_log->deactivate();
1927 _file_log->activate();
1929 _my_editor->textEditor()->update_display_from_props();
1931 m_session->mailRc(error)->getValue(error, "dontlogmessages", &value);
1932 if (logfile == NULL || error.isNotSet()) {
1933 // logfile is not specified or "dontlogmessages" is TRUE
1934 setLogState(DTM_FALSE);
1935 ((ToggleButtonCmd *)_file_log)->setButtonState(FALSE, TRUE);
1937 // logfile is specified and "dontlogmessages" is FALSE
1938 setLogState(DTM_TRUE);
1939 ((ToggleButtonCmd *)_file_log)->setButtonState(TRUE, TRUE);
1942 if (NULL != logfile)
1943 free((void*) logfile);
1945 free((void*) value);
1948 m_session->mailRc(error)->getValue(error, "templates", &value);
1949 if ( (value == NULL && _templateList != NULL) ||
1951 (_templateList == NULL || strcmp(value, _templateList)) != 0) ) {
1952 // Template list has changed
1953 if (_templateList != NULL)
1954 free (_templateList);
1955 if (value != NULL && *value != '\0')
1956 _templateList = strdup(value);
1958 _templateList = NULL;
1962 free((void*) value);
1964 // Alias Popup Menus
1965 DtVirtArray<PropStringPair*> *newAliases;
1966 Boolean aliasesChanged = FALSE;
1968 newAliases = new DtVirtArray<PropStringPair*> (10);
1969 createAliasList(newAliases);
1970 if (newAliases->length() == _aliasList->length())
1972 int length = newAliases->length();
1975 while (i<length && aliasesChanged==FALSE)
1977 PropStringPair *p1 = (*newAliases)[i];
1978 PropStringPair *p2 = (*_aliasList)[i];
1980 if ( strncmp(p1->label, p2->label, strlen(p2->label)) ||
1981 strncmp(p1->value, p2->value, strlen(p2->value)) )
1982 aliasesChanged = TRUE;
1988 aliasesChanged = TRUE;
1990 if (aliasesChanged == TRUE)
1992 destroyAliasPopupMenus();
1993 destroyAliasList(_aliasList);
1994 _aliasList = newAliases;
1995 createAliasPopupMenus();
1998 destroyAliasList(newAliases);
2000 disableWorkAreaResize();
2004 SendMsgDialog::createMenuPanes()
2009 const char * value = NULL;
2012 _separator = new SeparatorCmd( "Separator","Separator", TRUE );
2015 cmdList = new CmdList( "File", GETMSG(DT_catd, 1, 121, "File") );
2017 // Default directory is set below at the same time as the default
2018 // directory for att_add.
2019 _file_include = new UnifiedSelectFileCmd (
2021 GETMSG(DT_catd, 1, 122, "Include..."),
2022 GETMSG(DT_catd, 1, 123, "Mailer - Include"),
2023 GETMSG(DT_catd, 1, 124, "Include"),
2025 SendMsgDialog::include_file_cb,
2027 this->baseWidget());
2030 // Remap OK button to Include
2031 // XtVaSetValues(_file_include->fileBrowser,
2032 // XmNokLabelString, GETMSG(DT_catd,
2033 // 1, 77, "Include"), NULL);
2034 _file_save_as = new SaveAsTextCmd(
2036 GETMSG(DT_catd, 1, 125, "Save As Text..."),
2037 GETMSG(DT_catd, 1, 126, "Mailer - Save As Text"),
2039 get_editor()->textEditor(),
2043 _file_log = new LogMsgCmd (
2045 GETMSG(DT_catd, 1, 127, "Log Message"), TRUE, this);
2047 // 1 for default transport.
2049 _file_send = new SendCmd (
2051 GETMSG(DT_catd, 1, 117, "Send"),
2056 // Find out how many transports there are and build sub menu dynamically.
2057 DtMail::Session *d_session;
2059 if ( theRoamApp.session() == NULL ) {
2060 MailSession *new_session = new MailSession(
2062 theApplication->appContext());
2063 theRoamApp.setSession(new_session);
2066 CmdList *subcmdList1 = new CmdList (
2068 GETMSG(DT_catd, 1, 128, "Send As") );
2070 d_session = theRoamApp.session()->session();
2071 const char **impls = d_session->enumerateImpls(error);
2073 for ( int impl = 0; impls[impl]; impl++ ) {
2074 DtMailBoolean trans;
2075 d_session->queryImpl(error, impls[impl],
2076 DtMailCapabilityTransport, &trans);
2077 if (!error.isSet() && trans == DTM_TRUE ) {
2078 _file_sendAs[_num_sendAs] = new SendCmd( strdup(impls[impl]),
2079 (char *)impls[impl],
2083 subcmdList1->add( _file_sendAs[_num_sendAs] );
2086 // Assume an error means this query failed. But keep going and
2087 // get the next transport.
2090 _file_close = new CloseCmd (
2092 GETMSG(DT_catd, 1, 129, "Close"),
2094 _menuBar->baseWidget(),
2097 // Now build the menu
2099 cmdList->add( _file_include );
2100 cmdList->add( _file_save_as );
2101 cmdList->add( _file_log );
2102 cmdList->add( _separator );
2104 cmdList->add( _file_send );
2105 #if defined(USE_SEND_AS_MENU)
2106 cmdList->add( subcmdList1 );
2108 cmdList->add( _separator );
2110 cmdList->add( _file_close );
2112 _menuBar->addCommands ( cmdList );
2118 cmdList = new CmdList( "Edit", GETMSG(DT_catd, 1, 130, "Edit") );
2120 _edit_undo = new EditUndoCmd ( "Undo",
2121 GETMSG(DT_catd, 1, 131, "Undo"),
2123 _edit_cut = new EditCutCmd ( "Cut",
2124 GETMSG(DT_catd, 1, 132, "Cut"),
2126 _edit_copy = new EditCopyCmd ( "Copy",
2127 GETMSG(DT_catd, 1, 133, "Copy"),
2129 _edit_paste = new EditPasteCmd ( "Paste",
2130 GETMSG(DT_catd, 1, 134 , "Paste"),
2134 // Begin Paste Special submenu
2135 subcmdList1 = new CmdList ( "Paste Special", GETMSG(DT_catd, 1, 135 , "Paste Special") );
2136 _edit_paste_special[0] = new EditPasteSpecialCmd (
2138 GETMSG(DT_catd, 1, 136 , "Bracketed"),
2139 TRUE, this, Editor::IF_BRACKETED
2141 subcmdList1->add(_edit_paste_special[0]);
2142 _edit_paste_special[1] = new EditPasteSpecialCmd (
2144 GETMSG(DT_catd, 1, 137 , "Indented"),
2145 TRUE, this, Editor::IF_INDENTED );
2146 subcmdList1->add(_edit_paste_special[1]);
2147 // End Paste Special submenu
2149 _edit_clear = new EditClearCmd ( "Clear", GETMSG(DT_catd, 1, 138, "Clear"),
2152 _edit_delete = new EditDeleteCmd ( "Delete", GETMSG(DT_catd, 1, 139, "Delete"),
2155 _edit_select_all = new EditSelectAllCmd (
2157 GETMSG(DT_catd, 1, 140, "Select All"),
2160 _format_find_change = new FindChangeCmd (
2162 GETMSG(DT_catd, 1, 155, "Find/Change..."),
2165 _format_spell = new SpellCmd (
2166 "Check Spelling...",
2167 GETMSG(DT_catd, 1, 156, "Check Spelling..."),
2171 cmdList->add( _edit_undo );
2172 cmdList->add( _separator );
2173 cmdList->add( _edit_cut );
2174 cmdList->add( _edit_copy );
2175 cmdList->add( _edit_paste );
2176 cmdList->add( subcmdList1 ); // Add Paste Special submenu
2177 cmdList->add( _separator );
2178 cmdList->add( _edit_clear );
2179 cmdList->add( _edit_delete );
2180 cmdList->add( _separator );
2181 cmdList->add( _edit_select_all );
2182 cmdList->add( _separator );
2183 cmdList->add( _format_find_change );
2186 * SpellCheck is not supported by Base System for the multibyte language
2187 * currently. ( See dtpad's source ) So that this should be disabled.
2188 * See Defect 174873. (I should think this solution is not good one, but..)
2189 * What is the best way to check if I'm in MB or SB.....???
2192 if ( MB_CUR_MAX == 1 )
2193 cmdList->add( _format_spell );
2195 _menuBar->addCommands ( cmdList );
2199 // Alias Popup Menus
2200 if (NULL != _aliasList) delete _aliasList;
2201 _aliasList = new DtVirtArray<PropStringPair*> (10);
2202 createAliasList(_aliasList);
2203 createAliasPopupMenus();
2205 // Compose Popup CmdList
2206 construct_text_popup();
2210 cmdList = new CmdList(
2212 GETMSG(DT_catd, 1, 141, "Attachments"));
2214 _att_add = new UnifiedSelectFileCmd (
2216 GETMSG(DT_catd, 1, 142, "Add File..."),
2217 GETMSG(DT_catd, 1, 143, "Mailer - Add"),
2218 GETMSG(DT_catd, 1, 144, "Add"),
2220 SendMsgDialog::add_att_cb,
2222 this->baseWidget());
2224 _att_save = new SaveAttachCmd (
2226 GETMSG(DT_catd, 1, 145, "Save As..."),
2227 GETMSG(DT_catd, 1, 146,
2228 "Mailer - Attachments - Save As"),
2230 SendMsgDialog::save_att_cb,
2232 this->baseWidget());
2233 _att_delete = new DeleteAttachCmd (
2235 GETMSG(DT_catd, 1, 147, "Delete"),
2238 _att_undelete = new UndeleteAttachCmd (
2240 GETMSG(DT_catd, 1, 148, "Undelete"),
2243 _att_rename = new RenameAttachCmd(
2245 GETMSG(DT_catd, 1, 149, "Rename"),
2249 _att_select_all = new SelectAllAttachsCmd(
2251 GETMSG(DT_catd, 1, 150, "Select All"),
2255 * This is the label for a toggle item in a menu. When the item
2256 * is set to "Show List", the Attachment List is mapped in the
2257 * Compose Window. This message replaces message 151 in set 1.
2259 _att_show_pane = new ShowAttachPaneCmd(
2261 GETMSG(DT_catd, 1, 226, "Show List"),
2264 cmdList->add( _att_add );
2265 cmdList->add( _att_save );
2266 cmdList->add( _separator );
2268 // subcmdList1 = new CmdList ( "Create", "Create" );
2269 // // subcmdList1->add( att_audio );
2270 // // subcmdList1->add( att_appt );
2271 // cmdList->add( subcmdList1 );
2272 // cmdList->add( _separator );
2274 cmdList->add( _att_delete );
2275 cmdList->add( _att_undelete );
2276 cmdList->add( _att_rename );
2277 cmdList->add( _att_select_all );
2278 cmdList->add(_att_show_pane);
2280 // Create a pulldown from the items in the list. Retain a handle
2281 // to that pulldown since we need to dynamically add/delete entries
2282 // to this menu based on the selection of attachments.
2284 _attachmentMenu = _menuBar->addCommands ( cmdList );
2285 construct_attachment_popup();
2287 // delete subcmdList1;
2291 d_session->mailRc(error)->getValue(error, "templates", &value);
2292 if (value != NULL && *value != '\0')
2293 _templateList = strdup(value);
2295 free((void*) value);
2299 _overview = new OnAppCmd("Overview",
2300 GETMSG(DT_catd, 1, 71, "Overview"),
2302 _tasks = new TasksCmd("Tasks", GETMSG(DT_catd, 1, 72, "Tasks"),
2304 _reference = new ReferenceCmd("Reference",
2305 GETMSG(DT_catd, 1, 73, "Reference"),
2307 _on_item = new OnItemCmd("On Item", GETMSG(DT_catd, 1, 74, "On Item"),
2309 _using_help = new UsingHelpCmd("Using Help",
2310 GETMSG(DT_catd, 1, 75, "Using Help"),
2312 _about_mailer = new RelNoteCmd("About Mailer...",
2313 GETMSG(DT_catd, 1, 77, "About Mailer..."),
2315 cmdList = new CmdList("Help", GETMSG(DT_catd, 1, 76, "Help"));
2316 cmdList->add(_overview);
2317 cmdList->add(_separator);
2318 cmdList->add(_tasks);
2319 cmdList->add(_reference);
2320 cmdList->add(_separator);
2321 cmdList->add(_on_item);
2322 cmdList->add(_separator);
2323 cmdList->add(_using_help);
2324 cmdList->add(_separator);
2325 cmdList->add(_about_mailer);
2326 _menuBar->addCommands(cmdList, TRUE);
2331 SendMsgDialog::construct_attachment_popup(void)
2333 _attachmentPopupMenuList = new CmdList( "AttachmentsPopup", "AttachmentsPopup");
2335 LabelCmd *title = new LabelCmd (
2336 "Mailer - Attachments",
2337 GETMSG(DT_catd, 1, 158, "Mailer - Attachments"), TRUE);
2338 SeparatorCmd *separator = new SeparatorCmd( "Separator","Separator", TRUE );
2340 _attachmentPopupMenuList->add(title);
2341 _attachmentPopupMenuList->add(separator);
2342 _attachmentPopupMenuList->add( _att_add );
2343 _attachmentPopupMenuList->add( _att_save );
2344 _attachmentPopupMenuList->add( _att_delete );
2345 _attachmentPopupMenuList->add( _att_undelete );
2346 _attachmentPopupMenuList->add( _att_select_all );
2348 _menuPopupAtt = new MenuBar(_my_editor->attachArea()->getClipWindow(),
2349 "RoamAttachmentPopup", XmMENU_POPUP);
2350 _attachmentPopupMenu = _menuPopupAtt->addCommands(_attachmentPopupMenuList,
2351 FALSE, XmMENU_POPUP);
2355 SendMsgDialog::construct_text_popup(void)
2357 if (theApplication->bMenuButton() != Button3)
2360 _textPopupMenuList = new CmdList( "TextPopup", "TextPopup");
2362 LabelCmd *title = new LabelCmd (
2364 GETMSG(DT_catd, 1, 159, "Mailer - Compose"), TRUE);
2365 SeparatorCmd *separator = new SeparatorCmd("Separator", "Separator", TRUE );
2367 _textPopupMenuList->add(title);
2368 _textPopupMenuList->add(separator);
2369 _textPopupMenuList->add(_file_send);
2370 _textPopupMenuList->add( _edit_undo );
2371 _textPopupMenuList->add( _edit_cut );
2372 _textPopupMenuList->add( _edit_copy );
2373 _textPopupMenuList->add( _edit_paste );
2375 // Work in progress from Mike. This adds the Paste Special to the
2376 // third mouse button in the compose area of a compose window.
2377 // Begin Paste Special submenu
2378 CmdList * subcmdList1 = new CmdList ( "Paste Special", GETMSG(DT_catd, 1, 135 , "Paste Special") );
2379 subcmdList1->add(_edit_paste_special[0]);
2380 subcmdList1->add(_edit_paste_special[1]);
2381 // End Paste Special submenu
2382 _textPopupMenuList->add( subcmdList1 ); // Add Paste Special submenu
2383 // (Either way) _textPopupMenuList->add( separator );
2384 _textPopupMenuList->add( _edit_clear );
2386 _textPopupMenuList->add( _edit_delete );
2387 _textPopupMenuList->add( _edit_select_all );
2389 Widget parent = _my_editor->textEditor()->get_editor();
2390 _menuPopupText = new MenuBar(parent, "SendMsgTextPopup", XmMENU_POPUP);
2391 _textPopupMenu = _menuPopupText->addCommands(_textPopupMenuList,
2392 FALSE, XmMENU_POPUP);
2395 static int cmp_prop_pair(const void *v1, const void *v2)
2397 PropStringPair *p1 = *((PropStringPair **) v1);
2398 PropStringPair *p2 = *((PropStringPair **) v2);
2401 ret = strcmp((const char *) p1->label, (const char *) p2->label);
2405 static void alias_stuffing_func(char * key, void * data, void * client_data)
2407 DtVirtArray<PropStringPair *> *alias_list;
2408 PropStringPair *new_pair;
2410 alias_list = (DtVirtArray<PropStringPair*> *) client_data;
2411 new_pair = new PropStringPair;
2412 new_pair->label = strdup(key);
2413 new_pair->value = strdup((char *)data);
2414 alias_list->append(new_pair);
2418 SendMsgDialog::createAliasList(DtVirtArray<PropStringPair*> *aliases)
2421 DtMail::Session *d_session = theRoamApp.session()->session();
2422 DtMail::MailRc *mail_rc = d_session->mailRc(error);
2425 mail_rc->getAliasList(alias_stuffing_func, aliases);
2427 if (nalias = aliases->length())
2429 PropStringPair **prop_pairs = NULL;
2431 prop_pairs = (PropStringPair**) malloc(nalias*sizeof(PropStringPair*));
2433 for (i=0; i<nalias; i++)
2435 prop_pairs[i] = (*aliases)[0];
2438 qsort(prop_pairs, nalias, sizeof(PropStringPair*), cmp_prop_pair);
2439 for (i=0; i<nalias; i++)
2440 aliases->append(prop_pairs[i]);
2442 free((void*) prop_pairs);
2447 SendMsgDialog::destroyAliasList(DtVirtArray<PropStringPair*> *aliases)
2449 while (aliases->length() >= 0)
2451 PropStringPair *prop_pair = (*aliases)[0];
2457 // map_menu is used to figure out how many columns to split the menu
2458 // into. It is a callback that is called when the menu is mapped.
2459 // If the menu is over half the height of the screen, it figures out
2460 // how many columns to make the menu, and sets its XmNnumColumns
2461 // attribute to that value. It calculates the maximum number of columns
2462 // that would fit and never goes beyond that number.
2464 static void map_alias_menu(Widget menu, XtPointer, XtPointer)
2468 Dimension maxcols, newcols, columns;
2469 Dimension screenheight = (Dimension) HeightOfScreen(XtScreen(menu));
2470 Dimension fudgefact = 20; /* to allow for decorations on menu */
2477 XmNnumColumns, &columns,
2480 if ((h + fudgefact) > (screenheight / 2))
2482 // The menu is taller than half the screen.
2483 // We need to find out how many more columns
2484 // to specify for the menu to make it fit.
2486 newcols = (columns * ((h+fudgefact)/(screenheight/2))) + 1;
2487 maxcols = WidthOfScreen(XtScreen(menu))/(w/columns);
2489 if (newcols > maxcols)
2492 XtVaSetValues(menu, XmNnumColumns, newcols, NULL);
2497 SendMsgDialog::aliasMenuButtonHandler(
2499 XtPointer client_data,
2503 Widget menu = (Widget) client_data;
2504 XButtonEvent *be = (XButtonEvent *) event;
2506 if (event->xany.type != ButtonPress) return;
2507 if(be->button == theApplication->bMenuButton())
2509 XmMenuPosition(menu, (XButtonEvent *)event);
2510 XtManageChild(menu);
2515 SendMsgDialog::createAliasPopupMenu(
2519 DtVirtArray<PropStringPair*> *aliases)
2522 OtherAliasesCmd *otherAliases =
2523 new OtherAliasesCmd(
2525 GETMSG(DT_catd, 1, 247, "Other Aliases..."),
2527 #if defined(USE_TITLED_ALIAS_POPUPS)
2531 GETMSG(DT_catd, 1, 248, "Mailer - Aliases"),
2534 SeparatorCmd *separator =
2535 new SeparatorCmd("Separator","Separator", TRUE);
2537 (*cmdlist) = new CmdList("AliasCommands", "AliasCommands");
2538 #if defined(USE_TITLED_ALIAS_POPUPS)
2539 (*cmdlist)->add(title);
2540 (*cmdlist)->add(separator);
2542 for (int i=0, length=aliases->length(); i<length; i++)
2544 PropStringPair *prop_pair = (*aliases)[i];
2546 AliasCmd *alias = new AliasCmd(
2547 strdup(prop_pair->label),
2548 strdup(prop_pair->label),
2551 (*cmdlist)->add(alias);
2553 if (0 < aliases->length())
2554 (*cmdlist)->add(separator);
2555 (*cmdlist)->add(otherAliases);
2557 *menubar = new MenuBar(parent, "AliasesPopup", XmMENU_POPUP);
2558 menu = (*menubar)->addCommands((*cmdlist), FALSE, XmMENU_POPUP);
2564 aliasMenuButtonHandler,
2569 XmNpacking, XmPACK_COLUMN,
2570 XmNorientation, XmVERTICAL,
2575 XmNmapCallback, &map_alias_menu,
2582 SendMsgDialog::destroyAliasPopupMenu(
2588 XtRemoveEventHandler(
2592 aliasMenuButtonHandler,
2597 XmNmapCallback, &map_alias_menu,
2600 XtDestroyWidget(menu);
2607 SendMsgDialog::getHeaderWidget(const char *hdrname)
2609 for (int i=0, length=_header_list.length(); i<length; i++)
2611 HeaderList *hdritem = _header_list[i];
2613 if (0 == strncmp(hdrname, hdritem->header, strlen(hdrname)))
2614 return hdritem->field_widget;
2621 SendMsgDialog::createAliasPopupMenus(void)
2625 w = getHeaderWidget(DtMailMessageTo);
2627 _toPopupMenu = createAliasPopupMenu(
2633 w = getHeaderWidget(DtMailMessageCc);
2635 _ccPopupMenu = createAliasPopupMenu(
2641 w = getHeaderWidget(DtMailMessageBcc);
2643 _bccPopupMenu = createAliasPopupMenu(
2651 SendMsgDialog::destroyAliasPopupMenus(void)
2655 w = getHeaderWidget(DtMailMessageTo);
2656 destroyAliasPopupMenu(w, _toPopupMenuBar, _toPopupCmdlist, _toPopupMenu);
2657 _toPopupMenuBar = NULL;
2658 _toPopupCmdlist = NULL;
2659 _toPopupMenu = NULL;
2661 w = getHeaderWidget(DtMailMessageCc);
2662 destroyAliasPopupMenu(w, _ccPopupMenuBar, _ccPopupCmdlist, _ccPopupMenu);
2663 _ccPopupMenuBar = NULL;
2664 _ccPopupCmdlist = NULL;
2665 _ccPopupMenu = NULL;
2667 w = getHeaderWidget(DtMailMessageBcc);
2668 destroyAliasPopupMenu(w, _bccPopupMenuBar, _bccPopupCmdlist, _bccPopupMenu);
2669 _bccPopupMenuBar = NULL;
2670 _bccPopupCmdlist = NULL;
2671 _bccPopupMenu = NULL;
2675 SendMsgDialog::createFormatMenu()
2678 _format_separator = new SeparatorCmd( "Separator","Separator", TRUE );
2680 cmdList = new CmdList( "Format", GETMSG(DT_catd, 1, 152,"Format") );
2682 _format_word_wrap = new WordWrapCmd (
2684 GETMSG(DT_catd, 1, 153, "Word Wrap"),
2687 _format_settings = new FormatCmd ( "Settings...",
2688 GETMSG(DT_catd, 1, 154, "Settings..."),
2692 cmdList->add( _format_word_wrap );
2693 cmdList->add( _format_settings );
2694 cmdList->add( _format_separator);
2696 _templates = new CmdList ( "Templates", GETMSG(DT_catd, 1, 157, "Templates") );
2697 addTemplates(_templates);
2699 cmdList->add(_templates);
2701 cmdList->add( _format_separator );
2703 _format_menu = _menuBar->addCommands ( &_format_cascade, cmdList,
2708 doDynamicHeaderMenus();
2710 if (_template_count == 0 && _templates->getPaneWidget())
2712 XtSetSensitive(_templates->getPaneWidget(), FALSE);
2718 SendMsgDialog::addTemplates(CmdList * subCmd)
2722 _template_count = 0;
2724 if (_templateList == NULL)
2727 DtMail::Session *m_session = theRoamApp.session()->session();
2728 char * expanded_list = m_session->expandPath(error, _templateList);
2730 DtVirtArray<PropStringPair *> templates(8);
2731 parsePropString(expanded_list, templates);
2732 free(expanded_list);
2734 _template_count = templates.length();
2736 for (int tmp = 0; tmp < _template_count; tmp++) {
2737 PropStringPair * psp = templates[tmp];
2738 if (psp->label && psp->value) {
2739 Cmd * button = new TemplateCmd(strdup(psp->label),
2744 subCmd->add(button);
2748 while (templates.length()) {
2749 PropStringPair * psp = templates[0];
2751 templates.remove(0);
2756 SendMsgDialog::initialize()
2760 const char * hideAttachPane = NULL;
2763 // Without the TearOffModelConverter call, there will be warning messages:
2764 // Warning: No type converter registered for 'String' to 'TearOffModel'
2767 XmRepTypeInstallTearOffModelConverter();
2768 MenuWindow::initialize();
2770 char *ttl = GETMSG(DT_catd, 1, 160, "New Message");
2773 XtSetArg(args[n], XmNdeleteResponse, XmDO_NOTHING); n++;
2774 XtSetValues( _w, args, n);
2776 _genDialog = new DtMailGenDialog("Dialog", _main);
2778 // See if the .mailrc specifies if attachPane is to be shown or hid
2779 // at SMD startup time.
2781 DtMail::Session *m_session = theRoamApp.session()->session();
2782 m_session->mailRc(error)->getValue(error, "hideattachments",
2785 if (!hideAttachPane) {
2786 _show_attach_area = TRUE;
2789 _show_attach_area = FALSE;
2790 // The user wants to hide attachments
2792 this->hideAttachArea();
2794 if (NULL != hideAttachPane)
2795 free((void*) hideAttachPane);
2797 _confirm_attachment_threshold = get_confirm_attachment_threshold();
2799 // Log Message Toggle button. A LogMsgCmd is a ToggleButtonCmd....
2800 const char * logfile = NULL;
2801 const char * value = NULL;
2802 m_session->mailRc(error)->getValue(error, "record", &logfile);
2804 _file_log->deactivate();
2806 _file_log->activate();
2808 m_session->mailRc(error)->getValue(error, "dontlogmessages", &value);
2809 if (logfile == NULL || error.isNotSet()) {
2810 // logfile is not specified or "dontlogmessages" is TRUE
2811 setLogState(DTM_FALSE);
2812 ((ToggleButtonCmd *)_file_log)->setButtonState(FALSE, TRUE);
2814 // logfile is specified and "dontlogmessages" is FALSE
2815 setLogState(DTM_TRUE);
2816 ((ToggleButtonCmd *)_file_log)->setButtonState(TRUE, TRUE);
2819 if (NULL != logfile)
2820 free((void*) logfile);
2822 free((void*) value);
2824 // Word Wrap Toggle button. A WordWrapCmd is a ToggleButtonCmd...
2825 ((ToggleButtonCmd *)_format_word_wrap)->setButtonState(
2826 ((WordWrapCmd *)_format_word_wrap)->wordWrap(),
2830 // Initialize the Edit menu
2832 this->text_unselected();
2834 setIconName(ComposeIcon);
2838 Self_destruct(XtPointer, XtIntervalId *)
2841 fprintf(stderr, "DEBUG: Self_destruct(): invoked!\n");
2845 XtRemoveAllCallbacks(
2846 theApplication->baseWidget(),
2847 XmNdestroyCallback);
2848 delete theApplication;
2851 // Clears Compose window title, header fields, text, and attachment areas.
2853 SendMsgDialog::reset()
2855 _my_editor->textEditor()->clear_contents();
2856 _my_editor->attachArea()->resetPendingAction();
2859 // This will deselect any Attachment action, if any available now.
2860 // Also deselect text menu items....
2862 this->deactivate_default_attach_menu();
2863 this->text_unselected();
2864 this->all_attachments_deselected();
2865 _att_undelete->deactivate(); // This needs to be done in addition
2867 this->get_editor()->attachArea()->removeCurrentAttachments();
2869 // Unmanage the dialog
2872 if (_show_attach_area) { // .mailrc wants default attach area invisible
2874 // Unmanage the attach Area. Set the show_pane button.
2875 // This is done because if we are caching this window (after
2876 // unmanaging), we don't want the window to pop back up, on uncaching,
2877 // with the attachment pane visible, etc..
2879 this->showAttachArea();
2882 this->hideAttachArea();
2885 // Need to destroy current Message handle.
2886 delete _msgHandle; // All its body parts are deleted.
2888 _lastAttBP = NULL; // So just set this to NULL.
2889 // Delete or set to NULL ???
2890 _inclMsgHandle = NULL;
2891 _inclMsgHasText = 0;
2893 for (int clear = 0; clear < _header_list.length(); clear++) {
2894 HeaderList * hl = _header_list[clear];
2896 // Bugfix: Old selection area remained selected, after text cleared
2897 // and parent widget unmanged, and then managed again for next
2898 // Compose. (So new text in old select area was still being selected).
2899 // Perhaps, this is a Motif bug ... but this fixes the problem.
2900 XmTextFieldClearSelection( hl->field_widget, CurrentTime );
2903 XtVaSetValues(hl->field_widget,
2904 XmNvalue, hl->value,
2908 XtVaSetValues(hl->field_widget,
2913 // Reset the Log state in case the user happened to change it.
2914 DtMail::Session *m_session = theRoamApp.session()->session();
2915 const char * logfile = NULL;
2916 const char * value = NULL;
2919 m_session->mailRc(error)->getValue(error, "record", &logfile);
2921 _file_log->deactivate();
2923 _file_log->activate();
2925 m_session->mailRc(error)->getValue(error, "dontlogmessages", &value);
2926 if (logfile == NULL || error.isNotSet()) {
2927 // logfile is not specified or "dontlogmessages" is TRUE
2928 setLogState(DTM_FALSE);
2929 ((ToggleButtonCmd *)_file_log)->setButtonState(FALSE, TRUE);
2931 // logfile is specified and "dontlogmessages" is FALSE
2932 setLogState(DTM_TRUE);
2933 ((ToggleButtonCmd *)_file_log)->setButtonState(TRUE, TRUE);
2936 if (NULL != logfile)
2937 free((void*) logfile);
2939 free((void*) value);
2942 // Recycles Compose window.
2944 SendMsgDialog::quit(Boolean delete_win)
2947 // There are several ways we could have reached here.
2948 // 1) From the user choosing Send.
2949 // 2) From the user clicking on the Close button or Close menu item
2950 // 3) The user choosing Close from window manager menu.
2951 // For (1), we just forge ahead. For that, the _takeDown boolean
2952 // is set in send_message() method.
2953 // For (2), the boolean is set in goAway().
2954 // For (3), we call goAway() which sets the _takeDown depending on
2955 // a dialog negotiation if SMD has contents.
2957 if (_file_include->fileBrowser() != NULL)
2958 XtPopdown(XtParent(_file_include->fileBrowser()));
2959 if (_att_add->fileBrowser() != NULL)
2960 XtPopdown(XtParent(_att_add->fileBrowser()));
2962 if (_file_save_as->fileBrowser() != NULL)
2963 XtPopdown(XtParent(_file_save_as->fileBrowser()));
2964 if (_att_save->fileBrowser() != NULL)
2965 XtPopdown(XtParent(_att_save->fileBrowser()));
2968 // Check to see if it's the first time through the quit()
2969 // method. Set _first_time to FALSE so that we don't come
2970 // down this path again until we're done quitting or bad
2971 // things will happen.
2972 if (_first_time == TRUE) {
2973 _first_time = FALSE;
2975 // We're done quitting, so we can set _first_time to TRUE again.
2983 #ifdef DTMAIL_TOOLTALK
2984 // For explanation of dtmail_mapped, look at RoamApp.h.
2985 if ( started_by_tt && (0 == theCompose.getTimeOutId()) &&
2986 (theCompose.numUnusedWindows() == theCompose.numCreatedWindows()) &&
2990 id = XtAppAddTimeOut(
2991 theApplication->appContext(),
2992 (unsigned long)DESTRUCT_TIMEOUT,
2993 Self_destruct, NULL);
2994 theCompose.putTimeOutId(id);
3003 theCompose.putWin(this, FALSE);
3007 // If there are no composer timeouts, check if its time to shutdown.
3009 if (0 == theCompose.getTimeOutId()) theRoamApp.checkForShutdown();
3013 SendMsgDialog::panicQuit()
3016 // Need to make sure the message is still valid before proceeding.
3017 // ::reset may have been called so the message may no longer be valid.
3026 // Given a file name, include the file as attachment.
3028 SendMsgDialog::inclAsAttmt(char *file, char *name)
3030 this->get_editor()->attachArea()->addAttachment(_msgHandle, _lastAttBP,
3032 this->setLastAttBP();
3036 // Given a buffer, include its content as an attachment.
3038 SendMsgDialog::inclAsAttmt(unsigned char *contents, int len, char *name)
3042 mbuf.buffer = (void *)contents;
3043 mbuf.size = (unsigned long)len;
3044 this->get_editor()->attachArea()->addAttachment(_msgHandle, _lastAttBP,
3045 (String)name, mbuf);
3046 this->setLastAttBP();
3049 // Given a RFC_822_Message formatted buffer, parse it and fill the Compose Window.
3051 SendMsgDialog::parseNplace(char *contents, int len)
3053 // 1. Create message handle for contents
3056 DtMail::Session * d_session = theRoamApp.session()->session();
3059 mbuf.buffer = (void *)contents;
3060 mbuf.size = (unsigned long)len;
3062 DtMail::Message * msg = d_session->messageConstruct(error,
3070 } else if ( error.isSet() ) {
3071 if ( (DTMailError_t) error == DTME_UnknownFormat ) {
3072 // The content does not have header info. Therefore, store
3073 // everything as text.
3074 _my_editor->textEditor()->set_contents((const char *)mbuf.buffer,
3080 char * status_string;
3081 DtMailBoolean first_bp_handled;
3082 first_bp_handled = _my_editor->textEditor()->set_message(
3088 int num_bodyParts = msg->getBodyCount(error);
3090 // Don't use setInclMsgHnd() because it causes the SMD's attachments
3091 // to get out of sink with the BE. Just assign the newly created message
3094 if ((num_bodyParts > 1) || (!first_bp_handled)) {
3096 if (first_bp_handled) {
3098 // setInclMsgHnd(msg, TRUE);
3102 // setInclMsgHnd(msg, FALSE);
3109 _my_editor->attachArea()->parseAttachments(error,
3114 // Need to call this after calling parseAttachments() so attachments
3115 // will be displayed in the attachment pane.
3116 _my_editor->manageAttachArea();
3118 // Need to update this compose window's internal message handle.
3120 // GL - calling updateMsgHndAtt is no longer necessary because we
3121 // just assigning the newly created msg to _msgHandle.
3122 // updateMsgHndAtt();
3125 loadHeaders(msg, DTM_TRUE);
3128 // Given a RFC_822_Message formatted file, parse it and fill the Compose Window.
3130 SendMsgDialog::parseNplace(const char * path)
3132 // 1. Get file content into buffer.
3133 int fd = SafeOpen(path, O_RDONLY);
3139 if (SafeFStat(fd, &buf) < 0) {
3144 _dead_letter_buf = new char[buf.st_size];
3145 if (!_dead_letter_buf) {
3150 if (SafeRead(fd, _dead_letter_buf,
3151 (unsigned int) buf.st_size) != buf.st_size) {
3152 delete _dead_letter_buf;
3157 parseNplace(_dead_letter_buf, (int) buf.st_size);
3161 SendMsgDialog::text( const char *text )
3163 _my_editor->textEditor()->set_contents( text, strlen(text) );
3167 SendMsgDialog::append( const char *text )
3169 _my_editor->textEditor()->append_to_contents( text, strlen(text) );
3173 SendMsgDialog::text()
3175 // Potential memory leak here. Because XmTextGetString returns
3176 // pointer to space containing all the text in the widget. Need
3177 // to call XtFree after we use this space
3178 // Also DtEditor widget requires application to free data.
3180 return (_my_editor->textEditor()->get_contents());
3186 SendMsgDialog::text_selected()
3188 // turn on sensitivity for Cut/Clear/Copy/Delete
3189 _edit_cut->activate();
3190 _edit_copy->activate();
3191 _edit_clear->activate();
3192 _edit_delete->activate();
3193 _edit_select_all->activate();
3197 SendMsgDialog::text_unselected()
3199 // turn off sensitivity for those items
3200 _edit_cut->deactivate();
3201 _edit_copy->deactivate();
3202 _edit_clear->deactivate();
3203 _edit_delete->deactivate();
3209 SendMsgDialog::attachment_selected()
3211 _att_save->activate();
3212 _att_delete->activate();
3213 _att_rename->activate();
3218 SendMsgDialog::all_attachments_selected()
3220 _att_delete->activate();
3221 _att_save->deactivate();
3222 _att_rename->deactivate();
3224 if (_attachmentActionsList != NULL) {
3225 _menuBar->removeCommands(_attachmentMenu, _attachmentActionsList);
3226 _menuPopupAtt->removeCommands(_attachmentPopupMenu,
3227 _attachmentActionsList);
3228 delete _attachmentActionsList;
3229 _attachmentActionsList = NULL;
3236 SendMsgDialog::all_attachments_deselected()
3238 _att_save->deactivate();
3239 _att_delete->deactivate();
3240 _att_rename->deactivate();
3242 if (_attachmentActionsList != NULL) {
3243 _menuBar->removeCommands(_attachmentMenu, _attachmentActionsList);
3244 _menuPopupAtt->removeCommands(_attachmentPopupMenu,
3245 _attachmentActionsList);
3246 delete _attachmentActionsList;
3247 _attachmentActionsList = NULL;
3254 SendMsgDialog::addAttachmentActions(
3261 AttachmentActionCmd *attachActionCmd;
3263 if (_attachmentActionsList == NULL) {
3264 _attachmentActionsList = new CmdList("AttachmentActions", "AttachmentActions");
3267 _menuBar->removeCommands(_attachmentMenu, _attachmentActionsList);
3268 _menuPopupAtt->removeCommands(_attachmentPopupMenu,
3269 _attachmentActionsList);
3270 delete _attachmentActionsList;
3271 _attachmentActionsList = new CmdList("AttachmentActions", "AttachmentActions");
3275 for (i = 0; i < indx; i++) {
3276 anAction = actions[i];
3277 actionLabel = DtActionLabel(anAction); // get the localized action label
3278 attachActionCmd = new AttachmentActionCmd(
3283 _attachmentActionsList->add(attachActionCmd);
3286 _attachmentMenu = _menuBar->addCommands(
3288 _attachmentActionsList
3290 _attachmentPopupMenu = _menuPopupAtt->addCommands(
3291 _attachmentPopupMenu,
3292 _attachmentActionsList
3297 SendMsgDialog::removeAttachmentActions()
3300 // Stubbed out for now
3304 SendMsgDialog::invokeAttachmentAction(
3308 DtMailEditor *editor = this->get_editor();
3309 AttachArea *attacharea = editor->attachArea();
3310 Attachment *attachment = attacharea->getSelectedAttachment();
3312 attachment->invokeAction(index);
3316 SendMsgDialog::selectAllAttachments()
3319 DtMailEditor *editor = this->get_editor();
3320 AttachArea *attachArea = editor->attachArea();
3322 attachArea->selectAllAttachments();
3328 SendMsgDialog::activate_default_attach_menu()
3330 _att_select_all->activate();
3334 SendMsgDialog::deactivate_default_attach_menu()
3336 _att_select_all->deactivate();
3341 SendMsgDialog::delete_selected_attachments()
3343 DtMailEnv mail_error;
3345 // Initialize the mail_error.
3349 AttachArea *attachArea = _my_editor->attachArea();
3350 attachArea->deleteSelectedAttachments(mail_error);
3352 if (mail_error.isSet()) {
3356 // Activate this button to permit the user to undelete.
3358 _att_undelete->activate();
3360 // Deactivate buttons that will be activated when another
3361 // selection applies.
3363 _att_save->deactivate();
3364 _att_delete->deactivate();
3365 _att_rename->deactivate();
3367 if (_attachmentActionsList) {
3368 _menuBar->removeCommands(_attachmentMenu, _attachmentActionsList);
3369 _menuPopupAtt->removeCommands(_attachmentPopupMenu,
3370 _attachmentActionsList);
3371 delete _attachmentActionsList;
3372 _attachmentActionsList = NULL;
3377 SendMsgDialog::undelete_last_deleted_attachment()
3379 DtMailEnv mail_error;
3381 // Initialize the mail_error.
3385 AttachArea *attachArea = _my_editor->attachArea();
3386 attachArea->undeleteLastDeletedAttachment(mail_error);
3388 if (mail_error.isSet()) {
3392 if(_my_editor->attachArea()->getIconSelectedCount())
3393 _att_delete->activate();
3395 if (attachArea->getDeleteCount() == 0) {
3396 _att_undelete->deactivate();
3401 SendMsgDialog::renameAttachmentOK()
3403 AttachArea *attachArea = _my_editor->attachArea();
3405 if (attachArea->getIconSelectedCount() > 1) {
3406 char *buf = new char[512];
3408 sprintf(buf, "%s", GETMSG(DT_catd, 5, 4, "Select only one attachment\n\
3409 and then choose rename"));
3411 _genDialog->setToQuestionDialog(
3412 GETMSG(DT_catd, 5, 2, "Mailer"),
3415 char * helpId = DTMAILHELPSELECTONEATTACH;
3417 int answer = _genDialog->post_and_return(helpId);
3428 SendMsgDialog::showAttachArea()
3430 DtMailEditor *editor = this->get_editor();
3431 editor->showAttachArea();
3432 ((ToggleButtonCmd *)_att_show_pane)->setButtonState(TRUE, FALSE);
3436 SendMsgDialog::hideAttachArea()
3438 DtMailEditor *editor = this->get_editor();
3439 editor->hideAttachArea();
3440 ((ToggleButtonCmd *)_att_show_pane)->setButtonState(FALSE, FALSE);
3444 SendMsgDialog::lookupHeader(const char * name)
3446 for (int h = 0; h < _header_list.length(); h++) {
3447 HeaderList * hl = _header_list[h];
3448 if (hl->show != SMD_NEVER &&
3449 strcmp(hl->label, name) == 0) {
3458 SendMsgDialog::headerValueChanged(Widget,
3459 XtPointer client_data,
3462 SendMsgDialog * self = (SendMsgDialog *)client_data;
3463 self->_headers_changed = DTM_TRUE;
3467 SendMsgDialog::reattachHeaders(void)
3469 // We have to walk through the entire list of headers, attaching
3470 // the shown headers to the ones above them.
3472 HeaderList * hl = _header_list[0];
3473 Widget previous_form = hl->form_widget;
3475 for (int h = 1; h < _header_list.length(); h++) {
3476 hl = _header_list[h];
3480 previous_form = hl->form_widget;
3484 XtVaSetValues(hl->form_widget,
3485 XmNtopAttachment, XmATTACH_WIDGET,
3486 XmNtopWidget, previous_form,
3488 previous_form = hl->form_widget;
3496 forceFormResize(_main_form);
3497 forceFormResize(_header_form);
3501 SendMsgDialog::justifyHeaders(void)
3503 // Find out which header label has the longest display width to right
3504 // justify all labels.
3506 Dimension longest = 0;
3509 for (int count = 0; count < _header_list.length(); count++) {
3510 HeaderList * hl = _header_list[count];
3511 if (hl->show == SMD_HIDDEN || hl->show == SMD_NEVER) {
3515 XtVaGetValues(hl->label_widget,
3517 XmNmarginLeft, &margin,
3520 if ( w > longest ) {
3525 for (int adjust = 0; adjust < _header_list.length(); adjust++) {
3526 HeaderList * hl = _header_list[adjust];
3527 if (hl->show == SMD_HIDDEN || hl->show == SMD_NEVER) {
3531 XtVaGetValues(hl->label_widget,
3533 XmNmarginLeft, &margin,
3536 XtVaSetValues(hl->label_widget, XmNmarginLeft, (longest-w) > 0 ? longest-w : 1, NULL );
3541 SendMsgDialog::forceFormResize(Widget form)
3543 // The Motif Form widget is at least a little bit brain damaged.
3544 // We need to convince it to do the right thing after we make
3545 // minor adjustments in the children.
3547 Dimension width, height, border;
3551 XmNborderWidth, &border,
3555 XmNwidth, width + 1,
3556 XmNheight, height + 1,
3567 SendMsgDialog::unfilled_headers()
3569 // Walk through the headers. See if any of them have a value.
3571 for (int scan = 0; scan < _header_list.length(); scan++) {
3572 HeaderList * hl = _header_list[scan];
3573 if (hl->show != SMD_ALWAYS && hl->show != SMD_SHOWN) {
3577 char * value = NULL;
3578 XtVaGetValues(hl->field_widget,
3582 if (strlen(value) > 0) {
3592 // Method checks if self has text in it.
3595 SendMsgDialog::checkDirty()
3597 if (this->unfilled_headers() &&
3598 (this->get_editor()->textEditor()->no_text()) &&
3599 (this->get_editor()->attachArea()->getIconCount() == 0) ) {
3601 // return FALSE so quit() can go ahead.
3612 SendMsgDialog::handleQuitDialog()
3616 DtMail::Session *m_session = theRoamApp.session()->session();
3617 const char * value = NULL;
3620 m_session->mailRc(error)->getValue(error, "expert", &value);
3621 if (error.isNotSet() && value != NULL)
3624 free((void*) value);
3629 DtMailGenDialog *dialog = this->genDialog();
3631 dialog->setToQuestionDialog(
3641 "The Compose window contains text or\n\
3642 attachments that will be lost if\n\
3643 the window is closed.\n\
3644 Close the Compose window?")
3646 helpId = DTMAILHELPCLOSECOMPOSEWINDOW;
3647 if ( dialog->post_and_return(
3658 helpId) == 1 ) { // Close selected
3663 return(FALSE); // Cancel selected
3668 SendMsgDialog::goAway(
3669 Boolean checkForDirty
3673 if (!checkForDirty) {
3678 // Check to see if self has contents (ie., is dirty)
3680 Boolean is_dirty = this->checkDirty();
3683 if (isIconified()) {
3684 MainWindow::manage();
3687 // Enquire if user really wants this window to go away
3689 Boolean really_quit = this->handleQuitDialog();
3700 SendMsgDialog::manage()
3702 MenuWindow::manage();
3704 HeaderList * hl = _header_list[0];
3705 (void) XmProcessTraversal(hl->field_widget, XmTRAVERSE_CURRENT);
3710 SendMsgDialog::unmanage()
3712 MenuWindow::unmanage();
3713 XFlush(XtDisplay(this->_main_form));
3714 XSync(XtDisplay(this->_main_form), False);
3720 _compose_head = NULL;
3728 Compose::Compose_Win *a_node;
3729 Compose::Compose_Win *next_node;
3731 theRoamApp.registerPendingTask();
3733 a_node = _compose_head;
3736 next_node = a_node->next;
3737 if (!a_node->in_use)
3740 free((void*) a_node);
3745 theRoamApp.unregisterPendingTask();
3749 Compose::putWin(SendMsgDialog *smd, Boolean in_use)
3751 Compose::Compose_Win* a_node = NULL;
3752 Compose::Compose_Win *tmp = NULL;
3755 // Update the _not_in_use count.
3761 // Check to see if compose window is already in the list.
3763 for (a_node = _compose_head; a_node; a_node=a_node->next)
3765 if (a_node->win == smd)
3767 a_node->in_use = in_use;
3772 // Need new node with smd.
3773 tmp = (Compose::Compose_Win *)malloc(sizeof(Compose::Compose_Win));
3776 tmp->in_use = in_use;
3778 // If nothing is cached so far, add this Compose window to the head.
3779 if (NULL == _compose_head)
3781 _compose_head = tmp;
3785 // There exists a cache. Add this compose window to the tail.
3786 for (a_node=_compose_head; a_node; a_node=a_node->next)
3788 if (NULL == a_node->next)
3797 Compose::getUnusedWin()
3799 if (NULL == _compose_head) return NULL;
3801 Compose::Compose_Win* a_node = NULL;
3802 Compose::Compose_Win* the_node = NULL;
3804 // Find a node with unused smd. Return smd
3805 for (a_node=_compose_head; a_node; a_node=a_node->next)
3807 if (!a_node->in_use)
3809 a_node->in_use = TRUE;
3818 // Get a compose window either by creating a new SendMsgDialog or
3819 // from the recycle list.
3823 SendMsgDialog *newsend = NULL;
3825 #ifdef DTMAIL_TOOLTALK
3828 XtRemoveTimeOut(_timeout_id);
3833 newsend = getUnusedWin();
3837 // We have no unused SMDs around; therefore, create new window.
3838 theRoamApp.busyAllWindows();
3839 newsend = new SendMsgDialog();
3840 newsend->initialize();
3842 putWin(newsend, TRUE);
3843 theRoamApp.unbusyAllWindows();
3847 newsend->resetHeaders();
3848 newsend->displayInCurrentWorkspace();
3851 newsend->text_unselected();
3853 newsend->startAutoSave();
3855 // Get new Message Handle
3856 newsend->setMsgHnd();
3857 char *ttl = GETMSG(DT_catd, 1, 160, "New Message");
3858 newsend->setTitle(ttl);
3859 newsend->setIconTitle(ttl);
3865 SendMsgDialog::setTitle(char *subject)
3867 char *format = "%s - %s";
3868 char *prefix = GETMSG(DT_catd, 1, 6, "Mailer");
3872 len = strlen(format) + strlen(prefix) + strlen(subject) + 1;
3873 new_title = new char[len];
3874 sprintf(new_title, format, prefix, subject);
3877 delete [] new_title;
3881 SendMsgDialog::resetHeaders(void)
3883 DtMail::Session *m_session = theRoamApp.session()->session();
3884 const char * value = NULL;
3888 m_session->mailRc(error)->getValue(error, "additionalfields", &value);
3890 // Return if no props were applied and headers did not change.
3891 if ((_additionalfields == NULL && value == NULL) ||
3892 ( _additionalfields != NULL && value != NULL &&
3893 strcmp (_additionalfields, value) == 0))
3896 free((void*) value);
3901 // User changed the Header list via props. Recreate list
3904 // First hide all shown headers
3905 for (i=0; i < _header_list.length(); i++) {
3906 HeaderList * hl = _header_list[i];
3907 if (hl->show == SMD_SHOWN) {
3908 hl->show = SMD_HIDDEN;
3909 XtUnmanageChild(hl->form_widget);
3913 // Now remove the old list.
3914 DtVirtArray<PropStringPair *> results(8);
3915 parsePropString(_additionalfields, results);
3916 for (i=0, j=results.length(); i < j; i++) {
3917 PropStringPair * psp = results[i];
3918 int slot = lookupHeader(psp->label);
3919 // dont allow removal of default headers.
3920 HeaderList * hl = _header_list[slot];
3921 if (!reservedHeader(hl->label)) {
3923 hl->show = SMD_NEVER;
3925 else if (hl->value != NULL) {
3930 while(results.length()) {
3931 PropStringPair * psp = results[0];
3936 if (_additionalfields != NULL)
3937 free(_additionalfields);
3938 if (value != NULL && *value != '\0')
3939 _additionalfields = strdup(value);
3941 _additionalfields = NULL;
3943 parsePropString(value, results);
3946 for (j=results.length(), i=0; i < j; i++) {
3947 PropStringPair * psp = results[i];
3948 int slot = lookupHeader(psp->label);
3951 HeaderList * hl = _header_list[slot];
3952 if (!reservedHeader(hl->label))
3953 hl->show = SMD_HIDDEN;
3954 if (hl->value != NULL) {
3958 if (psp->value != NULL)
3959 hl->value = strdup(psp->value);
3962 HeaderList * copy_hl = new HeaderList;
3963 copy_hl->label = strdup(psp->label);
3964 copy_hl->header = strdup(psp->label);
3966 copy_hl->value = strdup(psp->value);
3967 copy_hl->show = SMD_HIDDEN;
3968 _header_list.append(copy_hl);
3970 while(results.length()) {
3971 PropStringPair * psp = results[0];
3976 createHeaders(_header_form);
3977 doDynamicHeaderMenus();
3980 free((void*) value);
3984 SendMsgDialog::setInputFocus(const int mode)
3988 HeaderList * hl = _header_list[0];
3989 (void) XmProcessTraversal(hl->field_widget, XmTRAVERSE_CURRENT);
3991 else if (mode == 1) {
3992 Widget edWid = _my_editor->textEditor()->get_editor();
3993 (void) XmProcessTraversal(edWid, XmTRAVERSE_CURRENT);
3998 SendMsgDialog::attachmentFeedback(
4006 this->normalCursor();
4011 SendMsgDialog::hasAddressee()
4015 DtMail::Envelope * env = _msgHandle->getEnvelope(error);
4017 // Walk through the headers.
4018 // Return TRUE if the message has a value for either of the
4019 // following headers: To:, Cc:, or Bcc:.
4020 // Return FALSE if none of the three headers have any value.
4022 for (int scan = 0; scan < _header_list.length(); scan++) {
4023 HeaderList * hl = _header_list[scan];
4024 if (hl->show != SMD_ALWAYS && hl->show != SMD_SHOWN) {
4027 if ((strcmp(hl->label, "To") == 0) ||
4028 (strcmp(hl->label, "Cc") == 0) ||
4029 (strcmp(hl->label, "Bcc") == 0)) {
4030 char * value = NULL;
4031 XtVaGetValues(hl->field_widget,
4035 for (char *cv = value; *cv; cv++) {
4036 if (!isspace(*cv)) {
4038 return(TRUE); // text value contains contents
4041 XtFree(value); // text value is "content free" - try the next one
4045 return(FALSE); // no field has contents