1 /*
2  * xhime  -  Himechan for X Window System
3  * Copyright(C) 1994-1996,1998 `Shochan'Shoichi-NAKAYAMA (PED02616@nifty.ne.jp)
4  *
5  *	Original version for PC-9801  "Resident Himechan Ver1.10"
6  *	Copyright(C) 1994 MSP-Iris(Mapletown Network: MAP4370)
7  */
8 static char rcsid[] ="$Header: /home/naka/xhime/xhime1.51/RCS/xhime.c,v 1.42 1998/09/11 11:57:51 naka Exp $";
9 
10 char
11 *Copyright = "xhime version 1.51 by `Shochan' Shoichi-NAKAYAMA (C) 1994-1996,1998\n  Original: `rhime.exe' by MSP-Iris (C) 1994\n";
12 
13 #include	<X11/Xlib.h>
14 #include	<X11/Xutil.h>
15 #include	<X11/keysym.h>
16 #include	<X11/Xos.h>
17 
18 #ifdef	SHAPE
19 #include	<X11/extensions/shape.h>
20 #endif/*SHAPE*/
21 
22 #include	<stdio.h>
23 #include	<stdlib.h>
24 #include	<signal.h>
25 #include	<ctype.h> /* defined in X11/Xos.h ? */
26 #include	<string.h>/* defined in X11/Xos.h ? */
27 #include	<limits.h>
28 #include	<stdarg.h>
29 #include	<sys/time.h>/* defined in X11/Xos.h */
30 #include	<sys/types.h>
31 #include	<sys/stat.h>
32 #ifndef	O_RDONLY
33 #include	<fcntl.h>
34 #endif/*!O_RDONLY*/
35 
36 #define	DOUBLEQUOTE	'\"'	/* " <- for hilit comment (^^ */
37 
38 #ifndef	MIN
39 #define	MIN(a, b)	((a)<(b) ? (a):(b))
40 #endif/*!MIN*/
41 
42 #ifndef	MAX
43 #define	MAX(a, b)	((a)>(b) ? (a):(b))
44 #endif/*!MAX*/
45 
46 #ifndef MAILSPOOL_PATH
47 #define MAILSPOOL_PATH	"/usr/spool/mail/"
48 #endif/*!MAILSPOOL_PATH*/
49 
50 #ifndef AUDIO_DEVICE
51 #define AUDIO_DEVICE	"/dev/audio"
52 #endif/*!AUDIO_DEVICE*/
53 
54 #define	AUD_NONE	0
55 #define	AUD_BELL	1
56 #define	AUD_DEV		2
57 #define	AUD_CMD		3
58 
59 #ifndef XHIMEDAT_PATH
60 #define	XHIMEDAT_PATH	"/usr/X11R6/lib/X11/xhime"
61 #endif/*!XHIMEDAT_PATH*/
62 
63 char	*XHIMEDAT = XHIMEDAT_PATH;
64 char	*DisplayName = "";
65 char	*ProgramName = NULL;
66 char	*Geometry = NULL;
67 char	*DataName = "rh110.xhm";
68 char	*ActionKey = "Return";
69 char	*AudioCommand = "showaudio";
70 char	*AudioDevice = AUDIO_DEVICE;
71 char	*AudioDataName = "IKEIKE_J.au";
72 char	AudioDataPath[256] = "";
73 char	*Background = "black";
74 char	*MailPathArg = NULL;
75 Bool	Debug = False;
76 Bool	NoShape = False;
77 Bool	UseWM = False;
78 Bool	Rhime = True;
79 Bool	Biff = False;
80 int	Audio = AUD_NONE;
81 int	ActionState = 1;
82 int	MAX_AUSIZE = 65536;
83 Bool	FocusDebug = False;
84 
85 #define	DEF_INT_TIME_MS	125
86 #define	DEF_MAIL_CHECK_INT_TIME_MS	30000	/* 30sec. */
87 #define	FOCUS_CHECK_INTERVAL_TIME_MS	500
88 int	MAIL_CHECK_INTERVAL_TIME_MS = DEF_MAIL_CHECK_INT_TIME_MS;
89 int	INTERVAL_TIME_MS = DEF_INT_TIME_MS;
90 int	FocusCheckCountMax = FOCUS_CHECK_INTERVAL_TIME_MS / DEF_INT_TIME_MS;
91 int	MailCheckCountMax  = DEF_MAIL_CHECK_INT_TIME_MS   / DEF_INT_TIME_MS;
92 int	NCOLORS, NCELLS, NPATTERNS, NSTATES;
93 int	WIDTH, HEIGHT;
94 
95 #define	H_OFF	0	/*window height OFFSET no use*/
96 #define	MOVECHECK_MASK	0
97 /*#define	MOVECHECK_MASK	(UseWM ? StructureNotifyMask : 0)*/
98 #define	EVENT_MASK	(KeyPressMask|ButtonPressMask|ButtonReleaseMask|PointerMotionMask|MOVECHECK_MASK)
99 #define	FOCUS_EVENT_MASK	(KeyPressMask|StructureNotifyMask)
100 
101 Display		*MyDisplay;
102 int		MyScreen;
103 unsigned int	MyDepth;
104 Window		MyWindow;
105 int		Myx, Myy;
106 KeySym	ActionKeysym;
107 
108 #define	IDLE	0
109 #define	ACTION	1
110 int	State = IDLE;
111 int	PatternNumber = 0;
112 #define	ACT_NONE	0
113 #define	ACT_KEY		1
114 #define	ACT_MAIL	2
115 int	ActionFlag = ACT_NONE;
116 
117 /* -- */
118 void
Error(char * fmt,...)119 Error(char *fmt, ...)
120 {
121   va_list	args;
122 
123   fprintf(stderr, "%s: ", ProgramName);
124 
125   va_start(args, fmt);
126   fmt = (char *)va_arg(args, char *);
127   vfprintf(stderr, fmt, args);
128   va_end(args);
129 
130   fprintf(stderr, "\n");
131 }
132 
133 void
ErrorExit(char * fmt,...)134 ErrorExit(char *fmt, ...)
135 {
136   va_list	args;
137 
138   fprintf(stderr, "%s: ", ProgramName);
139 
140   va_start(args, fmt);
141   fmt = (char *)va_arg(args, char *);
142   vfprintf(stderr, fmt, args);
143   va_end(args);
144 
145   fprintf(stderr, "\n");
146   exit(1);
147 }
148 
149 #define CALLOC(p, nelem, elsize)        \
150   do {\
151     if (p) ErrorExit("not null pointer");\
152     if ((nelem)*(elsize) > 0) {\
153       if (! ((p) = (void *)calloc((unsigned)(nelem), (unsigned)(elsize))) )\
154         ErrorExit("cannot alocate memory");\
155     }else {\
156       ErrorExit("invalid memory size '%d'", (nelem)*(elsize));\
157     }\
158   } while (0)
159 
160 #define	FREE(p)	do {if (p) { free(p); (p) = NULL; } } while (0)
161 
162 #ifdef	GET_DEBUG
163 #define	DEBUG_PUTC(c)	putchar(c)
164 #define	DEBUG_PUTS(c)	fputs(c, stdout)
165 #else
166 #define	DEBUG_PUTC(c)
167 #define	DEBUG_PUTS(c)
168 #endif/*GET_DEBUG*/
169 
170 typedef	struct {
171   char	name[256];
172   int	x;
173   int	y;
174   int	nmask;
175   int	*mask_num;
176   int	width;
177   int	height;
178   char	**pxl;
179   Pixmap	pixmap;
180   Pixmap	mask;
181 }CELL;
182 
183 CELL	*Cell = NULL;
184 
185 typedef	struct {
186   char	c;
187   char	type[3];
188   char	name[256];
189   GC	GC;
190 }COLOR;
191 
192 COLOR	*DummyColor = NULL;
193 COLOR	*ColorN = NULL;
194 COLOR	*ColorD = NULL;
195 COLOR	*ColorB = NULL;
196 COLOR	**Color = &ColorN;
197 
198 typedef	struct {
199   int	num;
200   int	x;
201   int	y;
202 }PATTERN;
203 
204 PATTERN	*Pattern = NULL;
205 
206 typedef	struct {
207   int	start;
208   int	end;
209   int	next_state;
210 }STATES;
211 
212 STATES	*States = NULL;
213 
214 
215 int
Skip(fp)216 Skip(fp)
217      FILE	*fp;
218 {
219   int	flg = 1, c;
220 
221   DEBUG_PUTC('<');
222   while (EOF != (c = getc(fp))) {
223     DEBUG_PUTC(c);
224     if (isspace(c)) continue;
225     if (c == ',' && flg) {
226       flg = 0;
227       continue;
228     }
229     break;
230   }
231   DEBUG_PUTC('>');
232 
233   if (c == EOF) ErrorExit("eof");
234 
235   ungetc(c, fp);
236   return (c);
237 }
238 
239 int
Found(fp,f)240 Found(fp, f)
241      FILE	*fp;
242      int	f;
243 {
244   int	c;
245 
246   while (EOF != (c = getc(fp)) && c != f);
247   if (c == EOF) {
248     ErrorExit("not found char '%c'", f);
249   }
250   return (c);
251 }
252 
253 int
GetStr(fp,str,len)254 GetStr(fp, str, len)
255      FILE	*fp;
256      char	*str;
257      int	len;
258 {
259   int	i = 0, c;
260 
261   DEBUG_PUTC('<');
262   while (EOF != (c = getc(fp))) {
263     DEBUG_PUTC(c);
264     if (isspace(c) || c == ',' || c == DOUBLEQUOTE) break;
265     if (i++ < len - 1) {
266       *str++ = c;
267     }
268   }
269   DEBUG_PUTC('>');
270 
271   if (c == EOF) ErrorExit("not found string");
272 
273   ungetc(c, fp);
274   *str = '\0';
275   return (c);
276 }
277 
278 int
GetInt(fp,value)279 GetInt(fp, value)
280      FILE	*fp;
281      int	*value;
282 {
283   char	buf[24];
284   int	c = GetStr(fp, buf, sizeof(buf));
285   *value = atoi(buf);
286   return (c);
287 }
288 
289 int
GetDefinedInt(fp,msg)290 GetDefinedInt(fp, msg)
291      FILE	*fp;
292      char	*msg;
293 {
294   static char	define[] = "#define";
295   char	line[256];
296   int	value;
297 
298   for (;;) {
299     if (!fgets(line, sizeof(line), fp)) {
300       ErrorExit("not found #define");
301     }
302 
303     if (strncmp(line, define, sizeof(define)-1) == 0) {
304       if (sscanf(line, "#define %*s %d", &value) != 1) {
305 	ErrorExit("cannot read '%s'", msg);
306       }
307 
308       if (Debug) printf("%s = %d\n", msg, value);
309       break;
310     }
311   }
312   return (value);
313 }
314 
315 void
GetColor(fp,color,ncolors)316 GetColor(fp, color, ncolors)
317      FILE	*fp;
318      COLOR	*color;
319      int	ncolors;
320 {
321   int	i;
322 
323   for (i = 0; i < ncolors; i++, color++) {
324     Found(fp, DOUBLEQUOTE);
325     if ((color->c = getc(fp)) == EOF) ErrorExit("eof");
326     Skip(fp);
327     GetStr(fp, color->type, sizeof(color->type));
328     Skip(fp);
329     GetStr(fp, color->name, sizeof(color->name));
330     Found(fp, DOUBLEQUOTE);
331 
332     if (Debug) printf("%c %s %s\n", color->c, color->type, color->name);
333   }
334 }
335 
336 int
GetXpm(fp,cell,color)337 GetXpm(fp, cell, color)
338      FILE	*fp;
339      CELL	*cell;
340      COLOR	*color;
341 {
342   static char	XPM[] = "/* XPM */";
343   int	ncolors, chars_per_pixel;
344   char	**yp = NULL;
345   char	line[80];
346   int	x, y;
347 
348   for (;;) {
349     if (!fgets(line, sizeof(line), fp)) {
350       ErrorExit("not found XPM header");
351     }
352     if (strncmp(line, XPM, sizeof(XPM)-1) == 0) break;
353   }
354   Found(fp, '{');
355   Found(fp, DOUBLEQUOTE);
356   GetInt(fp, &cell->width);	Skip(fp);
357   GetInt(fp, &cell->height);	Skip(fp);
358   GetInt(fp, &ncolors);	Skip(fp);
359   GetInt(fp, &chars_per_pixel);
360   if (Debug) printf("width=%d, height=%d, ncolors=%d, %d(chars/pixel)\n",
361 		    cell->width, cell->height, ncolors, chars_per_pixel);
362   if (chars_per_pixel != 1) {
363     ErrorExit("not supported XPM (chars/pixel != 1)");
364   }
365   Found(fp, DOUBLEQUOTE);
366 
367   CALLOC(color, ncolors, sizeof(*color));
368   GetColor(fp, color, ncolors);
369 
370   CALLOC(cell->pxl, cell->height, sizeof(cell->pxl));
371   yp = cell->pxl;
372   for (y = 0; y < cell->height; y++, yp++) {
373     char	*xp = NULL;
374 
375     Found(fp, DOUBLEQUOTE);
376     CALLOC(*yp, cell->width + 1, sizeof(char));
377     xp = *yp;
378     for (x = 0; x < cell->width; x++) {
379       int c = getc(fp);
380       if (EOF == c) ErrorExit("eof");
381       DEBUG_PUTC(c);
382       *xp++ = c;
383     }
384     Found(fp, DOUBLEQUOTE);
385     DEBUG_PUTC('\n');
386   }
387   Found(fp, '}');
388 
389   return (ncolors);
390 }
391 
392 char OpenDataName[256] = "";
393 #define	STR_TAIL(p)	(*(p) ? *((char *)(p) + strlen(p) - 1): *(p) )
394 
395 FILE*
OpenData(fname,mode)396 OpenData(fname, mode)
397      char	*fname;
398      char	*mode;
399 {
400   FILE	*fp = stdin;
401   strncpy(OpenDataName, fname, sizeof(OpenDataName));
402   if (strcmp(fname, "-") != 0) {
403     if (Debug) fprintf(stderr, "Data Searching...\n\tCurrent  '%s'\n", fname);
404     if ((fp = fopen(fname, mode)) == NULL) {
405       if (*fname == '/' ) {
406 	ErrorExit("cannot open file '%s'", fname);
407       }else {
408 	char path[256];
409 	strncpy(path, fname, sizeof(path));
410 	if (XHIMEDAT) {
411 	  strncpy(path, XHIMEDAT, sizeof(path));
412 	  if (STR_TAIL(path) != '/') strncat(path, "/", sizeof(path));
413 	  strncat(path, fname, sizeof(path));
414 	  fp = fopen(path, mode);
415 	  if (Debug) fprintf(stderr, "\tXHIMEDAT '%s'\n", path);
416 	}
417 	if (fp == NULL && strrchr(ProgramName, '/') != NULL) {
418 	  strncpy(path, ProgramName, sizeof(path));
419 	  *(strrchr(path, '/') + 1) = '\0';
420 	  strncat(path, fname, sizeof(path));
421 	  fp = fopen(path, mode);
422 	  if (Debug) fprintf(stderr, "\tProgram  '%s'\n", path);
423 	}
424 	if (fp == NULL) {
425 	  ErrorExit("cannot open file '%s'", path);
426 	}
427 	strncpy(OpenDataName, path, sizeof(OpenDataName));
428       }
429     }
430   }
431   return (fp);
432 }
433 
434 
435 
436 int
GetData(fname)437 GetData(fname)
438      char	*fname;
439 {
440   FILE	*fp = NULL;
441   char	buf[256];
442   int	c, i, j;
443   char  *s = (char *)getenv("XHIMEDAT");
444 
445   if (s) XHIMEDAT = s;
446   fp = OpenData(fname, "r");
447 
448   if (!fgets(buf, sizeof(buf), fp)) {
449     ErrorExit("cannot read");
450   }
451   if (strncmp(buf, "/* xhime */", 11) != 0) {
452     ErrorExit("not found xhime header");
453   }
454 
455   NCOLORS = GetDefinedInt(fp, "NCOLORS");
456   CALLOC(ColorN, NCOLORS, sizeof(*ColorN));
457   CALLOC(ColorB, NCOLORS, sizeof(*ColorB));
458   CALLOC(ColorD, NCOLORS, sizeof(*ColorD));
459 
460   GetColor(fp, ColorN, NCOLORS);
461   GetColor(fp, ColorB, NCOLORS);
462   GetColor(fp, ColorD, NCOLORS);
463 
464   WIDTH = GetDefinedInt(fp, "WIDTH");
465   HEIGHT = GetDefinedInt(fp, "HEIGHT");
466   NCELLS = GetDefinedInt(fp, "NCELLS");
467   CALLOC(Cell, NCELLS, sizeof(*Cell));
468   {
469     CELL	*clp = Cell;
470     Found(fp, '{');
471     for (i = 0; i < NCELLS; i++, clp++) {
472       Found(fp, DOUBLEQUOTE);
473       GetStr(fp, clp->name, sizeof(clp->name));    Skip(fp);
474       GetInt(fp, &clp->x);	Skip(fp);
475       GetInt(fp, &clp->y);	c = Skip(fp);
476 
477       if (Debug) printf("%d: %s (%d,%d) ", i, clp->name, clp->x, clp->y);
478 
479       if (c != DOUBLEQUOTE) {
480 	int	*mp;
481 
482 	CALLOC(clp->mask_num, NCELLS, sizeof(clp->mask_num));
483 
484 	mp = clp->mask_num;
485 	for (j = 0; j < NCELLS; j++, mp++) {
486 	  if (c == DOUBLEQUOTE) break;
487 
488 	  GetInt(fp, mp);	c = Skip(fp);
489 	  if (*mp < 0 || NCELLS <= *mp) {
490 	    ErrorExit("mask number error '%d'", *mp);
491 	  }
492 	  if (Debug) printf(" %d", *mp);
493 	}
494 	clp->nmask = j;
495       }
496       if (Debug) printf("\n");
497       Found(fp, DOUBLEQUOTE);
498     }
499   }
500 
501   if ((INTERVAL_TIME_MS = GetDefinedInt(fp, "INTERVAL_TIME_MS") ) <= 0) {
502     ErrorExit("invalid INTERVAL_TIME_MS number");
503   }
504   NPATTERNS = GetDefinedInt(fp, "NPATTERNS");
505   if (NPATTERNS <= 0) {
506     ErrorExit("invalid NPATTERNS number");
507   }
508 
509   CALLOC(Pattern, NPATTERNS, sizeof(*Pattern));
510   {
511     PATTERN	*pp = Pattern;
512     Found(fp, '{');
513     for (i = 0; i < NPATTERNS; i++, pp++) {
514       Found(fp, '{');    Skip(fp);
515       GetInt(fp, &pp->num);	Skip(fp);
516       GetInt(fp, &pp->x);	Skip(fp);
517       GetInt(fp, &pp->y);
518 
519       if (Debug) printf("%d %d %d\n", pp->num, pp->x, pp->y);
520       if (pp->num < 0 || NCELLS <= pp->num) {
521 	ErrorExit("invalid cell number '%d'", pp->num);
522       }
523     }
524   }
525 
526   NSTATES = GetDefinedInt(fp, "NSTATES");
527   CALLOC(States, NSTATES, sizeof(*States));
528   {
529     STATES	*sp = States;
530     Found(fp, '{');
531     for (i = 0; i < NSTATES; i++, sp++) {
532       Found(fp, '{');    Skip(fp);
533       GetInt(fp, &sp->start);	Skip(fp);
534       GetInt(fp, &sp->end);	Skip(fp);
535       GetInt(fp, &sp->next_state);
536 
537       if (Debug) printf("%d %d %d\n", sp->start, sp->end, sp->next_state);
538 
539       if (sp->start < 0 || NPATTERNS <= sp->start) {
540 	ErrorExit("invalid pattern number '%d'", sp->start);
541       }
542       if (sp->end < 0 || sp->end < sp->start) {
543 	ErrorExit("invalid pattern number '%d'", sp->end);
544       }
545       if (sp->next_state < 0 || NSTATES <= sp->next_state) {
546 	ErrorExit("invalid state number '%d'", sp->next_state);
547       }
548     }
549     if (ActionState >= NSTATES) ActionState = 0;
550   }
551 
552   {
553     CELL	*clp = Cell;
554     for (j = 0; j < NCELLS; j++, clp++) {
555       FILE	*fpx = fp;
556 
557       if (strcmp(clp->name, "-") != 0) {
558 	fpx = OpenData(clp->name, "r");
559       }
560       if (Debug) printf("%d: xpmfile='%s'\n", j, clp->name);
561       if (GetXpm(fpx, clp, DummyColor) != NCOLORS) {
562 	ErrorExit("invalid ncolors '%s'", clp->name);
563       }
564       FREE(DummyColor);
565       if (fpx != fp) fclose(fpx);
566     }
567   }
568 
569   if (fp != stdin) fclose(fp);
570 }
571 /* -- */
572 char	MailPath[256] = MAILSPOOL_PATH;
573 
574 void
GetMailPath()575 GetMailPath()
576 {
577   if (MailPathArg) {
578     strncpy(MailPath, MailPathArg, sizeof(MailPath));
579   }else if (getenv("MAIL")) {
580     strncpy(MailPath, (char *)getenv("MAIL"), sizeof(MailPath));
581   }else {
582     if (STR_TAIL(MailPath) != '/') strncat(MailPath, "/", sizeof(MailPath));
583     strncat(MailPath, (char *)getenv("USER"), sizeof(MailPath));
584   }
585   if (Debug) fprintf(stderr, "MailPath '%s'\n", MailPath);
586 }
587 
588 Bool
CheckMail()589 CheckMail()
590 {
591   static int	mail_size = 0;
592   struct stat	f_stat;
593 
594   if (stat(MailPath, &f_stat) == 0) {
595     if (f_stat.st_size != mail_size && f_stat.st_size != 0) {
596       mail_size = f_stat.st_size;
597       if (Debug) fprintf(stderr, "mail arrived\n");
598       return (True);
599     }
600   }
601   return (False);
602 }
603 /* -- */
604 char	*Au;
605 int	Ausize = 0;
606 
607 void
ReadAudioFile()608 ReadAudioFile()
609 {
610   if (Audio == AUD_DEV || Audio == AUD_CMD) {
611     FILE	*fp = OpenData( AudioDataName, "r");
612 
613     strncpy(AudioDataPath, OpenDataName, sizeof(AudioDataPath));
614     if (Audio == AUD_DEV) {
615       CALLOC(Au, MAX_AUSIZE, sizeof(*Au));
616       Ausize = fread(&Au[0], 1, MAX_AUSIZE, fp);
617       if (Debug) fprintf( stderr, "Ausize = %d\n", Ausize );
618     }
619     fclose(fp);
620   }
621 }
622 
623 void
PlayAudioFile()624 PlayAudioFile()
625 {
626   int	pid;
627   if (Audio == AUD_BELL) {
628     if (ActionFlag == ACT_MAIL)	XBell(MyDisplay, 0);
629   }else if ((pid = fork()) == 0) {
630     signal(SIGALRM, SIG_IGN);
631     if (Audio == AUD_CMD) {
632       if (execlp(AudioCommand, AudioDataPath, AudioDataPath, NULL) == -1) {
633 	Error("cannot exec '%s %s'", AudioCommand, AudioDataPath);
634       }
635     }else if (Audio == AUD_DEV) {
636       FILE	*fpau = fopen(AudioDevice, "wb+");
637       if (fpau) {
638 	fwrite(&Au[0], 1, Ausize, fpau);	fflush(fpau); fclose(fpau);
639       }else {
640 	Error("cannot open file '%s'", AudioDevice);
641       }
642       FREE(Au);
643     }
644     _exit(0);
645   }else if (pid < 0) {
646     Error("cannot fork");
647   }else {
648     /* wait() in ResetChild() ^^; */
649   }
650 }
651 /* -- */
652 
653 int
SetMask(cell,xbm,width,height)654 SetMask(cell, xbm, width, height)
655      CELL	*cell;
656      unsigned char	*xbm;
657      unsigned int	width, height;
658 {
659   static unsigned char BITON[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0};
660   int	w = cell->width;
661   int	h = cell->height;
662   int	xs = cell->x;
663   int	ys = cell->y;
664   char	**yp = cell->pxl;
665   int	x, y, i;
666 
667   xbm += ((ys*width/8) + xs/8);
668   for (y = ys; y < ys+h; y++, yp++) {
669     unsigned char	*xbm_back = xbm;
670     char *xp = *yp;
671     for (x = xs; x < xs+w; x+=8) {
672       unsigned char	c = 0;
673       for (i = 0; i < 8; i++) {
674 	c |= (BITON[ (*xp != ' ') ? i : 8 ]);
675 	xp++;
676       }
677       *xbm++ = c;
678     }
679     xbm = xbm_back + (width/8);
680   }
681 }
682 
683 int
GetPointerPosition(win,x,y)684 GetPointerPosition(win, x, y)
685      Window	win;
686      int	*x, *y;
687 {
688   Window	root, child;
689   int	wx, wy;
690   unsigned int	key;
691 
692   return (XQueryPointer(MyDisplay, win, &root, &child, x, y, &wx, &wy, &key));
693 }
694 
695 int
GetPixelIndex(color,ncolors,c)696 GetPixelIndex(color, ncolors, c)
697      COLOR	*color;
698      int	ncolors;
699      char	*c;
700 {
701   int	i;
702   for (i = 0; i < ncolors; i++) {
703     if (color[i].c == *c) return (i);
704   }
705   return (-1);
706 }
707 
708 void
MakePixmap()709 MakePixmap()
710 {
711   XGCValues	GCValues;
712   char	*xbm = NULL;
713   int	xbm_size = ((WIDTH+7)/8)*HEIGHT;
714   int	i;
715 
716   CALLOC(xbm, xbm_size, sizeof(*xbm));
717 
718   GCValues.function   = GXcopy;
719   GCValues.fill_style = FillTiled;
720 
721   for (i = 0; i < NCELLS; i++) {
722     CELL	*clp = &Cell[i];
723     int	width = clp->width;
724     int	height = clp->height;
725     char **yp = clp->pxl;
726     int	x, y;
727 
728     clp->pixmap = XCreatePixmap(MyDisplay, MyWindow, width, height, MyDepth);
729 
730     for (y = 0; y < height; y++, yp++) {
731       char *xp = *yp;
732       for (x = 0; x < width; x++, xp++) {
733 	int	c = GetPixelIndex(*Color, NCOLORS, xp);
734 	if (c == -1) {
735 	  ErrorExit("invalid pixel char '%c'", *xp);
736 	}
737 	XDrawPoint(MyDisplay, clp->pixmap, (*Color + c)->GC, x, y);
738       }
739     }
740 
741 #ifdef	SHAPE
742     if (!NoShape) {
743       int	*mp = clp->mask_num, k;
744       for (k = 0; k < xbm_size; k++) xbm[k] = 0;
745       for (k = 0; k < clp->nmask; k++, mp++) {
746 	SetMask(&Cell[*mp], xbm, WIDTH, HEIGHT);
747       }
748       SetMask(clp, xbm, WIDTH, HEIGHT);
749       clp->mask = XCreateBitmapFromData(MyDisplay, MyWindow, xbm,
750 					WIDTH, HEIGHT);
751     }
752 #endif/*SHAPE*/
753   }
754   FREE(xbm);
755 }
756 
757 Bool
Draw(no)758 Draw(no)
759      int	no;
760 {
761   static int	no_back = -1;
762   Bool	flag = (no_back != no);
763   int	offset_x = 0, offset_y = 0;
764   static int	ptx_back = -1, pty_back = -1;
765 
766   if (UseWM) {
767     if (   ptx_back != Pattern[PatternNumber].x
768 	|| pty_back != Pattern[PatternNumber].y) {
769       ptx_back = Pattern[PatternNumber].x;
770       pty_back = Pattern[PatternNumber].y;
771       flag = True;
772     }
773     offset_x = ptx_back;
774     offset_y = pty_back + H_OFF;
775   }
776 
777   if (flag) {
778     CELL	*clp = &Cell[no];
779 
780 #ifdef	SHAPE
781     if (!NoShape) {
782       XShapeCombineMask(MyDisplay, MyWindow, ShapeBounding,
783 			offset_x, offset_y, clp->mask, ShapeSet);
784     }
785 #endif/*SHAPE*/
786 
787     XCopyArea(MyDisplay, clp->pixmap, MyWindow, (*Color)->GC,
788 	      0, 0, clp->width, clp->height,
789 	      offset_x + clp->x, offset_y + clp->y);
790     no_back = no;
791   }
792   return (flag);
793 }
794 
795 void
DrawPattern()796 DrawPattern()
797 {
798   static int	ptx_back = -1, pty_back = -1;
799   Bool	flush;
800   STATES	*sp = &States[State];
801 
802   if (State == IDLE) {
803     if (ActionFlag) {
804       if (Audio) PlayAudioFile();
805       ActionFlag = ACT_NONE;
806       State = ActionState;
807       PatternNumber = States[State].start;
808     }else if (PatternNumber > sp->end) {
809       State = sp->next_state;
810       PatternNumber = States[State].start;
811     }
812   }else {
813     if (PatternNumber > sp->end) {
814       ActionFlag = ACT_NONE;
815       State = sp->next_state;
816       PatternNumber = States[State].start;
817     }
818   }
819 
820   flush = Draw(Pattern[PatternNumber].num);
821 
822   if (!UseWM) {
823     if (ptx_back != Pattern[PatternNumber].x
824 	|| pty_back != Pattern[PatternNumber].y) {
825       ptx_back = Pattern[PatternNumber].x;
826       pty_back = Pattern[PatternNumber].y;
827       XMoveWindow(MyDisplay, MyWindow, Myx + ptx_back, Myy + pty_back);
828       flush = True;
829     }
830   }
831 
832   if (flush) XFlush(MyDisplay);
833 
834   pause();
835 
836   PatternNumber++;
837 }
838 
839 #define	N_CHILD	10
840 typedef	struct {
841   Window	window;
842   Window	child [N_CHILD];
843   Window	child2[N_CHILD];
844 }FOCUS;
845 
846 FOCUS	MyFocus     = {None, None, None};
847 FOCUS	MyFocusBack = {None, None, None};
848 FOCUS	MyFocusBack2= {None, None, None};
849 
850 Bool
ErrWindow(win)851 ErrWindow(win)
852      Window	win;
853 {
854   int	i;
855 
856   if (win == None) return (True);
857 
858   if (win == MyFocus.window) {
859     if (FocusDebug) fprintf(stderr, "<%x>\n", win);		return (False);
860   }else if (win == MyFocusBack.window) {
861     if (FocusDebug) fprintf(stderr, "b<%x>\n", win);		return (False);
862   }else if (win == MyFocusBack2.window) {
863     if (FocusDebug) fprintf(stderr, "bb<%x>\n", win);		return (False);
864   }
865   for (i = 0; i < N_CHILD; i++) {
866     if (win == MyFocus.child[i]) {
867       if (FocusDebug) fprintf(stderr, "child<%x>\n", win);	return (False);
868     }else if (win == MyFocus.child2[i]) {
869       if (FocusDebug) fprintf(stderr, "child2<%x>\n", win);	return (False);
870     }else if (win == MyFocusBack.child[i]) {
871       if (FocusDebug) fprintf(stderr, "bchild<%x>\n", win);	return (False);
872     }else if (win == MyFocusBack.child2[i]) {
873       if (FocusDebug) fprintf(stderr, "bchild2<%x>\n", win);	return (False);
874     }else if (win == MyFocusBack2.child[i]) {
875       if (FocusDebug) fprintf(stderr, "bbchild<%x>\n", win);	return (False);
876     }else if (win == MyFocusBack2.child2[i]) {
877       if (FocusDebug) fprintf(stderr, "bbchild2<%x>\n",win);	return (False);
878     }
879   }
880   return (True);
881 }
882 
883 int
MyErrorHandler(display,myerr)884 MyErrorHandler(display, myerr)
885      Display		*display;
886      XErrorEvent	*myerr;
887 {
888   if (ErrWindow(myerr->resourceid)) {
889     char	msg[256];
890 
891     XGetErrorText(display, myerr->error_code, msg, sizeof(msg));
892     Error("Error code %s", msg);
893     Error("Resouce id %x", myerr->resourceid);
894     exit(1);
895   }
896   MyFocusBack.window = None;
897   return (0);
898 }
899 
900 KeySym
GetKeysym(key)901 GetKeysym(key)
902      char	*key;
903 {
904   KeySym	sym = XStringToKeysym(key);
905 
906   if (sym == NoSymbol)	ErrorExit("not found keysym '%s'", key);
907   return (sym);
908 }
909 
910 Bool
CheckEvent()911 CheckEvent()
912 {
913   static int	drag_x = -1, drag_y = -1;
914   XEvent	event;
915   Bool		flag = True;
916   int	ix = 0;
917 
918   while (XEventsQueued(MyDisplay, QueuedAfterReading) > 0) {
919     XNextEvent(MyDisplay, &event);
920     switch(event.type) {
921     case DestroyNotify:
922       if (event.xdestroywindow.window == MyFocusBack.window) {
923 	MyFocusBack.window = None;
924       }else {
925 	int	i;
926 	for (i = 0; i < N_CHILD; i++) {
927 	  if (event.xdestroywindow.window == MyFocusBack.child[i]) {
928 	    MyFocusBack.child[i] = None;
929 	    break;
930 	  }else if (event.xdestroywindow.window == MyFocusBack.child2[i]) {
931 	    MyFocusBack.child2[i] = None;
932 	    break;
933 	  }
934 	}
935       }
936       if (FocusDebug) {
937 	fprintf(stderr, "destory(%x)%s\n", event.xdestroywindow.window,
938 		(event.xdestroywindow.window==MyFocusBack.window) ? "-":"");
939       }
940       break;
941     case KeyPress:
942       if (FocusDebug) {
943 	fprintf(stderr, "win=%x, keycode=%d, keysym=%x\n",
944 		event.xkey.window, event.xkey.keycode,
945 		XKeycodeToKeysym(MyDisplay, event.xkey.keycode, ix) );
946       }
947       if (XKeycodeToKeysym(MyDisplay, event.xkey.keycode, ix) == ActionKeysym){
948 	ActionFlag = ACT_KEY;
949       }
950       break;
951     case ButtonPress:
952       if (event.xbutton.button == Button1) {
953 	drag_x = event.xbutton.x;
954 	drag_y = event.xbutton.y;
955       }else if (event.xbutton.button == Button2) {
956 	XMapRaised(MyDisplay, MyWindow);
957       }else {
958 	flag = False;
959       }
960       break;
961     case ButtonRelease:
962       drag_x = drag_y = -1;
963       break;
964     case MotionNotify:
965       if (drag_x >= 0 && drag_y >= 0) {
966 	while (XCheckWindowEvent(MyDisplay, MyWindow,
967 				 PointerMotionMask, &event)) {
968 	}
969 	GetPointerPosition(MyWindow, &Myx, &Myy);
970 	Myx -= drag_x;
971 	Myy -= drag_y;
972 	XMoveWindow(MyDisplay, MyWindow, Myx, Myy);
973       }
974       break;
975     case MappingNotify:
976       XRefreshKeyboardMapping((XMappingEvent*)&event);
977       ActionKeysym = GetKeysym(ActionKey);
978       break;
979 /**
980     case ConfigureNotify:
981       if (UseWM) {
982 	if (event.xconfigure.window == MyWindow && State == IDLE) {
983 	  Myx = event.xconfigure.x;
984 	  Myy = event.xconfigure.y;
985 	  if (Debug) fprintf(stderr, "%d %d %d\n",
986 			     Myx, Myy, event.xconfigure.send_event);
987 	}
988       }
989       break;
990 **/
991     default:
992       break;
993     }
994   }
995 
996   if (Rhime) {
997     static int	focus_check_count = 0;
998 
999     if (++focus_check_count >= FocusCheckCountMax) {
1000       int	rever_to;
1001 
1002       focus_check_count = 0;
1003 
1004       XGetInputFocus(MyDisplay, &MyFocus.window, &rever_to);
1005 
1006       if (   MyFocus.window != MyFocusBack.window
1007 	  && MyFocus.window != None
1008 	  && MyFocus.window != PointerRoot
1009 	  && MyFocus.window != MyWindow) {
1010 	Window	root, parent, *children, *children2;
1011 	unsigned int	nchildren, nchildren2;
1012 	unsigned int	i, j;
1013 
1014 	if (FocusDebug) fprintf(stderr, "<%x", MyFocus.window);
1015 	XSelectInput(MyDisplay, MyFocus.window, FOCUS_EVENT_MASK);
1016 
1017 	for ( i = 0; i < N_CHILD; i++) MyFocus.child [i] = None;
1018 	for ( j = 0; j < N_CHILD; j++) MyFocus.child2[j] = None;
1019 
1020 	if (XQueryTree(MyDisplay, MyFocus.window,
1021 		       &root, &parent, &children, &nchildren)) {
1022 	  for (i = j = 0; i < MIN(N_CHILD, nchildren); i++) {
1023 	    MyFocus.child[i] = children[i];
1024 	    XSelectInput(MyDisplay, children[i], FOCUS_EVENT_MASK);
1025 	    if (FocusDebug) fprintf(stderr, ",%x", children[i]);
1026 
1027 	    if (XQueryTree(MyDisplay, children[i],
1028 			   &root, &parent, &children2, &nchildren2)) {
1029 	      for ( ; j < MIN(N_CHILD, nchildren2); j++) {
1030 		MyFocus.child2[j] = children2[j];
1031 		XSelectInput(MyDisplay, children2[j], FOCUS_EVENT_MASK);
1032 		if (FocusDebug) fprintf(stderr, ";%x", children2[j]);
1033 	      }
1034 	      XFree(children2);
1035 	    }
1036 	  }
1037 	  XFree(children);
1038 	}
1039 	if (FocusDebug) fprintf(stderr, ">\n");
1040 
1041 	if (FocusDebug) fprintf(stderr, "(");
1042 	if (MyFocusBack.window != None) {
1043 	  XSelectInput(MyDisplay, MyFocusBack.window, 0);
1044 	  if (FocusDebug) fprintf(stderr, "%x", MyFocusBack.window);
1045 	}
1046 	for (i = 0; i < N_CHILD; i++) {
1047 	  if (MyFocusBack.child [i] != None) {
1048 	    XSelectInput(MyDisplay, MyFocusBack.child [i], 0);
1049 	    if (FocusDebug) fprintf(stderr, ",%x", MyFocusBack.child [i]);
1050 	  }
1051 	  if (MyFocusBack.child2[i] != None) {
1052 	    XSelectInput(MyDisplay, MyFocusBack.child2[i], 0);
1053 	    if (FocusDebug) fprintf(stderr, ";%x", MyFocusBack.child2[i]);
1054 	  }
1055 	}
1056 	if (FocusDebug) fprintf(stderr, ")\n");
1057 
1058 	MyFocusBack2.window = MyFocusBack.window;
1059 	MyFocusBack.window = MyFocus.window;
1060 	for (i = 0; i < N_CHILD; i++) {
1061 	  MyFocusBack2.child [i] = MyFocusBack.child [i];
1062 	  MyFocusBack2.child2[i] = MyFocusBack.child2[i];
1063 	  MyFocusBack.child [i] = MyFocus.child [i];
1064 	  MyFocusBack.child2[i] = MyFocus.child2[i];
1065 	}
1066       }
1067     }
1068   }
1069 
1070   if (Biff) {
1071     static int	mail_check_count = INT_MAX - 1;
1072     if (++mail_check_count >= MailCheckCountMax) {
1073       mail_check_count = 0;
1074       if (CheckMail()) ActionFlag = ACT_MAIL;
1075     }
1076   }
1077   return (flag);
1078 }
1079 
1080 void
Animation()1081 Animation()
1082 {
1083   struct itimerval	itime;
1084 
1085   timerclear(&itime.it_interval);
1086   timerclear(&itime.it_value);
1087 
1088   itime.it_interval.tv_usec = INTERVAL_TIME_MS*1000L;
1089   itime.it_value.tv_usec    = INTERVAL_TIME_MS*1000L;
1090 
1091   setitimer(ITIMER_REAL, &itime, 0);
1092 
1093   FocusCheckCountMax = FOCUS_CHECK_INTERVAL_TIME_MS / INTERVAL_TIME_MS;
1094   MailCheckCountMax  = MAIL_CHECK_INTERVAL_TIME_MS  / INTERVAL_TIME_MS;
1095   do {
1096     DrawPattern();
1097   } while (CheckEvent());
1098 }
1099 
1100 void
AllocColors()1101 AllocColors()
1102 {
1103   Colormap	colormap = DefaultColormap(MyDisplay, MyScreen);
1104   XColor	color;
1105   XGCValues	values;
1106   COLOR	*cp = *Color;
1107   int	i;
1108 
1109   for (i = 0; i < NCOLORS; i++, cp++) {
1110     char	*name = cp->name;
1111 
1112     if (Background && i == 0) name = Background;
1113 
1114     if (XParseColor(MyDisplay, colormap, name, &color)) {
1115       if (XAllocColor(MyDisplay, colormap, &color) == 0) {
1116 	ErrorExit("cannot allocate color '%s'", name);
1117       }
1118 
1119       values.foreground = color.pixel;
1120       cp->GC = XCreateGC(MyDisplay, MyWindow, GCForeground, &values);
1121     }else {
1122       ErrorExit("cannot parse color '%s'", name);
1123     }
1124   }
1125 }
1126 
1127 void
InitScreen()1128 InitScreen()
1129 {
1130   Window		root;
1131   XSizeHints		sizehints;
1132   XSetWindowAttributes	attributes;
1133   unsigned long		mask;
1134   int			eventbase, errorbase;
1135   unsigned long   black;
1136 
1137   if ((MyDisplay = XOpenDisplay(DisplayName)) == NULL) {
1138     if (!DisplayName || (DisplayName && *DisplayName == '\0')) {
1139       char	*p = (char *)getenv("DISPLAY");
1140       ErrorExit("cannot open display '%s'", (p ? p : "(null)"));
1141     }else {
1142       ErrorExit("cannot open display '%s'", DisplayName);
1143     }
1144   }
1145 
1146   ActionKeysym = GetKeysym(ActionKey);
1147 
1148 #ifdef	SHAPE
1149   if (!NoShape && !XShapeQueryExtension(MyDisplay, &eventbase, &errorbase)) {
1150     Error("Display not suported shape extension");
1151     NoShape = True;
1152   }
1153 #endif/*SHAPE*/
1154 
1155   MyScreen = DefaultScreen(MyDisplay);
1156   MyDepth  = DefaultDepth(MyDisplay, MyScreen);
1157   root     = RootWindow(MyDisplay, MyScreen);
1158 
1159   if (Geometry) {
1160     char	ge[256];
1161     sprintf(ge, "%dx%d+0+0", WIDTH, HEIGHT);
1162     if (XGeometry(MyDisplay, MyScreen, Geometry, ge, 1, 1, 1, 0, 0, &Myx, &Myy,
1163 		  &sizehints.width, &sizehints.height) & (XValue|YValue)
1164 	== 0) {
1165       Geometry = NULL;
1166     }
1167   }
1168   if (!Geometry) {
1169     GetPointerPosition(root, &Myx, &Myy);
1170     Myx -= (WIDTH /2);
1171     Myy -= (HEIGHT/2);
1172   }
1173   mask = CWSaveUnder | CWOverrideRedirect;
1174   attributes.save_under        = True;
1175   attributes.override_redirect = !UseWM;
1176 
1177   MyWindow = XCreateWindow(MyDisplay, root, Myx, Myy, WIDTH, HEIGHT + H_OFF,
1178 			   0, MyDepth, InputOutput, CopyFromParent,
1179 			   mask, &attributes);
1180 
1181   sizehints.flags = PMinSize | PMaxSize;
1182   sizehints.min_width  = sizehints.max_width  = WIDTH;
1183   sizehints.min_height = sizehints.max_height = HEIGHT + H_OFF;
1184 
1185   XSetStandardProperties(MyDisplay, MyWindow, ProgramName, ProgramName, None,
1186 			 NULL, 0, &sizehints);
1187 
1188 /*  black = BlackPixel(MyDisplay, MyScreen);
1189   XSetWindowBackgroundPixmap(MyDisplay, MyWindow, black); perfomance bad! */
1190   XSetWindowBackgroundPixmap(MyDisplay, MyWindow, None);
1191   AllocColors();
1192 
1193   XSelectInput(MyDisplay, MyWindow, EVENT_MASK);
1194   XSelectInput(MyDisplay, root, KeyPressMask);
1195 
1196   XFlush(MyDisplay);
1197 
1198   XSetErrorHandler(MyErrorHandler);
1199 }
1200 
1201 
1202 char *OptionsAre[] = {
1203   "-help              Print usage message and exit\n",
1204   "-display <host:n>  Specify the host and display number\n",
1205   "-geometry <+X+Y>   Specify the geometry\n",
1206   "-key <keyname>     Specify the keysym of the special key\n",
1207   "-nokey             Don't check for the special key\n",
1208 #ifdef	SHAPE
1209   "-noshape           Don't use shape extension\n",
1210 #endif/*SHAPE*/
1211   "-bg <color>        Specify the background color\n",
1212   "[-N | -B | -D]     Draw in normal, brighter, or darker colors\n",
1213   "-<statenumber>     Specify the action state\n",
1214   "-use_wm            Use window manager\n",
1215   "-audio <audiofile> Specify audio file\n",
1216   " [-audev <dev>|-aucmd <cmd>]\n",
1217   "                    Specify audio device or command\n",
1218   " -showaudio         the same as ``-aucmd showaudio''\n",
1219   "-biff              Enable biff feature\n",
1220   " -file <mailfile>   Specify the mail file\n",
1221   " -update <sec>      Specify the mail polling interval\n",
1222   " -nobell            Don't ring the bell when mails arrive\n",
1223   NULL,
1224 };
1225 
1226 void
PrintUsage()1227 PrintUsage()
1228 {
1229   char	**p = OptionsAre;
1230   fprintf(stderr, "%s", Copyright);
1231   fprintf(stderr, "usage: %s [<options>] [<filename.xhm>]\n", ProgramName);
1232   fprintf(stderr, "  options are:\n");
1233   while (*p) fprintf(stderr, "    %s", *p++);
1234   return;
1235 }
1236 
1237 #define	MissingArg(argv)	ErrorExit("missing argument to %s", (argv))
1238 #define	CheckArg(argc, argv)	do{if((argc)<= 0) MissingArg(argv);}while(0)
1239 
1240 void
GetOptions(argc,argv)1241 GetOptions(argc, argv)
1242      int	argc;
1243      char	**argv;
1244 {
1245   Bool	bell = True;
1246 
1247   ProgramName = *argv;
1248 
1249   while (--argc > 0) {
1250     argv++;
1251     if (strcmp(*argv, "-display") == 0) {
1252       CheckArg(--argc, argv);	DisplayName = *++argv;
1253     }else if (strcmp(*argv, "-geometry") == 0) {
1254       CheckArg(--argc, *argv);	Geometry = *++argv;
1255     }else if (strcmp(*argv, "-key") == 0) {
1256       CheckArg(--argc, *argv);	ActionKey = *++argv;
1257     }else if (strcmp(*argv, "-bg") == 0) {
1258       CheckArg(--argc, *argv);	Background = *++argv;
1259 #ifdef	SHAPE
1260     }else if (strcmp(*argv, "-noshape") == 0) {
1261       NoShape = True;
1262     }else if (strcmp(*argv, "-shape") == 0) {
1263       NoShape = False;
1264 #endif/*SHAPE*/
1265     }else if (strcmp(*argv, "-use_wm") == 0) {
1266       UseWM = True;	NoShape = True;
1267     }else if (strcmp(*argv, "-audio") == 0) {
1268       Audio = AUD_DEV;
1269       CheckArg(--argc, *argv);	AudioDataName = *++argv;
1270     }else if (strcmp(*argv, "-audev") == 0) {
1271       Audio = AUD_DEV;
1272       CheckArg(--argc, *argv);	AudioDevice = *++argv;
1273     }else if (strcmp(*argv, "-max_ausize") == 0) {
1274       CheckArg(--argc, *argv);	MAX_AUSIZE = atoi(*++argv);
1275     }else if (strcmp(*argv, "-showaudio") == 0) {
1276       Audio = AUD_CMD;
1277     }else if (strcmp(*argv, "-noshowaudio") == 0) {
1278       Audio = AUD_DEV;
1279     }else if (   strcmp(*argv, "-nokey" ) == 0
1280 	      || strcmp(*argv, "-nohime") == 0) {
1281       Rhime = False;
1282     }else if (   strcmp(*argv, "-aucmd"   ) == 0
1283 	      || strcmp(*argv, "-mscript" ) == 0) {
1284       Audio = AUD_CMD;
1285       CheckArg(--argc, *argv);	AudioCommand = *++argv;
1286     }else if (strcmp(*argv, "-biff") == 0) {
1287       Biff = True;
1288     }else if (strcmp(*argv, "-nobiff") == 0) {
1289       Biff = False;
1290     }else if (strcmp(*argv, "-nobell") == 0) {
1291       bell = False;
1292     }else if (   strcmp(*argv, "-update") == 0
1293 	      || strcmp(*argv, "-mtime" ) == 0) {
1294       Biff = True;
1295       CheckArg(--argc, *argv);
1296       MAIL_CHECK_INTERVAL_TIME_MS = atoi(*++argv) * 1000;
1297     }else if (   strcmp(*argv, "-file") == 0
1298 	      || strcmp(*argv, "-mail") == 0) {
1299       Biff = True;
1300       CheckArg(--argc, *argv);	MailPathArg = *++argv;
1301     }else if (strcmp(*argv, "-debug") == 0) {
1302       Debug = True;
1303     }else if (strcmp(*argv, "-focusdebug") == 0) {
1304       FocusDebug = True;
1305     }else if (strcmp(*argv, "-N") == 0) {
1306       Color = &ColorN;
1307     }else if (strcmp(*argv, "-B") == 0) {
1308       Color = &ColorB;
1309     }else if (strcmp(*argv, "-D") == 0) {
1310       Color = &ColorD;
1311     }else if (strcmp(*argv, "-") == 0 && argc == 1) {
1312       DataName = "-";
1313     }else if (strncmp(*argv, "-", 1) == 0) {
1314       if ('0' <= *(*argv + 1) && *(*argv + 1) <= '9') {
1315 	ActionState = atoi(*argv + 1);
1316       }else {
1317 	PrintUsage(ProgramName);
1318 	exit(0);
1319       }
1320     }else if (argc == 1) {
1321       DataName = *argv;
1322     }
1323   }
1324 
1325   if (Biff && bell && Audio == AUD_NONE) Audio = AUD_BELL;
1326 
1327   GetData(DataName);
1328 }
1329 
1330 void
ResetChild()1331 ResetChild()
1332 {
1333   int	stat;
1334   wait(&stat);
1335 #ifdef	NO_SIGACTION
1336 #if defined(SYSV) || defined(XSYSV_SIG)
1337   signal(SIGCHLD, ResetChild);
1338 #endif/*SYSV || XSYSV_SIG*/
1339 #endif/*NO_SIGACTION*/
1340   if (Debug) fprintf(stderr, "SIGCHLD caught\n");
1341 }
1342 
1343 void
ResetAlarm()1344 ResetAlarm()
1345 {
1346 #ifdef	NO_SIGACTION
1347 #if defined(SYSV) || defined(XSYSV_SIG)
1348   signal(SIGALRM, ResetAlarm);
1349 #endif/*SYSV || XSYSV_SIG*/
1350 #endif/*NO_SIGACTION*/
1351 }
1352 
1353 void
Exit()1354 Exit()
1355 {
1356   if (MyDisplay) {
1357     XDestroyWindow(MyDisplay, MyWindow);
1358     XCloseDisplay(MyDisplay);
1359   }
1360   exit(0);
1361 }
1362 
1363 int
main(argc,argv)1364 main(argc, argv)
1365      int	argc;
1366      char	*argv[];
1367 {
1368   GetOptions(argc, argv);
1369 
1370   InitScreen();
1371   MakePixmap();
1372 
1373   if (Biff) GetMailPath();
1374   if (Audio) ReadAudioFile();
1375 
1376 #ifdef	NO_SIGACTION
1377   signal(SIGALRM, ResetAlarm);
1378   signal(SIGCHLD, ResetChild);
1379 #else
1380   {
1381     static struct sigaction alrm, chld;
1382     alrm.sa_handler = ResetAlarm;
1383     chld.sa_handler = ResetChild;
1384     sigaction(SIGALRM, &alrm, NULL);
1385     sigaction(SIGCHLD, &chld, NULL);
1386   }
1387 #endif/*NO_SIGACTION*/
1388 
1389   signal(SIGINT,  Exit);
1390   signal(SIGTERM, Exit);
1391   signal(SIGQUIT, Exit);
1392 
1393   XMapWindow(MyDisplay, MyWindow);
1394   Animation();
1395 
1396   Exit();
1397 }
1398