Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtinfo / clients / dtinfo_start / dtinfo_start.c
1 /* $TOG: dtinfo_start.c /main/9 1999/09/20 13:26:59 mgreess $
2  *
3  * (c) Copyright 1996 Digital Equipment Corporation.
4  * (c) Copyright 1996 Hewlett-Packard Company.
5  * (c) Copyright 1996 International Business Machines Corp.
6  * (c) Copyright 1996 Sun Microsystems, Inc.
7  * (c) Copyright 1996 Novell, Inc. 
8  * (c) Copyright 1996 FUJITSU LIMITED.
9  * (c) Copyright 1996 Hitachi.
10  *
11  * This file contains the main program for: dtinfo_start
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16
17 #include <X11/Intrinsic.h>
18
19 #include <Xm/XmP.h>
20 #include <Xm/XmAll.h>
21
22 #include <Dt/EnvControlP.h>
23 #include <Dt/Action.h>
24 #include <Dt/DtGetMessageP.h>
25 #include <Dt/MsgLog.h>
26
27 #include <Tt/tt_c.h>
28
29 #include "dtinfo_start.h"
30 #include "dtinfo_start.opnums"
31
32 /*
33  * Operation names, number of arguments and default action names
34  */
35 static const char       * LOAD_INFO_LIB_STRING = "DtInfo_LoadInfoLib";
36 static const int        LOAD_INFO_LIB_ARGS = 3;
37 static const char       * LOAD_INFO_LIB_ACTION = "DtInfoStart";
38
39 static const char       * SHOW_INFO_AT_LOC_STRING = "DtInfo_ShowInfoAtLoc";
40 static const int        SHOW_INFO_AT_LOC_ARGS = 4;
41 static const char       * SHOW_INFO_LIB_SECTION_ACTION = "DtInfoStartAtLoc";
42
43 /*
44  * Static global vars
45  */
46 static Widget           top_level;
47
48 static XtAppContext     app_context;
49
50 static const int        time_out = 1000;        /* milliseconds */
51
52 static const int        SET_NUM = 1;            /* message cat set number */
53
54 static const char       * name = "DtInfo"; /* ptype name and Xt name */
55
56 /*
57  * Forward declarations for static functions
58  */
59 static int InvokeAction (
60         char                    * prog_name, 
61         int                     op_num,
62         const char              * action_name, 
63         char                    * exec_host, 
64         char                    * info_lib, 
65         char                    * topic);
66
67 static void ActionDoneCallback (
68         DtActionInvocationID    id,
69         XtPointer               client_data,
70         DtActionArg             * args,
71         int                     num_args,
72         DtActionStatus          status);
73
74 static void Exit (
75         XtPointer               client_data,
76         XtIntervalId            id);
77
78 static Tt_status ConnectToMessageServer (
79         char                    * prog_name);
80
81 static void ReceiveMessage (
82         XtPointer               client_data,
83         int                     * fd,
84         XtInputId               * id);
85
86 static void LogToolTalkError (
87         DtMsgLogType            msg_type,
88         char                    * prog_name,
89         char                    * function_name,
90         Tt_status               error_num);
91 static void DieFromToolTalkError (
92         Widget                  parent,
93         char                    * errfmt,
94         Tt_status               status);
95
96
97 void
98 main ( 
99         int                     argc,
100         char                    ** argv) 
101 {
102         Display                 * display;
103         Arg                     args[10];
104         int                     i = 0;
105         Tt_status               status;
106   
107         XtSetLanguageProc (NULL, NULL, NULL);
108
109         _DtEnvControl (DT_ENV_SET);
110
111         XtToolkitInitialize ();
112
113         app_context = XtCreateApplicationContext ();
114
115         if (!(display = XtOpenDisplay (app_context, NULL, NULL, name,
116                                        NULL, NULL, &argc, argv))) {
117                 DtMsgLogMessage (argv[0], DtMsgLogError, 
118                         (char *) GETMESSAGE (SET_NUM, 7, "XtOpenDisplay() failed.  Perhaps the DISPLAY environment\nvariable is not set or is invalid."));
119                 exit (1);
120         }
121   
122         /*
123          * Create a minimalist application shell - needed by
124          * DtActionInvoke.
125          */
126         XtSetArg (args[i], XtNallowShellResize,         True);  i++;
127         XtSetArg (args[i], XtNmappedWhenManaged,        False); i++;
128         XtSetArg (args[i], XtNheight,                   1);     i++;
129         XtSetArg (args[i], XtNwidth,                    1);     i++;
130
131         top_level = XtAppCreateShell (argv[0], 
132                                       name, 
133                                       topLevelShellWidgetClass, 
134                                       display, 
135                                       args, 
136                                       i);
137
138         XtRealizeWidget (top_level);
139
140         /*  
141          * Initialize the desktop
142          */
143         if (DtAppInitialize (app_context, display, top_level, argv[0], name) 
144                         == False) {
145                 DtMsgLogMessage (argv[0], DtMsgLogError, 
146                         (char *) GETMESSAGE (SET_NUM, 8, "DtAppInitialize() failed.  Perhaps the desktop environment\nis not properly installed."));
147                 exit (1);
148         }
149
150         /*
151          * Connect to the message server
152          */
153         status = ConnectToMessageServer (argv[0]);
154         if (TT_OK != status) {
155                 char *errfmt;
156
157                 /*
158                  * An error Message has already been logged.
159                  */
160                 errfmt = GETMESSAGE (2, 2,
161                           "Could not connect to ToolTalk:\n%s\nExiting ...");
162                 DieFromToolTalkError (top_level, errfmt, status);
163         }
164
165         /* 
166          * Load the datatypes and actions 
167          */
168         DtDbLoad();
169
170         XtAppMainLoop (app_context);
171 }
172
173
174 static int
175 InvokeAction (
176         char                    * prog_name, 
177         int                     op_num,
178         const char              * action_name, 
179         char                    * exec_host, 
180         char                    * info_lib, 
181         char                    * topic)
182 {
183         DtActionArg             * args;
184         int                     num_args = 1;
185         DtActionInvocationID    action_id;
186
187         if (op_num == SHOW_INFO_AT_LOC)
188                 num_args = 2;
189
190         args = (DtActionArg *) XtCalloc (num_args, sizeof (DtActionArg));
191         if (!args) {
192                 DtMsgLogMessage (prog_name, DtMsgLogError, 
193                         (char *) GETMESSAGE (SET_NUM, 6,
194                         "Cannot invoke an action because malloc(1) failed."));
195                 return (0);
196         }
197
198         args[0].argClass = DtACTION_FILE;
199         args[0].u.file.name = info_lib;
200
201         if (op_num == SHOW_INFO_AT_LOC) {
202                 args[1].argClass = DtACTION_BUFFER;
203                 args[1].u.buffer.name = topic;
204                 args[1].u.buffer.size = strlen (topic) + 1;
205                 args[1].u.buffer.writable = False;
206         }
207
208         action_id = DtActionInvoke (top_level,
209                                     (char *) action_name,
210                                     args,
211                                     num_args,
212                                     NULL,
213                                     exec_host,
214                                     NULL,
215                                     True,
216                                     (DtActionCallbackProc) ActionDoneCallback,
217                                     prog_name);
218
219 #if defined(DEBUG)
220         DtMsgLogMessage (prog_name, DtMsgLogError, "Invoked %s\n", action_name);
221 #endif
222
223         /*
224          * The following test, comment and code are from:
225          *   $TOP/dtaction/Main.c
226          *
227          * "Set up a timer if we didn't get a valid procId --
228          *  since there will be no invocation update in that case."
229          */
230         if (!action_id) {
231                 XtAppAddTimeOut (app_context,
232                                  10, 
233                                  (XtTimerCallbackProc) Exit,
234                                  NULL);
235         }
236
237         return (1);
238 }
239
240
241 /* ARGSUSED */
242 static void 
243 ActionDoneCallback (
244         DtActionInvocationID    id,
245         XtPointer               client_data,
246         DtActionArg             * args,
247         int                     num_args,
248         DtActionStatus          status)
249 {
250 #if defined(DEBUG)
251         char *status_name;
252
253         switch (status) {
254                 case DtACTION_DONE:
255                     status_name = "DtACTION_DONE";
256                     break;
257                 case DtACTION_OK:
258                     status_name = "DtACTION_DONE";
259                     break;
260                 case DtACTION_INVOKED:
261                     status_name = "DtACTION_DONE";
262                     break;
263                 case DtACTION_FAILED:
264                     status_name = "DtACTION_DONE";
265                     break;
266                 case DtACTION_CANCELED:
267                     status_name = "DtACTION_DONE";
268                     break;
269                 case DtACTION_INVALID_ID:
270                     status_name = "DtACTION_DONE";
271                     break;
272                 case DtACTION_STATUS_UPDATE:
273                     status_name = "DtACTION_DONE";
274                     break;
275                 default:
276                     status_name = "UNKNOWN";
277                     break;
278         }
279 #endif
280         switch (status) {
281                 case DtACTION_DONE:
282                 case DtACTION_OK:
283 #if defined(DEBUG)
284                         DtMsgLogMessage ("dtinfo_start", DtMsgLogError,
285                                          "Action returned %s\n", status_name);
286 #endif
287                         XtAppAddTimeOut(app_context, 10 * time_out, 
288                                         (XtTimerCallbackProc) Exit,
289                                         NULL);
290
291                 case DtACTION_INVOKED:
292                 case DtACTION_FAILED:
293                 case DtACTION_CANCELED:
294                 case DtACTION_INVALID_ID:
295                 case DtACTION_STATUS_UPDATE:
296                 default:
297 #if defined(DEBUG)
298                         DtMsgLogMessage ("dtinfo_start", DtMsgLogError,
299                                          "Action returned %s\n", status_name);
300 #endif
301                         XtAppAddTimeOut(app_context, 10 * time_out, 
302                                         (XtTimerCallbackProc) Exit,
303                                         NULL);
304         }
305 }
306
307
308 static Tt_status
309 ConnectToMessageServer (
310         char                    * prog_name)
311 {
312         int                     mark;
313         char                    * procid;
314         int                     ttfd;
315         Tt_status               status;
316   
317         mark = tt_mark();
318
319         procid = tt_open();
320         status = tt_pointer_error (procid);
321         if (status != TT_OK) {
322                 LogToolTalkError (DtMsgLogError, prog_name,
323                                     "tt_open", status);
324                 tt_release (mark);
325                 return (status);
326         }
327   
328         status = tt_ptype_declare (name);
329         if (status != TT_OK) {
330                 LogToolTalkError (DtMsgLogError, prog_name, 
331                                     "tt_ptype_declare", status);
332                 tt_release (mark);
333                 return (status);
334         }
335
336         ttfd = tt_fd ();
337         if ((tt_int_error (ttfd)) != TT_OK) {
338                 LogToolTalkError (DtMsgLogError, prog_name, 
339                                     "tt_fd", status);
340                 tt_release (mark);
341                 return (status);
342         }
343
344         XtAppAddInput (app_context, ttfd, (XtPointer) XtInputReadMask,
345                        ReceiveMessage, (char *) prog_name);
346
347         status = tt_session_join (tt_default_session());
348         if ((tt_int_error (ttfd)) != TT_OK) {
349                 LogToolTalkError (DtMsgLogError, prog_name, 
350                                     "tt_session_join", status);
351                 tt_release (mark);
352                 return (status);
353         }
354   
355         tt_release(mark);
356
357         return (TT_OK);
358 }
359
360
361 /* ARGSUSED */
362 static void
363 ReceiveMessage (
364         XtPointer               client_data,
365         int                     * fd,
366         XtInputId               * id)
367 {
368         static int              last_op_num = 0;
369         int                     op_num;
370         int                     opstatus;
371         int                     num_args;
372         Tt_message              message;
373         const char              * action_name;
374         char                    * exec_host;
375         char                    * locale;
376         char                    * topic = NULL;
377         char                    * prog_name = (char *) client_data;
378         static                  char lang[200];
379         const char              * op_name;
380         char                    * info_lib = NULL;
381
382         message = tt_message_receive();
383
384         /* from tt_message_receive(3), and after examining other TT clients */
385         if (message == 0) return;
386
387         if (tt_pointer_error (message) != TT_OK) {
388                 LogToolTalkError (DtMsgLogError, prog_name, 
389                                     "tt_message_receive", 
390                                     tt_pointer_error (message));
391                 exit (1);
392         }
393
394         op_num = tt_message_opnum (message);
395         switch (op_num) {
396
397                 case LOAD_INFO_LIB:
398                         op_name = LOAD_INFO_LIB_STRING;
399                         break;
400
401                 case SHOW_INFO_AT_LOC:
402                         op_name = SHOW_INFO_AT_LOC_STRING;
403                         break;
404
405                 default: {
406                         /*
407                          * Don't know how I got this message
408                          */
409                         DtMsgLogMessage (prog_name, DtMsgLogError, 
410                                 (char *) GETMESSAGE (SET_NUM, 11, "The message operation '%d' is not supported."),
411                                 op_num);
412
413                         tt_message_reject (message);
414                         tt_message_destroy(message);
415                         exit (1);
416                 }
417         }
418
419         /*
420          * Check the number of arguments
421          */
422         num_args =  tt_message_args_count (message);
423         if ((op_num == LOAD_INFO_LIB &&    num_args != LOAD_INFO_LIB_ARGS) ||
424             (op_num == SHOW_INFO_AT_LOC && num_args != SHOW_INFO_AT_LOC_ARGS)) {
425
426                 DtMsgLogMessage (prog_name, DtMsgLogError, 
427                         (char *) GETMESSAGE (SET_NUM, 12, "Message '%s' does not have the required\nnumber of arguments '%d'."),
428                         op_name, 
429                         (op_num == LOAD_INFO_LIB) ?
430                                 LOAD_INFO_LIB_ARGS : SHOW_INFO_AT_LOC_ARGS);
431                 tt_message_reject (message);
432                 tt_message_destroy(message);
433                 exit (1);
434         }
435
436         /*
437          * Check for an info lib
438          */
439         info_lib = tt_message_file (message);
440         if ((tt_ptr_error (info_lib) != TT_OK) || info_lib == NULL) {
441                 /*
442                  * Use DTINFOLIBDEFAULT if it is defined
443                  */
444                 if ((info_lib = getenv ("DTINFOLIBDEFAULT")) == NULL) {
445                         DtMsgLogMessage (prog_name, DtMsgLogError, 
446                                 (char *) GETMESSAGE (SET_NUM, 10, "An InfoLib was not provided in the '%s' message\nand the environment variable DTINFOLIBDEFAULT was not defined."),
447                                 op_name);
448                         exit (1);
449                 }
450         }
451
452         if ((action_name = tt_message_arg_val (message, 0)) == NULL) {
453
454                 action_name = (op_num == LOAD_INFO_LIB) ? 
455                         LOAD_INFO_LIB_ACTION : SHOW_INFO_LIB_SECTION_ACTION;
456
457                 DtMsgLogMessage (prog_name, DtMsgLogWarning,
458                         (char *) GETMESSAGE (SET_NUM, 13, "Message '%s' specified a NULL action name.\nAction '%s' will be invoked."),
459                         op_name,
460                         action_name);
461         }
462
463         if ((exec_host = tt_message_arg_val (message, 1)) == NULL) {
464
465                 DtMsgLogMessage (prog_name, DtMsgLogWarning, 
466                         (char *) GETMESSAGE (SET_NUM, 14, "Message '%s' specified a NULL execution host."),
467                         op_name);
468         }
469
470         if ((locale = tt_message_arg_val (message, 2)) == NULL) {
471
472                 DtMsgLogMessage (prog_name, DtMsgLogWarning,
473                         (char *) GETMESSAGE (SET_NUM, 15, "Message '%s' specified a NULL locale."),
474                         op_name);
475         }
476         else {
477                 /*
478                  * Put locale into the environment so that DtActionInvoke
479                  * will propagate it to the dtinfo process.
480                  */
481                 (void) sprintf (lang, "LANG=%s", locale);
482                 (void) putenv (lang);
483         }
484
485         if (op_num == SHOW_INFO_AT_LOC) {
486                 if ((topic = tt_message_arg_val (message, 3)) == NULL) {
487
488                         DtMsgLogMessage (prog_name, DtMsgLogError, 
489                                 (char *) GETMESSAGE (SET_NUM, 16, "Message '%s' specified a NULL topic."),
490                                 op_name);
491                         exit (1);
492                 }
493         }
494
495         if (op_num == last_op_num)
496         {
497 #if defined(DEBUG)
498             DtMsgLogMessage("dtinfo_start", DtMsgLogError,
499                             "Received a duplicate tooltalk message:  %s",
500                             (op_num == LOAD_INFO_LIB) ? 
501                               "LOAD_INFO_LIB" : "SHOW_INFO_AT_LOC" );
502 #endif
503         }
504         else
505         {
506 #if defined(DEBUG)
507             DtMsgLogMessage(
508                 "dtinfo_start", DtMsgLogError,
509                 "Received a tooltalk message:  %s\nInvoking action %s",
510                 (op_num==LOAD_INFO_LIB) ? "LOAD_INFO_LIB" : "SHOW_INFO_AT_LOC",
511                 action_name);
512 #endif
513             last_op_num = op_num;
514             opstatus = InvokeAction (prog_name, 
515                                      op_num, 
516                                      action_name, 
517                                      exec_host, 
518                                      info_lib,
519                                      topic);
520             if (!opstatus) {
521                     tt_message_fail (message);
522                     exit (1);
523             }
524         }
525
526         tt_message_reply (message);
527
528         tt_message_destroy(message);
529 }
530
531
532 static void
533 LogToolTalkError (
534         DtMsgLogType            msg_type,
535         char                    * prog_name,
536         char                    * function_name,
537         Tt_status               error_num)
538 {
539         char                    *message;
540         message = tt_status_message(error_num);
541         DtMsgLogMessage (prog_name, msg_type, "%s: %s", function_name, message);
542 }
543
544 #define GETXMSTRING(s, m, d)    XmStringCreateLocalized(GETMESSAGE(s,m,d))
545
546 static void
547 ExitCB (Widget dialog, XtPointer client_data, XtPointer call_data)
548 {
549     exit((int) client_data);
550 }
551
552 static void
553 DieFromToolTalkError(Widget parent, char *errfmt, Tt_status status)
554 {
555     Arg          args[10];
556     Widget       dialog, dialogShell;
557     char        *errmsg, *statmsg, *title;
558     XmString     xms_errmsg, xms_ok, xms_title;
559     int          n;
560
561     if (! tt_is_err(status)) return;
562
563     statmsg = tt_status_message(status);
564     errmsg = XtMalloc(strlen(errfmt) + strlen(statmsg) + 2);
565     sprintf(errmsg, errfmt, statmsg);
566
567     xms_ok = GETXMSTRING(2, 3, "OK");
568     xms_errmsg = XmStringCreateLocalized(errmsg);
569     xms_title = GETXMSTRING(2, 1, "Dtinfo: Error");
570
571     n = 0;
572     XtSetArg(args[n], XmNautoUnmanage, False); n++;
573     XtSetArg(args[n], XmNokLabelString, xms_ok); n++;
574     XtSetArg(args[n], XmNdialogTitle, xms_title); n++;
575     XtSetArg(args[n], XmNmessageString, xms_errmsg); n++;
576     XtSetArg(args[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); n++;
577
578     dialog = XmCreateErrorDialog(parent, "DtinfoStartError", args, n);
579     XtAddCallback(dialog, XmNokCallback, ExitCB, (XtPointer) status);
580     XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
581     XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
582
583     /*
584      * Disable the frame menu from dialog since we don't want the user
585      * to be able to close dialogs with the frame menu
586      */
587     dialogShell = XtParent(dialog);
588     n = 0;
589     XtSetArg(args[n], XmNmwmDecorations, MWM_DECOR_ALL | MWM_DECOR_MENU); n++;
590     XtSetValues(dialogShell, args, n);
591     XtManageChild(dialog);
592     XtRealizeWidget(dialogShell);
593
594     XtFree(errmsg);
595     XmStringFree(xms_ok);
596     XmStringFree(xms_errmsg);
597     XmStringFree(xms_title);
598
599     while (TRUE)
600       XtAppProcessEvent(XtWidgetToApplicationContext(dialog), XtIMAll);
601 }
602
603 /* ARGSUSED */
604 static void
605 Exit (
606         XtPointer               client_data,
607         XtIntervalId            id)
608 {
609         /*
610          * The following code to determine if DtActionInvoke
611          * resulted in the posting a dialog is from:
612          *   $TOP/dtaction/Main.c
613          */
614         if (top_level->core.num_popups ==  0)
615                 exit(0);
616
617         XtAppAddTimeOut (app_context, 
618                          time_out, 
619                          (XtTimerCallbackProc) Exit, 
620                          NULL);
621
622 }