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

« back to all changes in this revision

Viewing changes to render/search.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Meurer
  • Date: 2004-09-26 16:27:51 UTC
  • Revision ID: james.westby@ubuntu.com-20040926162751-z1ohcjltv7ojtg6z
Tags: upstream-1.2
ImportĀ upstreamĀ versionĀ 1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  $Id: search.cpp,v 1.17 2004/08/27 15:04:05 terpstra Exp $
 
2
 *  
 
3
 *  sindex.cpp - Handle a search/ command
 
4
 *  
 
5
 *  Copyright (C) 2002 - Wesley W. Terpstra
 
6
 *  
 
7
 *  License: GPL
 
8
 *  
 
9
 *  Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca>
 
10
 *  
 
11
 *    This program is free software; you can redistribute it and/or modify
 
12
 *    it under the terms of the GNU General Public License as published by
 
13
 *    the Free Software Foundation; version 2.
 
14
 *    
 
15
 *    This program is distributed in the hope that it will be useful,
 
16
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
 *    GNU General Public License for more details.
 
19
 *    
 
20
 *    You should have received a copy of the GNU General Public License
 
21
 *    along with this program; if not, write to the Free Software
 
22
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
23
 */
 
24
 
 
25
#define _XOPEN_SOURCE 500
 
26
#define _FILE_OFFSET_BITS 64
 
27
 
 
28
#include <iostream>
 
29
#include <cerrno>
 
30
#include <cstring>
 
31
#include <cassert>
 
32
#include <algorithm>
 
33
 
 
34
#include <MessageId.h>
 
35
#include <XmlEscape.h>
 
36
#include <Keys.h>
 
37
 
 
38
#include "commands.h"
 
39
#include "Search.h"
 
40
#include "Cache.h"
 
41
#include "ConfigFile.h"
 
42
 
 
43
int search_format_error(const string& param)
 
44
{
 
45
        cout << "Status: 200 OK\r\n";
 
46
        cout << "Content-Type: text/html\r\n\r\n";
 
47
        cout << error(_("Bad request"), param,
 
48
                _("The given parameter was not of the correct format. "
 
49
                  "A searc request must be formatted like: "
 
50
                  "search/YYYYMMDD.HHMMSS.hashcode@word,word,word.xml"));
 
51
        return 1;
 
52
}
 
53
 
 
54
inline int fromHex(char c)
 
55
{
 
56
        if (c >= 'A' && c <= 'Z') return c - 'A' + 10;
 
57
        if (c >= 'a' && c <= 'z') return c - 'a' + 10;
 
58
        return c - '0';
 
59
}
 
60
                        
 
61
string decipherHalf(const string& str)
 
62
{
 
63
        // cout << "deciper: " << str << endl;
 
64
        
 
65
        string out;
 
66
        
 
67
        string::size_type b = 0, e;
 
68
        
 
69
        while ((e = str.find_first_of("%+", b)) 
 
70
                != string::npos)
 
71
        {
 
72
                out.append(str, b, e - b);
 
73
                if (str[e] == '+') out.append(" ");
 
74
                else if (str.length() > e+2)
 
75
                {
 
76
                        int ch = fromHex(str[e+1]) << 4 | fromHex(str[e+2]);
 
77
                        out += ((char)ch);
 
78
                        e += 2;
 
79
                }
 
80
                
 
81
                b = e+1;
 
82
        }
 
83
        
 
84
        out.append(str, b, str.length() - b);
 
85
        
 
86
        return out;
 
87
}
 
88
 
 
89
int handle_search(const Config& cfg, ESort::Reader* db, const string& param)
 
