9a18ab380890008410ff10c6c9582609e9749677
[webgit] / src / webgit.c
1 /*
2     cehtehs git web frontend
3
4   Copyright (C)
5     2007,               Christian Thaeter <ct@pipapo.org>
6
7   This program is free software; you can redistribute it and/or
8   modify it under the terms of the GNU General Public License as
9   published by the Free Software Foundation; either version 2 of the
10   License, or (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22
23 #include "webgit.h"
24
25 #define WEBGIT_CONFIG "./webgit.conf"
26
27 #ifndef WEBGIT_CONFIG
28 #define WEBGIT_CONFIG "/etc/webgit.conf"
29 #endif
30
31 #include "actions.h"
32 #include "query.h"
33 #include "options.h"
34
35 #include "git/git-compat-util.h"
36
37 #include <cwa.h>
38
39 #include <stdio.h>
40 #include <stdarg.h>
41 #include <string.h>
42 #include <time.h>
43 #include <setjmp.h>
44
45 Html error_log;
46 jmp_buf err_jmp;
47
48 static void
49 webgit_err_vargs (const char *err, va_list params)
50 {
51   html_list_append (error_log, html (html_fmt_vargs (err, params), html_tag ("br")));
52   longjmp (err_jmp, 0);
53 }
54
55
56 void
57 webgit_err (const char *err, ...)
58 {
59   va_list args;
60   va_start (args, err);
61   webgit_err_vargs (err, args);
62   va_end (args);
63 }
64
65
66 static void
67 webgit_warn_vargs (const char *err, va_list params)
68 {
69   html_list_append (error_log, html (html_fmt_vargs (err, params), html_tag("br")));
70 }
71
72
73 void
74 webgit_warn (const char *err, ...)
75 {
76   va_list args;
77   va_start (args, err);
78   webgit_warn_vargs (err, args);
79   va_end (args);
80 }
81
82
83 static void
84 webgit_setup (void)
85 {
86   set_die_routine (webgit_err_vargs);
87   set_error_routine (webgit_err_vargs);
88   set_warn_routine (webgit_warn_vargs);
89 }
90
91
92 char*
93 webgit_buffer_provide (size_t size)
94 {
95   static char* buffers[32];
96   static size_t sizes[32];
97   static unsigned idx;
98
99   idx = (idx + 1) & ~0x1f;
100
101   if (sizes[idx] < size)
102     {
103       free (buffers[idx]);
104       sizes[idx] = (size+32) & ~0x1f;
105       buffers[idx] = cwa_malloc (sizes[idx]);
106     }
107   return buffers[idx];
108 }
109
110
111 char*
112 webgit_webskinpath (struct webgit_query* query, const char* element)
113 {
114   char* buffer = webgit_buffer_provide (strlen (query->webskindir) + strlen (query->skin) + strlen (element) + 3);
115   sprintf (buffer, "%s/%s/%s", query->webskindir, query->skin, element);
116   return buffer;
117 }
118
119
120 char*
121 webgit_skinpath (struct webgit_query* query, const char* element)
122 {
123   char* buffer = webgit_buffer_provide (strlen (query->skindir) + strlen (query->skin) + strlen (element) + 3);
124   sprintf (buffer, "%s/%s/%s", query->skindir, query->skin, element);
125   return buffer;
126 }
127
128
129 Html
130 webgit_email_link (Html name, Html email)
131 {
132   return html (
133                html_tag("a",
134                         html_attr ("href",
135                                    html ("mailto:", email))
136                         ),
137                name
138                );
139 }
140
141
142 char*
143 webgit_mimetype (const char* name)
144 {
145   char buf[256];
146
147   if (!name)
148     return NULL;
149
150   char* ext = strrchr (name, '.');
151   if (!ext)
152     return NULL;
153   ++ext;
154   if (!*ext)
155     return NULL;
156
157   FILE* mime_types = fopen ("/etc/mime.types", "r");
158   if (!mime_types)
159     return NULL;
160
161   while (fgets (buf, 256, mime_types))
162     {
163       if (buf[0] == '#' || !strtok (buf, " \t\n"))
164         continue;
165
166       char* suffix;
167       while ((suffix = strtok (NULL, " \t\n")))
168         if (!strcmp (suffix, ext))
169           {
170             fclose (mime_types);
171             return cwa_strndup (buf, SIZE_MAX);
172           }
173     }
174   return NULL;
175 }
176
177
178 int
179 main (int argc, char**argv)
180 {
181   Html page;
182   struct webgit_query query;
183
184   webgit_setup();
185
186   error_log = html_list();
187
188   clock_t timestat = clock();
189
190   webgit_query_init (&query);
191
192   /* set some defaults if not already set */
193   setenv ("REQUEST_METHOD", "GET", 0);
194   setenv ("SCRIPT_NAME", argv[0], 0);
195   setenv ("WEBGIT_CONFIG", WEBGIT_CONFIG, 0);
196
197   /* we can only longjmp out of libgit's error handling */
198   if (setjmp (err_jmp))
199     goto error;
200
201   if (webgit_commandline_dispatch (argc, argv, &query))
202     goto error;
203
204   // read config
205   if (webgit_configfile_dispatch (getenv("WEBGIT_CONFIG"), &query))
206     goto error;
207
208
209   // parse request/query What to show?
210
211   query.request = cgi_new ();
212
213   cgi_run_query (query.request, webgit_param_dispatch, &query);
214
215   if (query.count < 0)
216     query.count = query.count_def;
217
218   /* TODO: if no object given but repo+path+ref are given then compute object */
219
220   /* default action is to show the main page with the list of repos */
221   if (!query.action)
222     query.action = cwa_strndup ("main", SIZE_MAX);
223
224
225   // query to cache-line
226
227   // check if in cache
228
229   // generate page
230
231   Html content = webgit_action_dispatch (&query);
232
233   if (query.content_type && !strcmp (query.content_type, "text/html"))
234     {
235       /* generate html page */
236       page = html(
237                   html_httpheader(
238                                   html_httpfield(
239                                                  "Content-type",
240                                                  query.content_type,
241                                                  html_attr("charset", "UTF-8")
242                                                  )//,
243                                   //html_httpfield("Last-Modified", cgit_page.modified),
244                                   //html_httpfield("Expires", cgit_page.expires)
245                                   ),
246                   html_document(
247                                 "-//W3C//DTD XHTML 1.0 Transitional//EN",
248                                 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd",
249                                 html_content(
250                                              /*head*/
251                                              html(
252                                                   html(html_tag("title"), "webgit"),
253                                                   html_nl(),
254                                                   html_meta("generator", "webgit"),
255                                                   html_link_rel("stylesheet", "text/css",
256                                                                 webgit_webskinpath (&query, "css/webgit.css")
257                                                                 ),
258                                                   html_link_rel("icon", "image/png",
259                                                                 webgit_webskinpath (&query, "icons/favicon.png")
260                                                                 )
261                                                   ),
262                                              /*body*/
263                                              html (
264                                                    html (
265                                                          html_tag("div",
266                                                                   html_attr("id", "container")
267                                                                   ),
268                                                          /*
269                                                            TODO header.inc should be configurable and may not exist
270                                                             The idea is to have a project header and footer available
271                                                             as plain html so that someone can install webgit
272                                                             and quickly add their project logo, menu back to the main
273                                                             project website and any other notices they may wish to add
274                                                          */
275                                                          html (
276                                                                html_tag("div",
277                                                                         html_attr("id", "header")),
278                                                                html_include (webgit_skinpath (&query, "inc/header.inc"))
279                                                                ),
280                                                          content,
281                                                          html(
282                                                               html_tag("div",
283                                                                        html_attr("id", "errors")
284                                                                        ),
285                                                               error_log
286                                                               ),
287                                                          // See TODO header.inc above
288                                                          html (
289                                                                html_tag("div",
290                                                                         html_attr("id", "footer")),
291                                                                html_include (webgit_skinpath (&query, "inc/footer.inc"))
292                                                                )
293
294                                                          )
295                                                    ),
296                                              html_attr ("xmlns", "http://www.w3.org/1999/xhtml"),
297                                              html_attr ("xml:lang", "en"),
298                                              html_attr ("lang", "en")
299                                              )
300                                 )
301                   );
302
303       timestat = clock() - timestat;
304       html_list_append (error_log, html (
305                                          html_tag("div", html_attr ("id", "timestat")),
306                                          html_fmt ("processing took %g secs\n", timestat/(float)CLOCKS_PER_SEC)
307                                          )
308                         );
309
310     }
311   else
312     {
313       /* diffrent content type, raw content */
314       html_free (error_log);
315
316       page = html(
317                   html_httpheader (
318                                    html_httpfield ("Content-type",
319                                                    query.content_type ?
320                                                    query.content_type
321                                                    : "application/octet-stream")
322                                    ),
323                   content
324                   );
325     }
326
327   html_fprint (stdout, page);
328
329   html_free (page);
330
331   webgit_query_destroy (&query);
332
333   return 0;
334
335  error:
336   page = html(
337               html_httpheader(
338                               html_httpfield(
339                                              "Content-type",
340                                              "text/html",
341                                              html_attr("charset", "UTF-8")
342                                              )                              ),
343               html_document(
344                             "-//W3C//DTD XHTML 1.0 Transitional//EN",
345                             "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd",
346                             html_content(
347                                          /*head*/
348                                          html(
349                                               html(html_tag("title"), "ERROR: webgit"),
350                                               html_nl(),
351                                               html_meta("generator", "webgit")
352                                               ),
353                                          /*body*/
354                                          html(
355                                               html_tag("div"),
356                                               error_log
357                                               ),
358                                          html_attr("xmlns", "http://www.w3.org/1999/xhtml"),
359                                          html_attr("xml:lang", "en"),
360                                          html_attr("lang", "en")
361                                          )
362                             )
363               );
364
365   html_fprint (stdout, page);
366   html_free (page);
367   return 10;
368 }
369
370
371 /*
372 //      Local Variables:
373 //      mode: C
374 //      c-file-style: "gnu"
375 //      indent-tabs-mode: nil
376 //      End:
377 */