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: RoamApp.C /main/62 1999/09/14 16:52:18 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 * Common Desktop Environment
45 * (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
46 * (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
47 * (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
48 * (c) Copyright 1993, 1994, 1995 Novell, Inc.
49 * (c) Copyright 1995 Digital Equipment Corp.
50 * (c) Copyright 1995 Fujitsu Limited
51 * (c) Copyright 1995 Hitachi, Ltd.
54 * RESTRICTED RIGHTS LEGEND
56 *Use, duplication, or disclosure by the U.S. Government is subject to
57 *restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in
58 *Technical Data and Computer Software clause in DFARS 252.227-7013. Rights
59 *for non-DOD U.S. Government Departments and Agencies are as set forth in
60 *FAR 52.227-19(c)(1,2).
62 *Hewlett-Packard Company, 3000 Hanover Street, Palo Alto, CA 94304 U.S.A.
63 *International Business Machines Corp., Route 100, Somers, NY 10589 U.S.A.
64 *Sun Microsystems, Inc., 2550 Garcia Avenue, Mountain View, CA 94043 U.S.A.
65 *Novell, Inc., 190 River Road, Summit, NJ 07901 U.S.A.
66 *Digital Equipment Corp., 111 Powdermill Road, Maynard, MA 01754, U.S.A.
67 *Fujitsu Limited, 1015, Kamikodanaka Nakahara-Ku, Kawasaki 211, Japan
68 *Hitachi, Ltd., 6, Kanda Surugadai 4-Chome, Chiyoda-ku, Tokyo 101, Japan
73 #if defined(USL) || defined(__uxp__) || defined(linux) || defined(CSRG_BASED)
75 #include <wctype.h> // iswspace is defined in this header on USL */
78 #ifdef DTMAIL_TOOLTALK
81 #include "SendMsgDialog.h"
84 #if defined(POSIX_THREADS)
91 #include <sys/param.h>
95 #include <Xm/MessageB.h>
97 #include <Dt/Action.h>
99 #include <Dt/DtPStrings.h>
101 #include <Dt/EnvControlP.h>
103 #include <DtMail/Common.h>
104 #include <DtMail/DtMailError.hh>
105 #include <DtMail/DtMailSigChld.h>
106 #include <DtMail/IO.hh>
107 #include <DtMail/OptCmd.h>
109 #include "DmxPrintJob.h"
110 #include "DtMailGenDialog.hh"
111 #include "DtMailHelp.hh"
112 #include "EUSDebug.hh"
114 #include "MemUtils.hh"
117 #include "RoamMenuWindow.h"
118 #include "RoamCmds.h"
119 #include "SendMsgDialog.h"
120 #include "WorkingDialogManager.h"
123 int use_XmTextEditor = 0;
127 // Provide interface to the DtSvc function DtSimpleError
128 // When this interface is better defined, this can be removed
129 // and replaced with the appropriate include file
140 extern "C" void _DtSimpleError(
148 extern "C" int _DtPrintDefaultErrorSafe(
154 static int x_error_handler(Display *display, XErrorEvent* error_event)
156 #define _DTMAIL_BUFSIZE 1024
157 char error_msg[_DTMAIL_BUFSIZE];
160 _DtPrintDefaultErrorSafe(display, error_event, error_msg, _DTMAIL_BUFSIZE);
161 _DtSimpleError("dtmail", DtWarning, NULL, error_msg, NULL);
163 // if the error occured on the print display we're going to set
164 // a variable so that and when the job is done, right before calling
165 // XpEndJob, we call XpCancelJob, and notify the user.
167 if (theRoamApp.isActivePrintDisplay(display) &&
168 error_event->error_code == BadAlloc)
170 theRoamApp.setErrorPrintDisplay(display);
174 theRoamApp._default_x_error_handler(display, error_event);
184 XWindowAttributes xwa;
186 XtAppContext cxt=XtWidgetToApplicationContext( w );
190 dpy=XtDisplay(shell);
191 window=XtWindow( shell );
193 while ( XGetWindowAttributes(dpy,window,&xwa)) {
194 if ( XGetWindowAttributes( dpy, window, &xwa ) &&
195 xwa.map_state != IsViewable )
198 XtAppNextEvent( cxt, &event );
199 XtDispatchEvent( &event );
201 XmUpdateDisplay(shell);
205 forceUpdate( Widget w )
207 Widget diashell, topshell;
208 Window diawindow, topwindow;
209 XtAppContext cxt = XtWidgetToApplicationContext( w );
211 XWindowAttributes xwa;
214 for (diashell=w;!XtIsShell(diashell);diashell=XtParent(diashell));
215 for ( topshell=diashell;XtIsTopLevelShell( topshell );
216 topshell = XtParent( topshell ) );
218 dpy=XtDisplay(diashell);
219 diawindow=XtWindow( diashell );
220 topwindow=XtWindow(topshell);
221 while ( XGetWindowAttributes(dpy,diawindow,&xwa)
222 && XEventsQueued( dpy, QueuedAlready) ) {
224 XtAppNextEvent( cxt, &event );
225 XtDispatchEvent( &event );
227 XmUpdateDisplay(topshell);
231 RoamApp::_resources[] = {
237 XtOffset ( RoamApp *, _print_script ),
246 XtOffset ( RoamApp *, _mailfiles_folder ),
255 XtOffset ( RoamApp *, _default_mailbox ),
266 XtOffset ( RoamApp *, _user_font ),
268 ( XtPointer )"-b&h-lucidatypewriter-medium-r-*-sans-*-120-*-*-*-*-*-*",
271 // Fixed width fontlist
276 sizeof( XmFontList ),
277 XtOffset ( RoamApp *, _user_fontlist ),
279 ( XtPointer )"-b&h-lucidatypewriter-medium-r-*-sans-*-120-*-*-*-*-*-*",
282 // Variable width font
288 XtOffset ( RoamApp *, _system_font ),
290 ( XtPointer )"-b&h-lucida-medium-r-*-sans-*-120-*-*-*-*-*-*"
293 // Variable width fontlist
298 sizeof( XmFontList ),
299 XtOffset ( RoamApp *, _system_fontlist ),
301 ( XtPointer )"-b&h-lucida-medium-r-*-sans-*-120-*-*-*-*-*-*"
304 // Font used for attachment glyph
310 XtOffset ( RoamApp *, _glyph_font ),
318 RoamApp theRoamApp("Dtmail");
319 int just_compose = 0;
324 theRoamApp.quitSilently();
325 theRoamApp.closeAllWindows();
330 panicQuitSignalHandler()
332 panicQuitSignalHandler(int)
335 theRoamApp.setQuitQuickly();
336 theRoamApp.setQuitSilently();
337 theRoamApp.closeAllWindows();
342 RoamApp::closeAllWindows(void)
344 // Remove callbacks to prevent XtPhase2Destroy crashes.
345 XtRemoveAllCallbacks(baseWidget(), XmNdestroyCallback);
347 for (int win = 0; win < _numWindows; win++)
349 _windows[win]->panicQuit();
350 else if (quitSilently())
351 _windows[win]->quit();
353 _windows[win]->quit();
359 RoamApp::statusCallback(DtMailOperationId, DtMailEnv &error, void *)
362 // fprintf(stderr, "DEBUG: statusCallback(): Submission failed error = %d\n", error._major);
364 // fprintf(stderr, "DEBUG: statusCallback(): Submission done.%s\n");
368 #ifdef DTMAIL_TOOLTALK
370 int started_by_tt = 0;
371 // Move this to constructor of RoamMenuWindow???
372 int dtmail_mapped = 0; // For explanation, look in RoamApp.h.
373 static int roam_tt_fd = 0;
374 char *roam_tt_procid = NULL;
375 Tt_pattern *roam_tt_pattern = NULL;
377 // Report ToolTalk error
378 int dieFromTtError(Tt_status errid, char *procname, char *errmsg, char *helpid)
380 /* Do not die on warnings or TT_OK */
381 if ( tt_is_err(errid) )
383 char *title = GETMSG(DT_catd, 2, 1, "Mailer");
384 char *errmsg = tt_status_message(errid);
391 GETMSG(DT_catd, 2, 30, "%s returned ToolTalk error: %s\n"),
392 procname, tt_status_message(errid));
394 DtMailGenDialog *exit_dialog = new DtMailGenDialog(
396 theApplication->baseWidget());
397 exit_dialog->setToErrorDialog(title, errmsg);
398 if (NULL == helpid) helpid = DTMAILHELPERROR;
399 exit_dialog->post_and_return(GETMSG(DT_catd, 1, 1, "OK"), helpid);
401 XtRemoveAllCallbacks(theApplication->baseWidget(), XmNdestroyCallback);
407 Tt_message attachmt_msg_handler(
412 unsigned char *contents,
417 static const char *thisFcn = "attachmt_msg_handler()";
418 Tt_status status = TT_OK;
420 SendMsgDialog *compose;
422 if ( diag != TT_OK ) {
423 // Toolkit detected an error
424 // Let toolkit handle error
428 pattern = ttdt_message_accept(msg, NULL, (Widget)0, client_data, 1, 1);
429 dieFromTtError(tt_ptr_error(pattern),
430 "attachmt_msg_handler.ttdt_message_accept", NULL, NULL);
432 if ( op == TTME_MAIL_EDIT ) {
433 status = tt_message_reply(msg);
434 dieFromTtError(status,
435 "attachmt_msg_handler.tt_message_reply", NULL, NULL);
437 // Put the data that is coming in (via buffer or file) as
438 // the attachment of a message.
439 if ( len > 0 ) { // Pass by content
440 compose = theCompose.getWin();
441 compose->inclAsAttmt(contents, len, docname);
443 compose->setTitle(docname);
444 compose->setIconTitle(docname);
446 } else if ( file != NULL ) { // Pass by filename
447 compose = theCompose.getWin();
448 compose->inclAsAttmt(file, docname);
450 compose->setTitle(docname);
451 compose->setIconTitle(docname);
453 } else { // DO NOTHING.
454 // This is not an entry point to bring up a blank compose window
455 // because ttMediaLoadPatCB() returns with diagnosis =
456 // TT_DESKTOP_ENODATA. For INOUT mode, it expects file or buffer.
459 status = tttk_message_fail( msg, TT_DESKTOP_ENOTSUP, 0, 1 );
460 dieFromTtError(status,
461 "tooltalk_msg_handler.tttk_message_fail", NULL, NULL);
465 // Not sure if these should be freed.
467 // tt_free( (caddr_t)contents );
469 // tt_free( docname );
474 typedef struct _msg_handler_done_cb_struct
478 RoamMenuWindow *roamWin;
480 } MsgHandlerDoneCbData;
483 tooltalk_msg_handler_done_cb( Widget w, XtPointer client_data, XtPointer )
485 MsgHandlerDoneCbData *cbData = (MsgHandlerDoneCbData *) client_data;
486 Tt_status status = TT_OK;
488 status = tt_message_reply(cbData->msg);
489 dieFromTtError(status,
490 "tooltalk_msg_handler_done_cb.tt_message_reply", NULL, NULL);
494 XtNdestroyCallback, tooltalk_msg_handler_done_cb,
497 cbData->roamApp->unregisterPendingTask();
498 if (NULL != cbData->roamWin)
500 cbData->roamWin->quit(TRUE);
501 delete cbData->roamWin;
503 XtFree((char*) cbData);
506 static char *tooltalk_save_buffer_to_file(
507 unsigned char *contents,
511 char *tmpdir = new char[MAXPATHLEN+1];
513 // 1. Get buffer content into file.
514 sprintf(tmpdir, "%s/%s", getenv("HOME"), DtPERSONAL_TMP_DIRECTORY);
515 p = tempnam(tmpdir, "mail");
522 int fd = SafeOpen(p, O_RDWR | O_CREAT);
529 if (SafeWrite(fd, contents, len) != len)
541 tooltalk_msg_handler(
546 unsigned char *contents,
552 static const char *thisFcn = "RoamApp::tooltalk_msg_handler()";
553 Tt_status status = TT_OK;
554 SendMsgDialog *compose;
555 RoamApp *roamapp = (RoamApp *) client_data;
558 if ( diag != TT_OK ) {
559 // toolkit detected an error
560 // Let toolkit handle error
564 // Need to check the return value of this call.
566 pattern = ttdt_message_accept(msg, NULL, (Widget)0, client_data, 1, 1);
567 dieFromTtError(tt_ptr_error(pattern),
568 "tooltalk_msg_handler.ttdt_message_accept", NULL, NULL);
570 if ( op == TTME_MAIL ) {
572 status = tt_message_reply(msg);
573 dieFromTtError(status,
574 "tooltalk_msg_handler.tt_message_reply", NULL, NULL);
576 // Construct message handle
579 mbuf.buffer = (void *)contents;
580 mbuf.size = (unsigned long)len;
581 } else if ( file != NULL ) {
582 // 1. Get file content into buffer.
583 int fd = SafeOpen(file, O_RDONLY);
588 if (SafeFStat(fd, &buf) < 0) {
593 mbuf.buffer = new char[buf.st_size];
599 if (SafeRead(fd, mbuf.buffer,
600 (unsigned int) buf.st_size) != buf.st_size) {
601 delete [] mbuf.buffer;
605 mbuf.size = (unsigned long)buf.st_size;
608 DtMail::Session *d_session = theRoamApp.session()->session();
609 DtMail::Message *msgHandle = d_session->messageConstruct(
616 if ( error.isSet() || !msgHandle ) {
621 theRoamApp.default_transport()->submit(error, msgHandle,
622 (DtMailBoolean)FALSE);
624 } else if ( op == TTME_MAIL_COMPOSE ) {
625 // Bring up blank compose window.
626 status = tt_message_reply(msg);
627 dieFromTtError(status,
628 "tooltalk_msg_handler.tt_message_reply", NULL, NULL);
630 compose = theCompose.getWin();
632 compose->setTitle(docname);
633 compose->setIconTitle(docname);
635 } else if ( op == TTME_MAIL_EDIT ) {
636 // Bring up compose window with given data filled in.
637 status = tt_message_reply(msg);
638 dieFromTtError(status,
639 "tooltalk_msg_handler.tt_message_reply", NULL, NULL);
641 // Parse data (coming in as buffer or file)
642 if ( len > 0 ) { // Pass by content
643 compose = theCompose.getWin();
644 compose->parseNplace((char *)contents, len);
646 compose->setTitle(docname);
647 compose->setIconTitle(docname);
649 } else if ( file != NULL ) { // Pass by filename
650 compose = theCompose.getWin();
651 compose->parseNplace(file);
653 compose->setTitle(docname);
654 compose->setIconTitle(docname);
658 // This is not an entry point to bring up a blank compose window
659 // because ttMediaLoadPatCB() returns with diagnosis =
660 // TT_DESKTOP_ENODATA. For INOUT mode, it expects file or buffer.
662 } else if ( op == TTME_DISPLAY ) {
664 char *opname = tt_message_op(msg);
666 // It is the Display message.
667 // Since the compose window can be started independent of
668 // RoamMenuWindow, a DtMail process may be around
669 // (because of a compose window). Then if a DtMail process
670 // exists (ToolTalk will not start another DtMail process),
671 // that process needs to respond to this DISPLAY message.
672 // If for some reason, the view of the specified mail folder
673 // is unmapped, then need to map it. Otherwise, create the
674 // view for the specified mail folder. Need to remove self
675 // destruct when using an existing DtMail process if that
676 // process was started by compose.
678 // This is the wrong place to reply to this message.
679 // Replying here causes the action layer to think that
680 // it is ok to remove the file it passed in, but we
681 // are not done with it yet. Calling tt_message_reply
682 // at the end of this function doesn't work either. We
683 // are just not going to reply to this tooltalk message
684 // (tooltalk folks say this is ok) for the time being.
685 if (! strcmp("Display", opname)) {
686 MailSession *ses = theRoamApp.session();
687 RoamMenuWindow *roamwin = NULL;
689 if ( theApplication == NULL ) {
691 fprintf(stdout, "%s: theApplication is NULL\n", thisFcn);
697 fprintf(stdout, "%s: TTME_DISPLAY\n", thisFcn);
700 if ( theCompose.getTimeOutId() != 0 )
701 XtRemoveTimeOut(theCompose.getTimeOutId());
706 DtMailEnv mail_error;
707 DtMailObjectSpace space;
708 DtMail::Session *d_session = theRoamApp.session()->session();
710 char *str = (char*) malloc(len + 1);
712 memcpy(str, contents, len);
715 if (0 == strcmp("DTMAIL_INBOX", str))
718 d_session->queryImpl(
720 d_session->getDefaultImpl(mail_error),
721 DtMailCapabilityInboxName,
730 file = tooltalk_save_buffer_to_file(contents, len);
731 if (NULL == file) return msg;
735 // Check to see if the mbox is already open. If it is, we will
736 // simply make sure it's displayed in the current workspace.
737 if (ses->isMboxOpen(file))
740 roamwin = ses->getRMW(file);
741 ses->activateRMW(roamwin);
742 if (NULL != roamwin) roamwin->displayInCurrentWorkspace();
746 roamwin = new RoamMenuWindow(file);
747 roamwin->initialize();
751 MsgHandlerDoneCbData *cbData;
753 cbData = (MsgHandlerDoneCbData*)
754 XtMalloc(sizeof(MsgHandlerDoneCbData));
756 cbData->roamApp = roamapp;
757 cbData->roamWin = NULL;
758 XtAddCallback(roamwin->GetMainWin(),
760 tooltalk_msg_handler_done_cb,
762 roamapp->registerPendingTask();
764 // Set this to True so Self_destruct()
765 // would not be started by Compose.
767 } else if (! strcmp("Print", opname)) {
771 p = tooltalk_save_buffer_to_file(contents, len);
772 if (NULL == p) return msg;
773 } else if (file != NULL) {
780 MsgHandlerDoneCbData *cbData = NULL;
782 DmxPrintJob *pjob = NULL;
783 RoamMenuWindow *roamwin = NULL;
784 MailSession *ses = theRoamApp.session();
787 (MsgHandlerDoneCbData*) XtMalloc(sizeof(MsgHandlerDoneCbData));
788 if (ses->isMboxOpen(file))
791 roamwin = ses->getRMW(file);
792 ses->activateRMW(roamwin);
793 if (NULL != roamwin) roamwin->displayInCurrentWorkspace();
795 cbData->roamWin = NULL;
799 roamwin = new RoamMenuWindow(file);
800 roamwin->initialize();
802 roamwin->list()->select_all_and_display_last(error);
804 cbData->roamWin = roamwin;
807 pjob = new DmxPrintJob(p, DTM_FALSE, (MainWindow*) roamwin);
810 cbData->roamApp = roamapp;
811 XtAddCallback(pjob->baseWidget(),
813 tooltalk_msg_handler_done_cb,
815 roamapp->registerPendingTask();
819 MainWindow *mw = roamapp->defaultStatusWindow();
822 char *buf = new char[1024];
823 sprintf(buf, "Printing %s", p);
828 status = tt_message_reply(msg);
829 dieFromTtError(status,
830 "tooltalk_msg_handler.tt_message_reply", NULL, NULL);
834 status = tttk_message_fail( msg, TT_DESKTOP_ENOTSUP, 0, 1 );
835 dieFromTtError(status,
836 "tooltalk_msg_handler.tttk_message_fail", NULL, NULL);
839 // tt_free( (caddr_t)contents );
841 // tt_free( docname );
846 quit_message_cb(Tt_message m,
850 static const char *thisFcn = "quit_message_cb()";
854 // int mark = tt_mark();
856 char *op = tt_message_op(m);
857 if ( tttk_string_op(op) == TTDT_QUIT ) {
860 status = tt_message_arg_ival(m, 0, &silent);
861 if ( status != TT_OK ) {
862 fprintf(stderr, "DEBUG: %s: tt_message_arg_ival(0): %s\n",
863 thisFcn, tt_status_message(status));
870 status = tt_message_arg_ival(m, 1, &force);
871 if ( status != TT_OK ) {
872 fprintf(stderr, "DEBUG: %s: tt_message_arg_ival(1): %s\n",
873 thisFcn, tt_status_message(status));
880 RoamApp *app = (RoamApp *)client_data;
881 // Need to make the following call; otherwise, will
882 // run into Phase2Destroy
883 XtRemoveAllCallbacks(app->baseWidget(),
897 reload_notify_cb(XtPointer)
899 DebugPrintf(2, "reload_notify_cb: Reloading types database\n");
902 #endif /* DTMAIL_TOOLTALK */
909 int pid = (int) wait(&status);
911 ChildExitNotify(pid, status);
913 #endif /* DEAD_WOOD */
916 void pspace_signal( int )
918 Widget parent=theApplication->baseWidget();
921 DtMailGenDialog *genDialog = new DtMailGenDialog("Dialog",parent);
923 char *errMsg = (char *) XtCalloc(1,10240);
925 // Serious error here -- No Space on Filesystem --
926 sprintf(errMsg,"Insufficient paging space, \n Mailer cannot perform any operations.\n Please contact the System Administrator to \n correct the paging space problem ");
927 genDialog->setToErrorDialog(
928 GETMSG(DT_catd, 1, 6, "Mailer"),
932 genDialog->post_and_return(
933 GETMSG(DT_catd, 3, 9, "OK"),
938 printf("Insufficient paging space, \n Mailer cannot perform any operations.\n Please contact the System Administrator to \n correct the paging space problem ");
945 Usage(char *progname)
947 printf("Usage: %s\n", progname);
948 printf("[-h] Help\n");
949 printf("[-c] A blank compose window comes up.\n");
950 printf("[-a file1 ... fileN] Compose window comes up with file1 through fileN as attachments.\n");
951 printf("[-f mailfile] The specified mail folder is displayed instead of INBOX.\n");
952 printf("[-l] Start the compose window on a dead letter file.\n");
954 // There is also a "-e" option which would run dtmail with the XmTextEditor
955 // instead of DtEditor. Right now it is an undocumented feature.
958 nl_catd DT_catd = (nl_catd) -1; // catgets file descriptor
960 #if defined(reallyoldsun) || defined(USL)
961 #define SA_HANDLER_TYPE void (*)(void)
963 #define SA_HANDLER_TYPE void (*)(int)
966 void RoamApp::initialize(int *argcp, char **argv)
969 struct sigaction *action;
970 struct sigaction action_buf;
974 _firstSaveYourselfArrived = FALSE;
976 _optionsHandle = NULL;
977 _quitSilently = FALSE;
978 _quitQuickly = FALSE;
979 _shutdownWorkprocID = 0;
982 char * mail_file = NULL;
983 char * dead_letter = NULL;
984 char *session_file = NULL;
989 signal(SIGUSR1, (void(*)(int ...))SigUsr1);
991 signal(SIGUSR1, SigUsr1);
995 (void)signal( SIGDANGER, pspace_signal );
998 action = &action_buf;
999 memset((void*) action, 0, sizeof(struct sigaction));
1000 action->sa_handler = (SA_HANDLER_TYPE) panicQuitSignalHandler;
1001 action->sa_flags = 0;
1002 sigaction(SIGHUP, action, NULL);
1003 sigaction(SIGINT, action, NULL);
1004 sigaction(SIGQUIT, action, NULL);
1005 sigaction(SIGILL, action, NULL);
1006 sigaction(SIGABRT, action, NULL);
1007 sigaction(SIGBUS, action, NULL);
1008 sigaction(SIGSEGV, action, NULL);
1009 sigaction(SIGTERM, action, NULL);
1011 // Must be called before XtAppInitialize.
1012 XtSetLanguageProc(NULL, NULL, NULL);
1014 // Set up environment variable (including NLSPATH) before calling
1015 // XtAppInitialize() (cmvc 6576).
1016 _DtEnvControl (DT_ENV_SET);
1018 // This will take care of standard arguments such as -display.
1019 Application::initialize(argcp,argv);
1021 // If -session arg is present remove it and return session file name.
1022 session_file = parseSessionArg(argcp, argv);
1024 // export display and locale settings
1026 static char displayenv[256]; /* Needs to be static for putenv */
1027 sprintf(displayenv, "DISPLAY=%s", XDisplayString(_display));
1030 // Process dtmail opt args.
1032 int num_legit_args = 0;
1034 while((opt = getopt(*argcp, argv, "a:cef:hl:t")) != EOF) {
1046 use_XmTextEditor = 1;
1051 mail_file = strdup(optarg);
1058 dead_letter = optarg;
1062 // Started by ToolTalk
1071 // Remove cbs else face Phase2Destroy!
1072 XtRemoveAllCallbacks(baseWidget(), XmNdestroyCallback);
1079 if(!just_compose && !started_by_tt && !mail_file && session_file)
1080 openSessionFile(session_file); // Open the session file
1083 getResources( _resources, XtNumber ( _resources ) );
1085 DtInitialize(XtDisplay(baseWidget()), baseWidget(), argv[0], "Dtmail");
1087 // Must be called after XtSetLanguageProc and DtInitialize because
1088 // DtInitialize sets the environment variable NLSPATH which is used
1089 // in catopen(). That's why we have to take out catopen from
1090 // Application::initialize and put a new mathod open->catalog for
1091 // both Application and RoamApp
1092 this->open_catalog();
1094 // Initialize the mail_error. This also has to be done after DtInitialize
1095 // because the DtMailEnv consturctor calls catopen as well.
1096 DtMailEnv mail_error;
1102 // Some of the scrolling lists contain formatted text and thus
1103 // require a fixed width font to display the text correctly.
1104 // We want to use the fixed width font defined by dt.userFont as
1105 // it will be internationalized correctly. If it is not there
1106 // we fall back to a fixed width lucida font. If that fails
1107 // we let the widget fallback to what ever it thinks is best.
1110 // Default font in case we can't find anything else.
1111 XrmDatabase db = XtScreenDatabase(XtScreen(baseWidget()));
1115 char *buf = new char[1024];
1118 // Need to check fixed width font mailrc variable. Assume
1123 XrmPutStringResource(
1124 &db, "*Work_Area*XmText.fontList", _user_font);
1125 XrmPutStringResource(
1126 &db, "*Work_Area*XmTextField.fontList", _user_font);
1128 XrmPutStringResource(
1129 &db, "*Work_Area*DtEditor.textFontList", _user_font);
1130 XrmPutStringResource(
1131 &db, "*Work_Area*iconGadget.fontList", _user_font);
1132 XrmPutStringResource(
1133 &db, "*XmDialogShell*XmList.FontList", _user_font);
1135 // Convert the user fontlist to a font.
1136 if (!fontlist_to_font(_user_fontlist, &userfont)) {
1137 if (!(userfont.f.cf_font = XLoadQueryFont(
1138 XtDisplay(baseWidget()),
1140 /* Couldn't convert the user fontlist to a font */
1143 "RoamApp::initialize : error loading fixed font\n");
1145 userfont.cf_type = XmFONT_IS_FONT;
1150 FontType systemfont;
1152 XrmPutStringResource(
1153 &db, "*Work_Area*Text*fontList", _system_font);
1154 XrmPutStringResource(
1155 &db, "*Work_Area*iconGadget*fontList", _system_font);
1156 XrmPutStringResource(
1157 &db, "*Work_Area*Text*textFontList", _system_font);
1158 XrmPutStringResource(
1159 &db, "*XmDialogShell*XmList*FontList", _system_font);
1161 if (!fontlist_to_font(_system_fontlist, &systemfont)) {
1162 /* Couldn't convert the system fontlist to a font */
1163 if (!(systemfont.f.cf_font = XLoadQueryFont(
1164 XtDisplay(baseWidget()),
1168 "RoamApp::initialize : error loading variable font\n");
1170 systemfont.cf_type = XmFONT_IS_FONT;
1176 // If the glyph font is specified in a resource file, use it.
1178 _glyph_name = XtNewString(_glyph_font);
1182 // If the glyph font hasn't been specified, try to match it with
1185 // Get the font name that matches the user font pixel size.
1186 load_app_font(baseWidget(), &userfont, &_glyph_name);
1189 // Create a fontlist that contains the glyph and user fonts
1190 strcpy(buf, _user_font);
1192 // Never refer to the "plain" tag so dont add it.
1193 if (strchr(_user_font, '=') == NULL) {
1195 strcat(buf, "=plain, ");
1198 // If the symbol font can't be found, use user font above
1201 strcat(buf, _glyph_name);
1202 strcat(buf, "=attach");
1205 // Loosely bind font to message list. This lets users override
1206 // with a more strongly bound name (ie "Dtmail*Message_List*FontList");
1208 // Matches the MsgScrollingList in the RoamMenuWindows.
1209 XrmPutStringResource(&db, "*Message_List*FontList", buf);
1212 // Matches the UndelMsgScrollingList in the UndelFromListDialog
1213 // and overrides the "*XmDialogShell*XmList*FontList" spec above.
1214 XrmPutStringResource(&db, "*XmDialogShell*Message_List*FontList", buf);
1219 // If we don't have a mail file yet, then we need to retrieve the
1220 // Initialize Tooltalk
1221 // NOTE: For now, must make the FIRST ttdt_open call to be the proc_id
1222 // that will respond to the start message. Therefore, call gui's
1223 // ttdt_open before libDtMail calls its.
1226 sess = (char *)getenv("TT_SESSION");
1227 if (!sess || (*sess == '\0')) {
1228 sess = getenv("_SUN_TT_SESSION");
1230 if (!sess || (*sess == '\0')) {
1231 tt_default_session_set(tt_X_session(XDisplayString(_display)));
1234 roam_tt_procid = ttdt_open( &roam_tt_fd, "DTMAIL", "SunSoft", "%I", 1 );
1235 dieFromTtError(tt_ptr_error(roam_tt_procid),
1236 "initialize.ttdt_open",
1237 GETMSG(DT_catd, 2, 2, "ToolTalk is not initialized. Mailer cannot run without ToolTalk.\nTry starting /usr/dt/bin/dtsession, or contact your System Administrator."),
1238 DTMAILHELPCANTINITTOOLTALK);
1240 // This is for supporting old ptype where RFC_822_Message is
1242 status = ttmedia_ptype_declare( "RFC_822_Message",
1244 tooltalk_msg_handler,
1247 dieFromTtError(status,
1248 "initialize.ttmedia_ptype_declare.RFC_822_Message", NULL, NULL);
1250 status = ttmedia_ptype_declare( "RFC_822_MESSAGE",
1252 tooltalk_msg_handler,
1255 dieFromTtError(status,
1256 "initialize.ttmedia_ptype_declare.RFC_822_MESSAGE", NULL, NULL);
1258 status = ttmedia_ptype_declare( "MAIL_TYPE",
1260 attachmt_msg_handler,
1263 dieFromTtError(status,
1264 "initialize.ttmedia_ptype_declare.MAIL_TYPE", NULL, NULL);
1266 /* Join the default session -- This should have been done by default */
1267 roam_tt_pattern = ttdt_session_join(
1269 (Ttdt_contract_cb)quit_message_cb,
1270 baseWidget(), this, 1);
1271 dieFromTtError(tt_ptr_error(roam_tt_pattern),
1272 "initialize.ttdt_session_join", NULL, NULL);
1274 _mail_session = new MailSession(mail_error, Application::appContext());
1275 if (mail_error.isSet()) {
1276 // what do we do here? there are no windows for dialogs
1277 // should we just register a syslog() and exit? ugggh
1279 fprintf(stderr, "RoamApp::initialize : error creating MailSession\n");
1284 // .mailrc parsing error checking
1286 DtMail::Session * d_session = _mail_session->session();
1287 DtMail::MailRc* mailRc = d_session->mailRc(mail_error);
1288 DTMailError_t pErr = mailRc->getParseError();
1289 if (pErr != DTME_NoError) {
1291 DtMailGenDialog *mailrc_dialog = new DtMailGenDialog(
1293 theApplication->baseWidget());
1294 mailrc_dialog->setToQuestionDialog(
1295 GETMSG(DT_catd, 2, 1, "Mailer"),
1296 GETMSG(DT_catd, 2, 22,
1297 "There were unrecoverable syntax errors found in the ~/.mailrc file.\nCheck for more messages on terminal. Fix the errors and restart dtmail.\nIf you choose to continue you will not be able to save any changes made\nin the options dialog to file.") );
1298 helpId = DTMAILHELPERROR;
1299 answer = mailrc_dialog->post_and_return(
1300 GETMSG(DT_catd, 2, 23, "Continue"),
1301 GETMSG(DT_catd, 2, 24, "Exit"),
1304 XtRemoveAllCallbacks(
1305 theApplication->baseWidget(),
1306 XmNdestroyCallback);
1313 // Check if mailer is installed properly if we are not in debugging mode.
1315 const char *value = NULL;
1317 d_session->mailRc(mail_error)->getValue(mail_error,
1318 "__ignore_group_permissions",
1320 if (mail_error.isSet()) {
1324 theApplication->enableGroupPrivileges();
1325 GetGroupName(grp_name);
1326 theApplication->disableGroupPrivileges();
1327 if (strcmp(grp_name, DTMAIL_DEFAULT_CREATE_MAILGROUP))
1328 mail_error.setError(DTME_BadRunGroup);
1331 if ((DTMailError_t)mail_error == DTME_BadRunGroup) {
1335 DtMailGenDialog *install_errDialog =
1336 new DtMailGenDialog("Dialog", theApplication->baseWidget());
1337 sprintf(buf, "%s", GETMSG(DT_catd, 2, 4,
1338 "Mailer has not been properly installed,\n\
1339 and cannot run because the execution group\n\
1340 is incorrectly set."));
1342 install_errDialog->setToErrorDialog(
1343 GETMSG(DT_catd, 1, 6, "Mailer"),
1346 // No choice at this state other than to OK.
1347 helpId = DTMAILHELPBADGROUPID;
1348 answer = install_errDialog->post_and_return(
1349 GETMSG(DT_catd, 3, 9, "OK"),
1351 XtRemoveAllCallbacks(
1352 theApplication->baseWidget(),
1353 XmNdestroyCallback);
1359 free((void*) value);
1361 _options = new OptCmd("Mail Options...",
1362 GETMSG(DT_catd, 1, 2,"Mail Options..."),
1366 if ( just_compose ) {
1367 // Need to install self destruct
1368 SendMsgDialog *compose = theCompose.getWin();
1371 char *ttl = GETMSG(DT_catd, 1, 262, "Dead Letter Message");
1372 compose->loadDeadLetter(dead_letter);
1373 compose->setTitle(ttl);
1374 compose->setIconTitle(ttl);
1377 if ( *argcp > num_legit_args + 1) { // Have attachment(s)
1378 for ( int k = num_legit_args + 1; k < *argcp; k++ ) {
1379 compose->inclAsAttmt(argv[k], NULL);
1385 // inbox. We do this by querying the current implementation for
1386 // the path to its inbox.
1389 DtMailObjectSpace space;
1391 d_session->queryImpl(mail_error,
1392 d_session->getDefaultImpl(mail_error),
1393 DtMailCapabilityInboxName,
1398 // We need to determine which transport to use. The order of preference
1401 // 1) The value of DEFAULT_TRANSPORT in the .mailrc file.
1403 // 2) The value of DEFAULT_TRANSPORT in the environment.
1405 // 3) The transport, if available for the default implementation.
1407 // 4) The first implementation that provides a transport.
1409 const char * trans_impl = NULL;
1411 d_session->mailRc(mail_error)->getValue(mail_error,
1412 "DEFAULT_TRANSPORT",
1414 if (mail_error.isSet()) {
1420 trans_impl = getenv("DEFAULT_TRANSPORT");
1424 trans_impl = d_session->getDefaultImpl(mail_error);
1426 DtMailBoolean trans;
1428 d_session->queryImpl(mail_error, trans_impl,
1429 DtMailCapabilityTransport, &trans);
1430 if (mail_error.isSet() || trans == DTM_FALSE) {
1436 const char ** impls = d_session->enumerateImpls(mail_error);
1438 for (int impl = 0; impls[impl]; impl++) {
1439 DtMailBoolean trans;
1440 d_session->queryImpl(mail_error, impls[impl],
1441 DtMailCapabilityTransport, &trans);
1442 if (!mail_error.isSet() || trans == DTM_TRUE) {
1443 trans_impl = impls[impl];
1450 _mail_transport = d_session->transportConstruct(mail_error,
1456 _mail_transport = NULL;
1459 // Register all callbacks the backend may have to deal with
1461 d_session->registerLastInteractiveEventTimeCallback(lastInteractiveEventTime, this);
1463 // These callbacks are only needed on systems where sendmail is run as
1464 // 'root', and so has access permissions to any file on the system.
1465 d_session->registerDisableGroupPrivilegesCallback(disableGroupPrivileges, this);
1466 d_session->registerEnableGroupPrivilegesCallback(enableGroupPrivileges, this);
1468 if (d_session->pollRequired(mail_error) == DTM_TRUE) {
1469 d_session->registerBusyCallback(mail_error, setBusyState, this);
1470 _appTimeoutId = XtAppAddTimeOut(
1471 XtWidgetToApplicationContext( _w ),
1473 &RoamApp::applicationTimeout,
1477 // Process the message that started us, if any. Should I pass in
1478 // roam_tt_procid or NULL.
1479 tttk_Xt_input_handler( 0, 0, 0 );
1480 XtAppAddInput( Application::appContext(), roam_tt_fd,
1481 (XtPointer)XtInputReadMask,
1482 tttk_Xt_input_handler, roam_tt_procid );
1484 // Get the vacation handle before the new RoamMenuWindow
1485 // This is for setting the Vacation title stripe on the window
1486 _vacation = new VacationCmd("Vacation", GETMSG(DT_catd, 1, 3, "Vacation"));
1488 // DtMail only supports the "Mail" message.
1489 // If DtMail is started by ToolTalk, then we assume that the
1490 // client wants a Compose window. Therefore, we do not
1491 // bring up a RoamMenuWindow.
1493 if ( !session_fp && !started_by_tt && !just_compose) {
1495 _mailview = new RoamMenuWindow(mail_file);
1496 _mailview->initialize();
1497 _mailview->manage();
1507 _dialog = new DtMailGenDialog("Dialog", _w);
1509 DtDbReloadNotify(reload_notify_cb, (XtPointer) NULL);
1510 _default_x_error_handler = XSetErrorHandler(x_error_handler);
1511 if (NULL != mail_file)
1512 free((void*) mail_file);
1515 RoamApp::RoamApp(char *name) : Application (name), _activePrintDisplays(5)
1517 DebugPrintf(2, "RoamApp::RoamApp(%p \"%s\")\n", name, name);
1521 // Let the destructor of parent Application class handle the
1526 #ifdef DTMAIL_TOOLTALK
1527 if ( roam_tt_procid != NULL ) {
1529 // Temporary workaround to get PrintToFile to work.
1530 // Currently, PrintToFile forks a child which is
1531 // calling ~RoamApp when it exits. This clobbers
1532 // the tooltalk connection causing the parent to hang.
1534 ttdt_close(0, 0, 1);
1535 roam_tt_procid = NULL;
1541 XtRemoveTimeOut(_appTimeoutId);
1545 RoamApp::shutdownWorkproc(XtPointer client_data)
1547 RoamApp *thisApp = (RoamApp*) client_data;
1549 if (thisApp->_numPendingTasks > 0)
1552 if (thisApp->_shutdownWorkprocID != 0)
1554 XtRemoveWorkProc(thisApp->_shutdownWorkprocID);
1555 thisApp->_shutdownWorkprocID = 0;
1558 delete thisApp->_mail_session;
1560 // Delete this and let the parent class's destructor call exit(0)
1569 if (_numPendingTasks > 0)
1571 if (_shutdownWorkprocID == 0)
1572 _shutdownWorkprocID = XtAppAddWorkProc(
1574 &RoamApp::shutdownWorkproc,
1578 shutdownWorkproc((XtPointer) this);
1582 RoamApp::checkForShutdown()
1584 int nappwin, ncompunused, nrmwunused;
1586 if (! theApplication->isEnabledShutdown()) return;
1587 nappwin = theApplication->num_windows();
1588 ncompunused = theCompose.numUnusedWindows();
1589 nrmwunused = theRoamApp.session()->numDeactivatedRMW();
1591 if (nappwin == ncompunused + nrmwunused)
1593 theCompose.~Compose();
1594 while (_numWindows > 0)
1602 RoamApp::applicationTimeout( XtPointer client_data,
1605 RoamApp *app = ( RoamApp * ) client_data;
1610 RoamApp::timeout( XtIntervalId * )
1612 DtMail::Session * d_session = _mail_session->session();
1615 d_session->poll(error);
1617 _appTimeoutId = XtAppAddTimeOut(
1618 XtWidgetToApplicationContext( _w ),
1620 &RoamApp::applicationTimeout,
1625 RoamApp::lastInteractiveEventTime(void * client_data)
1627 RoamApp * self = (RoamApp *)client_data;
1628 return (theApplication->lastInteractiveEventTime());
1632 RoamApp::disableGroupPrivileges(void * client_data)
1634 RoamApp * self = (RoamApp *)client_data;
1635 theApplication->disableGroupPrivileges();
1640 RoamApp::enableGroupPrivileges(void * client_data)
1642 RoamApp * self = (RoamApp *)client_data;
1643 theApplication->enableGroupPrivileges();
1649 RoamApp::setBusyState(
1651 DtMailBusyState busy_state,
1654 static const int MAXBUSYSTATES=20;
1655 static int busyStateStackTop = 0;
1656 static DtMailBusyState busyStateStack[MAXBUSYSTATES] =
1657 {DtMailBusyState_NotBusy};
1658 RoamApp *self = (RoamApp*) client_data;
1662 case DtMailBusyState_AutoSave:
1663 case DtMailBusyState_NewMail:
1665 showBusyState(error, busy_state, client_data);
1666 // if (busyStateStackTop) // Already busy from previous message?
1667 // self->_busy_count--; // Decrement busy count for
1668 // displaying this message
1669 busyStateStack[++busyStateStackTop] = busy_state;
1670 assert(busyStateStackTop < MAXBUSYSTATES);
1673 case DtMailBusyState_NotBusy:
1674 if (busyStateStackTop)
1677 self->_mailview->postErrorDialog(error);
1679 busy_state = busyStateStack[--busyStateStackTop];
1680 showBusyState(error, busy_state, client_data);
1681 // if (busyStateStackTop)
1682 // self->_busy_count--; // Decrement busy count for
1683 // redisplaying this message
1686 showBusyState(error, busy_state, client_data);
1689 assert(busyStateStack[0] == DtMailBusyState_NotBusy);
1693 RoamApp::showBusyState(
1695 DtMailBusyState busy_state,
1699 RoamApp * self = (RoamApp *)client_data;
1703 case DtMailBusyState_AutoSave:
1704 self->busyAllWindows(GETMSG(DT_catd, 3, 1, "Auto-saving..."));
1707 case DtMailBusyState_NewMail:
1708 self->busyAllWindows(GETMSG(DT_catd, 3, 86, "Checking for new mail..."));
1711 case DtMailBusyState_NotBusy:
1713 self->unbusyAllWindows();
1719 RoamApp::busyAllWindows(const char * msg)
1721 for (int win = 0; win < _numWindows; win++) {
1722 // if (_busy_count == 0) {
1723 _windows[win]->busyCursor();
1726 _windows[win]->setStatus(msg);
1733 RoamApp::unbusyAllWindows(void)
1736 // if (_busy_count == 0) {
1737 for (int win = 0; win < _numWindows; win++) {
1738 _windows[win]->normalCursor();
1739 _windows[win]->clearStatus();
1745 RoamApp::globalAddToCachedContainerList(char *destname)
1748 RoamMenuWindow *rmw;
1750 for (int win = 0; win < _numWindows; win++) {
1751 cname = _windows[win]->className();
1752 if (strcmp(cname, "RoamMenuWindow") == 0) {
1753 rmw = (RoamMenuWindow *)_windows[win];
1754 rmw->addToCachedContainerList(destname);
1760 RoamApp::globalPropChange(void)
1762 busyAllWindows(GETMSG(DT_catd, 1, 4, "Updating properties..."));
1764 for (int win = 0; win < _numWindows; win++) {
1765 _windows[win]->propsChanged();
1772 RoamApp::genDialog()
1779 RoamApp::startVacation(
1786 RoamMenuWindow *rmw;
1790 XtVaGetValues(subject_tf,
1794 XtVaGetValues(text_tp,
1798 status = _vacation->startVacation((char *)subj, (char *) text);
1800 for (int win = 0; win < _numWindows; win++) {
1801 cname = _windows[win]->className();
1802 if (strcmp(cname, "RoamMenuWindow") == 0) {
1803 rmw = (RoamMenuWindow *)_windows[win];
1804 rmw->setVacationTitle();
1811 RoamApp::stopVacation()
1814 RoamMenuWindow *rmw;
1816 _vacation->stopVacation();
1818 for (int win = 0; win < _numWindows; win++) {
1819 cname = _windows[win]->className();
1820 if (strcmp(cname, "RoamMenuWindow") == 0) {
1821 rmw = (RoamMenuWindow *)_windows[win];
1822 rmw->removeVacationTitle();
1828 getPropStringValue(DtVirtArray<PropStringPair *> &results, const char *label)
1830 for (int mrc = 0; mrc < results.length(); mrc++) {
1831 PropStringPair * psp = results[mrc];
1832 if (strcmp(label, psp->label) == 0)
1833 return strdup(psp->value);
1839 parsePropString(const char * input, DtVirtArray<PropStringPair *> & results)
1844 // If it's not multibyte, use the regular string function
1845 if (MB_CUR_MAX <= 1) {
1846 const char * start = input;
1851 while (isspace(*start)) {
1855 for (end = start; end && *end; end++)
1856 if (isspace(*end) && *(end-1) != '\\')
1859 PropStringPair * new_pair = new PropStringPair;
1861 int len = end - start;
1862 char * label = new char[len + 5];
1863 strncpy(label, start, len);
1865 for (ptr = label; (ptr = strstr(ptr, "\\ ")); ptr++)
1868 char * file = strchr(label, ':');
1870 new_pair->label = strdup(label);
1871 new_pair->value = NULL;
1875 new_pair->label = strdup(label);
1878 if (strlen(file) == 0) {
1879 new_pair->value = NULL;
1882 new_pair->value = strdup(file);
1886 results.append(new_pair);
1891 while (*start && isspace(*start)) {
1895 } while(*start && *end);
1899 // The string can contain multibyte characters and it must be converted to
1900 // wide character string before parsing
1901 int len = strlen(input);
1902 wchar_t *wc_input= new wchar_t[len+1];
1903 mbstowcs(wc_input, input, len+1);
1904 const wchar_t *start = wc_input;
1909 while (iswspace(*start)) {
1913 for (end = start; end && *end; end++)
1914 if (iswspace(*end) && *(end-1) != (wint_t)'\\')
1916 PropStringPair * new_pair = new PropStringPair;
1918 int wclen = end - start;
1919 wchar_t *wc_label = new wchar_t[wclen+1];
1920 wcsncpy(wc_label, start, wclen);
1921 wc_label[wclen] = (wint_t)'\0';
1923 // Search the string "\ " and take out the back slash
1924 wchar_t esc_space[3];
1925 mbstowcs(esc_space, "\\ ", 3);
1926 for (ptr = wc_label; (ptr = wcswcs(ptr, esc_space)); ptr++)
1929 wchar_t *file = wcschr(wc_label, (wint_t)':');
1931 new_pair->label = new char[(wclen+1)*MB_CUR_MAX];
1932 wcstombs(new_pair->label, wc_label, wclen+1);
1933 new_pair->value = NULL;
1938 *file = (wint_t)'\0';
1939 new_pair->label = new char[(wclen+1)*MB_CUR_MAX];
1940 wcstombs(new_pair->label, wc_label, (wclen+1)*MB_CUR_MAX);
1943 int filelen = wcslen(file);
1945 new_pair->value = NULL;
1948 new_pair->value = new char[(filelen+1)*MB_CUR_MAX];
1949 wcstombs(new_pair->value, file, (filelen+1)*MB_CUR_MAX);
1953 results.append(new_pair);
1957 while (*start && iswspace(*start)) {
1961 } while(*start && *end);
1967 PropStringPair::PropStringPair(void)
1973 PropStringPair::PropStringPair(const PropStringPair & other)
1979 label = strdup(other.label);
1983 value = strdup(other.value);
1987 PropStringPair::~PropStringPair(void)
1999 RoamApp::setSession( MailSession *session )
2001 _mail_session = session;
2011 char *formatPropPair(char * key, const void * data)
2013 char *formatted_str = NULL;
2014 char *white_space = NULL;
2015 int i, num_spaces = 0;
2016 int key_len = strlen(key);
2022 // figure out whitespace for formatting
2023 // assume 13 for normal sized alias name
2025 if(key_len < 13) // need to add spaces
2027 num_spaces = 13 - key_len;
2029 white_space = (char *)malloc(num_spaces + 1);
2030 strcpy(white_space, "\0");
2032 for(i = 0; i < num_spaces; i++)
2033 strcat(white_space, " ");
2035 m_size = key_len + strlen((char *)white_space)
2036 + strlen((char *)data) + strlen(" = ") + 1;
2037 formatted_str = (char *)malloc(m_size);
2039 sprintf(formatted_str, "%s%s = %s",key, white_space, (const char *) data);
2044 /* make an alias string */
2045 formatted_str = (char *)malloc(key_len + strlen((const char *)data) + 2);
2047 m_size = key_len + strlen((const char *)data) + strlen(" = ") + 1;
2048 formatted_str = (char *)malloc(m_size);
2050 sprintf(formatted_str, "%s = %s",key, (const char *) data);
2054 return formatted_str;
2059 RoamApp::inboxWindow()
2061 RoamMenuWindow *rmw;
2064 for (int win = 0; win < _numWindows; win++) {
2065 cname = _windows[win]->className();
2066 if (strcmp(cname, "RoamMenuWindow") == 0) {
2067 rmw = (RoamMenuWindow *)_windows[win];
2077 RoamApp::nextRoamMenuWindow(RoamMenuWindow *last)
2079 RoamMenuWindow *looking_for = last;
2080 RoamMenuWindow *rmw;
2083 for (int win = 0; win < _numWindows; win++) {
2084 cname = _windows[win]->className();
2085 if (strcmp(cname, "RoamMenuWindow") == 0) {
2086 rmw = (RoamMenuWindow *)_windows[win];
2087 if (NULL == looking_for)
2089 if (rmw == looking_for)
2097 RoamApp::closeInactiveRoamMenuWindows(void)
2099 MailSession *ses = theRoamApp.session();
2100 RoamMenuWindow **rmws;
2104 rmws = (RoamMenuWindow**) malloc(_numWindows * sizeof(RoamMenuWindow *));
2105 for (win=0; win<_numWindows; win++)
2107 cname = _windows[win]->className();
2108 if (strcmp(cname, "RoamMenuWindow") == 0)
2109 rmws[nrmws++] = (RoamMenuWindow*) _windows[win];
2112 for (win=0; win<nrmws; win++)
2113 if (! ses->isActiveRMW(rmws[win])) rmws[win]->quit(TRUE);
2119 RoamApp::reopenRoamMenuWindows(void)
2121 RoamMenuWindow *rmw, **rmws;
2125 theApplication->disableShutdown();
2127 rmws = (RoamMenuWindow**) malloc(_numWindows * sizeof(RoamMenuWindow *));
2128 for (win=0; win<_numWindows; win++)
2130 cname = _windows[win]->className();
2131 if (strcmp(cname, "RoamMenuWindow") == 0)
2132 rmws[nrmws++] = (RoamMenuWindow*) _windows[win];
2135 for (win=0; win<nrmws; win++)
2139 name = strdup(rmw->mailboxName());
2142 rmw = new RoamMenuWindow(name);
2149 theApplication->enableShutdown();
2153 RoamApp::defaultStatusWindow()
2155 MainWindow *mw = NULL;
2157 if ((mw = (MainWindow *) _mailview) != NULL)
2159 if ((mw = (MainWindow *) inboxWindow()) != NULL)
2161 if (_numWindows > 0)
2162 mw = (MainWindow *) _windows[0];
2168 RoamApp::open_catalog()
2170 Application::open_catalog(); // Open Motif Application message catalog file
2171 DT_catd = catopen(DTMAIL_CAT, NL_CAT_LOCALE); // Open DtMail message catalog file