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 void RoamApp::initialize(int *argcp, char **argv)
963 struct sigaction *action;
964 struct sigaction action_buf;
968 _firstSaveYourselfArrived = FALSE;
970 _optionsHandle = NULL;
971 _quitSilently = FALSE;
972 _quitQuickly = FALSE;
973 _shutdownWorkprocID = 0;
976 char * mail_file = NULL;
977 char * dead_letter = NULL;
978 char *session_file = NULL;
983 signal(SIGUSR1, (void(*)(int ...))SigUsr1);
985 signal(SIGUSR1, SigUsr1);
989 (void)signal( SIGDANGER, pspace_signal );
992 action = &action_buf;
993 memset((void*) action, 0, sizeof(struct sigaction));
995 action->sa_handler = (void (*)())panicQuitSignalHandler;
997 action->sa_handler = panicQuitSignalHandler;
999 action->sa_flags = 0;
1000 sigaction(SIGHUP, action, NULL);
1001 sigaction(SIGINT, action, NULL);
1002 sigaction(SIGQUIT, action, NULL);
1003 sigaction(SIGILL, action, NULL);
1004 sigaction(SIGABRT, action, NULL);
1005 sigaction(SIGBUS, action, NULL);
1006 sigaction(SIGSEGV, action, NULL);
1007 sigaction(SIGTERM, action, NULL);
1009 // Must be called before XtAppInitialize.
1010 XtSetLanguageProc(NULL, NULL, NULL);
1012 // Set up environment variable (including NLSPATH) before calling
1013 // XtAppInitialize() (cmvc 6576).
1014 _DtEnvControl (DT_ENV_SET);
1016 // This will take care of standard arguments such as -display.
1017 Application::initialize(argcp,argv);
1019 // If -session arg is present remove it and return session file name.
1020 session_file = parseSessionArg(argcp, argv);
1022 // export display and locale settings
1024 static char displayenv[256]; /* Needs to be static for putenv */
1025 sprintf(displayenv, "DISPLAY=%s", XDisplayString(_display));
1028 // Process dtmail opt args.
1030 int num_legit_args = 0;
1032 while((opt = getopt(*argcp, argv, "a:cef:hl:t")) != EOF) {
1044 use_XmTextEditor = 1;
1049 mail_file = strdup(optarg);
1056 dead_letter = optarg;
1060 // Started by ToolTalk
1069 // Remove cbs else face Phase2Destroy!
1070 XtRemoveAllCallbacks(baseWidget(), XmNdestroyCallback);
1077 if(!just_compose && !started_by_tt && !mail_file && session_file)
1078 openSessionFile(session_file); // Open the session file
1081 getResources( _resources, XtNumber ( _resources ) );
1083 DtInitialize(XtDisplay(baseWidget()), baseWidget(), argv[0], "Dtmail");
1085 // Must be called after XtSetLanguageProc and DtInitialize because
1086 // DtInitialize sets the environment variable NLSPATH which is used
1087 // in catopen(). That's why we have to take out catopen from
1088 // Application::initialize and put a new mathod open->catalog for
1089 // both Application and RoamApp
1090 this->open_catalog();
1092 // Initialize the mail_error. This also has to be done after DtInitialize
1093 // because the DtMailEnv consturctor calls catopen as well.
1094 DtMailEnv mail_error;
1100 // Some of the scrolling lists contain formatted text and thus
1101 // require a fixed width font to display the text correctly.
1102 // We want to use the fixed width font defined by dt.userFont as
1103 // it will be internationalized correctly. If it is not there
1104 // we fall back to a fixed width lucida font. If that fails
1105 // we let the widget fallback to what ever it thinks is best.
1108 // Default font in case we can't find anything else.
1109 XrmDatabase db = XtScreenDatabase(XtScreen(baseWidget()));
1113 char *buf = new char[1024];
1116 // Need to check fixed width font mailrc variable. Assume
1121 XrmPutStringResource(
1122 &db, "*Work_Area*XmText.fontList", _user_font);
1123 XrmPutStringResource(
1124 &db, "*Work_Area*XmTextField.fontList", _user_font);
1126 XrmPutStringResource(
1127 &db, "*Work_Area*DtEditor.textFontList", _user_font);
1128 XrmPutStringResource(
1129 &db, "*Work_Area*iconGadget.fontList", _user_font);
1130 XrmPutStringResource(
1131 &db, "*XmDialogShell*XmList.FontList", _user_font);
1133 // Convert the user fontlist to a font.
1134 if (!fontlist_to_font(_user_fontlist, &userfont)) {
1135 if (!(userfont.f.cf_font = XLoadQueryFont(
1136 XtDisplay(baseWidget()),
1138 /* Couldn't convert the user fontlist to a font */
1141 "RoamApp::initialize : error loading fixed font\n");
1143 userfont.cf_type = XmFONT_IS_FONT;
1148 FontType systemfont;
1150 XrmPutStringResource(
1151 &db, "*Work_Area*Text*fontList", _system_font);
1152 XrmPutStringResource(
1153 &db, "*Work_Area*iconGadget*fontList", _system_font);
1154 XrmPutStringResource(
1155 &db, "*Work_Area*Text*textFontList", _system_font);
1156 XrmPutStringResource(
1157 &db, "*XmDialogShell*XmList*FontList", _system_font);
1159 if (!fontlist_to_font(_system_fontlist, &systemfont)) {
1160 /* Couldn't convert the system fontlist to a font */
1161 if (!(systemfont.f.cf_font = XLoadQueryFont(
1162 XtDisplay(baseWidget()),
1166 "RoamApp::initialize : error loading variable font\n");
1168 systemfont.cf_type = XmFONT_IS_FONT;
1174 // If the glyph font is specified in a resource file, use it.
1176 _glyph_name = XtNewString(_glyph_font);
1180 // If the glyph font hasn't been specified, try to match it with
1183 // Get the font name that matches the user font pixel size.
1184 load_app_font(baseWidget(), &userfont, &_glyph_name);
1187 // Create a fontlist that contains the glyph and user fonts
1188 strcpy(buf, _user_font);
1190 // Never refer to the "plain" tag so dont add it.
1191 if (strchr(_user_font, '=') == NULL) {
1193 strcat(buf, "=plain, ");
1196 // If the symbol font can't be found, use user font above
1199 strcat(buf, _glyph_name);
1200 strcat(buf, "=attach");
1203 // Loosely bind font to message list. This lets users override
1204 // with a more strongly bound name (ie "Dtmail*Message_List*FontList");
1206 // Matches the MsgScrollingList in the RoamMenuWindows.
1207 XrmPutStringResource(&db, "*Message_List*FontList", buf);
1210 // Matches the UndelMsgScrollingList in the UndelFromListDialog
1211 // and overrides the "*XmDialogShell*XmList*FontList" spec above.
1212 XrmPutStringResource(&db, "*XmDialogShell*Message_List*FontList", buf);
1217 // If we don't have a mail file yet, then we need to retrieve the
1218 // Initialize Tooltalk
1219 // NOTE: For now, must make the FIRST ttdt_open call to be the proc_id
1220 // that will respond to the start message. Therefore, call gui's
1221 // ttdt_open before libDtMail calls its.
1224 sess = (char *)getenv("TT_SESSION");
1225 if (!sess || (*sess == '\0')) {
1226 sess = getenv("_SUN_TT_SESSION");
1228 if (!sess || (*sess == '\0')) {
1229 tt_default_session_set(tt_X_session(XDisplayString(_display)));
1232 roam_tt_procid = ttdt_open( &roam_tt_fd, "DTMAIL", "SunSoft", "%I", 1 );
1233 dieFromTtError(tt_ptr_error(roam_tt_procid),
1234 "initialize.ttdt_open",
1235 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."),
1236 DTMAILHELPCANTINITTOOLTALK);
1238 // This is for supporting old ptype where RFC_822_Message is
1240 status = ttmedia_ptype_declare( "RFC_822_Message",
1242 tooltalk_msg_handler,
1245 dieFromTtError(status,
1246 "initialize.ttmedia_ptype_declare.RFC_822_Message", NULL, NULL);
1248 status = ttmedia_ptype_declare( "RFC_822_MESSAGE",
1250 tooltalk_msg_handler,
1253 dieFromTtError(status,
1254 "initialize.ttmedia_ptype_declare.RFC_822_MESSAGE", NULL, NULL);
1256 status = ttmedia_ptype_declare( "MAIL_TYPE",
1258 attachmt_msg_handler,
1261 dieFromTtError(status,
1262 "initialize.ttmedia_ptype_declare.MAIL_TYPE", NULL, NULL);
1264 /* Join the default session -- This should have been done by default */
1265 roam_tt_pattern = ttdt_session_join(
1267 (Ttdt_contract_cb)quit_message_cb,
1268 baseWidget(), this, 1);
1269 dieFromTtError(tt_ptr_error(roam_tt_pattern),
1270 "initialize.ttdt_session_join", NULL, NULL);
1272 _mail_session = new MailSession(mail_error, Application::appContext());
1273 if (mail_error.isSet()) {
1274 // what do we do here? there are no windows for dialogs
1275 // should we just register a syslog() and exit? ugggh
1277 fprintf(stderr, "RoamApp::initialize : error creating MailSession\n");
1282 // .mailrc parsing error checking
1284 DtMail::Session * d_session = _mail_session->session();
1285 DtMail::MailRc* mailRc = d_session->mailRc(mail_error);
1286 DTMailError_t pErr = mailRc->getParseError();
1287 if (pErr != DTME_NoError) {
1289 DtMailGenDialog *mailrc_dialog = new DtMailGenDialog(
1291 theApplication->baseWidget());
1292 mailrc_dialog->setToQuestionDialog(
1293 GETMSG(DT_catd, 2, 1, "Mailer"),
1294 GETMSG(DT_catd, 2, 22,
1295 "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.") );
1296 helpId = DTMAILHELPERROR;
1297 answer = mailrc_dialog->post_and_return(
1298 GETMSG(DT_catd, 2, 23, "Continue"),
1299 GETMSG(DT_catd, 2, 24, "Exit"),
1302 XtRemoveAllCallbacks(
1303 theApplication->baseWidget(),
1304 XmNdestroyCallback);
1311 // Check if mailer is installed properly if we are not in debugging mode.
1313 const char *value = NULL;
1315 d_session->mailRc(mail_error)->getValue(mail_error,
1316 "__ignore_group_permissions",
1318 if (mail_error.isSet()) {
1322 theApplication->enableGroupPrivileges();
1323 GetGroupName(grp_name);
1324 theApplication->disableGroupPrivileges();
1325 if (strcmp(grp_name, DTMAIL_DEFAULT_CREATE_MAILGROUP))
1326 mail_error.setError(DTME_BadRunGroup);
1329 if ((DTMailError_t)mail_error == DTME_BadRunGroup) {
1333 DtMailGenDialog *install_errDialog =
1334 new DtMailGenDialog("Dialog", theApplication->baseWidget());
1335 sprintf(buf, GETMSG(DT_catd, 2, 4,
1336 "Mailer has not been properly installed,\n\
1337 and cannot run because the execution group\n\
1338 is incorrectly set."));
1340 install_errDialog->setToErrorDialog(
1341 GETMSG(DT_catd, 1, 6, "Mailer"),
1344 // No choice at this state other than to OK.
1345 helpId = DTMAILHELPBADGROUPID;
1346 answer = install_errDialog->post_and_return(
1347 GETMSG(DT_catd, 3, 9, "OK"),
1349 XtRemoveAllCallbacks(
1350 theApplication->baseWidget(),
1351 XmNdestroyCallback);
1357 free((void*) value);
1359 _options = new OptCmd("Mail Options...",
1360 GETMSG(DT_catd, 1, 2,"Mail Options..."),
1364 if ( just_compose ) {
1365 // Need to install self destruct
1366 SendMsgDialog *compose = theCompose.getWin();
1369 char *ttl = GETMSG(DT_catd, 1, 262, "Dead Letter Message");
1370 compose->loadDeadLetter(dead_letter);
1371 compose->setTitle(ttl);
1372 compose->setIconTitle(ttl);
1375 if ( *argcp > num_legit_args + 1) { // Have attachment(s)
1376 for ( int k = num_legit_args + 1; k < *argcp; k++ ) {
1377 compose->inclAsAttmt(argv[k], NULL);
1383 // inbox. We do this by querying the current implementation for
1384 // the path to its inbox.
1387 DtMailObjectSpace space;
1389 d_session->queryImpl(mail_error,
1390 d_session->getDefaultImpl(mail_error),
1391 DtMailCapabilityInboxName,
1396 // We need to determine which transport to use. The order of preference
1399 // 1) The value of DEFAULT_TRANSPORT in the .mailrc file.
1401 // 2) The value of DEFAULT_TRANSPORT in the environment.
1403 // 3) The transport, if available for the default implementation.
1405 // 4) The first implementation that provides a transport.
1407 const char * trans_impl = NULL;
1409 d_session->mailRc(mail_error)->getValue(mail_error,
1410 "DEFAULT_TRANSPORT",
1412 if (mail_error.isSet()) {
1418 trans_impl = getenv("DEFAULT_TRANSPORT");
1422 trans_impl = d_session->getDefaultImpl(mail_error);
1424 DtMailBoolean trans;
1426 d_session->queryImpl(mail_error, trans_impl,
1427 DtMailCapabilityTransport, &trans);
1428 if (mail_error.isSet() || trans == DTM_FALSE) {
1434 const char ** impls = d_session->enumerateImpls(mail_error);
1436 for (int impl = 0; impls[impl]; impl++) {
1437 DtMailBoolean trans;
1438 d_session->queryImpl(mail_error, impls[impl],
1439 DtMailCapabilityTransport, &trans);
1440 if (!mail_error.isSet() || trans == DTM_TRUE) {
1441 trans_impl = impls[impl];
1448 _mail_transport = d_session->transportConstruct(mail_error,
1454 _mail_transport = NULL;
1457 // Register all callbacks the backend may have to deal with
1459 d_session->registerLastInteractiveEventTimeCallback(lastInteractiveEventTime, this);
1461 // These callbacks are only needed on systems where sendmail is run as
1462 // 'root', and so has access permissions to any file on the system.
1463 d_session->registerDisableGroupPrivilegesCallback(disableGroupPrivileges, this);
1464 d_session->registerEnableGroupPrivilegesCallback(enableGroupPrivileges, this);
1466 if (d_session->pollRequired(mail_error) == DTM_TRUE) {
1467 d_session->registerBusyCallback(mail_error, setBusyState, this);
1468 _appTimeoutId = XtAppAddTimeOut(
1469 XtWidgetToApplicationContext( _w ),
1471 &RoamApp::applicationTimeout,
1475 // Process the message that started us, if any. Should I pass in
1476 // roam_tt_procid or NULL.
1477 tttk_Xt_input_handler( 0, 0, 0 );
1478 XtAppAddInput( Application::appContext(), roam_tt_fd,
1479 (XtPointer)XtInputReadMask,
1480 tttk_Xt_input_handler, roam_tt_procid );
1482 // Get the vacation handle before the new RoamMenuWindow
1483 // This is for setting the Vacation title stripe on the window
1484 _vacation = new VacationCmd("Vacation", GETMSG(DT_catd, 1, 3, "Vacation"));
1486 // DtMail only supports the "Mail" message.
1487 // If DtMail is started by ToolTalk, then we assume that the
1488 // client wants a Compose window. Therefore, we do not
1489 // bring up a RoamMenuWindow.
1491 if ( !session_fp && !started_by_tt && !just_compose) {
1493 _mailview = new RoamMenuWindow(mail_file);
1494 _mailview->initialize();
1495 _mailview->manage();
1505 _dialog = new DtMailGenDialog("Dialog", _w);
1507 DtDbReloadNotify(reload_notify_cb, (XtPointer) NULL);
1508 _default_x_error_handler = XSetErrorHandler(x_error_handler);
1509 if (NULL != mail_file)
1510 free((void*) mail_file);
1513 RoamApp::RoamApp(char *name) : Application (name), _activePrintDisplays(5)
1515 DebugPrintf(2, "RoamApp::RoamApp(%p \"%s\")\n", name, name);
1519 // Let the destructor of parent Application class handle the
1524 #ifdef DTMAIL_TOOLTALK
1525 if ( roam_tt_procid != NULL ) {
1527 // Temporary workaround to get PrintToFile to work.
1528 // Currently, PrintToFile forks a child which is
1529 // calling ~RoamApp when it exits. This clobbers
1530 // the tooltalk connection causing the parent to hang.
1532 ttdt_close(0, 0, 1);
1533 roam_tt_procid = NULL;
1539 XtRemoveTimeOut(_appTimeoutId);
1543 RoamApp::shutdownWorkproc(XtPointer client_data)
1545 RoamApp *thisApp = (RoamApp*) client_data;
1547 if (thisApp->_numPendingTasks > 0)
1550 if (thisApp->_shutdownWorkprocID != 0)
1552 XtRemoveWorkProc(thisApp->_shutdownWorkprocID);
1553 thisApp->_shutdownWorkprocID = 0;
1556 delete thisApp->_mail_session;
1558 // Delete this and let the parent class's destructor call exit(0)
1567 if (_numPendingTasks > 0)
1569 if (_shutdownWorkprocID == 0)
1570 _shutdownWorkprocID = XtAppAddWorkProc(
1572 &RoamApp::shutdownWorkproc,
1576 shutdownWorkproc((XtPointer) this);
1580 RoamApp::checkForShutdown()
1582 int nappwin, ncompunused, nrmwunused;
1584 if (! theApplication->isEnabledShutdown()) return;
1585 nappwin = theApplication->num_windows();
1586 ncompunused = theCompose.numUnusedWindows();
1587 nrmwunused = theRoamApp.session()->numDeactivatedRMW();
1589 if (nappwin == ncompunused + nrmwunused)
1591 theCompose.~Compose();
1592 while (_numWindows > 0)
1600 RoamApp::applicationTimeout( XtPointer client_data,
1603 RoamApp *app = ( RoamApp * ) client_data;
1608 RoamApp::timeout( XtIntervalId * )
1610 DtMail::Session * d_session = _mail_session->session();
1613 d_session->poll(error);
1615 _appTimeoutId = XtAppAddTimeOut(
1616 XtWidgetToApplicationContext( _w ),
1618 &RoamApp::applicationTimeout,
1623 RoamApp::lastInteractiveEventTime(void * client_data)
1625 RoamApp * self = (RoamApp *)client_data;
1626 return (theApplication->lastInteractiveEventTime());
1630 RoamApp::disableGroupPrivileges(void * client_data)
1632 RoamApp * self = (RoamApp *)client_data;
1633 theApplication->disableGroupPrivileges();
1638 RoamApp::enableGroupPrivileges(void * client_data)
1640 RoamApp * self = (RoamApp *)client_data;
1641 theApplication->enableGroupPrivileges();
1647 RoamApp::setBusyState(
1649 DtMailBusyState busy_state,
1652 static const int MAXBUSYSTATES=20;
1653 static int busyStateStackTop = 0;
1654 static DtMailBusyState busyStateStack[MAXBUSYSTATES] =
1655 {DtMailBusyState_NotBusy};
1656 RoamApp *self = (RoamApp*) client_data;
1660 case DtMailBusyState_AutoSave:
1661 case DtMailBusyState_NewMail:
1663 showBusyState(error, busy_state, client_data);
1664 // if (busyStateStackTop) // Already busy from previous message?
1665 // self->_busy_count--; // Decrement busy count for
1666 // displaying this message
1667 busyStateStack[++busyStateStackTop] = busy_state;
1668 assert(busyStateStackTop < MAXBUSYSTATES);
1671 case DtMailBusyState_NotBusy:
1672 if (busyStateStackTop)
1675 self->_mailview->postErrorDialog(error);
1677 busy_state = busyStateStack[--busyStateStackTop];
1678 showBusyState(error, busy_state, client_data);
1679 // if (busyStateStackTop)
1680 // self->_busy_count--; // Decrement busy count for
1681 // redisplaying this message
1684 showBusyState(error, busy_state, client_data);
1687 assert(busyStateStack[0] == DtMailBusyState_NotBusy);
1691 RoamApp::showBusyState(
1693 DtMailBusyState busy_state,
1697 RoamApp * self = (RoamApp *)client_data;
1701 case DtMailBusyState_AutoSave:
1702 self->busyAllWindows(GETMSG(DT_catd, 3, 1, "Auto-saving..."));
1705 case DtMailBusyState_NewMail:
1706 self->busyAllWindows(GETMSG(DT_catd, 3, 86, "Checking for new mail..."));
1709 case DtMailBusyState_NotBusy:
1711 self->unbusyAllWindows();
1717 RoamApp::busyAllWindows(const char * msg)
1719 for (int win = 0; win < _numWindows; win++) {
1720 // if (_busy_count == 0) {
1721 _windows[win]->busyCursor();
1724 _windows[win]->setStatus(msg);
1731 RoamApp::unbusyAllWindows(void)
1734 // if (_busy_count == 0) {
1735 for (int win = 0; win < _numWindows; win++) {
1736 _windows[win]->normalCursor();
1737 _windows[win]->clearStatus();
1743 RoamApp::globalAddToCachedContainerList(char *destname)
1746 RoamMenuWindow *rmw;
1748 for (int win = 0; win < _numWindows; win++) {
1749 cname = _windows[win]->className();
1750 if (strcmp(cname, "RoamMenuWindow") == 0) {
1751 rmw = (RoamMenuWindow *)_windows[win];
1752 rmw->addToCachedContainerList(destname);
1758 RoamApp::globalPropChange(void)
1760 busyAllWindows(GETMSG(DT_catd, 1, 4, "Updating properties..."));
1762 for (int win = 0; win < _numWindows; win++) {
1763 _windows[win]->propsChanged();
1770 RoamApp::genDialog()
1777 RoamApp::startVacation(
1784 RoamMenuWindow *rmw;
1788 XtVaGetValues(subject_tf,
1792 XtVaGetValues(text_tp,
1796 status = _vacation->startVacation((char *)subj, (char *) text);
1798 for (int win = 0; win < _numWindows; win++) {
1799 cname = _windows[win]->className();
1800 if (strcmp(cname, "RoamMenuWindow") == 0) {
1801 rmw = (RoamMenuWindow *)_windows[win];
1802 rmw->setVacationTitle();
1809 RoamApp::stopVacation()
1812 RoamMenuWindow *rmw;
1814 _vacation->stopVacation();
1816 for (int win = 0; win < _numWindows; win++) {
1817 cname = _windows[win]->className();
1818 if (strcmp(cname, "RoamMenuWindow") == 0) {
1819 rmw = (RoamMenuWindow *)_windows[win];
1820 rmw->removeVacationTitle();
1826 getPropStringValue(DtVirtArray<PropStringPair *> &results, const char *label)
1828 for (int mrc = 0; mrc < results.length(); mrc++) {
1829 PropStringPair * psp = results[mrc];
1830 if (strcmp(label, psp->label) == 0)
1831 return strdup(psp->value);
1837 parsePropString(const char * input, DtVirtArray<PropStringPair *> & results)
1842 // If it's not multibyte, use the regular string function
1843 if (MB_CUR_MAX <= 1) {
1844 const char * start = input;
1849 while (isspace(*start)) {
1853 for (end = start; end && *end; end++)
1854 if (isspace(*end) && *(end-1) != '\\')
1857 PropStringPair * new_pair = new PropStringPair;
1859 int len = end - start;
1860 char * label = new char[len + 5];
1861 strncpy(label, start, len);
1863 for (ptr = label; (ptr = strstr(ptr, "\\ ")); ptr++)
1866 char * file = strchr(label, ':');
1868 new_pair->label = strdup(label);
1869 new_pair->value = NULL;
1873 new_pair->label = strdup(label);
1876 if (strlen(file) == 0) {
1877 new_pair->value = NULL;
1880 new_pair->value = strdup(file);
1884 results.append(new_pair);
1889 while (*start && isspace(*start)) {
1893 } while(*start && *end);
1897 // The string can contain multibyte characters and it must be converted to
1898 // wide character string before parsing
1899 int len = strlen(input);
1900 wchar_t *wc_input= new wchar_t[len+1];
1901 mbstowcs(wc_input, input, len+1);
1902 const wchar_t *start = wc_input;
1907 while (iswspace(*start)) {
1911 for (end = start; end && *end; end++)
1912 if (iswspace(*end) && *(end-1) != (wint_t)'\\')
1914 PropStringPair * new_pair = new PropStringPair;
1916 int wclen = end - start;
1917 wchar_t *wc_label = new wchar_t[wclen+1];
1918 wcsncpy(wc_label, start, wclen);
1919 wc_label[wclen] = (wint_t)'\0';
1921 // Search the string "\ " and take out the back slash
1922 wchar_t esc_space[3];
1923 mbstowcs(esc_space, "\\ ", 3);
1924 for (ptr = wc_label; (ptr = wcswcs(ptr, esc_space)); ptr++)
1927 wchar_t *file = wcschr(wc_label, (wint_t)':');
1929 new_pair->label = new char[(wclen+1)*MB_CUR_MAX];
1930 wcstombs(new_pair->label, wc_label, wclen+1);
1931 new_pair->value = NULL;
1936 *file = (wint_t)'\0';
1937 new_pair->label = new char[(wclen+1)*MB_CUR_MAX];
1938 wcstombs(new_pair->label, wc_label, (wclen+1)*MB_CUR_MAX);
1941 int filelen = wcslen(file);
1943 new_pair->value = NULL;
1946 new_pair->value = new char[(filelen+1)*MB_CUR_MAX];
1947 wcstombs(new_pair->value, file, (filelen+1)*MB_CUR_MAX);
1951 results.append(new_pair);
1955 while (*start && iswspace(*start)) {
1959 } while(*start && *end);
1965 PropStringPair::PropStringPair(void)
1971 PropStringPair::PropStringPair(const PropStringPair & other)
1977 label = strdup(other.label);
1981 value = strdup(other.value);
1985 PropStringPair::~PropStringPair(void)
1997 RoamApp::setSession( MailSession *session )
1999 _mail_session = session;
2009 char *formatPropPair(char * key, void * data)
2011 char *formatted_str = NULL;
2012 char *white_space = NULL;
2013 int i, num_spaces = 0;
2014 int key_len = strlen(key);
2020 // figure out whitespace for formatting
2021 // assume 13 for normal sized alias name
2023 if(key_len < 13) // need to add spaces
2025 num_spaces = 13 - key_len;
2027 white_space = (char *)malloc(num_spaces + 1);
2028 strcpy(white_space, "\0");
2030 for(i = 0; i < num_spaces; i++)
2031 strcat(white_space, " ");
2033 m_size = key_len + strlen((char *)white_space)
2034 + strlen((char *)data) + strlen(" = ") + 1;
2035 formatted_str = (char *)malloc(m_size);
2037 sprintf(formatted_str, "%s%s = %s",key, white_space, data);
2042 /* make an alias string */
2043 formatted_str = (char *)malloc(key_len + strlen((char *)data) + 2);
2045 m_size = key_len + strlen((char *)data) + strlen(" = ") + 1;
2046 formatted_str = (char *)malloc(m_size);
2048 sprintf(formatted_str, "%s = %s",key, data);
2052 return formatted_str;
2057 RoamApp::inboxWindow()
2059 RoamMenuWindow *rmw;
2062 for (int win = 0; win < _numWindows; win++) {
2063 cname = _windows[win]->className();
2064 if (strcmp(cname, "RoamMenuWindow") == 0) {
2065 rmw = (RoamMenuWindow *)_windows[win];
2075 RoamApp::nextRoamMenuWindow(RoamMenuWindow *last)
2077 RoamMenuWindow *looking_for = last;
2078 RoamMenuWindow *rmw;
2081 for (int win = 0; win < _numWindows; win++) {
2082 cname = _windows[win]->className();
2083 if (strcmp(cname, "RoamMenuWindow") == 0) {
2084 rmw = (RoamMenuWindow *)_windows[win];
2085 if (NULL == looking_for)
2087 if (rmw == looking_for)
2095 RoamApp::closeInactiveRoamMenuWindows(void)
2097 MailSession *ses = theRoamApp.session();
2098 RoamMenuWindow **rmws;
2102 rmws = (RoamMenuWindow**) malloc(_numWindows * sizeof(RoamMenuWindow *));
2103 for (win=0; win<_numWindows; win++)
2105 cname = _windows[win]->className();
2106 if (strcmp(cname, "RoamMenuWindow") == 0)
2107 rmws[nrmws++] = (RoamMenuWindow*) _windows[win];
2110 for (win=0; win<nrmws; win++)
2111 if (! ses->isActiveRMW(rmws[win])) rmws[win]->quit(TRUE);
2117 RoamApp::reopenRoamMenuWindows(void)
2119 RoamMenuWindow *rmw, **rmws;
2123 theApplication->disableShutdown();
2125 rmws = (RoamMenuWindow**) malloc(_numWindows * sizeof(RoamMenuWindow *));
2126 for (win=0; win<_numWindows; win++)
2128 cname = _windows[win]->className();
2129 if (strcmp(cname, "RoamMenuWindow") == 0)
2130 rmws[nrmws++] = (RoamMenuWindow*) _windows[win];
2133 for (win=0; win<nrmws; win++)
2137 name = strdup(rmw->mailboxName());
2140 rmw = new RoamMenuWindow(name);
2147 theApplication->enableShutdown();
2151 RoamApp::defaultStatusWindow()
2153 MainWindow *mw = NULL;
2155 if ((mw = (MainWindow *) _mailview) != NULL)
2157 if ((mw = (MainWindow *) inboxWindow()) != NULL)
2159 if (_numWindows > 0)
2160 mw = (MainWindow *) _windows[0];
2166 RoamApp::open_catalog()
2168 Application::open_catalog(); // Open Motif Application message catalog file
2169 DT_catd = catopen(DTMAIL_CAT, NL_CAT_LOCALE); // Open DtMail message catalog file