Plan 9 from Bell Labs’s /usr/web/sources/contrib/steve/root/sys/src/cmd/ip/httpd/webphoto.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include <fcall.h>
#include <libsec.h>
#include "httpd.h"
#include "httpsrv.h"

enum {
	Tpl = 7,	// # thumbnails per line
	Lpp = 4,	// # thumbnails lines per page
	Twid = 100,	// thumbnail width (pixels)
	Downwid = 16,	// width of down arrow on directories

			// file types in directory scan
	Tdull = 0,	// boring file
	Tdir,		// real directory
	Tphoto,		// virtual dir from photosrv
	Timage		// image (known extension)
};

Hio *hout;
static Hio houtb;
static HConnect	*connect;
static int vermaj;
static char *Magic = "exif is over-complex";
static char *Imgexts[] = { ".jpg", ".gif", ".png" };

char *Strapcolor = "#EFFFEF";		// acme title bar green
char *Rulercolor = "#428a42";		// acme ruler green
char *Textcolor = "black";
char *Bodycolor = "white";

/*********************************************************/

char *
path2text(char *path)
{
	int i;
	char *p, *s, *text;

	if((s = strrchr(path, '/')) == nil)
		s = path;
	else
		s++;
	text = strdup(s);
	if((p = strrchr(text, '.')) != nil)
		for(i = 0; i < nelem(Imgexts); i++)
			if(cistrcmp(p, Imgexts[i]) == 0){
				*p = 0;
				break;
			}
	if(isalpha(*text))
		*text = toupper(*text);
	return text;
}

char *
path2parent(char *path)
{
	char *p, *parent;

	parent = strdup(path);
	if(strcmp(parent, "/") == 0)
		return parent;
	if((p = strrchr(parent, '/')) != nil){
		if(p != parent)
			p[0] = 0;
		else
			p[1] = 0;
	}
	return parent;
}

char *
mkuri(char *fmt, ...)
{
	va_list a;
	char *r, *w, *p, *s, *t;

	va_start(a, fmt);
	s = vsmprint(fmt, a);
	va_end(a);

	// strip duplicate slashes
	p = "";	
	for(w = r = s; *r; r++){
		*w = *r;
		if(*p == '/' && *w == '/')
			continue;
		p = w++;
	}
	*w = 0;

	t = smprint("%U", s);
	free(s);
	return t;
}

int
filetype(Dir *d)
{
	int i;
	char *p;
	DigestState *ds;
	uchar hash[SHA1dlen];
	char muid[SHA1dlen*2];

	ds = sha1((uchar *)Magic, strlen(Magic), nil, nil);
	sha1((uchar *)d->name, strlen(d->name), hash, ds);
	snprint(muid, sizeof(muid), "%.*[", 8, hash);
	if(strcmp(muid, d->muid) == 0)
		return Tphoto;

	if((p = strrchr(d->name, '.')) != nil)
		for(i = 0; i < nelem(Imgexts); i++)
			if(cistrcmp(p, Imgexts[i]) == 0)
				return Timage;

	if((d->mode & DMDIR) == 0)
		return Tdull;
	return Tdir;
}

/*********************************************************/

/*
 * couldn't open a file
 * figure out why and return and error message
 */
static int
notfound(char *path)
{
	connect->xferbuf[0] = 0;
	errstr(connect->xferbuf, sizeof connect->xferbuf);

	if(strstr(connect->xferbuf, "file does not exist") != nil)
		return hfail(connect, HNotFound, path);

	if(strstr(connect->xferbuf, "permission denied") != nil)
		return hfail(connect, HUnauth, path);

	return hfail(connect, HNotFound, path);
}

