File: thumbview.pike

package info (click to toggle)
libroxen-thumbview 1.1-3
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 32 kB
  • sloc: makefile: 38
file content (308 lines) | stat: -rw-r--r-- 7,437 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
/*
 * A directory listing module which displays files in an x-column table
 * and creates thumbnails of any images present in the supported formats.
 *
 * Owes a great deal to the fast directory lister module of Roxen 1.3, and
 * a thumbnail module written by Chris Jantzen (chris@maybe.net).
 *
 * Could be cleaned up a lot, but hey, it works.
 *
 * Author: Petter E. Stokke <gibreel@nettstudio.no>
 *
 */

// This is for debug output
//#define RETURN_ERROR(x) http_string_answer(x)
#define RETURN_ERROR(x) 0

constant cvs_version = "$Id: thumbview.pike,v 1.1 2000/06/07 17:46:45 gibreel Exp $";
int thread_safe=1;

#include <module.h>
inherit "module";
inherit "roxenlib";

import Image;

/************** Generic module stuff ***************/

// Required functions for Roxen modules--

int usecount;

string starttime = ctime(time());

string status()
{
   return "Called " + usecount + " times since " + starttime;
}

string query_location()
{
  return query("mountpoint");
}

array register_module()
{
  return ({ MODULE_DIRECTORIES | MODULE_LOCATION, 
	    "Thumbnail directory module",
	    "Displays a thumbnail overview of pictures in directories.", 
	    ({ }), 
	    1
         });
}

void create()
{
  defvar("indexfiles", ({ "index.html", "Main.html", "welcome.html", }),
	 "Index files", TYPE_STRING_LIST,
	 "If one of these files is present in a directory, it will "
	 "be returned instead of the overview.");

  defvar("readme", 1, "Include readme files", TYPE_FLAG,
	 "If set, include readme files in directory listings");

  defvar("override", 0, "Allow directory index file overrides", TYPE_FLAG,
	 "If this variable is set, you can get a listing of all files "
	 "in a directory by appending '.' or '/' to the directory name, like "
	 "this: <a href=http://www.roxen.com//>http://www.roxen.com//</a>"
	 ". It is _very_ useful for debugging, but some people regard it as a "
	 "security hole.");

  defvar("mountpoint", "/thumbview/", "Mount point", TYPE_LOCATION, 
	 "Thumbnail result location in virtual filesystem "
	 "(trailing slash important).");

  defvar("thumbsize", 80, "Thumbnail size", TYPE_INT, 
	 "Size of generated thumbnails. This is either the X size or the Y size, depending on which is larger.");

  defvar("columns", 6, "Number of columns", TYPE_INT, 
	 "The number of columns in the generated table view.");

  defvar("cmapsize", 64, "GIF colourmap size", TYPE_INT, 
	 "The size of the colourmap of the generated GIF thumbnails. Must be a multiple of 2, and maximum 256.");
}

/*  Module specific stuff */


#define TYPE_MP  "    Module location"
#define TYPE_DIR "    Directory"


inline string image(string f) 
{ 
  return ("<img border=0 src="+(f)+" alt=>"); 
}

inline string link(string a, string b) 
{ 
  return ("<a href="+replace(b, ({ "//", "#" }), ({ "/", "%23" }))
	  +">"+a+"</a>"); 
}

string find_readme(string path, object id)
{
  string rm, f;
  object n;
  foreach(({ "README.html", "README" }), f)
  {
    rm=roxen->try_get_file(path+f, id);
    if(rm) if(f[-1] == 'l')
      return "<hr noshade>"+rm;
    else
      return "<pre><hr noshade>"+
	replace(rm, ({"<",">","&"}), ({"&lt;","&gt;","&amp;"}))+"</pre>";
  }
  return "";
}

string head(string path,object id)
{
  string rm="";

  if(QUERY(readme)) 
    rm=find_readme(path,id);

  return ("<h1>Directory listing of "+path+"</h1>\n<p>"+rm
	  +"<pre>\n<hr noshade>");
}

