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
23 /* $TOG: Main.c /main/18 1998/07/23 17:56:36 mgreess $ */
24 /*****************************************************************************
25 *****************************************************************************
31 ** Description: This file contains the main program for dtaction.
34 **(c) Copyright 1993, 1994 Hewlett-Packard Company
35 **(c) Copyright 1993, 1994 International Business Machines Corp.
36 **(c) Copyright 1993, 1994 Sun Microsystems, Inc.
37 **(c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of Novell, Inc.
40 ****************************************************************************
41 ************************************<+>*************************************/
49 #include <sys/param.h> /* for MAXPATHLEN and MAXHOSTNAMELEN */
60 #include <X11/Intrinsic.h>
63 #include <Xm/SelectioB.h>
64 #include <Xm/MessageB.h>
65 #include <Xm/Protocols.h>
66 #include <Xm/MwmUtil.h>
69 #include <Dt/DbUtil.h>
70 #include <Dt/CmdInv.h>
71 #include <Dt/Action.h>
72 #include <Dt/EnvControlP.h>
75 /******************************************************************************/
80 /* Command line options */
81 XrmOptionDescRec option_list[] =
83 { "-user", "user", XrmoptionSepArg, NULL},
84 { "-contextDir", "contextDir", XrmoptionSepArg, NULL},
85 { "-execHost", "execHost", XrmoptionSepArg, NULL},
86 { "-termOpts", "termOpts", XrmoptionSepArg, NULL},
89 /* Fallback Resources */
90 static char *fallback_resources[] = {
100 } ApplArgs, *ApplArgsPtr;
102 #define LOGIN_STR_LEN 15
108 int passwordLength = 0;
110 Boolean finished = False;
111 Boolean rootRequest = False;
112 char * toPword = NULL;
113 char * rootPword = NULL;
114 char * origName = "Unknown";
118 /* Dtaction resources */
119 XtResource resources[] =
122 "user", "User", XmRString, sizeof(char *),
123 XtOffsetOf(ApplArgs, user), XmRImmediate, (XtPointer) NULL,
126 "contextDir", "ContextDir", XmRString, sizeof(char *),
127 XtOffsetOf(ApplArgs, contextDir), XmRImmediate, (XtPointer) NULL,
130 "execHost", "ExecHost", XmRString, sizeof(char *),
131 XtOffsetOf(ApplArgs, execHost), XmRImmediate, (XtPointer) NULL,
134 "termOpts", "TermParms", XmRString, sizeof(char *),
135 XtOffsetOf(ApplArgs, termOpts), XmRImmediate, (XtPointer) NULL,
140 * macro to get message catalog strings
143 #ifndef NO_MESSAGE_CATALOG
145 # define _CLIENT_CAT_NAME "dtact.cat"
146 # else /* __ultrix */
147 # define _CLIENT_CAT_NAME "dtact"
148 # endif /* __ultrix */
149 extern char *_DtGetMessage(char *filename, int set, int n, char *s);
150 # define GETMESSAGE(set, number, string)\
151 (_DtGetMessage(_CLIENT_CAT_NAME, set, number, string))
153 # define GETMESSAGE(set, number, string)\
157 Boolean _DtWmStringsAreEqual(
158 register char *in_str,
159 register char *test_str) ;
161 XtPointer clientData,
163 void CheckUserRequest( void ) ;
164 void CheckPasswd( void ) ;
173 XtPointer clientData,
174 XtPointer callData) ;
177 XtPointer clientData,
178 XtPointer callData) ;
181 XtPointer clientData,
182 XtPointer callData) ;
185 XtPointer clientData,
186 XtPointer callData) ;
188 void actionStatusCallback (
189 DtActionInvocationID id,
190 XtPointer client_data,
193 DtActionStatus status );
195 void GetUserPrompt( void ) ;
196 void LogSuccess( void ) ;
197 void LogFailure( void ) ;
202 Cardinal *num_params) ;
207 Cardinal *num_params) ;
212 void UnknownUser( void ) ;
213 void UnknownUserCallback(
215 XtPointer clientData,
216 XtPointer callData) ;
219 /******** End Forward Function Declarations ********/
222 /***************************************************************************
224 * Text widget actions and translations
226 ***************************************************************************/
228 XtActionsRec textActions[] = {
229 {"my-insert", (XtActionProc)MyInsert},
230 {"my-cancel", (XtActionProc)MyCancel},
233 char textEventBindings[] = {
234 "Shift <Key>Tab: prev-tab-group() \n\
235 Ctrl <Key>Tab: next-tab-group() \n\
236 <Key>Tab: next-tab-group() \n\
237 <Key>osfEndLine: end-of-line() \n\
238 <Key>osfBeginLine: beginning-of-line() \n\
239 ~Shift <Key>osfRight: forward-character()\n\
240 ~Shift <Key>osfLeft: backward-character()\n\
241 Ctrl <Key>osfDelete: delete-to-end-of-line()\n\
242 <Key>osfDelete: delete-next-character()\n\
243 <Key>osfBackSpace: delete-previous-character()\n\
244 <Key>osfActivate: activate()\n\
245 Ctrl <Key>Return: activate()\n\
246 <Key>Return: activate()\n\
247 <Key>osfCancel: my-cancel()\n\
248 <Key>: my-insert()\n\
249 ~Ctrl ~Shift ~Meta ~Alt<Btn1Down>: grab-focus() \n\
250 <EnterWindow>: enter()\n\
251 <LeaveWindow>: leave()\n\
252 <FocusIn>: focusIn()\n\
253 <FocusOut>: focusOut()\n\
258 /****************************************************************************/
259 /****************************************************************************/
261 static Widget toplevel;
262 static ApplArgs appArgs;
263 static XtAppContext appContext;
264 static DtActionInvocationID actionId;
265 static Boolean exitAfterInvoked = False;
266 static int exitStatus = 0;
271 XtPointer clientData,
274 if ( toplevel->core.num_popups == 0 )
277 XtAppAddTimeOut(appContext,
278 10, (XtTimerCallbackProc)CheckForDone,
293 char contextDir[MAXPATHLEN+1];
294 DtActionArg *ap = NULL;
296 XtSetLanguageProc(NULL, NULL, NULL);
297 _DtEnvControl(DT_ENV_SET);
298 (void) signal(SIGCHLD, (void (*)())SIG_IGN);
300 /* Initialize the toolkit and open the display */
301 XtToolkitInitialize() ;
302 appContext = XtCreateApplicationContext() ;
303 if ( !(display = XtOpenDisplay( appContext, NULL, argv[0], "Dtaction",
305 sizeof(option_list)/sizeof(XrmOptionDescRec),
308 setlocale(LC_ALL, "");
309 fprintf(stderr,GETMESSAGE(1,11,"Can't open display.\n"));
313 XtSetArg(args[n], XmNallowShellResize, True); n++;
314 XtSetArg(args[n], XmNmappedWhenManaged, False); n++;
315 XtSetArg(args[n], XmNheight, 1); n++;
316 XtSetArg(args[n], XmNwidth, 1); n++;
317 toplevel = XtAppCreateShell( argv[0], "Dtaction",
318 topLevelShellWidgetClass, display, args, n) ;
320 XtRealizeWidget(toplevel);
322 display = XtDisplay (toplevel);
323 XtGetApplicationResources(toplevel, &appArgs,
324 resources, XtNumber(resources), NULL, 0);
326 password = XtMalloc(1);
331 /* Get Dt initialized */
332 if (DtInitialize (display, toplevel, argv[0], "Dtaction") == False)
334 /* Fatal Error: could not connect to the messaging system. */
335 /* DtInitialize() has already logged an appropriate error msg */
340 * If the request specified that it wanted to run as a different
341 * user, then take care of prompting for a password, and doing any
342 * necessary verification and logging.
346 /* Load the filetype/action dbs; DtInvokeAction() requires this */
350 * Get the requested action name
352 if ( (actionName = argv[1]) == NULL)
354 fprintf(stderr,GETMESSAGE(1,10,"No action name specified.\n"));
361 * create an action arg array for the file objects for
362 * this action. This number of objects should be one
363 * less than the argument count. The returned vector will
364 * be terminated by a null pointer.
367 ap = (DtActionArg *) XtCalloc(numArgs,sizeof(DtActionArg));
371 * This client is restricted to FILE arguments.
372 * for the time being.
374 for ( n = 0; n < numArgs; n++) {
375 ap[n].argClass = DtACTION_FILE;
376 ap[n].u.file.name = argv[n+2];
379 actionId = DtActionInvoke(toplevel, actionName, ap, numArgs,
383 True, /* use indicator */
384 (DtActionCallbackProc) actionStatusCallback,
388 * Set up a timer if we didn't get a valid procId -- since there will
389 * be no invocation update in that case.
390 * We must invoke XtMainLoop() at least once, to force any prompt or
391 * error dialogs to get posted.
394 XtAppAddTimeOut(appContext,
395 10, (XtTimerCallbackProc)CheckForDone,
398 XtAppMainLoop(appContext);
404 SetGidUid ( unsigned short rgid, unsigned short ruid )
407 /* fix process gid */
408 #if defined(SVR4) || defined(_AIX)
410 #elif defined(__osf__) || defined(linux) || defined(CSRG_BASED)
411 setregid(rgid, rgid);
412 #elif defined(__hpux)
413 setresgid(rgid, rgid, rgid);
415 setregid(rgid, rgid, rgid);
418 /* fix process uid */
419 #if defined (SVR4) || defined (_AIX)
421 #elif defined(__osf__) || defined(linux) || defined(CSRG_BASED)
422 setreuid(ruid, ruid);
423 #elif defined(__hpux)
424 setresuid(ruid, ruid, ruid);
426 setreuid(ruid, ruid, ruid);
433 * This function checks to see if the user has requested that the action
434 * be invoked under a different user Id. If a different user Id has been
435 * requested, then the user will be prompted to enter either the password
436 * for that user, or the root password. Once a valid password has been
437 * entered, this function will return.
441 CheckUserRequest( void )
446 struct passwd * passwd;
450 Boolean notExist = False;
451 Boolean alreadySetToRoot = False;
455 /* get current group id */
457 /* get current user id */
460 /* See if the user wants to run as himself */
461 if (appArgs.user == NULL)
463 SetGidUid(rgid,ruid);
467 /* Get password for the requested user */
468 passwd = getpwnam(appArgs.user);
471 spwd = getspnam(appArgs.user);
475 if (passwd->pw_uid == ruid)
478 * We are already running as the
479 * requested user. So return now.
481 SetGidUid(rgid,ruid);
487 toPword = XtNewString(spwd->sp_pwdp);
490 if (passwd->pw_passwd)
491 toPword = XtNewString(passwd->pw_passwd);
493 basegid = passwd->pw_gid;
494 newuid = passwd->pw_uid;
499 /* Root requests require some extra work later */
500 if (strcmp(appArgs.user, "root") == 0)
503 /* Get name for the current user */
504 passwd = getpwuid(ruid);
505 if (passwd && passwd->pw_name)
506 origName = XtNewString(passwd->pw_name);
508 /* Get password for the root user */
509 passwd = getpwnam("root");
510 if (passwd && passwd->pw_passwd)
513 spwd = getspnam("root");
514 if (spwd && spwd->sp_pwdp)
516 rootPword = XtNewString(spwd->sp_pwdp);
519 rootPword = XtNewString(passwd->pw_passwd);
522 if (passwd->pw_uid == ruid)
523 alreadySetToRoot = True;
527 * If 'alreadySetToRoot' is set to True, then that means that the
528 * user is currently running as root.
533 /* Requested user does not exist; this function will exit() */
536 else if ((alreadySetToRoot) || /* requested users passwd is null */
537 ((toPword && (toPword[0] == '\0')) || (toPword == NULL)))
539 /* Already there -- no need to check a passwd */
548 * void CheckPasswd ()
550 * get a password from the user and check it against an encrypted passwd
565 * get this users password
572 * void AddSuLog (FromName, ToName, ChangeType)
574 * add switch from user "FromName" to user "ToName" to sulog.
575 * ChangeType is "+" for success, "-" for failure.
578 * char *FromName -- from name (for logging).
579 * char *ToName -- to name (for logging).
580 * char *ChangeType -- +/- (for logging).
591 struct tm *localtime ();
598 #ifdef hpV4 /* 10.* versions */
599 char * SULog = "/var/adm/sulog";
600 #elif defined( hpux ) /* 9.* versions */
601 char * SULog = "/usr/adm/sulog";
603 char * SULog = "/var/adm/sulog";
606 if ((f = fopen (SULog, "a")) == NULL)
609 (void) time (&timenow);
610 now = localtime (&timenow);
612 /* build toString... */
613 if (ToName && *ToName)
618 fprintf(f, (GETMESSAGE(1,1,
619 "dtaction %1$.2d/%2$.2d %3$.2d:%4$.2d %5$1.1s %6$s %7$s-%8$s\n")),
620 now -> tm_mon + 1, now -> tm_mday, now -> tm_hour,
621 now -> tm_min, ChangeType, "?", FromName, toString);
626 * take away write access from SULog
629 if (stat (SULog, &st) == 0)
630 chmod (SULog, (int) (st.st_mode & 07777) & ~0222);
637 * void CleanPath (Path);
639 * remove any directories from the path that are
640 * - null (leading/trailing colon or double colon)
641 * - not anchored to root (no leading /)
643 * the returned path is the original path with any such
644 * directories stripped
647 * char *Path -- $PATH to clean
653 * Unanchored paths will be stripped off of Path.
661 register char *StrippedPath;
662 register char *PathHead;
664 StrippedPath = PathHead = Path;
669 * remove multiple ':'s
672 while (*Path && (*Path == ':')) {
677 * is the first character of this
678 * directory a '/'????
684 * copy directory intact;
687 while (*Path && (*Path != ':')) {
688 *StrippedPath++ = *Path++;
692 *StrippedPath++ = *Path++;
701 while (*Path && (*Path != ':')) {
713 * remove all trailing ':'s
716 while ((StrippedPath > PathHead) && (StrippedPath[-1] == ':')) {
721 * null terminate the path
724 *StrippedPath = '\0';
730 * This is the Ok callback for the password dialog. It will attempt to
731 * validate the password. If invalid, then an error dialog is posted,
732 * and the user is prompted to try again. If valid, then the process
733 * will change to run as the requested user, and dtaction will continue
734 * on its way, attempting to invoke the requested action.
741 XtPointer clientData,
745 Boolean valid = False;
747 /* Do any verification here */
749 /* check for primary passwd... */
750 if (!strcmp (crypt (password, toPword), toPword))
753 /* check for secondary passwd ... */
754 if (rootPword && *rootPword &&
755 !strcmp (crypt (password, rootPword), rootPword))
759 else if (((rootPword == NULL) || (*rootPword == '\0')) &&
762 /* No root password, and the user entered no password */
767 /* If valid password, then unpost */
770 XtUnmanageChild(dlog);
771 XFlush(XtDisplay(dlog));
777 /* Invalid password */
787 okLabel = XmStringCreateLocalized(GETMESSAGE(1, 2, "OK"));
788 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."));
789 master = XtMalloc(strlen(template) + strlen(appArgs.user) + 10);
790 sprintf(master, template, appArgs.user);
791 message = XmStringCreateLocalized(master);
792 title = (GETMESSAGE(1,4, "Action Invoker - Password Error"));
794 /* Post an error dialog */
796 XtSetArg(args[n], XmNtitle, title); n++;
797 XtSetArg(args[n], XmNmessageString, message); n++;
798 XtSetArg(args[n], XmNokLabelString, okLabel); n++;
799 err = XmCreateErrorDialog(dlog, "err", args, n);
800 XtUnmanageChild(XmMessageBoxGetChild(err, XmDIALOG_CANCEL_BUTTON));
801 XtUnmanageChild(XmMessageBoxGetChild(err, XmDIALOG_HELP_BUTTON));
803 XtAddCallback(err, XmNokCallback, ErrOkCallback, err);
805 XFlush(XtDisplay(dlog));
806 XmUpdateDisplay(dlog);
808 XmStringFree(okLabel);
809 XmStringFree(message);
816 * This is the Cancel callback for the password dialog. It will unpost
817 * the dialog, and exit.
824 XtPointer clientData,
828 XtUnmanageChild(dlog);
829 XFlush(XtDisplay(dlog));
835 * This is the 'Ok' callback for the invalid password error dialog.
836 * It will simply unpost and destroy the error dialog.
843 XtPointer clientData,
847 Widget err = (Widget)clientData;
849 XtUnmanageChild(err);
850 XFlush(XtDisplay(err));
851 XmUpdateDisplay(err);
852 XtDestroyWidget(err);
857 * This callback is invoked when the password dialog is posted; it forces
858 * the focus to the text input field.
865 XtPointer clientData,
870 Widget dlog = (Widget)clientData;
872 /* Force focus initially to the text field */
873 text = XmSelectionBoxGetChild(dlog, XmDIALOG_TEXT);
874 XmProcessTraversal(text, XmTRAVERSE_CURRENT);
879 * This function creates the prompt dialog for collecting the password
880 * from the user. It will not give up control until a valid password
881 * has been entered. If the user cancels the request, then the cancel
882 * callback will exit.
886 GetUserPrompt( void )
897 XtTranslations textTable;
898 XmString cancelLabel;
901 snprintf(prompt, sizeof prompt, (GETMESSAGE(1,5, "Enter password for user %s:")),
903 xmString = XmStringCreateLocalized(prompt);
904 xmString2 =XmStringCreateLocalized(GETMESSAGE(1,6, "Action Invoker - Password"));
905 cancelLabel = XmStringCreateLocalized(GETMESSAGE(1,7, "Cancel"));
906 okLabel = XmStringCreateLocalized(GETMESSAGE(1,2, "OK"));
908 XtAppAddActions(appContext,textActions, 2);
909 textTable = XtParseTranslationTable(textEventBindings);
911 /* Create the prompt dialog */
913 XtSetArg(args[n], XmNselectionLabelString, xmString); n++;
914 XtSetArg(args[n], XmNdialogTitle, xmString2); n++;
915 XtSetArg(args[n], XmNautoUnmanage, False); n++;
916 XtSetArg(args[n], XmNokLabelString, okLabel); n++;
917 XtSetArg(args[n], XmNcancelLabelString, cancelLabel); n++;
918 XtSetArg(args[n], XmNdefaultPosition, False); n++;
919 dlog = XmCreatePromptDialog(toplevel, "prompt", args, n);
920 XmStringFree(xmString);
921 XmStringFree(xmString2);
922 XmStringFree(okLabel);
923 XmStringFree(cancelLabel);
924 XtAddCallback(dlog, XmNokCallback, OkCallback, NULL);
925 XtAddCallback(dlog, XmNcancelCallback, CancelCallback, NULL);
927 text = XmSelectionBoxGetChild(dlog, XmDIALOG_TEXT);
929 XtSetArg(args[n], XmNtranslations, textTable); n++;
930 XtSetArg(args[n], XmNverifyBell, False); n++;
931 XtSetValues(text, args, n);
932 XtAddCallback(text, XmNmodifyVerifyCallback, EditPasswdCB, NULL);
934 /* Add callback for forcing traversal to the text field */
935 XtAddCallback (XtParent(dlog), XmNpopupCallback, MapCallback, dlog);
937 /* Unmanage the help button */
938 help = XmSelectionBoxGetChild(dlog, XmDIALOG_HELP_BUTTON);
939 XtUnmanageChild(help);
941 /* Center the dialog */
942 XtRealizeWidget(dlog);
943 XtSetArg (args[0], XmNx,
944 (Position)(WidthOfScreen(XtScreen(dlog)) -
945 dlog->core.width) / 2);
946 XtSetArg (args[1], XmNy,
947 (Position)(HeightOfScreen(XtScreen(dlog)) -
948 dlog->core.height) / 2);
949 XtSetValues (dlog, args, 2);
951 /* Set the transient property */
952 XSetTransientForHint (XtDisplay (toplevel),
953 XtWindow (XtParent (dlog)),
954 XtWindow (toplevel));
956 /* Adjust the decorations for the dialog shell of the dialog */
958 XtSetArg(args[n], XmNmwmFunctions, 0); n++;
959 XtSetArg(args[n], XmNmwmDecorations,
960 MWM_DECOR_BORDER | MWM_DECOR_TITLE); n++;
961 XtSetValues(XtParent(dlog), args, n);
963 /* Post the dialog */
966 /* Wait for the user to finish with the dialog */
969 XtAppNextEvent(appContext,&event);
970 XtDispatchEvent(&event);
973 /* Destroy the widget, and return any data back to the appl */
974 XtDestroyWidget(dlog);
979 * When a user has successfully logged in as another user, we need to set
980 * the uid and gid to the requested user. In addition, if the user is
981 * changing to 'root', then we need to log this in /usr/adm/sulog, and
982 * we need to do some housekeeping of the $PATH environment variable.
992 AddSuLog(origName, appArgs.user, "+");
996 /* Special stuff for the root user */
997 /* Cleanse the $PATH setting */
998 tmpPath = getenv("PATH");
999 path = XtNewString(tmpPath);
1001 tmpPath = XtMalloc(strlen(path) + 10);
1002 strcpy(tmpPath, "PATH=");
1003 strcat(tmpPath, path);
1007 /* Set up the user's new id's */
1008 SetGidUid(basegid,newuid);
1010 initgroups(appArgs.user, basegid);
1017 * Each time the user enters an invalid password, we need to log this in
1018 * /usr/adm/sulog, if the user is attempting to switch to the 'root' user.
1025 /* Unable to change to specified user; post error, then exit */
1026 AddSuLog(origName, appArgs.user, "-");
1030 /***************************************************************************
1034 * Local self-insert action for the text widget. The default action
1035 * discards control characters, which are allowed in password.
1036 ***************************************************************************/
1044 Cardinal *num_params )
1047 XComposeStatus compstatus;
1050 n = XLookupString((XKeyEvent *)event, str, sizeof(str),
1051 (KeySym *)NULL, &compstatus);
1055 XmTextFieldInsert(w, XmTextFieldGetInsertionPosition(w), str);
1060 /***************************************************************************
1064 * This action catches the 'Escape' key, and following Motif standards,
1065 * unposts the dialog, as if the 'Cancel' button had been pressed.
1066 ***************************************************************************/
1074 Cardinal *num_params )
1076 CancelCallback(w, NULL, NULL);
1081 /***************************************************************************
1085 * implement no-echo of the password
1086 ***************************************************************************/
1097 static Boolean allow_flag = False;
1098 int replaced_length, i;
1100 XmTextVerifyPtr cbData = (XmTextVerifyPtr) call;
1105 * we need to keep track of the password ourselves in order to
1106 * disable echoing of the password...
1109 replaced_length = cbData->endPos - cbData->startPos;
1110 if (replaced_length > cbData->text->length)
1112 /* shift the text at and after endPos to the left... */
1113 for (src = password + cbData->endPos,
1114 dst = src + (cbData->text->length - replaced_length),
1115 i = passwordLength - cbData->endPos;
1122 else if (replaced_length < cbData->text->length)
1124 /* Buffer must grow */
1125 password = XtRealloc(password,
1126 passwordLength + cbData->text->length - replaced_length + 5);
1128 /* shift the text at and after endPos to the right... */
1129 for (src = password + passwordLength - 1,
1130 dst = src + (cbData->text->length - replaced_length),
1131 i = passwordLength - cbData->endPos;
1140 * update the password...
1143 for (src = cbData->text->ptr,
1144 dst = password + cbData->startPos,
1145 i = cbData->text->length;
1152 passwordLength += cbData->text->length - replaced_length;
1153 password[passwordLength] = '\0';
1154 stars = XtRealloc(stars, cbData->text->length + 10);
1155 for (i = 0; i < cbData->text->length; i++)
1157 stars[cbData->text->length] = '\0';
1160 * put the appropriate number of stars in the passwd Widget..
1164 XmTextFieldReplace(w, cbData->startPos, cbData->endPos, stars);
1168 cbData->doit = allow_flag;
1173 * This function posts an error dialog informing the user that they have
1174 * specified an invalid user name. No further processing will be done; we
1175 * will simply wait for the user to acknowledge the error, and then exit.
1191 okLabel = XmStringCreateLocalized(GETMESSAGE(1,2, "OK"));
1192 template = (GETMESSAGE(1,8, "The user '%s' is an unknown user name.\n\nThe requested action will not be executed."));
1193 master = XtMalloc(strlen(template) + strlen(appArgs.user) + 10);
1194 sprintf(master, template, appArgs.user);
1195 message = XmStringCreateLocalized(master);
1196 title = (GETMESSAGE(1,9, "Action Invoker - Unknown User"));
1198 /* Post an error dialog */
1200 XtSetArg(args[n], XmNtitle, title); n++;
1201 XtSetArg(args[n], XmNmessageString, message); n++;
1202 XtSetArg(args[n], XmNokLabelString, okLabel); n++;
1203 XtSetArg(args[n], XmNdefaultPosition, False); n++;
1204 err = XmCreateErrorDialog(toplevel, "err", args, n);
1205 XtUnmanageChild(XmMessageBoxGetChild(err, XmDIALOG_CANCEL_BUTTON));
1206 XtUnmanageChild(XmMessageBoxGetChild(err, XmDIALOG_HELP_BUTTON));
1208 /* Center the dialog */
1209 XtRealizeWidget(err);
1210 XtSetArg (args[0], XmNx,
1211 (Position)(WidthOfScreen(XtScreen(err)) -
1212 err->core.width) / 2);
1213 XtSetArg (args[1], XmNy,
1214 (Position)(HeightOfScreen(XtScreen(err)) -
1215 err->core.height) / 2);
1216 XtSetValues (err, args, 2);
1219 XtAddCallback(err, XmNokCallback, UnknownUserCallback, err);
1220 XtAddCallback(err, XmNcancelCallback, UnknownUserCallback, err);
1222 XFlush(XtDisplay(toplevel));
1223 XmUpdateDisplay(toplevel);
1225 XmStringFree(okLabel);
1226 XmStringFree(message);
1228 XtAppMainLoop(appContext);
1233 * This is the 'Cancel' callback for the 'Invalid User' error dialog.
1234 * It removes the dialog, and then exits.
1239 UnknownUserCallback(
1241 XtPointer clientData,
1242 XtPointer callData )
1245 Widget err = (Widget)clientData;
1247 XtUnmanageChild(err);
1248 XFlush(XtDisplay(err));
1249 XmUpdateDisplay(err);
1253 void actionStatusCallback(
1254 DtActionInvocationID id,
1255 XtPointer client_data,
1258 DtActionStatus status )
1262 case DtACTION_INVOKED:
1264 * There may still be error dialogs to post so we must return
1265 * to mainLoop before exiting.
1267 if ( exitAfterInvoked )
1268 XtAppAddTimeOut(appContext,
1269 10 , (XtTimerCallbackProc)CheckForDone,
1274 XtAppAddTimeOut(appContext,
1275 10 , (XtTimerCallbackProc)CheckForDone,
1279 case DtACTION_FAILED:
1280 case DtACTION_CANCELED:
1282 XtAppAddTimeOut(appContext,
1283 10 , (XtTimerCallbackProc)CheckForDone,