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: Sun Feb 13 17:03:59 1994
27 * Update Count : 139
28 * Status : Released
29 *
30 * HISTORY
31 * 13-Feb-1994 Chris Liebman
32 * Last Modified: Sat Feb 12 22:51:24 1994 #138 (Chris Liebman)
33 * Removed the labelBindings. (the general bindings can now specify the
34 * labels.
35 *
36 * 31-Jan-1994 Chris Liebman
37 * Last Modified: Sat Jan 29 23:44:35 1994 #133 (Chris Liebman)
38 * *Major* changes to support new searching configuration.
39 *
40 * 24-Jan-1994 Chris Liebman
41 * Last Modified: Sun Jan 23 18:55:48 1994 #64 (Chris Liebman)
42 * Added path support and added X-Face header support.
43 *
44 * 14-Jan-1994 Chris Liebman
45 * Last Modified: Tue Jan 11 14:19:02 1994 #1 (Chris Liebman)
46 * added #if to use XtDatabase() for versions of Xt less than 5
47 *
48 * PURPOSE
49 * Handle images in an image independent way.
50 */
51
52 #ifndef lint
53 static char *RCSid = "$Id: face_image.c,v 1.12 1994/02/23 13:17:02 liebman Exp $";
54 #endif
55
56 #include "faces.h"
57 #include "face_image.h"
58 #include "face_search.h"
59 #include <sys/stat.h>
60
61 /*
62 * This is the master list of supported image types.
63 */
64
65 static FaceImageType* AllImageTypes = NULL;
66
67 /*
68 * Look up an image type by name.
69 */
70
71 FaceImageType*
FaceImageTypeByName(name)72 FaceImageTypeByName(name)
73 char* name;
74 {
75 FaceImageType* type;
76
77 for (type = AllImageTypes; type != NULL; type = type->next)
78 {
79 if (strcmp(name, type->name) == 0)
80 {
81 return type;
82 }
83 }
84
85 return NULL;
86 }
87
88 /*
89 * Register a new image type.
90 */
91
92 void
FaceImageTypeRegister(type)93 FaceImageTypeRegister(type)
94 FaceImageType* type;
95 {
96 type->next = AllImageTypes;
97 AllImageTypes = type;
98 }
99
100 /*
101 * Parse a string of ':' seperated image type names into an array of
102 * image type pointers.
103 */
104
105 FaceImageType**
FaceImageTypeListParse(str)106 FaceImageTypeListParse(str)
107 char* str;
108 {
109 FaceImageType* type;
110 char* name;
111 int type_count = 0;
112 int array_size = 0;
113 FaceImageType** array = NULL;
114
115 if (str == NULL)
116 {
117 return NULL;
118 }
119
120 array_size = 10;
121 array = (FaceImageType**)XtMalloc(array_size * sizeof(FaceImageType*));
122
123 while((name = ParseToken(&str, ":")) != NULL)
124 {
125 type = FaceImageTypeByName(name);
126
127 if (type == NULL)
128 {
129 fprintf(stderr, "FaceImageTypeListParse: bad type name: <%s>\n", name);
130 continue;
131 }
132
133 if (type_count >= array_size)
134 {
135 array_size += 10;
136 array = (FaceImageType**)XtRealloc((char*)array,
137 array_size * sizeof(FaceImageType*));
138 }
139
140 array[type_count++] = type;
141 }
142
143 array[type_count] = NULL;
144
145 return array;
146 }
147
148 /*
149 * Here we store a complete list of images.
150 */
151
152 static FaceImage *TheImages = NULL;
153
154 /*
155 * Create face image data for face.
156 */
157
158 FaceImage*
FaceImageCreate(file,type,data)159 FaceImageCreate(file, type, data)
160 char* file;
161 FaceImageType* type;
162 void* data;
163 {
164 FaceImage* fi;
165
166 fi = (FaceImage *)XtCalloc(1, sizeof(FaceImage));
167 fi->file = XtNewString(file);
168 fi->refs = 1;
169 fi->type = type;
170 fi->data = data;
171
172 /*
173 * Put the new image on the list.
174 */
175
176 fi->next = TheImages;
177 fi->prev = NULL;
178
179 if (fi->next != NULL)
180 {
181 fi->next->prev = fi;
182 }
183
184 TheImages = fi;
185
186 return fi;
187 }
188
189 typedef struct face_image_load_info
190 {
191 MailItem *item;
192 FaceImageType* type;
193 } FaceImageLoadInfo;
194
195 static int
FaceImageLoadWork(file,path,info)196 FaceImageLoadWork(file, path, info)
197 char* file;
198 char* path;
199 FaceImageLoadInfo* info;
200 {
201 struct stat buf;
202 void* image_data = NULL;
203 FaceImage* fi;
204 int length;
205 static char* filename = NULL;
206 static int filename_length = 0;
207
208 char my_label[512];
209 /*
210 * First see if we already have this image.
211 */
212
213
214 for (fi = TheImages; fi != NULL; fi = fi->next)
215 {
216 if (strcmp(fi->file, file) == 0)
217 {
218 if (info && info->item) {
219 sprintf(my_label, "%s@%s", info->item->user, info->item->host);
220 if (strcmp(fi->label, my_label))
221 break;
222 }
223 /*
224 * Yep!
225 */
226
227 fi->refs += 1;
228
229 info->item->image = fi;
230 return 1;
231 }
232 }
233
234 /*
235 * Only read if file exists and is not a directory.
236 */
237
238 if ((stat(file, &buf) != -1) && !(buf.st_mode & S_IFDIR))
239 {
240 /*
241 * Attempt to read the file.
242 */
243
244 image_data = info->type->read(file, info->type->data);
245 }
246
247
248 /*
249 * Try the common extension if we failed.
250 */
251
252 if (image_data == NULL)
253 {
254 /*
255 * Now try common extension.
256 */
257
258 length = strlen(file) + strlen(info->type->extension) + 1;
259
260 if (filename_length < length)
261 {
262 filename_length = length;
263
264 if (filename)
265 {
266 XtFree(filename);
267 }
268
269 filename = XtMalloc(filename_length);
270 }
271
272 sprintf(filename, "%s%s", file, info->type->extension);
273
274 /*
275 * Only read if file exists and is not a directory.
276 */
277
278 if ((stat(filename, &buf) != -1) && !(buf.st_mode & S_IFDIR))
279 {
280 /*
281 * Attempt to read the file.
282 */
283
284 image_data = info->type->read(filename, info->type->data);
285 }
286 }
287
288 /*
289 * If we still do not have it then fail.
290 */
291
292 if (image_data == NULL)
293 {
294 return 0;
295 }
296
297 /*
298 * Ok, create a face image struct.
299 */
300 fi = FaceImageCreate(file, info->type, image_data);
301
302 info->item->image = fi;
303
304 return 1;
305 }
306
307 int
FaceImageLoad(file,item,data)308 FaceImageLoad(file, item, data)
309 char* file;
310 MailItem* item;
311 FaceSearchData* data;
312 {
313 int type;
314 FaceImageType** types = TheFacesResources.image_types;
315 int found = 0;
316 FaceImageLoadInfo info;
317 char** paths = TheFacesResources.image_paths;
318
319 if (data != NULL)
320 {
321 /*
322 * Use the image types in teh search data.
323 */
324
325 if (data->itypes != NULL)
326 {
327 types = data->itypes;
328 }
329
330 /*
331 * Fixup paths.
332 */
333
334 if (data->paths != NULL)
335 {
336 paths = data->paths;
337 }
338 }
339
340 /*
341 * No image types?
342 */
343
344 if (types == NULL)
345 {
346 fprintf(stderr, "FaceImageLoad: no image types!\n");
347 return 0;
348 }
349
350 info.item = item;
351
352 for(type = 0; types[type] != NULL; ++type)
353 {
354 info.type = types[type];
355
356 /*
357 * enumerate thru paths if needed.
358 */
359
360 if ((*file != '/') &&
361 strncmp(file, "./", 2) &&
362 strncmp(file, "../", 3))
363 {
364 found = PathEnumerate(file, paths, FaceImageLoadWork, &info);
365 }
366 else
367 {
368 found = FaceImageLoadWork(file, ".", &info);
369 }
370
371 if (found)
372 {
373 break;
374 }
375 }
376
377 #ifdef FACEDB_DEBUG
378 if (found)
379 fprintf(stderr, "FaceImageLoad: Reporting %s as found\n", file);
380 #endif
381
382 return found;
383 }
384
385 /*
386 * Free an image.
387 */
388
389 void
FaceImageFree(fi)390 FaceImageFree(fi)
391 FaceImage *fi;
392 {
393 if (!fi)
394 {
395 return;
396 }
397
398 /*
399 * First remove one reference. If there are still more refs just
400 * return.
401 */
402
403 fi->refs -= 1;
404 if (fi->refs != 0)
405 {
406 return;
407 }
408
409 /*
410 * The previous image is now previous to the next image.
411 */
412
413 if (fi->next != NULL)
414 {
415 fi->next->prev = fi->prev;
416 }
417
418 /*
419 * The next face is now next from the previous face.
420 */
421
422 if (fi->prev != NULL)
423 {
424 fi->prev->next = fi->next;
425 }
426
427 /*
428 * If this was the first image then the next image is
429 * first.
430 */
431
432 if (fi == TheImages)
433 {
434 TheImages = fi->next;
435 }
436
437 /*
438 * Ok, free the name.
439 */
440
441 XtFree(fi->file);
442
443 /*
444 * Free any label.
445 */
446
447 XtFree(fi->label);
448
449 /*
450 * Free the image data.
451 */
452
453 if (fi->type != NULL && fi->type->free != NULL)
454 {
455 fi->type->free(fi->data, fi->type->data);
456 }
457
458 /*
459 * Free the struct.
460 */
461
462 XtFree((void *)fi);
463 }
464
465 /*
466 * Retrieve the image pixmap.
467 */
468
469 Pixmap
FaceImagePixmap(fi)470 FaceImagePixmap(fi)
471 FaceImage *fi;
472 {
473 Pixmap pixmap = None;
474
475 if (fi != NULL && fi->type != NULL && fi->type->pixmap != NULL)
476 {
477 pixmap = fi->type->pixmap(fi->data, fi->type->data);
478 }
479
480 return(pixmap);
481 }
482
483 /*
484 * Retrieve the image shape mask.
485 */
486
487 Pixmap
FaceImageShape(fi)488 FaceImageShape(fi)
489 FaceImage *fi;
490 {
491 Pixmap shape = None;
492
493 if (fi != NULL && fi->type != NULL && fi->type->shape != NULL)
494 {
495 shape = fi->type->shape(fi->data, fi->type->data);
496 }
497
498 return(shape);
499 }
500
501
502 /*
503 * Add a label to an image, if there is no image then create one.
504 */
505
506 void
FaceImageLabelCreate(item)507 FaceImageLabelCreate(item)
508 MailItem* item;
509 {
510 FaceImage* fi;
511 char *label;
512
513 label = XtMalloc(strlen(item->user) + strlen(item->host) + 2);
514 sprintf(label, "%s@%s", item->user, item->host);
515
516 /*
517 * Ok, create a face image struct.
518 */
519
520 if (item->image == NULL)
521 {
522 /*
523 * First see if we already have this image/label.
524 */
525
526 for (fi = TheImages; fi != NULL; fi = fi->next)
527 {
528 if (strcmp(fi->file, label) == 0)
529 {
530 /*
531 * Yep!
532 */
533
534 XtFree(label);
535 fi->refs += 1;
536
537 item->image = fi;
538 return;
539 }
540 }
541
542 item->image = FaceImageCreate(label, NULL, NULL);
543 }
544
545 /*
546 * Add the label.
547 */
548
549 item->image->label = label;
550 }
551
552 String
StringConcat(s1,s2)553 StringConcat(s1, s2)
554 String s1;
555 String s2;
556 {
557 String s;
558
559 s = XtMalloc(strlen(s1) + strlen(s2) + 1);
560 sprintf(s, "%s%s", s1, s2);
561
562 return(s);
563 }
564
565 void
FaceImageRef(fi)566 FaceImageRef(fi)
567 FaceImage* fi;
568 {
569 if (fi)
570 {
571 fi->refs += 1;
572 }
573 }
574
575 void
FaceImageCount(fi)576 FaceImageCount(fi)
577 FaceImage* fi;
578 {
579 if (fi)
580 {
581 fi->list_count += 1;
582 }
583 }
584
585 void
FaceImageDecount(fi)586 FaceImageDecount(fi)
587 FaceImage* fi;
588 {
589 if (fi)
590 {
591 fi->list_count -= 1;
592 }
593 }
594
595 String
FaceImageLabelGet(fi)596 FaceImageLabelGet(fi)
597 FaceImage* fi;
598 {
599 if (!fi)
600 {
601 return "NoLabel";
602 }
603
604 return fi->label;
605 }
606
607 /*
608 * Find an image for the given mail item.
609 */
610
611 void
FaceImageFind(item)612 FaceImageFind(item)
613 MailItem* item;
614 {
615 FaceSearch(item, TheFacesResources.image_search);
616 FaceImageLabelCreate(item);
617 }
618