1 /* $TOG: Main.c /main/18 1998/07/23 17:56:36 mgreess $ */
2 /*****************************************************************************
3 *****************************************************************************
9 ** Description: This file contains the main program for dtaction.
12 **(c) Copyright 1993, 1994 Hewlett-Packard Company
13 **(c) Copyright 1993, 1994 International Business Machines Corp.
14 **(c) Copyright 1993, 1994 Sun Microsystems, Inc.
15 **(c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of Novell, Inc.
18 ****************************************************************************
19 ************************************<+>*************************************/
27 #include <sys/param.h> /* for MAXPATHLEN and MAXHOSTNAMELEN */
38 #include <X11/Intrinsic.h>
41 #include <Xm/SelectioB.h>
42 #include <Xm/MessageB.h>
43 #include <Xm/Protocols.h>
44 #include <Xm/MwmUtil.h>
47 #include <Dt/DbUtil.h>
48 #include <Dt/CmdInv.h>
49 #include <Dt/Action.h>
50 #include <Dt/EnvControlP.h>
53 /******************************************************************************/
58 /* Command line options */
59 XrmOptionDescRec option_list[] =
61 { "-user", "user", XrmoptionSepArg, NULL},
62 { "-contextDir", "contextDir", XrmoptionSepArg, NULL},
63 { "-execHost", "execHost", XrmoptionSepArg, NULL},
64 { "-termOpts", "termOpts", XrmoptionSepArg, NULL},
67 /* Fallback Resources */
68 static char *fallback_resources[] = {
78 } ApplArgs, *ApplArgsPtr;
80 #define LOGIN_STR_LEN 15
86 int passwordLength = 0;
88 Boolean finished = False;
89 Boolean rootRequest = False;
90 char * toPword = NULL;
91 char * rootPword = NULL;
92 char * origName = "Unknown";
96 /* Dtaction resources */
97 XtResource resources[] =
100 "user", "User", XmRString, sizeof(char *),
101 XtOffsetOf(ApplArgs, user), XmRImmediate, (XtPointer) NULL,
104 "contextDir", "ContextDir", XmRString, sizeof(char *),
105 XtOffsetOf(ApplArgs, contextDir), XmRImmediate, (XtPointer) NULL,
108 "execHost", "ExecHost", XmRString, sizeof(char *),
109 XtOffsetOf(ApplArgs, execHost), XmRImmediate, (XtPointer) NULL,
112 "termOpts", "TermParms", XmRString, sizeof(char *),
113 XtOffsetOf(ApplArgs, termOpts), XmRImmediate, (XtPointer) NULL,
118 * macro to get message catalog strings
121 #ifndef NO_MESSAGE_CATALOG
123 # define _CLIENT_CAT_NAME "dtact.cat"
124 # else /* __ultrix */
125 # define _CLIENT_CAT_NAME "dtact"
126 # endif /* __ultrix */
127 extern char *_DtGetMessage(char *filename, int set, int n, char *s);
128 # define GETMESSAGE(set, number, string)\
129 (_DtGetMessage(_CLIENT_CAT_NAME, set, number, string))
131 # define GETMESSAGE(set, number, string)\
135 Boolean _DtWmStringsAreEqual(
136 register char *in_str,
137 register char *test_str) ;
139 XtPointer clientData,
141 void CheckUserRequest( void ) ;
142 void CheckPasswd( void ) ;
151 XtPointer clientData,
152 XtPointer callData) ;
155 XtPointer clientData,
156 XtPointer callData) ;
159 XtPointer clientData,
160 XtPointer callData) ;
163 XtPointer clientData,
164 XtPointer callData) ;
166 void actionStatusCallback (
167 DtActionInvocationID id,
168 XtPointer client_data,
171 DtActionStatus status );
173 void GetUserPrompt( void ) ;
174 void LogSuccess( void ) ;
175 void LogFailure( void ) ;
180 Cardinal *num_params) ;
185 Cardinal *num_params) ;
190 void UnknownUser( void ) ;
191 void UnknownUserCallback(
193 XtPointer clientData,
194 XtPointer callData) ;
197 /******** End Forward Function Declarations ********/
200 /***************************************************************************
202 * Text widget actions and translations
204 ***************************************************************************/
206 XtActionsRec textActions[] = {
207 {"my-insert", (XtActionProc)MyInsert},
208 {"my-cancel", (XtActionProc)MyCancel},
211 char textEventBindings[] = {
212 "Shift <Key>Tab: prev-tab-group() \n\
213 Ctrl <Key>Tab: next-tab-group() \n\
214 <Key>Tab: next-tab-group() \n\
215 <Key>osfEndLine: end-of-line() \n\
216 <Key>osfBeginLine: beginning-of-line() \n\
217 ~Shift <Key>osfRight: forward-character()\n\
218 ~Shift <Key>osfLeft: backward-character()\n\
219 Ctrl <Key>osfDelete: delete-to-end-of-line()\n\
220 <Key>osfDelete: delete-next-character()\n\
221 <Key>osfBackSpace: delete-previous-character()\n\
222 <Key>osfActivate: activate()\n\
223 Ctrl <Key>Return: activate()\n\
224 <Key>Return: activate()\n\
225 <Key>osfCancel: my-cancel()\n\
226 <Key>: my-insert()\n\
227 ~Ctrl ~Shift ~Meta ~Alt<Btn1Down>: grab-focus() \n\
228 <EnterWindow>: enter()\n\
229 <LeaveWindow>: leave()\n\
230 <FocusIn>: focusIn()\n\
231 <FocusOut>: focusOut()\n\
236 /****************************************************************************/
237 /****************************************************************************/
239 static Widget toplevel;
240 static ApplArgs appArgs;
241 static XtAppContext appContext;
242 static DtActionInvocationID actionId;
243 static Boolean exitAfterInvoked = False;
244 static int exitStatus = 0;
249 XtPointer clientData,
252 if ( toplevel->core.num_popups == 0 )
255 XtAppAddTimeOut(appContext,
256 10, (XtTimerCallbackProc)CheckForDone,
271 char contextDir[MAXPATHLEN+1];
272 DtActionArg *ap = NULL;
274 XtSetLanguageProc(NULL, NULL, NULL);
275 _DtEnvControl(DT_ENV_SET);
276 (void) signal(SIGCLD, (void (*)())SIG_IGN);
278 /* Initialize the toolkit and open the display */
279 XtToolkitInitialize() ;
280 appContext = XtCreateApplicationContext() ;
281 if ( !(display = XtOpenDisplay( appContext, NULL, argv[0], "Dtaction",
283 sizeof(option_list)/sizeof(XrmOptionDescRec),
286 setlocale(LC_ALL, "");
287 fprintf(stderr,GETMESSAGE(1,11,"Can't open display.\n"));
291 XtSetArg(args[n], XmNallowShellResize, True); n++;
292 XtSetArg(args[n], XmNmappedWhenManaged, False); n++;
293 XtSetArg(args[n], XmNheight, 1); n++;
294 XtSetArg(args[n], XmNwidth, 1); n++;
295 toplevel = XtAppCreateShell( argv[0], "Dtaction",
296 topLevelShellWidgetClass, display, args, n) ;
298 XtRealizeWidget(toplevel);
300 display = XtDisplay (toplevel);
301 XtGetApplicationResources(toplevel, &appArgs,
302 resources, XtNumber(resources), NULL, 0);
304 password = XtMalloc(1);
309 /* Get Dt initialized */
310 if (DtInitialize (display, toplevel, argv[0], "Dtaction") == False)
312 /* Fatal Error: could not connect to the messaging system. */
313 /* DtInitialize() has already logged an appropriate error msg */
318 * If the request specified that it wanted to run as a different
319 * user, then take care of prompting for a password, and doing any
320 * necessary verification and logging.
324 /* Load the filetype/action dbs; DtInvokeAction() requires this */
328 * Get the requested action name
330 if ( (actionName = argv[1]) == NULL)
332 fprintf(stderr,GETMESSAGE(1,10,"No action name specified.\n"));
339 * create an action arg array for the file objects for
340 * this action. This number of objects should be one
341 * less than the argument count. The returned vector will
342 * be terminated by a null pointer.
345 ap = (DtActionArg *) XtCalloc(numArgs,sizeof(DtActionArg));
349 * This client is restricted to FILE arguments.
350 * for the time being.
352 for ( n = 0; n < numArgs; n++) {
353 ap[n].argClass = DtACTION_FILE;
354 ap[n].u.file.name = argv[n+2];
357 actionId = DtActionInvoke(toplevel, actionName, ap, numArgs,
361 True, /* use indicator */
362 (DtActionCallbackProc) actionStatusCallback,
366 * Set up a timer if we didn't get a valid procId -- since there will
367 * be no invocation update in that case.
368 * We must invoke XtMainLoop() at least once, to force any prompt or
369 * error dialogs to get posted.
372 XtAppAddTimeOut(appContext,
373 10, (XtTimerCallbackProc)CheckForDone,
376 XtAppMainLoop(appContext);
382 SetGidUid ( unsigned short rgid, unsigned short ruid )
385 /* fix process gid */
386 #if defined(SVR4) || defined(_AIX)
388 #elif defined(__osf__) || defined(linux)
389 setregid(rgid, rgid);
390 #elif defined(__hpux)
391 setresgid(rgid, rgid, rgid);
393 setregid(rgid, rgid, rgid);
396 /* fix process uid */
397 #if defined (SVR4) || defined (_AIX)
399 #elif defined(__osf__) || defined(linux)
400 setreuid(ruid, ruid);
401 #elif defined(__hpux)
402 setresuid(ruid, ruid, ruid);
404 setreuid(ruid, ruid, ruid);
411 * This function checks to see if the user has requested that the action
412 * be invoked under a different user Id. If a different user Id has been
413 * requested, then the user will be prompted to enter either the password
414 * for that user, or the root password. Once a valid password has been
415 * entered, this function will return.
419 CheckUserRequest( void )
424 struct passwd * passwd;
428 Boolean notExist = False;
429 Boolean alreadySetToRoot = False;
433 /* get current group id */
435 /* get current user id */
438 /* See if the user wants to run as himself */
439 if (appArgs.user == NULL)
441 SetGidUid(rgid,ruid);
445 /* Get password for the requested user */
446 passwd = getpwnam(appArgs.user);
449 spwd = getspnam(appArgs.user);
453 if (passwd->pw_uid == ruid)
456 * We are already running as the
457 * requested user. So return now.
459 SetGidUid(rgid,ruid);
465 toPword = XtNewString(spwd->sp_pwdp);
468 if (passwd->pw_passwd)
469 toPword = XtNewString(passwd->pw_passwd);
471 basegid = passwd->pw_gid;
472 newuid = passwd->pw_uid;
477 /* Root requests require some extra work later */
478 if (strcmp(appArgs.user, "root") == 0)
481 /* Get name for the current user */
482 passwd = getpwuid(ruid);
483 if (passwd && passwd->pw_name)
484 origName = XtNewString(passwd->pw_name);
486 /* Get password for the root user */
487 passwd = getpwnam("root");
488 if (passwd && passwd->pw_passwd)
491 spwd = getspnam("root");
492 if (spwd && spwd->sp_pwdp)
494 rootPword = XtNewString(spwd->sp_pwdp);
497 rootPword = XtNewString(passwd->pw_passwd);
500 if (passwd->pw_uid == ruid)
501 alreadySetToRoot = True;
505 * If 'alreadySetToRoot' is set to True, then that means that the
506 * user is currently running as root.
511 /* Requested user does not exist; this function will exit() */
514 else if ((alreadySetToRoot) || /* requested users passwd is null */
515 ((toPword && (toPword[0] == '\0')) || (toPword == NULL)))
517 /* Already there -- no need to check a passwd */
526 * void CheckPasswd ()
528 * get a password from the user and check it against an encrypted passwd
543 * get this users password
550 * void AddSuLog (FromName, ToName, ChangeType)
552 * add switch from user "FromName" to user "ToName" to sulog.
553 * ChangeType is "+" for success, "-" for failure.
556 * char *FromName -- from name (for logging).
557 * char *ToName -- to name (for logging).
558 * char *ChangeType -- +/- (for logging).
569 struct tm *localtime ();
576 #ifdef hpV4 /* 10.* versions */
577 char * SULog = "/var/adm/sulog";
578 #elif defined( hpux ) /* 9.* versions */
579 char * SULog = "/usr/adm/sulog";
581 char * SULog = "/var/adm/sulog";
584 if ((f = fopen (SULog, "a")) == NULL)
587 (void) time (&timenow);
588 now = localtime (&timenow);
590 /* build toString... */
591 if (ToName && *ToName)
596 fprintf(f, (GETMESSAGE(1,1,
597 "dtaction %1$.2d/%2$.2d %3$.2d:%4$.2d %5$1.1s %6$s %7$s-%8$s\n")),
598 now -> tm_mon + 1, now -> tm_mday, now -> tm_hour,
599 now -> tm_min, ChangeType, "?", FromName, toString);
604 * take away write access from SULog
607 if (stat (SULog, &st) == 0)
608 chmod (SULog, (int) (st.st_mode & 07777) & ~0222);
615 * void CleanPath (Path);
617 * remove any directories from the path that are
618 * - null (leading/trailing colon or double colon)
619 * - not anchored to root (no leading /)
621 * the returned path is the original path with any such
622 * directories stripped
625 * char *Path -- $PATH to clean
631 * Unanchored paths will be stripped off of Path.
639 register char *StrippedPath;
640 register char *PathHead;
642 StrippedPath = PathHead = Path;
647 * remove multiple ':'s
650 while (*Path && (*Path == ':')) {
655 * is the first character of this
656 * directory a '/'????
662 * copy directory intact;
665 while (*Path && (*Path != ':')) {
666 *StrippedPath++ = *Path++;
670 *StrippedPath++ = *Path++;
679 while (*Path && (*Path != ':')) {
691 * remove all trailing ':'s
694 while ((StrippedPath > PathHead) && (StrippedPath[-1] == ':')) {
699 * null terminate the path
702 *StrippedPath = '\0';
708 * This is the Ok callback for the password dialog. It will attempt to
709 * validate the password. If invalid, then an error dialog is posted,
710 * and the user is prompted to try again. If valid, then the process
711 * will change to run as the requested user, and dtaction will continue
712 * on its way, attempting to invoke the requested action.
719 XtPointer clientData,
723 Boolean valid = False;
725 /* Do any verification here */
727 /* check for primary passwd... */
728 if (!strcmp (crypt (password, toPword), toPword))
731 /* check for secondary passwd ... */
732 if (rootPword && *rootPword &&
733 !strcmp (crypt (password, rootPword), rootPword))
737 else if (((rootPword == NULL) || (*rootPword == '\0')) &&
740 /* No root password, and the user entered no password */
745 /* If valid password, then unpost */
748 XtUnmanageChild(dlog);
749 XFlush(XtDisplay(dlog));
755 /* Invalid password */
765 okLabel = XmStringCreateLocalized(GETMESSAGE(1, 2, "OK"));
766 template = (GETMESSAGE(1,3, "The password you entered does not match\nthe password for user %s.\n\nPlease reenter the password, or select the\nCancel button to terminate the operation."));
767 master = XtMalloc(strlen(template) + strlen(appArgs.user) + 10);
768 sprintf(master, template, appArgs.user);
769 message = XmStringCreateLocalized(master);
770 title = (GETMESSAGE(1,4, "Action Invoker - Password Error"));
772 /* Post an error dialog */
774 XtSetArg(args[n], XmNtitle, title); n++;
775 XtSetArg(args[n], XmNmessageString, message); n++;
776 XtSetArg(args[n], XmNokLabelString, okLabel); n++;
777 err = XmCreateErrorDialog(dlog, "err", args, n);
778 XtUnmanageChild(XmMessageBoxGetChild(err, XmDIALOG_CANCEL_BUTTON));
779 XtUnmanageChild(XmMessageBoxGetChild(err, XmDIALOG_HELP_BUTTON));
781 XtAddCallback(err, XmNokCallback, ErrOkCallback, err);
783 XFlush(XtDisplay(dlog));
784 XmUpdateDisplay(dlog);
786 XmStringFree(okLabel);
787 XmStringFree(message);
794 * This is the Cancel callback for the password dialog. It will unpost
795 * the dialog, and exit.
802 XtPointer clientData,
806 XtUnmanageChild(dlog);
807 XFlush(XtDisplay(dlog));
813 * This is the 'Ok' callback for the invalid password error dialog.
814 * It will simply unpost and destroy the error dialog.
821 XtPointer clientData,
825 Widget err = (Widget)clientData;
827 XtUnmanageChild(err);
828 XFlush(XtDisplay(err));
829 XmUpdateDisplay(err);
830 XtDestroyWidget(err);
835 * This callback is invoked when the password dialog is posted; it forces
836 * the focus to the text input field.
843 XtPointer clientData,
848 Widget dlog = (Widget)clientData;
850 /* Force focus initially to the text field */
851 text = XmSelectionBoxGetChild(dlog, XmDIALOG_TEXT);
852 XmProcessTraversal(text, XmTRAVERSE_CURRENT);
857 * This function creates the prompt dialog for collecting the password
858 * from the user. It will not give up control until a valid password
859 * has been entered. If the user cancels the request, then the cancel
860 * callback will exit.
864 GetUserPrompt( void )
875 XtTranslations textTable;
876 XmString cancelLabel;
879 sprintf(prompt, (GETMESSAGE(1,5, "Enter password for user %s:")),
881 xmString = XmStringCreateLocalized(prompt);
882 xmString2 =XmStringCreateLocalized(GETMESSAGE(1,6, "Action Invoker - Password"));
883 cancelLabel = XmStringCreateLocalized(GETMESSAGE(1,7, "Cancel"));
884 okLabel = XmStringCreateLocalized(GETMESSAGE(1,2, "OK"));
886 XtAppAddActions(appContext,textActions, 2);
887 textTable = XtParseTranslationTable(textEventBindings);
889 /* Create the prompt dialog */
891 XtSetArg(args[n], XmNselectionLabelString, xmString); n++;
892 XtSetArg(args[n], XmNdialogTitle, xmString2); n++;
893 XtSetArg(args[n], XmNautoUnmanage, False); n++;
894 XtSetArg(args[n], XmNokLabelString, okLabel); n++;
895 XtSetArg(args[n], XmNcancelLabelString, cancelLabel); n++;
896 XtSetArg(args[n], XmNdefaultPosition, False); n++;
897 dlog = XmCreatePromptDialog(toplevel, "prompt", args, n);
898 XmStringFree(xmString);
899 XmStringFree(xmString2);
900 XmStringFree(okLabel);
901 XmStringFree(cancelLabel);
902 XtAddCallback(dlog, XmNokCallback, OkCallback, NULL);
903 XtAddCallback(dlog, XmNcancelCallback, CancelCallback, NULL);
905 text = XmSelectionBoxGetChild(dlog, XmDIALOG_TEXT);
907 XtSetArg(args[n], XmNtranslations, textTable); n++;
908 XtSetArg(args[n], XmNverifyBell, False); n++;
909 XtSetValues(text, args, n);
910 XtAddCallback(text, XmNmodifyVerifyCallback, EditPasswdCB, NULL);
912 /* Add callback for forcing traversal to the text field */
913 XtAddCallback (XtParent(dlog), XmNpopupCallback, MapCallback, dlog);
915 /* Unmanage the help button */
916 help = XmSelectionBoxGetChild(dlog, XmDIALOG_HELP_BUTTON);
917 XtUnmanageChild(help);
919 /* Center the dialog */
920 XtRealizeWidget(dlog);
921 XtSetArg (args[0], XmNx,
922 (Position)(WidthOfScreen(XtScreen(dlog)) -
923 dlog->core.width) / 2);
924 XtSetArg (args[1], XmNy,
925 (Position)(HeightOfScreen(XtScreen(dlog)) -
926 dlog->core.height) / 2);
927 XtSetValues (dlog, args, 2);
929 /* Set the transient property */
930 XSetTransientForHint (XtDisplay (toplevel),
931 XtWindow (XtParent (dlog)),
932 XtWindow (toplevel));
934 /* Adjust the decorations for the dialog shell of the dialog */
936 XtSetArg(args[n], XmNmwmFunctions, 0); n++;
937 XtSetArg(args[n], XmNmwmDecorations,
938 MWM_DECOR_BORDER | MWM_DECOR_TITLE); n++;
939 XtSetValues(XtParent(dlog), args, n);
941 /* Post the dialog */
944 /* Wait for the user to finish with the dialog */
947 XtAppNextEvent(appContext,&event);
948 XtDispatchEvent(&event);
951 /* Destroy the widget, and return any data back to the appl */
952 XtDestroyWidget(dlog);
957 * When a user has successfully logged in as another user, we need to set
958 * the uid and gid to the requested user. In addition, if the user is
959 * changing to 'root', then we need to log this in /usr/adm/sulog, and
960 * we need to do some housekeeping of the $PATH environment variable.
970 AddSuLog(origName, appArgs.user, "+");
974 /* Special stuff for the root user */
975 /* Cleanse the $PATH setting */
976 tmpPath = getenv("PATH");
977 path = XtNewString(tmpPath);
979 tmpPath = XtMalloc(strlen(path) + 10);
980 strcpy(tmpPath, "PATH=");
981 strcat(tmpPath, path);
985 /* Set up the user's new id's */
986 SetGidUid(basegid,newuid);
988 initgroups(appArgs.user, basegid);
995 * Each time the user enters an invalid password, we need to log this in
996 * /usr/adm/sulog, if the user is attempting to switch to the 'root' user.
1003 /* Unable to change to specified user; post error, then exit */
1004 AddSuLog(origName, appArgs.user, "-");
1008 /***************************************************************************
1012 * Local self-insert action for the text widget. The default action
1013 * discards control characters, which are allowed in password.
1014 ***************************************************************************/
1022 Cardinal *num_params )
1025 XComposeStatus compstatus;
1028 n = XLookupString((XKeyEvent *)event, str, sizeof(str),
1029 (KeySym *)NULL, &compstatus);
1033 XmTextFieldInsert(w, XmTextFieldGetInsertionPosition(w), str);
1038 /***************************************************************************
1042 * This action catches the 'Escape' key, and following Motif standards,
1043 * unposts the dialog, as if the 'Cancel' button had been pressed.
1044 ***************************************************************************/
1052 Cardinal *num_params )
1054 CancelCallback(w, NULL, NULL);
1059 /***************************************************************************
1063 * implement no-echo of the password
1064 ***************************************************************************/
1075 static Boolean allow_flag = False;
1076 int replaced_length, i;
1078 XmTextVerifyPtr cbData = (XmTextVerifyPtr) call;
1083 * we need to keep track of the password ourselves in order to
1084 * disable echoing of the password...
1087 replaced_length = cbData->endPos - cbData->startPos;
1088 if (replaced_length > cbData->text->length)
1090 /* shift the text at and after endPos to the left... */
1091 for (src = password + cbData->endPos,
1092 dst = src + (cbData->text->length - replaced_length),
1093 i = passwordLength - cbData->endPos;
1100 else if (replaced_length < cbData->text->length)
1102 /* Buffer must grow */
1103 password = XtRealloc(password,
1104 passwordLength + cbData->text->length - replaced_length + 5);
1106 /* shift the text at and after endPos to the right... */
1107 for (src = password + passwordLength - 1,
1108 dst = src + (cbData->text->length - replaced_length),
1109 i = passwordLength - cbData->endPos;
1118 * update the password...
1121 for (src = cbData->text->ptr,
1122 dst = password + cbData->startPos,
1123 i = cbData->text->length;
1130 passwordLength += cbData->text->length - replaced_length;
1131 password[passwordLength] = '\0';
1132 stars = XtRealloc(stars, cbData->text->length + 10);
1133 for (i = 0; i < cbData->text->length; i++)
1135 stars[cbData->text->length] = '\0';
1138 * put the appropriate number of stars in the passwd Widget..
1142 XmTextFieldReplace(w, cbData->startPos, cbData->endPos, stars);
1146 cbData->doit = allow_flag;
1151 * This function posts an error dialog informing the user that they have
1152 * specified an invalid user name. No further processing will be done; we
1153 * will simply wait for the user to acknowledge the error, and then exit.
1169 okLabel = XmStringCreateLocalized(GETMESSAGE(1,2, "OK"));
1170 template = (GETMESSAGE(1,8, "The user '%s' is an unknown user name.\n\nThe requested action will not be executed."));
1171 master = XtMalloc(strlen(template) + strlen(appArgs.user) + 10);
1172 sprintf(master, template, appArgs.user);
1173 message = XmStringCreateLocalized(master);
1174 title = (GETMESSAGE(1,9, "Action Invoker - Unknown User"));
1176 /* Post an error dialog */
1178 XtSetArg(args[n], XmNtitle, title); n++;
1179 XtSetArg(args[n], XmNmessageString, message); n++;
1180 XtSetArg(args[n], XmNokLabelString, okLabel); n++;
1181 XtSetArg(args[n], XmNdefaultPosition, False); n++;
1182 err = XmCreateErrorDialog(toplevel, "err", args, n);
1183 XtUnmanageChild(XmMessageBoxGetChild(err, XmDIALOG_CANCEL_BUTTON));
1184 XtUnmanageChild(XmMessageBoxGetChild(err, XmDIALOG_HELP_BUTTON));
1186 /* Center the dialog */
1187 XtRealizeWidget(err);
1188 XtSetArg (args[0], XmNx,
1189 (Position)(WidthOfScreen(XtScreen(err)) -
1190 err->core.width) / 2);
1191 XtSetArg (args[1], XmNy,
1192 (Position)(HeightOfScreen(XtScreen(err)) -
1193 err->core.height) / 2);
1194 XtSetValues (err, args, 2);
1197 XtAddCallback(err, XmNokCallback, UnknownUserCallback, err);
1198 XtAddCallback(err, XmNcancelCallback, UnknownUserCallback, err);
1200 XFlush(XtDisplay(toplevel));
1201 XmUpdateDisplay(toplevel);
1203 XmStringFree(okLabel);
1204 XmStringFree(message);
1206 XtAppMainLoop(appContext);
1211 * This is the 'Cancel' callback for the 'Invalid User' error dialog.
1212 * It removes the dialog, and then exits.
1217 UnknownUserCallback(
1219 XtPointer clientData,
1220 XtPointer callData )
1223 Widget err = (Widget)clientData;
1225 XtUnmanageChild(err);
1226 XFlush(XtDisplay(err));
1227 XmUpdateDisplay(err);
1231 void actionStatusCallback(
1232 DtActionInvocationID id,
1233 XtPointer client_data,
1236 DtActionStatus status )
1240 case DtACTION_INVOKED:
1242 * There may still be error dialogs to post so we must return
1243 * to mainLoop before exiting.
1245 if ( exitAfterInvoked )
1246 XtAppAddTimeOut(appContext,
1247 10 , (XtTimerCallbackProc)CheckForDone,
1252 XtAppAddTimeOut(appContext,
1253 10 , (XtTimerCallbackProc)CheckForDone,
1257 case DtACTION_FAILED:
1258 case DtACTION_CANCELED:
1260 XtAppAddTimeOut(appContext,
1261 10 , (XtTimerCallbackProc)CheckForDone,