Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <bio.h>
4
#include "httpd.h"
5
#include "httpsrv.h"
6
 
7
static	Hio		*hout;
8
static	Hio		houtb;
9
static	HConnect	*connect;
10
 
11
void	doconvert(char*, int);
12
 
13
void
14
error(char *title, char *fmt, ...)
15
{
16
	va_list arg;
17
	char buf[1024], *out;
18
 
19
	va_start(arg, fmt);
20
	out = vseprint(buf, buf+sizeof(buf), fmt, arg);
21
	va_end(arg);
22
	*out = 0;
23
 
24
	hprint(hout, "%s 404 %s\n", hversion, title);
25
	hprint(hout, "Date: %D\n", time(nil));
26
	hprint(hout, "Server: Plan9\n");
27
	hprint(hout, "Content-type: text/html\n");
28
	hprint(hout, "\n");
29
	hprint(hout, "<head><title>%s</title></head>\n", title);
30
	hprint(hout, "<body><h1>%s</h1></body>\n", title);
31
	hprint(hout, "%s\n", buf);
32
	hflush(hout);
33
	writelog(connect, "Reply: 404\nReason: %s\n", title);
34
	exits(nil);
35
}
36
 
37
typedef struct Hit	Hit;
38
struct Hit 
39
{
40
	Hit *next;
41
	char *file;
42
};
43
 
44
void
45
lookup(char *object, int section, Hit **list)
46
{
47
	int fd;
48
	char *p, *f;
49
	Biobuf b;
50
	char file[256];
51
	Hit *h;
52
 
53
	while(*list != nil)
54
		list = &(*list)->next;
55
 
56
	snprint(file, sizeof(file), "/sys/man/%d/INDEX", section);
57
	fd = open(file, OREAD);
58
	if(fd > 0){
59
		Binit(&b, fd, OREAD);
60
		for(;;){
61
			p = Brdline(&b, '\n');
62
			if(p == nil)
63
				break;
64
			p[Blinelen(&b)-1] = 0;
65
			f = strchr(p, ' ');
66
			if(f == nil)
67
				continue;
68
			*f++ = 0;
69
			if(strcmp(p, object) == 0){
70
				h = ezalloc(sizeof *h);
71
				*list = h;
72
				h->next = nil;
73
				snprint(file, sizeof(file), "/%d/%s", section, f);
74
				h->file = estrdup(file);
75
				close(fd);
76
				return;
77
			}
78
		}
79
		close(fd);
80
	}
81
	snprint(file, sizeof(file), "/sys/man/%d/%s", section, object);
82
	if(access(file, 0) == 0){
83
		h = ezalloc(sizeof *h);
84
		*list = h;
85
		h->next = nil;
86
		h->file = estrdup(file+8);
87
	}
88
}
89
 
90
void
91
manindex(int sect, int vermaj)
92
{
93
	int i;
94
 
95
	if(vermaj){
96
		hokheaders(connect);
97
		hprint(hout, "Content-type: text/html\r\n");
98
		hprint(hout, "\r\n");
99
	}
100
 
101
	hprint(hout, "<head><title>plan 9 section index");
102
	if(sect)
103
		hprint(hout, "(%d)\n", sect);
104
	hprint(hout, "</title></head><body>\n");
105
	hprint(hout, "<H6>Section Index");
106
	if(sect)
107
		hprint(hout, "(%d)\n", sect);
108
	hprint(hout, "</H6>\n");
109
 
110
	if(sect)
111
		hprint(hout, "<p><a href=\"/plan9/man%d.html\">/plan9/man%d.html</a>\n",
112
			sect, sect);
113
	else for(i = 1; i < 10; i++)
114
		hprint(hout, "<p><a href=\"/plan9/man%d.html\">/plan9/man%d.html</a>\n",
115
			i, i);
116
	hprint(hout, "</body>\n");
117
}
118
 
119
void
120
man(char *o, int sect, int vermaj)
121
{
122
	int i;
123
	Hit *list;
124
 
125
	list = nil;
126
 
127
	if(*o == 0){
128
		manindex(sect, vermaj);
129
		return;
130
	}
131
 
132
	if(sect > 0 && sect < 10)
133
		lookup(o, sect, &list);
134
	else
135
		for(i = 1; i < 9; i++)
136
			lookup(o, i, &list);
137
 
138
	if(list != nil && list->next == nil){
139
		doconvert(list->file, vermaj);
140
		return;
141
	}
142
 
143
	if(vermaj){
144
		hokheaders(connect);
145
		hprint(hout, "Content-type: text/html\r\n");
146
		hprint(hout, "\r\n");
147
	}
148
 
149
	hprint(hout, "<head><title>plan 9 man %H", o);
150
	if(sect)
151
		hprint(hout, "(%d)\n", sect);
152
	hprint(hout, "</title></head><body>\n");
153
	hprint(hout, "<H6>Search for %H", o);
154
	if(sect)
155
		hprint(hout, "(%d)\n", sect);
156
	hprint(hout, "</H6>\n");
157
 
158
	for(; list; list = list->next)
159
		hprint(hout, "<p><a href=\"/magic/man2html%U\">/magic/man2html%H</a>\n",
160
			list->file, list->file);
161
	hprint(hout, "</body>\n");
162
}
163
 
