]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ip/httpd/man2html.c
etheriwl: don't break controller on command flush timeout
[plan9front.git] / sys / src / cmd / ip / httpd / man2html.c
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 }