| /* |
| * Copyright 2001-2004 Brandon Long |
| * All Rights Reserved. |
| * |
| * ClearSilver Templating System |
| * |
| * This code is made available under the terms of the ClearSilver License. |
| * http://www.clearsilver.net/license.hdf |
| * |
| */ |
| |
| /* Bring in gd library functions */ |
| #include "gd.h" |
| |
| /* Bring in standard I/O so we can output the PNG to a file */ |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <stdlib.h> |
| #include <dirent.h> |
| #include <errno.h> |
| #include <sys/fcntl.h> |
| #include <time.h> |
| #include <ctype.h> |
| |
| #include "ClearSilver.h" |
| |
| /* from httpd util.c : made infamous with Roy owes Rob beer. */ |
| static char *months[] = { |
| "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" |
| }; |
| |
| int find_month(char *mon) { |
| register int x; |
| |
| for(x=0;x<12;x++) |
| if(!strcmp(months[x],mon)) |
| return x; |
| return -1; |
| } |
| |
| int later_than(struct tm *lms, char *ims) { |
| char *ip; |
| char mname[256]; |
| int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0, x; |
| |
| /* Whatever format we're looking at, it will start |
| * with weekday. */ |
| /* Skip to first space. */ |
| if(!(ip = strchr(ims,' '))) |
| return 0; |
| else |
| while(isspace(*ip)) |
| ++ip; |
| |
| if(isalpha(*ip)) { |
| /* ctime */ |
| sscanf(ip,"%25s %d %d:%d:%d %d",mname,&day,&hour,&min,&sec,&year); |
| } |
| else if(ip[2] == '-') { |
| /* RFC 850 (normal HTTP) */ |
| char t[256]; |
| sscanf(ip,"%s %d:%d:%d",t,&hour,&min,&sec); |
| t[2] = '\0'; |
| day = atoi(t); |
| t[6] = '\0'; |
| strcpy(mname,&t[3]); |
| x = atoi(&t[7]); |
| /* Prevent wraparound from ambiguity */ |
| if(x < 70) |
| x += 100; |
| year = 1900 + x; |
| } |
| else { |
| /* RFC 822 */ |
| sscanf(ip,"%d %s %d %d:%d:%d",&day,mname,&year,&hour,&min,&sec); |
| } |
| month = find_month(mname); |
| |
| if((x = (1900+lms->tm_year) - year)) |
| return x < 0; |
| if((x = lms->tm_mon - month)) |
| return x < 0; |
| if((x = lms->tm_mday - day)) |
| return x < 0; |
| if((x = lms->tm_hour - hour)) |
| return x < 0; |
| if((x = lms->tm_min - min)) |
| return x < 0; |
| if((x = lms->tm_sec - sec)) |
| return x < 0; |
| |
| return 1; |
| } |
| |
| |
| |
| int gif_size (char *file, int *width, int *height) |
| { |
| UINT8 data[256]; |
| int fd; |
| int blen; |
| |
| *width = 0; *height = 0; |
| fd = open (file, O_RDONLY); |
| if (fd == -1) |
| return -1; |
| |
| blen = read(fd, data, sizeof(data)); |
| close(fd); |
| |
| if (blen < 10) return -1; |
| if (strncmp(data, "GIF87a", 6) && strncmp(data, "GIF89a", 6)) |
| return -1; |
| |
| *width = data[6] + data[7]*256; |
| *height = data[8] + data[9]*256; |
| |
| return 0; |
| } |
| |
| int jpeg_size (char *file, int *width, int *height) |
| { |
| UINT8 data[64*1024]; |
| int blen; |
| int fd; |
| int pos; |
| int length; |
| UINT8 tag, marker; |
| |
| |
| *width = 0; *height = 0; |
| fd = open (file, O_RDONLY); |
| if (fd == -1) |
| return -1; |
| |
| blen = read(fd, data, sizeof(data)); |
| close(fd); |
| pos = 2; |
| while (pos+8 < blen) |
| { |
| tag = data[pos+0]; |
| if (tag != 0xff) return -1; |
| marker = data[pos+1]; |
| length = data[pos+2] * 256 + data[pos+3] + 2; |
| if (marker >= 0xc0 && marker <= 0xcf && marker != 0xc4 && |
| marker != 0xc8 && marker != 0xcc) |
| { |
| *height = data[pos+5] * 256 + data[pos+6]; |
| *width = data[pos+7] * 256 + data[pos+8]; |
| ne_warn("%s: %dx%d", file, *width, *height); |
| return 0; |
| } |
| pos += length; |
| } |
| return -1; |
| } |
| |
| int isdir(char *dir) { |
| struct stat statinfo; |
| if ( stat(dir, &statinfo) != 0) { |
| return 0; |
| } |
| |
| return S_ISDIR(statinfo.st_mode); |
| } |
| |
| int create_directories(char *fullpath) { |
| char s[4000]; |
| char *last_slash; |
| int last_slash_pos; |
| |
| if ((fullpath == NULL) || (strlen(fullpath) > 4000)) { |
| return 1; |
| } |
| |
| last_slash = strrchr(fullpath,'/'); |
| last_slash_pos = (last_slash - fullpath); |
| /* fprintf(stderr,"dira(%d): %s\n", last_slash_pos,fullpath); */ |
| |
| if (last_slash_pos > 2) { |
| strncpy(s,fullpath,last_slash_pos); |
| s[last_slash_pos] = 0; |
| /* fprintf(stderr,"dir: %s\n", s); */ |
| |
| if (!isdir(s)) { |
| char s2[4000]; |
| sprintf(s2,"mkdir -p %s", s); |
| return system(s2); |
| } |
| |
| } else { |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| NEOERR *rotate_image(char *path, char *file, int degree, char *rpath) |
| { |
| char cmd[256]; |
| char nfile[_POSIX_PATH_MAX]; |
| char ofile[_POSIX_PATH_MAX]; |
| char *ch, *opt; |
| int is_jpeg = 0; |
| struct stat s; |
| int r; |
| |
| snprintf (ofile, sizeof(ofile), "%s/%s", path, file); |
| snprintf (rpath, _POSIX_PATH_MAX, "%s/%s", path, file); |
| ch = strrchr(rpath, '.'); |
| if ((!strcasecmp(ch, ".jpg")) || |
| (!strcasecmp(ch, ".jpeg")) || |
| (!strcasecmp(ch, ".thm"))) |
| { |
| is_jpeg = 1; |
| } |
| else if (strcasecmp(ch, ".gif")) |
| { |
| return nerr_raise(NERR_ASSERT, "Only support gif/jpeg for rotation, ext %s", |
| ch); |
| } |
| *ch = '\0'; |
| if (degree == 90) |
| { |
| strcat(rpath, "_r"); |
| opt = "-cw"; |
| } |
| else if (degree == -90) |
| { |
| strcat(rpath, "_l"); |
| opt = "-ccw"; |
| } |
| else if (degree == 180) |
| { |
| strcat(rpath, "_u"); |
| opt = "-rotate180"; |
| } |
| else |
| { |
| return nerr_raise(NERR_ASSERT, "currently only support 90/-90/180 rotations"); |
| } |
| if (is_jpeg) |
| { |
| strcat(rpath, ".jpg"); |
| snprintf(cmd, sizeof(cmd), "djpeg -pnm %s | pnmflip %s | cjpeg -quality 85 > %s", ofile, opt, rpath); |
| } |
| else |
| { |
| strcat(rpath, ".gif"); |
| snprintf(cmd, sizeof(cmd), "giftopnm %s | pnmflip %s | ppmtogif > %s", ofile, opt, rpath); |
| } |
| /* already exists? */ |
| if (!stat(rpath, &s)) |
| { |
| return STATUS_OK; |
| } |
| r = system(cmd); |
| if (r) return nerr_raise_errno (NERR_SYSTEM, "%s returned %d", cmd, r); |
| /* always save off the old file */ |
| snprintf (nfile, sizeof(nfile), "%s/%s.orig", path, file); |
| if (stat(nfile, &s)) |
| { |
| if (link(ofile, nfile)) |
| return nerr_raise_errno (NERR_SYSTEM, "Unable to link %s -> %s", ofile, nfile); |
| unlink(ofile); |
| } |
| return STATUS_OK; |
| } |
| |
| NEOERR *scale_and_display_image(char *fname,int maxW,int maxH,char *cachepath, |
| int quality) |
| { |
| NEOERR *err = STATUS_OK; |
| /* Declare the image */ |
| gdImagePtr src_im = 0; |
| /* Declare input file */ |
| FILE *infile=0, *cachefile=0; |
| int srcX,srcY,srcW,srcH; |
| FILE *dispfile=0; |
| struct stat s; |
| |
| /* if we can open the cachepath, then just print it */ |
| if (!stat(cachepath, &s) && s.st_size) |
| cachefile = fopen(cachepath,"rb"); |
| if (cachefile) { |
| /* we should probably stat the files and make sure the thumbnail |
| is current */ |
| /* fprintf(stderr,"using cachefile: %s\n",cachepath); */ |
| dispfile = cachefile; |
| } else { |
| char cmd[1024]; |
| int factor=1; |
| int l; |
| int is_jpeg = 0, is_gif = 0; |
| |
| l = strlen(fname); |
| if ((l>4 && !strcasecmp(fname+l-4, ".jpg")) || |
| (l>4 && !strcasecmp(fname+l-4, ".thm")) || |
| (l>5 && !strcasecmp(fname+l-5, ".jpeg"))) |
| is_jpeg = 1; |
| else if (l>4 && !strcasecmp(fname+l-4, ".gif")) |
| is_gif = 1; |
| |
| |
| if (is_jpeg) |
| { |
| if (!quality) |
| { |
| if (!jpeg_size (fname, &srcW, &srcH)) |
| { |
| if ((srcW > maxW) || (srcH > maxH)) |
| { |
| factor = 2; |
| if (srcW / factor > maxW) |
| { |
| factor = 4; |
| if (srcW / factor > maxW) |
| factor = 8; |
| } |
| } |
| } |
| |
| /* ne_warn("factor %d\n", factor); */ |
| 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); |
| |
| create_directories(cachepath); |
| system(cmd); |
| if (!stat(cachepath, &s) && s.st_size) |
| cachefile = fopen(cachepath,"rb"); |
| else |
| ne_warn("external command failed to create file\n"); |
| } |
| if (cachefile) { |
| dispfile = cachefile; |
| |
| } else /* no cachefile */ { |
| |
| |
| /* fprintf(stderr,"reading image\n"); */ |
| /* Read the image in */ |
| infile = fopen(fname,"rb"); |
| src_im = gdImageCreateFromJpeg(infile); |
| srcX=0; srcY=0; srcW=src_im->sx; srcH=src_im->sy; |
| |
| |
| /* figure out if we need to scale it */ |
| |
| if ((maxW && srcW > maxW) || (maxH && srcH > maxH)) { |
| /* scale paramaters */ |
| int dstX,dstY,dstW,dstH; |
| /* Declare output file */ |
| FILE *jpegout; |
| gdImagePtr dest_im; |
| float srcAspect,dstAspect; |
| |
| /* create the destination image */ |
| |
| dstX=0; dstY=0; |
| |
| |
| srcAspect = ((float)srcW/(float)srcH); |
| dstAspect = ((float)maxW/(float)maxH); |
| |
| if (srcAspect == dstAspect) { |
| /* they are the same aspect ratio */ |
| dstW = maxW; |
| dstH = maxH; |
| } else if ( srcAspect > dstAspect ) { |
| /* if the src image has wider aspect ratio than the max */ |
| dstW = maxW; |
| dstH = (int) ( ((float)dstW/(float)srcW) * srcH ); |
| } else { |
| /* if the src image has taller aspect ratio than the max */ |
| dstH = maxW; |
| dstW = (int) ( ((float)dstH/(float)srcH) * srcW ); |
| } |
| |
| #ifdef GD2_VERS |
| dest_im = gdImageCreateTrueColor(dstW,dstH); |
| #else |
| dest_im = gdImageCreate(dstW,dstH); |
| #endif |
| |
| /* fprintf(stderr,"scaling to (%d,%d)\n",dstW,dstH); */ |
| |
| /* Scale it to the destination image */ |
| |
| gdImageCopyResized(dest_im,src_im,dstX,dstY,srcX,srcY,dstW,dstH,srcW,srcH); |
| |
| /* fprintf(stderr,"scaling finished\n"); */ |
| |
| /* write the output image */ |
| create_directories(cachepath); |
| jpegout = fopen(cachepath,"wb+"); |
| if (!jpegout) { |
| jpegout = fopen("/tmp/foobar.jpg","wb+"); |
| } |
| if (jpegout) { |
| gdImageJpeg(dest_im,jpegout,-1); |
| fflush(jpegout); |
| |
| /* now print that data out the stream */ |
| dispfile = jpegout; |
| } else { |
| return nerr_raise_errno(NERR_IO, "Unable to create output file: %s", cachepath); |
| } |
| |
| |
| gdImageDestroy(dest_im); |
| |
| } else { |
| /* just print the input file because it's small enough */ |
| dispfile = infile; |
| } |
| |
| } |
| } |
| else if (is_gif) |
| { |
| float scale = 1.0; |
| if (!gif_size (fname, &srcW, &srcH)) |
| { |
| if ((srcW > maxW) || (srcH > maxH)) |
| { |
| scale = 0.5; |
| if (srcW * scale > maxW) |
| { |
| scale = 0.25; |
| if (srcW * scale > maxW) |
| factor = 0.125; |
| } |
| } |
| } |
| |
| if (scale < 1.0) |
| { |
| snprintf (cmd, sizeof(cmd), "/usr/bin/giftopnm '%s' | /usr/bin/pnmscale %5.3f | ppmquant 256 | ppmtogif > '%s'", fname, scale, cachepath); |
| |
| create_directories(cachepath); |
| system(cmd); |
| dispfile = fopen(cachepath,"rb"); |
| if (dispfile == NULL) |
| return nerr_raise_errno(NERR_IO, "Unable to open file: %s", cachepath); |
| |
| } |
| else |
| { |
| dispfile = fopen(fname, "rb"); |
| if (dispfile == NULL) |
| return nerr_raise_errno(NERR_IO, "Unable to open file: %s", fname); |
| } |
| } |
| else { |
| dispfile = fopen(fname,"rb"); |
| } |
| } |
| |
| /* the data in "dispfile" is going to be printed now */ |
| { |
| |
| char buf[8192]; |
| int count; |
| |
| if (!fstat(fileno(dispfile), &s) && s.st_size) |
| { |
| cgiwrap_writef("Content-Length: %ld\n\n", s.st_size); |
| } |
| else |
| { |
| cgiwrap_writef("\n"); |
| } |
| |
| fseek(dispfile,0,SEEK_SET); |
| |
| do { |
| count = fread(buf,1,sizeof(buf),dispfile); |
| if (count > 0) { |
| err = cgiwrap_write(buf,count); |
| } |
| } while (count > 0); |
| |
| } |
| |
| if (dispfile) fclose(dispfile); |
| if (src_im) gdImageDestroy(src_im); |
| |
| return nerr_pass(err); |
| } |
| |
| NEOERR *load_images (char *path, ULIST **rfiles, char *partial, int descend) |
| { |
| NEOERR *err = STATUS_OK; |
| DIR *dp; |
| struct dirent *de; |
| int is_jpeg, is_gif, l; |
| char fpath[_POSIX_PATH_MAX]; |
| char ppath[_POSIX_PATH_MAX]; |
| ULIST *files = NULL; |
| |
| if ((dp = opendir (path)) == NULL) |
| { |
| return nerr_raise(NERR_IO, "Unable to opendir %s: [%d] %s", path, errno, |
| strerror(errno)); |
| } |
| |
| if (rfiles == NULL || *rfiles == NULL) |
| { |
| err = uListInit(&files, 50, 0); |
| if (err) return nerr_pass(err); |
| *rfiles = files; |
| } |
| else |
| { |
| files = *rfiles; |
| } |
| |
| while ((de = readdir (dp)) != NULL) |
| { |
| if (de->d_name[0] != '.') |
| { |
| snprintf(fpath, sizeof(fpath), "%s/%s", path, de->d_name); |
| if (partial) |
| { |
| snprintf(ppath, sizeof(ppath), "%s/%s", partial, de->d_name); |
| } |
| else |
| { |
| strncpy(ppath, de->d_name, sizeof(ppath)); |
| } |
| if (descend && isdir(fpath)) |
| { |
| err = load_images(fpath, rfiles, ppath, descend); |
| if (err) break; |
| } |
| else |
| { |
| l = strlen(de->d_name); |
| is_jpeg = 0; is_gif = 0; |
| |
| if ((l>4 && !strcasecmp(de->d_name+l-4, ".jpg")) || |
| (l>4 && !strcasecmp(de->d_name+l-4, ".thm")) || |
| (l>5 && !strcasecmp(de->d_name+l-5, ".jpeg"))) |
| is_jpeg = 1; |
| else if (l>4 && !strcasecmp(de->d_name+l-4, ".gif")) |
| is_gif = 1; |
| |
| if (is_gif || is_jpeg) |
| { |
| err = uListAppend(files, strdup(ppath)); |
| if (err) break; |
| } |
| } |
| } |
| } |
| closedir(dp); |
| if (err) |
| { |
| uListDestroy(&files, ULIST_FREE); |
| } |
| else |
| { |
| *rfiles = files; |
| } |
| return nerr_pass(err); |
| } |
| |
| NEOERR *export_image(CGI *cgi, char *prefix, char *path, char *file) |
| { |
| NEOERR *err; |
| char buf[256]; |
| char num[20]; |
| int i = 0; |
| int r, l; |
| int width, height; |
| char ipath[_POSIX_PATH_MAX]; |
| int is_jpeg = 0, is_gif = 0, is_thm = 0; |
| |
| l = strlen(file); |
| if ((l>4 && !strcasecmp(file+l-4, ".jpg")) || |
| (l>5 && !strcasecmp(file+l-5, ".jpeg"))) |
| is_jpeg = 1; |
| else if (l>4 && !strcasecmp(file+l-4, ".gif")) |
| is_gif = 1; |
| else if (l>4 && !strcasecmp(file+l-4, ".thm")) |
| is_thm = 1; |
| |
| snprintf (buf, sizeof(buf), "%s.%d", prefix, i); |
| err = hdf_set_value (cgi->hdf, prefix, file); |
| if (err != STATUS_OK) return nerr_pass(err); |
| snprintf (ipath, sizeof(ipath), "%s/%s", path, file); |
| if (is_jpeg || is_thm) |
| r = jpeg_size(ipath, &width, &height); |
| else |
| r = gif_size(ipath, &width, &height); |
| if (!r) |
| { |
| snprintf (buf, sizeof(buf), "%s.width", prefix); |
| snprintf (num, sizeof(num), "%d", width); |
| err = hdf_set_value (cgi->hdf, buf, num); |
| if (err != STATUS_OK) return nerr_pass(err); |
| snprintf (buf, sizeof(buf), "%s.height", prefix); |
| snprintf (num, sizeof(num), "%d", height); |
| err = hdf_set_value (cgi->hdf, buf, num); |
| if (err != STATUS_OK) return nerr_pass(err); |
| } |
| if (is_thm) |
| { |
| strcpy(ipath, file); |
| strcpy(ipath+l-4, ".avi"); |
| snprintf(buf, sizeof(buf), "%s.avi", prefix); |
| err = hdf_set_value (cgi->hdf, buf, ipath); |
| if (err != STATUS_OK) return nerr_pass(err); |
| } |
| return STATUS_OK; |
| } |
| |
| NEOERR *scale_images (CGI *cgi, char *prefix, int width, int height, int force) |
| { |
| NEOERR *err; |
| char num[20]; |
| HDF *obj; |
| int i, x; |
| int factor; |
| |
| obj = hdf_get_obj (cgi->hdf, prefix); |
| if (obj) obj = hdf_obj_child (obj); |
| while (obj) |
| { |
| factor = 1; |
| i = hdf_get_int_value(obj, "height", -1); |
| if (i != -1) |
| { |
| x = i; |
| while (x > height) |
| { |
| /* factor = factor * 2;*/ |
| factor++; |
| x = i / factor; |
| } |
| snprintf (num, sizeof(num), "%d", x); |
| err = hdf_set_value (obj, "height", num); |
| if (err != STATUS_OK) return nerr_pass (err); |
| |
| i = hdf_get_int_value(obj, "width", -1); |
| if (i != -1) |
| { |
| i = i / factor; |
| snprintf (num, sizeof(num), "%d", i); |
| err = hdf_set_value (obj, "width", num); |
| if (err != STATUS_OK) return nerr_pass (err); |
| } |
| } |
| else |
| { |
| snprintf (num, sizeof(num), "%d", height); |
| err = hdf_set_value (obj, "height", num); |
| if (err != STATUS_OK) return nerr_pass (err); |
| snprintf (num, sizeof(num), "%d", width); |
| err = hdf_set_value (obj, "width", num); |
| if (err != STATUS_OK) return nerr_pass (err); |
| } |
| obj = hdf_obj_next(obj); |
| } |
| return STATUS_OK; |
| } |
| |
| int alpha_sort(const void *a, const void *b) |
| { |
| char **sa = (char **)a; |
| char **sb = (char **)b; |
| |
| /* ne_warn("%s %s: %d", *sa, *sb, strcmp(*sa, *sb)); */ |
| |
| return strcmp(*sa, *sb); |
| } |
| |
| static NEOERR *export_album_path(CGI *cgi, char *album, char *prefix) |
| { |
| NEOERR *err = STATUS_OK; |
| char *p, *l; |
| int n = 0; |
| char buf[256]; |
| |
| l = album; |
| p = strchr(album, '/'); |
| |
| while (p != NULL) |
| { |
| *p = '\0'; |
| snprintf(buf, sizeof(buf), "%s.%d", prefix, n); |
| err = hdf_set_value(cgi->hdf, buf, l); |
| if (err) break; |
| snprintf(buf, sizeof(buf), "%s.%d.path", prefix, n++); |
| err = hdf_set_value(cgi->hdf, buf, album); |
| if (err) break; |
| *p = '/'; |
| l = p+1; |
| p = strchr(l, '/'); |
| } |
| if (err) return nerr_pass(err); |
| if (strlen(l)) |
| { |
| snprintf(buf, sizeof(buf), "%s.%d", prefix, n); |
| err = hdf_set_value(cgi->hdf, buf, l); |
| if (err) return nerr_pass(err); |
| snprintf(buf, sizeof(buf), "%s.%d.path", prefix, n++); |
| err = hdf_set_value(cgi->hdf, buf, album); |
| if (err) return nerr_pass(err); |
| } |
| |
| return STATUS_OK; |
| } |
| |
| |
| NEOERR *dowork_picture (CGI *cgi, char *album, char *picture) |
| { |
| NEOERR *err = STATUS_OK; |
| char *base, *name; |
| char path[_POSIX_PATH_MAX]; |
| char buf[256]; |
| int i, x, factor, y; |
| int thumb_width, thumb_height; |
| int pic_width, pic_height; |
| ULIST *files = NULL; |
| char t_album[_POSIX_PATH_MAX]; |
| char t_pic[_POSIX_PATH_MAX]; |
| char nfile[_POSIX_PATH_MAX]; |
| char *ch; |
| char *avi = NULL; |
| int rotate; |
| |
| ch = strrchr(picture, '/'); |
| if (ch != NULL) |
| { |
| *ch = '\0'; |
| snprintf(t_album, sizeof(t_album), "%s/%s", album, picture); |
| *ch = '/'; |
| strncpy(t_pic, ch+1, sizeof(t_pic)); |
| picture = t_pic; |
| album = t_album; |
| } |
| |
| base = hdf_get_value (cgi->hdf, "BASEDIR", NULL); |
| if (base == NULL) |
| { |
| cgi_error (cgi, "No BASEDIR in imd file"); |
| return nerr_raise(CGIFinished, "Finished"); |
| } |
| |
| thumb_width = hdf_get_int_value (cgi->hdf, "ThumbWidth", 120); |
| thumb_height = hdf_get_int_value (cgi->hdf, "ThumbWidth", 90); |
| pic_width = hdf_get_int_value (cgi->hdf, "PictureWidth", 120); |
| pic_height = hdf_get_int_value (cgi->hdf, "PictureWidth", 90); |
| |
| err = hdf_set_value (cgi->hdf, "Context", "picture"); |
| if (err != STATUS_OK) return nerr_pass(err); |
| |
| snprintf (path, sizeof(path), "%s/%s", base, album); |
| rotate = hdf_get_int_value(cgi->hdf, "Query.rotate", 0); |
| if (rotate) |
| { |
| err = rotate_image(path, picture, rotate, nfile); |
| if (err) return nerr_pass(err); |
| picture = strrchr(nfile, '/') + 1; |
| } |
| |
| err = hdf_set_value (cgi->hdf, "Album", album); |
| if (err != STATUS_OK) return nerr_pass(err); |
| err = hdf_set_value (cgi->hdf, "Album.Raw", album); |
| if (err != STATUS_OK) return nerr_pass(err); |
| err = export_album_path(cgi, album, "Album.Path"); |
| if (err) return nerr_pass(err); |
| err = hdf_set_value (cgi->hdf, "Picture", picture); |
| if (err != STATUS_OK) return nerr_pass(err); |
| |
| err = load_images(path, &files, NULL, 0); |
| if (err != STATUS_OK) return nerr_pass(err); |
| err = uListSort(files, alpha_sort); |
| if (err != STATUS_OK) return nerr_pass(err); |
| |
| i = -1; |
| for (x = 0; x < uListLength(files); x++) |
| { |
| err = uListGet(files, x, (void *)&name); |
| if (err) break; |
| if (!strcmp(name, picture)) |
| { |
| i = x; |
| break; |
| } |
| } |
| if (i != -1) |
| { |
| for (x = 2; x > 0; x--) |
| { |
| if (i - x < 0) continue; |
| err = uListGet(files, i-x, (void *)&name); |
| if (err) break; |
| snprintf(buf, sizeof(buf), "Show.%d", i-x); |
| err = export_image(cgi, buf, path, name); |
| if (err) break; |
| } |
| for (x = 0; x < 3; x++) |
| { |
| if (i + x > uListLength(files)) break; |
| err = uListGet(files, i+x, (void *)&name); |
| if (err) break; |
| snprintf(buf, sizeof(buf), "Show.%d", i+x); |
| err = export_image(cgi, buf, path, name); |
| if (err) break; |
| } |
| snprintf (buf, sizeof(buf), "Show.%d.width", i); |
| x = hdf_get_int_value (cgi->hdf, buf, -1); |
| if (x != -1) |
| { |
| factor = 1; |
| y = x; |
| while (y > pic_width) |
| { |
| factor = factor * 2; |
| /* factor++; */ |
| y = x / factor; |
| ne_warn("factor = %d, y = %d", factor, y); |
| } |
| snprintf (buf, sizeof(buf), "%d", y); |
| hdf_set_value (cgi->hdf, "Picture.width", buf); |
| snprintf (buf, sizeof(buf), "Show.%d.height", i); |
| x = hdf_get_int_value (cgi->hdf, buf, -1); |
| y = x / factor; |
| snprintf (buf, sizeof(buf), "%d", y); |
| hdf_set_value (cgi->hdf, "Picture.height", buf); |
| } |
| else |
| { |
| snprintf (buf, sizeof(buf), "%d", pic_width); |
| hdf_set_value (cgi->hdf, "Picture.width", buf); |
| snprintf (buf, sizeof(buf), "%d", pic_height); |
| hdf_set_value (cgi->hdf, "Picture.height", buf); |
| } |
| snprintf (buf, sizeof(buf), "Show.%d.avi", i); |
| avi = hdf_get_value (cgi->hdf, buf, NULL); |
| if (avi) |
| { |
| err = hdf_set_value(cgi->hdf, "Picture.avi", avi); |
| } |
| |
| err = scale_images (cgi, "Show", thumb_width, thumb_height, 0); |
| } |
| uListDestroy(&files, ULIST_FREE); |
| |
| return nerr_pass(err); |
| } |
| |
| static int is_album(void *rock, char *filename) |
| { |
| char path[_POSIX_PATH_MAX]; |
| char *prefix = (char *)rock; |
| |
| if (filename[0] == '.') return 0; |
| snprintf(path, sizeof(path), "%s/%s", prefix, filename); |
| if (isdir(path)) return 1; |
| return 0; |
| } |
| |
| NEOERR *dowork_album_overview (CGI *cgi, char *album) |
| { |
| NEOERR *err = STATUS_OK; |
| DIR *dp; |
| struct dirent *de; |
| char path[_POSIX_PATH_MAX]; |
| char buf[256]; |
| int i = 0, x, y; |
| int thumb_width, thumb_height; |
| ULIST *files = NULL; |
| ULIST *albums = NULL; |
| char *name; |
| |
| thumb_width = hdf_get_int_value (cgi->hdf, "ThumbWidth", 120); |
| thumb_height = hdf_get_int_value (cgi->hdf, "ThumbWidth", 90); |
| |
| err = ne_listdir_fmatch(album, &albums, is_album, album); |
| if (err) return nerr_pass(err); |
| |
| |
| err = uListSort(albums, alpha_sort); |
| if (err) return nerr_pass(err); |
| for (y = 0; y < uListLength(albums); y++) |
| { |
| err = uListGet(albums, y, (void *)&name); |
| if (err) break; |
| |
| snprintf(path, sizeof(path), "%s/%s", album, name); |
| snprintf(buf, sizeof(buf), "Albums.%d", i); |
| err = hdf_set_value (cgi->hdf, buf, name); |
| if (err != STATUS_OK) break; |
| err = load_images(path, &files, NULL, 1); |
| if (err != STATUS_OK) break; |
| err = uListSort(files, alpha_sort); |
| if (err != STATUS_OK) break; |
| snprintf(buf, sizeof(buf), "Albums.%d.Count", i); |
| err = hdf_set_int_value(cgi->hdf, buf, uListLength(files)); |
| if (err != STATUS_OK) break; |
| for (x = 0; (x < 4) && (x < uListLength(files)); x++) |
| { |
| err = uListGet(files, x, (void *)&name); |
| if (err) break; |
| snprintf(buf, sizeof(buf), "Albums.%d.Images.%d", i, x); |
| err = export_image(cgi, buf, path, name); |
| if (err) break; |
| } |
| uListDestroy(&files, ULIST_FREE); |
| if (err != STATUS_OK) break; |
| snprintf(buf, sizeof(buf), "Albums.%d.Images", i); |
| err = scale_images (cgi, buf, thumb_width, thumb_height, 0); |
| if (err != STATUS_OK) break; |
| i++; |
| } |
| return nerr_pass(err); |
| } |
| |
| NEOERR *dowork_album (CGI *cgi, char *album) |
| { |
| NEOERR *err; |
| char *base; |
| char buf[256]; |
| char path[_POSIX_PATH_MAX]; |
| int thumb_width, thumb_height; |
| int per_page, start, next, prev, last; |
| ULIST *files = NULL; |
| char *name; |
| int x; |
| |
| base = hdf_get_value (cgi->hdf, "BASEDIR", NULL); |
| if (base == NULL) |
| { |
| cgi_error (cgi, "No BASEDIR in imd file"); |
| return nerr_raise(CGIFinished, "Finished"); |
| } |
| thumb_width = hdf_get_int_value (cgi->hdf, "ThumbWidth", 120); |
| thumb_height = hdf_get_int_value (cgi->hdf, "ThumbWidth", 90); |
| per_page = hdf_get_int_value (cgi->hdf, "PerPage", 50); |
| start = hdf_get_int_value (cgi->hdf, "Query.start", 0); |
| |
| err = hdf_set_value (cgi->hdf, "Album", album); |
| if (err != STATUS_OK) return nerr_pass(err); |
| err = hdf_set_value (cgi->hdf, "Album.Raw", album); |
| if (err != STATUS_OK) return nerr_pass(err); |
| err = export_album_path(cgi, album, "Album.Path"); |
| if (err) return nerr_pass(err); |
| |
| |
| err = hdf_set_value (cgi->hdf, "Context", "album"); |
| if (err != STATUS_OK) return nerr_pass(err); |
| |
| |
| snprintf (path, sizeof(path), "%s/%s", base, album); |
| err = dowork_album_overview(cgi, path); |
| if (err != STATUS_OK) return nerr_pass(err); |
| |
| err = load_images(path, &files, NULL, 0); |
| if (err != STATUS_OK) return nerr_pass (err); |
| err = uListSort(files, alpha_sort); |
| if (err != STATUS_OK) return nerr_pass (err); |
| err = hdf_set_int_value(cgi->hdf, "Album.Count", uListLength(files)); |
| if (err != STATUS_OK) return nerr_pass (err); |
| if (start > uListLength(files)) start = 0; |
| next = start + per_page; |
| if (next > uListLength(files)) next = uListLength(files); |
| prev = start - per_page; |
| if (prev < 0) prev = 0; |
| last = uListLength(files) - per_page; |
| if (last < 0) last = 0; |
| err = hdf_set_int_value(cgi->hdf, "Album.Start", start); |
| if (err != STATUS_OK) return nerr_pass (err); |
| err = hdf_set_int_value(cgi->hdf, "Album.Next", next); |
| if (err != STATUS_OK) return nerr_pass (err); |
| err = hdf_set_int_value(cgi->hdf, "Album.Prev", prev); |
| if (err != STATUS_OK) return nerr_pass (err); |
| err = hdf_set_int_value(cgi->hdf, "Album.Last", last); |
| if (err != STATUS_OK) return nerr_pass (err); |
| for (x = start; x < next; x++) |
| { |
| err = uListGet(files, x, (void *)&name); |
| if (err) break; |
| snprintf(buf, sizeof(buf), "Images.%d", x); |
| err = export_image(cgi, buf, path, name); |
| if (err) break; |
| } |
| uListDestroy(&files, ULIST_FREE); |
| if (err != STATUS_OK) return nerr_pass (err); |
| err = scale_images (cgi, "Images", thumb_width, thumb_height, 0); |
| if (err != STATUS_OK) return nerr_pass (err); |
| return STATUS_OK; |
| } |
| |
| NEOERR *dowork_image (CGI *cgi, char *image) |
| { |
| NEOERR *err = STATUS_OK; |
| int maxW = 0, maxH = 0; |
| char *basepath = ""; |
| char *cache_basepath = "/tmp/.imgcache/"; |
| char srcpath[_POSIX_PATH_MAX] = ""; |
| char cachepath[_POSIX_PATH_MAX] = ""; |
| char buf[256]; |
| char *if_mod; |
| int i, l, quality; |
| struct stat s; |
| struct tm *t; |
| |
| if ((i = hdf_get_int_value(cgi->hdf, "Query.width", 0)) != 0) { |
| maxW = i; |
| } |
| |
| if ((i = hdf_get_int_value(cgi->hdf, "Query.height", 0)) != 0) { |
| maxH = i; |
| } |
| quality = hdf_get_int_value(cgi->hdf, "Query.quality", 0); |
| |
| if_mod = hdf_get_value(cgi->hdf, "HTTP.IfModifiedSince", NULL); |
| |
| basepath = hdf_get_value(cgi->hdf, "BASEDIR", NULL); |
| if (basepath == NULL) |
| { |
| cgi_error (cgi, "No BASEDIR in imd file"); |
| return nerr_raise(CGIFinished, "Finished"); |
| } |
| |
| snprintf (srcpath, sizeof(srcpath), "%s/%s", basepath, image); |
| snprintf (cachepath, sizeof(cachepath), "%s/%dx%d/%s", cache_basepath, |
| maxW, maxH,image); |
| |
| if (stat(srcpath, &s)) |
| { |
| cgiwrap_writef("Status: 404\nContent-Type: text/html\n\n"); |
| cgiwrap_writef("File %s not found.", srcpath); |
| return nerr_raise_errno(NERR_IO, "Unable to stat file %s", srcpath); |
| } |
| |
| t = gmtime(&(s.st_mtime)); |
| if (if_mod && later_than(t, if_mod)) |
| { |
| cgiwrap_writef("Status: 304\nContent-Type: text/html\n\n"); |
| cgiwrap_writef("Use Local Copy"); |
| return STATUS_OK; |
| } |
| |
| /* fprintf(stderr,"cachepath: %s\n",cachepath); */ |
| |
| ne_warn("srcpath: %s", srcpath); |
| l = strlen(srcpath); |
| if ((l>4 && !strcasecmp(srcpath+l-4, ".jpg")) || |
| (l>4 && !strcasecmp(srcpath+l-4, ".thm")) || |
| (l>5 && !strcasecmp(srcpath+l-5, ".jpeg"))) |
| cgiwrap_writef("Content-Type: image/jpeg\n"); |
| else if (l>4 && !strcasecmp(srcpath+l-4, ".gif")) |
| cgiwrap_writef("Content-Type: image/gif\n"); |
| else if (l>4 && !strcasecmp(srcpath+l-4, ".avi")) |
| { |
| ne_warn("found avi"); |
| cgiwrap_writef("Content-Type: video/x-msvideo\n"); |
| } |
| t = gmtime(&(s.st_mtime)); |
| strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", t); |
| cgiwrap_writef("Last-modified: %s\n", buf); |
| |
| err = scale_and_display_image(srcpath,maxW,maxH,cachepath,quality); |
| return nerr_pass(err); |
| } |
| |
| int main(int argc, char **argv, char **envp) |
| { |
| NEOERR *err; |
| CGI *cgi; |
| char *image; |
| char *album; |
| char *imd_file; |
| char *cs_file; |
| char *picture; |
| |
| ne_warn("Starting IMD"); |
| cgi_debug_init (argc,argv); |
| cgiwrap_init_std (argc, argv, envp); |
| |
| nerr_init(); |
| |
| ne_warn("CGI init"); |
| err = cgi_init(&cgi, NULL); |
| if (err != STATUS_OK) |
| { |
| nerr_log_error(err); |
| cgi_destroy(&cgi); |
| return -1; |
| } |
| imd_file = hdf_get_value(cgi->hdf, "CGI.PathTranslated", NULL); |
| ne_warn("Reading IMD file %s", imd_file); |
| err = hdf_read_file (cgi->hdf, imd_file); |
| if (err != STATUS_OK) |
| { |
| cgi_neo_error(cgi, err); |
| nerr_log_error(err); |
| cgi_destroy(&cgi); |
| return -1; |
| } |
| |
| cs_file = hdf_get_value(cgi->hdf, "Template", NULL); |
| image = hdf_get_value(cgi->hdf, "Query.image", NULL); |
| album = hdf_get_value(cgi->hdf, "Query.album", ""); |
| picture = hdf_get_value(cgi->hdf, "Query.picture", NULL); |
| if (image) |
| { |
| err = dowork_image(cgi, image); |
| if (err) |
| { |
| nerr_log_error(err); |
| cgi_destroy(&cgi); |
| return -1; |
| } |
| } |
| else |
| { |
| if (!picture) |
| { |
| err = dowork_album (cgi, album); |
| } |
| else |
| { |
| err = dowork_picture (cgi, album, picture); |
| } |
| if (err != STATUS_OK) |
| { |
| if (nerr_handle(&err, CGIFinished)) |
| { |
| /* pass */ |
| } |
| else |
| { |
| cgi_neo_error(cgi, err); |
| nerr_log_error(err); |
| cgi_destroy(&cgi); |
| return -1; |
| } |
| } |
| else |
| { |
| err = cgi_display(cgi, cs_file); |
| if (err != STATUS_OK) |
| { |
| cgi_neo_error(cgi, err); |
| nerr_log_error(err); |
| cgi_destroy(&cgi); |
| return -1; |
| } |
| } |
| } |
| cgi_destroy(&cgi); |
| return 0; |
| } |