1 /*                             -*- Mode: C++-C -*-
2  *
3  *		 Copyright 1994 Christopher B. Liebman
4  *
5  *     Permission to use, copy, modify, distribute, and sell this software
6  *     and its documentation for any purpose is hereby granted without fee,
7  *     provided that the above copyright notice appear in all copies and that
8  *     both that copyright notice and this permission notice appear in
9  *     supporting documentation, and that the name Christopher B. Liebman not
10  *     be used in advertising or publicity pertaining to distribution of this
11  *     software without specific, written prior permission.
12  *
13  *    THIS SOFTWARE IS PROVIDED `AS-IS'.  CHRISTOPHER B. LIEBMAN, DISCLAIMS
14  *    ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT
15  *    LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16  *    PARTICULAR PURPOSE, OR NONINFRINGEMENT.  IN NO EVENT SHALL CHRISTOPHER
17  *    B. LIEBMAN, BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING SPECIAL,
18  *    INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS OF USE, DATA, OR
19  *    PROFITS, EVEN IF ADVISED OF THE POSSIBILITY THEREOF, AND REGARDLESS OF
20  *    WHETHER IN AN ACTION IN CONTRACT, TORT OR NEGLIGENCE, ARISING OUT OF
21  *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Author          : Chris Liebman
24  * Created On      : Tue Jan 11 14:11:30 1994
25  * Last Modified By: Chris Liebman
26  * Last Modified On: Mon Mar  7 16:56:37 1994
27  * Update Count    : 130
28  * Status          : Released
29  *
30  * HISTORY
31  * 13-Feb-1994		Chris Liebman
32  *    Last Modified: Sun Feb 13 00:40:08 1994 #111 (Chris Liebman)
33  *    Added new command support and support to annotate mail items.
34  *
35  * 8-Feb-1994		Chris Liebman
36  *    Last Modified: Sat Feb  5 22:03:01 1994 #82 (Chris Liebman)
37  *    Added new command line options.  Added new Tiled widget.
38  *
39  * 2-Feb-1994		Chris Liebman
40  *    Last Modified: Tue Feb  1 14:41:17 1994 #72 (Chris Liebman)
41  *    Added annotation support.
42  *
43  * 31-Jan-1994		Chris Liebman
44  *    Last Modified: Sun Jan 30 02:05:43 1994 #67 (Chris Liebman)
45  *    New search code.
46  *    Command line options.
47  *    New resources.
48  *    List Commad support.
49  *
50  * 24-Jan-1994		Chris Liebman
51  *    Last Modified: Sun Jan 23 18:46:43 1994 #18 (Chris Liebman)
52  *    Added new bindings.
53  *
54  * 20-Jan-1994		Chris Liebman
55  *    Last Modified: Tue Jan 18 17:14:31 1994 #9 (Chris Liebman)
56  *    Added new closeness resource and some cleanups.
57  *
58  * 14-Jan-1994		Chris Liebman
59  *    Last Modified: Fri Jan 14 09:59:56 1994 #4 (Chris Liebman)
60  *    Added ignoreMessageBindings resource.
61  *
62  * PURPOSE
63  * 	This is xfaces initialization.
64 */
65 
66 #ifndef lint
67 static char *RCSid = "$Id: main.c,v 1.29 1994/03/08 02:19:48 liebman Exp $";
68 #endif
69 
70 #include "faces.h"
71 #include <pwd.h>
72 #ifdef __STDC__
73 #include <stdlib.h>
74 #endif
75 
76 /*
77  * The resources.
78 */
79 
80 FacesResourcesRec TheFacesResources;
81 
82 /*
83  * This is ugly but it will remove some error messages when
84  * some options are not compiled in.
85 */
86 
87 #ifdef SHAPE
88 #ifdef XPM
89 #define	IMAGE_TYPES	"xpm-shape:xpm:xbm-shape:xbm"
90 #else /* XPM*/
91 #define	IMAGE_TYPES	"xbm-shape:xbm"
92 #endif /* XPM */
93 #else /* SHAPE */
94 #ifdef XPM
95 #define	IMAGE_TYPES	"xpm:xbm"
96 #else /* XPM*/
97 #define	IMAGE_TYPES	"xbm"
98 #endif /* XPM*/
99 #endif /* SHAPE */
100 
101 #ifdef XFACE
102 #define	IMAGE_SEARCH	"beforeImage\nresource\nfacedb\nx-face\nafterImage"
103 #else /* XFACE */
104 #define	IMAGE_SEARCH	"beforeImage\nresource\nfacedb\nafterImage"
105 #endif /* XFACE */
106 #define	SOUND_SEARCH	"beforeSound\nresource\nfacedb\nafterSound"
107 #define	COMMAND_SEARCH	"beforeCommand\nresource\nafterCommand"
108 
109 /*
110  * Here is a description of our resources for the toolkit.
111 */
112 
113 static Boolean defFalse = False;
114 static Boolean defTrue = True;
115 #define XtNvolume "volume"		/* Int: volume for bell */
116 #define XtCVolume "Volume"
117 
118 #define	offset(field)	XtOffset(FacesResources, field)
119 static XtResource FacesResourcesList[] =
120 {
121     {
122 	"spoolFile", "SpoolFile", XtRString, sizeof(String),
123 	offset(spool_file), XtRString, NULL
124     },
125     {
126 	"spoolDir", "SpoolDir", XtRString, sizeof(String),
127 	offset(spool_dir), XtRString, "/usr/spool/mail"
128     },
129     {
130 	"popHost", "PopHost", XtRString, sizeof(String),
131 	offset(pop_host), XtRString, NULL
132     },
133     {
134 	"popAuthFile", "PopAuthFile", XtRString, sizeof(String),
135 	offset(pop_auth_file), XtRString, NULL
136     },
137     {
138 	"popPort", "PopPort", XtRInt, sizeof(int),
139 	offset(pop_port), XtRString, "110"
140     },
141     {
142 	"listCommand", "Command", XtRString, sizeof(String),
143 	offset(list_command), XtRString, NULL
144     },
145     {
146 	"imagePath", "Path", XtRString, sizeof(String),
147 	offset(image_path), XtRString, "/usr/images"
148     },
149     {
150 	"soundPath", "Path", XtRString, sizeof(String),
151 	offset(sound_path), XtRString, "/usr/sounds"
152     },
153     {
154 	"facedbPath", "Path", XtRString, sizeof(String),
155 	offset(facedb_path), XtRString, "/usr/local/faces"
156     },
157     {
158 	"machine", "Path", XtRString, sizeof(String),
159 	offset(machine), XtRString, "machine.tab"
160     },
161     {
162 	"people", "Path", XtRString, sizeof(String),
163 	offset(people), XtRString, "people.tab"
164     },
165     {
166 	"update", "Update", XtRInt, sizeof(int),
167 	offset(update), XtRString, "60"
168     },
169     {
170         XtNvolume, XtCVolume, XtRInt, sizeof(int),
171 	offset(volume), XtRString, "33"
172     },
173     {
174 	"fromField",  "FromField", XtRString, sizeof(String),
175 	offset(from_field), XtRString, "From "
176     },
177     {
178 	"noMailImage", "Image", XtRString, sizeof(String),
179 	offset(no_mail_image), XtRString, "nomail"
180     },
181     {
182 	"noMailSound", "Sound", XtRString, sizeof(String),
183 	offset(no_mail_sound), XtRString, NULL
184     },
185     {
186 	"keepOrder", "KeepOrder", XtRBoolean, sizeof(Boolean),
187 	offset(keep_order), XtRBoolean, (caddr_t) &defFalse
188     },
189     {
190 	"compressImages", "CompressImages", XtRBoolean, sizeof(Boolean),
191 	offset(compress_images), XtRBoolean, (caddr_t) &defTrue
192     },
193     {
194 	"useSound", "UseSound", XtRBoolean, sizeof(Boolean),
195 	offset(use_sound), XtRBoolean, (caddr_t) &defTrue
196     },
197     {
198 	"useShape", "UseShape", XtRBoolean, sizeof(Boolean),
199 	offset(use_shape), XtRBoolean, (caddr_t) &defTrue
200     },
201     {
202 	"useCommands", "UseCommands", XtRBoolean, sizeof(Boolean),
203 	offset(use_commands), XtRBoolean, (caddr_t) &defFalse
204     },
205     {
206 	"useContentLength", "UseContentLength", XtRBoolean, sizeof(Boolean),
207 	offset(use_content_length), XtRBoolean, (caddr_t) &defFalse
208     },
209     {
210 	"shapeBorders", "ShapeBorders", XtRBoolean, sizeof(Boolean),
211 	offset(shape_borders), XtRBoolean, (caddr_t) &defTrue
212     },
213     {
214 	"shapeInternal", "ShapeInternal", XtRBoolean, sizeof(Boolean),
215 	offset(shape_internal), XtRBoolean, (caddr_t) &defTrue
216     },
217     {
218 	"closeness", "Closeness", XtRInt, sizeof(int),
219 	offset(closeness), XtRString, (caddr_t) "40000"
220     },
221     {
222 	"imageTypes", "ImageTypes", XtRString, sizeof(String),
223 	offset(image_types_str), XtRString, IMAGE_TYPES
224     },
225     {
226 	"imageSearch", "Search", XtRString, sizeof(String),
227 	offset(image_search_str), XtRString, IMAGE_SEARCH
228     },
229     {
230 	"soundSearch", "Search", XtRString, sizeof(String),
231 	offset(sound_search_str), XtRString, SOUND_SEARCH
232     },
233     {
234 	"commandSearch", "Search", XtRString, sizeof(String),
235 	offset(command_search_str), XtRString, COMMAND_SEARCH
236     },
237     {
238 	"ignoreMessageBindings", "IgnoreBindings", XtRString, sizeof(String),
239 	offset(ignore_message_bindings_str), XtRString, NULL
240     },
241     {
242 	"beforeImageBindings", "ImageBindings", XtRString, sizeof(String),
243 	offset(before_image_bindings_str), XtRString, NULL
244     },
245     {
246 	"afterImageBindings", "ImageBindings", XtRString, sizeof(String),
247 	offset(after_image_bindings_str), XtRString, NULL
248     },
249     {
250 	"beforeSoundBindings", "SoundBindings", XtRString, sizeof(String),
251 	offset(before_sound_bindings_str), XtRString, NULL
252     },
253     {
254 	"afterSoundBindings", "SoundBindings", XtRString, sizeof(String),
255 	offset(after_sound_bindings_str), XtRString, NULL
256     },
257     {
258 	"beforeCommandBindings", "CommandBindings", XtRString, sizeof(String),
259 	offset(before_command_bindings_str), XtRString, NULL
260     },
261     {
262 	"afterCommandBindings", "CommandBindings", XtRString, sizeof(String),
263 	offset(after_command_bindings_str), XtRString, NULL
264     },
265     {
266 	"annotationCount", "Count", XtRInt, sizeof(int),
267         offset(annotation_count), XtRString, "1"
268     },
269     {
270 	"unknownAnnotationCount", "Count", XtRInt, sizeof(int),
271         offset(unknown_annotation_count), XtRString, "1"
272     },
273     {
274 	"annotationAbove", "AnnotationAbove", XtRBoolean, sizeof(Boolean),
275 	offset(annotation_above), XtRString, "False"
276     },
277     {
278 	"background", "Background", XtRPixel, sizeof(Pixel),
279 	offset(background), XtRString, XtDefaultBackground
280     },
281     {
282 	"shapeExtra", "Shape", XtRBoolean, sizeof(Boolean),
283 	offset(shape_extra), XtRString, "True"
284     },
285     {
286 	"pathByChdir", "PathByChdir", XtRBoolean, sizeof(Boolean),
287 	offset(path_by_chdir), XtRString, "True"
288     },
289     {
290 	"lookupHostname", "LookupHostname", XtRBoolean, sizeof(Boolean),
291 	offset(lookup_hostname), XtRString, "False"
292     },
293 };
294 
295 #undef offset
296 
297 static XrmOptionDescRec options[] =
298 {
299     {
300 	"-c", "frame.maxWidth", XrmoptionSepArg, NULL
301     },
302     {
303 	"-e", "listCommand", XrmoptionSepArg, NULL
304     },
305     {
306 	"-f", "facedbPath", XrmoptionSepArg, NULL
307     },
308     {
309 	"-h", "frame.tileHeight",  XrmoptionSepArg, NULL
310     },
311     {
312 	"-p", "update", XrmoptionSepArg, NULL
313     },
314     {
315 	"-s", "spoolFile", XrmoptionSepArg, NULL
316     },
317     {
318 	"-w", "frame.tileWidth",  XrmoptionSepArg, NULL
319     },
320     {
321 	"-C", "compressImages", XrmoptionNoArg, "False"
322     },
323     {
324 	"-K", "keepOrder", XrmoptionNoArg, "True"
325     },
326     {
327 	"-S", "shapeExtra", XrmoptionNoArg, "False"
328     },
329     {
330 	"-pop", "popHost", XrmoptionSepArg, NULL
331     }
332 };
333 
334 
335 static Atom wm_delete_window;
336 
337 static void
quit(w,event,params,num_params)338 quit (w, event, params, num_params)
339 Widget w;
340 XEvent *event;
341 String *params;
342 Cardinal *num_params;
343 {
344     if (event->type == ClientMessage &&
345         event->xclient.data.l[0] != wm_delete_window)
346     {
347         XBell (XtDisplay(w), 0);
348         return;
349     }
350 
351 
352     /*
353      * First suspend layout.  Then cleanup.
354     */
355 
356     XtVaSetValues(TheFrame, XtNlayout, False, NULL);
357 
358     MailBoxClear();
359     MailBoxClean();
360 
361     XCloseDisplay (XtDisplay(w));
362     exit (0);
363 }
364 
365 static XtActionsRec xfaces_actions[] =
366 {
367     { "quit",	quit },
368 };
369 
370 /*
371  * Here are the main widgets.
372 */
373 
374 Widget TheTopLevel;		       /* The top level shell widget. */
375 Widget TheFrame;		       /* A frame to hold the faces. */
376 
377 FaceImage	*NoMailImage = NULL;
378 FaceSound	*NoMailSound = NULL;
379 
380 void
CheckMailNow()381 CheckMailNow()
382 {
383     /*
384      * First suspend layout.
385     */
386 
387     XtVaSetValues(TheFrame, XtNlayout, False, NULL);
388 
389     /*
390      *   Wipe the current face display list.
391     */
392 
393     MailBoxClear();
394 
395     /*
396      * Process items.
397     */
398 
399 #ifdef POP
400     if (TheFacesResources.pop_host)
401     {
402 	PopCheck();
403     }
404     else
405 #endif
406     if (TheFacesResources.list_command)
407     {
408 	CmdCheck();
409     }
410     else
411     {
412 	MailCheck();
413     }
414 
415     /*
416      *    Build the FaceDisplay list from the item list.
417     */
418 
419     MailBoxClean();
420 
421     /*
422      * Now resume layout.
423     */
424 
425     XtVaSetValues(TheFrame, XtNlayout, True, NULL);
426 
427     /*
428      *    Shape the window.
429     */
430 
431 #ifdef SHAPE
432     FaceShapeCreate();
433 #endif
434 
435 
436 }
437 
438 static void StartTimer();
439 
440 /*
441  * Check for changes to the mail spool file and kick the
442  * timer again.
443 */
444 
445 /* ARGSUSED */
446 static void
CheckMail(data,id)447 CheckMail( data, id )
448 caddr_t data;
449 XtIntervalId *id;
450 {
451 
452     CheckMailNow();
453 
454     /*
455      * Restart the timer.
456     */
457 
458     StartTimer(TheFacesResources.update);
459 
460     return;
461 }
462 
463 static void
StartTimer(secs)464 StartTimer(secs)
465 int secs;
466 {
467     (void) XtAddTimeOut((unsigned long) secs * 1000,
468 			CheckMail,
469                         (caddr_t) NULL );
470 }
471 
472 /*
473  * Here is the main routine.
474 */
475 
476 int
main(argc,argv)477 main(argc, argv)
478 int argc;
479 char *argv[];
480 {
481     char *name;
482     char *home;
483     struct passwd *pw;
484     FacesResources	fr = &TheFacesResources;
485 
486     /*
487      * Create the top level widget.
488     */
489 
490     TheTopLevel = XtInitialize(NULL, XFACES_CLASS,
491 			       options, XtNumber(options),
492 			       &argc, argv);
493 
494     /*
495      * Load any application resources.
496     */
497 
498     XtGetApplicationResources( TheTopLevel,
499                               fr,
500                               FacesResourcesList,
501                               XtNumber(FacesResourcesList),
502 			      NULL,
503                               0 );
504 
505     /*
506      * This is a hack so that f.delete will do something useful in this
507      * single-window application.
508     */
509 
510     XtAppAddActions (XtWidgetToApplicationContext(TheTopLevel),
511 		     xfaces_actions, XtNumber(xfaces_actions));
512 
513     XtOverrideTranslations(TheTopLevel,
514 		    XtParseTranslationTable ("<Message>WM_PROTOCOLS: quit()"));
515 
516     /*
517      * If the spool file is null then create one from the
518      * user name.
519     */
520 
521     if (fr->spool_file == NULL)
522     {
523 	if ((name = getlogin()) == NULL)
524 	{
525 	    pw = getpwuid(getuid());
526 	    if (pw != NULL || pw->pw_name != NULL)
527 	    {
528 		name = pw->pw_name;
529 	    }
530 	    else
531 	    {
532 		name = "nobody";
533 	    }
534 	    endpwent();
535 	}
536 
537 	fr->spool_file = XtMalloc(strlen(fr->spool_dir)+ strlen(name) + 2);
538 	(void) sprintf(fr->spool_file, "%s/%s", fr->spool_dir, name);
539     }
540 
541     if (fr->pop_auth_file == NULL)
542     {
543 	home = getenv("HOME");
544 	if (home == NULL)
545 	{
546 	    home = "/tmp";
547 	}
548 
549 	fr->pop_auth_file = XtMalloc(strlen(home) + 30);
550 	sprintf(fr->pop_auth_file, "%s/.popauth", home);
551     }
552 
553     /*
554      *   Initialize the image types.
555     */
556 
557     FaceImageXbmInit();
558 #ifdef XPM
559     FaceImageXpmInit();
560 #endif
561 #ifdef IKON
562     FaceImageIkonInit();
563 #endif
564 
565     /*
566      * Initialize the search types.
567     */
568 
569     FaceSearchBindingInit();
570     FaceSearchFacedbInit();
571     FaceSearchResourceInit();
572     FaceSearchUserHostInit();
573 #ifdef XFACE
574     FaceSearchXFaceInit();
575 #endif
576 
577     /*
578      * Parse up the image/sound paths.
579     */
580 
581     fr->image_path_str  = XtNewString(fr->image_path);
582     fr->sound_path_str  = XtNewString(fr->sound_path);
583     fr->facedb_path_str = XtNewString(fr->facedb_path);
584 
585     fr->image_paths  = PathParse(fr->image_path_str);
586     fr->sound_paths  = PathParse(fr->sound_path_str);
587     fr->facedb_paths = PathParse(fr->facedb_path_str);
588 
589     /*
590      *   Parse the image types.
591     */
592 
593     fr->image_types_str = XtNewString(fr->image_types_str);
594     fr->image_types = FaceImageTypeListParse(fr->image_types_str);
595 
596     /*
597      *    Create binding lists.
598     */
599 
600     fr->ignore_message_bindings =FaceBindingParse(fr->ignore_message_bindings_str, 0, 0);
601     fr->before_image_bindings = FaceBindingParse(fr->before_image_bindings_str, 1, 1);
602     fr->after_image_bindings = FaceBindingParse(fr->after_image_bindings_str, 1, 1);
603     fr->before_sound_bindings = FaceBindingParse(fr->before_sound_bindings_str, 1,1 );
604     fr->after_sound_bindings =FaceBindingParse(fr->after_sound_bindings_str, 1, 1);
605     /* fr->command_bindings = FaceBindingParse(fr->command_bindings_str, 1, 0); */
606 
607     /*
608      * Parse the search instructions.
609     */
610 
611     fr->image_search_str = XtNewString(fr->image_search_str);
612     fr->image_search = FaceSearchParse(fr->image_search_str, FormatImage);
613     fr->sound_search_str = XtNewString(fr->sound_search_str);
614     fr->sound_search = FaceSearchParse(fr->sound_search_str, FormatAudio);
615     fr->command_search_str = XtNewString(fr->command_search_str);
616     fr->command_search = FaceSearchParse(fr->command_search_str, FormatCommand);
617 
618     /*
619      * Now we create a box to keep our faces in.
620     */
621 
622     TheFrame = XtVaCreateManagedWidget("frame", tiledWidgetClass,
623 				       TheTopLevel, NULL);
624 
625     /*
626      * Initialize the face list.
627     */
628 
629 #ifdef SOUND
630     FaceSoundInit();
631 #endif /* SOUND */
632     FaceActionsInit();
633     FaceDisplayInit();
634     FaceAnnotateInit();
635     MailItemInit();
636 
637     XtRealizeWidget(TheTopLevel);
638 
639     wm_delete_window = XInternAtom (XtDisplay(TheTopLevel),
640 				    "WM_DELETE_WINDOW",
641                                     False);
642 
643     (void) XSetWMProtocols (XtDisplay(TheTopLevel), XtWindow(TheTopLevel),
644                             &wm_delete_window, 1);
645 
646     /*
647      * Set the initial shape.
648     */
649 
650 #ifdef SHAPE
651     FaceShapeCreate();
652 #endif
653 
654     /*
655      * Kick off the timer. (we start the timer with one second so that the
656      * the shape stuff will get flushed first.
657     */
658 
659     StartTimer(1);
660 
661     /*
662      * Ok, we are all set up!
663     */
664 
665     XtMainLoop();
666 
667     return 0;
668 }
669 
670 void
regerror(s)671 regerror(s)
672 String	s;
673 {
674     fprintf(stderr, "regerror: %s\n", s);
675     abort();
676 }
677