1 /*
2  * Copyright 2001-2004 Brandon Long
3  * All Rights Reserved.
4  *
5  * ClearSilver Templating System
6  *
7  * This code is made available under the terms of the ClearSilver License.
8  * http://www.clearsilver.net/license.hdf
9  *
10  */
11 
12 /* Bring in gd library functions */
13 #include "gd.h"
14 
15 /* Bring in standard I/O so we can output the PNG to a file */
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <string.h>
19 #include <sys/stat.h>
20 #include <stdlib.h>
21 #include <dirent.h>
22 #include <errno.h>
23 #include <sys/fcntl.h>
24 #include <time.h>
25 #include <ctype.h>
26 
27 #include "ClearSilver.h"
28 
29 /* from httpd util.c : made infamous with Roy owes Rob beer. */
30 static char *months[] = {
31   "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
32 };
33 
find_month(char * mon)34 int find_month(char *mon) {
35   register int x;
36 
37   for(x=0;x<12;x++)
38     if(!strcmp(months[x],mon))
39       return x;
40   return -1;
41 }
42 
later_than(struct tm * lms,char * ims)43 int later_than(struct tm *lms, char *ims) {
44   char *ip;
45   char mname[256];
46   int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0, x;
47 
48   /* Whatever format we're looking at, it will start
49    * with weekday. */
50   /* Skip to first space. */
51   if(!(ip = strchr(ims,' ')))
52     return 0;
53   else
54     while(isspace(*ip))
55       ++ip;
56 
57   if(isalpha(*ip)) {
58     /* ctime */
59     sscanf(ip,"%25s %d %d:%d:%d %d",mname,&day,&hour,&min,&sec,&year);
60   }
61   else if(ip[2] == '-') {
62     /* RFC 850 (normal HTTP) */
63     char t[256];
64     sscanf(ip,"%s %d:%d:%d",t,&hour,&min,&sec);
65     t[2] = '\0';
66     day = atoi(t);
67     t[6] = '\0';
68     strcpy(mname,&t[3]);
69     x = atoi(&t[7]);
70     /* Prevent wraparound from ambiguity */
71     if(x < 70)
72       x += 100;
73     year = 1900 + x;
74   }
75   else {
76     /* RFC 822 */
77     sscanf(ip,"%d %s %d %d:%d:%d",&day,mname,&year,&hour,&min,&sec);
78   }
79   month = find_month(mname);
80 
81   if((x = (1900+lms->tm_year) - year))
82     return x < 0;
83   if((x = lms->tm_mon - month))
84     return x < 0;
85   if((x = lms->tm_mday - day))
86     return x < 0;
87   if((x = lms->tm_hour - hour))
88     return x < 0;
89   if((x = lms->tm_min - min))
90     return x < 0;
91   if((x = lms->tm_sec - sec))
92     return x < 0;
93 
94   return 1;
95 }
96 
97 
98 
gif_size(char * file,int * width,int * height)99 int gif_size (char *file, int *width, int *height)
100 {
101   UINT8 data[256];
102   int fd;
103   int blen;
104 
105   *width = 0; *height = 0;
106   fd = open (file, O_RDONLY);
107   if (fd == -1)
108     return -1;
109 
110   blen = read(fd, data, sizeof(data));
111   close(fd);
112 
113   if (blen < 10) return -1;
114   if (strncmp(data, "GIF87a", 6) && strncmp(data, "GIF89a", 6))
115     return -1;
116 
117   *width = data[6] + data[7]*256;
118   *height = data[8] + data[9]*256;
119 
120   return 0;
121 }
122 
jpeg_size(char * file,int * width,int * height)123 int jpeg_size (char *file, int *width, int *height)
124 {
125   UINT8 data[64*1024];
126   int blen;
127   int fd;
128   int pos;
129   int length;
130   UINT8 tag, marker;
131 
132 
133   *width = 0; *height = 0;
134   fd = open (file, O_RDONLY);
135   if (fd == -1)
136     return -1;
137 
138   blen = read(fd, data, sizeof(data));
139   close(fd);
140   pos = 2;
141   while (pos+8 < blen)
142   {
143     tag = data[pos+0];
144     if (tag != 0xff) return -1;
145     marker = data[pos+1];
146     length = data[pos+2] * 256 + data[pos+3] + 2;
147     if (marker >= 0xc0 && marker <= 0xcf && marker != 0xc4 &&
148 	marker != 0xc8 && marker != 0xcc)
149     {
150       *height = data[pos+5] * 256 + data[pos+6];
151       *width = data[pos+7] * 256 + data[pos+8];
152       ne_warn("%s: %dx%d", file, *width, *height);
153       return 0;
154     }
155     pos += length;
156   }
157   return -1;
158 }
159 
isdir(char * dir)160 int isdir(char *dir) {
161   struct stat statinfo;
162   if ( stat(dir, &statinfo) != 0) {
163     return 0;
164   }
165 
166   return S_ISDIR(statinfo.st_mode);
167 }
168 
create_directories(char * fullpath)169 int create_directories(char *fullpath) {
170   char s[4000];
171   char *last_slash;
172   int last_slash_pos;
173 
174   if ((fullpath == NULL) || (strlen(fullpath) > 4000)) {
175     return 1;
176   }
177 
178   last_slash = strrchr(fullpath,'/');
179   last_slash_pos = (last_slash - fullpath);
180   /* fprintf(stderr,"dira(%d): %s\n", last_slash_pos,fullpath); */
181 
182   if (last_slash_pos > 2) {
183     strncpy(s,fullpath,last_slash_pos);
184     s[last_slash_pos] = 0;
185     /* fprintf(stderr,"dir: %s\n", s); */
186 
187     if (!isdir(s)) {
188       char s2[4000];
189       sprintf(s2,"mkdir -p %s", s);
190       return system(s2);
191     }
192 
193   } else {
194     return 1;
195   }
196 
197   return 0;
198 }
199 
rotate_image(char * path,char * file,int degree,char * rpath)200 NEOERR *rotate_image(char *path, char *file, int degree, char *rpath)
201 {
202   char cmd[256];
203   char nfile[_POSIX_PATH_MAX];
204   char ofile[_POSIX_PATH_MAX];
205   char *ch, *opt;
206   int is_jpeg = 0;
207   struct stat s;
208   int r;
209 
210   snprintf (ofile, sizeof(ofile), "%s/%s", path, file);
211   snprintf (rpath, _POSIX_PATH_MAX, "%s/%s", path, file);
212   ch = strrchr(rpath, '.');
213   if ((!strcasecmp(ch, ".jpg")) ||
214       (!strcasecmp(ch, ".jpeg")) ||
215       (!strcasecmp(ch, ".thm")))
216   {
217     is_jpeg = 1;
218   }
219   else if (strcasecmp(ch, ".gif"))
220   {
221     return nerr_raise(NERR_ASSERT, "Only support gif/jpeg for rotation, ext %s",
222 	ch);
223   }
224   *ch = '\0';
225   if (degree == 90)
226   {
227     strcat(rpath, "_r");
228     opt = "-cw";
229   }
230   else if (degree == -90)
231   {
232     strcat(rpath, "_l");
233     opt = "-ccw";
234   }
235   else if (degree == 180)
236   {
237     strcat(rpath, "_u");
238     opt = "-rotate180";
239   }
240   else
241   {
242     return nerr_raise(NERR_ASSERT, "currently only support 90/-90/180 rotations");
243   }
244   if (is_jpeg)
245   {
246     strcat(rpath, ".jpg");
247     snprintf(cmd, sizeof(cmd), "djpeg -pnm %s | pnmflip %s | cjpeg -quality 85 > %s", ofile, opt, rpath);
248   }
249   else
250   {
251     strcat(rpath, ".gif");
252     snprintf(cmd, sizeof(cmd), "giftopnm %s | pnmflip %s | ppmtogif > %s", ofile, opt, rpath);
253   }
254   /* already exists? */
255   if (!stat(rpath, &s))
256   {
257     return STATUS_OK;
258   }
259   r = system(cmd);
260   if (r) return nerr_raise_errno (NERR_SYSTEM, "%s returned %d", cmd, r);
261   /* always save off the old file */
262   snprintf (nfile, sizeof(nfile), "%s/%s.orig", path, file);
263   if (stat(nfile, &s))
264   {
265     if (link(ofile, nfile))
266       return nerr_raise_errno (NERR_SYSTEM, "Unable to link %s -> %s", ofile, nfile);
267     unlink(ofile);
268   }
269   return STATUS_OK;
270 }
271 
scale_and_display_image(char * fname,int maxW,int maxH,char * cachepath,int quality)272 NEOERR *scale_and_display_image(char *fname,int maxW,int maxH,char *cachepath,
273     int quality)
274 {
275   NEOERR *err = STATUS_OK;
276   /* Declare the image */
277   gdImagePtr src_im = 0;
278   /* Declare input file */
279   FILE *infile=0, *cachefile=0;
280   int srcX,srcY,srcW,srcH;
281   FILE *dispfile=0;
282   struct stat s;
283 
284   /* if we can open the cachepath, then just print it */
285   if (!stat(cachepath, &s) && s.st_size)
286     cachefile = fopen(cachepath,"rb");
287   if (cachefile) {
288     /* we should probably stat the files and make sure the thumbnail
289        is current */
290     /* fprintf(stderr,"using cachefile: %s\n",cachepath); */
291     dispfile = cachefile;
292   } else {
293     char cmd[1024];
294     int factor=1;
295     int l;
296     int is_jpeg = 0, is_gif = 0;
297 
298     l = strlen(fname);
299     if ((l>4 && !strcasecmp(fname+l-4, ".jpg")) ||
300 	(l>4 && !strcasecmp(fname+l-4, ".thm")) ||
301 	(l>5 && !strcasecmp(fname+l-5, ".jpeg")))
302       is_jpeg = 1;
303     else if (l>4 && !strcasecmp(fname+l-4, ".gif"))
304       is_gif = 1;
305 
306 
307     if (is_jpeg)
308     {
309       if (!quality)
310       {
311 	if (!jpeg_size (fname, &srcW, &srcH))
312 	{
313 	  if ((srcW > maxW) || (srcH > maxH))
314 	  {
315 	    factor = 2;
316 	    if (srcW / factor > maxW)
317 	    {
318 	      factor = 4;
319 	      if (srcW / factor > maxW)
320 		factor = 8;
321 	    }
322 	  }
323 	}
324 
325 	/* ne_warn("factor %d\n", factor); */
326 	snprintf (cmd, sizeof(cmd), "/usr/bin/djpeg -fast -scale 1/%d '%s' | /usr/bin/cjpeg -quality 60 -progressive -dct fast -outfile '%s'", factor, fname, cachepath);
327 
328 	create_directories(cachepath);
329 	system(cmd);
330 	if (!stat(cachepath, &s) && s.st_size)
331 	  cachefile = fopen(cachepath,"rb");
332 	else
333 	  ne_warn("external command failed to create file\n");
334       }
335       if (cachefile) {
336 	dispfile = cachefile;
337 
338       } else /* no cachefile */ {
339 
340 
341 	/* fprintf(stderr,"reading image\n"); */
342 	/* Read the image in */
343 	infile = fopen(fname,"rb");
344 	src_im = gdImageCreateFromJpeg(infile);
345 	srcX=0; srcY=0; srcW=src_im->sx; srcH=src_im->sy;
346 
347 
348 	/* figure out if we need to scale it */
349 
350 	if ((maxW && srcW > maxW) || (maxH && srcH > maxH)) {
351 	  /* scale paramaters */
352 	  int dstX,dstY,dstW,dstH;
353 	  /* Declare output file */
354 	  FILE *jpegout;
355 	  gdImagePtr dest_im;
356 	  float srcAspect,dstAspect;
357 
358 	  /* create the destination image */
359 
360 	  dstX=0; dstY=0;
361 
362 
363 	  srcAspect = ((float)srcW/(float)srcH);
364 	  dstAspect = ((float)maxW/(float)maxH);
365 
366 	  if (srcAspect == dstAspect) {
367 	    /* they are the same aspect ratio */
368 	    dstW = maxW;
369 	    dstH = maxH;
370 	  } else if ( srcAspect > dstAspect ) {
371 	    /* if the src image has wider aspect ratio than the max */
372 	    dstW = maxW;
373 	    dstH = (int) ( ((float)dstW/(float)srcW) * srcH );
374 	  } else {
375 	    /* if the src image has taller aspect ratio than the max */
376 	    dstH = maxW;
377 	    dstW = (int) ( ((float)dstH/(float)srcH) * srcW );
378 	  }
379 
380 #ifdef GD2_VERS
381 	  dest_im = gdImageCreateTrueColor(dstW,dstH);
382 #else
383 	  dest_im = gdImageCreate(dstW,dstH);
384 #endif
385 
386 	  /* fprintf(stderr,"scaling to (%d,%d)\n",dstW,dstH); */
387 
388 	  /* Scale it to the destination image */
389 
390 	  gdImageCopyResized(dest_im,src_im,dstX,dstY,srcX,srcY,dstW,dstH,srcW,srcH);
391 
392 	  /* fprintf(stderr,"scaling finished\n"); */
393 
394 	  /* write the output image */
395 	  create_directories(cachepath);
396 	  jpegout = fopen(cachepath,"wb+");
397 	  if (!jpegout) {
398 	    jpegout = fopen("/tmp/foobar.jpg","wb+");
399 	  }
400 	  if (jpegout) {
401 	    gdImageJpeg(dest_im,jpegout,-1);
402 	    fflush(jpegout);
403 
404 	    /* now print that data out the stream */
405 	    dispfile = jpegout;
406 	  } else {
407 	    return nerr_raise_errno(NERR_IO, "Unable to create output file: %s", cachepath);
408 	  }
409 
410 
411 	  gdImageDestroy(dest_im);
412 
413 	} else {
414 	  /* just print the input file because it's small enough */
415 	  dispfile = infile;
416 	}
417 
418       }
419     }
420     else if (is_gif)
421     {
422       float scale = 1.0;
423       if (!gif_size (fname, &srcW, &srcH))
424       {
425 	if ((srcW > maxW) || (srcH > maxH))
426 	{
427 	  scale = 0.5;
428 	  if (srcW * scale > maxW)
429 	  {
430 	    scale = 0.25;
431 	    if (srcW * scale > maxW)
432 	      factor = 0.125;
433 	  }
434 	}
435       }
436 
437       if (scale < 1.0)
438       {
439 	snprintf (cmd, sizeof(cmd), "/usr/bin/giftopnm '%s' | /usr/bin/pnmscale  %5.3f | ppmquant 256 | ppmtogif > '%s'", fname, scale, cachepath);
440 
441 	create_directories(cachepath);
442 	system(cmd);
443 	dispfile = fopen(cachepath,"rb");
444 	if (dispfile == NULL)
445 	  return nerr_raise_errno(NERR_IO, "Unable to open file: %s", cachepath);
446 
447       }
448       else
449       {
450 	dispfile = fopen(fname, "rb");
451 	if (dispfile == NULL)
452 	  return nerr_raise_errno(NERR_IO, "Unable to open file: %s", fname);
453       }
454     }
455     else {
456       dispfile = fopen(fname,"rb");
457     }
458   }
459 
460   /* the data in "dispfile" is going to be printed now */
461   {
462 
463     char buf[8192];
464     int count;
465 
466     if (!fstat(fileno(dispfile), &s) && s.st_size)
467     {
468       cgiwrap_writef("Content-Length: %ld\n\n", s.st_size);
469     }
470     else
471     {
472       cgiwrap_writef("\n");
473     }
474 
475     fseek(dispfile,0,SEEK_SET);
476 
477     do {
478       count = fread(buf,1,sizeof(buf),dispfile);
479       if (count > 0) {
480 	err = cgiwrap_write(buf,count);
481       }
482     } while (count > 0);
483 
484   }
485 
486   if (dispfile) fclose(dispfile);
487   if (src_im) gdImageDestroy(src_im);
488 
489   return nerr_pass(err);
490 }
491 
load_images(char * path,ULIST ** rfiles,char * partial,int descend)492 NEOERR *load_images (char *path, ULIST **rfiles, char *partial, int descend)
493 {
494   NEOERR *err = STATUS_OK;
495   DIR *dp;
496   struct dirent *de;
497   int is_jpeg, is_gif, l;
498   char fpath[_POSIX_PATH_MAX];
499   char ppath[_POSIX_PATH_MAX];
500   ULIST *files = NULL;
501 
502   if ((dp = opendir (path)) == NULL)
503   {
504     return nerr_raise(NERR_IO, "Unable to opendir %s: [%d] %s", path, errno,
505 	strerror(errno));
506   }
507 
508   if (rfiles == NULL || *rfiles == NULL)
509   {
510     err = uListInit(&files, 50, 0);
511     if (err) return nerr_pass(err);
512     *rfiles = files;
513   }
514   else
515   {
516     files = *rfiles;
517   }
518 
519   while ((de = readdir (dp)) != NULL)
520   {
521     if (de->d_name[0] != '.')
522     {
523       snprintf(fpath, sizeof(fpath), "%s/%s", path, de->d_name);
524       if (partial)
525       {
526 	snprintf(ppath, sizeof(ppath), "%s/%s", partial, de->d_name);
527       }
528       else
529       {
530 	strncpy(ppath, de->d_name, sizeof(ppath));
531       }
532       if (descend && isdir(fpath))
533       {
534 	err = load_images(fpath, rfiles, ppath, descend);
535 	if (err) break;
536       }
537       else
538       {
539 	l = strlen(de->d_name);
540 	is_jpeg = 0; is_gif = 0;
541 
542 	if ((l>4 && !strcasecmp(de->d_name+l-4, ".jpg")) ||
543 	    (l>4 && !strcasecmp(de->d_name+l-4, ".thm")) ||
544 	    (l>5 && !strcasecmp(de->d_name+l-5, ".jpeg")))
545 	  is_jpeg = 1;
546 	else if (l>4 && !strcasecmp(de->d_name+l-4, ".gif"))
547 	  is_gif = 1;
548 
549 	if (is_gif || is_jpeg)
550 	{
551 	  err = uListAppend(files, strdup(ppath));
552 	  if (err) break;
553 	}
554       }
555     }
556   }
557   closedir(dp);
558   if (err)
559   {
560     uListDestroy(&files, ULIST_FREE);
561   }
562   else
563   {
564     *rfiles = files;
565   }
566   return nerr_pass(err);
567 }
568 
export_image(CGI * cgi,char * prefix,char * path,char * file)569 NEOERR *export_image(CGI *cgi, char *prefix, char *path, char *file)
570 {
571   NEOERR *err;
572   char buf[256];
573   char num[20];
574   int i = 0;
575   int r, l;
576   int width, height;
577   char ipath[_POSIX_PATH_MAX];
578   int is_jpeg = 0, is_gif = 0, is_thm = 0;
579 
580   l = strlen(file);
581   if ((l>4 && !strcasecmp(file+l-4, ".jpg")) ||
582       (l>5 && !strcasecmp(file+l-5, ".jpeg")))
583     is_jpeg = 1;
584   else if (l>4 && !strcasecmp(file+l-4, ".gif"))
585     is_gif = 1;
586   else if (l>4 && !strcasecmp(file+l-4, ".thm"))
587     is_thm = 1;
588 
589   snprintf (buf, sizeof(buf), "%s.%d", prefix, i);
590   err = hdf_set_value (cgi->hdf, prefix, file);
591   if (err != STATUS_OK) return nerr_pass(err);
592   snprintf (ipath, sizeof(ipath), "%s/%s", path, file);
593   if (is_jpeg || is_thm)
594     r = jpeg_size(ipath, &width, &height);
595   else
596     r = gif_size(ipath, &width, &height);
597   if (!r)
598   {
599     snprintf (buf, sizeof(buf), "%s.width", prefix);
600     snprintf (num, sizeof(num), "%d", width);
601     err = hdf_set_value (cgi->hdf, buf, num);
602     if (err != STATUS_OK) return nerr_pass(err);
603     snprintf (buf, sizeof(buf), "%s.height", prefix);
604     snprintf (num, sizeof(num), "%d", height);
605     err = hdf_set_value (cgi->hdf, buf, num);
606     if (err != STATUS_OK) return nerr_pass(err);
607   }
608   if (is_thm)
609   {
610     strcpy(ipath, file);
611     strcpy(ipath+l-4, ".avi");
612     snprintf(buf, sizeof(buf), "%s.avi", prefix);
613     err = hdf_set_value (cgi->hdf, buf, ipath);
614     if (err != STATUS_OK) return nerr_pass(err);
615   }
616   return STATUS_OK;
617 }
618 
scale_images(CGI * cgi,char * prefix,int width,int height,int force)619 NEOERR *scale_images (CGI *cgi, char *prefix, int width, int height, int force)
620 {
621   NEOERR *err;
622   char num[20];
623   HDF *obj;
624   int i, x;
625   int factor;
626 
627   obj = hdf_get_obj (cgi->hdf, prefix);
628   if (obj) obj = hdf_obj_child (obj);
629   while (obj)
630   {
631     factor = 1;
632     i = hdf_get_int_value(obj, "height", -1);
633     if (i != -1)
634     {
635       x = i;
636       while (x > height)
637       {
638 	/* factor = factor * 2;*/
639 	factor++;
640 	x = i / factor;
641       }
642       snprintf (num, sizeof(num), "%d", x);
643       err = hdf_set_value (obj, "height", num);
644       if (err != STATUS_OK) return nerr_pass (err);
645 
646       i = hdf_get_int_value(obj, "width", -1);
647       if (i != -1)
648       {
649 	i = i / factor;
650 	snprintf (num, sizeof(num), "%d", i);
651 	err = hdf_set_value (obj, "width", num);
652 	if (err != STATUS_OK) return nerr_pass (err);
653       }
654     }
655     else
656     {
657       snprintf (num, sizeof(num), "%d", height);
658       err = hdf_set_value (obj, "height", num);
659       if (err != STATUS_OK) return nerr_pass (err);
660       snprintf (num, sizeof(num), "%d", width);
661       err = hdf_set_value (obj, "width", num);
662       if (err != STATUS_OK) return nerr_pass (err);
663     }
664     obj = hdf_obj_next(obj);
665   }
666   return STATUS_OK;
667 }
668 
alpha_sort(const void * a,const void * b)669 int alpha_sort(const void *a, const void *b)
670 {
671   char **sa = (char **)a;
672   char **sb = (char **)b;
673 
674   /* ne_warn("%s %s: %d", *sa, *sb, strcmp(*sa, *sb)); */
675 
676   return strcmp(*sa, *sb);
677 }
678 
export_album_path(CGI * cgi,char * album,char * prefix)679 static NEOERR *export_album_path(CGI *cgi, char *album, char *prefix)
680 {
681   NEOERR *err = STATUS_OK;
682   char *p, *l;
683   int n = 0;
684   char buf[256];
685 
686   l = album;
687   p = strchr(album, '/');
688 
689   while (p != NULL)
690   {
691     *p = '\0';
692     snprintf(buf, sizeof(buf), "%s.%d", prefix, n);
693     err = hdf_set_value(cgi->hdf, buf, l);
694     if (err) break;
695     snprintf(buf, sizeof(buf), "%s.%d.path", prefix, n++);
696     err = hdf_set_value(cgi->hdf, buf, album);
697     if (err) break;
698     *p = '/';
699     l = p+1;
700     p = strchr(l, '/');
701   }
702   if (err) return nerr_pass(err);
703   if (strlen(l))
704   {
705     snprintf(buf, sizeof(buf), "%s.%d", prefix, n);
706     err = hdf_set_value(cgi->hdf, buf, l);
707     if (err) return nerr_pass(err);
708     snprintf(buf, sizeof(buf), "%s.%d.path", prefix, n++);
709     err = hdf_set_value(cgi->hdf, buf, album);
710     if (err) return nerr_pass(err);
711   }
712 
713   return STATUS_OK;
714 }
715 
716 
dowork_picture(CGI * cgi,char * album,char * picture)717 NEOERR *dowork_picture (CGI *cgi, char *album, char *picture)
718 {
719   NEOERR *err = STATUS_OK;
720   char *base, *name;
721   char path[_POSIX_PATH_MAX];
722   char buf[256];
723   int i, x, factor, y;
724   int thumb_width, thumb_height;
725   int pic_width, pic_height;
726   ULIST *files = NULL;
727   char t_album[_POSIX_PATH_MAX];
728   char t_pic[_POSIX_PATH_MAX];
729   char nfile[_POSIX_PATH_MAX];
730   char *ch;
731   char *avi = NULL;
732   int rotate;
733 
734   ch = strrchr(picture, '/');
735   if (ch != NULL)
736   {
737     *ch = '\0';
738     snprintf(t_album, sizeof(t_album), "%s/%s", album, picture);
739     *ch = '/';
740     strncpy(t_pic, ch+1, sizeof(t_pic));
741     picture = t_pic;
742     album = t_album;
743   }
744 
745   base = hdf_get_value (cgi->hdf, "BASEDIR", NULL);
746   if (base == NULL)
747   {
748     cgi_error (cgi, "No BASEDIR in imd file");
749     return nerr_raise(CGIFinished, "Finished");
750   }
751 
752   thumb_width = hdf_get_int_value (cgi->hdf, "ThumbWidth", 120);
753   thumb_height = hdf_get_int_value (cgi->hdf, "ThumbWidth", 90);
754   pic_width = hdf_get_int_value (cgi->hdf, "PictureWidth", 120);
755   pic_height = hdf_get_int_value (cgi->hdf, "PictureWidth", 90);
756 
757   err = hdf_set_value (cgi->hdf, "Context", "picture");
758   if (err != STATUS_OK) return nerr_pass(err);
759 
760   snprintf (path, sizeof(path), "%s/%s", base, album);
761   rotate = hdf_get_int_value(cgi->hdf, "Query.rotate", 0);
762   if (rotate)
763   {
764     err = rotate_image(path, picture, rotate, nfile);
765     if (err) return nerr_pass(err);
766     picture = strrchr(nfile, '/') + 1;
767   }
768 
769   err = hdf_set_value (cgi->hdf, "Album", album);
770   if (err != STATUS_OK) return nerr_pass(err);
771   err = hdf_set_value (cgi->hdf, "Album.Raw", album);
772   if (err != STATUS_OK) return nerr_pass(err);
773   err = export_album_path(cgi, album, "Album.Path");
774   if (err) return nerr_pass(err);
775   err = hdf_set_value (cgi->hdf, "Picture", picture);
776   if (err != STATUS_OK) return nerr_pass(err);
777 
778   err = load_images(path, &files, NULL, 0);
779   if (err != STATUS_OK) return nerr_pass(err);
780   err = uListSort(files, alpha_sort);
781   if (err != STATUS_OK) return nerr_pass(err);
782 
783   i = -1;
784   for (x = 0; x < uListLength(files); x++)
785   {
786     err = uListGet(files, x, (void *)&name);
787     if (err) break;
788     if (!strcmp(name, picture))
789     {
790       i = x;
791       break;
792     }
793   }
794   if (i != -1)
795   {
796     for (x = 2; x > 0; x--)
797     {
798       if (i - x < 0) continue;
799       err = uListGet(files, i-x, (void *)&name);
800       if (err) break;
801       snprintf(buf, sizeof(buf), "Show.%d", i-x);
802       err = export_image(cgi, buf, path, name);
803       if (err) break;
804     }
805     for (x = 0; x < 3; x++)
806     {
807       if (i + x > uListLength(files)) break;
808       err = uListGet(files, i+x, (void *)&name);
809       if (err) break;
810       snprintf(buf, sizeof(buf), "Show.%d", i+x);
811       err = export_image(cgi, buf, path, name);
812       if (err) break;
813     }
814     snprintf (buf, sizeof(buf), "Show.%d.width", i);
815     x = hdf_get_int_value (cgi->hdf, buf, -1);
816     if (x != -1)
817     {
818       factor = 1;
819       y = x;
820       while (y > pic_width)
821       {
822 	factor = factor * 2;
823 	/* factor++; */
824 	y = x / factor;
825 	ne_warn("factor = %d, y = %d", factor, y);
826       }
827       snprintf (buf, sizeof(buf), "%d", y);
828       hdf_set_value (cgi->hdf, "Picture.width", buf);
829       snprintf (buf, sizeof(buf), "Show.%d.height", i);
830       x = hdf_get_int_value (cgi->hdf, buf, -1);
831       y = x / factor;
832       snprintf (buf, sizeof(buf), "%d", y);
833       hdf_set_value (cgi->hdf, "Picture.height", buf);
834     }
835     else
836     {
837       snprintf (buf, sizeof(buf), "%d", pic_width);
838       hdf_set_value (cgi->hdf, "Picture.width", buf);
839       snprintf (buf, sizeof(buf), "%d", pic_height);
840       hdf_set_value (cgi->hdf, "Picture.height", buf);
841     }
842     snprintf (buf, sizeof(buf), "Show.%d.avi", i);
843     avi = hdf_get_value (cgi->hdf, buf, NULL);
844     if (avi)
845     {
846       err = hdf_set_value(cgi->hdf, "Picture.avi", avi);
847     }
848 
849     err = scale_images (cgi, "Show", thumb_width, thumb_height, 0);
850   }
851   uListDestroy(&files, ULIST_FREE);
852 
853   return nerr_pass(err);
854 }
855 
is_album(void * rock,char * filename)856 static int is_album(void *rock, char *filename)
857 {
858   char path[_POSIX_PATH_MAX];
859   char *prefix = (char *)rock;
860 
861   if (filename[0] == '.') return 0;
862   snprintf(path, sizeof(path), "%s/%s", prefix, filename);
863   if (isdir(path)) return 1;
864   return 0;
865 }
866 
dowork_album_overview(CGI * cgi,char * album)867 NEOERR *dowork_album_overview (CGI *cgi, char *album)
868 {
869   NEOERR *err = STATUS_OK;
870   DIR *dp;
871   struct dirent *de;
872   char path[_POSIX_PATH_MAX];
873   char buf[256];
874   int i = 0, x, y;
875   int thumb_width, thumb_height;
876   ULIST *files = NULL;
877   ULIST *albums = NULL;
878   char *name;
879 
880   thumb_width = hdf_get_int_value (cgi->hdf, "ThumbWidth", 120);
881   thumb_height = hdf_get_int_value (cgi->hdf, "ThumbWidth", 90);
882 
883   err = ne_listdir_fmatch(album, &albums, is_album, album);
884   if (err) return nerr_pass(err);
885 
886 
887   err = uListSort(albums, alpha_sort);
888   if (err) return nerr_pass(err);
889   for (y = 0; y < uListLength(albums); y++)
890   {
891     err = uListGet(albums, y, (void *)&name);
892     if (err) break;
893 
894     snprintf(path, sizeof(path), "%s/%s", album, name);
895     snprintf(buf, sizeof(buf), "Albums.%d", i);
896     err = hdf_set_value (cgi->hdf, buf, name);
897     if (err != STATUS_OK) break;
898     err = load_images(path, &files, NULL, 1);
899     if (err != STATUS_OK) break;
900     err = uListSort(files, alpha_sort);
901     if (err != STATUS_OK) break;
902     snprintf(buf, sizeof(buf), "Albums.%d.Count", i);
903     err = hdf_set_int_value(cgi->hdf, buf, uListLength(files));
904     if (err != STATUS_OK) break;
905     for (x = 0; (x < 4) && (x < uListLength(files)); x++)
906     {
907       err = uListGet(files, x, (void *)&name);
908       if (err) break;
909       snprintf(buf, sizeof(buf), "Albums.%d.Images.%d", i, x);
910       err = export_image(cgi, buf, path, name);
911       if (err) break;
912     }
913     uListDestroy(&files, ULIST_FREE);
914     if (err != STATUS_OK) break;
915     snprintf(buf, sizeof(buf), "Albums.%d.Images", i);
916     err = scale_images (cgi, buf, thumb_width, thumb_height, 0);
917     if (err != STATUS_OK) break;
918     i++;
919   }
920   return nerr_pass(err);
921 }
922 
dowork_album(CGI * cgi,char * album)923 NEOERR *dowork_album (CGI *cgi, char *album)
924 {
925   NEOERR *err;
926   char *base;
927   char buf[256];
928   char path[_POSIX_PATH_MAX];
929   int thumb_width, thumb_height;
930   int per_page, start, next, prev, last;
931   ULIST *files = NULL;
932   char *name;
933   int x;
934 
935   base = hdf_get_value (cgi->hdf, "BASEDIR", NULL);
936   if (base == NULL)
937   {
938     cgi_error (cgi, "No BASEDIR in imd file");
939     return nerr_raise(CGIFinished, "Finished");
940   }
941   thumb_width = hdf_get_int_value (cgi->hdf, "ThumbWidth", 120);
942   thumb_height = hdf_get_int_value (cgi->hdf, "ThumbWidth", 90);
943   per_page = hdf_get_int_value (cgi->hdf, "PerPage", 50);
944   start = hdf_get_int_value (cgi->hdf, "Query.start", 0);
945 
946   err = hdf_set_value (cgi->hdf, "Album", album);
947   if (err != STATUS_OK) return nerr_pass(err);
948   err = hdf_set_value (cgi->hdf, "Album.Raw", album);
949   if (err != STATUS_OK) return nerr_pass(err);
950   err = export_album_path(cgi, album, "Album.Path");
951   if (err) return nerr_pass(err);
952 
953 
954   err = hdf_set_value (cgi->hdf, "Context", "album");
955   if (err != STATUS_OK) return nerr_pass(err);
956 
957 
958   snprintf (path, sizeof(path), "%s/%s", base, album);
959   err = dowork_album_overview(cgi, path);
960   if (err != STATUS_OK) return nerr_pass(err);
961 
962   err = load_images(path, &files, NULL, 0);
963   if (err != STATUS_OK) return nerr_pass (err);
964   err = uListSort(files, alpha_sort);
965   if (err != STATUS_OK) return nerr_pass (err);
966   err = hdf_set_int_value(cgi->hdf, "Album.Count", uListLength(files));
967   if (err != STATUS_OK) return nerr_pass (err);
968   if (start > uListLength(files)) start = 0;
969   next = start + per_page;
970   if (next > uListLength(files)) next = uListLength(files);
971   prev = start - per_page;
972   if (prev < 0) prev = 0;
973   last = uListLength(files) - per_page;
974   if (last < 0) last = 0;
975   err = hdf_set_int_value(cgi->hdf, "Album.Start", start);
976   if (err != STATUS_OK) return nerr_pass (err);
977   err = hdf_set_int_value(cgi->hdf, "Album.Next", next);
978   if (err != STATUS_OK) return nerr_pass (err);
979   err = hdf_set_int_value(cgi->hdf, "Album.Prev", prev);
980   if (err != STATUS_OK) return nerr_pass (err);
981   err = hdf_set_int_value(cgi->hdf, "Album.Last", last);
982   if (err != STATUS_OK) return nerr_pass (err);
983   for (x = start; x < next; x++)
984   {
985     err = uListGet(files, x, (void *)&name);
986     if (err) break;
987     snprintf(buf, sizeof(buf), "Images.%d", x);
988     err = export_image(cgi, buf, path, name);
989     if (err) break;
990   }
991   uListDestroy(&files, ULIST_FREE);
992   if (err != STATUS_OK) return nerr_pass (err);
993   err = scale_images (cgi, "Images", thumb_width, thumb_height, 0);
994   if (err != STATUS_OK) return nerr_pass (err);
995   return STATUS_OK;
996 }
997 
dowork_image(CGI * cgi,char * image)998 NEOERR *dowork_image (CGI *cgi, char *image)
999 {
1000   NEOERR *err = STATUS_OK;
1001   int maxW = 0, maxH = 0;
1002   char *basepath = "";
1003   char *cache_basepath = "/tmp/.imgcache/";
1004   char srcpath[_POSIX_PATH_MAX] = "";
1005   char cachepath[_POSIX_PATH_MAX] = "";
1006   char buf[256];
1007   char *if_mod;
1008   int i, l, quality;
1009   struct stat s;
1010   struct tm *t;
1011 
1012   if ((i = hdf_get_int_value(cgi->hdf, "Query.width", 0)) != 0) {
1013     maxW = i;
1014   }
1015 
1016   if ((i = hdf_get_int_value(cgi->hdf, "Query.height", 0)) != 0) {
1017     maxH = i;
1018   }
1019   quality = hdf_get_int_value(cgi->hdf, "Query.quality", 0);
1020 
1021   if_mod = hdf_get_value(cgi->hdf, "HTTP.IfModifiedSince", NULL);
1022 
1023   basepath = hdf_get_value(cgi->hdf, "BASEDIR", NULL);
1024   if (basepath == NULL)
1025   {
1026     cgi_error (cgi, "No BASEDIR in imd file");
1027     return nerr_raise(CGIFinished, "Finished");
1028   }
1029 
1030   snprintf (srcpath, sizeof(srcpath), "%s/%s", basepath, image);
1031   snprintf (cachepath, sizeof(cachepath), "%s/%dx%d/%s", cache_basepath,
1032       maxW, maxH,image);
1033 
1034   if (stat(srcpath, &s))
1035   {
1036     cgiwrap_writef("Status: 404\nContent-Type: text/html\n\n");
1037     cgiwrap_writef("File %s not found.", srcpath);
1038     return nerr_raise_errno(NERR_IO, "Unable to stat file %s", srcpath);
1039   }
1040 
1041   t = gmtime(&(s.st_mtime));
1042   if (if_mod && later_than(t, if_mod))
1043   {
1044     cgiwrap_writef("Status: 304\nContent-Type: text/html\n\n");
1045     cgiwrap_writef("Use Local Copy");
1046     return STATUS_OK;
1047   }
1048 
1049   /* fprintf(stderr,"cachepath: %s\n",cachepath); */
1050 
1051   ne_warn("srcpath: %s", srcpath);
1052   l = strlen(srcpath);
1053   if ((l>4 && !strcasecmp(srcpath+l-4, ".jpg")) ||
1054       (l>4 && !strcasecmp(srcpath+l-4, ".thm")) ||
1055       (l>5 && !strcasecmp(srcpath+l-5, ".jpeg")))
1056     cgiwrap_writef("Content-Type: image/jpeg\n");
1057   else if (l>4 && !strcasecmp(srcpath+l-4, ".gif"))
1058     cgiwrap_writef("Content-Type: image/gif\n");
1059   else if (l>4 && !strcasecmp(srcpath+l-4, ".avi"))
1060   {
1061     ne_warn("found avi");
1062     cgiwrap_writef("Content-Type: video/x-msvideo\n");
1063   }
1064   t = gmtime(&(s.st_mtime));
1065   strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", t);
1066   cgiwrap_writef("Last-modified: %s\n", buf);
1067 
1068   err = scale_and_display_image(srcpath,maxW,maxH,cachepath,quality);
1069   return nerr_pass(err);
1070 }
1071 
main(int argc,char ** argv,char ** envp)1072 int main(int argc, char **argv, char **envp)
1073 {
1074   NEOERR *err;
1075   CGI *cgi;
1076   char *image;
1077   char *album;
1078   char *imd_file;
1079   char *cs_file;
1080   char *picture;
1081 
1082   ne_warn("Starting IMD");
1083   cgi_debug_init (argc,argv);
1084   cgiwrap_init_std (argc, argv, envp);
1085 
1086   nerr_init();
1087 
1088   ne_warn("CGI init");
1089   err = cgi_init(&cgi, NULL);
1090   if (err != STATUS_OK)
1091   {
1092     nerr_log_error(err);
1093     cgi_destroy(&cgi);
1094     return -1;
1095   }
1096   imd_file = hdf_get_value(cgi->hdf, "CGI.PathTranslated", NULL);
1097   ne_warn("Reading IMD file %s", imd_file);
1098   err = hdf_read_file (cgi->hdf, imd_file);
1099   if (err != STATUS_OK)
1100   {
1101     cgi_neo_error(cgi, err);
1102     nerr_log_error(err);
1103     cgi_destroy(&cgi);
1104     return -1;
1105   }
1106 
1107   cs_file = hdf_get_value(cgi->hdf, "Template", NULL);
1108   image = hdf_get_value(cgi->hdf, "Query.image", NULL);
1109   album = hdf_get_value(cgi->hdf, "Query.album", "");
1110   picture = hdf_get_value(cgi->hdf, "Query.picture", NULL);
1111   if (image)
1112   {
1113     err = dowork_image(cgi, image);
1114     if (err)
1115     {
1116       nerr_log_error(err);
1117       cgi_destroy(&cgi);
1118       return -1;
1119     }
1120   }
1121   else
1122   {
1123     if (!picture)
1124     {
1125       err = dowork_album (cgi, album);
1126     }
1127     else
1128     {
1129       err = dowork_picture (cgi, album, picture);
1130     }
1131     if (err != STATUS_OK)
1132     {
1133       if (nerr_handle(&err, CGIFinished))
1134       {
1135 	/* pass */
1136       }
1137       else
1138       {
1139 	cgi_neo_error(cgi, err);
1140 	nerr_log_error(err);
1141         cgi_destroy(&cgi);
1142 	return -1;
1143       }
1144     }
1145     else
1146     {
1147       err = cgi_display(cgi, cs_file);
1148       if (err != STATUS_OK)
1149       {
1150 	cgi_neo_error(cgi, err);
1151 	nerr_log_error(err);
1152         cgi_destroy(&cgi);
1153 	return -1;
1154       }
1155     }
1156   }
1157   cgi_destroy(&cgi);
1158   return 0;
1159 }
1160