~ubuntu-branches/ubuntu/raring/lurker/raring

« back to all changes in this revision

Viewing changes to render/main.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Meurer
  • Date: 2006-12-20 05:05:31 UTC
  • mfrom: (3.1.6 feisty)
  • Revision ID: james.westby@ubuntu.com-20061220050531-79inzy7o6uu95qx7
Tags: 2.1-7
* updated vi debconf translations, thanks to Clytie Siddall
  <clytie@riverland.net.au>
* fixed typo in one template (that you would like, not that
  would you like), thanks as well to Clytie Siddall
  - unfuzzied all translations

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  $Id: main.cpp,v 1.14 2004/08/27 15:04:05 terpstra Exp $
 
1
/*  $Id: main.cpp,v 1.29 2006/03/02 21:28:50 terpstra Exp $
2
2
 *  
3
3
 *  main.cpp - Transform a database snapshot to useful output
4
4
 *  
22
22
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
23
 */
24
24
 
25
 
#define _XOPEN_SOURCE 500
26
25
#define _FILE_OFFSET_BITS 64
27
26
 
28
27
#include <cstdlib>
35
34
#include <vector>
36
35
 
37
36
#include "commands.h"
 
37
#include "parse.h"
38
38
 
 
39
#include <XmlEscape.h>
39
40
#include <unistd.h>     // chdir
40
41
 
41
42
/* #define DEBUG 1 */
42
43
 
43
44
using namespace std;
44
45
 
45
 
string redirect(const string& url)
46
 
{
47
 
        return  "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
48
 
                "<html><head>\r\n"
49
 
                "<title>301 Moved Permanently</title>\r\n"
50
 
                "</head><body>\r\n"
51
 
                "<h1>Moved Permanently</h1>\r\n"
52
 
                "The document has moved <a href=\""
53
 
                + url + 
54
 
                "s\">here</a>.\r\n"
55
 
                "<p><hr>\r\n"
56
 
                "</body></html>\r\n";
57
 
}
58
 
 
59
 
string error(
 
46
void error(
60
47
        const string& main, 
61
48
        const string& sub, 
62
 
        const string& suggest)
 
49
        const string& suggest,
 
50
        const string& header)
63
51
{
64
 
        return  "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
65
 
                "<html>\r\n"
66
 
                " <head><title>Lurker - "
67
 
                + main + 
68
 
                "</title></head>\r\n"
69
 
                " <body>\r\n"
70
 
                "  <h1>Lurker - failed to render page:</h1>\r\n"
71
 
                "  <h2>"
72
 
                + main + " (" + sub + "):</h2><p>\r\n"
73
 
                + suggest + "\r\n"
74
 
                "  <p><hr>\r\n"
75
 
                " </body>\r\n"
76
 
                "</html>\r\n";
 
52
        cout << "Status: 200 OK\r\n";
 
53
        cout << header;
 
54
        cout << "Content-Type: text/html\r\n\r\n";
 
55
        cout << "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
 
56
             << "<html>\r\n"
 
57
             << " <head><title>Lurker - "
 
58
             << xmlEscape << main
 
59
             << "</title></head>\r\n"
 
60
             << " <body>\r\n"
 
61
             << "  <h1>Lurker - failed to render page:</h1>\r\n"
 
62
             << "  <h2>"
 
63
             << xmlEscape << main << " (" << xmlEscape << sub << "):</h2><p>\r\n"
 
64
             << xmlEscape << suggest << "\r\n"
 
65
             << "  <p><hr>\r\n"
 
66
             << " </body>\r\n"
 
67
             << "</html>\r\n";
 
68
        exit(1);
77
69
}
78
70
 
79
71
void tokenize(
92
84
        }
93
85
}
94
86
 
95
 
void help(const string& about)
96
 
