/[mws]/trunk/httpd.pl
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/httpd.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 47 - (hide annotations)
Tue May 11 22:59:27 2004 UTC (20 years ago) by dpavlin
File MIME type: text/plain
File size: 8390 byte(s)
Major code update: 0.9-rc3 if no serious problems are found, this will
become first public version (0.9).

- search.pl is working again
- fixed Mail::Box problem with unimplemented lock_type => 'none' on Maildir
- documented Mozilla 1.5 problem with sidebar float: right
- don't output anything from swish-e while indexing
- remove (e-mail) from addresses (it seems that Exchange like to add those)
- added progress report while indexing
- documented all command-line utilities

1 dpavlin 5 #!/usr/bin/perl
2    
3     # based on post
4     # http://www.mail-archive.com/libwww@perl.org/msg04750.html
5    
6 dpavlin 43 BEGIN {
7     my $basedir = readlink($0) || $0; $basedir =~ s#/[^/]+$##;
8     unshift(@INC, $basedir);
9     }
10    
11 dpavlin 47 =head1 NAME
12    
13     httpd.pl - http server for Mail::Box Web Search
14    
15     =head1 SYNOPSYS
16    
17     httpd.pl [local.conf]
18    
19     =head1 DESCRIPTION
20    
21     This is small http server, based on C<HTTP::Daemon> which is designed
22     for single-user use (on laptop for example) via loopback.
23    
24     It doesn't provide any authentification or authorisation, and it can handle
25     just one request at the time, so it's not suted for public-facing sites,
26     even if you don't care about security of your mailboxes.
27    
28     =head1 SEE ALSO
29    
30     C<MWS> perl modules which are part of this package
31    
32     =cut
33    
34 dpavlin 5 use strict;
35     use warnings;
36 dpavlin 41 use MWS::SWISH;
37     #use MWS::Plucene;
38 dpavlin 5 use HTTP::Daemon;
39     use HTTP::Status;
40     use IO::String;
41 dpavlin 6 use CGI::Lite;
42     use Template;
43 dpavlin 24 use URI::Escape;
44 dpavlin 5
45 dpavlin 6 use Data::Dumper;
46    
47 dpavlin 17 my $debug = 1;
48    
49 dpavlin 27 my $config_file = shift @ARGV || 'global.conf';
50    
51     if (! -f $config_file) {
52     print qq{Usage: $0 [/path/to/local.conf]
53    
54     If local.conf is not specified, global.conf in current directory will
55     be used.
56     };
57     exit 1;
58     }
59    
60 dpavlin 41 my $mws = MWS::SWISH->new(config_file => $config_file);
61     #my $mws = MWS::Plucene->new(config_file => $config_file, debug => $debug);
62 dpavlin 39
63     my ($local_addr,$local_port) = ('127.0.0.1',6969);
64    
65     my $listen = $mws->{config}->val('global', 'listen');
66 dpavlin 41
67     print STDERR "using listen $listen\n" if ($listen);
68    
69     if ($listen && $listen =~ m/:/) {
70     ($local_addr,$local_port) = split(/:/,$listen,2);
71 dpavlin 39 } elsif ($listen) {
72     $local_addr = $listen;
73     }
74    
75     my $d = HTTP::Daemon->new(
76     Reuse => 1,
77     LocalAddr => $local_addr,
78     LocalPort => $local_port,
79 dpavlin 41 ) || die "can't create HTTP::Daemon on $local_addr:$local_port: $!";
80 dpavlin 39
81 dpavlin 6 my $cgi = new CGI::Lite;
82     my $tt = Template->new({
83     INCLUDE_PATH => $mws->{config}->val('global', 'templates'),
84     FILTERS => {
85     'body5' => \&body5_filter,
86 dpavlin 28 'body' => \&body_filter,
87 dpavlin 6 },
88 dpavlin 20 EVAL_PERL => 1,
89 dpavlin 6 });
90    
91 dpavlin 25 my $static_html = $mws->{config}->val('global', 'static_html');
92    
93 dpavlin 13 print "Web server ready at: ", $d->url, "\n";
94 dpavlin 6
95 dpavlin 13
96 dpavlin 5 while ( my $c = $d->accept ) {
97     while ( my $r = $c->get_request ) {
98    
99     # environs that a webserver should set.
100     $ENV{'REQUEST_METHOD'} = $r->method;
101     $ENV{'GATEWAY_INTERFACE'} = "CGI/1.0";
102     $ENV{'SERVER_PROTOCOL'} = $r->protocol;
103     $ENV{'CONTENT_TYPE'} = $r->content_type;
104    
105 dpavlin 6 # this part is based on CGI::Lite
106 dpavlin 5
107 dpavlin 6 $cgi->close_all_files();
108     $cgi->{web_data} = {};
109     $cgi->{ordered_keys} = [];
110     $cgi->{all_handles} = [];
111     $cgi->{error_status} = 0;
112     $cgi->{error_message} = undef;
113    
114 dpavlin 5 if ( $r->method eq 'GET' || $r->uri =~ /\?/ ) {
115 dpavlin 6 my $query_string = $r->uri;
116     $query_string =~ s/[^\?]+\?(.*)/$1/;
117     $cgi->_decode_url_encoded_data (\$query_string, 'form');
118    
119     } elsif ( $r->method eq 'POST' ) {
120    
121     if ($r->content_type eq 'application/x-www-form-urlencoded') {
122     # local $^W = 0;
123     $cgi->_decode_url_encoded_data (\$r->content, 'form');
124     } elsif ($r->content_type =~ /multipart\/form-data/) {
125     my ($boundary) = $r->content_type =~ /boundary=(\S+)$/;
126     $cgi->_parse_multipart_data ($r->content_length, $boundary);
127     }
128     } else {
129     $c->send_error(RC_FORBIDDEN);
130 dpavlin 5 }
131    
132 dpavlin 6 my $param = $cgi->{web_data};
133     my $url = $r->url->path;
134 dpavlin 5
135 dpavlin 6 # XXX LOG
136 dpavlin 30 print $r->method," ",$url,"\n";
137 dpavlin 42 print Dumper($param,$mws->{counter}),"\n" if ($debug);
138 dpavlin 5
139 dpavlin 25 # is this static page?
140     if ($static_html && -f "$static_html/$url") {
141     print "static file: $static_html/$url\n" if ($debug);
142     $c->send_file_response("$static_html/$url");
143     $c->close;
144     next;
145     }
146    
147 dpavlin 7 # template file name (use ?format=html as default)
148     my $tpl_file = 'master.';
149     $tpl_file .= $param->{'format'} || 'html';
150    
151 dpavlin 20 # parse date from url
152     my ($yyyy,$mm,$dd) = $mws->yyyymmdd;
153    
154     my $yyyymm;
155    
156     my $date_limit;
157    
158     if ($url =~ m,^/(\d{4})[/-](\d+)[/-](\d+),) {
159     ($yyyy, $mm, $dd) = $mws->fmtdate($1,$2,$3);
160     $date_limit = "$yyyy-$mm-$dd";
161     } elsif ($url =~ m,^/(\d{4})[/-](\d+),) {
162     ($yyyy,$mm) = $mws->fmtdate($1,$2);
163     $date_limit = "$yyyy-$mm";
164     } elsif ($url =~ m,^/(\d{4}),) {
165     $date_limit = $mws->fmtdate($1);
166     }
167    
168 dpavlin 7 #
169     # implement functionality and generate HTML
170     #
171 dpavlin 6 my $html;
172 dpavlin 5
173 dpavlin 12 if ($param->{'search_val'} && $param->{'search_fld'} && !$param->{'search'}) {
174     $param->{'search'} = $param->{'search_fld'}.":".$param->{'search_val'};
175 dpavlin 16 } elsif ($param->{'search'}) {
176     ($param->{'search_fld'}, $param->{'search_val'}) = split(/:/,$param->{'search'},2);
177 dpavlin 12 }
178    
179 dpavlin 13 my $tpl_var = {
180 dpavlin 20 param => $param,
181     yyyy => $yyyy,
182     mm => $mm,
183     dd => $dd,
184 dpavlin 21 date_limit => $date_limit,
185 dpavlin 13 };
186    
187 dpavlin 27 # is this access to root of web server?
188     if ($url eq "/" && !$param->{'search'}) {
189     # if first access, go to current year
190     $date_limit = $mws->fmtdate($yyyy);
191 dpavlin 28 $param->{sort_by} = "date desc";
192 dpavlin 27 }
193    
194 dpavlin 21 # ?show_id=XXXXxxxx___message_id___xxxxXXXX
195     if ($param->{'show_id'}) {
196 dpavlin 20
197 dpavlin 21 $mws->reset_counters;
198     my $row = $mws->fetch_result_by_id($param->{'show_id'});
199     $tpl_var->{message} = $row;
200     } elsif ($param->{'search'} || $date_limit) {
201 dpavlin 5
202 dpavlin 21 # show search results
203     # ?search=foo:bar
204 dpavlin 5
205 dpavlin 27 my @search;
206     push @search, $param->{'search'} if ($param->{'search'});
207 dpavlin 21
208     if ($date_limit) {
209     push @search, "and" if (@search);
210     push @search, "date:\"$date_limit\"";
211     }
212    
213 dpavlin 24 if ($param->{sort_by}) {
214     push @search, "sort:".$param->{sort_by};
215     }
216    
217 dpavlin 21 print STDERR "search: ",join(" ",@search),"\n";
218    
219     my $results = $mws->search(@search);
220 dpavlin 6 my @res = $mws->fetch_all_results();
221 dpavlin 5
222 dpavlin 20 $tpl_var->{results} = \@res if (@res);
223 dpavlin 25 $tpl_var->{total_hits} = $mws->{total_hits} || 0;
224 dpavlin 7
225 dpavlin 30 # no hits, offer suggestions
226     if (! $tpl_var->{results}) {
227     @{$tpl_var->{apropos}} = $mws->apropos_index($param->{'search_fld'}, $param->{'search_val'});
228     }
229    
230 dpavlin 6 }
231 dpavlin 5
232 dpavlin 19
233     # push counters to template
234 dpavlin 42 foreach my $f (qw(from to cc bcc folder)) {
235 dpavlin 19 my $h = $mws->counter($f) || next;
236     my @a;
237     foreach my $k (sort { $h->{$b}->{usage} <=> $h->{$a}->{usage} } keys %$h) {
238     push @a, $h->{$k};
239     }
240     $tpl_var->{counters}->{$f} = [ @a ] if (@a);
241     }
242    
243 dpavlin 20 # push calendar in template
244     $tpl_var->{calendar} = $mws->counter('calendar');
245    
246 dpavlin 13 $tt->process($tpl_file, $tpl_var, \$html) || die $tt->error();
247    
248 dpavlin 7 #
249     # send HTMLto client
250     #
251    
252 dpavlin 5 my $res = HTTP::Response->new(RC_OK);
253 dpavlin 14 $res->header( 'Content-type' => 'text/html; charset=ISO-8859-2' );
254 dpavlin 6 $res->content($html);
255 dpavlin 5 $c->send_response($res);
256    
257     $c->close;
258     }
259     undef($c);
260     }
261 dpavlin 6
262     # template toolkit filter
263    
264 dpavlin 28 sub html_escape($) {
265 dpavlin 30 my $text = shift || return;
266 dpavlin 28
267 dpavlin 30 # don't re-escape html
268 dpavlin 37 #return $text if ($text =~ /&(?:lt|gt|amp|quot);/);
269 dpavlin 30
270 dpavlin 28 # Escape <, >, & and ", and to produce valid XML
271     my %escape = ('<'=>'&lt;', '>'=>'&gt;', '&'=>'&amp;', '"'=>'&quot;');
272     my $escape_re = join '|' => keys %escape;
273    
274     $text =~ s/($escape_re)/$escape{$1}/gs;
275 dpavlin 34
276     while ($text =~ s/#-#(quote|signature)(\d*)##(.+?)##\1\2#-#/<span class="$1">$3<\/span>/gs) { } ;
277    
278 dpavlin 28 return $text;
279     }
280    
281 dpavlin 12 #use Text::Context::EitherSide;
282    
283 dpavlin 6 sub body5_filter {
284     my $text = shift;
285 dpavlin 28
286     # remove quote
287 dpavlin 37 $text =~ s/^[\>:\|=]+[^\n\r]*[\n\r]*$/#-q-#/msg;
288 dpavlin 28 # remove quote author
289 dpavlin 37 $text =~ s/[\n\r]+[^\n\r]+:\s*(?:#-q-#[\n\r*])+//gs;
290     $text =~ s/^[^\n\r]+:\s*(?:#-q-#[\n\r]*)+//gs;
291 dpavlin 30 $text =~ s/#-q-#[\n\r]*//gs;
292 dpavlin 28 # outlook quoting
293     $text =~ s/(\s*--+\s*Original\s+Message\s*--+.*)$//si;
294 dpavlin 34 $text =~ s/(\s*--+\s*Forwarded\s+message.+\s*--+.*)$//si;
295 dpavlin 28
296     # remove signature
297 dpavlin 44 $text =~ s/(?:^|[\n\r]+)*--\s*[\n\r]+.*$//s;
298     $text =~ s/(?:^|[\n\r]+)*_____+[\n\r]+.*$//s;
299 dpavlin 28
300     # compress cr/lf
301     $text =~ s/[\n\r]+/\n/gs;
302    
303     # remove whitespaces
304     $text =~ s/^\n+//gs;
305     $text =~ s/[\s\n]+$//gs;
306    
307 dpavlin 34 if ($text eq "") {
308     $text="#-#quote##forwarded message##quote#-#";
309     }
310    
311 dpavlin 28 # cut to 5 lines;
312 dpavlin 14 if ($text =~ s,^((?:.*?[\n\r]){5}).*$,$1,s) {
313     $text =~ s/[\n\r]*$/ .../;
314     }
315 dpavlin 12
316     # my $context = Text::Context::EitherSide->new($text, context => 5);
317     # return $context->as_string("perl");
318    
319 dpavlin 28 return html_escape($text);
320     }
321    
322     sub body_filter {
323     my $text = shift;
324    
325     my $sig = '';
326    
327     # remove signature
328     if ($text =~ s/([\n\r]+)(--\s*[\n\r]+.*)$//s) {
329     $sig = "$1#-#signature##$2##signature#-#";
330 dpavlin 44 } elsif ($text =~s/(^|[\n\r]+)*(_____+[\n\r]+.*)$//s) {
331     $sig = "$1#-#signature##$2##signature#-#";
332 dpavlin 28 }
333    
334     # find quoted text
335 dpavlin 37 $text =~ s/^([\>:\|=]+[^\n\r]*[\n\r]*)$/#-#quote1##$1##quote1#-#/mg;
336 dpavlin 30 $text =~ s/(--+\s*Original\s+Message\s*--+.*)$/#-#quote2##$1##quote2#-#/si;
337 dpavlin 34 $text =~ s/(--+\s*Forwarded\s+message.+\s*--+.*)$/#-#quote3##$1##quote3#-#/si;
338 dpavlin 28
339     $text = html_escape($text . $sig);
340 dpavlin 6 return $text;
341     }
342 dpavlin 7

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26