164
void
165
strlwr(char *p)
166
{
167
	for(; *p; p++)
168
		if('A' <= *p && *p <= 'Z')
169
			*p += 'a'-'A';
170
}
171
 
172
void
173
redirectto(char *uri)
174
{
175
	if(connect){
176
		hmoved(connect, uri);
177
		exits(0);
178
	}else
179
		hprint(hout, "Your selection moved to <a href=\"%U\"> here</a>.<p></body>\r\n", uri);
180
}
181
 
182
void
183
searchfor(char *search)
184
{
185
	int i, j, n, fd;
186
	char *p, *sp;
187
	Biobufhdr *b;
188
	char *arg[32];
189
 
190
	hprint(hout, "<head><title>plan 9 search for %H</title></head>\n", search);
191
	hprint(hout, "<body>\n");
192
 
193
	hprint(hout, "<p>This is a keyword search through Plan 9 man pages.\n");
194
	hprint(hout, "The search is case insensitive; blanks denote \"boolean and\".\n");
195
	hprint(hout, "<FORM METHOD=\"GET\" ACTION=\"/magic/man2html\">\n");
196
	hprint(hout, "<INPUT NAME=\"pat\" TYPE=\"text\" SIZE=\"60\">\n");
197
	hprint(hout, "<INPUT TYPE=\"submit\" VALUE=\"Submit\">\n");
198
	hprint(hout, "</FORM>\n");
199
 
200
	hprint(hout, "<hr><H6>Search for %H</H6>\n", search);
201
	n = getfields(search, arg, 32, 1, "+");
202
	for(i = 0; i < n; i++){
203
		for(j = i+1; j < n; j++){
204
			if(strcmp(arg[i], arg[j]) > 0){
205
				sp = arg[j];
206
				arg[j] = arg[i];
207
				arg[i] = sp;
208
			}
209
		}
210
		sp = malloc(strlen(arg[i]) + 2);
211
		if(sp != nil){
212
			strcpy(sp+1, arg[i]);
213
			sp[0] = ' ';
214
			arg[i] = sp;
215
		}
216
	}
217
 
218
	/*
219
	 *  search index till line starts alphabetically < first token
220
	 */
221
	fd = open("/sys/man/searchindex", OREAD);
222
	if(fd < 0){
223
		hprint(hout, "<body>error: No Plan 9 search index\n");
224
		hprint(hout, "</body>");
225
		return;
226
	}
227
	p = malloc(32*1024);
228
	if(p == nil){
229
		close(fd);
230
		return;
231
	}
232
	b = ezalloc(sizeof *b);
233
	Binits(b, fd, OREAD, (uchar*)p, 32*1024);
234
	for(;;){
235
		p = Brdline(b, '\n');
236
		if(p == nil)
237
			break;
238
		p[Blinelen(b)-1] = 0;
239
		for(i = 0; i < n; i++){
240
			sp = strstr(p, arg[i]);
241
			if(sp == nil)
242
				break;
243
			p = sp;
244
		}
245
		if(i < n)
246
			continue;
247
		sp = strrchr(p, '\t');
248
		if(sp == nil)
249
			continue;
250
		sp++;
251
		hprint(hout, "<p><a href=\"/magic/man2html/%U\">/magic/man2html/%H</a>\n",
252
			sp, sp);
253
	}
254
	hprint(hout, "</body>");
255
 
256
	Bterm(b);
257
	free(b);
258
	free(p);
259
	close(fd);
260
}
261
 
262
/*
263
 *  find man pages mentioning the search string
264
 */
265
void
266
dosearch(int vermaj, char *search)
267
{
268
	int sect;
269
	char *p;
270
 
271
	if(strncmp(search, "man=", 4) == 0){
272
		sect = 0;
273
		search = hurlunesc(connect, search+4);
274
		p = strchr(search, '&');
275
		if(p != nil){
276
			*p++ = 0;
277
			if(strncmp(p, "sect=", 5) == 0)
278
				sect = atoi(p+5);
279
		}
280
		man(search, sect, vermaj);
281
		return;
282
	}
283
 
284
	if(vermaj){
285
		hokheaders(connect);
286
		hprint(hout, "Content-type: text/html\r\n");
287
		hprint(hout, "\r\n");
288
	}
289
 
290
	if(strncmp(search, "pat=", 4) == 0){
291
		search = hurlunesc(connect, search+4);
292
		search = hlower(search);
293
		searchfor(search);
294
		return;
295
	}
296
 
297
	hprint(hout, "<head><title>illegal search</title></head>\n");
298
	hprint(hout, "<body><p>Illegally formatted Plan 9 man page search</p>\n");
299
	search = hurlunesc(connect, search);
300
	hprint(hout, "<body><p>%H</p>\n", search);
301
	hprint(hout, "</body>");
302
}
303
 