{
97
 
        cout << "Status: 200 OK\r\n";
98
 
        cout << "Content-Type: text/html\r\n\r\n";
99
 
        cout << error(_("Not invoked correctly"), about,
100
 
                _("The lurker.cgi must have two parameters: the config file "
101
 
                  "and the request to render. The value of QUERY_STRING is "
102
 
                  "taken to be the config file, and REQUEST_URI is taken "
103
 
                  "to be the requested page to render. Setting a 404 error "
104
 
                  "handler to lurker.cgi?config.file will usually set these "
105
 
                  "environment variables. Additionally, lurker may be invoked "
106
 
                  "from the command-line. Here, the first parameter is the "
107
 
                  "config file and the second is the requested uri."));
108
 
}
109
 
 
110
87
Request parse_request(const string& param)
111
88
{
112
89
        string::size_type dot1 = param.rfind('.');
113
90
        if (dot1 == string::npos || dot1 == 0)
114
 
        {
115
 
                cout << "Status: 200 OK\r\n";
116
 
                cout << "Content-Type: text/html\r\n\r\n";
117
 
                cout << error(_("Missing extension"), param,
118
 
                        _("An extension for the request was required, but missing"));
119
 
                exit(1);
120
 
        }
 
91
                error(_("Missing extension"), param,
 
92
                      _("An extension for the request was required, but missing"));
121
93
        
122
94
        string::size_type dot2 = param.rfind('.', dot1-1);
123
95
        
145
117
                out.ext = param.substr(dot1+1, string::npos);
146
118
        }
147
119
        
 
120
        if (out.ext.length() < 3 || out.ext.length() > 6)
 
121
                error(_("Bogus extension"), out.ext,
 
122
                      _("The extension is not 3-6 characters long."));
 
123
        
 
124
        for (string::size_type i = 0; i < out.ext.length(); ++i)
 
125
                if ((out.ext[i] < 'a' || out.ext[i] > 'z') &&
 
126
                    (out.ext[i] < '0' || out.ext[i] > '9'))
 
127
                        error(_("Bogus extension"), out.ext,
 
128
                              _("Not simple lower-case alphanumeric letters."));
 
129
        
148
130
        if (!lstring::locale_normalize(out.language))
149
 
        {
150
 
                cout << "Status: 200 OK\r\n";
151
 
                cout << "Content-Type: text/html\r\n\r\n";
152
 
                cout << error(_("Bogus locale"), out.language,
153
 
                        _("The specified locale is not valid."));
154
 
                exit(1);
155
 
        }
 
131
                error(_("Bogus locale"), out.language,
 
132
                      _("The specified locale is not valid."));
156
133
        
157
134
        return out;
158
135
}
159
136
 
