blib/lib/HTML/EP.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 349 | 605 | 57.6 |
branch | 166 | 344 | 48.2 |
condition | 32 | 148 | 21.6 |
subroutine | 33 | 54 | 61.1 |
pod | 0 | 26 | 0.0 |
total | 580 | 1177 | 49.2 |
line | stmt | bran | cond | sub | pod | time | code | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | # -*- perl -*- | |||||||||||||
2 | # | |||||||||||||
3 | # HTML::EP - A Perl based HTML extension. | |||||||||||||
4 | # | |||||||||||||
5 | # | |||||||||||||
6 | # Copyright (C) 1998 Jochen Wiedmann | |||||||||||||
7 | # Am Eisteich 9 | |||||||||||||
8 | # 72555 Metzingen | |||||||||||||
9 | # Germany | |||||||||||||
10 | # | |||||||||||||
11 | # Email: joe@ispsoft.de | |||||||||||||
12 | # | |||||||||||||
13 | # | |||||||||||||
14 | # Portions Copyright (C) 1999 OnTV Pittsburgh, L.P. | |||||||||||||
15 | # 123 University St. | |||||||||||||
16 | # Pittsburgh, PA 15213 | |||||||||||||
17 | # USA | |||||||||||||
18 | # | |||||||||||||
19 | # Phone: 1 412 681 5230 | |||||||||||||
20 | # Developer: Jason McMullan |
|||||||||||||
21 | # Developer: Erin Glendenning |
|||||||||||||
22 | # | |||||||||||||
23 | # | |||||||||||||
24 | # All rights reserved. | |||||||||||||
25 | # | |||||||||||||
26 | # You may distribute this module under the terms of either | |||||||||||||
27 | # the GNU General Public License or the Artistic License, as | |||||||||||||
28 | # specified in the Perl README file. | |||||||||||||
29 | # | |||||||||||||
30 | ############################################################################ | |||||||||||||
31 | ||||||||||||||
32 | require 5.005; | |||||||||||||
33 | 8 | 8 | 22314 | use strict; | ||||||||||
8 | 17 | |||||||||||||
8 | 347 | |||||||||||||
34 | ||||||||||||||
35 | 8 | 8 | 159909 | use CGI (); | ||||||||||
8 | 20731030 | |||||||||||||
8 | 234 | |||||||||||||
36 | 8 | 8 | 16621 | use Symbol (); | ||||||||||
8 | 7467 | |||||||||||||
8 | 173 | |||||||||||||
37 | 8 | 8 | 4780 | use HTML::EP::Config (); | ||||||||||
8 | 32 | |||||||||||||
8 | 163 | |||||||||||||
38 | 8 | 8 | 3837 | use HTML::EP::Parser (); | ||||||||||
8 | 26 | |||||||||||||
8 | 31091 | |||||||||||||
39 | ||||||||||||||
40 | ||||||||||||||
41 | package HTML::EP; | |||||||||||||
42 | ||||||||||||||
43 | $HTML::EP::VERSION = '0.2011'; | |||||||||||||
44 | ||||||||||||||
45 | ||||||||||||||
46 | sub new { | |||||||||||||
47 | 86 | 86 | 0 | 27078 | my $proto = shift; | |||||||||
48 | 86 | 100 | 315 | my $self = (@_ == 1) ? {%{shift()}} : { @_ }; | ||||||||||
9 | 34 | |||||||||||||
49 | 86 | 304 | $self->{'_ep_output'} = ''; | |||||||||||
50 | 86 | 202 | $self->{'_ep_output_stack'} = []; | |||||||||||
51 | 86 | 33 | 532 | $self->{'_ep_config'} ||= $HTML::EP::Config::CONFIGURATION; | ||||||||||
52 | 86 | 50 | 336 | $self->{'debug'} ||= 0; | ||||||||||
53 | 86 | 50 | 547 | $self->{'cgi'} ||= (CGI->new() || die "Failed to create CGI object: $!"); | ||||||||||
33 | ||||||||||||||
54 | 86 | 33 | 61229 | bless($self, (ref($proto) || $proto)); | ||||||||||
55 | } | |||||||||||||
56 | ||||||||||||||
57 | sub Run { | |||||||||||||
58 | 84 | 84 | 0 | 1918 | my($self, $template) = @_; | |||||||||
59 | 84 | 365 | my $parser = HTML::EP::Parser->new(); | |||||||||||
60 | 84 | 161 | my $r = $self->{'_ep_r'}; | |||||||||||
61 | 84 | 50 | 33 | 524 | $self->{'env'} ||= $r ? | |||||||||
62 | { $r->cgi_env(), 'PATH_INFO' => $r->uri() } : \%ENV; | |||||||||||||
63 | 84 | 50 | 164 | if ($template) { | ||||||||||
64 | 84 | 966 | $parser->parse($template); | |||||||||||
65 | } else { | |||||||||||||
66 | 0 | 0 | 0 | my $file = $self->{'env'}->{'PATH_TRANSLATED'} | ||||||||||
67 | || die "Missing server environment (PATH_TRANSLATED variable)"; | |||||||||||||
68 | 0 | 0 | my $fh = Symbol::gensym(); | |||||||||||
69 | 0 | 0 | 0 | open($fh, "<$file") || die "Failed to open $file: $!"; | ||||||||||
70 | 0 | 0 | $parser->parse_file($fh); | |||||||||||
71 | } | |||||||||||||
72 | 84 | 359 | $parser->eof(); | |||||||||||
73 | 84 | 316 | my $tokens = HTML::EP::Tokens->new('tokens' => $parser->{'_ep_tokens'}); | |||||||||||
74 | 84 | 360 | $self->{'_ep_output'} = $self->ParseVars($self->TokenMarch($tokens)); | |||||||||||
75 | } | |||||||||||||
76 | ||||||||||||||
77 | ||||||||||||||
78 | sub CgiRun { | |||||||||||||
79 | 0 | 0 | 0 | 0 | my($self, $path, $r) = @_; | |||||||||
80 | 0 | 0 | my $cgi = $self->{'cgi'}; | |||||||||||
81 | 0 | 0 | my $ok_templates = $self->{'_ep_config'}->{'ok_templates'}; | |||||||||||
82 | 0 | 0 | local $| = 1; | |||||||||||
83 | 0 | 0 | my $output = eval { | |||||||||||
84 | 0 | 0 | 0 | 0 | die "Access to $path forbidden; check ok_templates in ", | |||||||||
85 | $INC{'HTML/EP/Config.pm'} | |||||||||||||
86 | if $ok_templates && $path !~ /$ok_templates/; | |||||||||||||
87 | 0 | 0 | 0 | $self->_ep_debug({}) if $cgi->param('debug'); | ||||||||||
88 | 0 | 0 | $self->Run(); | |||||||||||
89 | }; | |||||||||||||
90 | ||||||||||||||
91 | 0 | 0 | 0 | if ($@) { | ||||||||||
92 | 0 | 0 | 0 | if ($@ =~ /_ep_exit, ignore/) { | ||||||||||
93 | 0 | 0 | $output .= $self->ParseVars($self->{'_ep_output'}); | |||||||||||
94 | } else { | |||||||||||||
95 | 0 | 0 | my $errmsg; | |||||||||||
96 | 0 | 0 | my $errstr = $@; | |||||||||||
97 | 0 | 0 | 0 | my $errfile = $self->{_ep_err_type} ? | ||||||||||
98 | $self->{_ep_err_file_user} : $self->{_ep_err_file_system}; | |||||||||||||
99 | 0 | 0 | 0 | if ($errfile) { | ||||||||||
100 | 0 | 0 | 0 | if ($errfile =~ /^\//) { | ||||||||||
101 | 0 | 0 | 0 | my $derrfile = $r ? | ||||||||||
102 | $r->cgi_var('DOCUMENT_ROOT') : $ENV{'DOCUMENT_ROOT'} | |||||||||||||
103 | . $errfile; | |||||||||||||
104 | 0 | 0 | 0 | if ($self->{'debug'}) { | ||||||||||
105 | 0 | 0 | $self->print("Error type = " . $self->{_ep_err_type} . | |||||||||||
106 | ", error file = $errfile" . | |||||||||||||
107 | ", derror file = $derrfile\n"); | |||||||||||||
108 | } | |||||||||||||
109 | 0 | 0 | 0 | if (-f $derrfile) { $errfile = $derrfile } | ||||||||||
0 | 0 | |||||||||||||
110 | } | |||||||||||||
111 | 0 | 0 | my $fh = Symbol::gensym(); | |||||||||||
112 | 0 | 0 | 0 | if (open($fh, "<$errfile")) { | ||||||||||
113 | 0 | 0 | local $/ = undef; | |||||||||||
114 | 0 | 0 | $errmsg = <$fh>; | |||||||||||
115 | 0 | 0 | close($fh); | |||||||||||
116 | } | |||||||||||||
117 | } | |||||||||||||
118 | 0 | 0 | 0 | if (!$errmsg) { | ||||||||||
119 | 0 | 0 | 0 | $errmsg = $self->{_ep_err_type} ? | ||||||||||
120 | $self->{_ep_err_msg_user} : $self->{_ep_err_msg_system}; | |||||||||||||
121 | } | |||||||||||||
122 | 0 | 0 | return $self->SimpleError($errmsg, $errstr); | |||||||||||
123 | } | |||||||||||||
124 | } | |||||||||||||
125 | ||||||||||||||
126 | 0 | 0 | 0 | if (!$self->{_ep_stop}) { | ||||||||||
127 | 0 | 0 | $self->print($cgi->header($self->SetCookies(), | |||||||||||
128 | 0 | 0 | %{$self->{'_ep_headers'}}), $output); | |||||||||||
129 | } | |||||||||||||
130 | } | |||||||||||||
131 | ||||||||||||||
132 | sub FindEndTag { | |||||||||||||
133 | 29 | 29 | 0 | 47 | my($self, $tokens, $tag) = @_; | |||||||||
134 | 29 | 32 | my $level = 0; | |||||||||||
135 | 29 | 77 | while (defined(my $token = $tokens->Token())) { | |||||||||||
136 | 77 | 100 | 285 | if ($token->{'type'} eq 'S') { | ||||||||||
100 | ||||||||||||||
137 | 9 | 100 | 42 | ++$level if $token->{'tag'} eq $tag; | ||||||||||
138 | } elsif ($token->{'type'} eq 'E') { | |||||||||||||
139 | 36 | 100 | 81 | if ($token->{'tag'} eq $tag) { | ||||||||||
140 | 34 | 100 | 127 | return $tokens->First() unless $level--; | ||||||||||
141 | } | |||||||||||||
142 | } | |||||||||||||
143 | } | |||||||||||||
144 | 0 | 0 | die "$tag without /$tag"; | |||||||||||
145 | } | |||||||||||||
146 | ||||||||||||||
147 | sub AttrVal { | |||||||||||||
148 | 12 | 12 | 0 | 29 | my($self, $val, $tokens, $token, $parse) = @_; | |||||||||
149 | 12 | 100 | 30 | return $val if defined($val); | ||||||||||
150 | 9 | 26 | my $first = $tokens->First(); | |||||||||||
151 | 9 | 50 | 34 | my $last = $self->FindEndTag($tokens, | ||||||||||
152 | ref($token) ? $token->{'tag'} : $token); | |||||||||||||
153 | 9 | 32 | my $output = $self->TokenMarch($tokens->Clone($first, $last-1)); | |||||||||||
154 | 9 | 100 | 47 | $parse ? $self->ParseVars($output) : $output; | ||||||||||
155 | } | |||||||||||||
156 | ||||||||||||||
157 | sub ParseAttr { | |||||||||||||
158 | 152 | 152 | 0 | 192 | my $self = shift; my $attr = shift; | |||||||||
152 | 242 | |||||||||||||
159 | 152 | 216 | my $parsed_attr = {}; | |||||||||||
160 | 152 | 619 | while (my($var, $val) = each %$attr) { | |||||||||||
161 | 187 | 100 | 575 | if ($val =~ /\$\_\W/) { | ||||||||||
100 | ||||||||||||||
162 | 49 | 90 | $_ = $self; | |||||||||||
163 | 49 | 1442 | $parsed_attr->{$var} = eval $val; | |||||||||||
164 | 49 | 50 | 281 | die $@ if $@; | ||||||||||
165 | } elsif ($val =~ /\$/) { | |||||||||||||
166 | 34 | 87 | $parsed_attr->{$var} = $self->ParseVars($val); | |||||||||||
167 | } else { | |||||||||||||
168 | 104 | 497 | $parsed_attr->{$var} = $val; | |||||||||||
169 | } | |||||||||||||
170 | } | |||||||||||||
171 | 152 | 558 | $parsed_attr; | |||||||||||
172 | } | |||||||||||||
173 | ||||||||||||||
174 | sub RepeatedTokenMarch { | |||||||||||||
175 | 75 | 75 | 0 | 87 | my $self = shift; my $tokens = shift; | |||||||||
75 | 85 | |||||||||||||
176 | 75 | 182 | my $first = $tokens->First(); | |||||||||||
177 | 75 | 196 | my $last = $tokens->Last(); | |||||||||||
178 | 75 | 156 | my $res = $self->TokenMarch($tokens); | |||||||||||
179 | 75 | 188 | $tokens->First($first); | |||||||||||
180 | 75 | 170 | $tokens->Last($last); | |||||||||||
181 | 75 | 267 | $res; | |||||||||||
182 | } | |||||||||||||
183 | sub TokenMarch { | |||||||||||||
184 | 227 | 227 | 0 | 309 | my($self, $tokens) = @_; | |||||||||
185 | 227 | 318 | my $debug = $self->{'debug'}; | |||||||||||
186 | ||||||||||||||
187 | 227 | 460 | push(@{$self->{'_ep_output_stack'}}, $self->{'_ep_output'}); | |||||||||||
227 | 559 | |||||||||||||
188 | 227 | 425 | $self->{'_ep_output'} = ''; | |||||||||||
189 | 227 | 50 | 478 | $self->print("TokenMarch: From ", $tokens->First(), " to ", | ||||||||||
190 | $tokens->Last(), ".\n") if $debug >= 2; | |||||||||||||
191 | 227 | 622 | while (defined(my $token = $tokens->Token())) { | |||||||||||
192 | 337 | 549 | my $type = $token->{'type'}; | |||||||||||
193 | 337 | 341 | my $res; | |||||||||||
194 | 337 | 100 | 803 | if ($type eq 'T') { | ||||||||||
100 | ||||||||||||||
50 | ||||||||||||||
0 | ||||||||||||||
195 | 205 | 342 | $res = $token->{'text'}; | |||||||||||
196 | } elsif ($token->{'type'} eq 'S') { | |||||||||||||
197 | 126 | 237 | my $method = "_$token->{'tag'}"; | |||||||||||
198 | 126 | 177 | my $attr = $token->{'attr'}; | |||||||||||
199 | 126 | 540 | $method =~ s/\-/_/g; | |||||||||||
200 | 126 | 320 | $res = $self->$method($self->ParseAttr($attr), $tokens, $token); | |||||||||||
201 | 120 | 50 | 474 | if (!defined($res)) { | ||||||||||
202 | # Upwards compatibility: If the method returned undef, then | |||||||||||||
203 | # it is a multiline tag in the sense of EP1. We've got to | |||||||||||||
204 | # collect all lines until a matching /$tag and evaluate it. | |||||||||||||
205 | 0 | 0 | my $def = delete $tokens->{'default'}; | |||||||||||
206 | 0 | 0 | my $first = $tokens->First(); | |||||||||||
207 | 0 | 0 | my $last = $self->FindEndTag($tokens, $token->{'tag'}); | |||||||||||
208 | 0 | 0 | my $t = $tokens->Clone($first, $last-1); | |||||||||||
209 | 0 | 0 | $attr->{$def} = $self->TokenMarch($t); | |||||||||||
210 | 0 | 0 | $res = $self->$method($attr, $tokens); | |||||||||||
211 | } | |||||||||||||
212 | } elsif ($token->{'type'} eq 'I') { | |||||||||||||
213 | 6 | 14 | $res = $self->RepeatedTokenMarch($token->{'tokens'}); | |||||||||||
214 | } elsif ($token->{'type'} eq 'E') { | |||||||||||||
215 | 0 | 0 | die "Unexpected end tag: /$token->{'tag'} without $token->{'tag'}"; | |||||||||||
216 | } else { | |||||||||||||
217 | 0 | 0 | die "Unknown token type $self->{'type'}"; | |||||||||||
218 | } | |||||||||||||
219 | 331 | 1266 | $self->{'_ep_output'} .= $res; | |||||||||||
220 | } | |||||||||||||
221 | 221 | 380 | my $result = $self->{'_ep_output'}; | |||||||||||
222 | 221 | 50 | 419 | $self->print("TokenMarch: Returning $result.\n") if $debug >= 2; | ||||||||||
223 | 221 | 222 | $self->{'_ep_output'} = pop(@{$self->{'_ep_output_stack'}}); | |||||||||||
221 | 458 | |||||||||||||
224 | 221 | 708 | $result; | |||||||||||
225 | } | |||||||||||||
226 | ||||||||||||||
227 | ||||||||||||||
228 | ||||||||||||||
229 | ||||||||||||||
230 | sub WarnHandler { | |||||||||||||
231 | 0 | 0 | 0 | 0 | my $msg = shift; | |||||||||
232 | 0 | 0 | 0 | die $msg unless defined($^S); | ||||||||||
233 | 0 | 0 | print STDERR $msg; | |||||||||||
234 | 0 | 0 | 0 | print STDERR "\n" unless $msg =~ /\n$/; | ||||||||||
235 | } | |||||||||||||
236 | ||||||||||||||
237 | ||||||||||||||
238 | sub SimpleError { | |||||||||||||
239 | 0 | 0 | 0 | 0 | my($self, $template, $errmsg, $admin) = @_; | |||||||||
240 | 0 | 0 | my $r; | |||||||||||
241 | 0 | 0 | 0 | 0 | $r = $self->{'_ep_r'} if $self && ref($self); | |||||||||
242 | 0 | 0 | 0 | 0 | $admin ||= ($r ? $r->cgi_var('SERVER_ADMIN') : $ENV{'SERVER_ADMIN'}); | |||||||||
243 | 0 | 0 | 0 | $admin = $admin ? "Webmaster" : 'Webmaster'; | ||||||||||
244 | 0 | 0 | my $vars = { errmsg => $errmsg, admin => $admin }; | |||||||||||
245 | ||||||||||||||
246 | 0 | 0 | 0 | if (!$template) { | ||||||||||
247 | 0 | 0 | $template = <<'END_OF_HTML'; | |||||||||||
248 | |
|||||||||||||
249 | Fatal internal error |
|||||||||||||
250 | An internal error occurred. The error message is: |
|||||||||||||
251 | |
|||||||||||||
252 | $errmsg$. | |||||||||||||
253 | ||||||||||||||
254 | Please contact the $admin$ and tell him URL, time and error message. |
|||||||||||||
255 | We apologize for any inconvenience, please try again later. |
|||||||||||||
256 | |
|||||||||||||
257 | Yours sincerely |
|||||||||||||
258 | ||||||||||||||
259 | END_OF_HTML | |||||||||||||
260 | } | |||||||||||||
261 | ||||||||||||||
262 | 0 | 0 | $template =~ s/\$(\w+)\$/$vars->{$1}/g; | |||||||||||
263 | 0 | 0 | 0 | if ($r) { | ||||||||||
264 | 0 | 0 | $r->print($self->{'cgi'}->header('-type' => 'text/html'), $template); | |||||||||||
265 | } else { | |||||||||||||
266 | 0 | 0 | print("content-type: text/html\n\n", $template); | |||||||||||
267 | 0 | 0 | exit 0; | |||||||||||
268 | } | |||||||||||||
269 | } | |||||||||||||
270 | ||||||||||||||
271 | sub print ($;@) { | |||||||||||||
272 | 0 | 0 | 0 | 0 | my $self = shift; | |||||||||
273 | 0 | 0 | 0 | $self->{_ep_r} ? $self->{_ep_r}->print(@_) : print @_; | ||||||||||
274 | } | |||||||||||||
275 | ||||||||||||||
276 | sub printf { | |||||||||||||
277 | 0 | 0 | 0 | 0 | my($self, $format, @args) = @_; | |||||||||
278 | 0 | 0 | $self->print(sprintf($format, @args)); | |||||||||||
279 | } | |||||||||||||
280 | ||||||||||||||
281 | sub escapeHTML { | |||||||||||||
282 | 192 | 192 | 0 | 227 | my $self = shift; my $str = shift; | |||||||||
192 | 215 | |||||||||||||
283 | 192 | 277 | $str =~ s/&/&/g; | |||||||||||
284 | 192 | 225 | $str =~ s/\"/"/g; | |||||||||||
285 | 192 | 200 | $str =~ s/>/>/g; | |||||||||||
286 | 192 | 208 | $str =~ s/</g; | |||||||||||
287 | 192 | 209 | $str =~ s/\$/$/g; | |||||||||||
288 | 192 | 453 | $str; | |||||||||||
289 | } | |||||||||||||
290 | ||||||||||||||
291 | sub FindVar { | |||||||||||||
292 | 208 | 208 | 0 | 366 | my($self, $var, $subvar) = @_; | |||||||||
293 | 208 | 50 | 530 | if ($var eq 'cgi') { | ||||||||||
294 | 0 | 0 | $subvar =~ s/\-\>//; | |||||||||||
295 | 0 | 0 | return $self->{'cgi'}->param($subvar); | |||||||||||
296 | } | |||||||||||||
297 | ||||||||||||||
298 | 208 | 306 | $var = $self->{$var}; | |||||||||||
299 | 208 | 66 | 575 | while ($subvar && $subvar =~ /^\-\>(\w+)(.*)/) { | ||||||||||
300 | 31 | 50 | 69 | return '' unless ref $var; | ||||||||||
301 | 31 | 44 | my $v = $1; | |||||||||||
302 | 31 | 45 | $subvar = $2; | |||||||||||
303 | 31 | 100 | 369 | if ($v =~ /^\d+$/) { | ||||||||||
304 | 4 | 19 | $var = $var->[$v]; | |||||||||||
305 | } else { | |||||||||||||
306 | 27 | 126 | $var = $var->{$v}; | |||||||||||
307 | } | |||||||||||||
308 | } | |||||||||||||
309 | 208 | 50 | 537 | defined $var ? $var : ''; | ||||||||||
310 | } | |||||||||||||
311 | ||||||||||||||
312 | sub ParseVar { | |||||||||||||
313 | 207 | 207 | 0 | 607 | my($self, $type, $var, $subvar) = @_; | |||||||||
314 | 207 | 233 | my $func; | |||||||||||
315 | ||||||||||||||
316 | 207 | 100 | 100 | 505 | if ($type && $type eq '&') { | |||||||||
317 | # Custom format | |||||||||||||
318 | 9 | 50 | 38 | $func = exists($self->{'_ep_custom_formats'}->{$var}) ? | ||||||||||
319 | $self->{'_ep_custom_formats'}->{$var} : "_format_$var"; | |||||||||||||
320 | ||||||||||||||
321 | # First part of subvar becomes var | |||||||||||||
322 | 9 | 50 | 33 | 66 | if ($subvar && $subvar =~ /^\-\>(\w+)(.*)/) { | |||||||||
323 | 9 | 1105 | $var = $1; | |||||||||||
324 | 9 | 19 | $subvar = $2; | |||||||||||
325 | } else { | |||||||||||||
326 | 0 | 0 | $var = ''; | |||||||||||
327 | } | |||||||||||||
328 | } | |||||||||||||
329 | ||||||||||||||
330 | 207 | 437 | $var = FindVar($self, $var, $subvar); | |||||||||||
331 | ||||||||||||||
332 | 207 | 100 | 100 | 721 | if (!$type || $type eq '%') { | |||||||||
100 | ||||||||||||||
50 | ||||||||||||||
100 | ||||||||||||||
333 | 191 | 581 | $var = $self->escapeHTML($var); | |||||||||||
334 | } elsif ($type eq '#') { | |||||||||||||
335 | 3 | 14 | $var = CGI->escape($var); | |||||||||||
336 | } elsif ($type eq '~') { | |||||||||||||
337 | 0 | 0 | 0 | my $dbh = $self->{'dbh'} || die "Not connected"; | ||||||||||
338 | 0 | 0 | $var = $dbh->quote($var); | |||||||||||
339 | } elsif ($func) { | |||||||||||||
340 | 9 | 74 | $var = $self->$func($var); | |||||||||||
341 | } | |||||||||||||
342 | ||||||||||||||
343 | 207 | 857 | $var; | |||||||||||
344 | } | |||||||||||||
345 | ||||||||||||||
346 | sub ParseVars ($$) { | |||||||||||||
347 | 206 | 206 | 0 | 345 | my($self, $str) = @_; | |||||||||
348 | 206 | 1088 | $str =~ s/\$([\&\@\#\~\%]?)(\w+)((?:\-\>\w+)*)\$/$self->ParseVar($1,$2,$3)/eg; | |||||||||||
206 | 456 | |||||||||||||
349 | 206 | 2309 | $str; | |||||||||||
350 | } | |||||||||||||
351 | ||||||||||||||
352 | ||||||||||||||
353 | ||||||||||||||
354 | # For debugging | |||||||||||||
355 | sub Dump { | |||||||||||||
356 | 0 | 0 | 0 | 0 | my $self = shift; | |||||||||
357 | 0 | 0 | require Data::Dumper; | |||||||||||
358 | 0 | 0 | Data::Dumper->new([@_])->Indent(1)->Terse(1)->Dump(); | |||||||||||
359 | } | |||||||||||||
360 | ||||||||||||||
361 | sub SetCookies { | |||||||||||||
362 | 0 | 0 | 0 | 0 | my $self = shift; | |||||||||
363 | 0 | 0 | my @cookies = values %{$self->{'_ep_cookies'}}; | |||||||||||
0 | 0 | |||||||||||||
364 | 0 | 0 | 0 | return () unless @cookies; | ||||||||||
365 | 0 | 0 | 0 | print "Setting cookies:\n", $self->Dump(\@cookies), "\n" | ||||||||||
366 | if $self->{'debug'}; | |||||||||||||
367 | 0 | 0 | ('-cookie' => \@cookies); | |||||||||||
368 | } | |||||||||||||
369 | ||||||||||||||
370 | ||||||||||||||
371 | ||||||||||||||
372 | sub EvalIf { | |||||||||||||
373 | 83 | 83 | 0 | 118 | my($self, $tag, $attr) = @_; | |||||||||
374 | 83 | 119 | my $debug = $self->{'debug'}; | |||||||||||
375 | 83 | 100 | 211 | if (exists($attr->{'eval'})) { | ||||||||||
376 | 55 | 50 | 99 | $self->print("$tag: Evaluating $attr->{'eval'}\n") if $debug; | ||||||||||
377 | 55 | 256 | return $attr->{'eval'}; | |||||||||||
378 | } | |||||||||||||
379 | 28 | 100 | 69 | if (exists($attr->{'neval'})) { | ||||||||||
380 | 2 | 50 | 6 | $self->print("$tag: Evaluating ! $attr->{'neval'}\n") if $debug; | ||||||||||
381 | 2 | 7 | return !$attr->{'neval'}; | |||||||||||
382 | } | |||||||||||||
383 | 26 | 50 | 65 | die "Missing condition" unless(exists($attr->{'cnd'})); | ||||||||||
384 | 26 | 100 | 160 | if ($attr->{'cnd'} =~ /^(.*?)(==|!=|<=?|>=?)(.*)$/) { | ||||||||||
385 | 22 | 50 | 49 | $self->print("$tag: Numeric condition $1 $2 $3\n") if $debug; | ||||||||||
386 | 22 | 50 | 72 | my $left = $1 || 0; | ||||||||||
387 | 22 | 39 | my $cnd = $2; | |||||||||||
388 | 22 | 50 | 70 | my $right = $3 || 0; | ||||||||||
389 | 22 | 100 | 60 | return ($left == $right) if $cnd eq '=='; | ||||||||||
390 | 19 | 100 | 50 | return ($left != $right) if $cnd eq '!='; | ||||||||||
391 | 16 | 100 | 57 | return ($left < $right) if $cnd eq '<'; | ||||||||||
392 | 9 | 100 | 35 | return ($left > $right) if $cnd eq '>'; | ||||||||||
393 | 6 | 100 | 22 | return ($left >= $right) if $cnd eq '>='; | ||||||||||
394 | 3 | 11 | return ($left <= $right); | |||||||||||
395 | } | |||||||||||||
396 | 4 | 50 | 27 | die "Cannot parse condition cnd=$attr->{'cnd'}" | ||||||||||
397 | unless $attr->{'cnd'} =~ /^\s*\'(.*?)\'\s*(eq|ne)\s*\'(.*)\'\s*$/; | |||||||||||||
398 | 4 | 50 | 9 | $self->print("$tag: String condition $1 $2 $3\n") if $debug; | ||||||||||
399 | 4 | 100 | 17 | return $1 eq $3 if $2 eq 'eq'; | ||||||||||
400 | 2 | 7 | return $1 ne $3; | |||||||||||
401 | } | |||||||||||||
402 | ||||||||||||||
403 | ||||||||||||||
404 | ||||||||||||||
405 | 16 | 16 | 0 | 34 | sub init { 1 } | |||||||||
406 | ||||||||||||||
407 | 0 | 0 | 0 | 0 | sub Stop ($) { my($self) = @_; $self->{_ep_stop} = 1; } | |||||||||
0 | 0 | |||||||||||||
408 | ||||||||||||||
409 | ||||||||||||||
410 | sub _ep_comment { | |||||||||||||
411 | 2 | 2 | 4 | my $self = shift; my $attr = shift; | ||||||||||
2 | 3 | |||||||||||||
412 | 2 | 12 | $self->AttrVal($attr->{'comment'}, @_); | |||||||||||
413 | 2 | 5 | ''; | |||||||||||
414 | } | |||||||||||||
415 | ||||||||||||||
416 | ||||||||||||||
417 | sub _ep_package { | |||||||||||||
418 | 15 | 15 | 24 | my $self = shift; my $attr = shift; | ||||||||||
15 | 38 | |||||||||||||
419 | 15 | 28 | my $package = $attr->{name}; | |||||||||||
420 | 15 | 50 | 33 | 47 | if (!exists($attr->{'require'}) || $attr->{'require'}) { | |||||||||
421 | 15 | 50 | 41 | my @inc = ($ENV{'DOCUMENT_ROOT'} . $attr->{'lib'}, | ||||||||||
422 | $attr->{'lib'}, @INC) if $attr->{'lib'}; | |||||||||||||
423 | 15 | 50 | 37 | local @INC = @inc if @inc; | ||||||||||
424 | 15 | 23 | my $ppm = $package; | |||||||||||
425 | 15 | 54 | $ppm =~ s/\:\:/\//g; | |||||||||||
426 | 15 | 2084 | require "$ppm.pm"; | |||||||||||
427 | } | |||||||||||||
428 | ||||||||||||||
429 | 15 | 100 | 83 | my $pack = ($self->{'_ep_package'} || 0) + 1; | ||||||||||
430 | 15 | 100 | 66 | 77 | if ($attr->{'isa'} || $self->{'_ep_package'}) { | |||||||||
431 | # If ep-package is called multiple times, or if $attr->{'isa'} | |||||||||||||
432 | # is set, we create a new package and bless $self into it. | |||||||||||||
433 | 1 | 3 | my @isa; | |||||||||||
434 | 1 | 50 | 21 | @isa = split(',', $attr->{'isa'}) if @isa; | ||||||||||
435 | 1 | 4 | my $p = ref($self); | |||||||||||
436 | 8 | 8 | 104 | no strict 'refs'; | ||||||||||
8 | 15 | |||||||||||||
8 | 47163 | |||||||||||||
437 | 1 | 3 | push(@isa, $p); | |||||||||||
438 | 1 | 4 | my $bpack = "HTML::EP::PACK$pack"; | |||||||||||
439 | 1 | 3 | @{"$bpack\::ISA"} = ($package, @isa); | |||||||||||
1 | 32 | |||||||||||||
440 | 1 | 7 | bless($self, $bpack); | |||||||||||
441 | } else { | |||||||||||||
442 | # Otherwise it's faster to bless $self into the package | |||||||||||||
443 | 14 | 37 | bless($self, $package); | |||||||||||
444 | } | |||||||||||||
445 | 15 | 50 | $self->{'_ep_package'} = $pack; | |||||||||||
446 | ||||||||||||||
447 | 15 | 57 | $self->init($attr); | |||||||||||
448 | 15 | 36 | ''; | |||||||||||
449 | } | |||||||||||||
450 | ||||||||||||||
451 | sub _ep_debug { | |||||||||||||
452 | 0 | 0 | 0 | my $self = shift; | ||||||||||
453 | 0 | 0 | my $cgi = $self->{'cgi'}; | |||||||||||
454 | ||||||||||||||
455 | 0 | 0 | my $debughosts = $self->{'_ep_config'}->{'debughosts'}; | |||||||||||
456 | 0 | 0 | 0 | if ($debughosts) { | ||||||||||
457 | 0 | 0 | my $remoteip = ''; | |||||||||||
458 | 0 | 0 | my $remotehost = ''; | |||||||||||
459 | 0 | 0 | 0 | 0 | if ($self->{'_ep_r'} && (my $r = $self->{'_ep_r'})) { | |||||||||
460 | 0 | 0 | 0 | $remoteip = ($r->connection()->remote_ip() || ''); | ||||||||||
461 | 0 | 0 | 0 | $remotehost = ($r->get_remote_host() || ''); | ||||||||||
462 | } else { | |||||||||||||
463 | 0 | 0 | 0 | $remoteip = ($ENV{'REMOTE_ADDR'} || ''); | ||||||||||
464 | } | |||||||||||||
465 | 0 | 0 | 0 | 0 | die "Debugging not permitted from $remoteip" | |||||||||
0 | ||||||||||||||
466 | . " ($remotehost), debug hosts = $debughosts" | |||||||||||||
467 | if (($remoteip and $remoteip !~ /$debughosts/) and | |||||||||||||
468 | ($remotehost !~ /$debughosts/)); | |||||||||||||
469 | } | |||||||||||||
470 | ||||||||||||||
471 | 0 | 0 | $| = 1; | |||||||||||
472 | 0 | 0 | $self->print($cgi->header('-type' => 'text/plain')); | |||||||||||
473 | 0 | 0 | $self->print("Entering debugging mode;", | |||||||||||
474 | " list of input values:\n"); | |||||||||||||
475 | 0 | 0 | foreach my $p ($cgi->param()) { | |||||||||||
476 | 0 | 0 | $self->print(" $p = ", $cgi->param($p), "\n"); | |||||||||||
477 | } | |||||||||||||
478 | 0 | 0 | 0 | $self->{'debug'} = $cgi->param('debug') || 1; | ||||||||||
479 | 0 | 0 | ''; | |||||||||||
480 | } | |||||||||||||
481 | ||||||||||||||
482 | sub GetPerlCode { | |||||||||||||
483 | 2 | 2 | 0 | 2 | my $self = shift; my $attr = shift; | |||||||||
2 | 3 | |||||||||||||
484 | ||||||||||||||
485 | 2 | 2 | my $code; | |||||||||||
486 | 2 | 50 | 4 | if (my $file = $attr->{'src'}) { | ||||||||||
487 | 0 | 0 | my $fh = Symbol::gensym(); | |||||||||||
488 | 0 | 0 | 0 | 0 | if (! -f $file && -f ($self->{env}->{DOCUMENT_ROOT} . $file)) { | |||||||||
489 | 0 | 0 | $file = ($self->{env}->{DOCUMENT_ROOT} . $file); | |||||||||||
490 | } | |||||||||||||
491 | 0 | 0 | 0 | open($fh, "<$file") || die "Cannot open $file: $!"; | ||||||||||
492 | 0 | 0 | local $/ = undef; | |||||||||||
493 | 0 | 0 | $code = <$fh>; | |||||||||||
494 | 0 | 0 | 0 | 0 | die "Error while reading $file: $!" unless defined($fh) and close($fh); | |||||||||
495 | } else { | |||||||||||||
496 | 2 | 9 | $code = $self->AttrVal($attr->{'code'}, @_); | |||||||||||
497 | } | |||||||||||||
498 | 2 | 5 | $code; | |||||||||||
499 | } | |||||||||||||
500 | ||||||||||||||
501 | sub EvalPerlCode { | |||||||||||||
502 | 2 | 2 | 0 | 2 | my($self, $attr, $code) = @_; | |||||||||
503 | 2 | 3 | my $output; | |||||||||||
504 | 2 | 50 | 6 | if ($attr->{'safe'}) { | ||||||||||
505 | 0 | 0 | my $compartment = $self->{_ep_compartment}; | |||||||||||
506 | 0 | 0 | 0 | if (!$compartment) { | ||||||||||
507 | 0 | 0 | require Safe; | |||||||||||
508 | 0 | 0 | $compartment = $self->{_ep_compartment} = Safe->new(); | |||||||||||
509 | } | |||||||||||||
510 | 0 | 0 | 0 | if ($self->{debug}) { | ||||||||||
511 | 0 | 0 | $self->print("Evaluating in Safe compartment:\n$code\n"); | |||||||||||
512 | } | |||||||||||||
513 | 0 | 0 | local $_ = $self; # The 'local' is required for garbage collection | |||||||||||
514 | 0 | 0 | $output = $compartment->reval($code); | |||||||||||
515 | } else { | |||||||||||||
516 | 2 | 50 | 14 | $code = "package ". | ||||||||||
517 | ($attr->{'package'} || "HTML::EP::main").";".$code; | |||||||||||||
518 | 2 | 50 | 9 | $self->print("Evaluating script:\n$code\n") if $self->{'debug'}; | ||||||||||
519 | 2 | 4 | local $_ = $self; # The 'local' is required for garbage collection | |||||||||||
520 | 2 | 149 | $output = eval $code; | |||||||||||
521 | } | |||||||||||||
522 | 2 | 50 | 10 | die $@ if $@; | ||||||||||
523 | 2 | 50 | 8 | $self->printf("Script returned:\n$output\nEnd of output.\n") | ||||||||||
524 | if $self->{debug}; | |||||||||||||
525 | 2 | 8 | $output; | |||||||||||
526 | } | |||||||||||||
527 | ||||||||||||||
528 | sub EncodeByAttr { | |||||||||||||
529 | 2 | 2 | 0 | 4 | my($self, $attr, $str) = @_; | |||||||||
530 | 2 | 5 | my $debug = $self->{'debug'}; | |||||||||||
531 | 2 | 50 | 4 | $self->print("EncodeByAttr: Input $str\n") if $debug; | ||||||||||
532 | 2 | 50 | 6 | if (my $type = $attr->{'output'}) { | ||||||||||
533 | 0 | 0 | 0 | if ($type eq 'html') { | ||||||||||
0 | ||||||||||||||
0 | ||||||||||||||
534 | 0 | 0 | $str = $self->escapeHTML($str); | |||||||||||
535 | } elsif ($type eq 'htmlbr') { | |||||||||||||
536 | 0 | 0 | $str = $self->escapeHTML($str); | |||||||||||
537 | 0 | 0 | $str =~ s/\n/ /sg; |
|||||||||||
538 | } elsif ($type eq 'url') { | |||||||||||||
539 | 0 | 0 | $str = CGI->escape($str); | |||||||||||
540 | } | |||||||||||||
541 | } | |||||||||||||
542 | 2 | 50 | 5 | $self->print("EncodeByAttr: Output $str\n") if $debug; | ||||||||||
543 | 2 | 4 | $str; | |||||||||||
544 | } | |||||||||||||
545 | ||||||||||||||
546 | sub _ep_perl { | |||||||||||||
547 | 2 | 2 | 5 | my $self = shift; my $attr = shift; | ||||||||||
2 | 3 | |||||||||||||
548 | 2 | 8 | my $code = $self->GetPerlCode($attr, @_); | |||||||||||
549 | 2 | 50 | 7 | return undef unless defined $code; | ||||||||||
550 | 2 | 6 | $self->EncodeByAttr($attr, $self->EvalPerlCode($attr, $code)); | |||||||||||
551 | } | |||||||||||||
552 | ||||||||||||||
553 | ||||||||||||||
554 | sub _ep_database ($$;$) { | |||||||||||||
555 | 0 | 0 | 0 | my $self = shift; my $attr = shift; | ||||||||||
0 | 0 | |||||||||||||
556 | 0 | 0 | 0 | my $dsn = $attr->{'dsn'} || $self->{env}->{DBI_DSN}; | ||||||||||
557 | 0 | 0 | 0 | my $user = $attr->{'user'} || $self->{env}->{DBI_USER}; | ||||||||||
558 | 0 | 0 | 0 | my $pass = $attr->{'password'} || $self->{env}->{DBI_PASS}; | ||||||||||
559 | 0 | 0 | 0 | my $dbhvar = $attr->{'dbh'} || 'dbh'; | ||||||||||
560 | 0 | 0 | require DBI; | |||||||||||
561 | 0 | 0 | 0 | $self->printf("Connecting to database: dsn = %s, user = %s," | ||||||||||
562 | . " pass = %s\n", $dsn, $user, $pass) if $self->{'debug'}; | |||||||||||||
563 | 0 | 0 | $self->{$dbhvar} = DBI->connect($dsn, $user, $pass, | |||||||||||
564 | { 'RaiseError' => 1, 'Warn' => 0, | |||||||||||||
565 | 'PrintError' => 0 }); | |||||||||||||
566 | 0 | 0 | ''; | |||||||||||
567 | } | |||||||||||||
568 | ||||||||||||||
569 | ||||||||||||||
570 | sub SqlSetupStatement { | |||||||||||||
571 | 0 | 0 | 0 | 0 | my($self, $attr, $dbh, $statement) = @_; | |||||||||
572 | ||||||||||||||
573 | 0 | 0 | 0 | my $start_at = $attr->{'startat'} || 0; | ||||||||||
574 | 0 | 0 | 0 | my $limit = $attr->{'limit'} || -1; | ||||||||||
575 | 0 | 0 | 0 | 0 | if (($start_at || $limit != -1) && | |||||||||
0 | ||||||||||||||
576 | $dbh->{'ImplementorClass'} eq 'DBD::mysql::db') { | |||||||||||||
577 | 0 | 0 | $statement .= " LIMIT $start_at, $limit"; | |||||||||||
578 | 0 | 0 | $start_at = 0; | |||||||||||
579 | } | |||||||||||||
580 | 0 | 0 | 0 | if ($self->{'debug'}) { | ||||||||||
581 | 0 | 0 | $self->print("Executing query, statement = $statement\n"); | |||||||||||
582 | 0 | 0 | 0 | $self->printf("Result starting at row %s\n", | ||||||||||
583 | $attr->{'startat'} || 0); | |||||||||||||
584 | 0 | 0 | $self->printf("Rows limited to %s\n", $attr->{'limit'}); | |||||||||||
585 | } | |||||||||||||
586 | 0 | 0 | my $sth = $dbh->prepare($statement); | |||||||||||
587 | 0 | 0 | $sth->execute(); | |||||||||||
588 | 0 | 0 | ($sth, $start_at, $limit) | |||||||||||
589 | } | |||||||||||||
590 | ||||||||||||||
591 | sub SqlSetupResult { | |||||||||||||
592 | 0 | 0 | 0 | 0 | my($self, $attr, $sth, $start_at, $limit) = @_; | |||||||||
593 | 0 | 0 | my $result = $attr->{'result'}; | |||||||||||
594 | 0 | 0 | my $list = []; | |||||||||||
595 | 0 | 0 | my $ref; | |||||||||||
596 | 0 | 0 | 0 | while ($limit && $start_at-- > 0) { | ||||||||||
597 | 0 | 0 | 0 | if (!$sth->fetchrow_arrayref()) { | ||||||||||
598 | 0 | 0 | $limit = 0; | |||||||||||
599 | 0 | 0 | last; | |||||||||||
600 | } | |||||||||||||
601 | } | |||||||||||||
602 | 0 | 0 | 0 | 0 | my $resultmethod = | |||||||||
603 | (exists($attr->{'resulttype'}) && $attr->{'resulttype'} =~ /array/) ? | |||||||||||||
604 | "fetchrow_arrayref" : "fetchrow_hashref"; | |||||||||||||
605 | 0 | 0 | 0 | while ($limit-- && ($ref = $sth->$resultmethod())) { | ||||||||||
606 | 0 | 0 | 0 | push(@$list, (ref($ref) eq 'ARRAY') ? [@$ref] : {%$ref}); | ||||||||||
607 | } | |||||||||||||
608 | 0 | 0 | 0 | 0 | if (exists($attr->{'resulttype'}) && | |||||||||
609 | $attr->{'resulttype'} =~ /^single_/) { | |||||||||||||
610 | 0 | 0 | $self->{$result} = $list->[0]; | |||||||||||
611 | } else { | |||||||||||||
612 | 0 | 0 | $self->{$result} = $list; | |||||||||||
613 | } | |||||||||||||
614 | 0 | 0 | $self->{"$result\_rows"} = scalar(@$list); | |||||||||||
615 | 0 | 0 | 0 | $self->print("Result: ", scalar(@$list), " rows.\n") if $self->{'debug'}; | ||||||||||
616 | } | |||||||||||||
617 | ||||||||||||||
618 | sub _ep_query { | |||||||||||||
619 | 0 | 0 | 0 | my($self, $attr, $tokens, $token) = @_; | ||||||||||
620 | 0 | 0 | my $debug = $self->{'debug'}; | |||||||||||
621 | 0 | 0 | my $statement = $self->AttrVal($attr->{'statement'}, $tokens, $token, 1); | |||||||||||
622 | 0 | 0 | 0 | my $dbh = $self->{$attr->{'dbh'} || 'dbh'} || die "Not connected"; | ||||||||||
623 | 0 | 0 | 0 | if (!exists($attr->{'result'})) { | ||||||||||
624 | 0 | 0 | 0 | $self->print("Doing Query: $statement\n") if $debug; | ||||||||||
625 | 0 | 0 | $dbh->do($statement); | |||||||||||
626 | 0 | 0 | return ''; | |||||||||||
627 | } | |||||||||||||
628 | ||||||||||||||
629 | 0 | 0 | $self->SqlSetupResult($attr, | |||||||||||
630 | $self->SqlSetupStatement($attr, $dbh, $statement)); | |||||||||||||
631 | 0 | 0 | ''; | |||||||||||
632 | } | |||||||||||||
633 | ||||||||||||||
634 | ||||||||||||||
635 | sub _ep_select ($$;$) { | |||||||||||||
636 | 1 | 1 | 3 | my $self = shift; my $attr = shift; | ||||||||||
1 | 5 | |||||||||||||
637 | 1 | 2 | my @tags; | |||||||||||
638 | 1 | 7 | while (my($var, $val) = each %$attr) { | |||||||||||
639 | 4 | 100 | 27 | if ($var !~ /^template|range|format|items?|selected(?:\-text)?$/i){ | ||||||||||
640 | 1 | 6 | push(@tags, sprintf('%s="%s"', $var, $self->escapeHTML($val))); | |||||||||||
641 | } | |||||||||||||
642 | } | |||||||||||||
643 | ||||||||||||||
644 | 1 | 6 | $attr->{'format'} = ''; | |||||||||||
645 | 1 | 5 | $self->_ep_list($attr, @_); | |||||||||||
646 | } | |||||||||||||
647 | ||||||||||||||
648 | ||||||||||||||
649 | sub _ep_list { | |||||||||||||
650 | 20 | 20 | 33 | my($self, $attr, $tokens, $token) = @_; | ||||||||||
651 | 20 | 37 | my $debug = $self->{'debug'}; | |||||||||||
652 | 20 | 23 | my $template; | |||||||||||
653 | 20 | 50 | 43 | if (defined($attr->{'template'})) { | ||||||||||
654 | 0 | 0 | my $parser = HTML::EP::Parser->new(); | |||||||||||
655 | 0 | 0 | $parser->text($attr->{'template'}); | |||||||||||
656 | 0 | 0 | $template = HTML::EP::Tokens->new('tokens' => $parser->{'_ep_tokens'}); | |||||||||||
657 | } else { | |||||||||||||
658 | 20 | 55 | my $first = $tokens->First(); | |||||||||||
659 | 20 | 59 | my $last = $self->FindEndTag($tokens, $token->{'tag'}); | |||||||||||
660 | 20 | 62 | $template = $tokens->Clone($first, $last-1); | |||||||||||
661 | } | |||||||||||||
662 | 20 | 31 | my $output = ''; | |||||||||||
663 | 20 | 27 | my($list, $range); | |||||||||||
664 | 20 | 100 | 46 | if ($range = $attr->{'range'}) { | ||||||||||
665 | 16 | 50 | 43 | $list = [ map { $_ =~ /(\d+)\.\.(\d+)/ ? ($1 .. $2) : $_} | ||||||||||
16 | 155 | |||||||||||||
666 | split(/,/, $range) ]; | |||||||||||||
667 | } else { | |||||||||||||
668 | 4 | 8 | my $items = $attr->{'items'}; | |||||||||||
669 | 4 | 100 | 27 | $list = ref($items) ? $items : | ||||||||||
50 | ||||||||||||||
670 | ($items =~ /^(\w+)((?:\-\>\w+)+)$/) ? | |||||||||||||
671 | $self->FindVar($1, $2) : $self->{$items}; | |||||||||||||
672 | } | |||||||||||||
673 | 20 | 50 | 50 | $self->print("_ep_list: Template = $template, Items = ", @$list, "\n") | ||||||||||
674 | if $debug; | |||||||||||||
675 | 20 | 50 | 48 | my $l = $attr->{'item'} or die "Missing item name"; | ||||||||||
676 | 20 | 22 | my $i = 0; | |||||||||||
677 | 20 | 27 | my $selected = $attr->{'selected'}; | |||||||||||
678 | 20 | 33 | my $isSelected; | |||||||||||
679 | 20 | 36 | foreach my $ref (@$list) { | |||||||||||
680 | 66 | 119 | $self->{$l} = $ref; | |||||||||||
681 | 66 | 50 | 172 | $self->{'i'} = $i++ unless $l eq 'i'; | ||||||||||
682 | 66 | 100 | 123 | if ($selected) { | ||||||||||
683 | 5 | 50 | 18 | if (ref($ref) eq 'HASH') { | ||||||||||
50 | ||||||||||||||
684 | 0 | 0 | $isSelected = $ref->{'val'} eq $selected; | |||||||||||
685 | } elsif (ref($ref) eq 'ARRAY') { | |||||||||||||
686 | 0 | 0 | $isSelected = $ref->[0] eq $selected; | |||||||||||
687 | } else { | |||||||||||||
688 | 5 | 10 | $isSelected = $ref eq $selected; | |||||||||||
689 | } | |||||||||||||
690 | 5 | 100 | 50 | 20 | $self->{'selected'} = $isSelected ? | |||||||||
691 | ($attr->{'selected-text'} || 'SELECTED') : ''; | |||||||||||||
692 | } | |||||||||||||
693 | 66 | 148 | $output .= $self->ParseVars($self->RepeatedTokenMarch($template)); | |||||||||||
694 | } | |||||||||||||
695 | 20 | 100 | 58 | if (my $format = $attr->{'format'}) { | ||||||||||
696 | 1 | 4 | $attr->{'output'} = $output; | |||||||||||
697 | 1 | 7 | $format =~ s/\$([\@\#\~]?)(\w+)((?:\-\>\w+)*)\$/HTML::EP::ParseVar($attr, $1, $2, $3)/eg; | |||||||||||
1 | 3 | |||||||||||||
698 | 1 | 8 | $format; | |||||||||||
699 | } else { | |||||||||||||
700 | 19 | 81 | $output; | |||||||||||
701 | } | |||||||||||||
702 | } | |||||||||||||
703 | ||||||||||||||
704 | ||||||||||||||
705 | sub _ep_errhandler { | |||||||||||||
706 | 0 | 0 | 0 | my $self = shift; my $attr = shift; | ||||||||||
0 | 0 | |||||||||||||
707 | 0 | 0 | my $type = $attr->{type}; | |||||||||||
708 | 0 | 0 | 0 | 0 | $type = ($type && (lc $type) eq 'user') ? 'user' : 'system'; | |||||||||
709 | 0 | 0 | 0 | if ($attr->{src}) { | ||||||||||
710 | 0 | 0 | $self->{"_ep_err_file_$type"} = $attr->{src}; | |||||||||||
711 | } else { | |||||||||||||
712 | 0 | 0 | my $template = $self->AttrVal($attr->{'template'}, @_); | |||||||||||
713 | 0 | 0 | $self->{"_ep_err_msg_$type"} = $template; | |||||||||||
714 | } | |||||||||||||
715 | 0 | 0 | ''; | |||||||||||
716 | } | |||||||||||||
717 | ||||||||||||||
718 | ||||||||||||||
719 | sub _ep_error { | |||||||||||||
720 | 0 | 0 | 0 | my($self, $attr, $tokens, $token) = @_; | ||||||||||
721 | 0 | 0 | my $msg = $self->AttrVal($attr->{'msg'}, $tokens, $token, 1); | |||||||||||
722 | 0 | 0 | my $type = $attr->{'type'}; | |||||||||||
723 | 0 | 0 | 0 | 0 | $self->{_ep_err_type} = ($type && (lc $type) eq 'user') ? 1 : 0; | |||||||||
724 | 0 | 0 | die $msg; | |||||||||||
725 | 0 | 0 | ''; | |||||||||||
726 | } | |||||||||||||
727 | ||||||||||||||
728 | ||||||||||||||
729 | sub _ep_input_sql_query { | |||||||||||||
730 | 0 | 0 | 0 | my $self = shift; my $attr = shift; | ||||||||||
0 | 0 | |||||||||||||
731 | 0 | 0 | 0 | my $dbh = $self->{'dbh'} || | ||||||||||
732 | die "Missing database-handle (Did you run ep-database?)"; | |||||||||||||
733 | 0 | 0 | 0 | my $dest = $attr->{'dest'} || | ||||||||||
734 | die "Missing attribute 'dest' (Destination variable)"; | |||||||||||||
735 | 0 | 0 | my $debug = $self->{'debug'}; | |||||||||||
736 | ||||||||||||||
737 | 0 | 0 | my $names = ''; | |||||||||||
738 | 0 | 0 | my $values = ''; | |||||||||||
739 | 0 | 0 | my $update = ''; | |||||||||||
740 | 0 | 0 | my $comma = ''; | |||||||||||
741 | 0 | 0 | while (my($var, $val) = each %{$self->{$dest}}) { | |||||||||||
0 | 0 | |||||||||||||
742 | 0 | 0 | $names .= $comma . $var; | |||||||||||
743 | 0 | 0 | my $v = $val->{'val'}; | |||||||||||
744 | 0 | 0 | 0 | 0 | $v = $dbh->quote($v) if !defined($v) || $val->{'type'} ne 'n'; | |||||||||
745 | 0 | 0 | $values .= $comma . $v; | |||||||||||
746 | 0 | 0 | $update .= $comma . "$var=$v"; | |||||||||||
747 | 0 | 0 | 0 | $comma = ',' unless $comma; | ||||||||||
748 | } | |||||||||||||
749 | 0 | 0 | my $hash = $self->{$dest}; | |||||||||||
750 | 0 | 0 | $hash->{'names'} = $names; | |||||||||||
751 | 0 | 0 | 0 | print "_ep_input_sql_query: Setting $dest\->names to $names\n" if $debug; | ||||||||||
752 | 0 | 0 | $hash->{'values'} = $values; | |||||||||||
753 | 0 | 0 | 0 | print "_ep_input_sql_query: Setting $dest\->values to $values\n" if $debug; | ||||||||||
754 | 0 | 0 | $hash->{'update'} = $update; | |||||||||||
755 | 0 | 0 | 0 | print "_ep_input_sql_query: Setting $dest\->update to $update\n" if $debug; | ||||||||||
756 | 0 | 0 | ''; | |||||||||||
757 | } | |||||||||||||
758 | ||||||||||||||
759 | sub _ep_input { | |||||||||||||
760 | 2 | 2 | 4 | my($self, $attr) = @_; | ||||||||||
761 | 2 | 5 | my $prefix = $attr->{'prefix'}; | |||||||||||
762 | 2 | 3 | my($var, $val); | |||||||||||
763 | 2 | 4 | my $cgi = $self->{'cgi'}; | |||||||||||
764 | 2 | 7 | my @params = $cgi->param(); | |||||||||||
765 | 2 | 46 | my $i = 0; | |||||||||||
766 | 2 | 5 | my $list = $attr->{'list'}; | |||||||||||
767 | 2 | 4 | my $dest = $attr->{'dest'}; | |||||||||||
768 | ||||||||||||||
769 | 2 | 100 | 9 | $self->{$dest} = [] if $list; | ||||||||||
770 | 2 | 3 | while(1) { | |||||||||||
771 | 4 | 7 | my $p = $prefix; | |||||||||||
772 | 4 | 7 | my $hash = {}; | |||||||||||
773 | 4 | 100 | 8 | if ($list) { | ||||||||||
774 | 3 | 7 | $p .= "$i\_"; | |||||||||||
775 | } | |||||||||||||
776 | 4 | 7 | foreach $var (@params) { | |||||||||||
777 | 25 | 100 | 230 | if ($var =~ /^\Q$p\E\_?(\w+?)_(.*)$/) { | ||||||||||
778 | 17 | 35 | my $col = $2; | |||||||||||
779 | 17 | 31 | my $type = $1; | |||||||||||
780 | 17 | 100 | 39 | if ($type =~ /^d[dmy]$/) { | ||||||||||
781 | # A date | |||||||||||||
782 | 9 | 100 | 26 | if ($hash->{$col}) { | ||||||||||
783 | # Do this only once | |||||||||||||
784 | 6 | 15 | next; | |||||||||||
785 | } | |||||||||||||
786 | 3 | 50 | 9 | if (!$hash->{$col}) { | ||||||||||
787 | 3 | 15 | my $year = $cgi->param("${p}dy_$col"); | |||||||||||
788 | 3 | 74 | my $month = $cgi->param("${p}dm_$col"); | |||||||||||
789 | 3 | 89 | my $day = $cgi->param("${p}dd_$col"); | |||||||||||
790 | 3 | 50 | 33 | 70 | if ($year eq '' && $month eq '' && $day eq '') { | |||||||||
33 | ||||||||||||||
791 | 0 | 0 | $val = undef; | |||||||||||
792 | } else { | |||||||||||||
793 | 3 | 100 | 15 | if ($year < 20) { | ||||||||||
100 | ||||||||||||||
794 | 1 | 3 | $year += 2000; | |||||||||||
795 | } elsif ($year < 100) { | |||||||||||||
796 | 1 | 2 | $year += 1900; | |||||||||||
797 | } | |||||||||||||
798 | 3 | 19 | $val = sprintf("%04d-%02d-%02d", | |||||||||||
799 | $year, $month, $day); | |||||||||||||
800 | } | |||||||||||||
801 | 3 | 32 | $hash->{$col} = { col => $col, | |||||||||||
802 | val => $val, | |||||||||||||
803 | type => 'd', | |||||||||||||
804 | year => $year, | |||||||||||||
805 | month => $month, | |||||||||||||
806 | day => $day | |||||||||||||
807 | }; | |||||||||||||
808 | } | |||||||||||||
809 | } else { | |||||||||||||
810 | 8 | 50 | 29 | $val = ($type eq 's') ? | ||||||||||
811 | join(",", $cgi->param($var)) : $cgi->param($var); | |||||||||||||
812 | 8 | 195 | $hash->{$col} = { col => $col, | |||||||||||
813 | type => $type, | |||||||||||||
814 | val => $val | |||||||||||||
815 | }; | |||||||||||||
816 | } | |||||||||||||
817 | } | |||||||||||||
818 | } | |||||||||||||
819 | 4 | 100 | 10 | if ($list) { | ||||||||||
820 | 3 | 50 | 8 | die "Cannot create 'names', 'values' and 'update' attributes" | ||||||||||
821 | . " if 'list' is set." if $attr->{'sqlquery'}; | |||||||||||||
822 | 3 | 100 | 9 | last unless %$hash; | ||||||||||
823 | 2 | 5 | $hash->{'i'} = $i++; | |||||||||||
824 | 2 | 2 | push(@{$self->{$dest}}, $hash); | |||||||||||
2 | 6 | |||||||||||||
825 | } else { | |||||||||||||
826 | 1 | 4 | $self->{$dest} = $hash; | |||||||||||
827 | 1 | 50 | 8 | $self->_ep_input_sql_query($attr) if $attr->{'sqlquery'}; | ||||||||||
828 | 1 | 3 | last; | |||||||||||
829 | } | |||||||||||||
830 | } | |||||||||||||
831 | 2 | 50 | 7 | if ($self->{'debug'}) { | ||||||||||
832 | 0 | 0 | $self->print("_ep_input: Gelesene Daten\n", | |||||||||||
833 | $self->Dump($self->{$dest})); | |||||||||||||
834 | } | |||||||||||||
835 | 2 | 8 | ''; | |||||||||||
836 | } | |||||||||||||
837 | ||||||||||||||
838 | sub _ep_if { | |||||||||||||
839 | 59 | 59 | 98 | my($self, $attr, $tokens, $token) = @_; | ||||||||||
840 | 59 | 75 | my $level = 0; | |||||||||||
841 | 59 | 93 | my $tag = $token->{'tag'}; | |||||||||||
842 | 59 | 138 | my $state = $self->EvalIf($tag, $attr); | |||||||||||
843 | 59 | 100 | 198 | my $start = $tokens->First() if $state; | ||||||||||
844 | 59 | 76 | my $state_done = $state; | |||||||||||
845 | 59 | 59 | my $last; | |||||||||||
846 | 59 | 168 | while (defined(my $token = $tokens->Token())) { | |||||||||||
847 | 371 | 100 | 1341 | if ($token->{'type'} eq 'S') { | ||||||||||
100 | ||||||||||||||
848 | 130 | 100 | 671 | if ($token->{'tag'} eq 'ep-if') { | ||||||||||
100 | ||||||||||||||
849 | 10 | 33 | ++$level; | |||||||||||
850 | } elsif ($token->{'tag'} =~ /^ep-els(?:e|e?if)?$/) { | |||||||||||||
851 | 114 | 100 | 252 | next if $level; | ||||||||||
852 | 96 | 100 | 270 | if ($state) { | ||||||||||
100 | ||||||||||||||
853 | 31 | 87 | $last = $tokens->First()-1; | |||||||||||
854 | 31 | 106 | $state = 0; | |||||||||||
855 | } elsif (!$state_done) { | |||||||||||||
856 | 42 | 100 | 100 | 173 | if ($state = $token->{'tag'} eq 'ep-else' || | |||||||||
857 | $self->EvalIf | |||||||||||||
858 | ($tag, $self->ParseAttr($token->{'attr'}))) { | |||||||||||||
859 | 29 | 35 | $state_done = 1; | |||||||||||
860 | 29 | 121 | $start = $tokens->First(); | |||||||||||
861 | } | |||||||||||||
862 | } | |||||||||||||
863 | } | |||||||||||||
864 | } elsif ($token->{'type'} eq 'E') { | |||||||||||||
865 | 71 | 100 | 160 | if ($token->{'tag'} eq 'ep-if') { | ||||||||||
866 | 69 | 100 | 167 | next if $level--; | ||||||||||
867 | 59 | 100 | 123 | return '' unless $state_done; | ||||||||||
868 | 55 | 100 | 148 | $last = $tokens->First()-1 if $state; | ||||||||||
869 | 55 | 177 | return $self->TokenMarch($tokens->Clone($start, $last)); | |||||||||||
870 | } | |||||||||||||
871 | } | |||||||||||||
872 | } | |||||||||||||
873 | 0 | 0 | die "ep-if without /ep-if"; | |||||||||||
874 | } | |||||||||||||
875 | ||||||||||||||
876 | 0 | 0 | 0 | sub _ep_elseif { die "ep-elseif without ep-if" } | ||||||||||
877 | 0 | 0 | 0 | sub _ep_elsif { die "ep-elsif without ep-if" } | ||||||||||
878 | 0 | 0 | 0 | sub _ep_else { die "ep-else without ep-if" } | ||||||||||
879 | ||||||||||||||
880 | ||||||||||||||
881 | sub _ep_mail { | |||||||||||||
882 | 0 | 0 | 0 | my($self, $attr, $tokens, $token) = @_; | ||||||||||
883 | ||||||||||||||
884 | 0 | 0 | 0 | my $host = (delete $attr->{'mailserver'}) || | ||||||||||
885 | $self->{'_ep_config'}->{'mailhost'} || '127.0.0.1'; | |||||||||||||
886 | 0 | 0 | my @options; | |||||||||||
887 | 0 | 0 | my $body = $self->AttrVal($attr->{'body'}, $tokens, $token, 1); | |||||||||||
888 | 0 | 0 | require Mail::Header; | |||||||||||
889 | 0 | 0 | my $msg = Mail::Header->new(); | |||||||||||
890 | 0 | 0 | my($header, $val); | |||||||||||
891 | 0 | 0 | 0 | my $from = $attr->{'from'} || die "Missing header attribute: from"; | ||||||||||
892 | 0 | 0 | 0 | die "Missing header attribute: to" unless $attr->{'to'}; | ||||||||||
893 | 0 | 0 | 0 | die "Missing header attribute: subject" unless $attr->{'subject'}; | ||||||||||
894 | 0 | 0 | while (($header, $val) = each %$attr) { | |||||||||||
895 | 0 | 0 | $msg->add($header, $val); | |||||||||||
896 | } | |||||||||||||
897 | 0 | 0 | require Net::SMTP; | |||||||||||
898 | 0 | 0 | require Mail::Internet; | |||||||||||
899 | 0 | 0 | my $debug = $self->{'debug'}; | |||||||||||
900 | 0 | 0 | 0 | local *STDERR if $debug; | ||||||||||
901 | 0 | 0 | 0 | if ($debug) { | ||||||||||
902 | 0 | 0 | $self->print("Headers: \n"); | |||||||||||
903 | 0 | 0 | $self->print($msg->as_string()); | |||||||||||
904 | 0 | 0 | $self->print("Making SMTP connection to $host.\n"); | |||||||||||
905 | 0 | 0 | open(STDERR, ">&STDOUT"); | |||||||||||
906 | } | |||||||||||||
907 | 0 | 0 | 0 | my $smtp = Net::SMTP->new($host, 'Debug' => $debug) | ||||||||||
908 | or die "Cannot open SMTP connection to $host: $!"; | |||||||||||||
909 | 0 | 0 | my $mail = Mail::Internet->new([$body], Header => $msg); | |||||||||||
910 | 0 | 0 | $Mail::Util::mailaddress = $from; # Ugly hack to prevent | |||||||||||
911 | # DNS lookup for 'mailhost' | |||||||||||||
912 | # in Mail::Util::mailaddress(). | |||||||||||||
913 | 0 | 0 | $mail->smtpsend('Host' => $smtp, @options); | |||||||||||
914 | 0 | 0 | $smtp->quit(); | |||||||||||
915 | 0 | 0 | ''; | |||||||||||
916 | } | |||||||||||||
917 | ||||||||||||||
918 | ||||||||||||||
919 | sub _ep_include { | |||||||||||||
920 | 3 | 3 | 5 | my($self, $attr, $tokens, $token) = @_; | ||||||||||
921 | 3 | 12 | my $parser = HTML::EP::Parser->new(); | |||||||||||
922 | 3 | 50 | 11 | my $f = $attr->{'file'} || die "Missing file name\n"; | ||||||||||
923 | 3 | 9 | my $df = $self->{'env'}->{'DOCUMENT_ROOT'} . $f; | |||||||||||
924 | 3 | 50 | 64 | $f = $df if -f $df; | ||||||||||
925 | 3 | 16 | my $fh = Symbol::gensym(); | |||||||||||
926 | 3 | 50 | 141 | open($fh, "<$f") || die "Failed to open file $f: $!"; | ||||||||||
927 | 3 | 20 | $parser->parse_file($fh); | |||||||||||
928 | 3 | 7 | $parser->eof(); | |||||||||||
929 | 3 | 17 | my $new_toks = HTML::EP::Tokens->new('tokens' => $parser->{'_ep_tokens'}); | |||||||||||
930 | 3 | 50 | 14 | $tokens->Replace | ||||||||||
931 | ($tokens->First()-1, | |||||||||||||
932 | { 'type' => 'I', | |||||||||||||
933 | 'tokens' => $new_toks | |||||||||||||
934 | }) if $tokens; # Upwards compatibility: Before EP 0.20 users | |||||||||||||
935 | # didn't pass a tokens argument. | |||||||||||||
936 | 3 | 9 | $self->RepeatedTokenMarch($new_toks) | |||||||||||
937 | } | |||||||||||||
938 | ||||||||||||||
939 | ||||||||||||||
940 | sub _ep_exit { | |||||||||||||
941 | 3 | 3 | 4 | my $self = shift; | ||||||||||
942 | # If we are inside of an ep-if, we need to collect previous output | |||||||||||||
943 | 3 | 4 | $self->{'_ep_output'} = join('', @{$self->{'_ep_output_stack'}}, | |||||||||||
3 | 10 | |||||||||||||
944 | $self->{'_ep_output'}); | |||||||||||||
945 | 3 | 54 | die "_ep_exit, ignore"; | |||||||||||
946 | } | |||||||||||||
947 | ||||||||||||||
948 | sub _ep_redirect { | |||||||||||||
949 | 0 | 0 | 0 | my $self = shift; my $attr = shift; | ||||||||||
0 | 0 | |||||||||||||
950 | 0 | 0 | 0 | my $to = $attr->{'to'} or die "Missing redirect target"; | ||||||||||
951 | 0 | 0 | 0 | $self->print("Redirecting to $to\n") if $self->{'debug'}; | ||||||||||
952 | 0 | 0 | 0 | $self->print($self->{'cgi'}->redirect('-uri' => $to, | ||||||||||
953 | '-type' => 'text/plain', | |||||||||||||
954 | '-refresh' => "0; URL=$to", | |||||||||||||
955 | $attr->{'cookies'} ? | |||||||||||||
956 | $self->SetCookies() : ())); | |||||||||||||
957 | 0 | 0 | $self->print('Click 958 | '">here to go on'); | ||||||||||
959 | 0 | 0 | $self->Stop(); | |||||||||||
960 | 0 | 0 | ''; | |||||||||||
961 | } | |||||||||||||
962 | ||||||||||||||
963 | sub _ep_set { | |||||||||||||
964 | 8 | 8 | 11 | my($self, $attr, $tokens, $token) = @_; | ||||||||||
965 | 8 | 33 | my $val = $self->AttrVal($attr->{'val'}, $tokens, $token, | |||||||||||
966 | !$attr->{'noparse'}); | |||||||||||||
967 | 8 | 17 | my $var = $attr->{'var'}; | |||||||||||
968 | 8 | 11 | my $ref = $self; | |||||||||||
969 | 8 | 28 | while ($var =~ /(.*?)\-\>(.*)/) { | |||||||||||
970 | 2 | 5 | my $key = $1; | |||||||||||
971 | 2 | 5 | $var = $2; | |||||||||||
972 | 2 | 50 | 8 | if ($key =~ /^\d+$/) { | ||||||||||
973 | 0 | 0 | $ref = $ref->[$key]; | |||||||||||
974 | } else { | |||||||||||||
975 | 2 | 7 | $ref = $ref->{$key}; | |||||||||||
976 | } | |||||||||||||
977 | } | |||||||||||||
978 | 8 | 50 | 17 | print "Setting $ref -> $var to $val\n" if $self->{'debug'}; | ||||||||||
979 | 8 | 100 | 21 | if ($var =~ /^\d+$/) { | ||||||||||
980 | 1 | 3 | $ref->[$var] = $val; | |||||||||||
981 | } else { | |||||||||||||
982 | 7 | 14 | $ref->{$var} = $val; | |||||||||||
983 | } | |||||||||||||
984 | 8 | 16 | ''; | |||||||||||
985 | } | |||||||||||||
986 | ||||||||||||||
987 | sub _format_NBSP { | |||||||||||||
988 | 2 | 2 | 4 | my $self = shift; my $str = shift; | ||||||||||
2 | 3 | |||||||||||||
989 | 2 | 100 | 66 | 12 | if (!defined($str) || $str eq '') { | |||||||||
990 | 1 | 2 | $str = ' '; | |||||||||||
991 | } | |||||||||||||
992 | 2 | 5 | $str; | |||||||||||
993 | } | |||||||||||||
994 | ||||||||||||||
995 | ||||||||||||||
996 | 1; |