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 17:49:59 1994
27  * Update Count    : 142
28  * Status          : Released
29  *
30  * HISTORY
31  * 6-Mar-1994		Chris Liebman
32  *    Last Modified: Sun Mar  6 22:35:49 1994 #122 (Chris Liebman)
33  *    Added customization for mail annotations.
34  *
35  * 13-Feb-1994		Chris Liebman
36  *    Last Modified: Sat Feb 12 23:17:13 1994 #51 (Chris Liebman)
37  *    Added new mail annotation.
38  *
39  * 2-Feb-1994		Chris Liebman
40  *    Last Modified: Mon Jan 31 23:13:16 1994 #34 (Chris Liebman)
41  *    Added annotation support.  This is only hooked up for scripts
42  *    currently.
43  *
44  * 31-Jan-1994		Chris Liebman
45  *    Last Modified: Sat Jan 29 20:40:41 1994 #33 (Chris Liebman)
46  *    Added new search support and a function to create an item that
47  *    has no headers.
48  *
49  * 24-Jan-1994		Chris Liebman
50  *    Last Modified: Sun Jan 23 14:04:47 1994 #28 (Chris Liebman)
51  *    Moved all of the sound / image searching to other files.
52  *
53  * 20-Jan-1994		Chris Liebman
54  *    Last Modified: Tue Jan 18 14:38:39 1994 #22 (Chris Liebman)
55  *    Added new header parsing and bindings.
56  *
57  * 14-Jan-1994		Chris Liebman
58  *    Last Modified: Fri Jan 14 10:42:41 1994 #7 (Chris Liebman)
59  *    Added new MailItemIgnore() function.
60  *    MailItemCreate() now ignores items for which MailItemIgnore()
61  *    returns true.
62  *    Search the status header with bindings.
63  *
64  * PURPOSE
65  * 	Routines to manage the list of mail items.
66 */
67 
68 #ifndef lint
69 static char *RCSid = "$Id: mail_items.c,v 1.20 1994/03/08 15:05:57 liebman Exp $";
70 #endif
71 
72 #include "faces.h"
73 #ifdef LOOKUP_HOSTNAME
74 #include <netdb.h>
75 #endif
76 
77 /*
78  * The list of mail items from mail box.
79 */
80 
81 MailItem	*TheMailItems;
82 MailItem	*TheMailItemsTail;
83 
84 /*
85  *
86 */
87 
88 typedef enum mail_annotation_types
89 {
90     MailAnnotateNone,
91     MailAnnotateCount,
92     MailAnnotateUser,
93     MailAnnotateHost,
94     MailAnnotateUserHost,
95     MailAnnotateHeader
96 } MailAnnotationType;
97 
98 typedef struct mail_annotation
99 {
100     MailAnnotationType	type;
101     char*		header;
102 } MailAnnotation;
103 
104 static MailAnnotation*	mailAnnotations;
105 static int		annotationCount;
106 static MailAnnotation*	unknownMailAnnotations;
107 static int		unknownAnnotationCount;
108 
109 static void
MailItemAnnotate(item,annotations)110 MailItemAnnotate(item, annotations)
111 MailItem*	item;
112 char**		annotations;
113 {
114     int 		i;
115     char		buffer[30];
116     MailHeader*		header;
117     int			count;
118     MailAnnotation*	annos;
119     char*		p;
120 
121     if (item->unknown)
122     {
123 	count = unknownAnnotationCount;
124 	annos = unknownMailAnnotations;
125 #ifdef ITEM_DEBUG
126 	fprintf(stderr, "MailItemAnnotate(): using unknown annotations.\n");
127 #endif
128     }
129     else
130     {
131 	count = annotationCount;
132 	annos = mailAnnotations;
133 #ifdef ITEM_DEBUG
134 	fprintf(stderr, "MailItemAnnotate(): using known annotations.\n");
135 #endif
136     }
137 
138     if (item->annotations != NULL)
139     {
140 	for (i = 0; item->annotations[i] != NULL; ++i)
141 	{
142 	    XtFree(item->annotations[i]);
143 	}
144 
145 	XtFree((char*)item->annotations);
146 	item->annotations = NULL;
147     }
148 
149     if (item->face == NULL)
150     {
151 	return;
152     }
153 
154     if (annotations == NULL)
155     {
156 	item->annotations = (char**)XtCalloc(count + 1, sizeof(char*));
157 
158 	for(i = 0; i < count; ++i)
159 	{
160 	    if (item->use_label == (i+1))
161 	    {
162 		item->annotations[i] = XtNewString(item->label);
163 	    }
164 	    else
165 	    {
166 		switch(annos[i].type)
167 		{
168 		  case MailAnnotateNone:
169 		    break;
170 
171 		  case MailAnnotateCount:
172 		    sprintf(buffer, "%d", item->face->count);
173 		    item->annotations[i] = XtNewString(buffer);
174 		    break;
175 
176 		  case MailAnnotateUser:
177 		    item->annotations[i] = XtNewString(item->user);
178 		    break;
179 
180 		  case MailAnnotateHost:
181 		    item->annotations[i] = XtNewString(item->host);
182 		    break;
183 
184 		  case MailAnnotateUserHost:
185 		    item->annotations[i] = XtMalloc(strlen(item->user) +
186 						    strlen(item->host) + 2);
187 		    sprintf(item->annotations[i], "%s@%s", item->user, item->host);
188 		    break;
189 
190 		  case MailAnnotateHeader:
191 		    header = MailHeaderFind(annos[i].header, item->headers);
192 		    if ((header != NULL) && (header->value != NULL))
193 		    {
194 			p = SkipChars(header->value, " \t");
195 			item->annotations[i] = XtNewString(p);
196 		    }
197 		    break;
198 
199 		  default:
200 		    fprintf(stderr, "Bad MailAnnotationType: %d\n",
201 			    annos[i].type);
202 		    break;
203 		}
204 	    }
205 
206 	    if (item->annotations[i] == NULL)
207 	    {
208 		item->annotations[i] = XtMalloc(1);
209 		*(item->annotations[i]) = '\0';
210 	    }
211 
212 #ifdef ITEM_DEBUG
213 	    fprintf(stderr, "item->annotation[%d]: <%s>\n",
214 		    i, item->annotations[i]);
215 #endif
216 	}
217     }
218     else
219     {
220 	/*
221 	 * Count annotations.
222 	*/
223 
224 	for(i = 0; annotations[i] != NULL; ++i);
225 
226 	/*
227 	 * Copy annotations.
228 	*/
229 
230 	item->annotations = (char**)XtCalloc(i+1, sizeof(char*));
231 
232 	for(i = 0; annotations[i] != NULL; ++i)
233 	{
234 	    item->annotations[i] = XtNewString(annotations[i]);
235 	}
236 
237 	item->annotations[i] = NULL;
238     }
239 }
240 
241 static void
MailItemFree(item)242 MailItemFree(item)
243 MailItem	*item;
244 {
245     if (item->next != NULL)
246     {
247 	item->next->prev = item->prev;
248     }
249 
250     if (item->prev != NULL)
251     {
252 	item->prev->next = item->next;
253     }
254 
255     if (TheMailItems == item)
256     {
257 	TheMailItems = item->next;
258     }
259 
260     if (TheMailItemsTail == item)
261     {
262 	TheMailItemsTail = item->prev;
263     }
264 
265     XtFree(item->user);
266     XtFree(item->host);
267     XtFree(item->realhost);
268     XtFree(item->label);
269     item->user  = NULL;
270     item->host  = NULL;
271     item->realhost  = NULL;
272     item->label = NULL;
273 
274     /*
275      * Free mail headers.
276     */
277 
278     MailHeaderListFree(item->headers);
279     item->headers = NULL;
280 
281     /*
282      * Free annotations.
283     */
284 
285     item->face = NULL;
286     MailItemAnnotate(item, NULL);
287 
288     FaceImageFree(item->image);
289     item->image = NULL;
290 
291 #ifdef SOUND
292     FaceSoundFree(item->sound);
293 #endif /* SOUND */
294     item->sound = NULL;
295 
296     FaceCommandFree(item->command);
297     item->command = NULL;
298 
299     XtFree((void *)item);
300 }
301 
302 /*
303  *    Use the ignoreMessage expression to see if this message should be
304  * ignored.
305 */
306 
307 static int
MailItemIgnore(item)308 MailItemIgnore(item)
309 MailItem	*item;
310 {
311     FaceBinding	*binding;
312 
313     binding = FaceBindingCheck(item->headers,
314 			       TheFacesResources.ignore_message_bindings);
315 
316     if (binding != NULL)
317     {
318 	return 1;
319     }
320 
321     return(0);
322 }
323 
324 
325 void
MailBoxClear()326 MailBoxClear()
327 {
328     MailItem	*item;
329 
330     for (item = TheMailItems; item != NULL; item = item->next)
331     {
332 	item->in_use = 0;
333     }
334 
335     FaceClear();
336 }
337 
338 void
MailBoxUnClear()339 MailBoxUnClear()
340 {
341     MailItem	*item;
342 
343     for (item = TheMailItems; item != NULL; item = item->next)
344     {
345 	item->in_use = 1;
346 	item->face = FaceDisplay(item);
347     }
348 }
349 
350 void
MailBoxClean()351 MailBoxClean()
352 {
353     MailItem *item;
354     MailItem *next_item;
355 
356     for (item = TheMailItems; item != NULL; item = next_item)
357     {
358 	/*
359 	 * Save item->next here because if MailItemFree() is called, it will
360 	 * free item and we won't be able to access it after the call.
361 	 * Found by phkmalloc. Philippe Charnier (charnier@xp11.frmug.org)
362 	 * 11/96.
363 	 */
364 	next_item = item->next;
365 
366 	if (item->in_use == 0)
367 	{
368 	    MailItemFree(item);
369 	}
370     }
371 
372     FaceClean();
373 }
374 
375 static void
MailItemLabel(item)376 MailItemLabel(item)
377 MailItem*	item;
378 {
379     if (item->label == NULL)
380     {
381 	item->label = XtMalloc(strlen(item->user) + strlen(item->host) + 2);
382 	sprintf(item->label, "%s@%s", item->user, item->host);
383 	item->use_label = 0;
384     }
385 }
386 
387 
388 /*
389  *    Create a new mail item
390 */
391 
392 void
MailItemCreate(headers)393 MailItemCreate(headers)
394 MailHeader*	headers;
395 {
396     MailItem	*item;
397     MailHeader	*from;
398 #ifdef LOOKUP_HOSTNAME
399     struct hostent *host;
400 #endif
401 
402     /*
403      *    Have we already seen this item?
404     */
405 
406     for (item = TheMailItems; item != NULL; item = item->next)
407     {
408 	if (item->in_use)
409 	{
410 	    continue;
411 	}
412 
413 	if (MailHeaderListCompare(headers, item->headers))
414 	{
415 	    /*
416 	     * Yep!
417 	    */
418 
419 	    item->face = FaceDisplay(item);
420 	    item->in_use = 1;
421 
422 	    /*
423 	     * Setup annotations.
424 	    */
425 
426 	    MailItemAnnotate(item, NULL);
427 
428 	    /*
429 	     * Don't need these headers!
430 	    */
431 
432 	    MailHeaderListFree(headers);
433 
434 	    return;
435 	}
436     }
437 
438     item 	  = (MailItem *)XtCalloc(1, sizeof(MailItem));
439     item->headers = headers;
440     item->in_use  = 1;
441 
442     /*
443      *    Now parse the from line into the user and host parts.
444     */
445 
446     from = MailHeaderFind(TheFacesResources.from_field, headers);
447 
448     if (from == NULL)
449     {
450 	from = MailHeaderFind("From:", headers);
451     }
452 
453     if (from == NULL)
454     {
455 	from = MailHeaderFind("From ", headers);
456     }
457 
458     /*
459      *   If we found no from line then we ignore this message.
460     */
461 
462     if (from == NULL)
463     {
464 	MailItemFree(item);
465 	return;
466     }
467 
468     /*
469      *   Parse the from address.
470     */
471 
472     MailParseAddress(from->value, &(item->user), &(item->host));
473 
474 #ifdef LOOKUP_HOSTNAME
475     /*
476      *  Lookup the host via gethostbyname if asked.
477     */
478 
479     if (TheFacesResources.lookup_hostname)
480     {
481 	host = gethostbyname(item->host);
482 
483 	if (host != NULL)
484 	{
485 	    if (strcmp(item->host, host->h_name) != 0)
486 	    {
487 		item->realhost = XtNewString(host->h_name);
488 	    }
489 #ifdef LOOKUP_DEBUG
490 	    fprintf(stderr, "lookup: <%s> -> <%s>\n",
491 		    item->host, host->h_name);
492 #endif
493 	}
494 #ifdef LOOKUP_DEBUG
495 	else
496 	{
497 	    fprintf(stderr, "lookup: <%s> -> <>\n", item->host);
498 	}
499 #endif
500 
501     }
502 #endif /* LOOKUP_HOSTNAME */
503 
504     /*
505      *   Now see if we should ignore this message.
506     */
507 
508     if (MailItemIgnore(item))
509     {
510 	/*
511 	 *   Yup!  Do not need this item.
512 	*/
513 
514 	MailItemFree(item);
515 	return;
516     }
517 
518     /*
519      *  Locate any image and sound.
520     */
521 
522     FaceImageFind(item);
523 #ifdef SOUND
524     FaceSoundFind(item);
525 #endif
526     FaceCommandFind(item);
527 
528     /*
529      *  Compute the label (this is what is used to compress images.)
530     */
531 
532     MailItemLabel(item);
533 
534     /*
535      *    Add this new item to the tail of the list.
536     */
537 
538     if (TheMailItems == NULL)
539     {
540 	TheMailItems = TheMailItemsTail = item;
541     }
542     else
543     {
544 	item->prev = TheMailItemsTail;
545 	item->prev->next = item;
546 	TheMailItemsTail = item;
547     }
548 
549     item->face = FaceDisplay(item);
550 
551     /*
552      * Setup annotations.
553     */
554 
555     MailItemAnnotate(item, NULL);
556 
557 #ifdef SOUND
558     FaceSoundPlay(item->sound);
559 #endif /* SOUND */
560 
561     FaceCommandRun(item->command);
562 }
563 
564 void
MailItemCreateNoHeaders(user,host,annotations)565 MailItemCreateNoHeaders(user, host, annotations)
566 char* user;
567 char* host;
568 char** annotations;
569 {
570     MailItem	*item;
571 
572     if (annotations != NULL)
573     {
574 	if (*annotations == NULL || **annotations == '\0')
575 	{
576 	    annotations = NULL;
577 	}
578     }
579 
580     if (user == NULL)
581     {
582 	user = "unknown";
583     }
584 
585     if (host == NULL)
586     {
587 	host = "LOCAL";
588     }
589 
590     /*
591      *    Have we already seen this item?
592     */
593 
594     for (item = TheMailItems; item != NULL; item = item->next)
595     {
596 	if (item->in_use)
597 	{
598 	    continue;
599 	}
600 
601 	if (strcmp(user, item->user) == 0 &&
602 	    strcmp(host, item->host) == 0)
603 	{
604 #ifdef ITEM_DEBUG
605 	    fprintf(stderr,"MailItemCreateNoHeaders: reusing: <%s>:<%s>\n",
606 		    user, host);
607 #endif
608 	    /*
609 	     * Yep!
610 	    */
611 
612 	    item->face = FaceDisplay(item);
613 
614 	    /*
615 	     * Annotations may have changed.
616 	    */
617 
618 	    MailItemAnnotate(item, annotations);
619 	    item->in_use = 1;
620 	    return;
621 	}
622     }
623 
624 #ifdef ITEM_DEBUG
625 	    fprintf(stderr,"MailItemCreateNoHeaders: creating: <%s>:<%s>\n",
626 		    user, host);
627 #endif
628 
629     item 	  = (MailItem *)XtCalloc(1, sizeof(MailItem));
630     item->headers = NULL;
631     item->user = XtNewString(user);
632     item->host = XtNewString(host);
633     item->in_use  = 1;
634 
635     /*
636      *  Compute the label (this is what is used to compress images.)
637     */
638 
639     MailItemLabel(item);
640 
641     /*
642      *  Locate any image and sound.
643     */
644 
645     FaceImageFind(item);
646 #ifdef SOUND
647     FaceSoundFind(item);
648 #endif
649     FaceCommandFind(item);
650 
651     /*
652      *    Add this new item to the tail of the list.
653     */
654 
655     if (TheMailItems == NULL)
656     {
657 	TheMailItems = TheMailItemsTail = item;
658     }
659     else
660     {
661 	item->prev = TheMailItemsTail;
662 	item->prev->next = item;
663 	TheMailItemsTail = item;
664     }
665 
666     item->face = FaceDisplay(item);
667 
668     MailItemAnnotate(item, annotations);
669 
670 #ifdef SOUND
671     FaceSoundPlay(item->sound);
672 #endif /* SOUND */
673 
674     FaceCommandRun(item->command);
675 }
676 
677 void
MailBoxEmpty()678 MailBoxEmpty()
679 {
680     /*
681      * There is no file, clear all counts and clean.  This
682      * will cause all faces to be removed.
683     */
684 
685     MailBoxClear();
686     MailBoxClean();
687 }
688 
689 void
MailItemInit()690 MailItemInit()
691 {
692     int		i;
693     XrmDatabase	db;
694     char*	appname = XtName(TheTopLevel);
695     char*	fullname;
696     char*	fullclass;
697     String	type;
698     XrmValue	value;
699 
700 #if (XtSpecificationRelease > 4)
701     db = XtScreenDatabase(XtScreen(TheTopLevel));
702 #else
703     db = XtDatabase(XtDisplay(TheTopLevel));
704 #endif
705 
706     fullname = XtMalloc(strlen(appname) + 50);
707     fullclass = XtMalloc(strlen(XFACES_CLASS) + 50);
708 
709     annotationCount = TheFacesResources.annotation_count;
710     mailAnnotations = (MailAnnotation*) XtCalloc(annotationCount,
711 						 sizeof(MailAnnotation));
712 
713     for(i = 0; i < annotationCount; ++i)
714     {
715 	type = NULL;
716 	mailAnnotations[i].type   = MailAnnotateNone;
717 	mailAnnotations[i].header = NULL;
718 
719 	sprintf(fullname,  "%s.mail.annotation%d", appname, i+1);
720 	sprintf(fullclass, "%s.Mail.Annotation", XFACES_CLASS);
721 
722 #ifdef ITEM_DEBUG
723 	fprintf(stderr, "looking for: %s/%s\n", fullname, fullclass);
724 #endif
725 
726 	if (XrmGetResource(db, fullname, fullclass, &type, &value) &&
727 	    (strcmp(type, XtRString) == 0))
728 	{
729 #ifdef ITEM_DEBUG
730 	    fprintf(stderr, "found: <%s>\n", (char*)(value.addr));
731 #endif
732 	    if (strcmp(value.addr, "none") == 0)
733 	    {
734 		mailAnnotations[i].type = MailAnnotateNone;
735 	    }
736 	    else if (strcmp(value.addr, "count") == 0)
737 	    {
738 		mailAnnotations[i].type = MailAnnotateCount;
739 	    }
740 	    else if (strcmp(value.addr, "user") == 0)
741 	    {
742 		mailAnnotations[i].type = MailAnnotateUser;
743 	    }
744 	    else if (strcmp(value.addr, "host") == 0)
745 	    {
746 		mailAnnotations[i].type = MailAnnotateHost;
747 	    }
748 	    else if (strcmp(value.addr, "user@host") == 0)
749 	    {
750 		mailAnnotations[i].type = MailAnnotateUserHost;
751 	    }
752 	    else if (strncmp(value.addr, "*", 1) == 0)
753 	    {
754 		mailAnnotations[i].type   = MailAnnotateHeader;
755 		mailAnnotations[i].header = (char*)(value.addr) + 1;
756 	    }
757 
758 #ifdef ITEM_DEBUG
759 	    switch (mailAnnotations[i].type)
760 	    {
761 	      case MailAnnotateNone:
762 		fprintf(stderr,
763 			"mailAnnotations[%d].type: MailAnnotateNone\n", i);
764 		break;
765 
766 	      case MailAnnotateCount:
767 		fprintf(stderr,
768 			"mailAnnotations[%d].type: MailAnnotateCount\n", i);
769 		break;
770 
771 	      case MailAnnotateUser:
772 		fprintf(stderr,
773 			"mailAnnotations[%d].type: MailAnnotateUser\n", i);
774 		break;
775 
776 	      case MailAnnotateHost:
777 		fprintf(stderr,
778 			"mailAnnotations[%d].type: MailAnnotateHost\n", i);
779 		break;
780 
781 	      case MailAnnotateUserHost:
782 		fprintf(stderr,
783 			"mailAnnotations[%d].type: MailAnnotateUserHost\n", i);
784 		break;
785 
786 	      case MailAnnotateHeader:
787 		fprintf(stderr,
788 			"mailAnnotations[%d].type: MailAnnotateHeader\n", i);
789 		fprintf(stderr,
790 			"mailAnnotations[%d].header: <%s>\n",
791 			i, mailAnnotations[i].header);
792 		break;
793 	    }
794 #endif
795 	}
796     };
797 
798     unknownAnnotationCount = TheFacesResources.unknown_annotation_count;
799     unknownMailAnnotations = (MailAnnotation*)XtCalloc(unknownAnnotationCount,
800 						       sizeof(MailAnnotation));
801 
802     for(i = 0; i < unknownAnnotationCount; ++i)
803     {
804 	type = NULL;
805 	unknownMailAnnotations[i].type   = MailAnnotateNone;
806 	unknownMailAnnotations[i].header = NULL;
807 
808 	sprintf(fullname,  "%s.mail.unknownAnnotation%d", appname, i+1);
809 	sprintf(fullclass, "%s.Mail.Annotation", XFACES_CLASS);
810 
811 #ifdef ITEM_DEBUG
812 	fprintf(stderr, "looking for: %s/%s\n", fullname, fullclass);
813 #endif
814 
815 	if (XrmGetResource(db, fullname, fullclass, &type, &value) &&
816 	    (strcmp(type, XtRString) == 0))
817 	{
818 #ifdef ITEM_DEBUG
819 	    fprintf(stderr, "found: <%s>\n", (char*)(value.addr));
820 #endif
821 	    if (strcmp(value.addr, "none") == 0)
822 	    {
823 		unknownMailAnnotations[i].type = MailAnnotateNone;
824 	    }
825 	    else if (strcmp(value.addr, "count") == 0)
826 	    {
827 		unknownMailAnnotations[i].type = MailAnnotateCount;
828 	    }
829 	    else if (strcmp(value.addr, "user") == 0)
830 	    {
831 		unknownMailAnnotations[i].type = MailAnnotateUser;
832 	    }
833 	    else if (strcmp(value.addr, "host") == 0)
834 	    {
835 		unknownMailAnnotations[i].type = MailAnnotateHost;
836 	    }
837 	    else if (strcmp(value.addr, "user@host") == 0)
838 	    {
839 		unknownMailAnnotations[i].type = MailAnnotateUserHost;
840 	    }
841 	    else if (strncmp(value.addr, "*", 1) == 0)
842 	    {
843 		unknownMailAnnotations[i].type   = MailAnnotateHeader;
844 		unknownMailAnnotations[i].header = (char*)(value.addr) + 1;
845 	    }
846 
847 #ifdef ITEM_DEBUG
848 	    switch (unknownMailAnnotations[i].type)
849 	    {
850 	      case MailAnnotateNone:
851 		fprintf(stderr,
852 			"unknownMailAnnotations[%d].type: MailAnnotateNone\n", i);
853 		break;
854 
855 	      case MailAnnotateCount:
856 		fprintf(stderr,
857 			"unknownMailAnnotations[%d].type: MailAnnotateCount\n", i);
858 		break;
859 
860 	      case MailAnnotateUser:
861 		fprintf(stderr,
862 			"unknownMailAnnotations[%d].type: MailAnnotateUser\n", i);
863 		break;
864 
865 	      case MailAnnotateHost:
866 		fprintf(stderr,
867 			"unknownMailAnnotations[%d].type: MailAnnotateHost\n", i);
868 		break;
869 
870 	      case MailAnnotateUserHost:
871 		fprintf(stderr,
872 			"unknownMailAnnotations[%d].type: MailAnnotateUserHost\n", i);
873 		break;
874 
875 	      case MailAnnotateHeader:
876 		fprintf(stderr,
877 			"unknownMailAnnotations[%d].type: MailAnnotateHeader\n", i);
878 		fprintf(stderr,
879 			"unknownMailAnnotations[%d].header: <%s>\n",
880 			i, unknownMailAnnotations[i].header);
881 		break;
882 	    }
883 #endif
884 	}
885     };
886 
887     XtFree(fullname);
888     XtFree(fullclass);
889 }
890