90
{
 
91
        Request req = parse_request(param);
 
92
        cfg.options = req.options;
 
93
        
 
94
        string::size_type o = req.options.find('@');
 
95
        if (o == string::npos || o != MessageId::full_len)
 
96
                return search_format_error(param);
 
97
        
 
98
        if (!MessageId::is_full(req.options.c_str()))
 
99
                return search_format_error(param);
 
100
        
 
101
        vector<string> tokens;
 
102
        ++o;
 
103
        
 
104
        MessageId id(req.options.c_str());
 
105
        string raw = decipherHalf(req.options.substr(o, string::npos));
 
106
        string keys(raw);
 
107
        // we need to translate '!' to '/'
 
108
        for (string::size_type es = 0; es < keys.length(); ++es)
 
109
                if (keys[es] == '!') keys[es] = '/';
 
110
                
 
111
        tokenize(keys, tokens, ",");
 
112
        
 
113
        // Right! Everything the user did is ok.
 
114
        
 
115
        vector<Summary> forward, backward, queue;
 
116
        
 
117
        Search backwardk(cfg, db, Backward, id);
 
118
        Search forwardk (cfg, db, Forward,  id);
 
119
        
 
120
        for (vector<string>::iterator i = tokens.begin(); i != tokens.end(); ++i)
 
121
        {
 
122
                string& key = *i;
 
123
                
 
124
                backwardk.keyword(key);
 
125
                forwardk.keyword(key);
 
126
        }
 
127
        
 
128
        if (!forwardk.pull(35, forward) || !backwardk.pull(35, backward))
 
129
        {
 
130
                cout << "Status: 200 OK\r\n";
 
131
                cout << "Content-Type: text/html\r\n\r\n";
 
132
                cout << error(_("Database search seek failure"), strerror(errno),
 
133
                        _("Something internal to the database failed. "
 
134
                          "Please contact the lurker user mailing list for "
 
135
                          "furth assistence."));
 
136
                return 1;
 
137
        }
 
138
        
 
139
        vector<Summary>::size_type left, right, i;
 
140
        if (forward.size() + backward.size() < 20)
 
141
        {
 
142
                left = backward.size();
 
143
                right = forward.size();
 
144
        }
 
145
        else if (forward.size() < 10)
 
146
        {
 
147
                right = forward.size();
 
148
                left = 20 - right;
 
149
        }
 
150
        else if (backward.size() < 10)
 
151
        {
 
152
                left = backward.size();
 
153
                right = 20 - left;
 
154
        }
 
155
        else
 
156
        {
 
157
                left = right = 10;
 
158
        }
 
159
        
 
160
        assert (left  <= backward.size());
 
161
        assert (right <= forward .size());
 
162
        
 
163
        for (i = left; i > 0; --i)  queue.push_back(backward[i-1]);
 
164
        for (i = 0; i < right; ++i) queue.push_back(forward[i]);
 
165
        
 
166
        string ok;
 
167
        for (i = 0; i < queue.size(); ++i)
 
168
                if ((ok = queue[i].load(db, cfg)) != "")
 
169
                        break;
 
170
        
 
171
        if (ok != "")
 
172
        {
 
173
                cout << "Status: 200 OK\r\n";
 
174
                cout << "Content-Type: text/html\r\n\r\n";
 
175
                cout << error(_("Database search pull failure"), ok,
 
176
                        _("Something internal to the database failed. "
 
177
                          "Please contact the lurker user mailing list for "
 
178
                          "further assistence."));
 
179
                return 1;
 
180
        }
 
181
        
 
182
        Cache cache(cfg, "search", 
 
183
                param.substr(0, o) + 
 
184
                raw + "." +     // this is transformed so the webserver can eat it
 
185
                req.language + "." +
 
186
                req.ext, req.ext);
 
187
        
 
188
        cache.o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
 
189
                << "<?xml-stylesheet type=\"text/xsl\" href=\"../fmt/search.xsl\"?>\n"
 
190
                << "<search xml:lang=\"" << req.language << "\">\n"
 
191
                << " " << cfg(req.language) << "\n"
 
192
                << " <query>" << xmlEscape << keys << "</query>\n";
 
193
        
 
194
        if (right < forward.size())
 
195
        {       // we need a next link
 
196
                i = std::min(right+9, forward.size()-1);
 
197
                MessageId nd(forward[i].id());
 
198
                nd.increment(); // hope that it doesn't exist (-> skips one)
 
199
                cache.o << " <next>" << nd.serialize() << "</next>\n";
 
200
        }
 
201
        
 
202
        if (left < backward.size())
 
203
        {       // we need a prev link
 
204
                i = std::min(left+10, backward.size()-1);
 
205
                MessageId pd(backward[i].id());
 
206
                pd.increment();
 
207
                cache.o << " <prev>" << pd.serialize() << "</prev>\n";
 
208
        }
 
209
        
 
210
        for (i = 0; i < queue.size(); ++i)
 
211
                cache.o << " <row>" << queue[i] << "</row>\n";
 
212
        
 
213
        cache.o << "</search>\n";
 
214
        
 
215
        return 1;
 
216
}