static void
prelude(char *title, char *icon)
{
	if (vermaj) {
		hokheaders(connect);
		hprint(hout, "Content-type: text/html\n");
		hprint(hout, "\n");
	}
	hprint(hout, "\n");
	hprint(hout, "<html>\n");
	hprint(hout, "<head>\n");
	hprint(hout, "<title>%s</title>\n", title);

	if(icon)
		hprint(hout, " <link rel='SHORTCUT ICON' href='%s'>\n", icon);

	hprint(hout, "</head>\n");
	hprint(hout, "<body text='%s' bgcolor='%s' topmargin='0' " 
		"leftmargin='0' marginwidth='0' marginheight='0'>\n", Textcolor, Bodycolor);

	/*
	 * A crude attempt at stopping people from snatching our pictures
	 * doesn't really work but discourages the dull masses.
	 */
	hprint(hout, "\n");
	hprint(hout, "<meta http-equiv='imagetoolbar' content='false'>\n");
	hprint(hout, "<div>\n");
	hprint(hout, "<script type='text/javascript' language=JavaScript>\n");
	hprint(hout, "var message='&copy; Copyright, all rights reserved';\n");
	hprint(hout, "function click(e) {\n");
	hprint(hout, " if (document.all) {\n");
	hprint(hout, "  if (event.button == 2) {\n");
	hprint(hout, "   alert(message);\n");
	hprint(hout, "  return false;\n");
	hprint(hout, "  }\n");
	hprint(hout, " }\n");
	hprint(hout, " if (document.layers) {\n");
	hprint(hout, "  if (e.which == 3) {\n");
	hprint(hout, "   alert(message);\n");
	hprint(hout, "   	return false;\n");
	hprint(hout, "  }\n");
	hprint(hout, " }\n");
	hprint(hout, " }\n");
	hprint(hout, " if (document.layers) {\n");
	hprint(hout, "  document.captureEvents(Event.MOUSEDOWN);\n");
	hprint(hout, " }\n");
	hprint(hout, " document.onmousedown=click;\n");
	hprint(hout, "</script>\n");
	hprint(hout, "</div>\n");

}

static void
prologue(void)
{
	hprint(hout, "</body>\n");
	hprint(hout, "</html>\n");
}



static void
framenav(char *path, char *names[3], int page, int npages)
{
	char *title, *uri;

	hprint(hout, "\n");
	hprint(hout, "<table frame='below' rules='none' border='2' bordercolor='%s'"
		"bgcolor='%s' width='100%%' >\n", Rulercolor, Strapcolor);
	hprint(hout, " <tr height='34'>\n");

	title = path2text(path);
	hprint(hout, " <td>\n");
	hprint(hout, "  <font face='ARIAL, HELVETICA, GENEVA' size='5'>\n");
	hprint(hout, "   %s\n", title);
	hprint(hout, "  </font>\n");
	hprint(hout, " </td>\n");
	free(title);

	hprint(hout, " <td align='right' >\n");
	hprint(hout, "  <font face='ARIAL, HELVETICA, GENEVA' size='3'>\n");
	hprint(hout, "   %d/%d\n", page, npages);
	hprint(hout, "  </font>\n");
	hprint(hout, " </td>\n");

	hprint(hout, " <td align='right' width='34' >\n");
	if(names[0]){
		uri = mkuri("/magic/webphoto?frame=%s/%s", path, names[0]);
		hprint(hout, "  <a href='%H'>\n", uri);
		hprint(hout, "   <img border='0' alt='Previous' "
			"src='/nav/left-arrow.gif' />\n");
		hprint(hout, "  </a>\n");
		free(uri);
	}
	else
		hprint(hout, " &nbsp;\n");
	hprint(hout, " </td>\n");

	uri = mkuri("/magic/webphoto?dir=%s", path);
	hprint(hout, " <td align='right' width='34' >\n");
	hprint(hout, "  <a href='%H?page=%d'>\n", uri,  (page + ((Tpl * Lpp)-1)) /(Tpl * Lpp));
	hprint(hout, "   <img  border='0' alt='Index' src='/nav/up-arrow.gif' />\n");
	hprint(hout, "  </a>\n");
	hprint(hout, " </td>\n");
	free(uri);

	hprint(hout, " <td align='right' width='34' >\n");
	if(names[2]){
		uri = mkuri("/magic/webphoto?frame=%s/%s", path, names[2]);
		hprint(hout, "  <a href='%H'>\n", uri);
		hprint(hout, "   <img border='0' alt='Next' "
			"src='/nav/right-arrow.gif' />\n");
		hprint(hout, "  </a>\n");
		free(uri);
	}
	else
		hprint(hout, " &nbsp;\n");
	hprint(hout, " </td>\n");
	hprint(hout, " </tr>\n");

	hprint(hout, "</table>\n");
	hprint(hout, "<br>\n");
}

