1 | /* $Id: xlogin.c,v 1.79 1999-01-22 23:16:27 ghudson Exp $ */ |
---|
2 | |
---|
3 | #include <unistd.h> |
---|
4 | #include <string.h> |
---|
5 | #include <stdio.h> |
---|
6 | #include <stdlib.h> |
---|
7 | #include <signal.h> |
---|
8 | #include <sys/types.h> |
---|
9 | #include <sys/wait.h> |
---|
10 | #include <sys/time.h> |
---|
11 | #include <sys/stat.h> |
---|
12 | #include <sys/file.h> |
---|
13 | #include <utmp.h> |
---|
14 | #include <fcntl.h> |
---|
15 | #include <X11/Intrinsic.h> |
---|
16 | #include <ctype.h> |
---|
17 | #include <errno.h> |
---|
18 | #include <pwd.h> |
---|
19 | #include <X11/Wc/WcCreate.h> |
---|
20 | #include <X11/StringDefs.h> |
---|
21 | #include <X11/Xaw/Label.h> |
---|
22 | #include <X11/Xaw/Text.h> |
---|
23 | #include <X11/Xaw/Form.h> |
---|
24 | #ifdef SOLARIS |
---|
25 | #include <X11/Xaw/SmeBSB.h> |
---|
26 | #endif |
---|
27 | #include <X11/Xlib.h> |
---|
28 | #include <X11/Xatom.h> |
---|
29 | #include <X11/Shell.h> |
---|
30 | #include <X11/Xmu/Drawing.h> |
---|
31 | #include <X11/Xmu/Converters.h> |
---|
32 | #include <larv.h> |
---|
33 | #include "Clock.h" |
---|
34 | #include "owl.h" |
---|
35 | #include "environment.h" |
---|
36 | |
---|
37 | #ifdef SYSV |
---|
38 | #define random lrand48 |
---|
39 | #define srandom srand48 |
---|
40 | #endif |
---|
41 | |
---|
42 | #ifndef MIN |
---|
43 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) |
---|
44 | #endif |
---|
45 | |
---|
46 | #ifndef MOTD_FILENAME |
---|
47 | #define MOTD_FILENAME "/afs/athena.mit.edu/system/config/motd/login.77" |
---|
48 | #endif |
---|
49 | |
---|
50 | #ifdef sgi |
---|
51 | char athconsole[64]; |
---|
52 | FILE *xdmstream; |
---|
53 | int xdmfd; |
---|
54 | #endif |
---|
55 | |
---|
56 | #define OWL_AWAKE 0 |
---|
57 | #define OWL_SLEEPY 1 |
---|
58 | |
---|
59 | #define OWL_STATIC 0 |
---|
60 | #define OWL_BLINKINGCLOSED 1 |
---|
61 | #define OWL_BLINKINGOPEN 2 |
---|
62 | #define OWL_SLEEPING 3 |
---|
63 | #define OWL_WAKING 4 |
---|
64 | |
---|
65 | #define ACTIVATED 1 |
---|
66 | #define REACTIVATING 2 |
---|
67 | |
---|
68 | gid_t def_grplist[] = { 101 }; /* default group list */ |
---|
69 | |
---|
70 | |
---|
71 | /* Function declarations. */ |
---|
72 | |
---|
73 | extern void AriRegisterAthena (); |
---|
74 | static void move_instructions(), screensave(), unsave(), start_reactivate(); |
---|
75 | static void blinkOwl(), blinkIs(), initOwl(), adjustOwl(); |
---|
76 | static void catch_child(), setFontPath(); |
---|
77 | static Boolean auxConditions(); |
---|
78 | extern pid_t fork_and_store(pid_t *var); |
---|
79 | void focusACT(), unfocusACT(), runACT(), runCB(), focusCB(), resetCB(); |
---|
80 | void idleReset(), loginACT(), localErrorHandler(), setcorrectfocus(); |
---|
81 | void sigconsACT(), sigconsCB(), callbackACT(), attachandrunCB(); |
---|
82 | void windowShutdownACT(), windowShutdownCB(); |
---|
83 | extern void add_converter (); |
---|
84 | |
---|
85 | |
---|
86 | /* Definition of the Application resources structure. */ |
---|
87 | |
---|
88 | typedef struct _XLoginResources { |
---|
89 | int save_timeout; |
---|
90 | int move_timeout; |
---|
91 | int blink_timeout; |
---|
92 | int reactivate_timeout; |
---|
93 | int activate_timeout; |
---|
94 | int restart_timeout; |
---|
95 | int randomize; |
---|
96 | int detach_interval; |
---|
97 | String activate_prog; |
---|
98 | String reactivate_prog; |
---|
99 | String tty; |
---|
100 | String session; |
---|
101 | String fontpath; |
---|
102 | String srvdcheck; |
---|
103 | String loginName; |
---|
104 | Boolean blankAll; |
---|
105 | Boolean showMotd; |
---|
106 | String motdFile; |
---|
107 | String motd2File; |
---|
108 | } XLoginResources; |
---|
109 | |
---|
110 | /* Command line options table. Only resources are entered here...there is a |
---|
111 | * pass over the remaining options after XtParseCommand is let loose. |
---|
112 | */ |
---|
113 | |
---|
114 | static XrmOptionDescRec options[] = { |
---|
115 | {"-save", "*saveTimeout", XrmoptionSepArg, NULL}, |
---|
116 | {"-move", "*moveTimeout", XrmoptionSepArg, NULL}, |
---|
117 | {"-blink", "*blinkTimeout", XrmoptionSepArg, NULL}, |
---|
118 | {"-reactivate","*reactivateProg", XrmoptionSepArg, NULL}, |
---|
119 | {"-randomize","*randomize", XrmoptionSepArg, NULL}, |
---|
120 | {"-detach", "*detachInterval", XrmoptionSepArg, NULL}, |
---|
121 | {"-idle", "*reactivateTimeout", XrmoptionSepArg, NULL}, |
---|
122 | {"-wait", "*activateTimeout", XrmoptionSepArg, NULL}, |
---|
123 | {"-restart", "*restartTimeout", XrmoptionSepArg, NULL}, |
---|
124 | {"-tty", "*loginTty", XrmoptionSepArg, NULL}, |
---|
125 | {"-session", "*sessionScript", XrmoptionSepArg, NULL}, |
---|
126 | {"-srvdcheck","*srvdCheck", XrmoptionSepArg, NULL}, |
---|
127 | {"-fp", "*fontPath", XrmoptionSepArg, NULL}, |
---|
128 | {"-blankall", "*blankAll", XrmoptionNoArg, (caddr_t) "on"}, |
---|
129 | {"-noblankall","*blankAll", XrmoptionNoArg, (caddr_t) "off"}, |
---|
130 | {"-motdfile", "*motdFile", XrmoptionSepArg, NULL}, |
---|
131 | {"-motd2file","*motd2File", XrmoptionSepArg, NULL}, |
---|
132 | }; |
---|
133 | |
---|
134 | /* The structure containing the resource information for the |
---|
135 | * Xlogin application resources. |
---|
136 | */ |
---|
137 | |
---|
138 | #define Offset(field) (XtOffset(XLoginResources *, field)) |
---|
139 | |
---|
140 | static XtResource my_resources[] = { |
---|
141 | {"saveTimeout", XtCInterval, XtRInt, sizeof(int), |
---|
142 | Offset(save_timeout), XtRImmediate, (caddr_t) 120}, |
---|
143 | {"moveTimeout", XtCInterval, XtRInt, sizeof(int), |
---|
144 | Offset(move_timeout), XtRImmediate, (caddr_t) 20}, |
---|
145 | {"blinkTimeout", XtCInterval, XtRInt, sizeof(int), |
---|
146 | Offset(blink_timeout), XtRImmediate, (caddr_t) 40}, |
---|
147 | {"reactivateProg", XtCFile, XtRString, sizeof(String), |
---|
148 | Offset(reactivate_prog), XtRImmediate, "/etc/athena/reactivate"}, |
---|
149 | {"randomize", XtCInterval, XtRInt, sizeof(int), |
---|
150 | Offset(randomize), XtRImmediate, (caddr_t) 60}, |
---|
151 | {"detachInterval", XtCInterval, XtRInt, sizeof(int), |
---|
152 | Offset(detach_interval), XtRImmediate, (caddr_t) 12}, |
---|
153 | {"activateTimeout", XtCInterval, XtRInt, sizeof(int), |
---|
154 | Offset(activate_timeout), XtRImmediate, (caddr_t) 30}, |
---|
155 | {"restartTimeout", XtCInterval, XtRInt, sizeof(int), |
---|
156 | Offset(restart_timeout), XtRImmediate, (caddr_t) (60 * 60 * 12)}, |
---|
157 | {"reactivateTimeout", XtCInterval, XtRInt, sizeof(int), |
---|
158 | Offset(reactivate_timeout), XtRImmediate, (caddr_t) 300}, |
---|
159 | {"loginTty", XtCFile, XtRString, sizeof(String), |
---|
160 | Offset(tty), XtRImmediate, (caddr_t) "ttyv0"}, |
---|
161 | {"sessionScript", XtCFile, XtRString, sizeof(String), |
---|
162 | Offset(session), XtRImmediate, (caddr_t) "/etc/athena/login/Xsession"}, |
---|
163 | {"srvdcheck", XtCFile, XtRString, sizeof(String), |
---|
164 | Offset(srvdcheck), XtRImmediate, (caddr_t) "/srvd/.rvdinfo"}, |
---|
165 | #ifdef SOLARIS |
---|
166 | {"fontPath", XtCString, XtRString, sizeof(String), |
---|
167 | Offset(fontpath), XtRImmediate, (caddr_t) "/usr/openwin/lib/fonts/" }, |
---|
168 | #else |
---|
169 | {"fontPath", XtCString, XtRString, sizeof(String), |
---|
170 | Offset(fontpath), XtRImmediate, (caddr_t) "/usr/athena/lib/X11/fonts/misc/,/usr/athena/lib/X11/fonts/75dpi/,/usr/athena/lib/X11/fonts/100dpi/" }, |
---|
171 | #endif |
---|
172 | {"loginName", XtCString, XtRString, sizeof(String), |
---|
173 | Offset(loginName), XtRImmediate, (caddr_t) "" }, |
---|
174 | {"blankAllScreens", XtCBoolean, XtRBoolean, sizeof(Boolean), |
---|
175 | Offset(blankAll), XtRImmediate, (caddr_t) True}, |
---|
176 | {"showMotd", XtCBoolean, XtRBoolean, sizeof(Boolean), |
---|
177 | Offset(showMotd), XtRImmediate, (caddr_t) True}, |
---|
178 | {"motdFile", XtCString, XtRString, sizeof(String), |
---|
179 | Offset(motdFile), XtRImmediate, (caddr_t) MOTD_FILENAME }, |
---|
180 | {"motd2File", XtCString, XtRString, sizeof(String), |
---|
181 | Offset(motd2File), XtRImmediate, (caddr_t) "" }, |
---|
182 | }; |
---|
183 | |
---|
184 | #undef Offset |
---|
185 | |
---|
186 | XtActionsRec actions[] = { |
---|
187 | { "setfocus", focusACT }, |
---|
188 | { "unsetfocus", unfocusACT }, |
---|
189 | { "run", runACT }, |
---|
190 | { "idleReset", idleReset }, |
---|
191 | { "login", loginACT }, |
---|
192 | { "reset", resetCB }, |
---|
193 | { "setCorrectFocus", setcorrectfocus }, |
---|
194 | { "signalConsoleACT", sigconsACT }, |
---|
195 | { "callbackACT", callbackACT }, |
---|
196 | { "windowShutdownACT", windowShutdownACT }, |
---|
197 | }; |
---|
198 | |
---|
199 | |
---|
200 | |
---|
201 | |
---|
202 | #ifndef CONSOLEPID |
---|
203 | #define CONSOLEPID "/var/athena/console.pid" |
---|
204 | #endif |
---|
205 | |
---|
206 | #ifndef UTMP_FILE |
---|
207 | #ifdef _PATH_UTMP |
---|
208 | #define UTMP_FILE _PATH_UTMP |
---|
209 | #else /* _PATH_UTMP */ |
---|
210 | #define UTMP_FILE "/var/adm/utmp" |
---|
211 | #endif /* _PATH_UTMP */ |
---|
212 | #endif /* UTMP_FILE */ |
---|
213 | |
---|
214 | /* Globals. */ |
---|
215 | |
---|
216 | XtIntervalId curr_timerid = 0, blink_timerid = 0, is_timerid = 0, |
---|
217 | react_timerid = 0; |
---|
218 | Widget appShell; |
---|
219 | Widget saver, ins; |
---|
220 | Widget savershell[10]; |
---|
221 | int num_screens; |
---|
222 | XLoginResources resources; |
---|
223 | GC owlGC, isGC; |
---|
224 | Display *dpy; |
---|
225 | Window owlWindow, isWindow; |
---|
226 | int owlNumBitmaps, isNumBitmaps; |
---|
227 | /* unsigned */ int owlWidth, owlHeight, isWidth, isHeight; |
---|
228 | int owlState, owlDelta, isDelta, owlTimeout, isTimeout; |
---|
229 | Pixmap owlBitmaps[20], isBitmaps[20]; |
---|
230 | struct timeval starttime; |
---|
231 | pid_t activation_pid, attach_pid, attachhelp_pid, quota_pid; |
---|
232 | int activation_state, activate_count = 0, attach_state, attachhelp_state; |
---|
233 | int exiting = FALSE; |
---|
234 | extern char *defaultpath; |
---|
235 | char login[128], passwd[128]; |
---|
236 | sigset_t sig_zero; |
---|
237 | |
---|
238 | #ifdef SOLARIS_MAE |
---|
239 | int netspy = FALSE; |
---|
240 | #endif |
---|
241 | |
---|
242 | /* Local Globals */ |
---|
243 | |
---|
244 | static struct sigaction sigact, osigact; |
---|
245 | |
---|
246 | void main(argc, argv) |
---|
247 | int argc; |
---|
248 | char* argv[]; |
---|
249 | { |
---|
250 | XtAppContext app; |
---|
251 | XEvent e; |
---|
252 | Widget hitanykey, namew; |
---|
253 | Display *dpy1; |
---|
254 | char hname[1024], *c; |
---|
255 | Arg args[1]; |
---|
256 | int i; |
---|
257 | unsigned acc = 0; |
---|
258 | int pid; |
---|
259 | #ifdef sgi |
---|
260 | int fdflags; |
---|
261 | #endif |
---|
262 | |
---|
263 | sigemptyset(&sig_zero); |
---|
264 | |
---|
265 | #ifdef sgi |
---|
266 | /* Get stderr and stdout for our own uses - we don't want them going |
---|
267 | * through various paths of xdm. Under Irix, xdm does a lot of the |
---|
268 | * actually logging-in; it calls xlogin with stdout a pipe it listens |
---|
269 | * to to determine whom to log in. We need this communication, but we |
---|
270 | * also want stdout to work correctly (out to console). So we make |
---|
271 | * a copy of the stdout stream, and then reopen stdout to whatever |
---|
272 | * tty we belong to (or /dev/console, if that doesn't work). |
---|
273 | */ |
---|
274 | if (nanny_getTty(athconsole, sizeof(athconsole))) |
---|
275 | strcpy(athconsole, "/dev/console"); |
---|
276 | |
---|
277 | xdmfd = dup(fileno(stdout)); |
---|
278 | if (xdmfd != -1) |
---|
279 | { |
---|
280 | xdmstream = fdopen(xdmfd, "w"); |
---|
281 | if (xdmstream == NULL) |
---|
282 | { |
---|
283 | close(xdmfd); |
---|
284 | xdmstream = stdout; |
---|
285 | } |
---|
286 | else if (NULL == freopen(athconsole, "w", stdout)) |
---|
287 | (void)freopen("/dev/console", "w", stdout); |
---|
288 | } |
---|
289 | else |
---|
290 | xdmstream = stdout; /* Some stuff will break, but better than losing. */ |
---|
291 | /* Actually, losing gracefully might be wise... */ |
---|
292 | |
---|
293 | fdflags = fcntl(fileno(xdmstream), F_GETFD); |
---|
294 | if (fdflags != -1) |
---|
295 | fcntl(fileno(xdmstream), F_SETFD, fdflags | FD_CLOEXEC); |
---|
296 | |
---|
297 | if (NULL == freopen(athconsole, "w", stderr)) |
---|
298 | (void)freopen("/dev/console", "w", stderr); |
---|
299 | /* if (stderr == NULL) |
---|
300 | tough luck; */ |
---|
301 | #endif |
---|
302 | |
---|
303 | /* Have to find this argument before initializing the toolkit. |
---|
304 | * We set both XUSERFILESEARCHPATH and XENVIRONMENT. The effect is |
---|
305 | * that the -config argument names a directory that will have the |
---|
306 | * file Xlogin which contains the resources, and may optionally have |
---|
307 | * a Xlogin.local file containing additional resources which will |
---|
308 | * override those in the regular file. |
---|
309 | */ |
---|
310 | for (i = 1; i < argc; i++) |
---|
311 | if (!strcmp(argv[i], "-config") && (i + 1 < argc)) |
---|
312 | { |
---|
313 | c = getenv("XUSERFILESEARCHPATH"); |
---|
314 | if (c) |
---|
315 | sprintf(hname, "%s:%s/%%N", c, argv[i + 1]); |
---|
316 | else |
---|
317 | sprintf(hname, "%s/%%N", argv[i + 1]); |
---|
318 | psetenv("XUSERFILESEARCHPATH", hname, 1); |
---|
319 | sprintf(hname, "%s/Xlogin.local", argv[i + 1]); |
---|
320 | psetenv("XENVIRONMENT", hname, 1); |
---|
321 | break; |
---|
322 | } |
---|
323 | |
---|
324 | /* Initialize Toolkit creating the application shell, and get |
---|
325 | * application resources. |
---|
326 | */ |
---|
327 | appShell = XtInitialize("xlogin", "Xlogin", |
---|
328 | options, XtNumber(options), |
---|
329 | &argc, argv); |
---|
330 | add_converter(); |
---|
331 | app = XtWidgetToApplicationContext(appShell); |
---|
332 | XtAppSetErrorHandler(app, localErrorHandler); |
---|
333 | dpy = XtDisplay(appShell); |
---|
334 | XtAppAddActions(app, actions, XtNumber(actions)); |
---|
335 | |
---|
336 | XtGetApplicationResources(appShell, (caddr_t)&resources, |
---|
337 | my_resources, XtNumber(my_resources), |
---|
338 | NULL, (Cardinal)0); |
---|
339 | |
---|
340 | #ifndef sgi |
---|
341 | /* Tell the display manager we're ready, just like the X server |
---|
342 | * handshake. This code used to be right before XtMainLoop. However, |
---|
343 | * under Ultrix dm is required to open /dev/xcons and manually pipe |
---|
344 | * it to the console window. It won't start this process until |
---|
345 | * it gets its SIGUSR1 from us. So, if we do output to the console |
---|
346 | * (where our stderr and stdout are directed) before sending the SIGUSR1, |
---|
347 | * it may show up as "black bar" messages. This is suboptimal. Since |
---|
348 | * I have no idea why this handshake is helpful in the first place, |
---|
349 | * beyond knowing the exec of XLogin succeeded, I don't see any reason |
---|
350 | * not to just get it over with and get the console flowing when we |
---|
351 | * need it. We need it now. --- cfields |
---|
352 | */ |
---|
353 | sigaction(SIGUSR1, NULL, &osigact); |
---|
354 | if (osigact.sa_handler == SIG_IGN) |
---|
355 | kill(getppid(), SIGUSR1); |
---|
356 | #endif /* not sgi */ |
---|
357 | |
---|
358 | #ifdef SOLARIS_MAE |
---|
359 | /* Make sure the network device has the proper owner and protections. |
---|
360 | * But don't muck with it unless the file NETSPY exists. */ |
---|
361 | |
---|
362 | netspy = file_exists(NETSPY); |
---|
363 | if (netspy) |
---|
364 | { |
---|
365 | chown(NETDEV, ROOT, SYS); |
---|
366 | chmod(NETDEV, 0600); |
---|
367 | } |
---|
368 | #endif |
---|
369 | |
---|
370 | /* Call reactivate with the -prelogin option. This restores /etc/passwd, |
---|
371 | * blows away stray processes, runs access_off, and a couple of other |
---|
372 | * low overhead things (if PUBLIC=true). This is low overhead because |
---|
373 | * we want login to start up ASAP, but we pay the price for what we do |
---|
374 | * to make sure the workstation is as clean as it ought to be with respect |
---|
375 | * to performance and security. This code has to come after the resources |
---|
376 | * are loaded, so we know where the reactivate script is. |
---|
377 | */ |
---|
378 | pid = fork(); |
---|
379 | switch(pid) |
---|
380 | { |
---|
381 | case 0: |
---|
382 | execl(resources.reactivate_prog, resources.reactivate_prog, |
---|
383 | "-prelogin", 0); |
---|
384 | fprintf(stderr, "XLogin: unable to exec reactivate program \"%s\"\n", |
---|
385 | resources.reactivate_prog); |
---|
386 | _exit(1); |
---|
387 | break; |
---|
388 | case -1: |
---|
389 | fprintf(stderr, "XLogin: unable to fork for reactivatation\n"); |
---|
390 | break; |
---|
391 | default: |
---|
392 | waitpid(pid, NULL, 0); |
---|
393 | break; |
---|
394 | } |
---|
395 | |
---|
396 | /* We set up the signal handler later than we used to because we don't |
---|
397 | * need or want it to be running to handle the prelogin script. |
---|
398 | */ |
---|
399 | sigemptyset(&sigact.sa_mask); |
---|
400 | sigact.sa_flags = 0; |
---|
401 | sigact.sa_handler = catch_child; |
---|
402 | sigaction(SIGCHLD, &sigact, NULL); |
---|
403 | |
---|
404 | WcRegisterCallback(app, "UnsetFocus", unfocusACT, NULL); |
---|
405 | WcRegisterCallback(app, "runCB", runCB, NULL); |
---|
406 | WcRegisterCallback(app, "setfocusCB", focusCB, NULL); |
---|
407 | WcRegisterCallback(app, "resetCB", resetCB, NULL); |
---|
408 | WcRegisterCallback(app, "signalConsoleCB", sigconsCB, NULL); |
---|
409 | WcRegisterCallback(app, "idleResetCB", idleReset, NULL); |
---|
410 | WcRegisterCallback(app, "attachAndRunCB", attachandrunCB, NULL); |
---|
411 | WcRegisterCallback(app, "windowShutdownCB", windowShutdownCB, NULL); |
---|
412 | |
---|
413 | /* Register all Athena widget classes. */ |
---|
414 | AriRegisterAthena (app); |
---|
415 | WcRegisterClassPtr(app, "ClockWidget", clockWidgetClass); |
---|
416 | WcRegisterClassPtr(app, "clockWidgetClass", clockWidgetClass); |
---|
417 | |
---|
418 | /* Clear console window. */ |
---|
419 | sigconsCB(NULL, "clear", NULL); |
---|
420 | |
---|
421 | /* Create widget tree below toplevel shell using Xrm database. */ |
---|
422 | WcWidgetCreation(appShell); |
---|
423 | |
---|
424 | /* Realize the widget tree, finish up initializing, and enter the |
---|
425 | * main application loop. |
---|
426 | */ |
---|
427 | XtRealizeWidget(appShell); |
---|
428 | |
---|
429 | initOwl(appShell); /* widget tree MUST be realized... */ |
---|
430 | adjustOwl(appShell); |
---|
431 | |
---|
432 | /* Put the first component of the hostname in the label of the host |
---|
433 | * widget. */ |
---|
434 | gethostname(hname, sizeof(hname)); |
---|
435 | c = strchr(hname, '.'); |
---|
436 | if (c) |
---|
437 | *c = 0; |
---|
438 | XtSetArg(args[0], XtNlabel, hname); |
---|
439 | namew = WcFullNameToWidget(appShell, "*login*host"); |
---|
440 | XtSetValues(namew, args, 1); |
---|
441 | namew = WcFullNameToWidget(appShell, "*instructions*host"); |
---|
442 | XtSetValues(namew, args, 1); |
---|
443 | XtSetArg(args[0], XtNstring, login); |
---|
444 | XtSetValues(WcFullNameToWidget(appShell, "*name_input"), args, 1); |
---|
445 | XtSetArg(args[0], XtNstring, passwd); |
---|
446 | XtSetValues(WcFullNameToWidget(appShell, "*pword_input"), args, 1); |
---|
447 | |
---|
448 | /* Seed the random number generator with our hostname. */ |
---|
449 | c = hname; |
---|
450 | while (*c) |
---|
451 | acc = (acc << 1) ^ *c++; |
---|
452 | srandom(acc); |
---|
453 | resources.reactivate_timeout += random() % resources.randomize; |
---|
454 | saver = WcFullNameToWidget(appShell, "*savershell"); |
---|
455 | ins = WcFullNameToWidget(appShell, "*instructions"); |
---|
456 | hitanykey = WcFullNameToWidget(appShell, "*hitanykey"); |
---|
457 | |
---|
458 | #define MASK KeyReleaseMask | ButtonReleaseMask |
---|
459 | XtAddEventHandler(saver, MASK, FALSE, unsave, (XtPointer)TRUE); |
---|
460 | XtAddEventHandler(hitanykey, MASK, FALSE, unsave, (XtPointer)TRUE); |
---|
461 | |
---|
462 | curr_timerid = XtAddTimeOut(resources.save_timeout * 1000, screensave, NULL); |
---|
463 | blink_timerid = XtAddTimeOut(1000, blinkOwl, NULL); |
---|
464 | is_timerid = XtAddTimeOut(1000, blinkIs, NULL); |
---|
465 | gettimeofday(&starttime, NULL); |
---|
466 | resetCB(namew, NULL, NULL); |
---|
467 | if (access(resources.srvdcheck, F_OK) != 0) |
---|
468 | start_reactivate(NULL, NULL); |
---|
469 | else |
---|
470 | activation_state = ACTIVATED; |
---|
471 | |
---|
472 | psetenv("PATH", defaultpath, 1); |
---|
473 | #ifdef HOSTTYPE |
---|
474 | psetenv("hosttype", HOSTTYPE, 1); /* environment.h */ |
---|
475 | #endif |
---|
476 | |
---|
477 | /* Create shells to blank out all other screens, if any... */ |
---|
478 | |
---|
479 | /* Cover ourselves by setting number of screens to one. */ |
---|
480 | num_screens = 1; |
---|
481 | savershell[0] = saver; /* Fill in the saver shell for now... */ |
---|
482 | |
---|
483 | if (resources.blankAll && ScreenCount(dpy) > 1) |
---|
484 | { |
---|
485 | int this_screen = XScreenNumberOfScreen(XtScreen(saver)); |
---|
486 | char *orig_dpy, *ptr; |
---|
487 | int zero = 0; |
---|
488 | num_screens = MIN(ScreenCount(dpy), 10); |
---|
489 | orig_dpy = XtNewString(DisplayString(dpy)); |
---|
490 | |
---|
491 | /* If the alloc worked, continue. We are counting on |
---|
492 | * displaystring to always contain a period. The displaystring |
---|
493 | * is always canonicalized for us... isn't that nice of them? |
---|
494 | */ |
---|
495 | if (orig_dpy != NULL) |
---|
496 | { |
---|
497 | if ((ptr = strrchr(orig_dpy, '.')) != NULL) |
---|
498 | { |
---|
499 | ptr++; |
---|
500 | /* Only does screens 0 thru 9. If you have more screens |
---|
501 | * than that, you lose. |
---|
502 | */ |
---|
503 | for (i = 0; i < ScreenCount(dpy) && i < 10; i++) |
---|
504 | { |
---|
505 | if (i == this_screen) |
---|
506 | savershell[i] = saver; |
---|
507 | else |
---|
508 | { |
---|
509 | Widget root; |
---|
510 | |
---|
511 | *ptr = (char) i + '0'; |
---|
512 | dpy1 = XtOpenDisplay(app, orig_dpy, "xlogin", "Xlogin", |
---|
513 | NULL, 0, &zero, NULL); |
---|
514 | root = XtAppCreateShell("xlogin", "Xlogin", |
---|
515 | applicationShellWidgetClass, |
---|
516 | dpy1, NULL, 0); |
---|
517 | savershell[i] = XtCreatePopupShell("savershell", |
---|
518 | transientShellWidgetClass, |
---|
519 | root, NULL, 0); |
---|
520 | XtAddEventHandler(savershell[i], MASK, |
---|
521 | FALSE, unsave, (XtPointer)TRUE); |
---|
522 | } |
---|
523 | } |
---|
524 | } |
---|
525 | } |
---|
526 | XtFree(orig_dpy); |
---|
527 | } |
---|
528 | |
---|
529 | larv_set_busy(0); |
---|
530 | |
---|
531 | /* This is just XtMainLoop() with a send_event filter. */ |
---|
532 | while (1) |
---|
533 | { |
---|
534 | XtAppNextEvent(app, &e); |
---|
535 | if (e.xany.send_event == False) |
---|
536 | XtDispatchEvent(&e); |
---|
537 | } |
---|
538 | } |
---|
539 | |
---|
540 | static Dimension x_max = 0, y_max = 0; |
---|
541 | |
---|
542 | static void move_instructions(data, timerid) |
---|
543 | XtPointer data; |
---|
544 | XtIntervalId *timerid; |
---|
545 | { |
---|
546 | Position x, y; |
---|
547 | Window wins[2]; |
---|
548 | |
---|
549 | if (!x_max) /* Get sizes if we haven't done so already. */ |
---|
550 | { |
---|
551 | Arg args[2]; |
---|
552 | |
---|
553 | XtSetArg(args[0], XtNwidth, &x_max); |
---|
554 | XtSetArg(args[1], XtNheight, &y_max); |
---|
555 | XtGetValues(ins, args, 2); |
---|
556 | |
---|
557 | if (WidthOfScreen(XtScreen(ins)) < x_max + 1) |
---|
558 | x_max = 1; |
---|
559 | else |
---|
560 | x_max = WidthOfScreen(XtScreen(ins)) - x_max; |
---|
561 | |
---|
562 | if (HeightOfScreen(XtScreen(ins)) < y_max + 1) |
---|
563 | y_max = 1; |
---|
564 | else |
---|
565 | y_max = HeightOfScreen(XtScreen(ins)) - y_max; |
---|
566 | } |
---|
567 | |
---|
568 | x = random() % x_max; |
---|
569 | y = random() % y_max; |
---|
570 | XtMoveWidget(ins, x, y); |
---|
571 | |
---|
572 | if (activation_state != REACTIVATING) |
---|
573 | { |
---|
574 | XRaiseWindow(XtDisplay(ins), XtWindow(ins)); |
---|
575 | wins[0] = XtWindow(ins); |
---|
576 | wins[1] = XtWindow(saver); |
---|
577 | XRestackWindows(XtDisplay(ins), wins, 2); |
---|
578 | } |
---|
579 | |
---|
580 | curr_timerid = XtAddTimeOut(resources.move_timeout * 1000, |
---|
581 | move_instructions, NULL); |
---|
582 | } |
---|
583 | |
---|
584 | static void start_reactivate(data, timerid) |
---|
585 | XtPointer data; |
---|
586 | XtIntervalId *timerid; |
---|
587 | { |
---|
588 | int in_use = 0; |
---|
589 | int file; |
---|
590 | struct utmp utmp; |
---|
591 | struct timeval now; |
---|
592 | |
---|
593 | #ifndef sgi /* Not our problem on the SGI. */ |
---|
594 | gettimeofday(&now, NULL); |
---|
595 | if (now.tv_sec - starttime.tv_sec > resources.restart_timeout) |
---|
596 | { |
---|
597 | fprintf(stderr, "Restarting X Server\n"); |
---|
598 | exit(0); |
---|
599 | } |
---|
600 | #endif /* sgi */ |
---|
601 | |
---|
602 | do_motd(); |
---|
603 | |
---|
604 | file = open(UTMP_FILE, O_RDONLY, 0); |
---|
605 | if (file >= 0) |
---|
606 | { |
---|
607 | while (read(file, (char *) &utmp, sizeof(utmp)) > 0) |
---|
608 | { |
---|
609 | if (utmp.ut_name[0] != 0 |
---|
610 | #ifdef USER_PROCESS |
---|
611 | && utmp.ut_type == USER_PROCESS |
---|
612 | #endif |
---|
613 | ) |
---|
614 | { |
---|
615 | in_use = 1; |
---|
616 | break; |
---|
617 | } |
---|
618 | } |
---|
619 | close(file); |
---|
620 | } |
---|
621 | |
---|
622 | if (in_use || activation_state == REACTIVATING) |
---|
623 | { |
---|
624 | react_timerid = XtAddTimeOut(resources.reactivate_timeout * 1000, |
---|
625 | start_reactivate, NULL); |
---|
626 | return; |
---|
627 | } |
---|
628 | |
---|
629 | /* Clear the console window. */ |
---|
630 | sigconsCB(NULL, "clear", NULL); |
---|
631 | |
---|
632 | activation_state = REACTIVATING; |
---|
633 | switch(fork_and_store(&activation_pid)) |
---|
634 | { |
---|
635 | case 0: |
---|
636 | if (activate_count % resources.detach_interval == 0) |
---|
637 | execl(resources.reactivate_prog, resources.reactivate_prog, |
---|
638 | "-detach", 0); |
---|
639 | else |
---|
640 | execl(resources.reactivate_prog, resources.reactivate_prog, 0); |
---|
641 | fprintf(stderr, "XLogin: unable to exec reactivate program \"%s\"\n", |
---|
642 | resources.reactivate_prog); |
---|
643 | _exit(1); |
---|
644 | case -1: |
---|
645 | fprintf(stderr, "XLogin: unable to fork for reactivatation\n"); |
---|
646 | activation_state = ACTIVATED; |
---|
647 | break; |
---|
648 | default: |
---|
649 | break; |
---|
650 | } |
---|
651 | activate_count++; |
---|
652 | react_timerid = XtAddTimeOut(resources.reactivate_timeout * 1000, |
---|
653 | start_reactivate, NULL); |
---|
654 | } |
---|
655 | |
---|
656 | void idleReset() |
---|
657 | { |
---|
658 | if (curr_timerid) |
---|
659 | XtRemoveTimeOut(curr_timerid); |
---|
660 | curr_timerid = XtAddTimeOut(resources.save_timeout * 1000, |
---|
661 | screensave, NULL); |
---|
662 | } |
---|
663 | |
---|
664 | static void stop_activate(data, timerid) |
---|
665 | XtPointer data; |
---|
666 | XtIntervalId *timerid; |
---|
667 | { |
---|
668 | if (activation_state == ACTIVATED) |
---|
669 | return; |
---|
670 | |
---|
671 | kill(activation_pid, SIGKILL); |
---|
672 | fprintf(stderr, "Workstation activation failed to finish normally.\n"); |
---|
673 | activation_state = ACTIVATED; |
---|
674 | } |
---|
675 | |
---|
676 | static void screensave(data, timerid) |
---|
677 | XtPointer data; |
---|
678 | XtIntervalId *timerid; |
---|
679 | { |
---|
680 | static int first_time = TRUE; |
---|
681 | Pixmap pixmap; |
---|
682 | Cursor cursor; |
---|
683 | XColor c; |
---|
684 | int i; |
---|
685 | |
---|
686 | XtPopdown(WcFullNameToWidget(appShell, "*getSessionShell")); |
---|
687 | XtPopdown(WcFullNameToWidget(appShell, "*warningShell")); |
---|
688 | XtPopdown(WcFullNameToWidget(appShell, "*queryShell")); |
---|
689 | |
---|
690 | for (i = 0; i < num_screens; i++) |
---|
691 | XtPopup(savershell[i], XtGrabNone); |
---|
692 | |
---|
693 | do_motd(); |
---|
694 | XtPopup(ins, XtGrabNone); |
---|
695 | XRaiseWindow(XtDisplay(ins), XtWindow(ins)); |
---|
696 | unfocusACT(appShell, NULL, NULL, NULL); |
---|
697 | if (first_time) |
---|
698 | { |
---|
699 | /* Contortions to "get rid of" cursor on screensaver windows. */ |
---|
700 | c.pixel = BlackPixel(dpy, DefaultScreen(dpy)); |
---|
701 | XQueryColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), &c); |
---|
702 | |
---|
703 | pixmap = XCreateBitmapFromData(dpy, XtWindow(appShell), "", 1, 1); |
---|
704 | |
---|
705 | cursor = XCreatePixmapCursor(dpy, pixmap, pixmap, &c, &c, |
---|
706 | (unsigned int)0, (unsigned int)0); |
---|
707 | XFreePixmap(dpy, pixmap); |
---|
708 | for (i = 0; i < num_screens; i++) |
---|
709 | XDefineCursor(dpy, XtWindow(savershell[i]), cursor); |
---|
710 | XDefineCursor(dpy, XtWindow(ins), cursor); |
---|
711 | XFreeCursor(dpy, cursor); |
---|
712 | |
---|
713 | first_time = FALSE; |
---|
714 | } |
---|
715 | |
---|
716 | if (blink_timerid != 0) /* Don't do animation while screensaved. */ |
---|
717 | XtRemoveTimeOut(blink_timerid); |
---|
718 | blink_timerid = 0; |
---|
719 | if (is_timerid != 0) |
---|
720 | XtRemoveTimeOut(is_timerid); |
---|
721 | is_timerid = 0; |
---|
722 | |
---|
723 | /* Don't let the X server's screensaver kick in. */ |
---|
724 | XSetScreenSaver(dpy, 0, -1, DefaultBlanking, DefaultExposures); |
---|
725 | curr_timerid = XtAddTimeOut(resources.move_timeout * 1000, |
---|
726 | move_instructions, NULL); |
---|
727 | react_timerid = XtAddTimeOut(resources.reactivate_timeout * 1000, |
---|
728 | start_reactivate, NULL); |
---|
729 | } |
---|
730 | |
---|
731 | /* Check the motd file and update the contents of the widget if necessary. */ |
---|
732 | do_motd() |
---|
733 | { |
---|
734 | static Widget motdtext = NULL; |
---|
735 | static time_t modtime = 0, modtime2 = 0; |
---|
736 | struct stat stbuf, stbuf2; |
---|
737 | Arg args[1]; |
---|
738 | char buf[10000], *temp, *s, *d; |
---|
739 | int fid, len, do_g_motd, do_l_motd; |
---|
740 | |
---|
741 | if (!motdtext) |
---|
742 | { |
---|
743 | motdtext = WcFullNameToWidget(appShell, "*motd"); |
---|
744 | |
---|
745 | /* Initialize motdtext to NULL in case it never gets set. |
---|
746 | * This happens in the case of a bad stat on the motd |
---|
747 | * file, or if showMotd false. |
---|
748 | */ |
---|
749 | buf[0] = '\0'; |
---|
750 | XtSetArg(args[0], XtNlabel, buf); |
---|
751 | XtSetValues(motdtext, args, 1); |
---|
752 | } |
---|
753 | |
---|
754 | if (resources.showMotd) |
---|
755 | { |
---|
756 | do_g_motd = (resources.motdFile != NULL && *resources.motdFile && |
---|
757 | !stat(resources.motdFile, &stbuf) && |
---|
758 | stbuf.st_mtime != modtime); |
---|
759 | if (do_g_motd) |
---|
760 | modtime = stbuf.st_mtime; |
---|
761 | |
---|
762 | do_l_motd = (resources.motd2File != NULL && *resources.motd2File && |
---|
763 | !stat(resources.motd2File, &stbuf2) && |
---|
764 | stbuf2.st_mtime != modtime2); |
---|
765 | if (do_l_motd) |
---|
766 | modtime2 = stbuf2.st_mtime; |
---|
767 | |
---|
768 | if (do_g_motd || do_l_motd) |
---|
769 | { |
---|
770 | /* Read the new motd. */ |
---|
771 | len = 0; |
---|
772 | if (resources.motdFile != NULL && *resources.motdFile && |
---|
773 | (fid = open(resources.motdFile, O_RDONLY)) >= 0) |
---|
774 | { |
---|
775 | len = read(fid, buf, sizeof(buf)); |
---|
776 | close(fid); |
---|
777 | } |
---|
778 | if (resources.motd2File != NULL && *resources.motd2File && |
---|
779 | (fid = open(resources.motd2File, O_RDONLY)) >= 0) |
---|
780 | { |
---|
781 | len += read(fid, &(buf[len]), sizeof(buf) - len); |
---|
782 | close(fid); |
---|
783 | } |
---|
784 | buf[len] = 0; |
---|
785 | |
---|
786 | /* De-tabbify the motd (label widgets don't do tabs). */ |
---|
787 | for (s = buf; *s; s++) |
---|
788 | if (*s == '\t') len += 7; |
---|
789 | d = temp = malloc(len + 1); |
---|
790 | len = 0; |
---|
791 | for (s = buf; *s; s++) |
---|
792 | { |
---|
793 | switch(*s) |
---|
794 | { |
---|
795 | case '\t': |
---|
796 | *d++ = ' '; |
---|
797 | len++; |
---|
798 | while (len++ % 8 != 0) |
---|
799 | *d++ = ' '; |
---|
800 | len--; |
---|
801 | break; |
---|
802 | case '\n': |
---|
803 | len = 0; |
---|
804 | *d++ = *s; |
---|
805 | break; |
---|
806 | default: |
---|
807 | *d++ = *s; |
---|
808 | len++; |
---|
809 | } |
---|
810 | } |
---|
811 | *d = 0; |
---|
812 | |
---|
813 | /* Now set the text. */ |
---|
814 | XtSetArg(args[0], XtNlabel, temp); |
---|
815 | XtSetValues(motdtext, args, 1); |
---|
816 | free(temp); |
---|
817 | |
---|
818 | /* Force move_instructions() to recompute size. */ |
---|
819 | x_max = 0; |
---|
820 | } |
---|
821 | } |
---|
822 | } |
---|
823 | |
---|
824 | static void unsave(w, popdown, event, bool) |
---|
825 | Widget w; |
---|
826 | int popdown; |
---|
827 | XEvent *event; |
---|
828 | Boolean *bool; |
---|
829 | { |
---|
830 | /* Hide the console window. */ |
---|
831 | sigconsCB(NULL, "hide", NULL); |
---|
832 | |
---|
833 | if (popdown) |
---|
834 | { |
---|
835 | int i; |
---|
836 | |
---|
837 | XtPopdown(ins); |
---|
838 | for (i = 0; i < num_screens; i++) |
---|
839 | XtPopdown(savershell[i]); |
---|
840 | } |
---|
841 | |
---|
842 | /* Enable the X server's screensaver. */ |
---|
843 | XSetScreenSaver(dpy, -1, -1, DefaultBlanking, DefaultExposures); |
---|
844 | resetCB(w, NULL, NULL); |
---|
845 | |
---|
846 | if (curr_timerid != 0) |
---|
847 | XtRemoveTimeOut(curr_timerid); |
---|
848 | curr_timerid = XtAddTimeOut(resources.save_timeout * 1000, |
---|
849 | screensave, NULL); |
---|
850 | blink_timerid = XtAddTimeOut(random() % (10 * 1000), |
---|
851 | blinkOwl, NULL); |
---|
852 | is_timerid = XtAddTimeOut(random() % (10 * 1000), |
---|
853 | blinkIs, NULL); |
---|
854 | if (react_timerid != 0) |
---|
855 | XtRemoveTimeOut(react_timerid); |
---|
856 | if (activation_state == REACTIVATING) |
---|
857 | react_timerid = XtAddTimeOut(resources.activate_timeout * 1000, |
---|
858 | stop_activate, NULL); |
---|
859 | } |
---|
860 | |
---|
861 | void loginACT(w, event, p, n) |
---|
862 | Widget w; |
---|
863 | XEvent *event; |
---|
864 | String *p; |
---|
865 | Cardinal *n; |
---|
866 | { |
---|
867 | Arg args[2]; |
---|
868 | char *script; |
---|
869 | int mode = 1; |
---|
870 | Pixmap bm1, bm2, bm3, bm4, bm5; |
---|
871 | XawTextBlock tb; |
---|
872 | extern char *dologin(); |
---|
873 | XEvent e; |
---|
874 | |
---|
875 | if (curr_timerid) |
---|
876 | XtRemoveTimeOut(curr_timerid); |
---|
877 | |
---|
878 | XtSetArg(args[0], XtNleftBitmap, &bm1); |
---|
879 | XtGetValues(WcFullNameToWidget(appShell, "*lmenuEntry1"), args, 1); |
---|
880 | XtSetArg(args[0], XtNleftBitmap, &bm2); |
---|
881 | XtGetValues(WcFullNameToWidget(appShell, "*lmenuEntry2"), args, 1); |
---|
882 | XtSetArg(args[0], XtNleftBitmap, &bm3); |
---|
883 | XtGetValues(WcFullNameToWidget(appShell, "*lmenuEntry3"), args, 1); |
---|
884 | XtSetArg(args[0], XtNleftBitmap, &bm4); |
---|
885 | XtGetValues(WcFullNameToWidget(appShell, "*lmenuEntry4"), args, 1); |
---|
886 | XtSetArg(args[0], XtNleftBitmap, &bm5); |
---|
887 | XtGetValues(WcFullNameToWidget(appShell, "*lmenuEntry5"), args, 1); |
---|
888 | |
---|
889 | /* Determine which option was selected by seeing which 4 of the 5 match. */ |
---|
890 | if (bm1 == bm2 && bm1 == bm3 && bm1 == bm4) |
---|
891 | mode = 5; |
---|
892 | if (bm1 == bm2 && bm1 == bm3 && bm1 == bm5) |
---|
893 | mode = 4; |
---|
894 | if (bm1 == bm2 && bm1 == bm4 && bm1 == bm5) |
---|
895 | mode = 3; |
---|
896 | if (bm1 == bm3 && bm1 == bm4 && bm1 == bm5) |
---|
897 | mode = 2; |
---|
898 | if (bm2 == bm3 && bm2 == bm4 && bm2 == bm5) |
---|
899 | mode = 1; |
---|
900 | |
---|
901 | XtSetArg(args[0], XtNstring, &script); |
---|
902 | XtGetValues(WcFullNameToWidget(appShell, "*getsession*value"), args, 1); |
---|
903 | unfocusACT(appShell, NULL, NULL, NULL); |
---|
904 | XtUnmapWidget(appShell); |
---|
905 | /* To clear the cut buffer in case someone types ^U while typing |
---|
906 | * their password. |
---|
907 | */ |
---|
908 | XDeleteProperty(dpy, DefaultRootWindow(dpy), XA_CUT_BUFFER0); |
---|
909 | XDeleteProperty(dpy, DefaultRootWindow(dpy), XA_CUT_BUFFER1); |
---|
910 | XFlush(dpy); |
---|
911 | |
---|
912 | /* Wait for activation to finish. We play games with signals here |
---|
913 | * because we are not waiting within the XtMainloop for it to handle |
---|
914 | * the timers. |
---|
915 | */ |
---|
916 | if (activation_state != ACTIVATED) |
---|
917 | { |
---|
918 | void (*oldsig)(); |
---|
919 | |
---|
920 | fprintf(stderr, "Waiting for workstation to finish activating..."); |
---|
921 | fflush(stderr); |
---|
922 | sigemptyset(&sigact.sa_mask); |
---|
923 | sigact.sa_flags = 0; |
---|
924 | sigact.sa_handler = stop_activate; |
---|
925 | sigaction(SIGALRM, &sigact, &osigact); |
---|
926 | alarm(resources.activate_timeout); |
---|
927 | while (activation_state != ACTIVATED) |
---|
928 | sigsuspend(&sig_zero); |
---|
929 | alarm(0); |
---|
930 | sigaction(SIGALRM, &osigact, NULL); |
---|
931 | fprintf(stderr, "done.\n"); |
---|
932 | } |
---|
933 | |
---|
934 | if (access(resources.srvdcheck, F_OK) != 0) |
---|
935 | tb.ptr = "Workstation failed to activate successfully. " |
---|
936 | "Please notify the Athena Hotline, x3-1410, hotline@mit.edu."; |
---|
937 | else |
---|
938 | { |
---|
939 | setFontPath(); |
---|
940 | #ifdef sgi |
---|
941 | /* We obtained the tty earlier from nanny. */ |
---|
942 | resources.tty = athconsole + 5; |
---|
943 | #endif |
---|
944 | |
---|
945 | XWarpPointer(dpy, None, RootWindow(dpy, DefaultScreen(dpy)), |
---|
946 | 0, 0, 0, 0, 300, 300); |
---|
947 | XFlush(dpy); |
---|
948 | larv_set_busy(1); |
---|
949 | tb.ptr = dologin(login, passwd, mode, script, resources.tty, |
---|
950 | resources.session, DisplayString(dpy)); |
---|
951 | larv_set_busy(0); |
---|
952 | XWarpPointer(dpy, None, RootWindow(dpy, DefaultScreen(dpy)), |
---|
953 | 0, 0, 0, 0, WidthOfScreen(DefaultScreenOfDisplay(dpy))/2, |
---|
954 | HeightOfScreen(DefaultScreenOfDisplay(dpy))/2); |
---|
955 | } |
---|
956 | |
---|
957 | XtMapWidget(appShell); |
---|
958 | XtPopup(WcFullNameToWidget(appShell, "*warningShell"), XtGrabExclusive); |
---|
959 | tb.firstPos = 0; |
---|
960 | tb.length = strlen(tb.ptr); |
---|
961 | tb.format = FMT8BIT; |
---|
962 | XawTextReplace(WcFullNameToWidget(appShell, "*warning*value"), |
---|
963 | 0, 65536, &tb); |
---|
964 | XtCallActionProc(WcFullNameToWidget(appShell, "*warning*value"), |
---|
965 | "form-paragraph", &e, NULL, 0); |
---|
966 | focusCB(appShell, "*warning*value", NULL); |
---|
967 | curr_timerid = XtAddTimeOut(resources.save_timeout * 1000, |
---|
968 | screensave, NULL); |
---|
969 | } |
---|
970 | |
---|
971 | /* Login failed: Set the exit flag, then return the message the usual way. */ |
---|
972 | char *lose(msg) |
---|
973 | char *msg; |
---|
974 | { |
---|
975 | exiting = TRUE; |
---|
976 | return msg; |
---|
977 | } |
---|
978 | |
---|
979 | void focusACT(w, event, p, n) |
---|
980 | Widget w; |
---|
981 | XEvent *event; |
---|
982 | String *p; |
---|
983 | Cardinal *n; |
---|
984 | { |
---|
985 | Widget target; |
---|
986 | |
---|
987 | #ifdef sgi |
---|
988 | static int done_once = 0; |
---|
989 | |
---|
990 | /* This crock works around the an invalid argument error on the |
---|
991 | * XSetInputFocus() call below the very first time it is called, |
---|
992 | * only when running on the RIOS. We still don't know just what |
---|
993 | * causes it. |
---|
994 | * I sure wish I'd modified this comment when I added sgi to |
---|
995 | * the ifdef the first time. I should try taking it back out to |
---|
996 | * find out. |
---|
997 | */ |
---|
998 | if (done_once == 0) |
---|
999 | { |
---|
1000 | done_once++; |
---|
1001 | XSync(dpy, FALSE); |
---|
1002 | sleep(1); |
---|
1003 | XSync(dpy, FALSE); |
---|
1004 | } |
---|
1005 | #endif |
---|
1006 | |
---|
1007 | target = WcFullNameToWidget(appShell, p[0]); |
---|
1008 | XSetInputFocus(dpy, XtWindow(target), RevertToPointerRoot, CurrentTime); |
---|
1009 | |
---|
1010 | if (owlState == OWL_SLEEPY) |
---|
1011 | if (blink_timerid != 0) |
---|
1012 | { |
---|
1013 | XtRemoveTimeOut(blink_timerid); |
---|
1014 | blink_timerid = 0; |
---|
1015 | owlDelta = OWL_WAKING; |
---|
1016 | blinkOwl(NULL, NULL); |
---|
1017 | } |
---|
1018 | } |
---|
1019 | |
---|
1020 | void focusCB(w, s, unused) |
---|
1021 | Widget w; |
---|
1022 | char *s; |
---|
1023 | caddr_t unused; |
---|
1024 | { |
---|
1025 | Cardinal one = 1; |
---|
1026 | |
---|
1027 | focusACT(w, NULL, &s, &one); |
---|
1028 | } |
---|
1029 | |
---|
1030 | void unfocusACT(w, event, p, n) |
---|
1031 | Widget w; |
---|
1032 | XEvent *event; |
---|
1033 | String *p; |
---|
1034 | Cardinal *n; |
---|
1035 | { |
---|
1036 | int rvt; |
---|
1037 | Window win; |
---|
1038 | |
---|
1039 | XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); |
---|
1040 | XGetInputFocus(dpy, &win, &rvt); |
---|
1041 | } |
---|
1042 | |
---|
1043 | void setcorrectfocus(w, event, p, n) |
---|
1044 | Widget w; |
---|
1045 | XEvent *event; |
---|
1046 | String *p; |
---|
1047 | Cardinal *n; |
---|
1048 | { |
---|
1049 | Arg args[2]; |
---|
1050 | char *win; |
---|
1051 | Cardinal i; |
---|
1052 | Boolean bool; |
---|
1053 | |
---|
1054 | XtSetArg(args[0], XtNdisplayCaret, &bool); |
---|
1055 | XtGetValues(WcFullNameToWidget(appShell, "*name_input"), args, 1); |
---|
1056 | if (bool) |
---|
1057 | win = "*name_input"; |
---|
1058 | else |
---|
1059 | win = "*pword_input"; |
---|
1060 | i = 1; |
---|
1061 | focusACT(w, event, &win, &i); |
---|
1062 | } |
---|
1063 | |
---|
1064 | void runACT(w, event, p, n) |
---|
1065 | Widget w; |
---|
1066 | XEvent *event; |
---|
1067 | char **p; |
---|
1068 | Cardinal *n; |
---|
1069 | { |
---|
1070 | char **argv; |
---|
1071 | int i; |
---|
1072 | #ifdef sgi |
---|
1073 | extern char **environ; |
---|
1074 | #endif |
---|
1075 | struct passwd *pw; |
---|
1076 | |
---|
1077 | unfocusACT(w, event, p, n); |
---|
1078 | argv = (char **)malloc(sizeof(char *) * (*n + 3)); |
---|
1079 | argv[0] = "sh"; |
---|
1080 | argv[1] = "-c"; |
---|
1081 | for (i = 0; i < *n; i++) |
---|
1082 | argv[i+2] = p[i]; |
---|
1083 | argv[i+2] = NULL; |
---|
1084 | |
---|
1085 | /* Wait for activation to finish. */ |
---|
1086 | if (activation_state != ACTIVATED) |
---|
1087 | fprintf(stderr, "Waiting for workstation to finish activating...\n"); |
---|
1088 | while (activation_state != ACTIVATED) |
---|
1089 | sigsuspend(&sig_zero); |
---|
1090 | if (access(resources.srvdcheck, F_OK) != 0) |
---|
1091 | { |
---|
1092 | fprintf(stderr, "Workstation failed to activate successfully.\n" |
---|
1093 | "Please notify the Athena Hotline, x3-1410, hotline@mit.edu.\n"); |
---|
1094 | return; |
---|
1095 | } |
---|
1096 | sigconsCB(NULL, "hide", NULL); |
---|
1097 | setFontPath(); |
---|
1098 | XFlush(dpy); |
---|
1099 | XtCloseDisplay(dpy); |
---|
1100 | |
---|
1101 | /* Set up the pre-login environment. |
---|
1102 | * |
---|
1103 | * By default, all of xlogin's environment is passed to the |
---|
1104 | * pre-login applications. Some of xlogin's environment is |
---|
1105 | * not appropriately passed on; if such a new element is |
---|
1106 | * introduced into xlogin, it should be unsetenved here. |
---|
1107 | * |
---|
1108 | * Note that the environment for user logins is set |
---|
1109 | * up in verify.c: it is NOT RELATED to this environment |
---|
1110 | * setup. If you add a new environment variable here, |
---|
1111 | * consider whether or not it also needs to be added there. |
---|
1112 | * Note that variables that need to be unsetenved here do not |
---|
1113 | * need similar treatment in the user login area, since there |
---|
1114 | * no variables are passed by default. |
---|
1115 | * |
---|
1116 | * Note also that below are not the only environment variables |
---|
1117 | * mucked with. Others are done earlier for other functions |
---|
1118 | * of xlogin. |
---|
1119 | */ |
---|
1120 | punsetenv("XUSERFILESEARCHPATH"); |
---|
1121 | punsetenv("XENVIRONMENT"); |
---|
1122 | |
---|
1123 | psetenv("PATH", defaultpath, 1); |
---|
1124 | psetenv("USER", "nobody", 1); |
---|
1125 | psetenv("SHELL", "/bin/sh", 1); |
---|
1126 | psetenv("DISPLAY", ":0", 1); |
---|
1127 | |
---|
1128 | #ifdef sgi |
---|
1129 | psetenv("PRELOGIN", "true", 1); |
---|
1130 | if (nanny_setupUser("nobody", environ, argv)) |
---|
1131 | { |
---|
1132 | fprintf(stderr, "Unable to set up for 'nobody' app\n"); |
---|
1133 | return; |
---|
1134 | } |
---|
1135 | |
---|
1136 | fprintf(xdmstream, "%s", "nobody"); |
---|
1137 | fputc(0, xdmstream); |
---|
1138 | |
---|
1139 | larv_set_busy(1); |
---|
1140 | exit(0); |
---|
1141 | #else |
---|
1142 | pw = getpwnam("nobody"); |
---|
1143 | if (!pw) |
---|
1144 | { |
---|
1145 | fprintf(stderr, "Unable to find 'nobody' account\n"); |
---|
1146 | return; |
---|
1147 | } |
---|
1148 | setgroups(sizeof(def_grplist)/sizeof(gid_t), def_grplist); |
---|
1149 | |
---|
1150 | setgid(def_grplist[0]); |
---|
1151 | if (setuid(pw->pw_uid)) |
---|
1152 | { |
---|
1153 | fprintf(stderr, "Unable to set user id.\n"); |
---|
1154 | return; |
---|
1155 | } |
---|
1156 | larv_set_busy(1); |
---|
1157 | execv("/bin/sh", argv); |
---|
1158 | fprintf(stderr, "XLogin: unable to exec /bin/sh\n"); |
---|
1159 | _exit(3); |
---|
1160 | #endif |
---|
1161 | } |
---|
1162 | |
---|
1163 | void runCB(w, s, unused) |
---|
1164 | Widget w; |
---|
1165 | char *s; |
---|
1166 | caddr_t unused; |
---|
1167 | { |
---|
1168 | Cardinal i = 1; |
---|
1169 | |
---|
1170 | runACT(w, NULL, &s, &i); |
---|
1171 | } |
---|
1172 | |
---|
1173 | void attachandrunCB(w, s, unused) |
---|
1174 | Widget w; |
---|
1175 | char *s; |
---|
1176 | caddr_t unused; |
---|
1177 | { |
---|
1178 | char *cmd, locker[256]; |
---|
1179 | Cardinal i = 1; |
---|
1180 | |
---|
1181 | cmd = strchr(s, ','); |
---|
1182 | if (cmd == NULL) |
---|
1183 | { |
---|
1184 | fprintf(stderr, |
---|
1185 | "Xlogin warning: need two arguments in AttachAndRun(%s)\n", |
---|
1186 | s); |
---|
1187 | return; |
---|
1188 | } |
---|
1189 | strncpy(locker, s, cmd - s); |
---|
1190 | locker[cmd - s] = 0; |
---|
1191 | cmd++; |
---|
1192 | |
---|
1193 | attach_state = -1; |
---|
1194 | switch(fork_and_store(&attach_pid)) |
---|
1195 | { |
---|
1196 | case 0: |
---|
1197 | execlp("attach", "attach", "-n", "-h", "-q", locker, NULL); |
---|
1198 | fprintf(stderr, "Xlogin warning: unable to attach locker %s\n", locker); |
---|
1199 | _exit(1); |
---|
1200 | case -1: |
---|
1201 | fprintf(stderr, "Xlogin: unable to fork to attach locker\n"); |
---|
1202 | break; |
---|
1203 | default: |
---|
1204 | while (attach_state == -1) |
---|
1205 | sigsuspend(&sig_zero); |
---|
1206 | if (attach_state != 0) |
---|
1207 | { |
---|
1208 | fprintf(stderr, "Unable to attach locker %s, aborting...\n", |
---|
1209 | locker); |
---|
1210 | return; |
---|
1211 | } |
---|
1212 | } |
---|
1213 | |
---|
1214 | runACT(w, NULL, &cmd, &i); |
---|
1215 | } |
---|
1216 | |
---|
1217 | void windowShutdownCB(w, s, unused) |
---|
1218 | Widget w; |
---|
1219 | char *s; |
---|
1220 | caddr_t unused; |
---|
1221 | { |
---|
1222 | larv_set_busy(1); |
---|
1223 | #ifdef sgi |
---|
1224 | /* If this returns 0, the X server has been killed and it's time |
---|
1225 | * to go. If not, we should probably pop up a dialog box. |
---|
1226 | */ |
---|
1227 | if (!nanny_setConsoleMode()) |
---|
1228 | exit(0); |
---|
1229 | #else |
---|
1230 | exit(3); |
---|
1231 | #endif |
---|
1232 | } |
---|
1233 | |
---|
1234 | void windowShutdownACT(w, event, p, n) |
---|
1235 | Widget w; |
---|
1236 | XEvent *event; |
---|
1237 | char **p; |
---|
1238 | Cardinal *n; |
---|
1239 | { |
---|
1240 | larv_set_busy(1); |
---|
1241 | #ifdef sgi |
---|
1242 | if (!nanny_setConsoleMode()) |
---|
1243 | exit(0); |
---|
1244 | #else |
---|
1245 | exit(3); |
---|
1246 | #endif |
---|
1247 | } |
---|
1248 | |
---|
1249 | void sigconsACT(w, event, p, n) |
---|
1250 | Widget w; |
---|
1251 | XEvent *event; |
---|
1252 | char **p; |
---|
1253 | Cardinal *n; |
---|
1254 | { |
---|
1255 | int sig, pid; |
---|
1256 | FILE *f; |
---|
1257 | char buf[BUFSIZ]; |
---|
1258 | |
---|
1259 | if (!strcmp(p[0], "clear")) |
---|
1260 | sig = SIGFPE; |
---|
1261 | else if (!strcmp(p[0], "hide")) |
---|
1262 | sig = SIGUSR2; |
---|
1263 | else if (!strcmp(p[0], "show")) |
---|
1264 | sig = SIGUSR1; |
---|
1265 | else if (!strcmp(p[0], "config")) |
---|
1266 | sig = SIGHUP; |
---|
1267 | else |
---|
1268 | sig = atoi(p[0]); |
---|
1269 | |
---|
1270 | f = fopen(CONSOLEPID, "r"); |
---|
1271 | if (f) |
---|
1272 | { |
---|
1273 | fgets(buf, sizeof(buf), f); |
---|
1274 | pid = atoi(buf); |
---|
1275 | if (pid) |
---|
1276 | kill(pid, sig); |
---|
1277 | fclose(f); |
---|
1278 | } |
---|
1279 | } |
---|
1280 | |
---|
1281 | void sigconsCB(w, s, unused) |
---|
1282 | Widget w; |
---|
1283 | char *s; |
---|
1284 | caddr_t unused; |
---|
1285 | { |
---|
1286 | Cardinal i = 1; |
---|
1287 | |
---|
1288 | sigconsACT(w, NULL, &s, &i); |
---|
1289 | } |
---|
1290 | |
---|
1291 | void callbackACT(w, event, p, n) |
---|
1292 | Widget w; |
---|
1293 | XEvent *event; |
---|
1294 | char **p; |
---|
1295 | Cardinal *n; |
---|
1296 | { |
---|
1297 | w = WcFullNameToWidget(appShell, p[0]); |
---|
1298 | XtCallCallbacks(w, "callback", p[1]); |
---|
1299 | } |
---|
1300 | |
---|
1301 | void resetCB(w, s, unused) |
---|
1302 | Widget w; |
---|
1303 | char *s; |
---|
1304 | caddr_t unused; |
---|
1305 | { |
---|
1306 | XawTextBlock tb; |
---|
1307 | Widget name_input; |
---|
1308 | |
---|
1309 | if (exiting == TRUE) |
---|
1310 | exit(0); |
---|
1311 | focusCB(appShell, "*name_input", NULL); |
---|
1312 | WcSetValueCB(appShell, "*lmenuEntry1.leftBitmap: check", NULL); |
---|
1313 | WcSetValueCB(appShell, "*lmenuEntry2.leftBitmap: white", NULL); |
---|
1314 | WcSetValueCB(appShell, "*lmenuEntry3.leftBitmap: white", NULL); |
---|
1315 | WcSetValueCB(appShell, "*lmenuEntry4.leftBitmap: white", NULL); |
---|
1316 | WcSetValueCB(appShell, "*lmenuEntry5.leftBitmap: white", NULL); |
---|
1317 | WcSetValueCB(appShell, "*selection.label: ", NULL); |
---|
1318 | WcSetValueCB(appShell, "*name_input.displayCaret: TRUE", NULL); |
---|
1319 | |
---|
1320 | tb.firstPos = tb.length = 0; |
---|
1321 | tb.ptr = ""; |
---|
1322 | tb.format = FMT8BIT; |
---|
1323 | XawTextReplace(WcFullNameToWidget(appShell, "*pword_input"), 0, 65536, &tb); |
---|
1324 | XawTextReplace(WcFullNameToWidget(appShell, "*getsession*value"), |
---|
1325 | 0, 65536, &tb); |
---|
1326 | |
---|
1327 | if (resources.loginName != NULL && strlen(resources.loginName) != 0) |
---|
1328 | { |
---|
1329 | if (strlen(resources.loginName) > 8) |
---|
1330 | resources.loginName[8] = '\0'; |
---|
1331 | tb.ptr = resources.loginName; |
---|
1332 | tb.length = strlen(tb.ptr); |
---|
1333 | } |
---|
1334 | name_input = WcFullNameToWidget(appShell, "*name_input"); |
---|
1335 | XawTextReplace(name_input, 0, 65536, &tb); |
---|
1336 | XawTextSetInsertionPoint(name_input, (XawTextPosition) tb.length); |
---|
1337 | |
---|
1338 | if (curr_timerid) |
---|
1339 | XtRemoveTimeOut(curr_timerid); |
---|
1340 | curr_timerid = XtAddTimeOut(resources.save_timeout * 1000, |
---|
1341 | screensave, NULL); |
---|
1342 | } |
---|
1343 | |
---|
1344 | setvalue(w, done, unused) |
---|
1345 | Widget w; |
---|
1346 | int *done; |
---|
1347 | { |
---|
1348 | *done = 1; |
---|
1349 | } |
---|
1350 | |
---|
1351 | typedef struct _prompt_callback_info { |
---|
1352 | void (*abort_proc)(); |
---|
1353 | void *abort_arg; |
---|
1354 | } prompt_callback_info; |
---|
1355 | |
---|
1356 | void click_abort(widget, client_data, call_data) |
---|
1357 | Widget widget; |
---|
1358 | XtPointer client_data, call_data; |
---|
1359 | { |
---|
1360 | prompt_callback_info *cdata = (prompt_callback_info *)client_data; |
---|
1361 | |
---|
1362 | cdata->abort_proc(cdata->abort_arg); |
---|
1363 | } |
---|
1364 | |
---|
1365 | void timeout_abort(client_data, timer_id) |
---|
1366 | XtPointer client_data; |
---|
1367 | XtIntervalId *timer_id; |
---|
1368 | { |
---|
1369 | prompt_callback_info *cdata = (prompt_callback_info *)client_data; |
---|
1370 | |
---|
1371 | cdata->abort_proc(cdata->abort_arg); |
---|
1372 | } |
---|
1373 | |
---|
1374 | prompt_user(msg, abort_proc, abort_arg) |
---|
1375 | char *msg; |
---|
1376 | void (*abort_proc)(); |
---|
1377 | void *abort_arg; |
---|
1378 | { |
---|
1379 | XawTextBlock tb; |
---|
1380 | XEvent e; |
---|
1381 | prompt_callback_info cb; |
---|
1382 | static void (*oldcallback)() = NULL; |
---|
1383 | static int done; |
---|
1384 | |
---|
1385 | cb.abort_proc = abort_proc; |
---|
1386 | cb.abort_arg = abort_arg; |
---|
1387 | |
---|
1388 | XtPopup(WcFullNameToWidget(appShell, "*queryShell"), XtGrabExclusive); |
---|
1389 | tb.firstPos = 0; |
---|
1390 | tb.ptr = msg; |
---|
1391 | tb.length = strlen(msg); |
---|
1392 | tb.format = FMT8BIT; |
---|
1393 | XawTextReplace(WcFullNameToWidget(appShell, "*query*value"), |
---|
1394 | 0, 65536, &tb); |
---|
1395 | XtCallActionProc(WcFullNameToWidget(appShell, "*query*value"), |
---|
1396 | "form-paragraph", &e, NULL, 0); |
---|
1397 | focusCB(appShell, "*query*value", NULL); |
---|
1398 | if (oldcallback) |
---|
1399 | XtRemoveCallback(WcFullNameToWidget(appShell, "*query*giveup"), |
---|
1400 | XtNcallback, oldcallback, NULL); |
---|
1401 | else |
---|
1402 | XtAddCallback(WcFullNameToWidget(appShell, "*query*cont"), |
---|
1403 | XtNcallback, (XtCallbackProc)setvalue, &done); |
---|
1404 | XtAddCallback(WcFullNameToWidget(appShell, "*query*giveup"), |
---|
1405 | XtNcallback, click_abort, &cb); |
---|
1406 | oldcallback = abort_proc; |
---|
1407 | curr_timerid = XtAddTimeOut(resources.save_timeout * 1000, |
---|
1408 | timeout_abort, &cb); |
---|
1409 | |
---|
1410 | /* Repeat main_loop here so we can check status & return. */ |
---|
1411 | done = 0; |
---|
1412 | while (!done) |
---|
1413 | { |
---|
1414 | XtAppNextEvent((XtAppContext)_XtDefaultAppContext(), &e); |
---|
1415 | if (e.xany.send_event == False) |
---|
1416 | XtDispatchEvent(&e); |
---|
1417 | } |
---|
1418 | |
---|
1419 | XtRemoveTimeOut(curr_timerid); |
---|
1420 | curr_timerid = 0; |
---|
1421 | XtPopdown(WcFullNameToWidget(appShell, "*queryShell")); |
---|
1422 | XFlush(dpy); |
---|
1423 | } |
---|
1424 | |
---|
1425 | #define updateOwl() XCopyPlane(dpy, owlBitmaps[owlCurBitmap], \ |
---|
1426 | owlWindow, owlGC, 0, 0, \ |
---|
1427 | owlWidth, owlHeight, 0, 0, 1) |
---|
1428 | #define updateIs() XCopyPlane(dpy, isBitmaps[isCurBitmap], \ |
---|
1429 | isWindow, isGC, 0, 0, \ |
---|
1430 | isWidth, isHeight, 0, 0, 1) |
---|
1431 | |
---|
1432 | static void blinkOwl(data, intervalid) |
---|
1433 | XtPointer data; |
---|
1434 | XtIntervalId *intervalid; |
---|
1435 | { |
---|
1436 | static int owlCurBitmap; |
---|
1437 | owlTimeout = 0; |
---|
1438 | |
---|
1439 | if (owlNumBitmaps == 0) |
---|
1440 | return; |
---|
1441 | |
---|
1442 | switch(owlDelta) |
---|
1443 | { |
---|
1444 | case OWL_BLINKINGCLOSED: /* your eyelids are getting heavy... */ |
---|
1445 | owlCurBitmap++; |
---|
1446 | updateOwl(); |
---|
1447 | if (owlCurBitmap == owlNumBitmaps - 1) |
---|
1448 | owlDelta = OWL_BLINKINGOPEN; |
---|
1449 | break; |
---|
1450 | |
---|
1451 | case OWL_BLINKINGOPEN: /* you will awake, feeling refreshed... */ |
---|
1452 | owlCurBitmap--; |
---|
1453 | updateOwl(); |
---|
1454 | if (owlCurBitmap == ((owlState == OWL_SLEEPY) * (owlNumBitmaps) / 2)) |
---|
1455 | { |
---|
1456 | owlTimeout = random() % (10 * 1000); |
---|
1457 | owlDelta = OWL_BLINKINGCLOSED; |
---|
1458 | } |
---|
1459 | break; |
---|
1460 | |
---|
1461 | case OWL_SLEEPING: /* transition to sleeping state */ |
---|
1462 | owlCurBitmap++; |
---|
1463 | updateOwl(); |
---|
1464 | if (owlCurBitmap == ((owlState == OWL_SLEEPY) * (owlNumBitmaps) / 2)) |
---|
1465 | { |
---|
1466 | owlDelta = OWL_BLINKINGCLOSED; |
---|
1467 | owlTimeout = random() % (10 * 1000); |
---|
1468 | } |
---|
1469 | break; |
---|
1470 | |
---|
1471 | case OWL_WAKING: /* transition to waking state */ |
---|
1472 | if (owlCurBitmap) |
---|
1473 | owlCurBitmap--; |
---|
1474 | updateOwl(); |
---|
1475 | if (owlCurBitmap == 0) |
---|
1476 | { |
---|
1477 | owlDelta = OWL_BLINKINGCLOSED; |
---|
1478 | owlTimeout = random() % (10 * 1000); |
---|
1479 | } |
---|
1480 | break; |
---|
1481 | |
---|
1482 | case OWL_STATIC: |
---|
1483 | break; |
---|
1484 | } |
---|
1485 | |
---|
1486 | blink_timerid = XtAddTimeOut((owlTimeout |
---|
1487 | ? owlTimeout : resources.blink_timeout + |
---|
1488 | 3 * resources.blink_timeout * |
---|
1489 | ((owlState == OWL_SLEEPY) && |
---|
1490 | (owlDelta != OWL_WAKING))), |
---|
1491 | blinkOwl, NULL); |
---|
1492 | } |
---|
1493 | |
---|
1494 | static void blinkIs(data, intervalid) |
---|
1495 | XtPointer data; |
---|
1496 | XtIntervalId *intervalid; |
---|
1497 | { |
---|
1498 | static int isCurBitmap; |
---|
1499 | isTimeout = 0; |
---|
1500 | |
---|
1501 | if (isNumBitmaps == 0) |
---|
1502 | return; |
---|
1503 | |
---|
1504 | switch(isDelta) |
---|
1505 | { |
---|
1506 | case OWL_BLINKINGCLOSED: /* your eyelids are getting heavy... */ |
---|
1507 | isCurBitmap++; |
---|
1508 | updateIs(); |
---|
1509 | if (isCurBitmap == isNumBitmaps - 1) |
---|
1510 | isDelta = OWL_BLINKINGOPEN; |
---|
1511 | break; |
---|
1512 | |
---|
1513 | case OWL_BLINKINGOPEN: /* you will awake, feeling refreshed... */ |
---|
1514 | isCurBitmap--; |
---|
1515 | updateIs(); |
---|
1516 | if (isCurBitmap == 0) |
---|
1517 | { |
---|
1518 | isTimeout = random() % (10 * 1000); |
---|
1519 | isDelta = OWL_BLINKINGCLOSED; |
---|
1520 | } |
---|
1521 | break; |
---|
1522 | |
---|
1523 | case OWL_STATIC: |
---|
1524 | break; |
---|
1525 | } |
---|
1526 | |
---|
1527 | is_timerid = XtAddTimeOut((isTimeout |
---|
1528 | ? isTimeout : resources.blink_timeout), |
---|
1529 | blinkIs, NULL); |
---|
1530 | } |
---|
1531 | |
---|
1532 | static void initOwl(search) |
---|
1533 | Widget search; |
---|
1534 | { |
---|
1535 | Widget owl, is; |
---|
1536 | Arg args[3]; |
---|
1537 | int n, done; |
---|
1538 | char *filenames, *ptr; |
---|
1539 | XGCValues values; |
---|
1540 | XtGCMask valuemask; |
---|
1541 | |
---|
1542 | owl = WcFullNameToWidget(search, "*eyes"); |
---|
1543 | |
---|
1544 | if (owl != NULL) |
---|
1545 | { |
---|
1546 | owlWindow = XtWindow(owl); |
---|
1547 | if (owlWindow != None) |
---|
1548 | { |
---|
1549 | n = 0; |
---|
1550 | done = 0; |
---|
1551 | XtSetArg(args[n], XtNlabel, &filenames); |
---|
1552 | n++; |
---|
1553 | XtSetArg(args[n], XtNforeground, &values.foreground); |
---|
1554 | n++; |
---|
1555 | XtSetArg(args[n], XtNbackground, &values.background); |
---|
1556 | n++; |
---|
1557 | XtGetValues(owl, args, n); |
---|
1558 | |
---|
1559 | values.function = GXcopy; |
---|
1560 | valuemask = GCForeground | GCBackground | GCFunction; |
---|
1561 | |
---|
1562 | owlNumBitmaps = 0; |
---|
1563 | ptr = filenames; |
---|
1564 | while (ptr != NULL && !done) |
---|
1565 | { |
---|
1566 | while (*ptr != '\0' && !isspace(*ptr)) |
---|
1567 | ptr++; |
---|
1568 | |
---|
1569 | if (*ptr == '\0') |
---|
1570 | done = 1; |
---|
1571 | else |
---|
1572 | *ptr = '\0'; |
---|
1573 | |
---|
1574 | owlBitmaps[owlNumBitmaps] = XmuLocateBitmapFile(XtScreen(owl), |
---|
1575 | filenames, |
---|
1576 | NULL, 0, |
---|
1577 | &owlWidth, |
---|
1578 | &owlHeight, |
---|
1579 | NULL, NULL); |
---|
1580 | if (owlBitmaps[owlNumBitmaps] == None) |
---|
1581 | return; /* abort */ |
---|
1582 | owlNumBitmaps++; |
---|
1583 | if (!done) |
---|
1584 | { |
---|
1585 | *ptr = ' '; |
---|
1586 | while (isspace(*ptr)) |
---|
1587 | ptr++; |
---|
1588 | } |
---|
1589 | filenames = ptr; |
---|
1590 | } |
---|
1591 | |
---|
1592 | owlGC = XtGetGC(owl, valuemask, &values); |
---|
1593 | if (auxConditions()) |
---|
1594 | { |
---|
1595 | owlState = OWL_SLEEPY; |
---|
1596 | owlDelta = OWL_SLEEPING; |
---|
1597 | } |
---|
1598 | else |
---|
1599 | { |
---|
1600 | owlState = OWL_AWAKE; |
---|
1601 | owlDelta = OWL_BLINKINGCLOSED; |
---|
1602 | } |
---|
1603 | isDelta = OWL_BLINKINGCLOSED; |
---|
1604 | } |
---|
1605 | } |
---|
1606 | |
---|
1607 | is = WcFullNameToWidget(search, "*logo2"); |
---|
1608 | |
---|
1609 | if (is != NULL) |
---|
1610 | { |
---|
1611 | isWindow = XtWindow(is); |
---|
1612 | if (isWindow != None) |
---|
1613 | { |
---|
1614 | n = 0; |
---|
1615 | done = 0; |
---|
1616 | XtSetArg(args[n], XtNlabel, &filenames); |
---|
1617 | n++; |
---|
1618 | XtSetArg(args[n], XtNforeground, &values.foreground); |
---|
1619 | n++; |
---|
1620 | XtSetArg(args[n], XtNbackground, &values.background); |
---|
1621 | n++; |
---|
1622 | XtGetValues(is, args, n); |
---|
1623 | |
---|
1624 | values.function = GXcopy; |
---|
1625 | valuemask = GCForeground | GCBackground | GCFunction; |
---|
1626 | |
---|
1627 | isNumBitmaps = 0; |
---|
1628 | ptr = filenames; |
---|
1629 | while (ptr != NULL && !done) |
---|
1630 | { |
---|
1631 | while (*ptr != '\0' && !isspace(*ptr)) |
---|
1632 | ptr++; |
---|
1633 | |
---|
1634 | if (*ptr == '\0') |
---|
1635 | done = 1; |
---|
1636 | else |
---|
1637 | *ptr = '\0'; |
---|
1638 | |
---|
1639 | isBitmaps[isNumBitmaps] = XmuLocateBitmapFile(XtScreen(is), |
---|
1640 | filenames, |
---|
1641 | NULL, 0, |
---|
1642 | &isWidth, |
---|
1643 | &isHeight, |
---|
1644 | NULL, NULL); |
---|
1645 | if (isBitmaps[isNumBitmaps] == None) |
---|
1646 | return; /* abort */ |
---|
1647 | isNumBitmaps++; |
---|
1648 | if (!done) |
---|
1649 | { |
---|
1650 | *ptr = ' '; |
---|
1651 | while (isspace(*ptr)) |
---|
1652 | ptr++; |
---|
1653 | } |
---|
1654 | filenames = ptr; |
---|
1655 | } |
---|
1656 | |
---|
1657 | isGC = XtGetGC(is, valuemask, &values); |
---|
1658 | } |
---|
1659 | } |
---|
1660 | } |
---|
1661 | |
---|
1662 | static short conditions[] = |
---|
1663 | { |
---|
1664 | 3116, 3147, 3180, 3211, 3243, 3273, 3305, 3335, 3366, 3397, |
---|
1665 | 3427, 3459, 3617, 3647, 3682, 3711, 3742, 3774, 3804, 3836, |
---|
1666 | 3866, 3897, 3928, 3959, 3990, 4148, 4179, 4211, 4242, 4274, |
---|
1667 | 4304, 4336, 4366, 4397, 4429, 4459, 4491, 4649, 4680, 4713, |
---|
1668 | 4743, 4775, 4805, 4837, 4868, 4898, 4930, 4961, 4990, 5022, |
---|
1669 | 5180, 5211, 5244, 5274, 5306, 5336, 5368, 5398, 5429, 5461, |
---|
1670 | 5491, 5523, 5682, 5712, 5746, 5776, 5807, 5838, 5869, 5899, |
---|
1671 | 5930, 5962, 5992, 6024, 6183, 6214, 6246, 6277, 6308, 6338, |
---|
1672 | 6370, 6399, 6429, 6460, 6491, 6522, 6554, 6713, 6743, 6777, |
---|
1673 | 6808, 6839, 6869, 6901, 6931, 6961, 6993, 7023, 7055, 7214, |
---|
1674 | 7244, 7278, 7309, 7341, 7371, 7402, 7433, 7463, 7494, 7525, |
---|
1675 | 7556, 7715, 7746, 7779, 7810, 7842, 7871, 7902, 7933, 7964, |
---|
1676 | 7994, 8025, 8056, 8087, 8246, 8276, 8309, 8340, 8371, 8402, |
---|
1677 | 8434, 8464, 8495, 8526, 8557, 8588, 8746, 8777, 8810, 8841, |
---|
1678 | 8872, 8903, 8935, 8965, 8996, 9028, 9058, 9090, 9119, 9278, |
---|
1679 | 9308, 9341, 9372, 9403, 9434, 9465, 9496, 9527, 9558, 9589, |
---|
1680 | 9621, 9779, 9810, 9843, 9873, 9905, 9935, 9967, 9997, 10028, |
---|
1681 | 10059, 10090, 10122, 10281, 10311, 10344, 10374, 10405, 10436, 10467, |
---|
1682 | 10497, 10527, 10557, 10589, 10620, 10652, 10810, 10841, 10875, 10905, |
---|
1683 | 10936, 10967, 10998, 11028, 11059, 11090, 11121, 11153, 11311, 11342, |
---|
1684 | 11376, 11407, 11438, 11468, 11500, 11530, 11560, 11592, 11622, 11654, |
---|
1685 | 11813, 11843, 11877, 11908, 11939, 11970, 12001, 12031, 12061, 12091, |
---|
1686 | 12123, 12153, 12185, 12343, 12374, 12407, 12437, 12469, 12500, 12531, |
---|
1687 | 12562, 12592, 12623, 12654, 12685, 12844, 12874, 12908, 12939, 12970, |
---|
1688 | 13001, 13032, 13063, 13094, 13125, 13156, 13187, 13345, 13375, 13409, |
---|
1689 | 13439, 13469, 13501, 13532, 13563, 13594, 13624, 13656, 13687, 13718, |
---|
1690 | 13877, 13907, 13940, 13971, 14002, 14033, 14064, 14095, 14125, 14157, |
---|
1691 | 14188, 14220, 14378, 14409, 14441, 14471, 14503, 14533, 14564, 14595, |
---|
1692 | 14626, 14657, 14687, 14718, 14749, 14908, 14939, 14972, 15002, 15034, |
---|
1693 | 15064, 15095, 15126, 15156, 15188, 15219, 15250, 15409, 15440, 15474, |
---|
1694 | 15504, 15535, 15566, 15597, 15627, 15658, 15689, 15720, 15751, 15910, |
---|
1695 | 15941, 15975, 16005, 16037, 16067, 16099, 16129, 16158, 16189, 16220, |
---|
1696 | 16251, 16282, 16441, 16472, 16505, 16535, 16567, 16597, 16629, 16659, |
---|
1697 | 16689, 16721, 16751, 16783, 16941, 16972, 17006, 17036, 17068, 17099, |
---|
1698 | 17130, 17161, 17191, 17222, 17253, 17284, 17443, 17473, 17507, 17537, |
---|
1699 | 17569, 17599, 17629, 17661, 17691, 17722, 17753, 17784, 17815, 17974, |
---|
1700 | 18004, 18038, 18068, 18100, 18130, 18162, 18193, 18223, 18255, 18285, |
---|
1701 | 18317, 18475, 18506, 18538, 18569, 18600, 18631, 18662, 18693, 18723, |
---|
1702 | 18755, 18786, 18817, 18847, 19006, 19036, 19069, 19100, 19131, 19161, |
---|
1703 | 19193, 19223, 19254, 19286, 19316, 19348, 19507, 19538, 19571, 19601, |
---|
1704 | 19633, 19663, 19694, 19725, 19755, 19787, 19817, 19849, 20008, 20039, |
---|
1705 | 20072, 20103, 20134, 20165, 20196, 20226, 20257, 20286, 20318, 20348, |
---|
1706 | 20380, 20539, 20570, 20602, 20633, 20664, 20695, 20726, 20756, 20787, |
---|
1707 | 20818, 20849, 20880, 21039, 21070, 21103, 21134, 21166, 21196, 21228, |
---|
1708 | 21258, 21288, 21320, 21350, 21382, 21540, 21571, 21604, 21635, 21667, |
---|
1709 | 21697, 21729, 21759, 21789, 21819, 21851, 21881, 21913, 22071, 22102, |
---|
1710 | 22135, 22166, 22197, 22228, 22260, 22290, 22321, 22352, 22383, 22414, |
---|
1711 | 22573, 22603, 22636, 22666, 22698, 22728, 22760, 22790, 22821, 22853, |
---|
1712 | 22883, 22915, 23073, 23103, 23137, 23167, 23197, 23228, 23259, 23290, |
---|
1713 | 23321, 23352, 23383, 23414, 23446 |
---|
1714 | }; |
---|
1715 | |
---|
1716 | static int conditions_len = sizeof(conditions) / sizeof(short); |
---|
1717 | |
---|
1718 | static Boolean conditionsMet() |
---|
1719 | { |
---|
1720 | time_t t; |
---|
1721 | struct tm *now; |
---|
1722 | short test; |
---|
1723 | int i; |
---|
1724 | |
---|
1725 | t = time(0); |
---|
1726 | now = localtime(&t); |
---|
1727 | test = (now->tm_year - 92) * 512 + (now->tm_mon + 1) * 32 + now->tm_mday; |
---|
1728 | |
---|
1729 | i = 0; |
---|
1730 | while ((i < conditions_len) && (test > conditions[i])) |
---|
1731 | i++; |
---|
1732 | |
---|
1733 | if (i == conditions_len) |
---|
1734 | return False; |
---|
1735 | |
---|
1736 | if ((test == conditions[i]) && (now->tm_hour >= 18)) |
---|
1737 | return True; |
---|
1738 | |
---|
1739 | return False; |
---|
1740 | } |
---|
1741 | |
---|
1742 | static short auxconditions[] = |
---|
1743 | { |
---|
1744 | 1424, 1427, 1428, 1429, 1430, 1718, 1719, 1720, 1721, 1722, |
---|
1745 | 2448, 2449, 2450, 2451, 2452, 2739, 2740, 2741, 2742, 2743, |
---|
1746 | 3470, 3471, 3472, 3473, 3474, 3761, 3762, 3763, 3764, 3765 |
---|
1747 | }; |
---|
1748 | |
---|
1749 | static int auxconditions_len = sizeof(auxconditions) / sizeof(short); |
---|
1750 | |
---|
1751 | static Boolean auxConditions() |
---|
1752 | { |
---|
1753 | time_t t; |
---|
1754 | struct tm *now; |
---|
1755 | short test; |
---|
1756 | int i; |
---|
1757 | |
---|
1758 | t = time(0); |
---|
1759 | now = localtime(&t); |
---|
1760 | test = (now->tm_year - 92) * 512 + (now->tm_mon + 1) * 32 + now->tm_mday; |
---|
1761 | |
---|
1762 | i = 0; |
---|
1763 | while ((i < auxconditions_len) && (test > auxconditions[i])) |
---|
1764 | i++; |
---|
1765 | |
---|
1766 | if (i == auxconditions_len) |
---|
1767 | return False; |
---|
1768 | |
---|
1769 | if ((test == auxconditions[i]) && |
---|
1770 | (now->tm_hour >= 6) && (now->tm_hour <= 18)) |
---|
1771 | return True; |
---|
1772 | |
---|
1773 | return False; |
---|
1774 | } |
---|
1775 | |
---|
1776 | static void adjustOwl(search) |
---|
1777 | Widget search; |
---|
1778 | { |
---|
1779 | Widget version, logo, eyes, Slogo, Sversion; |
---|
1780 | XtWidgetGeometry logoGeom, eyesGeom, versionGeom; |
---|
1781 | Pixmap owlPix; |
---|
1782 | Arg args[2]; |
---|
1783 | int newx; |
---|
1784 | |
---|
1785 | if (conditionsMet()) |
---|
1786 | { |
---|
1787 | /* Look up important widgets. */ |
---|
1788 | logo = WcFullNameToWidget(search, "*login*logo"); |
---|
1789 | eyes = WcFullNameToWidget(search, "*eyes"); |
---|
1790 | version = WcFullNameToWidget(search, "*login*version"); |
---|
1791 | |
---|
1792 | Slogo = WcFullNameToWidget(search, "*hitanykey*logo"); |
---|
1793 | Sversion = WcFullNameToWidget(search, "*hitanykey*version"); |
---|
1794 | |
---|
1795 | /* Plug in the owl bitmap. */ |
---|
1796 | owlPix = XCreatePixmapFromBitmapData(dpy, DefaultRootWindow(dpy), |
---|
1797 | owl_bits, owl_width, owl_height, |
---|
1798 | 1, 0, 1); |
---|
1799 | XtSetArg(args[0], XtNbitmap, owlPix); |
---|
1800 | XtSetValues(logo, args, 1); |
---|
1801 | |
---|
1802 | XtSetValues(Slogo, args, 1); |
---|
1803 | |
---|
1804 | /* Adjust position of eyes and version. */ |
---|
1805 | XtQueryGeometry(logo, NULL, &logoGeom); |
---|
1806 | XtQueryGeometry(eyes, NULL, &eyesGeom); |
---|
1807 | XtQueryGeometry(version, NULL, &versionGeom); |
---|
1808 | |
---|
1809 | XtMoveWidget(eyes, (logoGeom.width - |
---|
1810 | ((eyesGeom.x - logoGeom.x) + eyesGeom.width)) + |
---|
1811 | logoGeom.x, |
---|
1812 | eyesGeom.y); |
---|
1813 | |
---|
1814 | newx = (logoGeom.width - ((versionGeom.x - logoGeom.x) + |
---|
1815 | versionGeom.width)) + logoGeom.x; |
---|
1816 | XtMoveWidget(version, newx, versionGeom.y); |
---|
1817 | |
---|
1818 | /* This depends on the fact that both logos have the same geometry. */ |
---|
1819 | XtSetArg(args[0], XtNhorizDistance, newx); |
---|
1820 | XtSetValues(Sversion, args, 1); |
---|
1821 | } |
---|
1822 | } |
---|
1823 | |
---|
1824 | /* Called from within the toolkit. */ |
---|
1825 | void localErrorHandler(s) |
---|
1826 | String s; |
---|
1827 | { |
---|
1828 | fprintf(stderr, "XLogin X error: %s\n", s); |
---|
1829 | cleanup(NULL); |
---|
1830 | exit(1); |
---|
1831 | } |
---|
1832 | |
---|
1833 | static void catch_child() |
---|
1834 | { |
---|
1835 | int pid; |
---|
1836 | int status; |
---|
1837 | char *number(); |
---|
1838 | |
---|
1839 | while (1) |
---|
1840 | { |
---|
1841 | pid = waitpid(-1, &status, WNOHANG); |
---|
1842 | if (pid == -1 && errno == ECHILD) |
---|
1843 | break; |
---|
1844 | if (pid == activation_pid) |
---|
1845 | { |
---|
1846 | switch(activation_state) |
---|
1847 | { |
---|
1848 | case REACTIVATING: |
---|
1849 | if (pid == activation_pid) |
---|
1850 | activation_state = ACTIVATED; |
---|
1851 | break; |
---|
1852 | case ACTIVATED: |
---|
1853 | default: |
---|
1854 | fprintf(stderr, "XLogin: child %d exited\n", pid); |
---|
1855 | } |
---|
1856 | } |
---|
1857 | else if (pid == attach_pid) |
---|
1858 | { |
---|
1859 | attach_state = WEXITSTATUS(status); |
---|
1860 | } |
---|
1861 | else if (pid == attachhelp_pid) |
---|
1862 | { |
---|
1863 | attachhelp_state = WEXITSTATUS(status); |
---|
1864 | } |
---|
1865 | else if (pid == quota_pid) |
---|
1866 | { |
---|
1867 | quota_pid = 0; |
---|
1868 | } |
---|
1869 | else |
---|
1870 | { |
---|
1871 | fprintf(stderr, "XLogin: child %d exited with status %d\n", |
---|
1872 | pid, WEXITSTATUS(status)); |
---|
1873 | } |
---|
1874 | } |
---|
1875 | } |
---|
1876 | |
---|
1877 | static void setFontPath() |
---|
1878 | { |
---|
1879 | static int ndirs = 0; |
---|
1880 | static char **dirlist; |
---|
1881 | char *cp, **oldlist; |
---|
1882 | int i, j, nold; |
---|
1883 | char *dirs; |
---|
1884 | struct stat statbuf; |
---|
1885 | |
---|
1886 | if (!ndirs) |
---|
1887 | { |
---|
1888 | /* Make a copy of the fontpath which we can step on. */ |
---|
1889 | dirs = strdup(resources.fontpath); |
---|
1890 | if (dirs == NULL) |
---|
1891 | localErrorHandler("Out of memory"); |
---|
1892 | |
---|
1893 | /* Get the old font path so we can add to it. */ |
---|
1894 | oldlist = XGetFontPath(dpy, &nold); |
---|
1895 | |
---|
1896 | /* Count the number of directories we will have total. */ |
---|
1897 | ndirs = nold + 1; |
---|
1898 | cp = dirs; |
---|
1899 | while (cp = strchr(cp, ',')) |
---|
1900 | { |
---|
1901 | ndirs++; |
---|
1902 | cp++; |
---|
1903 | } |
---|
1904 | |
---|
1905 | /* Allocate space for the directory list. */ |
---|
1906 | dirlist = (char **) malloc(ndirs * sizeof(char *)); |
---|
1907 | if (dirlist == NULL) |
---|
1908 | localErrorHandler("Out of memory"); |
---|
1909 | |
---|
1910 | /* Copy the old directory list. */ |
---|
1911 | for (i = 0; i < nold; i++) |
---|
1912 | dirlist[i] = strdup(oldlist[i]); |
---|
1913 | XFreeFontPath(oldlist); |
---|
1914 | |
---|
1915 | /* Copy the entries in resources.fontpath. */ |
---|
1916 | cp = dirs; |
---|
1917 | dirlist[i++] = cp; |
---|
1918 | while (cp = strchr(cp, ',')) |
---|
1919 | { |
---|
1920 | *cp++ = '\0'; |
---|
1921 | dirlist[i++] = cp; |
---|
1922 | } |
---|
1923 | |
---|
1924 | /* Discard directories which aren't present. */ |
---|
1925 | j = 0; |
---|
1926 | for (i = 0; i < ndirs; i++) |
---|
1927 | { |
---|
1928 | if (stat(dirlist[i], &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) |
---|
1929 | dirlist[j++] = dirlist[i]; |
---|
1930 | } |
---|
1931 | ndirs = j; |
---|
1932 | } |
---|
1933 | |
---|
1934 | XSetFontPath(dpy, dirlist, ndirs); |
---|
1935 | } |
---|