first simple rxpd access check
[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 #include "rxpd_client.h"
35
36 #include "git/git-compat-util.h"
37
38 #include <cwa.h>
39
40 #include <stdio.h>
41 #include <stdarg.h>
42 #include <string.h>
43 #include <time.h>
44 #include <setjmp.h>
45
46 Html error_log;
47 jmp_buf err_jmp;
48
49 static void
50 webgit_err_vargs (const char *err, va_list params)
51 {
52   html_list_append (error_log, html (html_fmt_vargs (err, params), html_tag ("br")));
53   longjmp (err_jmp, 0);
54 }
55
56
57 void
58 webgit_err (const char *err, ...)
59 {
60   va_list args;
61   va_start (args, err);
62   webgit_err_vargs (err, args);
63   va_end (args);
64 }
65
66
67 static void
68 webgit_warn_vargs (const char *err, va_list params)
69 {
70   html_list_append (error_log, html (html_fmt_vargs (err, params), html_tag("br")));
71 }
72
73
74 void
75 webgit_warn (const char *err, ...)
76 {
77   va_list args;
78   va_start (args, err);
79   webgit_warn_vargs (err, args);
80   va_end (args);
81 }
82
83
84 static void
85 webgit_setup (void)
86 {
87   set_die_routine (webgit_err_vargs);
88   set_error_routine (webgit_err_vargs);
89   set_warn_routine (webgit_warn_vargs);
90 }
91
92
93 char*
94 webgit_buffer_provide (size_t size)
95 {
96   static char* buffers[32];
97   static size_t sizes[32];
98   static unsigned idx;
99
100   idx = (idx + 1) & ~0x1f;
101
102   if (sizes[idx] < size)
103     {
104       free (buffers[idx]);
105       sizes[idx] = (size+32) & ~0x1f;
106       buffers[idx] = cwa_malloc (sizes[idx]);
107     }
108   return buffers[idx];
109 }
110
111
112 char*
113 webgit_webskinpath (struct webgit_query* query, const char* element)
114 {
115   char* buffer = webgit_buffer_provide (strlen (query->webskindir) + strlen (query->skin) + strlen (element) + 3);
116   sprintf (buffer, "%s/%s/%s", query->webskindir, query->skin, element);
117   return buffer;
118 }
119
120
121 char*
122 webgit_skinpath (struct webgit_query* query, const char* element)
123 {
124   char* buffer = webgit_buffer_provide (strlen (query->skindir) + strlen (query->skin) + strlen (element) + 3);
125   sprintf (buffer, "%s/%s/%s", query->skindir, query->skin, element);
126   return buffer;
127 }
128
129
130 Html
131 webgit_email_link (Html name, Html email)
132 {
133   return html (
134                html_tag("a",
135                         html_attr ("href",
136                                    html ("mailto:", email))
137                         ),
138                name
139                );
140 }
141
142
143 char*
144 webgit_mimetype (const char* name)
145 {
146   char buf[256];
147
148   if (!name)
149     return NULL;
150
151   char* ext = strrchr (name, '.');
152   if (!ext)
153     return NULL;
154   ++ext;
155   if (!*ext)
156     return NULL;
157
158   FILE* mime_types = fopen ("/etc/mime.types", "r");
159   if (!mime_types)
160     return NULL;
161
162   while (fgets (buf, 256, mime_types))
163     {
164       if (buf[0] == '#' || !strtok (buf, " \t\n"))
165         continue;
166
167       char* suffix;
168       while ((suffix = strtok (NULL, " \t\n")))
169         if (!strcmp (suffix, ext))
170           {
171             fclose (mime_types);
172             return cwa_strndup (buf, SIZE_MAX);
173           }
174     }
175   return NULL;
176 }
177
178
179 int
180 main (int argc, char**argv)
181 {
182   Html page;
183   struct webgit_query query;
184
185   webgit_setup();
186
187   error_log = html_list();
188
189   clock_t timestat = clock();
190
191   webgit_query_init (&query);
192
193   /* set some defaults if not already set */
194   setenv ("REQUEST_METHOD", "GET", 0);
195   setenv ("SCRIPT_NAME", argv[0], 0);
196   setenv ("WEBGIT_CONFIG", WEBGIT_CONFIG, 0);
197
198   /* we can only longjmp out of libgit's error handling */
199   if (setjmp (err_jmp))
200     goto error;
201
202   if (webgit_commandline_dispatch (argc, argv, &query))
203     goto error;
204
205   // read config
206   if (webgit_configfile_dispatch (getenv("WEBGIT_CONFIG"), &query))
207     goto error;
208
209
210   // parse request/query What to show?
211
212   query.request = cgi_new ();
213
214   cgi_run_query (query.request, webgit_param_dispatch, &query);
215
216   if (query.count < 0)
217     query.count = query.count_def;
218
219   /* TODO: if no object given but repo+path+ref are given then compute object */
220
221   /* default action is to show the main page with the list of repos */
222   if (!query.action)
223     query.action = cwa_strndup ("main", SIZE_MAX);
224
225   if (query.rxpd)
226     {
227       RxpdClient rxpd = rxpd_client_new (query.rxpd, "webgit/");  /*TODO config rxpd prefix*/
228       rxpd_client_cmd (rxpd, "CHECK", "access");
229
230       if (query.request->user_agent && strchr (query.request->user_agent, '\n'))
231         webgit_err ("I dont like you");
232
233       rxpd_client_query (rxpd,
234                          "HOST=%s:USER-AGENT=%s:ACTION=%s:REPO=%s:HEAD=%s\n\n",
235                          query.request->user_addr?query.request->user_addr:"",
236                          query.request->user_agent?query.request->user_agent:"",
237                          query.action,
238                          query.repo?query.repo:"",
239                          query.head?query.head:""
240                          );
241
242       if (rxpd_client_pending (rxpd, 1000) < 1)
243         webgit_err ("rxpd check failed");
244
245       if (!!strncmp (rxpd_client_recieve (rxpd), "allow:", 6))
246         webgit_err ("access denied HOST=%s:USER-AGENT=%s:ACTION=%s:REPO=%s:HEAD=%s\n\n",
247                     query.request->user_addr?query.request->user_addr:"",
248                     query.request->user_agent?query.request->user_agent:"",
249                     query.action,
250                     query.repo?query.repo:"",
251                     query.head?query.head:""
252                     );
253
254       rxpd_client_free (rxpd);
255     }
256
257   // query to cache-line
258
259   // check if in cache
260
261   // generate page
262
263   Html content = webgit_action_dispatch (&query);
264
265   if (query.content_type && !strcmp (query.content_type, "text/html"))
266     {
267       /* generate html page */
268       page = html(
269                   html_httpheader(
270                                   html_httpfield(
271                                                  "Content-type",
272                                                  query.content_type,
273                                                  html_attr("charset", "UTF-8")
274                                                  )//,
275                                   //html_httpfield("Last-Modified", cgit_page.modified),
276                                   //html_httpfield("Expires", cgit_page.expires)
277                                   ),
278                   html_document(
279                                 "-//W3C//DTD XHTML 1.0 Transitional//EN",
280                                 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd",
281                                 html_content(
282                                              /*head*/
283                                              html(
284                                                   html(html_tag("title"), "webgit"),
285                                                   html_nl(),
286                                                   html_meta("generator", "webgit"),
287                                                   html_link_rel("stylesheet", "text/css",
288                                                                 webgit_webskinpath (&query, "css/webgit.css")
289                                                                 ),
290                                                   html_link_rel("icon", "image/png",
291                                                                 webgit_webskinpath (&query, "icons/favicon.png")
292                                                                 )
293                                                   ),
294                                              /*body*/
295                                              html (
296                                                    html (
297                                                          html_tag("div",
298                                                                   html_attr("id", "container")
299                                                                   ),
300                                                          /*
301                                                            TODO header.inc should be configurable and may not exist
302                                                             The idea is to have a project header and footer available
303                                                             as plain html so that someone can install webgit
304                                                             and quickly add their project logo, menu back to the main
305                                                             project website and any other notices they may wish to add
306                                                          */
307                                                          html (
308                                                                html_tag("div",
309                                                                         html_attr("id", "header")),
310                                                                html_include (webgit_skinpath (&query, "inc/header.inc"))
311                                                                ),
312                                                          content,
313                                                          html(
314                                                               html_tag("div",
315                                                                        html_attr("id", "errors")
316                                                                        ),
317                                                               error_log
318                                                               ),
319                                                          // See TODO header.inc above
320                                                          html (
321                                                                html_tag("div",
322                                                                         html_attr("id", "footer")),
323                                                                html_include (webgit_skinpath (&query, "inc/footer.inc"))
324                                                                )
325
326                                                          )
327                                                    ),
328                                              html_attr ("xmlns", "http://www.w3.org/1999/xhtml"),
329                                              html_attr ("xml:lang", "en"),
330                                              html_attr ("lang", "en")
331                                              )
332                                 )
333                   );
334
335       timestat = clock() - timestat;
336       html_list_append (error_log, html (
337                                          html_tag("div", html_attr ("id", "timestat")),
338                                          html_fmt ("processing took %g secs\n", timestat/(float)CLOCKS_PER_SEC)
339                                          )
340                         );
341
342     }
343   else
344     {
345       /* diffrent content type, raw content */
346       html_free (error_log);
347
348       page = html(
349                   html_httpheader (
350                                    html_httpfield ("Content-type",
351                                                    query.content_type ?
352                                                    query.content_type
353                                                    : "application/octet-stream")
354                                    ),
355                   content
356                   );
357     }
358
359   html_fprint (stdout, page);
360
361   html_free (page);
362
363   webgit_query_destroy (&query);
364
365   return 0;
366
367  error:
368   page = html(
369               html_httpheader(
370                               html_httpfield(
371                                              "Content-type",
372                                              "text/html",
373                                              html_attr("charset", "UTF-8")
374                                              )                              ),
375               html_document(
376                             "-//W3C//DTD XHTML 1.0 Transitional//EN",
377                             "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd",
378                             html_content(
379                                          /*head*/
380                                          html(
381                                               html(html_tag("title"), "ERROR: webgit"),
382                                               html_nl(),
383                                               html_meta("generator", "webgit")
384                                               ),
385                                          /*body*/
386                                          html(
387                                               html_tag("div"),
388                                               error_log
389                                               ),
390                                          html_attr("xmlns", "http://www.w3.org/1999/xhtml"),
391                                          html_attr("xml:lang", "en"),
392                                          html_attr("lang", "en")
393                                          )
394                             )
395               );
396
397   html_fprint (stdout, page);
398   html_free (page);
399   return 10;
400 }
401
402
403 /*
404 //      Local Variables:
405 //      mode: C
406 //      c-file-style: "gnu"
407 //      indent-tabs-mode: nil
408 //      End:
409 */