static void
doframe(char *path, char *file, int type)
{
	char *p, *name, *alt, *uri, *nuri;

	/* top edge of drop shadow */
	hprint(hout, "\n");
	hprint(hout, "<center>\n");
	hprint(hout, "<table summary='' border='0' cellspacing='0' cellpadding='0'>\n");
	hprint(hout, "<tr>\n");
	hprint(hout, " <td width='30'>\n");
	hprint(hout, "  <p><img src='/nav/top-left.gif' "
		"width='30' height='30' align='bottom'></p>\n");
	hprint(hout, " </td>\n");
	hprint(hout, " <td align='bottom' background='/nav/top-edge.gif' >\n");
	hprint(hout, "  <p>&nbsp;</p>\n");
	hprint(hout, " </td>\n");
	hprint(hout, " <td width='30'>\n");
	hprint(hout, "  <p><img src='/nav/top-right.gif' "
		"width='30' height='30' align='bottom'></p>\n");
	hprint(hout, " </td>\n");
	hprint(hout, "</tr>\n");

	alt = "Click for metadata";
	name = path2text(file);
	if(type == Tphoto){
		if((p = strrchr(file, '.')) == nil)
			p = "";
		uri = mkuri("/magic/webphoto?image=%s/%s/fullsize%s", path, file, p);
	}
	else
		uri = mkuri("/magic/webphoto?image=%s/%s", path, file);
	nuri = mkuri("/magic/webphoto?metadata=%s/%s", path, file);

	/* image and sides of drop shadow */
	hprint(hout, "\n");
	hprint(hout, "<tr>\n");
	hprint(hout, " <td background='/nav/left-edge.gif' width='30'>\n");
	hprint(hout, "  <p>&nbsp;</p>\n");
	hprint(hout, " </td>\n");

	hprint(hout, " <td>\n");
	hprint(hout, "  <font face='ARIAL, HELVETICA, GENEVA' color='black'>\n");
	hprint(hout, "    <a href='%H'><img src='%H' alt='%s' border='0'></a>\n", nuri, uri, alt);
	hprint(hout, "   </font>\n");
	hprint(hout, "  <br>\n");
	hprint(hout, "  <p align='left'>");
	hprint(hout, "   <font face='ARIAL, HELVETICA, GENEVA' size='3'>\n");
	hprint(hout, "    %s", name);
	hprint(hout, "   </font>\n");
	hprint(hout, "  </p>\n");
	hprint(hout, " </td>\n");

	hprint(hout, " <td background='/nav/right-edge.gif' width='30'>\n");
	hprint(hout, "  <p align='right'>&nbsp;</p>\n");
	hprint(hout, " </td>\n");
	hprint(hout, "</tr>\n");

	free(name);
	free(uri);
	free(nuri);

	/* bottom edge of drop shadow */
	hprint(hout, "\n");
	hprint(hout, "<tr>\n");
	hprint(hout, " <td width='30' height='30'>\n");
	hprint(hout, "  <p><img src='/nav/bottom-left.gif' "
		"width='30' height='30' align='bottom'></p>\n");
	hprint(hout, " </td>\n");
	hprint(hout, " <td align='center' valign='bottom' "
		"background='/nav/bottom-edge.gif' height='30'>\n");
	hprint(hout, "  <p>&nbsp;</p>\n");
	hprint(hout, " </td>\n");
	hprint(hout, " <td width='30' height='30'>\n");
	hprint(hout, "  <p align='right'><img src='/nav/bottom-right.gif' "
		"width='30' height='30' align='bottom'></p>\n");
	hprint(hout, " </td>\n");
	hprint(hout, "</tr>\n");
	hprint(hout, "</table>\n");
	hprint(hout, "</center>\n");
}

