044704e55f7cc43948dc3a3d9c28cb14e7e61d4c
[public/www-new.git] / src / web.d
1 //#!/usr/bin/rdmd
2 import std.stdio, std.path, std.process, std.file, std.array, std.string, std.algorithm, std.datetime, std.ascii;
3 import config;
4
5 string dweb_root;
6
7 string indent = "";
8 void html(string s) { writeln(indent ~ s); }
9 void html_pop(string s) { indent = indent[0..max(0, $-4)]; html(s); }
10 void html_push(string s) { html(s); indent ~= "    "; }
11
12 void write_link(string to, bool expand) {
13   bool isdir = dirExists(dweb_root ~ "/srv/" ~ to[url_root.length..$]);
14   string flair = nav_tree_chev? (expand? "» " : "› ") : "";
15   html_push("<li" ~ (expand? " class=\"thisPage\" " : "") ~ ">");
16   html("<a href=\"" ~ to ~ (isdir ? "/" : "") ~ "\">"
17         ~ flair ~ baseName(to) ~ (isdir ? "/" : "") ~ "</a>");
18   html_pop("</li>");
19 }
20
21 void nav_tree_r(string url, string cur_loc, string[] subdirs) {
22   string[] dirs = array(map!"a.name"(dirEntries(dweb_root ~ "/srv/" ~ cur_loc, SpanMode.shallow)));
23   sort(dirs);
24   if (dirs.length == 0) return;
25   bool inserted_ul = false;
26   bool next = false;
27   string next_loc;
28   foreach(string s; dirs) {
29     s= s[(dweb_root ~ "/srv/").length..$];
30     string name = stripExtension(baseName(s));
31     if (name.length == 0) continue; // e.g. ".md", should we do something else with these files?
32     if (name == "index") continue; // "index" will never appear in the nav_tree.
33     if (name[0] == '@') continue; // hidden file
34     if (!inserted_ul) { html_push("<ul>"); inserted_ul = true; }
35     bool expand = subdirs.length > 0 && name == subdirs[0];
36     write_link(url_root ~ stripExtension(s), expand);
37
38     if (expand && isDir(dweb_root ~ "/srv/" ~ s)) {
39       if (nav_tree_vert) {
40         html_push("<li>");
41         nav_tree_r(url, (cur_loc == "" ? "" : cur_loc ~ "/") ~ subdirs[0], subdirs[1..$]);
42         html_pop("</li>");
43       } else {
44         next = true;
45         next_loc = (cur_loc == "" ? "" : cur_loc ~ "/") ~ subdirs[0];
46       }
47     }
48   }
49
50   if (inserted_ul) html_pop("</ul>");
51   if (next) nav_tree_r(url, next_loc, subdirs[1..$]);
52 }
53
54 void do_nav_tree(string url) {
55   html_push("<div id=\"" ~ (nav_tree_vert ? "" : "horiz-") ~ "side-bar\">");
56   nav_tree_r(url, "", cast(string[])array(pathSplitter(url)));
57   html_pop("</div>\n");
58 }
59
60 void not_found(string path) {
61   html("The page <code>" ~ path ~ "</code> does not exist. (404)");
62 }
63
64 void do_header() {
65   html_push("<div id=\"header\">");
66   
67   html_push("<div class=\"superHeader\">");
68   
69   html_push("<div class=\"left\">");
70   html("<a href=\"http://wiki.csclub.uwaterloo.ca/\">wiki</a>");
71   html("<a href=\"http://git.csclub.uwaterloo.ca/\">git</a>");
72   html("<a href=\"http://mirror.csclub.uwaterloo.ca/\">mirror</a>");
73   html("<a href=\"http://csclub.uwaterloo.ca/stats\">stats</a>");
74   html("<a href=\"http://mail.csclub.uwaterloo.ca/\">webmail</a>");
75   html("<a href=\"http://csclub.uwaterloo.ca/newsgroup/\">newsgroups</a>");
76   html("<a href=\"http://csclub.uwaterloo.ca/mailman/\">mailing lists</a>");
77   html_pop("</div>"); 
78   
79   html_push("<div class=\"right\">");
80   html("<a href=\"" ~ url_root ~ "changelog\">changelog</a>");
81   html_pop("</div>");
82   
83   html_pop("</div>");
84
85   html_push("<div class=\"midHeader\">");
86   html_push("<h1 class=\"headerTitle\">");
87   html("<a href=\"" ~ url_root ~ "\"><img src=\"" ~ url_root ~ "pub/style/logo.png\" id=\"logo\"> <span id=\"headerSubTitle\">" ~ site_subtitle ~ "</span></a>");
88   html_pop("</h1>");
89   html_pop("</div>");
90   
91   html_push("<div class=\"subHeader\">");
92   html("<br>");
93   html_pop("</div>");
94   
95   html_pop("</div>\n");
96 }
97
98 bool dirExists(string path)  { try { if (isDir(path))  return true; else return false; } catch (Exception e) { return false; } }
99
100 void do_content(string url) {
101   html_push("<div id=\"main-copy\"" ~ (nav_tree_vert? " class=\"main-copy-side-bar\"" : "")  ~ ">");
102   // first, see if we have something that wants to handle url outright
103   foreach (string glob, string h; handlers) {
104     if (globMatch(url, glob)) {
105       html(shell(dweb_root ~ "/bin/" ~ h ~ " " ~ url));
106       html_pop("</div>");
107       return;
108     }
109   }
110   // if that failed, see if we can handle the file
111   if (url == "" ? false : url[$-1] == '/') url ~= "index";
112   foreach (f; array(map!"a.name"(dirEntries(dirName(dweb_root ~ "/srv/" ~ url), SpanMode.shallow)))) {
113     if (isDir(f)) continue;
114     string name = baseName(f); name = name[0] == '@' ? name[1..$] : name;
115     if (stripExtension(name) == baseName(url)) {
116       foreach (string glob, string h; handlers) { 
117         if (globMatch(name, glob)) {
118           html(shell(dweb_root ~ "/bin/" ~ h ~ " " ~ f));
119           html_pop("</div>");
120           return;
121         }
122       }
123     }
124   }
125   if (baseName(url) != "index") not_found(url);
126   html_pop("</div>");
127 }
128
129 void do_footer() {
130   html_push("<div id=\"footer\">");
131
132   html_push("<div class=\"left\">");
133   html("<a href=\"" ~ url_root ~ "dweb\">Powered by dweb</a>");
134   html_pop("</div>");
135
136   html_push("<div class=\"right\">");
137   html("&nbsp;");
138   html_pop("</div>");
139
140   html_pop("</div>\n");
141 }
142
143 bool evil(string s) {
144   foreach(char c; s) if (!isAlphaNum(c) && c != '/' && c != '-' && c != '_') return true;
145   return false;
146 }
147
148 void main(string[] args) {
149   init_handlers();
150   dweb_root = getcwd()[0..$-4]; // take out bin/
151  
152   html("Content-type: text/html\n");
153   html("<!DOCTYPE html>");
154   html_push("<html>\n");
155
156   string url = getenv("SCRIPT_URL")[url_root.length..$];
157   if (evil(url)) { html ("bad url."); return; }
158   
159   string pagename = baseName(url);
160   if (pagename.length != 0) pagename = " - " ~ pagename;
161   pagename = site_title ~ pagename;
162   
163   html_push("<head>");
164   html("<title>" ~ pagename ~ "</title>");
165   html("<link rel=\"stylesheet\" href=\"" ~ url_root ~ "pub/style/style.css\" type=\"text/css\" media=\"screen, handheld\" title=\"default\">");
166   html("<meta charset=\"UTF-8\">");
167   html("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");
168   html_pop("</head>\n");
169   
170   html_push("<body" ~ (page_container? " style=\"text-align: center\"" : "")~ ">");
171   if (page_container) html_push("<div id=\"container\">");
172   do_header();
173   do_nav_tree(url);
174   do_content(url);
175   do_footer();
176   if (page_container) html_pop("</div>");
177   html_pop("</body>\n");
178
179   html_pop("</html>");
180 }