3ce3ea1a54ffb9b539d267586d327bf1cd1e474e
[oweals/cde.git] / cde / programs / dtinfo / dtinfo / src / Managers / TtIpcMgr.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  * $TOG: TtIpcMgr.C /main/16 1999/09/20 13:30:40 mgreess $
25  *
26  * Copyright (c) 1992 HaL Computer Systems, Inc.  All rights reserved.
27  * UNPUBLISHED -- rights reserved under the Copyright Laws of the United
28  * States.  Use of a copyright notice is precautionary only and does not
29  * imply publication or disclosure.
30  * 
31  * This software contains confidential information and trade secrets of HaL
32  * Computer Systems, Inc.  Use, disclosure, or reproduction is prohibited
33  * without the prior express written permission of HaL Computer Systems, Inc.
34  * 
35  *                         RESTRICTED RIGHTS LEGEND
36  * Use, duplication, or disclosure by the Government is subject to
37  * restrictions as set forth in subparagraph (c)(l)(ii) of the Rights in
38  * Technical Data and Computer Software clause at DFARS 252.227-7013.
39  *                        HaL Computer Systems, Inc.
40  *                  1315 Dell Avenue, Campbell, CA  95008
41  * 
42  */
43
44 #define C_LibraryAgent
45 #define C_PrintPanelAgent
46 #define C_UrlAgent
47 #define L_Agents
48
49 #define C_Long_Lived
50 #define L_Basic
51
52 #define C_EnvMgr
53 #define C_TtIpcMgr
54 #define C_NodeMgr
55 #define C_MessageMgr
56 #define C_WorkspaceMgr
57 #define L_Managers
58
59 #define C_WindowSystem
60 #define L_Other
61
62 #include "Prelude.h"
63
64 #include "Managers/CatMgr.hh"
65 #include "Registration.hh"
66
67 #include "utility/mmdb_exception.h"
68 #include "utility/funcs.h"
69
70 #include <string.h>
71 #include <stdio.h>
72
73 #include <X11/Intrinsic.h>
74
75 //  the Session include file(s) are for locale_of_desktop()
76 //#include <Dt/SessionP.h>
77 #include <Dt/SessionM.h>
78
79 #include <Dt/EnvControlP.h>
80 #include <Dt/Action.h>
81 #include <Dt/DtGetMessageP.h>
82 #include <Dt/MsgLog.h>
83
84 #include <Tt/tt_c.h>
85 #include <Tt/tttk.h>
86
87
88
89 LONG_LIVED_CC( TtIpcMgr, tt_manager )
90
91 #if 0
92 #  define RCS_DEBUG(statement) cerr << statement << endl
93 #else
94 #  define RCS_DEBUG(statement) 
95 #endif
96
97 // the following defines for tt msg opnums must match those in the tttypes
98 // declaration for associated (Dtinfo) ptype use
99 #define LOAD_INFO_LIB           1
100 #define SHOW_INFO_AT_LOC        2
101 #define QUIT_DTINFO             3
102 #define PRINT_INFO_AT_LOC       4
103
104 // the following defines are for message index per catalog
105 // Set_AddLibraryAgent:
106 #define ERR_INFOLIB_SPEC_FORMAT 5
107 // Set_TtIpcMgr:
108 #define ERR_TT_DISPLAY_AS_SESSION       1
109 #define ERR_TT_DEFAULT_AS_SESSION       2
110 #define ERR_TT_OPEN                     3
111 #define ERR_TT_PTYPE_DECLARE            4
112
113 #define DFLTXT_DISPLAY_AS_SESSION "Can't get tt session for X display:\n%s"
114 #define DFLTXT_DEFAULT_AS_SESSION "Could not set default tooltalk session:\n%s"
115 #define DFLTXT_OPEN                "Failed to open ToolTalk connection:\n%s"
116 #define DFLTXT_PTYPE_DECLARE       "Could not declare ptype DtInfo:\n%s"
117
118 // the last message handled, for sanity checking
119 Tt_message prior_tt_msg ;
120
121 // temp internal tracking of curr workspace at time tt msg received
122 Atom       curr_ws_tt ;
123
124
125 // /////////////////////////////////////////////////////////////////
126 // LogToolTalkMessage - records messages to log
127 // /////////////////////////////////////////////////////////////////
128
129 static char *
130 LogToolTalkMessage (
131     DtMsgLogType        msg_type,
132     int                 msg_num,
133     char                * dflt_txt,
134     Tt_status           status)
135 {
136     char                * errfmt;
137     char                * statmsg;
138     char                * errmsg;
139     int                 errmsglen;
140     
141     if (! tt_is_err(status)) return XtsNewString("");;
142
143     errfmt = CATGETS(Set_TtIpcMgr, msg_num, dflt_txt);
144     statmsg = tt_status_message(status);
145     errmsglen = strlen(errfmt) + strlen(statmsg) + 2;
146     errmsg = XtMalloc(errmsglen);
147     if (! strlen(errfmt))
148       errfmt = (char*)"%s";
149     snprintf(errmsg, errmsglen, errfmt, statmsg);
150
151     DtMsgLogMessage ("Dtinfo", msg_type, errfmt, errmsg);
152     return errmsg;
153 }
154
155
156 // /////////////////////////////////////////////////////////////////
157 // class constructor
158 // /////////////////////////////////////////////////////////////////
159
160 // TtIpcMgr constructor
161 //
162 // It is highly recommended that this be invoked only after event
163 // loop entry, or at least as much as possible deferred until then.
164 // It is the creator's responsibility to do this at the first level
165 // via work proc or similar.
166 //
167 TtIpcMgr::TtIpcMgr()
168 {
169   int           mark ;
170   int           ttfd ;
171   char *        xsession ;
172   char *        errmsg ;
173
174
175   // Initialize ToolTalk
176
177   window_system().wait_cursor();    // this tt stuff Can take a while
178
179   mark = tt_mark() ;
180
181   xsession = tt_X_session(
182        (const char *)(XDisplayString((window_system().display()))) ) ;
183
184   if( tt_ptr_error( xsession ) != TT_OK )
185   {
186       errmsg = LogToolTalkMessage (DtMsgLogError, 
187                                    ERR_TT_DISPLAY_AS_SESSION,
188                                    (char*)DFLTXT_DISPLAY_AS_SESSION,
189                                    tt_state);
190       message_mgr().error_dialog( (char*)UAS_String(errmsg) ) ;
191       XtFree (errmsg);
192       tt_release( mark ) ;
193       return ;
194   }
195
196   // set up to actually join the "default" session for any
197   // patterns registered below to take effect there-in
198   XtAppAddWorkProc( window_system().app_context(),
199                     ipc_init_wp1, this ) ;
200
201   if( (tt_state = tt_default_session_set( xsession )) == TT_OK )
202   {
203       procid = ttdt_open( &ttfd, "Dtinfo", "Fujitsu", "CDE", True ) ;
204       //why is fujitsu mentioned here? 05/15/18 - C
205
206       if( (tt_state = tt_pointer_error( procid ))
207           == TT_OK )
208       {
209           // declare Dtinfo Ptype
210           if( (tt_state = tt_ptype_declare( "DtInfo" )) == TT_OK )
211           {
212               // success -- add an input handler for tooltalk msgs
213               XtAppAddInput( window_system().app_context(), ttfd,
214                          (XtPointer) XtInputReadMask,
215                          receive_tt_msg, this ) ;
216
217               // declare DtinfoPrint ptype (non-fatal if prior ptype ok).
218               // Also can be broken out & deferred via the work proc.
219               XtAppAddWorkProc( window_system().app_context(),
220                                 ipc_init_wp0, this ) ;
221           }
222           else
223           {
224               // HEY! No matter what exit you take from here, it must
225               // return True! -- its a work proc!
226
227               errmsg = LogToolTalkMessage (DtMsgLogError, 
228                                            ERR_TT_PTYPE_DECLARE,
229                                            (char*)DFLTXT_PTYPE_DECLARE,
230                                            tt_state);
231               message_mgr().error_dialog( (char*)UAS_String(errmsg) );
232               XtFree(errmsg);
233           }
234       }
235       else
236       {
237         errmsg = LogToolTalkMessage (DtMsgLogError,
238                                      ERR_TT_OPEN,
239                                      (char*)DFLTXT_OPEN,
240                                      tt_state);
241         message_mgr().error_dialog( (char*)UAS_String(errmsg) );
242         XtFree(errmsg);
243       }
244   }
245   else
246   {
247     errmsg = LogToolTalkMessage (DtMsgLogError, 
248                                  ERR_TT_DEFAULT_AS_SESSION,
249                                  (char*)DFLTXT_DEFAULT_AS_SESSION,
250                                  tt_state);
251     message_mgr().error_dialog( (char*)UAS_String(errmsg) );
252     XtFree(errmsg);
253   }
254   if( tt_state != TT_OK )
255   {
256       XtAppAddWorkProc( window_system().app_context(),
257                         ipc_error_wp, &tt_state ) ;
258   }
259   // else -- ipc_init_wp1 will attempt to join the session
260
261   tt_release( mark ) ;
262   window_system().reset_cursor();
263 }
264
265
266 // /////////////////////////////////////////////////////////////////
267 // ipc_init_wp0()
268 // 2nd-level tt init functions, set by class constructor as XtWorkProc
269 // /////////////////////////////////////////////////////////////////
270
271 Boolean
272 TtIpcMgr::ipc_init_wp0( XtPointer /* theIpcObj */ )
273 {
274   int           mark ;
275
276   mark = tt_mark() ;
277
278   Tt_status tstp = tt_ptype_declare("DtInfoPrint");
279   if(tstp != TT_OK )
280   {    
281       DtMsgLogMessage("dtinfo", DtMsgLogError,
282                     "%s: %s", "tt_ptype_declare",
283                     (char *) CATGETS(
284                     Set_TtIpcMgr, 9, 
285    "The process type 'DtInfoPrint' is not the\nname of an installed process type."));
286   }
287   tt_release( mark ) ;
288   return True ;         // do workproc once
289 }
290
291
292 // /////////////////////////////////////////////////////////////////
293 // ipc_init_wp1()
294 // 3rd-level tt init functions, set by class constructor as XtWorkProc
295 // /////////////////////////////////////////////////////////////////
296
297 Boolean
298 TtIpcMgr::ipc_init_wp1( XtPointer theIpcObj )
299 {
300   if( ((TtIpcMgr*)theIpcObj)->tt_state == TT_OK )
301   {
302       window_system().wait_cursor();    // this tt Can take a while
303
304       int mark = tt_mark() ;
305
306       // actually join the "default" session for all previously
307       // registered patterns to take effect there-in
308       // Tt_pattern *sess_patterns =
309              ttdt_session_join( NULL, NULL,
310                          window_system().toplevel(), theIpcObj, True ) ;
311       // invoke msg handler explicitly in case a message already queued
312       XtAppAddWorkProc( window_system().app_context(),
313                         receive_tt_msg_wp, theIpcObj ) ;
314       tt_release( mark ) ;
315       window_system().reset_cursor();
316   }
317   return True ;         // do workproc once
318 }
319
320
321 // /////////////////////////////////////////////////////////////////
322 // class destructor
323 // /////////////////////////////////////////////////////////////////
324
325 TtIpcMgr::~TtIpcMgr()
326 {
327   // char  *dfile;
328
329   // send a Dtinfo_Quit message to whomever may be observing
330   notify_quit() ;
331
332   // if ((dfile = tt_default_file()) != (char *)0)
333   // {
334   //   tt_file_quit(dfile) ;
335   // }
336   // ttdt_session_quit( NULL, sess_patterns, True ) ;
337   // ttdt_close( NULL, NULL, True ) ;
338 }
339
340
341 // /////////////////////////////////////////////////////////////////
342 // establish_server - for any coordination purposes (future)
343 // /////////////////////////////////////////////////////////////////
344
345 void
346 TtIpcMgr::establish_server()
347 {
348 }
349
350
351 // /////////////////////////////////////////////////////////////////
352 // do_infolib
353 //
354 // load of infolib requested, so do it here if infolib ID valid
355 // /////////////////////////////////////////////////////////////////
356
357 int
358 TtIpcMgr::do_infolib( char *lib_path )
359 {
360   int   sts = ID_SUCCESS ;
361
362   if( !lib_path )
363   {
364       // if no file argument specified, get the default
365       if( !(lib_path = env().infolibDefault()) )
366       {
367           message_mgr().error_dialog( (char*)UAS_String(CATGETS(
368                     Set_AddLibraryAgent, ERR_INFOLIB_SPEC_FORMAT,
369                     "Infolib specification format error." )) ) ;
370           return (sts = BAD_ARG_FORMAT);
371       }
372       sts = LibraryAgent::add_library( lib_path ) ;
373       XtFree( lib_path ) ;  // this path only
374   }
375   else
376       sts = LibraryAgent::add_library( lib_path ) ;
377
378   // possible returns ID_SUCCESS, NOT_FOUND, BAD_ARG_FORMAT, LOAD_ERROR
379   return sts ;
380 }
381
382
383 // /////////////////////////////////////////////////////////////////
384 // do_locator
385 //
386 // view of specific doc requested, so do it here if locator ID valid
387 //
388 // Check for NULL locator pointer before passing it.
389 // /////////////////////////////////////////////////////////////////
390
391 int
392 TtIpcMgr::do_locator( char      *locator,
393                       Boolean   new_window )
394 {
395   return UrlAgent::document( locator, new_window ) ;
396 }
397
398 // /////////////////////////////////////////////////////////////////
399 // do_print
400 // 
401 // takes a section locators and prints it
402 //
403 // Prerequisites: Load any infolibs separately specified first.
404 // /////////////////////////////////////////////////////////////////
405 int
406 TtIpcMgr::do_print(Tt_message msg)
407 {
408     UAS_Pointer<UAS_Common> d = NULL ;
409     char *filepath = tt_message_file(msg);
410     FILE *fp;
411     char locator[512];
412     int bufferlen;
413     
414     fprintf(stderr, "TtIpcMgr::do_print: filepath = %s.\n", filepath);
415     
416     //  Open the file containing the list of sections to be printed for reading
417     
418     if ((fp = fopen(filepath, "r")) == NULL) {
419         fprintf(stderr, "Cannot open file %s.\n", filepath);
420     }
421
422     //  Get a handle to the AppPrintData allocated in the WindowSystem class
423
424     AppPrintData* p = window_system().GetAppPrintData();
425
426     //  Create a list of items to be printed
427
428     xList<UAS_Pointer<UAS_Common> > * print_list = new  xList<UAS_Pointer<UAS_Common> >;
429
430     // each line of the temporary file contains a locator.  create a UAS_Common buffer
431     // for each locator and add it to the print list
432     
433     while (fgets(locator, sizeof(locator), fp) != NULL) {
434    
435         if( !strchr( locator, ':' ) && !strchr( locator, '/' ) )
436         {
437             // assume given a unique locator ID for the target.
438             // construct a fully-qualified form and pass it on.
439
440             bufferlen = strlen("mmdb:LOCATOR=") + strlen(locator) + 1;
441             char *buffer = new char[bufferlen];
442             snprintf (buffer, bufferlen, "mmdb:LOCATOR=%s", locator);
443             d = UAS_Common::create (buffer);
444             delete [] buffer;
445         }
446         else
447         {
448             // assume to have a fully-qualified locator
449             d = UAS_Common::create(locator);
450         }
451
452         //  add UAS_Common pointer to list of sections to print
453
454         if (d != (const int)0)
455         {
456             print_list->append(d);
457         }
458         else {
459             fprintf(stderr, "Wow!  Null section!\n");
460         }
461             
462     }    // end locators in file
463
464     p->f_outline_element = NULL;
465     p->f_print_list = print_list;
466
467     XtAppAddWorkProc(window_system().app_context(), ipc_print_wp, p) ;
468     
469     fclose(fp);
470     fprintf(stderr, "do_print: exiting\n");    
471     return 1 ;
472 }
473
474
475 // /////////////////////////////////////////////////////////////////
476 // handle
477 //
478 // based on message type, initiate the appropriate response
479 // /////////////////////////////////////////////////////////////////
480
481 int
482 TtIpcMgr::handle( Tt_message msg_in )
483 {
484   int   opstatus = UNKNOWN_MSG ;
485   char *info_file ;
486   char *info_uuid ;
487   Tt_status     tst ;
488
489   {
490     switch( tt_message_opnum(msg_in) )
491     {
492       case SHOW_INFO_AT_LOC :
493
494         // - arg for locator required (any valid format).
495         // - if File provided, an infolib Add is attempted first. 
496         // - The infolib path may be provided via the locator part,
497         //   but the infolib will not be Added if only this is the case.
498
499         if( (opstatus = check_locale( msg_in, 2 )) == ID_SUCCESS )
500         {
501             // get the locator value, per spec'd position
502             info_uuid = tt_message_arg_val( msg_in, 3 ) ;
503             if( (tst = tt_ptr_error( info_uuid )) != TT_OK ) 
504             {
505               XtAppAddWorkProc( window_system().app_context(),
506                                 ipc_error_wp, &tst ) ;
507               return (opstatus = MSG_SYNTAX_ERROR) ;
508             }
509
510             // check to see if an optional File arg is supplied for infolib
511
512             info_file = tt_message_file( msg_in ) ;
513             if( (tst = tt_ptr_error( info_file )) != TT_OK )
514             {
515               XtAppAddWorkProc( window_system().app_context(),
516                                 ipc_error_wp, &tst ) ;
517               return (opstatus = MSG_SYNTAX_ERROR) ;
518             }
519             else
520             {
521               do_infolib( info_file ) ;   // load infolib per File, first
522             }
523                        // try to get the section
524             workspace().target( curr_ws_tt ) ;
525             opstatus = do_locator( info_uuid, True ) ;
526         }
527         break ;
528
529       case LOAD_INFO_LIB :
530
531         if( (opstatus = check_locale( msg_in, 2 )) == ID_SUCCESS )
532         {
533             info_uuid = tt_message_file( msg_in ) ;
534             if( (tst = tt_ptr_error( info_uuid )) != TT_OK )
535             {
536               XtAppAddWorkProc( window_system().app_context(),
537                                 ipc_error_wp, &tst ) ;
538               return (opstatus = MSG_SYNTAX_ERROR) ;
539             }
540
541             workspace().target( curr_ws_tt ) ;
542             opstatus = do_infolib( info_uuid ) ;
543         }
544         break ;
545
546       case PRINT_INFO_AT_LOC :    
547           opstatus = do_print(msg_in);
548         break ;
549
550       case QUIT_DTINFO :        // ignored
551         break ;
552
553       default :
554         /* don't know what else to do with this message */
555         opstatus = UNKNOWN_MSG ;
556         break ;
557     }
558   }
559   return opstatus ;
560 }
561
562
563 // /////////////////////////////////////////////////////////////////
564 // check_locale
565 //
566 // 
567 // /////////////////////////////////////////////////////////////////
568 int
569 TtIpcMgr::check_locale( Tt_message msg_in,
570                         int        locale_arg_pos )
571 {
572   int       sts = ID_SUCCESS ;
573   Tt_status tst ;
574   char * target_locale ;
575
576   // test for locale match -- can't display data for different locale.
577   // NULL locale is OK.
578   target_locale = tt_message_arg_val( msg_in, locale_arg_pos ) ;
579
580   if( (tst = tt_ptr_error( target_locale )) != TT_OK ) 
581   {
582       XtAppAddWorkProc( window_system().app_context(),
583                         ipc_error_wp, &tst ) ;
584       return (sts = MSG_SYNTAX_ERROR) ;
585   }
586   if(    *target_locale != '\0'
587       && strcmp( target_locale, env().lang() ) != 0
588       && getenv( "LANG" ) != NULL
589       && strcmp( target_locale, getenv( "LANG" ) ) != 0 )
590   { sts = NOT_OWNER ; }
591
592   return (sts) ;
593 }
594
595
596 char * locale_of_desktop() ;
597
598 // /////////////////////////////////////////////////////////////////
599 // receive_tt_msg
600 //
601 // a static member function of the TtIpcMgr class.
602 // used as an input handler per X
603 //
604 // gets the msg, invokes handler for class, and makes the appropriate
605 // tt response per handler disposition status
606 // /////////////////////////////////////////////////////////////////
607
608 // /*ARGSUSED*/
609 void
610 TtIpcMgr::receive_tt_msg( XtPointer client_data,
611                           int *fid,
612                           XtInputId *id )
613 {
614   int           mark;
615   Tt_status     tst ;
616
617   mark = tt_mark();
618
619   Tt_message msg_in = tt_message_receive() ;
620
621   if( msg_in == NULL )
622   {
623     // NULL msg pointer input is "normal" in certain tt cases,
624     // and in typical non-tt start-up of dtinfo
625     tt_release(mark);
626     return ;
627   }
628   if( msg_in == prior_tt_msg )
629   {
630     // A single instance of dtinfo should never get the same message
631     // handle invocation twice, unless it is a reply to the msg which
632     // we sent (and none are currently expected).  This check
633     // should prevent any infinite loop conditions (which are possible
634     // between tt and joined processes, under certain error conditions).
635     tttk_message_fail( msg_in,
636                        TT_ERR_PROCID, NULL, 1 ) ;
637     tt_release(mark);
638     return ;
639   }
640
641   // record the current desktop workspace now
642   // (this should approximate tt requestor's workspace)
643   workspace().current( &curr_ws_tt ) ;
644
645   if( (tst = tt_pointer_error( msg_in )) == TT_ERR_NOMP )
646   {
647     // fprintf(stderr,"ToolTalk server down.\n");
648     XtAppAddWorkProc( window_system().app_context(),
649                       ipc_error_wp, &tst ) ;
650     return ;   // should not be fatal, but need feedback...
651   }
652
653   switch( ((TtIpcMgr*)client_data)->handle(msg_in) )
654   {
655     case ID_SUCCESS :
656
657         if( ( tt_message_class( msg_in ) == TT_REQUEST )
658             || ( id == NULL ) )
659         {
660             tt_message_reply( msg_in ) ;
661         }
662         break ;
663
664     case MSG_SYNTAX_ERROR :
665     case BAD_ARG_FORMAT :
666     case LOAD_ERROR :
667     case NOT_FOUND :
668
669            // *Only at This point* for "NOT_FOUND" case could we decide
670            // that "exec_host" might be relevant for a subsequent remote
671            // access attempt (were we handling that from dtinfo to kick
672            // off a fallback process...)
673
674         // arg format, not found, or
675         // load errors have already been "handled" with an error dialog,
676         // so if we did a fail here, there will be redundant and less
677         // specific dialog presented by the messaging system. Thus, reply.
678
679         if( ( tt_message_class( msg_in ) == TT_REQUEST )
680             || ( fid == NULL ) )
681         {
682             tt_message_reply( msg_in ) ;
683         }
684         // tttk_message_fail( msg_in,   // can't process message
685         //                 TT_ERR_FILE, NULL, 1 ) ;
686         break ;
687
688     case NOT_OWNER :
689
690         // exec host has to be detected prior to the dtinfo start to
691         // have any effect. locale is also expected to be set correctly
692         // prior to dtinfo invocation. However, if locale was specified
693         // it is checked, and in any case for which it does not match,
694         // the message must be rejected so that tt can pass it to another
695         // instance or launch an instance to handle it. Since this dtinfo
696         // instance may be the only handler currently available, we could
697         // also launch a dtinfo instance in the requested locale before
698         // rejecting the message. Else, if we are in the default
699         // (desktop's) locale, ttsession may go into an infinite
700         // loop creating default dtinfo instances (depending on
701         // the ptype definition), trying to find a handler...
702         // But... if this instance is Not running in the default locale,
703         // we want tt to go ahead and start such a copy! Need to determine
704         // whether this instance is running in the default/desktop locale,
705         // and based on that do fail or reject... jcb
706       {
707         char *ref_locale = locale_of_desktop();
708         if(   ref_locale
709            && strcmp( ref_locale, env().lang() ) != 0
710            && getenv( "LANG" ) != NULL
711            && strcmp( ref_locale, getenv( "LANG" ) ) != 0 )
712         {
713             // don't want to process nor kill message, so reject to
714             // let tooltalk start a default instance. If that instance
715             // also cannot service the request precisely, it will kill
716             // the message.
717             tttk_message_reject( msg_in, TT_ERR_NOTHANDLER, NULL, 0 ) ;
718         }
719         else                   // can't process message
720             tttk_message_fail( msg_in,
721                                TT_ERR_PROCID, NULL, 1 ) ;
722
723         if( ref_locale )  XFree( ref_locale );
724       }
725         break;
726
727     default:
728     case UNKNOWN_MSG :
729
730         tttk_message_abandon( msg_in ) ;        // don't understand message
731         break ;
732   }
733
734   // tt_mark/tt_release tags memory allocated by tt for a given
735   // msg cycle, to ensure that it is all freed when done.
736
737   tt_release(mark);
738
739   return;
740 }
741
742
743 // receive_tt_msg_wp
744 //
745 // Background task to check explicitly for tt message input
746 //
747 Boolean
748 TtIpcMgr::receive_tt_msg_wp( XtPointer theIpcObj )
749 {
750   receive_tt_msg( theIpcObj, NULL, NULL ) ;
751   return True ;
752 }
753
754
755 // ipc_print_wp
756 //
757 // Display print dialog
758 //
759 Boolean
760 TtIpcMgr::ipc_print_wp( XtPointer client_data )
761 {
762     AppPrintData* p = (AppPrintData *)client_data;
763  
764     CreatePrintSetup(p->f_pshell_parent, p);
765     
766     XtManageChild(p->f_print_dialog); /* popup dialog each time */
767     
768     return True ;
769 }
770
771 // ipc_error_wp
772 //
773 // Translate any tooltalk error message numbers and post for user.
774 // Probables: TT_ERR_SESSION TT_ERR_NOMP TT_ERR_PROCID TT_ERR_PTYPE
775 //
776 Boolean
777 TtIpcMgr::ipc_error_wp( XtPointer client_data )
778 {
779   message_mgr().error_dialog(
780                   tt_status_message( *((Tt_status*)client_data) ) ) ;
781   return True ;
782 }
783
784
785 void
786 TtIpcMgr::notify_quit()
787 {
788   Tt_message msg_out;
789
790   // create and send a "quit" notice message for any observers
791
792   msg_out = tt_pnotice_create( TT_SESSION, "DtInfo_Quit" ) ;
793
794   tt_message_send( msg_out ) ;
795   
796   // no reply expected since this was a notice, so no longer need
797   // handle for the message
798
799   tt_message_destroy( msg_out ) ;
800 }
801
802
803 // get the Dt session manager's locale context property as a reliable
804 // reference point with which to compare to the dtinfo instance's
805 // current locale. Caller needs to free the string memory returned
806 // with XFree().
807 //
808 // Note: this function should really reside in the EnvMgr class
809 //
810 char *
811 locale_of_desktop()
812 {
813         static Atom _DT_SM_WINDOW_INFO = None;
814         static Atom WM_LOCALE_NAME = None;
815
816         Atom type = None;
817         int format;
818         unsigned long nitems, after;
819         // WM_LOCALE_NAME Atom (string data)
820         char    *dt_locale;
821         // _DT_SM_WINDOW_INFO Atom (PropDtSmWindowInfo structure data)
822         Window  *sm_prop_window;
823
824         Display *dpy = window_system().display();
825
826
827         if(WM_LOCALE_NAME == None) {
828             WM_LOCALE_NAME = XInternAtom(dpy, "WM_LOCALE_NAME", True);
829         }
830 #ifdef DEBUG
831         if (!WM_LOCALE_NAME)
832             printf( "Atom WM_LOCALE_NAME not interned\n" );
833 #endif
834
835         if (!WM_LOCALE_NAME)    return (char *)NULL;
836
837         if(_DT_SM_WINDOW_INFO == None) {
838             _DT_SM_WINDOW_INFO =
839                          XInternAtom(dpy, _XA_DT_SM_WINDOW_INFO, False);
840         }
841 #ifdef DEBUG
842         if (!_DT_SM_WINDOW_INFO)
843             printf( "Atom _DT_SM_WINDOW_INFO not interned\n" );
844 #endif
845
846         if (!_DT_SM_WINDOW_INFO)  return (char *)NULL;
847
848         XGetWindowProperty( dpy,
849                             XDefaultRootWindow(dpy),
850                             _DT_SM_WINDOW_INFO,
851                             1L, 1L, False,
852                             _DT_SM_WINDOW_INFO,
853                             &type, &format, &nitems, &after,
854                             (unsigned char **)(void*)&sm_prop_window) ;
855
856 #ifdef DEBUG
857 // property.smWindow = (unsigned long) smGD.topLevelWindow;
858         if (!sm_prop_window)    
859             printf(
860              "null value from Atom _DT_SM_WINDOW_INFO for SM window ID\n" );
861         else
862             printf( "dtsession window is %lx\n", *sm_prop_window );
863 #endif
864
865         if (!sm_prop_window)    return (char *)NULL;
866
867         type = None;
868         XGetWindowProperty( dpy,
869                             *sm_prop_window,
870                             WM_LOCALE_NAME,
871                             0L, (long)8, False,
872                             XA_STRING,
873                             &type, &format, &nitems, &after,
874                             (unsigned char **)(void*)&dt_locale) ;
875
876 #ifdef DEBUG
877         printf( "desktop's locale is %s\n", dt_locale ) ;
878 #endif
879
880         if (!dt_locale)   return (char *)NULL;
881         else              return dt_locale;
882 }
883
884