char *
probedir(char *path, char *dir)
{
	Dir *d;
	int i, type, n, fd;
	char *p, *fn, *first;

	fn = smprint("%s/%s", path, dir);
	if((fd = open(fn, OREAD)) == -1){
		free(fn);
		return nil;
	}
	if((n = dirreadall(fd, &d)) < 1){
		free(fn);
		close(fd);
		return nil;
	}

	type = -1;
	for(i = 0; i < n; i++){
		type = filetype(&d[i]);
		if(type == Tphoto || type == Timage)
			break;
	}
	if(i < n){
		if(type == Tphoto){
			if((p = strrchr(d[i].name, '.')) == nil)
				p = "";
			first = mkuri("/magic/webphoto?thumb=%s/%s/%s/thumbnail%s", path, dir, d[i].name, p);
		}
		else
			first = mkuri("/magic/webphoto?thumb=%s/%s/%s", path, dir, d[i].name);
	}
	else
		first = mkuri("/nav/query.jpg");

	free(d);
	free(fn);
	return first;
}

void
dodir(char *path, char **files, int *types)
{
	int i;
	char *p, *alt, *name, *img, *uri, *nuri;

	hprint(hout, "<table border='0' cellspacing='8' cellpadding='8'>\n");
	hprint(hout, "<font face='ARIAL, HELVETICA, GENEVA' size='2'>");
	hprint(hout, "<tr>\n");

	hprint(hout, " <td align='center' width='50'>\n");
	hprint(hout, " </td>\n");

	for(i = 0; i < Tpl; i++){
		if(files[i] == nil)
			continue;
		hprint(hout, " <td align='center' valign='middle'>\n");
		name = path2text(files[i]);
		switch(types[i]){
		case Tdir:
			alt = "Click for album contents";
			if((img = probedir(path, files[i])) == nil)
				img = strdup("/nav/query.jpg");
			uri = mkuri("/magic/webphoto?dir=%s/%s", path, files[i]);
			hprint(hout, "  <a href='%H'>\n", uri);
			hprint(hout, "   <img border='0' alt='%s' width='%d' "
				"src='%s' /><br>%s\n", alt, Twid, img, name);
			hprint(hout, "   <img border='0' alt='%s' width='%d' "
				"src='/nav/down-arrow.gif' />\n", name, Downwid);
			hprint(hout, "  </a>\n");
			free(uri);
			break;
		case Timage:
			alt = "Click for larger image";
			uri = mkuri("/magic/webphoto?frame=%s/%s", path, files[i]);
			nuri = mkuri("/magic/webphoto?thumb=%s/%s", path, files[i]);
			hprint(hout, "  <a href='%H'>\n", uri);
			hprint(hout, "   <img  border='0' alt='%s' width='%d' src='%H' /><br>%s",
				alt, Twid, nuri, name);
			hprint(hout, "  </a>\n");
			free(uri);
			free(nuri);
			break;
		case Tphoto:
			alt = "Click for larger image";
			if((p = strrchr(files[i], '.')) == nil)
				p = "";
			uri = mkuri("/magic/webphoto?frame=%s/%s", path, files[i]);
			nuri = mkuri("/magic/webphoto?image=%s/%s/thumbnail%s", path, files[i], p);
			hprint(hout, "  <a href='%H'>\n", uri);
			hprint(hout, "   <img  border='0' alt='%s' width='%d' src='%H' /><br>%s",
				alt, Twid, nuri, name);
			hprint(hout, "  </a>\n");
			free(uri);
			free(nuri);
			break;
		default:
			alt = "Unknown";
			uri = mkuri("/magic/webphoto?image=%s/%s", path, files[i]);
			hprint(hout, "  <a href='%H'>", uri);
			hprint(hout, "   <img border='0' alt='%s' width='%d' src='/nav/query.jpg'/><br>%s",
				alt, Twid, name);
			hprint(hout, "  </a>\n");
			free(uri);
			break;
		}
		hprint(hout, " </td>\n");
		free(name);
	}
	hprint(hout, " <td align='center' width='50'>\n");
	hprint(hout, " </td>\n");

	hprint(hout, "</tr>\n");
	hprint(hout, "</font>");
	hprint(hout, "</table>\n");
}