string describe_dir_entry(string path, string filename, array stat, object id)
{
    string type, icon;
    int len;
    
    if(!stat)
	return "";
    
    switch(len=stat[1])
    {
    case -3:
	type = TYPE_MP;
	icon = "internal-gopher-menu";
	filename += "/";
	break;
	
    case -2:
	type = TYPE_DIR;
	filename += "/";
	icon = "internal-gopher-menu";
	break;
	
    default:
	array tmp;
	string buf;
	buf = id->conf->try_get_file("/thumbview/foo"+path+filename,id);
	if (buf) {
	    return link(image("/thumbview/foo"+path+filename),http_encode_string(path+filename));
	}
	tmp = roxen->type_from_filename(filename, 1);
	if(!tmp)
	    tmp=({ "Unknown", 0 });
	type = tmp[0];
	icon = image_from_type(type);
	if(tmp[1])  type += " " + tmp[1];
    }
    return sprintf("%s<br>%s",
		   link(image(icon), http_encode_string(path + filename)),
		   link(filename[0..15],http_encode_string(path + filename)));
}

static private string key;

void start()
{
    key="file:"+roxen->current_configuration->name;
}

string new_dir(string path, object id)
{
    int i,c;
    array files;
    string fname,foo = "<center><table border=0 cellpadding=8>";
    
    c = QUERY(columns);

    files = roxen->find_dir(path, id);
    if(!files) return "<h1>There is no such directory.</h1>";
    sort(files);
    
    for(i=0; i<sizeof(files) ; i++)
    {
	fname = replace(path+files[i], "//", "/");
	files[i] = describe_dir_entry(path,files[i],roxen->stat_file(fname, id),id);
    }
    for (i=0;i<sizeof(files);i++) {
	if (i % c == 0) foo += "<tr>";
	foo += "<td align=\"center\">" + files[i] + "</td>";
	if (i % c == (c-1)) foo += "</tr>";
    }
    if (sizeof(files) % c) foo += "</tr>";
    return foo+"</table></center>";
}

mapping parse_directory(object id)
{
  string f;
  string dir;
  array indexfiles;

  f=id->not_query;

  if(strlen(f) > 1)
  {
    if(!((f[-1] == '/') ||
	 (QUERY(override) && (f[-1] == '.') && (f[-2] == '/'))))
      return http_redirect(id->not_query+"/", id);
  } else {
    if(f != "/" )
      return http_redirect(id->not_query+"/", id);
  }

  // At this point the last character is either
  // a '.' in which case we should give a directory listing,
  // or a '/' in which case we should search for an index-file.
  if(f[-1] == '/') /* Handle indexfiles */
  {
    string file;
    foreach(query("indexfiles") - ({""}), file) {
      if(roxen->stat_file(f+file, id))
      {
	id->not_query = f + file;
	mapping got = roxen->get_file(id);
	if (got) {
	  return(got);
	}
      }
    }
    // Restore the old query.
    id->not_query = f;
  }

  if (f[-1] == '.') {
    // Remove the override '.'.
    f = f[..sizeof(f)-2];
  }
  
  if(id->pragma["no-cache"] || !(dir = cache_lookup(key, f))) {
    cache_set(key, f, dir=new_dir(f, id));
  }
  return http_string_answer(head(f, id) + dir);
}


// MODULE_LOCATION functions
mapping find_file(string fn, object id)
{
    string f;

//  return http_string_answer(" foo '"+f+"' bar '"+filename+"' ");

    if (sscanf(fn,"foo%s",f) != 1)
	return RETURN_ERROR("Invalid URL: '"+fn+"'.");

    // Retrieve thumbnail from cache. Load and scale, if it fails.
    object result = cache_lookup("thumbview", f);

    if(!result) {

	int err;
	mixed t;
	string buff;
	
	buff = id->conf->try_get_file(f,id);
	
	if(!buff)
	    return RETURN_ERROR("Can't read file '"+f+"'.");

	object ourimage;
	
	if(catch(ourimage = Image.JPEG.decode(buff))) {
	    if(catch(ourimage = Image.PNG.decode(buff))) {
		if(catch(ourimage = Image.GIF.decode(buff))) {
		    if(catch(ourimage = Image.PNM.decode(buff))) {
			return RETURN_ERROR("Image is not in one of the supported image formats.");
		    }
		}
	    }
	}
	
	float xsize = (float) ourimage->xsize();
	float ysize = (float) ourimage->ysize();
	float scale = 0;

	if (xsize > ysize) {
	    scale = (float)QUERY(thumbsize) / xsize;
	} else {
	    scale = (float)QUERY(thumbsize) / ysize;
	}
	
	result = ourimage->scale(scale);
	
	cache_set("thumbview", f, result);
    }
    
    return http_string_answer(GIF.encode(result,QUERY(cmapsize)), "image/gif");
}