304
/*
305
 *  convert a man page to html and output
306
 */
307
void
308
doconvert(char *uri, int vermaj)
309
{
310
	char *p;
311
	char file[256];
312
	char title[256];
313
	char err[ERRMAX];
314
	int pfd[2];
315
	Dir *d;
316
	Waitmsg *w;
317
	int x;
318
 
319
	if(strstr(uri, ".."))
320
		error("bad URI", "man page URI cannot contain ..");
321
	p = strstr(uri, "/intro");
322
 
323
	if(p == nil){
324
		while(*uri == '/')
325
			uri++;
326
		/* redirect section requests */
327
		snprint(file, sizeof(file), "/sys/man/%s", uri);
328
		d = dirstat(file);
329
		if(d == nil){
330
			strlwr(file);
331
			if(dirstat(file) != nil){
332
				snprint(file, sizeof(file), "/magic/man2html/%s", uri);
333
				strlwr(file);
334
				redirectto(file);
335
			}
336
			error(uri, "man page not found");
337
		}
338
		x = d->qid.type;
339
		free(d);
340
		if(x & QTDIR){
341
			if(*uri == 0 || strcmp(uri, "/") == 0)
342
				redirectto("/sys/man/index.html");
343
			else {
344
				snprint(file, sizeof(file), "/sys/man/%s/INDEX.html",
345
					uri+1);
346
				redirectto(file);
347
			}
348
			return;
349
		}
350
	} else {
351
		/* rewrite the name intro */
352
		*p = 0;
353
		snprint(file, sizeof(file), "/sys/man/%s/0intro", uri);
354
		d = dirstat(file);
355
		free(d);
356
		if(d == nil)
357
			error(uri, "man page not found");
358
	}
359
 
360
	if(vermaj){
361
		hokheaders(connect);
362
		hprint(hout, "Content-type: text/html\r\n");
363
		hprint(hout, "\r\n");
364
	}
365
	hflush(hout);
366
 
367
	if(pipe(pfd) < 0)
368
		error("out of resources", "pipe failed");
369
 
370
	/* troff -manhtml <file> | troff2html -t '' */
371
	switch(fork()){
372
	case -1:
373
		error("out of resources", "fork failed");
374
	case 0:
375
		snprint(title, sizeof(title), "Plan 9 %s", file);
376
		close(0);
377
		dup(pfd[0], 0);
378
		close(pfd[0]);
379
		close(pfd[1]);
380
		execl("/bin/troff2html", "troff2html", "-t", title, nil);
381
		errstr(err, sizeof err);
382
		exits(err);
383
	}
384
	switch(fork()){
385
	case -1:
386
		error("out of resources", "fork failed");
387
	case 0:
388
		snprint(title, sizeof(title), "Plan 9 %s", file);
389
		close(0);
390
		close(1);
391
		dup(pfd[1], 1);
392
		close(pfd[0]);
393
		close(pfd[1]);
394
		execl("/bin/troff", "troff", "-manhtml", file, nil);
395
		errstr(err, sizeof err);
396
		exits(err);
397
	}
398
	close(pfd[0]);
399
	close(pfd[1]);
400
 
401
	/* wait for completion */
402
	for(;;){
403
		w = wait();
404
		if(w == nil)
405
			break;
406
		if(w->msg[0] != 0)
407
			print("whoops %s\n", w->msg);
408
		free(w);
409
	}
410
}
411
 
412
void
413
main(int argc, char **argv)
414
{
415
	fmtinstall('H', httpfmt);
416
	fmtinstall('U', hurlfmt);
417
 
418
	if(argc == 2){
419
		hinit(&houtb, 1, Hwrite);
420
		hout = &houtb;
421
		doconvert(argv[1], 0);
422
		exits(nil);
423
	}
424
	close(2);
425
 
426
	connect = init(argc, argv);
427
	hout = &connect->hout;
428
	if(hparseheaders(connect, HSTIMEOUT) < 0)
429
		exits("failed");
430
 
431
	if(strcmp(connect->req.meth, "GET") != 0 && strcmp(connect->req.meth, "HEAD") != 0){
432
		hunallowed(connect, "GET, HEAD");
433
		exits("not allowed");
434
	}
435
	if(connect->head.expectother || connect->head.expectcont){
436
		hfail(connect, HExpectFail, nil);
437
		exits("failed");
438
	}
439
 
440
	bind("/usr/web/sys/man", "/sys/man", MREPL);
441
 
442
	if(connect->req.search != nil)
443
		dosearch(connect->req.vermaj, connect->req.search);
444
	else
445
		doconvert(connect->req.uri, connect->req.vermaj);
446
	hflush(hout);
447
	writelog(connect, "200 man2html %ld %ld\n", hout->seek, hout->seek);
448
	exits(nil);
449
}