static void
dirnav(char *path, char *parent, int page, int npages)
{
	char *title, *uri;

	hprint(hout, "\n");
	hprint(hout, "\n");

	hprint(hout, "<table border='2' frame='below' rules='none' bordercolor='%s'"
		"bgcolor='%s' width='100%%' >\n", Rulercolor, Strapcolor);
	hprint(hout, " <tr height='34'>\n");

	title = path2text(path);
	hprint(hout, " <td>\n");
	hprint(hout, "  <font face='ARIAL, HELVETICA, GENEVA' size='5'>\n");
	hprint(hout, "   %s\n", title);
	hprint(hout, "  </font>\n");
	hprint(hout, " </td>\n");
	free(title);

	hprint(hout, " <td align='right' >\n");
	hprint(hout, "  <font face='ARIAL, HELVETICA, GENEVA' size='3'>\n");
	hprint(hout, "   %d/%d\n", page, npages);
	hprint(hout, "  </font>\n");
	hprint(hout, " </td>\n");

	hprint(hout, " <td align='right' width='34' >\n");
	if(page > 1){
		uri = mkuri("/magic/webphoto?dir=%s", path);
		hprint(hout, "  <a href='%H?page=%d'>\n", uri, page-1);
		hprint(hout, "   <img border='0' alt='Previous' "
			"src='/nav/left-arrow.gif' />\n");
		hprint(hout, "  </a>\n");
		free(uri);
	}
	else
		hprint(hout, " &nbsp;\n");
	hprint(hout, " </td>\n");

	hprint(hout, " <td align='right' width='34' >\n");
	uri = mkuri("/magic/webphoto?dir=%s", parent);
	hprint(hout, "  <a href='%H'>\n", uri);
	hprint(hout, "   <img border='0' alt='Index' src='/nav/up-arrow.gif' />\n");
	hprint(hout, "  </a>\n");
	free(uri);
	hprint(hout, " </td>\n");

	hprint(hout, " <td align='right' width='34' >\n");
	if(page < npages){
		uri = mkuri("/magic/webphoto?dir=%s", path);
		hprint(hout, "  <a href='%H?page=%d'>\n", uri, page+1);
		hprint(hout, "   <img border='0' alt='Next'"
			"src='/nav/right-arrow.gif' />\n");
		hprint(hout, "  </a>\n");
		free(uri);
	}
	else
		hprint(hout, " &nbsp;\n");
	hprint(hout, " </tr>\n");

	hprint(hout, "</table>\n");
	hprint(hout, "<br>\n");
}


/*************************************************/

