1 /* xmotd is a message of the day displayer for X11 and dumb-terminals
2 *
3 * It displays a logo in the top-left corner, a 3-line title to its
4 * right and a text-widget (optionally a HTML widget) for displaying
5 * the message, just below. The motd filename(s) are supplied on the
6 * command-line. A single button is used to sequentailly access the
7 * motd(s) and to dismiss the browser when all the messages have been
8 * viewed. A label displays the time of the file being viewed and
9 * (optionally) the filename. It has options for automatically popping
10 * down w/o user intervention and other features which I can't be
11 * bothered to type-in here and would rather have you look at the
12 * man-page or http://www.ee.ryerson.ca:8080/~elf/xmotd.html
13 * */
14
15 /* $Id: main.c,v 1.19 2003/02/14 00:35:03 elf Exp elf $ */
16
17 /*
18 * Copyright 1993-97, 1999, 2003 Luis Fernandes <elf@ee.ryerson.ca>
19 *
20 * Permission to use, copy, hack, and distribute this software and its
21 * documentation for any purpose and without fee is hereby granted,
22 * provided that the above copyright notice appear in all copies and
23 * that both that copyright notice and this permission notice appear
24 * in supporting documentation. This application is presented as is
25 * without any implied or written warranty.
26 *
27 * This program is free software; you can redistribute it and/or modify
28 * it under the terms of the GNU General Public License as published by
29 * the Free Software Foundation; either version 2 of the License, or
30 * (at your option) any later version.
31 *
32 * This program is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 * GNU General Public License for more details.
36 *
37 * You should have received a copy of the GNU General Public License
38 * along with this program; if not, write to the Free Software
39 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
40 *
41 * libhtmlw is copyright (C) 1993, Board of Trustees of the University
42 * of Illinois. See the file libhtmlw/HTML.c for the complete text of
43 * the NCSA copyright.
44 */
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <time.h>
49
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <sys/time.h>
53 #include <utime.h>
54 #include <errno.h>
55 #include <fcntl.h>
56
57 #if defined(HPUX)
58
59 #include <ndir.h>
60 #define dirent direct
61
62 #else
63
64 #include <dirent.h>
65
66 #endif
67
68 #include <X11/Intrinsic.h>
69 #include <X11/StringDefs.h>
70 #include <X11/Xmu/Editres.h>
71
72 #ifdef HAVE_XPM
73 #include <X11/xpm.h>
74 #endif
75
76 #ifdef MOTIF
77
78 #include <Xm/Text.h>
79 #include <Xm/PushB.h>
80 #include <Xm/Form.h>
81 #include <Xm/Label.h>
82 #include <Xm/Separator.h>
83
84 #else
85
86 #include <X11/Shell.h>
87 #include <X11/Xaw/AsciiText.h>
88 #include <X11/Xaw/Command.h>
89 #include <X11/Xaw/Form.h>
90 #include <X11/Xaw/Label.h>
91
92 #endif
93
94 #ifdef HAVE_HTML
95 #include <HTML.h>
96 #endif
97
98 #define MIN_SLEEP_PERIOD 60 /* in seconds */
99 #define HOURS_TO_SECS 3600.0
100
101 #include "maindefs.h"
102 #include "appdefs.h"
103 #include "main.h"
104
105 extern time_t motdChanged();
106 extern void nextMessage(Widget w, caddr_t call_data, caddr_t client_data);
107 extern void AnchorCallbackProc(Widget w, caddr_t call_data, caddr_t client_data); /* browser.c */
108
109 extern void loadLogo(char *logo, Pixmap *icon_pixmap, Pixel fg, Pixel bg); /* in logo.c */
110
111 /* fwd decls*/
112 XtActionProc reallyQuit(Widget w, XButtonEvent *ev);
113 void Quit(Widget w, caddr_t call_data, caddr_t client_data);
114 void printUsage(char *str); /* usage.c */
115 int runSilentRunDeep(unsigned slumber);
116 unsigned getAlarmTime(float period);
117 messageptr freeMessage(messageptr msglist);
118 messageptr newMessage(char *file);
119
120 XtAppContext app_con;
121 Widget topLevel; /* the application widget*/
122
123 Widget text, quit;
124 Widget info;
125
126 XtIntervalId timer; /* pop-down time-out ID */
127
128 Pixmap icon_pixmap;
129
130 app_res_t app_res; /* application resources, in main.h */
131
132 /* list of pointers to the messages that will actually be displayed */
133 messageptr msgslist;
134
135 int gargc; /* globally accessible argc */
136 char **gargv; /* globally accessible argv*/
137
138 char timeStamp[256];
139
140 static int alreadyForked; /* flag to remember if we are already
141 running in the background */
142
143 #define offset(field) XtOffset (struct _resources *, field)
144
145 static XtResource resources[] = {
146 { "always","Always",XtRInt, sizeof(int),
147 offset(always),XtRString, "0"},
148
149 { "popdown","Popdown",XtRInt, sizeof(int),
150 offset(pto),XtRString, "0"},
151 { "usedomains","UseDomains",XtRInt, sizeof(int),
152 offset(usedomains),XtRString, "0"},
153 { "showfilename","ShowFilename",XtRInt, sizeof(int),
154 offset(showfilename),XtRString, "0"},
155 { "paranoid","Paranoid",XtRInt, sizeof(int),
156 offset(paranoid),XtRString, "0"},
157 { "tail","Tail",XtRInt, sizeof(int),
158 offset(tail),XtRString, "0"},
159 { "bitmaplogo","BitmapLogo",XtRString, sizeof(String),
160 offset(logo),XtRString, NULL},
161 { "warnfile","Warnfile",XtRString, sizeof(String),
162 offset(warnfile),XtRString, NULL},
163 { "wakeup","Wakeup",XtRFloat, sizeof(float),
164 offset(periodic),XtRString, "0"},
165 { "stampfile","Stampfile",XtRString, sizeof(String),
166 offset(stampfile),XtRString, TIMESTAMP},
167 { "atom","Atom",XtRString, sizeof(String),
168 offset(atomname),XtRString, ATOM},
169 #ifdef HAVE_HTML
170 { "browser","Browser",XtRString, sizeof(String),
171 offset(browser),XtRString, BROWSER},
172 #endif
173 };
174
175 static XrmOptionDescRec options[] = {
176 { "-always", "always", XrmoptionNoArg, "1"},
177 { "-showfilename", "showfilename", XrmoptionNoArg, "1"},
178 { "-usedomains", "usedomains", XrmoptionNoArg, "1"},
179 { "-paranoid", "paranoid", XrmoptionNoArg, "1"},
180 { "-tail", "tail", XrmoptionNoArg, "1"},
181 { "-popdown", "popdown", XrmoptionSepArg, (caddr_t) NULL},
182 { "-bitmaplogo", "bitmaplogo", XrmoptionSepArg, (caddr_t) NULL},
183 { "-warnfile", "warnfile", XrmoptionSepArg, (caddr_t) NULL},
184 { "-wakeup", "wakeup", XrmoptionSepArg, (caddr_t) NULL},
185 { "-stampfile", "stampfile", XrmoptionSepArg, (caddr_t) NULL},
186 { "-atom", "atom", XrmoptionSepArg, (caddr_t) NULL},
187 #ifdef HAVE_HTML
188 { "-browser", "browser", XrmoptionSepArg, (caddr_t) NULL},
189 #endif
190 };
191
192 /* You can use shift + btn1 to quit xmotd (when run with -wakeup)*/
193 static char shift1Trans[]="#override\n\
194 Shift<Btn1Down>,Shift<Btn1Up>: reallyquit()";
195
196 static XtActionsRec xlations[]={
197 {"reallyquit", (XtActionProc) reallyQuit},
198 };
199
200 /* when the text widget is mapped and we are in "tail" mode, scroll to
201 the end of the file*/
202 static char tailTrans[]="#override\n\
203 <Expose>: end-of-file()";
204
205 char *
getTimeStampName()206 getTimeStampName()
207 {
208 static char buf[256];
209
210 sprintf(buf, "%s/%s", getenv("HOME"), app_res.stampfile);
211
212 if(app_res.usedomains)
213 {
214 char domainame[256];
215
216 getdomainname(domainame, 256);
217
218 strcat(buf, ".");
219 strcat(buf, domainame);
220 }
221
222 return(buf);
223
224 }
225
226 /* convert user-specified wakeup time to seconds (argument to sleep)*/
227 unsigned
getAlarmTime(float period)228 getAlarmTime(float period)
229 {
230 unsigned slumber=(period*HOURS_TO_SECS);
231
232 /* fprintf(stderr,"slumber=%ld\n", slumber);*/
233
234 /* limit sleep to 60sec*/
235 return((slumber<MIN_SLEEP_PERIOD)?MIN_SLEEP_PERIOD:slumber);
236
237 }
238
239 /* NOTE: Jul 17 1996: This code doesn't work accurately for some
240 reason; the mod-time fo a file doesn't matchup with the time
241 returned by 'date' (this is on 4.1.3_U1). This is only a problem if
242 the wakeup period is something like 1 minute (which I use for
243 testing) -elf*/
244
245 void
updateTimeStamp(char * motdfile)246 updateTimeStamp(char *motdfile)
247 {
248 struct utimbuf ut;
249 time_t now;
250
251 /* fprintf(stderr, "Updating timestamp %s now.\n", getTimeStampName() ); */
252
253 now = time((time_t *)NULL);
254
255 ut.actime = now;
256 ut.modtime = now;
257
258 if(utime(motdfile,&ut))
259 {
260 extern int errno;
261
262 if(errno==ENOENT) /* if the file does not (1st time),
263 create it */
264 {
265 FILE *fp;
266
267 if((fp=fopen(motdfile,"w"))==NULL){
268 perror("xmotd");
269 }
270
271 fclose(fp);
272
273 }
274 else /* some other problem */
275 {
276 perror("xmotd");
277 exit(1);
278 }
279 }
280
281 }
282
283
284
285 XtActionProc
reallyQuit(Widget w,XButtonEvent * ev)286 reallyQuit(Widget w, XButtonEvent *ev )
287 {
288 extern char *txtbuf;
289
290 if(txtbuf) free(txtbuf);
291
292 if(icon_pixmap)
293 {
294 XFreePixmap(XtDisplay(topLevel), icon_pixmap);
295 }
296
297 XtDestroyApplicationContext(app_con);
298
299 /* fprintf(stderr,"Bye.\n");*/
300 exit(0);
301
302 }
303
304
305 void
306 /*ARGSUSED*/
Quit(Widget w,caddr_t call_data,caddr_t client_data)307 Quit(Widget w, caddr_t call_data, caddr_t client_data)
308 {
309 extern char *txtbuf;
310
311 if(!app_res.periodic)
312 {
313 /* we can exit because -wakeup is not specified*/
314 reallyQuit((Widget)NULL, (XButtonEvent *)NULL );
315 }
316 else
317 {
318 extern void revisitMessagesAndDisplay(int);
319
320 XUnmapWindow(XtDisplay(topLevel), XtWindow(topLevel));
321 XFlush(XtDisplay(topLevel));
322
323 if(!alreadyForked)
324 {
325 if(fork()) exit(0);
326
327 alreadyForked=1;
328 }
329
330 revisitMessagesAndDisplay(runSilentRunDeep(getAlarmTime(app_res.periodic)));
331
332 }
333
334 }
335
336 messageptr
freeMessage(messageptr msglist)337 freeMessage(messageptr msglist)
338 {
339 messageptr oldmsg;
340 oldmsg = msglist;
341 msglist = msglist->next;
342
343 free(oldmsg->file);
344 free(oldmsg);
345 return(msglist);
346
347 } /*freeMessage*/
348
349 messageptr
newMessage(char * file)350 newMessage(char *file)
351 {
352 messageptr newmsg;
353
354 if (!(newmsg = (messageptr)malloc(sizeof(struct messagenode))))
355 {
356 perror("xmotd");
357 exit (2); /*problems, probably no ram HA */
358 } /*if*/
359
360 newmsg->file=(char *)calloc(1,(strlen(file)+1)*sizeof(char));
361
362 if(!newmsg->file)
363 {
364 perror("xmotd");
365 exit(2);
366 }
367
368 strcpy(newmsg->file, file);
369 newmsg->next = NULL;
370 return(newmsg);
371
372 } /*newMessage*/
373
374
375 int
numFilesToDisplay(int argc,char ** argv)376 numFilesToDisplay(int argc, char **argv)
377 {
378 register int numsg=0, i;
379 struct stat motdstat;
380 messageptr newmsg, currentmsg = msgslist;
381
382 /* i starts at 1 since argv[0] is the program name*/
383 for(i=1; i<argc; i++)
384 {
385 stat(argv[i], &motdstat);
386
387 if(motdstat.st_mode & S_IFDIR) /* it's a directory */
388 {
389 DIR *dir;
390 struct dirent *dp;
391 char name[BUFSIZ];
392
393 if ((dir = opendir(argv[i])))
394 {
395 while (dp = readdir(dir))
396 {
397 if (dp->d_ino == 0)
398 continue;
399 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
400 continue;
401 strcpy(name, argv[i]);
402
403 if (name[strlen(name) - 1] != '/')
404 strcat(name, "/");
405 strcat(name, dp->d_name);
406
407 if (access(name, 0) < 0)
408 continue;
409
410 if(motdChanged(name, timeStamp) || app_res.always)
411 {
412 newmsg = newMessage(name);
413
414 if (!currentmsg) /* first in list */
415 msgslist = newmsg;
416 else
417 currentmsg->next = newmsg;
418
419 currentmsg = newmsg;
420 numsg++;
421 } /*if motdchanged*/
422
423 } /*while*/
424
425 closedir(dir);
426 } /*if opendir*/
427 }
428 else
429 if(motdChanged(argv[i], timeStamp) || app_res.always)
430 {
431 newmsg = newMessage(argv[i]);
432
433 if (!currentmsg) /* first in list */
434 msgslist = newmsg;
435 else
436 currentmsg->next = newmsg;
437
438 currentmsg = newmsg;
439 numsg++;
440 }
441 }
442
443 if((numsg || app_res.paranoid || app_res.always) && app_res.warnfile)
444 {
445 newmsg = newMessage(app_res.warnfile);
446 newmsg->next = msgslist;
447 msgslist = newmsg;
448 numsg++;
449 } /*if*/
450
451 return numsg;
452
453 }/* numFilesToDisplay*/
454
455 int
runSilentRunDeep(unsigned slumber)456 runSilentRunDeep(unsigned slumber)
457 {
458 int numsg=0;
459
460 while(1)
461 {
462 int fd;
463
464 /* fprintf(stderr, "Going to sleep! (Zzzzzzzz...)\n");*/
465 sleep(slumber);
466 /* fprintf(stderr, "Waking-up! (Yawn...)\n");*/
467
468 /* first thing we do after waking up is to see if the user is
469 still logged-in*/
470 if((fd=open("/dev/console", O_RDONLY, O_RDONLY)<0))
471 {
472 /* since xmotd can't read from the console we assume user
473 has logged-out, so we exit*/
474 exit(0);
475 }
476
477 close(fd);
478
479 /* next check if any messages need to be displayed, if there
480 aren't any, go back to sleep; otherwise return to display
481 messages*/
482 if(numsg=numFilesToDisplay(gargc, gargv)) return(numsg);
483 }
484
485 }
486
487
main(argc,argv)488 main(argc, argv)
489 int argc;
490 char **argv;
491 {
492 extern Boolean atomExists(String);
493 Display *display;
494 register int i, start=0;
495 int numsg;
496
497
498 if ((argc > 1) && !(strcmp(argv[1],"-help")))
499 {
500 printUsage(argv[0]); /* and exit */
501 }
502
503 /* Test to see whether we are connected to an X display. If we
504 aren't, we proceed in text-only mode: bare-bones functionality;
505 output to stdout. Why bare-bones, I hear you asking? Well, X
506 does all the command-line options parsing for me and I don't feel
507 like duplicating all that code. So there.*/
508
509 if((display=XOpenDisplay((char *)NULL))==NULL)
510 {
511
512 if(argc<2)
513 {
514 fprintf(stderr, "xmotd: ERROR, missing file.\n");
515 printUsage(argv[0]); /* and exit */
516 }
517 else
518 {
519 extern void runInTextMode();
520 runInTextMode(argc, argv); /* ...and exit... */
521 }
522
523 fprintf(stderr,"Never gets here!\n");
524 exit(0); /* just in case */
525
526 }
527 else
528 {
529 XCloseDisplay(display);
530 }
531
532 /* we have to init the toolkit *before* we check the command-line so
533 we can use X's parsing routines, since -geom options, etc. may be
534 specified, in which case, the motd-filename is *not* the 2nd
535 argument*/
536 topLevel = XtVaAppInitialize(&app_con, "XMotd", options,
537 XtNumber(options),
538 &argc, argv, fallback_resources,
539 NULL);
540
541 XtGetApplicationResources(topLevel, (caddr_t) &app_res,
542 resources, XtNumber(resources),
543 (ArgList) NULL, (Cardinal) 0);
544
545 if(argc<2)
546 {
547 fprintf(stderr,"xmotd: ERROR, missing file\n");
548 printUsage(argv[0]); /* and exit */
549 }
550
551 if(app_res.paranoid && !app_res.warnfile)
552 {
553 fprintf(stderr,"xmotd: ERROR, specified \"-paranoid\" without \"-warnfile\"\n");
554 printUsage(argv[0]); /* and exit */
555 }
556
557 strcpy(timeStamp, getTimeStampName());
558
559 gargc=argc;
560 gargv=argv;
561
562 /* first figure out how many of the files supplied on the
563 command-line we will be actually displaying; i.e. we only show
564 the new ones (unless -always has been specified, in which case we
565 show all of them)*/
566 numsg=numFilesToDisplay(argc, argv);
567
568 if(!app_res.periodic && !numsg)
569 {
570 /* if none of the messages need to be displayed and -wakeup not
571 specified */
572
573 XtDestroyApplicationContext(app_con);
574 exit(0);
575 }
576
577 if(app_res.periodic) /*-wakeup or -timeout specified*/
578 {
579
580 /*ensure no other copies of xmotd are running*/
581 if(atomExists(app_res.atomname)){
582 XtDestroyApplicationContext(app_con);
583 exit(0);
584 }
585
586 if(fork()) exit(0); /*we have to daemonize ourselves*/
587 alreadyForked=1; /* make a note of it */
588
589 if(!numsg)
590 {
591 /* if no messages to be displayed, we sleep */
592 numsg=runSilentRunDeep(getAlarmTime(app_res.periodic));
593 }
594
595 }
596
597 createWidgets(numsg);
598 nextMessage((Widget)NULL, (caddr_t)NULL, (caddr_t)NULL);
599
600 XtAddEventHandler(topLevel, (EventMask)0, True,
601 (XtEventHandler)_XEditResCheckMessages, 0);
602
603 XtRealizeWidget(topLevel);
604 XtAppMainLoop(app_con);
605 }
606
607
createWidgets(int anymsg)608 createWidgets(int anymsg)
609 {
610 Widget form, paned, logo, mlabel, hline;
611 XtTranslations shift1TransTable, tailTransTable;
612 Pixel fg, bg;
613 Arg args[8];
614 int n;
615
616 #ifdef MOTIF
617 XmString xmstr;
618
619 form=XtVaCreateManagedWidget("form", xmFormWidgetClass,topLevel,
620 NULL);
621 #else
622
623 form=XtVaCreateManagedWidget("form", formWidgetClass,topLevel,
624 XtNresizable, True,
625 NULL);
626 #endif /* ifdef MOTIF */
627
628 XtVaGetValues(form,
629 XtNbackground, &bg,
630 XtNforeground, &fg,
631 NULL);
632
633 loadLogo(app_res.logo, &icon_pixmap, fg, bg);
634
635 #ifdef MOTIF
636 logo=XtVaCreateManagedWidget("logo", xmLabelWidgetClass, form,
637 XmNleftAttachment, XmATTACH_FORM,
638 XmNtopAttachment, XmATTACH_FORM,
639 XmNlabelType, XmPIXMAP,
640 XmNlabelPixmap, icon_pixmap,
641 XmNborderWidth, 0,
642 NULL);
643
644 mlabel=XtVaCreateManagedWidget("title", xmLabelWidgetClass, form,
645 XmNleftAttachment, XmATTACH_WIDGET,
646 XmNleftWidget, logo,
647 XmNrightAttachment, XmATTACH_FORM,
648 NULL);
649
650 hline=XtVaCreateManagedWidget("hline", xmSeparatorWidgetClass, form,
651 XmNtopAttachment, XmATTACH_WIDGET,
652 XmNtopWidget, logo,
653 NULL);
654
655 quit = XtVaCreateManagedWidget("quit", xmPushButtonWidgetClass, form,
656 XmNtopAttachment, XmATTACH_WIDGET,
657 XmNtopWidget, logo,
658 XmNlabelType, XmSTRING,
659
660 XmNtraversalOn, False, /* remove
661 Dismiss button from the Tab group;
662 comment this line out if YOU WANT
663 "Space-bar" to activate the dismiss
664 button*/
665 NULL);
666
667 info=XtVaCreateManagedWidget("info", xmLabelWidgetClass, form,
668 XmNleftAttachment, XmATTACH_FORM,
669 XmNtopAttachment, XmATTACH_WIDGET,
670 XmNtopWidget, quit,
671 XmNlabelType, XmSTRING,
672 NULL);
673
674 #ifdef HAVE_HTML
675
676 n = 0;
677 XtSetArg(args[n],XmNtopAttachment, XmATTACH_WIDGET); n++;
678 XtSetArg(args[n],XmNtopWidget, info); n++;
679 XtSetArg(args[n],XmNbottomAttachment, XmATTACH_FORM); n++;
680
681 text = XtVaCreateManagedWidget("text", htmlWidgetClass, form,NULL);
682
683 XtSetValues(text,args,n);
684
685 XtManageChild(text);
686
687 #else
688
689 n=0;
690 XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
691 XtSetArg(args[n], XmNeditable, False); n++;
692 XtSetArg(args[n], XmNscrollHorizontal, False); n++;
693 XtSetArg(args[n], XmNscrollLeftSide, True); n++;
694 XtSetArg(args[n], XmNcursorPositionVisible, False); n++;
695
696 text=XmCreateScrolledText(form, "text", args, n);
697 n=0;
698
699 XtVaSetValues(XtParent(text),
700 XmNtopAttachment, XmATTACH_WIDGET,
701 XmNtopWidget, info,
702 XmNbottomAttachment, XmATTACH_FORM,
703 NULL);
704
705 XtManageChild(text);
706 #endif /* ifdef HAVE_HTML & ifdef MOTIF */
707
708 #else
709
710 logo=XtVaCreateManagedWidget("logo", labelWidgetClass, form,
711 XtNleft, XtChainLeft,
712 XtNright, XtChainLeft,
713 XtNbitmap, icon_pixmap,
714 NULL);
715
716 mlabel=XtVaCreateManagedWidget("title", labelWidgetClass, form,
717 XtNfromHoriz, logo,
718 NULL);
719
720 hline=XtVaCreateManagedWidget("hline", labelWidgetClass, form,
721 XtNfromVert, logo,
722 XtNfromVert, mlabel,
723 XtNlabel, (char *)NULL,
724 NULL);
725
726 quit = XtVaCreateManagedWidget("quit", commandWidgetClass, form,
727 XtNleft, XtChainLeft,
728 XtNright, XtChainLeft,
729 XtNfromVert, logo,
730 NULL);
731
732 info=XtVaCreateManagedWidget("info", labelWidgetClass, form,
733 XtNright, XtChainLeft,
734 XtNfromVert, quit,
735 XtNresizable, True,
736 NULL);
737
738 #ifdef HAVE_HTML
739 text = XtVaCreateManagedWidget("text",
740 htmlWidgetClass, form,
741 XtNfromVert, info,
742 XtNwidth, 680,
743 XtNheight, 500,
744 NULL);
745
746 #else
747 text = XtVaCreateManagedWidget("text",
748 asciiTextWidgetClass, form,
749 XtNfromVert, info,
750 NULL);
751
752 #endif /* ifdef HAVE_HTML */
753
754 if(app_res.tail)
755 {
756 tailTransTable=XtParseTranslationTable(tailTrans);
757 XtOverrideTranslations(text, tailTransTable);
758 }
759
760 #endif /* ifdef MOTIF */
761
762 if((anymsg>1))
763 {
764 #ifdef MOTIF
765 xmstr=XmStringCreateLocalized(NEXT_MESSAGE_LABEL);
766 XtVaSetValues(quit, XmNlabelString, xmstr, NULL);
767 XmStringFree(xmstr);
768
769 XtAddCallback(quit, XmNactivateCallback, (XtCallbackProc)nextMessage, 0);
770 #else
771 XtAddCallback(quit, XtNcallback, (XtCallbackProc)nextMessage,(caddr_t)0);
772 XtVaSetValues(quit, XtNlabel, NEXT_MESSAGE_LABEL, NULL);
773 #endif
774 if(app_res.pto)
775 timer=XtAppAddTimeOut(app_con, (unsigned long)(app_res.pto*1000),
776 (XtTimerCallbackProc)nextMessage, (caddr_t) NULL);
777 }
778 else
779 {
780 #ifdef MOTIF
781 xmstr=XmStringCreateLocalized(LAST_MESSAGE_LABEL);
782 XtVaSetValues(quit, XmNlabelString, xmstr, NULL);
783 XmStringFree(xmstr);
784
785 XtAddCallback(quit, XmNactivateCallback, (XtCallbackProc)Quit, 0);
786 #else
787 XtAddCallback(quit, XtNcallback, (XtCallbackProc)Quit, 0);
788 XtVaSetValues(quit, XtNlabel, LAST_MESSAGE_LABEL, NULL);
789 #endif
790 if(app_res.pto)
791 timer=XtAppAddTimeOut(app_con, (unsigned long)(app_res.pto*1000),
792 (XtTimerCallbackProc)Quit, (caddr_t) NULL);
793 }
794
795 #ifdef HAVE_HTML
796 XtAddCallback(text, WbNanchorCallback,
797 (XtCallbackProc)AnchorCallbackProc,(caddr_t)0);
798 #endif
799
800 XtAppAddActions(app_con, xlations, XtNumber(xlations));
801 shift1TransTable=XtParseTranslationTable(shift1Trans);
802 XtOverrideTranslations(quit, shift1TransTable);
803
804 }/* createWidgets*/
805
806