Einige strict Probleme mit vclimit=0
[kivitendo-erp.git] / SL / Menu.pm
1 #=====================================================================
2 # LX-Office ERP
3 # Copyright (C) 2004
4 # Based on SQL-Ledger Version 2.1.9
5 # Web http://www.lx-office.org
6 #
7 #=====================================================================
8 # SQL-Ledger Accounting
9 # Copyright (C) 2001
10 #
11 #  Author: Dieter Simader
12 #   Email: dsimader@sql-ledger.org
13 #     Web: http://www.sql-ledger.org
14 #
15 #  Contributors:
16 #
17 # This program is free software; you can redistribute it and/or modify
18 # it under the terms of the GNU General Public License as published by
19 # the Free Software Foundation; either version 2 of the License, or
20 # (at your option) any later version.
21 #
22 # This program is distributed in the hope that it will be useful,
23 # but WITHOUT ANY WARRANTY; without even the implied warranty of
24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25 # GNU General Public License for more details.
26 # You should have received a copy of the GNU General Public License
27 # along with this program; if not, write to the Free Software
28 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #=====================================================================
30 #
31 # routines for menu items
32 #
33 #=====================================================================
34
35 package Menu;
36
37 use SL::Auth;
38 use SL::Inifile;
39
40 use strict;
41
42 sub new {
43   $main::lxdebug->enter_sub();
44
45   my ($type, $menufile) = @_;
46
47   my $self    = {};
48   my $inifile = Inifile->new($menufile);
49
50   map { $self->{$_} = $inifile->{$_} } keys %{ $inifile };
51
52   bless $self, $type;
53
54   $self->set_access();
55
56   $main::lxdebug->leave_sub();
57
58   return $self;
59 }
60
61 sub menuitem {
62   $main::lxdebug->enter_sub();
63
64   my ($self, $myconfig, $form, $item) = @_;
65
66   my $module = $self->{$item}{module} || $form->{script};
67   my $action = $self->{$item}{action} || "section_menu";
68   my $target = $self->{$item}{target} || "";
69
70   my $level  = $form->escape($item);
71
72   my $style  = 'style="vertical-align:top"';
73   my $target_token = ($target)
74                    ? "target='$target'"
75                    : '';
76
77 #  my $str = qq|<a style="vertical-align:top" href='|;
78   my $href = ($self->{$item}{href})
79            ? $form->escape($self->{$item}{href})
80            : "$module?action=$action&amp;level=$level";
81
82   my @vars = ($self->{$item}{href})
83            ? qw(module target href)
84            : qw(module action target href);
85
86 #  if ($self->{$item}{href}) {
87 ##    $str  = qq|<a 'href=$self->{$item}{href}|;
88 #    @vars = qw(module target href);
89 #  }
90
91   map { delete $self->{$item}{$_} } @vars;
92
93   # add other params
94   foreach my $key (keys %{ $self->{$item} }) {
95     $href .= "&amp;" . $form->escape($key, 1) . "=";
96     my ($value, $conf) = split(/=/, $self->{$item}{$key}, 2);
97     $value = $myconfig->{$value} . "/$conf" if ($conf);
98     $href .= $form->escape($value, 1);
99   }
100
101 #  $str .= q|'|;
102 #
103 #  if ($target) {
104 #    $str .= qq| target=$target|;
105 #  }
106
107 #  $str .= ">";
108
109   my $str = "<a href='$href' $target_token $style>";
110
111   $main::lxdebug->leave_sub();
112
113   return $str;
114 }
115
116 sub menuitem_js {
117   my ($self, $myconfig, $form, $item) = @_;
118
119   my $module = $form->{script};
120   my $action = "section_menu";
121
122   #if ($self->{$item}{module}) {
123   $module = $self->{$item}{module};
124
125   #}
126   if ($self->{$item}{action}) {
127     $action = $self->{$item}{action};
128   }
129
130   my $level = $form->escape($item);
131   my $str   = qq|$module?action=$action&level=$level|;
132   my @vars  = qw(module action target href);
133
134   if ($self->{$item}{href}) {
135     $str  = qq|$self->{$item}{href}|;
136     @vars = qw(module target href);
137   }
138
139   map { delete $self->{$item}{$_} } @vars;
140
141   # add other params
142   foreach my $key (keys %{ $self->{$item} }) {
143     $str .= "&" . $form->escape($key, 1) . "=";
144     my ($value, $conf) = split(/=/, $self->{$item}{$key}, 2);
145     $value = $myconfig->{$value} . "/$conf" if ($conf);
146     $str .= $form->escape($value, 1);
147   }
148
149   $str .= " ";
150
151 }
152
153 sub menuitem_new {
154   $main::lxdebug->enter_sub();
155
156   my ($self, $name, $item) = @_;
157
158   my $form        =  $main::form;
159   my $myconfig    = \%main::myconfig;
160
161   my $module      = $self->{$name}->{module} || $form->{script};
162   my $action      = $self->{$name}->{action};
163
164   $item->{target} = $self->{$name}->{target} || "main_window";
165   $item->{href}   = $self->{$name}->{href}   || "${module}?action=" . $form->escape($action);
166
167   my @vars = qw(module target href);
168   push @vars, 'action' unless ($self->{$name}->{href});
169
170   map { delete $self->{$name}{$_} } @vars;
171
172   # add other params
173   foreach my $key (keys %{ $self->{$name} }) {
174     my ($value, $conf)  = split(m/=/, $self->{$name}->{$key}, 2);
175     $value              = $myconfig->{$value} . "/$conf" if ($conf);
176     $item->{href}      .= "&" . $form->escape($key) . "=" . $form->escape($value);
177   }
178
179   $main::lxdebug->leave_sub();
180 }
181
182 sub menuitem_v3 {
183   $main::lxdebug->enter_sub();
184
185   my ($self, $myconfig, $form, $item, $other) = @_;
186
187   my $module = $form->{script};
188   my $action = "section_menu";
189   my $target = "";
190
191   if ($self->{$item}{module}) {
192     $module = $self->{$item}{module};
193   }
194   if ($self->{$item}{action}) {
195     $action = $self->{$item}{action};
196   }
197   if ($self->{$item}{target}) {
198     $target = $self->{$item}{target};
199   }
200
201   my $level = $form->escape($item);
202
203   my $str = qq|<a href="$module?action=| . $form->escape($action) . qq|&level=| . $form->escape($level);
204
205   my @vars = qw(module action target href);
206
207   if ($self->{$item}{href}) {
208     $str  = qq|<a href=$self->{$item}{href}|;
209     @vars = qw(module target href);
210   }
211
212   map { delete $self->{$item}{$_} } @vars;
213
214   # add other params
215   foreach my $key (keys %{ $self->{$item} }) {
216     $str .= "&" . $form->escape($key, 1) . "=";
217     my ($value, $conf) = split(/=/, $self->{$item}{$key}, 2);
218     $value = $myconfig->{$value} . "/$conf" if ($conf);
219     $str .= $form->escape($value, 1);
220   }
221
222   $str .= '"';
223
224   if ($target) {
225     $str .= qq| target="| . $form->quote($target) . qq|"|;
226   }
227
228   if ($other) {
229     foreach my $key (keys(%{$other})) {
230       $str .= qq| ${key}="| . $form->quote($other->{$key}) . qq|"|;
231     }
232   }
233
234   $str .= ">";
235
236   $main::lxdebug->leave_sub();
237
238   return $str;
239 }
240
241 sub menuitem_XML {
242   $main::lxdebug->enter_sub();
243
244   my ($self, $myconfig, $form, $item, $other) = @_;
245
246   my $module = $form->{script};
247   my $action = "section_menu";
248   my $target = "";
249
250   if ($self->{$item}{module}) {
251     $module = $self->{$item}{module};
252   }
253   if ($self->{$item}{action}) {
254     $action = $self->{$item}{action};
255   }
256   if ($self->{$item}{target}) {
257     $target = $self->{$item}{target};
258   }
259
260   my $level = $form->escape($item);
261
262   my $str = qq| link="$module?action=| . $form->escape($action) .
263     qq|&amp;level=| . $form->escape($level);
264
265   my @vars = qw(module action target href);
266
267   if ($self->{$item}{href}) {
268     $str  = qq| link=$self->{$item}{href}|;
269     @vars = qw(module target href);
270   }
271
272   map { delete $self->{$item}{$_} } @vars;
273
274   # add other params
275   foreach my $key (keys %{ $self->{$item} }) {
276     $str .= "&amp;" . $form->escape($key, 1) . "=";
277     my ($value, $conf) = split(/=/, $self->{$item}{$key}, 2);
278     $value = $myconfig->{$value} . "/$conf" if ($conf);
279     $str .= $form->escape($value, 1);
280   }
281
282   $str .= '"';
283
284
285
286   if ($other) {
287     foreach my $key (keys(%{$other})) {
288       $str .= qq| ${key}="| . $form->quote($other->{$key}) . qq|"|;
289     }
290   }
291
292
293   $main::lxdebug->leave_sub();
294
295   return $str;
296 }
297
298 sub access_control {
299   $main::lxdebug->enter_sub(2);
300
301   my ($self, $myconfig, $menulevel) = @_;
302
303   my @menu = ();
304
305   if ($menulevel eq "") {
306     @menu = grep { !/--/ } @{ $self->{ORDER} };
307   } else {
308     @menu = grep { /^${menulevel}--/ } @{ $self->{ORDER} };
309   }
310
311   $main::lxdebug->leave_sub(2);
312
313   return @menu;
314 }
315
316 sub parse_access_string {
317   my $self   = shift;
318   my $key    = shift;
319   my $access = shift;
320
321   my $form        =  $main::form;
322   my $auth        =  $main::auth;
323   my $myconfig    = \%main::myconfig;
324
325   my @stack;
326   my $cur_ary = [];
327
328   push @stack, $cur_ary;
329
330   while ($access =~ m/^([a-z_]+|\||\&|\(|\)|\s+)/) {
331     my $token = $1;
332     substr($access, 0, length($1)) = "";
333
334     next if ($token =~ /\s/);
335
336     if ($token eq "(") {
337       my $new_cur_ary = [];
338       push @stack, $new_cur_ary;
339       push @{$cur_ary}, $new_cur_ary;
340       $cur_ary = $new_cur_ary;
341
342     } elsif ($token eq ")") {
343       pop @stack;
344       if (!@stack) {
345         $form->error("Error in menu.ini for entry ${key}: missing '('");
346       }
347       $cur_ary = $stack[-1];
348
349     } elsif (($token eq "|") || ($token eq "&")) {
350       push @{$cur_ary}, $token;
351
352     } else {
353       push @{$cur_ary}, $auth->check_right($form->{login}, $token, 1);
354     }
355   }
356
357   if ($access) {
358     $form->error("Error in menu.ini for entry ${key}: unrecognized token at the start of '$access'\n");
359   }
360
361   if (1 < scalar @stack) {
362     $main::form->error("Error in menu.ini for entry ${key}: Missing ')'\n");
363   }
364
365   return SL::Auth::evaluate_rights_ary($stack[0]);
366 }
367
368 sub set_access {
369   my $self = shift;
370
371   my $key;
372
373   foreach $key (@{ $self->{ORDER} }) {
374     my $entry = $self->{$key};
375
376     $entry->{GRANTED}              = $entry->{ACCESS} ? $self->parse_access_string($key, $entry->{ACCESS}) : 1;
377     $entry->{IS_MENU}              = $entry->{submenu} || ($key !~ m/--/);
378     $entry->{NUM_VISIBLE_CHILDREN} = 0;
379
380     if ($key =~ m/--/) {
381       my $parent = $key;
382       substr($parent, rindex($parent, '--')) = '';
383       $entry->{GRANTED} &&= $self->{$parent}->{GRANTED};
384     }
385
386     $entry->{VISIBLE} = $entry->{GRANTED};
387   }
388
389   foreach $key (reverse @{ $self->{ORDER} }) {
390     my $entry = $self->{$key};
391
392     if ($entry->{IS_MENU}) {
393       $entry->{VISIBLE} &&= $entry->{NUM_VISIBLE_CHILDREN} > 0;
394     }
395
396     next if (($key !~ m/--/) || !$entry->{VISIBLE});
397
398     my $parent = $key;
399     substr($parent, rindex($parent, '--')) = '';
400     $self->{$parent}->{NUM_VISIBLE_CHILDREN}++;
401   }
402
403 #   $self->dump_visible();
404
405   $self->{ORDER} = [ grep { $self->{$_}->{VISIBLE} } @{ $self->{ORDER} } ];
406
407   { no strict 'refs';
408   # ToDO: fix this. nuke and pave algorithm without type checking screams for problems.
409   map { delete @{$self->{$_}}{qw(GRANTED IS_MENU NUM_VISIBLE_CHILDREN VISIBLE ACCESS)} if ($_ ne 'ORDER') } keys %{ $self };
410   }
411 }
412
413 sub dump_visible {
414   my $self = shift;
415   foreach my $key (@{ $self->{ORDER} }) {
416     my $entry = $self->{$key};
417     $main::lxdebug->message(0, "$entry->{GRANTED} $entry->{VISIBLE} $entry->{NUM_VISIBLE_CHILDREN} $key");
418   }
419 }
420
421 1;
422