int
frame(char *path)
{
	Dir *d;
	int i, n, tot, idx, fd, t, types[3];
	char *title, *file, *names[3];

	if((file = strrchr(path, '/')) == nil){
		hfail(connect, HBadReq);
		exits("missing slash");
	}
	if(file == path){	// root dir is special
		file++;
		path = "/";
	}
	else{
		*file++ = 0;
	}

	if((fd = open(path, OREAD)) == -1){
		notfound(path);
		exits("not found");
	}
	if((n = dirreadall(fd, &d)) < 1){
		notfound(path);
		exits("not found");
	}

	title = path2text(path);
	prelude(title, "/favicon.ico");
	free(title);

	tot = 0;
	for(i = 0; i < n; i++)
		switch(filetype(&d[i])){
		case Tphoto:
		case Timage:
			tot++;
		}

	idx = 0;
	memset(types, 0, sizeof(types));
	memset(names, 0, sizeof(names));
	for(i = 0; i < n; i++){
		t = filetype(&d[i]);
		if(t != Timage && t != Tphoto)
			continue;
		types[2] = t;
		names[2] = d[i].name;

		if(names[1] && strcmp(names[1], file) == 0){
			framenav(path, names, idx, tot);
			doframe(path, names[1], types[1]);
			break;
		}
		memcpy(types, &types[1], sizeof(types) - sizeof(types[0]));
		memcpy(names, &names[1], sizeof(names) - sizeof(names[0]));
		names[2] = nil;
		types[2] = 0;
		idx++;
	}

	if(i >= n && names[1] && strcmp(names[1], file) == 0){
		framenav(path, names, idx, tot);
		doframe(path, names[1], types[1]);
	}

	prologue();
	close(fd);
	free(d);
	return 0;
}

	
void
dir(char *path)
{
	Dir *d;
	char *str, *title, *parent, *names[Tpl];
	int i, j, n, fd, page, npages, types[Tpl];

	page = 1;
	if((str = strchr(path, '?')) != 0){
		*str++ = 0;
		if(strncmp(str, "page=", 5) != 0){
			hfail(connect, HSyntax);
			exits("request syntax");
		}
		str = hurlunesc(connect, str+5);
		page = atoi(str);
	}

	if((fd = open(path, OREAD)) == -1){
		notfound(path);
		exits("not found");
	}
	if((n = dirreadall(fd, &d)) == -1){
		notfound(path);
		exits("not found");
	}

	npages = (n + ((Tpl * Lpp)-1)) /(Tpl * Lpp);

	if(page < 1 || page > npages){
		hfail(connect, HBadReq);
		exits("bad request");
	}

	title = path2text(path);
	prelude(title, "/favicon.ico");
	free(title);

	parent = path2parent(path);
	dirnav(path, parent, page, npages);
	free(parent);

	for(i = (page-1)*Tpl*Lpp; i < n && i < page*Tpl*Lpp;){
		memset(names, 0, sizeof(names));
		memset(types, 0, sizeof(types));
		for(j = 0; j < Tpl && i < n; i++){
			names[j] = d[i].name;
			types[j] = filetype(&d[i]);
			if(types[j] == Tdull)
				continue;
			j++;
		}
		dodir(path, names, types);
	}

	prologue();
	close(fd);
	free(d);
}

void
image(char *path)
{
	int fd;
	Dir *d;

	if((fd = open(path, OREAD)) == -1){
		notfound(path);
		exits("not found");
	}
	if((d = dirstat(path)) == nil){
		notfound(path);
		exits("not found");
	}
	/* generate mime type from file extension in request */
	connect->req.uri = connect->req.search;
	sendfd(connect, fd, d, nil, nil);
}

