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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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