160
137
int main(int argc, char** argv)
161
138
{
162
 
        string config, cdpath, request, host, port, cgipath, https;
 
139
        string config, frontend, document, request, host, port, cgipath, https, ok;
163
140
        const char* tmp;
164
141
        
165
142
#if 0   
169
146
        bind_textdomain_codeset(PACKAGE, "utf-8");
170
147
#endif
171
148
        
172
 
        if ((tmp = getenv("QUERY_STRING")) != 0) config  = tmp;
173
 
        if ((tmp = getenv("REQUEST_URI" )) != 0) request = tmp;
174
 
        if ((tmp = getenv("SERVER_NAME" )) != 0) host    = tmp;
175
 
        if ((tmp = getenv("SERVER_PORT" )) != 0) port    = tmp;
176
 
        if ((tmp = getenv("SCRIPT_NAME" )) != 0) cgipath = tmp;
177
 
        if ((tmp = getenv("HTTPS"       )) != 0) https   = tmp;
178
 
        
179
 
        if (argc > 1) config  = argv[1];
180
 
        if (argc > 2) request = argv[2];
181
 
        
182
 
        string::size_type csplit;
183
 
        if ((csplit = config.find('?')) != string::npos)
184
 
        {
185
 
                cdpath = config.substr(csplit+1, string::npos);
186
 
                
187
 
                
188
 
                if (csplit != 0 && config[csplit-1] == '\\')
189
 
                        config.resize(csplit-1);
190
 
                else    config.resize(csplit);
191
 
        }
192
 
        
193
 
        if (config == "")
194
 
        {
195
 
                help(_("no config file set"));
196
 
                return 1;
197
 
        }
198
 
        if (request == "")
199
 
        {
200
 
                help(_("no request set"));
201
 
                return 1;
202
 
        }
203
 
        
204
 
        if (cdpath != "" && chdir(cdpath.c_str()) != 0)
205
 
        {
206
 
                cout << "Status: 200 OK\r\n";
207
 
                cout << "Content-Type: text/html\r\n\r\n";
208
 
                cout << error(_("Cannot chdir"), cdpath + ":" + strerror(errno),
209
 
                        _("The specified path to the document root could "
210
 
                          "not be entered. Check the argument and permissions."));
211
 
                return 1;
212
 
        }
 
149
        // Every document about CGI agrees these exist:
 
150
        if ((tmp = getenv("SERVER_NAME" )) != 0) host     = tmp;
 
151
        if ((tmp = getenv("SERVER_PORT" )) != 0) port     = tmp;
 
152
        if ((tmp = getenv("SCRIPT_NAME" )) != 0) cgipath  = tmp;
 
153
        // Many CGI 'standards' seem to agree this one exists for https:
 
154
        if ((tmp = getenv("HTTPS"       )) != 0) https    = tmp;
 
155
        
 
156
        // CGI guarantees this in case called as an error document
 
157
        if ((tmp = getenv("REDIRECT_URL")) != 0) request  = tmp;
 
158
        // ... however, as we aren't always called that way, try this too:
 
159
        if ((tmp = getenv("REQUEST_URI" )) != 0) request  = tmp;
 
160
        
 
161
        // get an over-ridden config location
 
162
        if ((tmp = getenv("REDIRECT_LURKER_CONFIG"))   != 0) config = tmp;
 
163
        if ((tmp = getenv("LURKER_CONFIG"))            != 0) config = tmp;
 
164
        // get the frontend location
 
165
        if ((tmp = getenv("REDIRECT_LURKER_FRONTEND")) != 0) document = tmp;
 
166
        if ((tmp = getenv("LURKER_FRONTEND"))          != 0) document = tmp;
 
167
        
 
168
        if (request == "" || host == "" || port == "" || cgipath == "")
 
169
                error(_("Not invoked correctly"), 
 
170
                      _("CGI environment variables missing"),
 
171
                      _("The lurker.cgi must be run as a CGI script. See the "
 
172
                        "INSTALL file distributed with lurker for help setting "
 
173
                        "up your webserver to run lurker.cgi. Lurker.cgi reads "
 
174
                        "the environment variables REDIRECT_URL or REQUEST_URI "
 
175
                        "to determine the missing file requested by the user. "
 
176
                        "Also, SERVER_NAME, SERVER_PORT, and SCRIPT_NAME are "
 
177
                        "used to build absolute redirected URLs."));
 
178
        
 
179
        // be nice: use a default config file
 
180
        if (config == "") config = DEFAULT_CONFIG_FILE;
213
181
        
214
182
        Config cfg;
215
183
        if (cfg.load(config.c_str()) != 0)
216
 
        {
217
 
                cout << "Status: 200 OK\r\n";
218
 
                cout << "Content-Type: text/html\r\n\r\n";
219
 
                cout << error(_("Cannot open config file"), "Config::load",
220
 
                        cfg.getError());
221
 
                return 1;
222
 
        }
 
184
                 error(_("Cannot open config file"), "Config::load",
 
185
                       cfg.getError() +
 
186
                       _("\nPerhaps you should set the LURKER_CONFIG "
 
187
                         "environment variable to select the correct "
 
188
                         "config file location. See the INSTALL file for "
 
189
                         "help on configuring your webserver."));
 
190
        
 
191
        if (document == "" && cfg.frontends.size() > 1)
 
192
                error(_("No frontend specified"), "LURKER_FRONTEND",
 
193
                      _("The lurker config file lists multiple frontends, "
 
194
                        "however, the environment variable LURKER_FRONTEND "
 
195
                        "does not specify which to use. See the INSTALL file "
 
196
                        "for help on configuring your webserver."));
 
197
        
 
198
        // be nice: if only one frontend, use it by default:
 
199
        if (document == "" && cfg.frontends.size() == 1)
 
200
        {
 
201
                document = cfg.frontends.begin()->first;
 
202
        }
 
203
        else
 
204
        {
 
205
                // Simplify the path to the requested document
 
206
                if ((ok = simplifyPath(document)) != "")
 
207
                        error(_("Bad document request"), document,
 
208
                              _("The path '") + ok + _("' could not be resolved while "
 
209
                                "attempting to determine which frontend the document "
 
210
                                "belongs to. Perhaps a directory does not exist?"));
 
211
        }
 
212
        
 
213
        // Look for the matching front-end
 
214
        frontend = "";
 
215
        Config::Frontends::const_iterator i, e;
 
216
        for (i = cfg.frontends.begin(), e = cfg.frontends.end(); i != e; ++i)
 
217
        {
 
218
                // Either document IS the frontend path or it is a file
 
219
                // contained in the frontend path.
 
220
                if (i->first == document.substr(0, i->first.length()) ||
 
221
                    i->first + "/" == document.substr(0, i->first.length()+1))
 
222
                {
 
223
                        frontend = i->first;
 
224
                        break;
 
225
                }
 
226
        }
 
227
        
 
228
        if (frontend == "")
 
229
                error(_("No matching frontend"), document,
 
230
                      _("The frontend specified in the webserver "
 
231
                        "configuration does not match any frontend in the "
 
232
                        "lurker config file."));
 
233
        
 
234
        cfg.set_permissions(cfg.frontends[frontend]);
 
235
        
 
236
        if (chdir(frontend.c_str()) != 0)
 
237
                error(_("Cannot chdir"), frontend + ":" + strerror(errno),
 
238
                      _("The specified frontend path could "
 
239
                        "not be entered. Check the path and permissions."));
223
240
        
224
241
        auto_ptr<ESort::Reader> db(ESort::Reader::opendb(cfg.dbdir + "/db"));
225
242
        if (!db.get())
226
 
        {
227
 
                cout << "Status: 200 OK\r\n";
228
 
                cout << "Content-Type: text/html\r\n\r\n";
229
 
                cout << error(_("Cannot open database snapshot"), strerror(errno),
230
 
                        _("The configured database 'dbdir' in the config file "
231
 
                          "could not be opened. Typically this means that it is "
232
 
                          "not readable by the user which the cgi is invoked as. "
233
 
                          "We suggest making dbdir and all files in it readable "
234
 
                          "by everyone since you are serving them on a website "
235
 
                          "anyways."));
236
 
                return 1;
237
 
        }
 
243
                error(_("Cannot open database snapshot"), strerror(errno),
 
244
                      _("The configured database 'dbdir' in the config file "
 
245
                        "could not be opened. Typically this means that it is "
 
246
                        "not readable by the user which the cgi is invoked as. "
 
247
                        "We suggest making dbdir and all files in it readable "
 
248
                        "by everyone since you are serving them on a website "
 
249
                        "anyways."));
238
250
        
 
251
        request = decipherHalf(request);
239
252
        vector<string> tokens;
240
253
        tokenize(request, tokens, "/");
241
254
        if (tokens.size() < 2)
242
 
        {
243
 
                cout << "Status: 200 OK\r\n";
244
 
                cout << "Content-Type: text/html\r\n\r\n";
245
 
                cout << error(_("Request malformed"), "tokenize(request)",
246
 
                        _("The request does not have at least two directory "
247
 
                          "components. It must be like ..../command/param.xml"));
248
 
                return 1;
249
 
        }
 
255
                error(_("Request malformed"), "tokenize(request)",
 
256
                      _("The request does not have at least two directory "
 
257
                        "components. It must be like ..../command/param.xml"));
250
258
        
251
259
        string param   = tokens[tokens.size()-1];
252
260
        string command = tokens[tokens.size()-2];
253
261
        string server;
254
262
        
 
263
        if (document != frontend &&
 
264
            frontend + '/' + command + '/' + param != document)
 
265
                error(_("Requested document is in error"), document,
 
266
                      _("The requested document does not match the file "
 
267
                        "lurker intends to generate: ")
 
268
                      + frontend + '/' + command + '/' + param);
 
269
        
255
270
        if (https == "on")
256
271
        {
257
272
                server = "https://" + host;
288
303
        else if (command == "attach")  return handle_attach (cfg, db.get(), param);
289
304
        else if (command == "mbox")    return handle_mbox   (cfg, db.get(), param);
290
305
        else if (command == "list")    return handle_list   (cfg, db.get(), param);
 
306
        else if (command == "zap")     return handle_zap    (cfg, db.get(), param);
291
307
        else
292
 
        {
293
 
                cout << "Status: 200 OK\r\n";
294
 
                cout << "Content-Type: text/html\r\n\r\n";
295
 
                cout << error(_("Bad command"), command,
296
 
                        _("The requested command is not supported."));
297
 
                return 1;
298
 
        }
 
308
                error(_("Bad command"), command, 
 
309
                      _("The requested command is not supported."));
299
310
}