void
metadata(char *path)
{
	Dir *d;
	Biobuf *bp;
	int type, lines;
	char *p, *q;
	char *alt, *title, *parent, *uri, *meta;

	if((d = dirstat(path)) == nil){
		notfound(path);
		exits("not found");
	}
	type = filetype(d);
	free(d);

	alt = "Full size image";
	title = path2text(path);
	parent = path2parent(path);

	prelude(title, "/favicon.ico");

	/* navigation bar */
	hprint(hout, "\n");
	hprint(hout, "<table frame='below' rules='none' border='2' bordercolor='%s'"
		"bgcolor='%s' width='100%%' >\n", Rulercolor, Strapcolor);
	hprint(hout, " <tr height='34'>\n");

	hprint(hout, " <td>\n");
	hprint(hout, "  <font face='ARIAL, HELVETICA, GENEVA' size='5'>\n");
	hprint(hout, "   %H\n", title);
	hprint(hout, "  </font>\n");
	hprint(hout, " </td>\n");

	hprint(hout, " <td width='34'>\n");
	hprint(hout, " </td>\n");

	hprint(hout, " <td align='right' width='34'>\n");
	uri = mkuri("/magic/webphoto?frame=%s", path);
	hprint(hout, "  <a href='%H'>\n", uri);
	hprint(hout, "   <img  border='0' alt='%s' src='/nav/up-arrow.gif' />\n", alt);
	hprint(hout, "  </a>\n");
	free(uri);
	hprint(hout, " </td>\n");

	hprint(hout, " <td align='right' width='34'>\n");
	hprint(hout, " </tr>\n");

	hprint(hout, "</table>\n");
	hprint(hout, "<br>\n");

	free(parent);
	free(title);

	/* page body */
	hprint(hout, "<table border='0' bgcolor='%s' width='100%%' >\n", Bodycolor);
	hprint(hout, " <tr>\n");
	hprint(hout, " <td align='center' width='30%%'>\n");
	if(type == Tphoto)
		uri = mkuri("/magic/webphoto?image=%s/thumbnail.jpg", path);
	else
		uri = mkuri("/magic/webphoto?image=%s", path);
	hprint(hout, "   <img  border='0' width='%d' src='%H' />\n", Twid, uri);
	hprint(hout, " </td>\n");
	hprint(hout, "  <td align='center' >\n");

	hprint(hout, "  <table border='0' bgcolor='%s' ' >\n", Bodycolor);
	hprint(hout, "  <font face='ARIAL, HELVETICA, GENEVA' size='3'>\n");
	hprint(hout, "   <tr>\n");
	hprint(hout, "   <td >\n");
	hprint(hout, "      &nbsp;\n");
	hprint(hout, "   </td>\n");
	hprint(hout, "   </tr>\n");

	lines = 0;
	meta = smprint("%s/metadata", path);
	if((bp = Bopen(meta, OREAD)) != nil){
		while((p = Brdline(bp, '\n')) != nil){
    			lines++;

			p[Blinelen(bp) -1] = 0;
			if((q = strchr(p, ':')) != nil)
				*q++ = 0;
			hprint(hout, " <tr>\n");
	
			hprint(hout, " <td align='left' width='60%%'>\n");
			hprint(hout, "     %s\n", p);
			hprint(hout, "  </td>\n");
			if(q){
				while(*q && isspace(*q))
					q++;
				hprint(hout, " <td align='left'>\n");
				hprint(hout, "     %s\n", q);
				hprint(hout, "  </td>\n");
			}
			hprint(hout, " </tr>\n");
		}
		Bterm(bp);
	}
	free(meta);
	if(lines == 0){
		hprint(hout, "   <tr>\n");
		hprint(hout, "   <td >\n");
		hprint(hout, "      No EXIF metadata\n");
		hprint(hout, "   </td>\n");
		hprint(hout, "   </tr>\n");
	}

	hprint(hout, " </font>\n");
	hprint(hout, "  </table>\n");
	
	hprint(hout, " </td>\n");
	hprint(hout, " </tr>\n");
	hprint(hout, "</table>\n");

	prologue();
	hflush(hout);
}

void
photo(char *str)
{
	if (strncmp(str, "frame=", 6) == 0){
		str = hurlunesc(connect, str+6);
		frame(str);
		return;
	}
	if (strncmp(str, "dir=", 4) == 0){
		str = hurlunesc(connect, str+4);
		dir(str);
		return;
	}
	if (strncmp(str, "image=", 6) == 0){
		str = hurlunesc(connect, str+6);
		image(str);
		return;
	}
	if (strncmp(str, "thumb=", 6) == 0){
		str = hurlunesc(connect, str+6);
		image(str);
		return;
	}
	if (strncmp(str, "metadata=", 9) == 0){
		str = hurlunesc(connect, str+9);
		metadata(str);
		return;
	}
	hfail(connect, HBadReq);
}

void
main(int argc, char *argv[])
{
	fmtinstall('H', httpfmt);
	fmtinstall('U', hurlfmt);
	fmtinstall('M', dirmodefmt);
	fmtinstall('[', encodefmt);

	close(2);
	connect = init(argc, argv);
	hout = &connect->hout;
	vermaj = connect->req.vermaj;
	if(hparseheaders(connect, HSTIMEOUT) < 0)
		exits("failed");

	if(connect->head.expectother || connect->head.expectcont){
		hfail(connect, HExpectFail, nil);
		exits("failed");
	}

	contentinit();

	bind("/usr/photos", "/", MREPL);

	if(connect->req.search != nil)
		photo(connect->req.search);
	else
		hfail(connect, HSyntax);
	hflush(hout);
	writelog(connect, "200 webphoto %ld %ld\n", hout->seek, hout->seek);
	exits(nil);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.