Einkaufsrechnung -> Zahlung buchen: sinnlosen Quark gefixt.
[kivitendo-erp.git] / SL / Template.pm
index f19e67a..3556dc4 100644 (file)
@@ -5,9 +5,17 @@
 # Web http://www.lx-office.org
 #
 #====================================================================
+#
+#
+#    NOTE: strict checks are package global. don't check this file
+#            with perl -sc, it will only capture SimpleTemplate
+#
+#
 
 package SimpleTemplate;
 
+use strict;
+
 # Parameters:
 #   1. The template's file name
 #   2. A reference to the Form object
@@ -34,19 +42,22 @@ sub _init {
   $self->{userspath} = shift;
 
   $self->{error}     = undef;
+  $self->{quot_re}   = '"';
 
   $self->set_tag_style('<%', '%>');
 }
 
 sub set_tag_style {
-  my $self              = shift;
-  my $tag_start         = shift;
-  my $tag_end           = shift;
-
-  $self->{tag_start}    = $tag_start;
-  $self->{tag_end}      = $tag_end;
-  $self->{tag_start_qm} = quotemeta $tag_start;
-  $self->{tag_end_qm}   = quotemeta $tag_end;
+  my $self                    = shift;
+  my $tag_start               = shift;
+  my $tag_end                 = shift;
+
+  $self->{tag_start}          = $tag_start;
+  $self->{tag_end}            = $tag_end;
+  $self->{tag_start_qm}       = quotemeta $tag_start;
+  $self->{tag_end_qm}         = quotemeta $tag_end;
+
+  $self->{substitute_vars_re} = "$self->{tag_start_qm}(.+?)$self->{tag_end_qm}";
 }
 
 sub cleanup {
@@ -77,6 +88,133 @@ sub uses_temp_file {
   return 0;
 }
 
+sub _get_loop_variable {
+  my $self      = shift;
+  my $var       = shift;
+  my $get_array = shift;
+  my @indices   = @_;
+
+  my $form      = $self->{form};
+  my $value;
+
+  if (($get_array || @indices) && (ref $form->{TEMPLATE_ARRAYS} eq 'HASH') && (ref $form->{TEMPLATE_ARRAYS}->{$var} eq 'ARRAY')) {
+    $value = $form->{TEMPLATE_ARRAYS}->{$var};
+  } else {
+    $value = $form->{$var};
+  }
+
+  for (my $i = 0; $i < scalar(@indices); $i++) {
+    last unless (ref($value) eq "ARRAY");
+    $value = $value->[$indices[$i]];
+  }
+
+  return $value;
+}
+
+sub substitute_vars {
+  my ($self, $text, @indices) = @_;
+
+  my $form = $self->{"form"};
+
+  while ($text =~ /$self->{substitute_vars_re}/) {
+    my ($tag_pos, $tag_len) = ($-[0], $+[0] - $-[0]);
+    my ($var, @options)     = split(/\s+/, $1);
+
+    my $value               = $self->_get_loop_variable($var, 0, @indices);
+    $value                  = $self->format_string($value) unless (grep(/^NOESCAPE$/, @options));
+
+    substr($text, $tag_pos, $tag_len, $value);
+  }
+
+  return $text;
+}
+
+sub _parse_block_if {
+  $main::lxdebug->enter_sub();
+
+  my $self         = shift;
+  my $contents     = shift;
+  my $new_contents = shift;
+  my $pos_if       = shift;
+  my @indices      = @_;
+
+  $$new_contents .= $self->substitute_vars(substr($$contents, 0, $pos_if), @indices);
+  substr($$contents, 0, $pos_if) = "";
+
+  if ($$contents !~ m/^$self->{tag_start_qm}if
+                     \s*
+                     (not\b|\!)?           # $1 -- Eventuelle Negierung
+                     \s+
+                     (\b.+?\b)             # $2 -- Name der zu überprüfenden Variablen
+                     (                     # $3 -- Beginn des optionalen Vergleiches
+                       \s*
+                       ([!=])              # $4 -- Negierung des Vergleiches speichern
+                       ([=~])              # $5 -- Art des Vergleiches speichern
+                       \s*
+                       (                   # $6 -- Gequoteter String oder Bareword
+                         $self->{quot_re}
+                         (.*?)(?<!\\)      # $7 -- Gequoteter String -- direkter Vergleich mit eq bzw. ne oder Patternmatching; Escapete Anführungs als Teil des Strings belassen
+                         $self->{quot_re}
+                       |
+                         (\b.+?\b)         # $8 -- Bareword -- als Index für $form benutzen
+                       )
+                     )?
+                     \s*
+                     $self->{tag_end_qm}
+                    /x) {
+    $self->{"error"} = "Malformed $self->{tag_start}if$self->{tag_end}.";
+    $main::lxdebug->leave_sub();
+    return undef;
+  }
+
+  my $not           = $1;
+  my $var           = $2;
+  my $operator_neg  = $4; # '=' oder '!' oder undef, wenn kein Vergleich erkannt
+  my $operator_type = $5; # '=' oder '~' für Stringvergleich oder Regex
+  my $quoted_word   = $7; # nur gültig, wenn quoted string angegeben (siehe unten); dann "value" aus <%if var == "value" %>
+  my $bareword      = $8; # undef, falls quoted string angegeben wurde; andernfalls "othervar" aus <%if var == othervar %>
+
+  $not = !$not if ($operator_neg && $operator_neg eq '!');
+
+  substr($$contents, 0, length($&)) = "";
+
+  my $block;
+  ($block, $$contents) = $self->find_end($$contents, 0, $var, $not);
+  if (!$block) {
+    $self->{"error"} = "Unclosed $self->{tag_start}if$self->{tag_end}." unless ($self->{"error"});
+    $main::lxdebug->leave_sub();
+    return undef;
+  }
+
+  my $value = $self->_get_loop_variable($var, 0, @indices);
+  my $hit   = 0;
+
+  if ($operator_type) {
+    my $compare_to = $bareword ? $self->_get_loop_variable($bareword, 0, @indices) : $quoted_word;
+    if ($operator_type eq '=') {
+      $hit         = ($not && !($value eq $compare_to))     || (!$not && ($value eq $compare_to));
+    } else {
+      $hit         = ($not && !($value =~ m/$compare_to/i)) || (!$not && ($value =~ m/$compare_to/i));
+    }
+
+  } else {
+    $hit           = ($not && ! $value)                     || (!$not &&  $value);
+  }
+
+  if ($hit) {
+    my $new_text = $self->parse_block($block, @indices);
+    if (!defined($new_text)) {
+      $main::lxdebug->leave_sub();
+      return undef;
+    }
+    $$new_contents .= $new_text;
+  }
+
+  $main::lxdebug->leave_sub();
+
+  return 1;
+}
+
 1;
 
 ####
@@ -89,48 +227,21 @@ use vars qw(@ISA);
 
 @ISA = qw(SimpleTemplate);
 
+use strict;
+
 sub new {
   my $type = shift;
 
-  return $type->SUPER::new(@_);
+  my $self = $type->SUPER::new(@_);
+
+  return $self;
 }
 
 sub format_string {
   my ($self, $variable) = @_;
   my $form = $self->{"form"};
 
-  my %replace =
-    ('order' => [quotemeta("\\"),
-                 '<pagebreak>',
-                 '&', quotemeta("\n"),
-                 '"', '\$', '%', '_', '#', quotemeta('^'),
-                 '{', '}',  '<', '>', '£', "\r", '±', '\xe1',
-                 '²', '³',
-
-                 ],
-     quotemeta("\\") => '\\textbackslash ',
-     '<pagebreak>'   => '',
-     '"'             => "''",
-     '&'             => '\&',
-     '\$'            => '\$',
-     '%'             => '\%',
-     '_'             => '\_',
-     '#'             => '\#',
-     '{'             => '\{',
-     '}'             => '\}',
-     '<'             => '$<$',
-     '>'             => '$>$',
-     '£'             => '\pounds ',
-     "\r"            => "",
-     '±'             => '$\pm$',
-     '\xe1'          => '$\bullet$',
-     quotemeta('^')  => '\^\\',
-     quotemeta("\n") => '\newline ',
-     '²'             => '$^2$',
-     '³'             => '$^3$',
-     );
-
-  map({ $variable =~ s/$_/$replace{$_}/g; } @{ $replace{"order"} });
+  $variable = $main::locale->quote_special_chars('Template/LaTeX', $variable);
 
   # Allow some HTML markup to be converted into the output format's
   # corresponding markup code, e.g. bold or italic.
@@ -148,60 +259,41 @@ sub format_string {
   return $variable;
 }
 
-sub substitute_vars {
-  my ($self, $text, @indices) = @_;
-
-  my $form = $self->{"form"};
-
-  while ($text =~ /$self->{tag_start_qm}(.+?)$self->{tag_end_qm}/) {
-    my ($tag_pos, $tag_len) = ($-[0], $+[0] - $-[0]);
-    my ($var, @options) = split(/\s+/, $1);
-    my $value = $form->{$var};
-
-    for (my $i = 0; $i < scalar(@indices); $i++) {
-      last unless (ref($value) eq "ARRAY");
-      $value = $value->[$indices[$i]];
-    }
-    $value = $self->format_string($value) unless (grep(/^NOESCAPE$/, @options));
-    substr($text, $tag_pos, $tag_len) = $value;
-  }
-
-  return $text;
-}
-
 sub parse_foreach {
   my ($self, $var, $text, $start_tag, $end_tag, @indices) = @_;
 
   my ($form, $new_contents) = ($self->{"form"}, "");
 
-  my $ary = $form->{$var};
-  for (my $i = 0; $i < scalar(@indices); $i++) {
-    last unless (ref($ary) eq "ARRAY");
-    $ary = $ary->[$indices[$i]];
-  }
+  my $ary = $self->_get_loop_variable($var, 1, @indices);
 
-  my $sum = 0;
-  my $current_page = 1;
+  my $sum                          = 0;
+  my $current_page                 = 1;
   my ($current_line, $corrent_row) = (0, 1);
+  my $description_array            = $self->_get_loop_variable("description",     1);
+  my $longdescription_array        = $self->_get_loop_variable("longdescription", 1);
+  my $linetotal_array              = $self->_get_loop_variable("linetotal",       1);
+
+  $form->{TEMPLATE_ARRAYS}->{cumulatelinetotal} = [];
+
+  # forech block hasn't given us an array. ignore
+  return $new_contents unless ref $ary eq 'ARRAY';
 
   for (my $i = 0; $i < scalar(@{$ary}); $i++) {
-    $form->{"__first__"} = $i == 0;
-    $form->{"__last__"} = ($i + 1) == scalar(@{$ary});
-    $form->{"__odd__"} = (($i + 1) % 2) == 1;
+    # do magic markers
+    $form->{"__first__"}   = $i == 1;
+    $form->{"__last__"}    = ($i + 1) == scalar(@{$ary});
+    $form->{"__odd__"}     = (($i + 1) % 2) == 1;
     $form->{"__counter__"} = $i + 1;
 
-    if ((scalar(@{$form->{"description"}}) == scalar(@{$ary})) &&
-        $self->{"chars_per_line"}) {
-      my $lines =
-        int(length($form->{"description"}->[$i]) / $self->{"chars_per_line"});
+    if (   ref $description_array       eq 'ARRAY'
+        && scalar @{$description_array} == scalar @{$ary}
+        && $self->{"chars_per_line"}    != 0)
+    {
+      my $lines = int(length($description_array->[$i]) / $self->{"chars_per_line"});
       my $lpp;
 
-      $form->{"description"}->[$i] =~ s/(\\newline\s?)*$//;
-      my $_description = $form->{"description"}->[$i];
-      while ($_description =~ /\\newline/) {
-        $lines++;
-        $_description =~ s/\\newline//;
-      }
+      $description_array->[$i] =~ s/(\\newline\s?)*$//;
+      $lines++ while ($description_array->[$i] =~ m/\\newline/g);
       $lines++;
 
       if ($current_page == 1) {
@@ -211,8 +303,10 @@ sub parse_foreach {
       }
 
       # Yes we need a manual page break -- or the user has forced one
-      if ((($current_line + $lines) > $lpp) ||
-          ($form->{"description"}->[$i] =~ /<pagebreak>/)) {
+      if (   (($current_line + $lines) > $lpp)
+          || ($description_array->[$i]     =~ /<pagebreak>/)
+          || (   ref $longdescription_array eq 'ARRAY'
+              && $longdescription_array->[$i] =~ /<pagebreak>/)) {
         my $pb = $self->{"pagebreak_block"};
 
         # replace the special variables <%sumcarriedforward%>
@@ -231,13 +325,14 @@ sub parse_foreach {
       }
       $current_line += $lines;
     }
-    if ($i < scalar(@{$form->{"linetotal"}})) {
-      $sum += $form->parse_amount($self->{"myconfig"},
-                                  $form->{"linetotal"}->[$i]);
+
+    if (   ref $linetotal_array eq 'ARRAY'
+        && $i < scalar(@{$linetotal_array})) {
+      $sum += $form->parse_amount($self->{"myconfig"}, $linetotal_array->[$i]);
     }
-    
-    $form->{"cumulatelinetotal"}[$i] = $form->format_amount($self->{"myconfig"}, $sum, 2);
-    
+
+    $form->{TEMPLATE_ARRAYS}->{cumulatelinetotal}->[$i] = $form->format_amount($self->{"myconfig"}, $sum, 2);
+
     my $new_text = $self->parse_block($text, (@indices, $i));
     return undef unless (defined($new_text));
     $new_contents .= $start_tag . $new_text . $end_tag;
@@ -342,40 +437,10 @@ sub parse_block {
       $new_contents .= $new_text;
 
     } else {
-      $new_contents .= $self->substitute_vars(substr($contents, 0, $pos_if), @indices);
-      substr($contents, 0, $pos_if) = "";
-
-      if ($contents !~ m|^$self->{tag_start_qm}if\s*(not)?\s+(.*?)$self->{tag_end_qm}|) {
-        $self->{"error"} = "Malformed $self->{tag_start}if$self->{tag_end}.";
+      if (!$self->_parse_block_if(\$contents, \$new_contents, $pos_if, @indices)) {
         $main::lxdebug->leave_sub();
         return undef;
       }
-
-      my ($not, $var) = ($1, $2);
-
-      substr($contents, 0, length($&)) = "";
-
-      ($block, $contents) = $self->find_end($contents, 0, $var, $not);
-      if (!$block) {
-        $self->{"error"} = "Unclosed $self->{tag_start}if${not}$self->{tag_end}." unless ($self->{"error"});
-        $main::lxdebug->leave_sub();
-        return undef;
-      }
-
-      my $value = $self->{"form"}->{$var};
-      for (my $i = 0; $i < scalar(@indices); $i++) {
-        last unless (ref($value) eq "ARRAY");
-        $value = $value->[$indices[$i]];
-      }
-
-      if (($not && !$value) || (!$not && $value)) {
-        my $new_text = $self->parse_block($block, @indices);
-        if (!defined($new_text)) {
-          $main::lxdebug->leave_sub();
-          return undef;
-        }
-        $new_contents .= $new_text;
-      }
     }
   }
 
@@ -446,6 +511,31 @@ sub _parse_config_lines {
   }
 }
 
+sub _force_mandatory_packages {
+  my $self  = shift;
+  my $lines = shift;
+
+  my (%used_packages, $document_start_line);
+
+  foreach my $i (0 .. scalar @{ $lines } - 1) {
+    if ($lines->[$i] =~ m/\\usepackage[^\{]*{(.*?)}/) {
+      $used_packages{$1} = 1;
+
+    } elsif ($lines->[$i] =~ m/\\begin{document}/) {
+      $document_start_line = $i;
+      last;
+
+    }
+  }
+
+  $document_start_line = scalar @{ $lines } - 1 if (!defined $document_start_line);
+
+  if (!$used_packages{textcomp}) {
+    splice @{ $lines }, $document_start_line, 0, "\\usepackage{textcomp}\n";
+    $document_start_line++;
+  }
+}
+
 sub parse {
   my $self = $_[0];
   local *OUT = $_[1];
@@ -459,6 +549,7 @@ sub parse {
   close(IN);
 
   $self->_parse_config_lines(\@lines);
+  $self->_force_mandatory_packages(\@lines) if (ref $self eq 'LaTeXTemplate');
 
   my $contents = join("", @lines);
 
@@ -505,8 +596,10 @@ sub convert_to_postscript {
 
   $form->{tmpfile} =~ s/\Q$userspath\E\///g;
 
+  my $latex = $self->_get_latex_path();
+
   for (my $run = 1; $run <= 2; $run++) {
-    system("latex --interaction=nonstopmode $form->{tmpfile} " .
+    system("${latex} --interaction=nonstopmode $form->{tmpfile} " .
            "> $form->{tmpfile}.err");
     if ($?) {
       $self->{"error"} = $form->cleanup();
@@ -544,8 +637,10 @@ sub convert_to_pdf {
 
   $form->{tmpfile} =~ s/\Q$userspath\E\///g;
 
+  my $latex = $self->_get_latex_path();
+
   for (my $run = 1; $run <= 2; $run++) {
-    system("pdflatex --interaction=nonstopmode $form->{tmpfile} " .
+    system("${latex} --interaction=nonstopmode $form->{tmpfile} " .
            "> $form->{tmpfile}.err");
     if ($?) {
       $self->{"error"} = $form->cleanup();
@@ -559,6 +654,10 @@ sub convert_to_pdf {
   $self->cleanup();
 }
 
+sub _get_latex_path {
+  return $main::latex_bin || 'pdflatex';
+}
+
 sub get_mime_type() {
   my ($self) = @_;
 
@@ -584,6 +683,8 @@ use vars qw(@ISA);
 
 @ISA = qw(LaTeXTemplate);
 
+use strict;
+
 sub new {
   my $type = shift;
 
@@ -594,14 +695,7 @@ sub format_string {
   my ($self, $variable) = @_;
   my $form = $self->{"form"};
 
-  my %replace =
-    ('order' => ['<', '>', quotemeta("\n")],
-     '<'             => '&lt;',
-     '>'             => '&gt;',
-     quotemeta("\n") => '<br>',
-     );
-
-  map({ $variable =~ s/$_/$replace{$_}/g; } @{ $replace{"order"} });
+  $variable = $main::locale->quote_special_chars('Template/HTML', $variable);
 
   # Allow some HTML markup to be converted into the output format's
   # corresponding markup code, e.g. bold or italic.
@@ -715,6 +809,8 @@ use vars qw(@ISA);
 
 @ISA = qw(LaTeXTemplate);
 
+use strict;
+
 sub new {
   my $type = shift;
 
@@ -753,10 +849,12 @@ use IO::File;
 
 @ISA = qw(SimpleTemplate);
 
+use strict;
+
 sub new {
   my $type = shift;
 
-  $self = $type->SUPER::new(@_);
+  my $self = $type->SUPER::new(@_);
 
   foreach my $module (qw(Archive::Zip Text::Iconv)) {
     eval("use ${module};");
@@ -769,28 +867,13 @@ sub new {
     }
   }
 
-  $self->{"rnd"} = int(rand(1000000));
+  $self->{"rnd"}   = int(rand(1000000));
   $self->{"iconv"} = Text::Iconv->new($main::dbcharset, "UTF-8");
 
-  return $self;
-}
-
-sub substitute_vars {
-  my ($self, $text, @indices) = @_;
-
-  my $form = $self->{"form"};
+  $self->set_tag_style('&lt;%', '%&gt;');
+  $self->{quot_re} = '&quot;';
 
-  while ($text =~ /\&lt;\%(.*?)\%\&gt;/) {
-    my $value = $form->{$1};
-
-    for (my $i = 0; $i < scalar(@indices); $i++) {
-      last unless (ref($value) eq "ARRAY");
-      $value = $value->[$indices[$i]];
-    }
-    substr($text, $-[0], $+[0] - $-[0]) = $self->format_string($value);
-  }
-
-  return $text;
+  return $self;
 }
 
 sub parse_foreach {
@@ -798,11 +881,7 @@ sub parse_foreach {
 
   my ($form, $new_contents) = ($self->{"form"}, "");
 
-  my $ary = $form->{$var};
-  for (my $i = 0; $i < scalar(@indices); $i++) {
-    last unless (ref($ary) eq "ARRAY");
-    $ary = $ary->[$indices[$i]];
-  }
+  my $ary = $self->_get_loop_variable($var, 1, @indices);
 
   for (my $i = 0; $i < scalar(@{$ary}); $i++) {
     $form->{"__first__"} = $i == 0;
@@ -954,40 +1033,10 @@ sub parse_block {
         $new_contents .= $new_text;
 
       } else {
-        $new_contents .= $self->substitute_vars(substr($contents, 0, $pos_if), @indices);
-        substr($contents, 0, $pos_if) = "";
-
-        if ($contents !~ m|^\&lt;\%if\s*(not)?\s+(.*?)\%\&gt;|) {
-          $self->{"error"} = "Malformed <\%if\%>.";
+        if (!$self->_parse_block_if(\$contents, \$new_contents, $pos_if, @indices)) {
           $main::lxdebug->leave_sub();
           return undef;
         }
-
-        my ($not, $var) = ($1, $2);
-
-        substr($contents, 0, length($&)) = "";
-
-        ($block, $contents) = $self->find_end($contents, 0, $var, $not);
-        if (!$block) {
-          $self->{"error"} = "Unclosed <\%if${not}\%>." unless ($self->{"error"});
-          $main::lxdebug->leave_sub();
-          return undef;
-        }
-
-        my $value = $self->{"form"}->{$var};
-        for (my $i = 0; $i < scalar(@indices); $i++) {
-          last unless (ref($value) eq "ARRAY");
-          $value = $value->[$indices[$i]];
-        }
-
-        if (($not && !$value) || (!$not && $value)) {
-          my $new_text = $self->parse_block($block, @indices);
-          if (!defined($new_text)) {
-            $main::lxdebug->leave_sub();
-            return undef;
-          }
-          $new_contents .= $new_text;
-        }
       }
     }
   }
@@ -1014,7 +1063,7 @@ sub parse {
   }
 
   my $zip = Archive::Zip->new();
-  if (Archive::Zip::AZ_OK != $zip->read($file_name)) {
+  if (Archive::Zip->AZ_OK != $zip->read($file_name)) {
     $self->{"error"} = "File not found/is not a OpenDocument file.";
     $main::lxdebug->leave_sub();
     return 0;
@@ -1091,7 +1140,7 @@ sub is_xvfb_running {
   my $dfname = $self->{"userspath"} . "/xvfb_display";
   my $display;
 
-  $main::lxdebug->message(LXDebug::DEBUG2, "    Looking for $dfname\n");
+  $main::lxdebug->message(LXDebug->DEBUG2(), "    Looking for $dfname\n");
   if ((-f $dfname) && open(IN, $dfname)) {
     my $pid = <IN>;
     chomp($pid);
@@ -1101,10 +1150,10 @@ sub is_xvfb_running {
     chomp($xauthority);
     close(IN);
 
-    $main::lxdebug->message(LXDebug::DEBUG2, "      found with $pid and $display\n");
+    $main::lxdebug->message(LXDebug->DEBUG2(), "      found with $pid and $display\n");
 
     if ((! -d "/proc/$pid") || !open(IN, "/proc/$pid/cmdline")) {
-      $main::lxdebug->message(LXDebug::DEBUG2, "  no/wrong process #1\n");
+      $main::lxdebug->message(LXDebug->DEBUG2(), "  no/wrong process #1\n");
       unlink($dfname, $xauthority);
       $main::lxdebug->leave_sub();
       return undef;
@@ -1112,7 +1161,7 @@ sub is_xvfb_running {
     my $line = <IN>;
     close(IN);
     if ($line !~ /xvfb/i) {
-      $main::lxdebug->message(LXDebug::DEBUG2, "      no/wrong process #2\n");
+      $main::lxdebug->message(LXDebug->DEBUG2(), "      no/wrong process #2\n");
       unlink($dfname, $xauthority);
       $main::lxdebug->leave_sub();
       return undef;
@@ -1121,7 +1170,7 @@ sub is_xvfb_running {
     $ENV{"XAUTHORITY"} = $xauthority;
     $ENV{"DISPLAY"} = $display;
   } else {
-    $main::lxdebug->message(LXDebug::DEBUG2, "      not found\n");
+    $main::lxdebug->message(LXDebug->DEBUG2(), "      not found\n");
   }
 
   $main::lxdebug->leave_sub();
@@ -1134,7 +1183,7 @@ sub spawn_xvfb {
 
   my ($self) = @_;
 
-  $main::lxdebug->message(LXDebug::DEBUG2, "spawn_xvfb()\n");
+  $main::lxdebug->message(LXDebug->DEBUG2, "spawn_xvfb()\n");
 
   my $display = $self->is_xvfb_running();
 
@@ -1148,18 +1197,18 @@ sub spawn_xvfb {
     $display++;
   }
   $display = ":${display}";
-  $main::lxdebug->message(LXDebug::DEBUG2, "  display $display\n");
+  $main::lxdebug->message(LXDebug->DEBUG2(), "  display $display\n");
 
   my $mcookie = `mcookie`;
   die("Installation error: mcookie not found.") if ($? != 0);
   chomp($mcookie);
 
-  $main::lxdebug->message(LXDebug::DEBUG2, "  mcookie $mcookie\n");
+  $main::lxdebug->message(LXDebug->DEBUG2(), "  mcookie $mcookie\n");
 
   my $xauthority = "/tmp/.Xauthority-" . $$ . "-" . time() . "-" . int(rand(9999999));
   $ENV{"XAUTHORITY"} = $xauthority;
 
-  $main::lxdebug->message(LXDebug::DEBUG2, "  xauthority $xauthority\n");
+  $main::lxdebug->message(LXDebug->DEBUG2(), "  xauthority $xauthority\n");
 
   system("xauth add \"${display}\" . \"${mcookie}\"");
   if ($? != 0) {
@@ -1168,15 +1217,15 @@ sub spawn_xvfb {
     return undef;
   }
 
-  $main::lxdebug->message(LXDebug::DEBUG2, "  about to fork()\n");
+  $main::lxdebug->message(LXDebug->DEBUG2(), "  about to fork()\n");
 
   my $pid = fork();
   if (0 == $pid) {
-    $main::lxdebug->message(LXDebug::DEBUG2, "  Child execing\n");
+    $main::lxdebug->message(LXDebug->DEBUG2(), "  Child execing\n");
     exec($main::xvfb_bin, $display, "-screen", "0", "640x480x8", "-nolisten", "tcp");
   }
   sleep(3);
-  $main::lxdebug->message(LXDebug::DEBUG2, "  parent dont sleeping\n");
+  $main::lxdebug->message(LXDebug->DEBUG2(), "  parent dont sleeping\n");
 
   local *OUT;
   my $dfname = $self->{"userspath"} . "/xvfb_display";
@@ -1190,7 +1239,7 @@ sub spawn_xvfb {
   print(OUT "$pid\n$display\n$xauthority\n");
   close(OUT);
 
-  $main::lxdebug->message(LXDebug::DEBUG2, "  parent re-testing\n");
+  $main::lxdebug->message(LXDebug->DEBUG2(), "  parent re-testing\n");
 
   if (!$self->is_xvfb_running()) {
     $self->{"error"} = "Conversion to PDF failed because OpenOffice could not be started.";
@@ -1200,7 +1249,7 @@ sub spawn_xvfb {
     return undef;
   }
 
-  $main::lxdebug->message(LXDebug::DEBUG2, "  spawn OK\n");
+  $main::lxdebug->message(LXDebug->DEBUG2(), "  spawn OK\n");
 
   $main::lxdebug->leave_sub();
 
@@ -1213,7 +1262,7 @@ sub is_openoffice_running {
   system("./scripts/oo-uno-test-conn.py $main::openofficeorg_daemon_port " .
          "> /dev/null 2> /dev/null");
   my $res = $? == 0;
-  $main::lxdebug->message(LXDebug::DEBUG2, "  is_openoffice_running(): $?\n");
+  $main::lxdebug->message(LXDebug->DEBUG2(), "  is_openoffice_running(): $?\n");
 
   $main::lxdebug->leave_sub();
 
@@ -1225,7 +1274,7 @@ sub spawn_openoffice {
 
   my ($self) = @_;
 
-  $main::lxdebug->message(LXDebug::DEBUG2, "spawn_openoffice()\n");
+  $main::lxdebug->message(LXDebug->DEBUG2(), "spawn_openoffice()\n");
 
   my ($try, $spawned_oo, $res);
 
@@ -1239,14 +1288,14 @@ sub spawn_openoffice {
     if (!$spawned_oo) {
       my $pid = fork();
       if (0 == $pid) {
-        $main::lxdebug->message(LXDebug::DEBUG2, "  Child daemonizing\n");
+        $main::lxdebug->message(LXDebug->DEBUG2(), "  Child daemonizing\n");
         chdir('/');
         open(STDIN, '/dev/null');
         open(STDOUT, '>/dev/null');
         my $new_pid = fork();
         exit if ($new_pid);
         my $ssres = setsid();
-        $main::lxdebug->message(LXDebug::DEBUG2, "  Child execing\n");
+        $main::lxdebug->message(LXDebug->DEBUG2(), "  Child execing\n");
         my @cmdline = ($main::openofficeorg_writer_bin,
                        "-minimized", "-norestore", "-nologo", "-nolockcheck",
                        "-headless",
@@ -1255,7 +1304,7 @@ sub spawn_openoffice {
         exec(@cmdline);
       }
 
-      $main::lxdebug->message(LXDebug::DEBUG2, "  Parent after fork\n");
+      $main::lxdebug->message(LXDebug->DEBUG2(), "  Parent after fork\n");
       $spawned_oo = 1;
       sleep(3);
     }
@@ -1342,21 +1391,7 @@ sub format_string {
   my $form = $self->{"form"};
   my $iconv = $self->{"iconv"};
 
-  my %replace =
-    ('order' => ['&', '<', '>', '"', "'",
-                 '\x80',        # Euro
-                 quotemeta("\n"), quotemeta("\r")],
-     '<'             => '&lt;',
-     '>'             => '&gt;',
-     '"'             => '&quot;',
-     "'"             => '&apos;',
-     '&'             => '&amp;',
-     '\x80'          => chr(0xa4), # Euro
-     quotemeta("\n") => '<text:line-break/>',
-     quotemeta("\r") => '',
-     );
-
-  map({ $variable =~ s/$_/$replace{$_}/g; } @{ $replace{"order"} });
+  $variable = $main::locale->quote_special_chars('Template/OpenDocument', $variable);
 
   # Allow some HTML markup to be converted into the output format's
   # corresponding markup code, e.g. bold or italic.
@@ -1374,6 +1409,8 @@ sub format_string {
 }
 
 sub get_mime_type() {
+  my ($self) = @_;
+
   if ($self->{"form"}->{"format"} =~ /pdf/) {
     return "application/pdf";
   } else {
@@ -1392,12 +1429,14 @@ sub uses_temp_file {
 ####
 ##########################################################
 
-package XMLTemplate; 
+package XMLTemplate;
 
 use vars qw(@ISA);
 
 @ISA = qw(HTMLTemplate);
 
+use strict;
+
 sub new {
   #evtl auskommentieren
   my $type = shift;
@@ -1409,14 +1448,7 @@ sub format_string {
   my ($self, $variable) = @_;
   my $form = $self->{"form"};
 
-  my %replace =
-    ('order' => ['<', '>', quotemeta("\n")],
-     '<'             => '&lt;',
-     '>'             => '&gt;',
-     quotemeta("\n") => '<br>',
-     );
-
-  map({ $variable =~ s/$_/$replace{$_}/g; } @{ $replace{"order"} });
+  $variable = $main::locale->quote_special_chars('Template/XML', $variable);
 
   # Allow no markup to be converted into the output format
   my @markup_replace = ('b', 'i', 's', 'u', 'sub', 'sup');