1 #====================================================================
4 # Based on SQL-Ledger Version 2.1.9
5 # Web http://www.lx-office.org
7 #====================================================================
9 package SimpleTemplate;
12 # 1. The template's file name
13 # 2. A reference to the Form object
14 # 3. A reference to the myconfig hash
17 # A new template object
31 $self->{source} = shift;
32 $self->{form} = shift;
33 $self->{myconfig} = shift;
34 $self->{userspath} = shift;
36 $self->{error} = undef;
38 $self->set_tag_style('<%', '%>');
43 my $tag_start = shift;
46 $self->{tag_start} = $tag_start;
47 $self->{tag_end} = $tag_end;
48 $self->{tag_start_qm} = quotemeta $tag_start;
49 $self->{tag_end_qm} = quotemeta $tag_end;
57 # 1. A typeglob for the file handle. The output will be written
58 # to this file handle.
61 # 1 on success and undef or 0 if there was an error. In the latter case
62 # the calling function can retrieve the error message via $obj->get_error()
67 print(OUT "Hallo!\n");
73 return $self->{"error"};
86 package LaTeXTemplate;
90 @ISA = qw(SimpleTemplate);
95 return $type->SUPER::new(@_);
99 my ($self, $variable) = @_;
100 my $form = $self->{"form"};
103 ('order' => [quotemeta("\\"),
105 '&', quotemeta("\n"),
106 '"', '\$', '%', '_', '#', quotemeta('^'),
107 '{', '}', '<', '>', '£', "\r", '±', '\xe1',
111 quotemeta("\\") => '\\textbackslash ',
126 '\xe1' => '$\bullet$',
127 quotemeta('^') => '\^\\',
128 quotemeta("\n") => '\newline ',
133 map({ $variable =~ s/$_/$replace{$_}/g; } @{ $replace{"order"} });
135 # Allow some HTML markup to be converted into the output format's
136 # corresponding markup code, e.g. bold or italic.
137 my %markup_replace = ('b' => 'textbf',
141 foreach my $key (keys(%markup_replace)) {
142 my $new = $markup_replace{$key};
143 $variable =~ s/\$\<\$${key}\$\>\$(.*?)\$<\$\/${key}\$>\$/\\${new}\{$1\}/gi;
146 $variable =~ s/[\x00-\x1f]//g;
151 sub substitute_vars {
152 my ($self, $text, @indices) = @_;
154 my $form = $self->{"form"};
156 while ($text =~ /$self->{tag_start_qm}(.+?)$self->{tag_end_qm}/) {
157 my ($tag_pos, $tag_len) = ($-[0], $+[0] - $-[0]);
158 my ($var, @options) = split(/\s+/, $1);
159 my $value = $form->{$var};
161 for (my $i = 0; $i < scalar(@indices); $i++) {
162 last unless (ref($value) eq "ARRAY");
163 $value = $value->[$indices[$i]];
165 $value = $self->format_string($value) unless (grep(/^NOESCAPE$/, @options));
166 substr($text, $tag_pos, $tag_len) = $value;
173 my ($self, $var, $text, $start_tag, $end_tag, @indices) = @_;
175 my ($form, $new_contents) = ($self->{"form"}, "");
177 my $ary = $form->{$var};
178 for (my $i = 0; $i < scalar(@indices); $i++) {
179 last unless (ref($ary) eq "ARRAY");
180 $ary = $ary->[$indices[$i]];
184 my $current_page = 1;
185 my ($current_line, $corrent_row) = (0, 1);
187 for (my $i = 0; $i < scalar(@{$ary}); $i++) {
188 $form->{"__first__"} = $i == 0;
189 $form->{"__last__"} = ($i + 1) == scalar(@{$ary});
190 $form->{"__odd__"} = (($i + 1) % 2) == 1;
191 $form->{"__counter__"} = $i + 1;
193 if ((scalar(@{$form->{"description"}}) == scalar(@{$ary})) &&
194 $self->{"chars_per_line"}) {
196 int(length($form->{"description"}->[$i]) / $self->{"chars_per_line"});
199 $form->{"description"}->[$i] =~ s/(\\newline\s?)*$//;
200 my $_description = $form->{"description"}->[$i];
201 while ($_description =~ /\\newline/) {
203 $_description =~ s/\\newline//;
207 if ($current_page == 1) {
208 $lpp = $self->{"lines_on_first_page"};
210 $lpp = $self->{"lines_on_second_page"};
213 # Yes we need a manual page break -- or the user has forced one
214 if ((($current_line + $lines) > $lpp) ||
215 ($form->{"description"}->[$i] =~ /<pagebreak>/)) {
216 my $pb = $self->{"pagebreak_block"};
218 # replace the special variables <%sumcarriedforward%>
221 my $psum = $form->format_amount($self->{"myconfig"}, $sum, 2);
222 $pb =~ s/$self->{tag_start_qm}sumcarriedforward$self->{tag_end_qm}/$psum/g;
223 $pb =~ s/$self->{tag_start_qm}lastpage$self->{tag_end_qm}/$current_page/g;
225 my $new_text = $self->parse_block($pb, (@indices, $i));
226 return undef unless (defined($new_text));
227 $new_contents .= $new_text;
232 $current_line += $lines;
234 if ($i < scalar(@{$form->{"linetotal"}})) {
235 $sum += $form->parse_amount($self->{"myconfig"},
236 $form->{"linetotal"}->[$i]);
239 $form->{"cumulatelinetotal"}[$i] = $form->format_amount($self->{"myconfig"}, $sum, 2);
241 my $new_text = $self->parse_block($text, (@indices, $i));
242 return undef unless (defined($new_text));
243 $new_contents .= $start_tag . $new_text . $end_tag;
245 map({ delete($form->{"__${_}__"}); } qw(first last odd counter));
247 return $new_contents;
251 my ($self, $text, $pos, $var, $not) = @_;
253 my $tag_start_len = length $self->{tag_start};
256 $pos = 0 unless ($pos);
258 while ($pos < length($text)) {
261 next if (substr($text, $pos - 1, length($self->{tag_start})) ne $self->{tag_start});
263 my $keyword_pos = $pos - 1 + $tag_start_len;
265 if ((substr($text, $keyword_pos, 2) eq 'if') || (substr($text, $keyword_pos, 3) eq 'for')) {
268 } elsif ((substr($text, $keyword_pos, 4) eq 'else') && (1 == $depth)) {
271 "$self->{tag_start}else$self->{tag_end} outside of "
272 . "$self->{tag_start}if$self->{tag_end} / "
273 . "$self->{tag_start}ifnot$self->{tag_end}.";
277 my $block = substr($text, 0, $pos - 1);
278 substr($text, 0, $pos - 1) = "";
279 $text =~ s!^$self->{tag_start_qm}.+?$self->{tag_end_qm}!!;
280 $text = $self->{tag_start} . 'if' . ($not ? " " : "not ") . $var . $self->{tag_end} . $text;
282 return ($block, $text);
284 } elsif (substr($text, $keyword_pos, 3) eq 'end') {
287 my $block = substr($text, 0, $pos - 1);
288 substr($text, 0, $pos - 1) = "";
289 $text =~ s!^$self->{tag_start_qm}.+?$self->{tag_end_qm}!!;
291 return ($block, $text);
300 $main::lxdebug->enter_sub();
302 my ($self, $contents, @indices) = @_;
304 my $new_contents = "";
306 while ($contents ne "") {
307 my $pos_if = index($contents, $self->{tag_start} . 'if');
308 my $pos_foreach = index($contents, $self->{tag_start} . 'foreach');
310 if ((-1 == $pos_if) && (-1 == $pos_foreach)) {
311 $new_contents .= $self->substitute_vars($contents, @indices);
315 if ((-1 == $pos_if) || ((-1 != $pos_foreach) && ($pos_if > $pos_foreach))) {
316 $new_contents .= $self->substitute_vars(substr($contents, 0, $pos_foreach), @indices);
317 substr($contents, 0, $pos_foreach) = "";
319 if ($contents !~ m|^$self->{tag_start_qm}foreach (.+?)$self->{tag_end_qm}|) {
320 $self->{"error"} = "Malformed $self->{tag_start}foreach$self->{tag_end}.";
321 $main::lxdebug->leave_sub();
327 substr($contents, 0, length($&)) = "";
330 ($block, $contents) = $self->find_end($contents);
332 $self->{"error"} = "Unclosed $self->{tag_start}foreach$self->{tag_end}." unless ($self->{"error"});
333 $main::lxdebug->leave_sub();
337 my $new_text = $self->parse_foreach($var, $block, "", "", @indices);
338 if (!defined($new_text)) {
339 $main::lxdebug->leave_sub();
342 $new_contents .= $new_text;
345 $new_contents .= $self->substitute_vars(substr($contents, 0, $pos_if), @indices);
346 substr($contents, 0, $pos_if) = "";
348 if ($contents !~ m|^$self->{tag_start_qm}if\s*(not)?\s+(.*?)$self->{tag_end_qm}|) {
349 $self->{"error"} = "Malformed $self->{tag_start}if$self->{tag_end}.";
350 $main::lxdebug->leave_sub();
354 my ($not, $var) = ($1, $2);
356 substr($contents, 0, length($&)) = "";
358 ($block, $contents) = $self->find_end($contents, 0, $var, $not);
360 $self->{"error"} = "Unclosed $self->{tag_start}if${not}$self->{tag_end}." unless ($self->{"error"});
361 $main::lxdebug->leave_sub();
365 my $value = $self->{"form"}->{$var};
366 for (my $i = 0; $i < scalar(@indices); $i++) {
367 last unless (ref($value) eq "ARRAY");
368 $value = $value->[$indices[$i]];
371 if (($not && !$value) || (!$not && $value)) {
372 my $new_text = $self->parse_block($block, @indices);
373 if (!defined($new_text)) {
374 $main::lxdebug->leave_sub();
377 $new_contents .= $new_text;
382 $main::lxdebug->leave_sub();
384 return $new_contents;
387 sub parse_first_line {
389 my $line = shift || "";
391 if ($line =~ m/([^\s]+)set-tag-style([^\s]+)/) {
393 $self->{error} = "The tag start and end markers must not be equal.";
397 $self->set_tag_style($1, $2);
406 my $form = $self->{"form"};
408 if (!open(IN, "$form->{templates}/$form->{IN}")) {
409 $self->{"error"} = "$!";
415 return 0 if (!$self->parse_first_line($lines[0]));
417 my $contents = join("", @lines);
419 # detect pagebreak block and its parameters
420 if ($contents =~ /$self->{tag_start_qm}pagebreak\s+(\d+)\s+(\d+)\s+(\d+)\s*$self->{tag_end_qm}(.*?)$self->{tag_start_qm}end(\s*pagebreak)?$self->{tag_end_qm}/s) {
421 $self->{"chars_per_line"} = $1;
422 $self->{"lines_on_first_page"} = $2;
423 $self->{"lines_on_second_page"} = $3;
424 $self->{"pagebreak_block"} = $4;
426 substr($contents, length($`), length($&)) = "";
429 $self->{"forced_pagebreaks"} = [];
431 my $new_contents = $self->parse_block($contents);
432 if (!defined($new_contents)) {
433 $main::lxdebug->leave_sub();
437 print(OUT $new_contents);
439 if ($form->{"format"} =~ /postscript/i) {
440 return $self->convert_to_postscript();
441 } elsif ($form->{"format"} =~ /pdf/i) {
442 return $self->convert_to_pdf();
448 sub convert_to_postscript {
450 my ($form, $userspath) = ($self->{"form"}, $self->{"userspath"});
452 # Convert the tex file to postscript
454 if (!chdir("$userspath")) {
455 $self->{"error"} = "chdir : $!";
460 $form->{tmpfile} =~ s/$userspath\///g;
462 for (my $run = 1; $run <= 2; $run++) {
463 system("latex --interaction=nonstopmode $form->{tmpfile} " .
464 "> $form->{tmpfile}.err");
466 $self->{"error"} = $form->cleanup();
472 $form->{tmpfile} =~ s/tex$/dvi/;
474 system("dvips $form->{tmpfile} -o -q > /dev/null");
476 $self->{"error"} = "dvips : $!";
480 $form->{tmpfile} =~ s/dvi$/ps/;
489 my ($form, $userspath) = ($self->{"form"}, $self->{"userspath"});
491 # Convert the tex file to PDF
493 if (!chdir("$userspath")) {
494 $self->{"error"} = "chdir : $!";
499 $form->{tmpfile} =~ s/$userspath\///g;
501 for (my $run = 1; $run <= 2; $run++) {
502 system("pdflatex --interaction=nonstopmode $form->{tmpfile} " .
503 "> $form->{tmpfile}.err");
505 $self->{"error"} = $form->cleanup();
511 $form->{tmpfile} =~ s/tex$/pdf/;
516 sub get_mime_type() {
519 if ($self->{"form"}->{"format"} =~ /postscript/i) {
520 return "application/postscript";
522 return "application/pdf";
535 package HTMLTemplate;
539 @ISA = qw(LaTeXTemplate);
544 return $type->SUPER::new(@_);
548 my ($self, $variable) = @_;
549 my $form = $self->{"form"};
552 ('order' => ['<', '>', quotemeta("\n")],
555 quotemeta("\n") => '<br>',
558 map({ $variable =~ s/$_/$replace{$_}/g; } @{ $replace{"order"} });
560 # Allow some HTML markup to be converted into the output format's
561 # corresponding markup code, e.g. bold or italic.
562 my @markup_replace = ('b', 'i', 's', 'u', 'sub', 'sup');
564 foreach my $key (@markup_replace) {
565 $variable =~ s/\<(\/?)${key}\>/<$1${key}>/g;
571 sub get_mime_type() {
574 if ($self->{"form"}->{"format"} =~ /postscript/i) {
575 return "application/postscript";
576 } elsif ($self->{"form"}->{"format"} =~ /pdf/i) {
577 return "application/pdf";
586 if ($self->{"form"}->{"format"} =~ /postscript/i) {
588 } elsif ($self->{"form"}->{"format"} =~ /pdf/i) {
595 sub convert_to_postscript {
597 my ($form, $userspath) = ($self->{"form"}, $self->{"userspath"});
599 # Convert the HTML file to postscript
601 if (!chdir("$userspath")) {
602 $self->{"error"} = "chdir : $!";
607 $form->{"tmpfile"} =~ s/$userspath\///g;
608 my $psfile = $form->{"tmpfile"};
609 $psfile =~ s/.html/.ps/;
610 if ($psfile eq $form->{"tmpfile"}) {
614 system("html2ps -f html2ps-config < $form->{tmpfile} > $psfile");
616 $self->{"error"} = $form->cleanup();
621 $form->{"tmpfile"} = $psfile;
630 my ($form, $userspath) = ($self->{"form"}, $self->{"userspath"});
632 # Convert the HTML file to PDF
634 if (!chdir("$userspath")) {
635 $self->{"error"} = "chdir : $!";
640 $form->{"tmpfile"} =~ s/$userspath\///g;
641 my $pdffile = $form->{"tmpfile"};
642 $pdffile =~ s/.html/.pdf/;
643 if ($pdffile eq $form->{"tmpfile"}) {
647 system("html2ps -f html2ps-config < $form->{tmpfile} | ps2pdf - $pdffile");
649 $self->{"error"} = $form->cleanup();
654 $form->{"tmpfile"} = $pdffile;
663 #### PlainTextTemplate
666 package PlainTextTemplate;
670 @ISA = qw(LaTeXTemplate);
675 return $type->SUPER::new(@_);
679 my ($self, $variable) = @_;
694 #### OpenDocumentTemplate
697 package OpenDocumentTemplate;
705 # use File::Temp qw(:mktemp);
708 @ISA = qw(SimpleTemplate);
713 $self = $type->SUPER::new(@_);
715 foreach my $module (qw(Archive::Zip Text::Iconv)) {
716 eval("use ${module};");
718 $self->{"form"}->error("The Perl module '${module}' could not be " .
719 "loaded. Support for OpenDocument templates " .
720 "does not work without it. Please install your " .
721 "distribution's package or get the module from " .
722 "CPAN ( http://www.cpan.org ).");
726 $self->{"rnd"} = int(rand(1000000));
727 $self->{"iconv"} = Text::Iconv->new($main::dbcharset, "UTF-8");
732 sub substitute_vars {
733 my ($self, $text, @indices) = @_;
735 my $form = $self->{"form"};
737 while ($text =~ /\<\%(.*?)\%\>/) {
738 my $value = $form->{$1};
740 for (my $i = 0; $i < scalar(@indices); $i++) {
741 last unless (ref($value) eq "ARRAY");
742 $value = $value->[$indices[$i]];
744 substr($text, $-[0], $+[0] - $-[0]) = $self->format_string($value);
751 my ($self, $var, $text, $start_tag, $end_tag, @indices) = @_;
753 my ($form, $new_contents) = ($self->{"form"}, "");
755 my $ary = $form->{$var};
756 for (my $i = 0; $i < scalar(@indices); $i++) {
757 last unless (ref($ary) eq "ARRAY");
758 $ary = $ary->[$indices[$i]];
761 for (my $i = 0; $i < scalar(@{$ary}); $i++) {
762 $form->{"__first__"} = $i == 0;
763 $form->{"__last__"} = ($i + 1) == scalar(@{$ary});
764 $form->{"__odd__"} = (($i + 1) % 2) == 1;
765 $form->{"__counter__"} = $i + 1;
766 my $new_text = $self->parse_block($text, (@indices, $i));
767 return undef unless (defined($new_text));
768 $new_contents .= $start_tag . $new_text . $end_tag;
770 map({ delete($form->{"__${_}__"}); } qw(first last odd counter));
772 return $new_contents;
776 my ($self, $text, $pos, $var, $not) = @_;
779 $pos = 0 unless ($pos);
781 while ($pos < length($text)) {
784 next if (substr($text, $pos - 1, 5) ne '<%');
786 if ((substr($text, $pos + 4, 2) eq 'if') || (substr($text, $pos + 4, 3) eq 'for')) {
789 } elsif ((substr($text, $pos + 4, 4) eq 'else') && (1 == $depth)) {
791 $self->{"error"} = '<%else%> outside of <%if%> / <%ifnot%>.';
795 my $block = substr($text, 0, $pos - 1);
796 substr($text, 0, $pos - 1) = "";
797 $text =~ s!^\<\%[^\%]+\%\>!!;
798 $text = '<%if' . ($not ? " " : "not ") . $var . '%>' . $text;
800 return ($block, $text);
802 } elsif (substr($text, $pos + 4, 3) eq 'end') {
805 my $block = substr($text, 0, $pos - 1);
806 substr($text, 0, $pos - 1) = "";
807 $text =~ s!^\<\%[^\%]+\%\>!!;
809 return ($block, $text);
818 $main::lxdebug->enter_sub();
820 my ($self, $contents, @indices) = @_;
822 my $new_contents = "";
824 while ($contents ne "") {
825 if (substr($contents, 0, 1) eq "<") {
826 $contents =~ m|^<[^>]+>|;
828 substr($contents, 0, length($&)) = "";
830 if ($tag =~ m|<table:table-row|) {
831 $contents =~ m|^(.*?)(</table:table-row[^>]*>)|;
834 substr($contents, 0, length($1) + length($end_tag)) = "";
836 if ($table_row =~ m|\<\%foreachrow\s+(.*?)\%\>|) {
839 substr($table_row, length($`), length($&)) = "";
841 my ($t1, $t2) = $self->find_end($table_row, length($`));
843 $self->{"error"} = "Unclosed <\%foreachrow\%>." unless ($self->{"error"});
844 $main::lxdebug->leave_sub();
848 my $new_text = $self->parse_foreach($var, $t1 . $t2, $tag, $end_tag, @indices);
849 if (!defined($new_text)) {
850 $main::lxdebug->leave_sub();
853 $new_contents .= $new_text;
856 my $new_text = $self->parse_block($table_row, @indices);
857 if (!defined($new_text)) {
858 $main::lxdebug->leave_sub();
861 $new_contents .= $tag . $new_text . $end_tag;
865 $new_contents .= $tag;
869 $contents =~ /^[^<]+/;
872 my $pos_if = index($text, '<%if');
873 my $pos_foreach = index($text, '<%foreach');
875 if ((-1 == $pos_if) && (-1 == $pos_foreach)) {
876 substr($contents, 0, length($text)) = "";
877 $new_contents .= $self->substitute_vars($text, @indices);
881 if ((-1 == $pos_if) || ((-1 != $pos_foreach) && ($pos_if > $pos_foreach))) {
882 $new_contents .= $self->substitute_vars(substr($contents, 0, $pos_foreach), @indices);
883 substr($contents, 0, $pos_foreach) = "";
885 if ($contents !~ m|^\<\%foreach (.*?)\%\>|) {
886 $self->{"error"} = "Malformed <\%foreach\%>.";
887 $main::lxdebug->leave_sub();
893 substr($contents, 0, length($&)) = "";
896 ($block, $contents) = $self->find_end($contents);
898 $self->{"error"} = "Unclosed <\%foreach\%>." unless ($self->{"error"});
899 $main::lxdebug->leave_sub();
903 my $new_text = $self->parse_foreach($var, $block, "", "", @indices);
904 if (!defined($new_text)) {
905 $main::lxdebug->leave_sub();
908 $new_contents .= $new_text;
911 $new_contents .= $self->substitute_vars(substr($contents, 0, $pos_if), @indices);
912 substr($contents, 0, $pos_if) = "";
914 if ($contents !~ m|^\<\%if\s*(not)?\s+(.*?)\%\>|) {
915 $self->{"error"} = "Malformed <\%if\%>.";
916 $main::lxdebug->leave_sub();
920 my ($not, $var) = ($1, $2);
922 substr($contents, 0, length($&)) = "";
924 ($block, $contents) = $self->find_end($contents, 0, $var, $not);
926 $self->{"error"} = "Unclosed <\%if${not}\%>." unless ($self->{"error"});
927 $main::lxdebug->leave_sub();
931 my $value = $self->{"form"}->{$var};
932 for (my $i = 0; $i < scalar(@indices); $i++) {
933 last unless (ref($value) eq "ARRAY");
934 $value = $value->[$indices[$i]];
937 if (($not && !$value) || (!$not && $value)) {
938 my $new_text = $self->parse_block($block, @indices);
939 if (!defined($new_text)) {
940 $main::lxdebug->leave_sub();
943 $new_contents .= $new_text;
949 $main::lxdebug->leave_sub();
951 return $new_contents;
955 $main::lxdebug->enter_sub();
959 my $form = $self->{"form"};
964 if ($form->{"IN"} =~ m|^/|) {
965 $file_name = $form->{"IN"};
967 $file_name = $form->{"templates"} . "/" . $form->{"IN"};
970 my $zip = Archive::Zip->new();
971 if (Archive::Zip::AZ_OK != $zip->read($file_name)) {
972 $self->{"error"} = "File not found/is not a OpenDocument file.";
973 $main::lxdebug->leave_sub();
977 my $contents = $zip->contents("content.xml");
979 $self->{"error"} = "File is not a OpenDocument file.";
980 $main::lxdebug->leave_sub();
984 my $rnd = $self->{"rnd"};
985 my $new_styles = qq|<style:style style:name="TLXO${rnd}BOLD" style:family="text">
986 <style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"/>
988 <style:style style:name="TLXO${rnd}ITALIC" style:family="text">
989 <style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic"/>
991 <style:style style:name="TLXO${rnd}UNDERLINE" style:family="text">
992 <style:text-properties style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color"/>
994 <style:style style:name="TLXO${rnd}STRIKETHROUGH" style:family="text">
995 <style:text-properties style:text-line-through-style="solid"/>
997 <style:style style:name="TLXO${rnd}SUPER" style:family="text">
998 <style:text-properties style:text-position="super 58%"/>
1000 <style:style style:name="TLXO${rnd}SUB" style:family="text">
1001 <style:text-properties style:text-position="sub 58%"/>
1005 $contents =~ s|</office:automatic-styles>|${new_styles}</office:automatic-styles>|;
1006 $contents =~ s|[\n\r]||gm;
1008 my $new_contents = $self->parse_block($contents);
1009 if (!defined($new_contents)) {
1010 $main::lxdebug->leave_sub();
1014 # $new_contents =~ s|>|>\n|g;
1016 $zip->contents("content.xml", $new_contents);
1018 my $styles = $zip->contents("styles.xml");
1020 my $new_styles = $self->parse_block($styles);
1021 if (!defined($new_contents)) {
1022 $main::lxdebug->leave_sub();
1025 $zip->contents("styles.xml", $new_styles);
1028 $zip->writeToFileNamed($form->{"tmpfile"}, 1);
1031 if ($form->{"format"} =~ /pdf/) {
1032 $res = $self->convert_to_pdf();
1035 $main::lxdebug->leave_sub();
1039 sub is_xvfb_running {
1040 $main::lxdebug->enter_sub();
1045 my $dfname = $self->{"userspath"} . "/xvfb_display";
1048 $main::lxdebug->message(LXDebug::DEBUG2, " Looking for $dfname\n");
1049 if ((-f $dfname) && open(IN, $dfname)) {
1054 my $xauthority = <IN>;
1058 $main::lxdebug->message(LXDebug::DEBUG2, " found with $pid and $display\n");
1060 if ((! -d "/proc/$pid") || !open(IN, "/proc/$pid/cmdline")) {
1061 $main::lxdebug->message(LXDebug::DEBUG2, " no/wrong process #1\n");
1062 unlink($dfname, $xauthority);
1063 $main::lxdebug->leave_sub();
1068 if ($line !~ /xvfb/i) {
1069 $main::lxdebug->message(LXDebug::DEBUG2, " no/wrong process #2\n");
1070 unlink($dfname, $xauthority);
1071 $main::lxdebug->leave_sub();
1075 $ENV{"XAUTHORITY"} = $xauthority;
1076 $ENV{"DISPLAY"} = $display;
1078 $main::lxdebug->message(LXDebug::DEBUG2, " not found\n");
1081 $main::lxdebug->leave_sub();
1087 $main::lxdebug->enter_sub();
1091 $main::lxdebug->message(LXDebug::DEBUG2, "spawn_xvfb()\n");
1093 my $display = $self->is_xvfb_running();
1096 $main::lxdebug->leave_sub();
1101 while ( -f "/tmp/.X${display}-lock") {
1104 $display = ":${display}";
1105 $main::lxdebug->message(LXDebug::DEBUG2, " display $display\n");
1107 my $mcookie = `mcookie`;
1108 die("Installation error: mcookie not found.") if ($? != 0);
1111 $main::lxdebug->message(LXDebug::DEBUG2, " mcookie $mcookie\n");
1113 my $xauthority = "/tmp/.Xauthority-" . $$ . "-" . time() . "-" . int(rand(9999999));
1114 $ENV{"XAUTHORITY"} = $xauthority;
1116 $main::lxdebug->message(LXDebug::DEBUG2, " xauthority $xauthority\n");
1118 system("xauth add \"${display}\" . \"${mcookie}\"");
1120 $self->{"error"} = "Conversion to PDF failed because OpenOffice could not be started (xauth: $!)";
1121 $main::lxdebug->leave_sub();
1125 $main::lxdebug->message(LXDebug::DEBUG2, " about to fork()\n");
1129 $main::lxdebug->message(LXDebug::DEBUG2, " Child execing\n");
1130 exec($main::xvfb_bin, $display, "-screen", "0", "640x480x8", "-nolisten", "tcp");
1133 $main::lxdebug->message(LXDebug::DEBUG2, " parent dont sleeping\n");
1136 my $dfname = $self->{"userspath"} . "/xvfb_display";
1137 if (!open(OUT, ">$dfname")) {
1138 $self->{"error"} = "Conversion to PDF failed because OpenOffice could not be started ($dfname: $!)";
1139 unlink($xauthority);
1141 $main::lxdebug->leave_sub();
1144 print(OUT "$pid\n$display\n$xauthority\n");
1147 $main::lxdebug->message(LXDebug::DEBUG2, " parent re-testing\n");
1149 if (!$self->is_xvfb_running()) {
1150 $self->{"error"} = "Conversion to PDF failed because OpenOffice could not be started.";
1151 unlink($xauthority, $dfname);
1153 $main::lxdebug->leave_sub();
1157 $main::lxdebug->message(LXDebug::DEBUG2, " spawn OK\n");
1159 $main::lxdebug->leave_sub();
1164 sub is_openoffice_running {
1165 $main::lxdebug->enter_sub();
1167 system("./scripts/oo-uno-test-conn.py $main::openofficeorg_daemon_port " .
1168 "> /dev/null 2> /dev/null");
1170 $main::lxdebug->message(LXDebug::DEBUG2, " is_openoffice_running(): $?\n");
1172 $main::lxdebug->leave_sub();
1177 sub spawn_openoffice {
1178 $main::lxdebug->enter_sub();
1182 $main::lxdebug->message(LXDebug::DEBUG2, "spawn_openoffice()\n");
1184 my ($try, $spawned_oo, $res);
1187 for ($try = 0; $try < 15; $try++) {
1188 if ($self->is_openoffice_running()) {
1196 $main::lxdebug->message(LXDebug::DEBUG2, " Child daemonizing\n");
1198 open(STDIN, '/dev/null');
1199 open(STDOUT, '>/dev/null');
1200 my $new_pid = fork();
1202 my $ssres = setsid();
1203 $main::lxdebug->message(LXDebug::DEBUG2, " Child execing\n");
1204 my @cmdline = ($main::openofficeorg_writer_bin,
1205 "-minimized", "-norestore", "-nologo", "-nolockcheck",
1207 "-accept=socket,host=localhost,port=" .
1208 $main::openofficeorg_daemon_port . ";urp;");
1212 $main::lxdebug->message(LXDebug::DEBUG2, " Parent after fork\n");
1217 sleep($try >= 5 ? 2 : 1);
1221 $self->{"error"} = "Conversion from OpenDocument to PDF failed because " .
1222 "OpenOffice could not be started.";
1225 $main::lxdebug->leave_sub();
1230 sub convert_to_pdf {
1231 $main::lxdebug->enter_sub();
1235 my $form = $self->{"form"};
1237 my $filename = $form->{"tmpfile"};
1238 $filename =~ s/.odt$//;
1239 if (substr($filename, 0, 1) ne "/") {
1240 $filename = getcwd() . "/${filename}";
1243 if (substr($self->{"userspath"}, 0, 1) eq "/") {
1244 $ENV{'HOME'} = $self->{"userspath"};
1246 $ENV{'HOME'} = getcwd() . "/" . $self->{"userspath"};
1249 if (!$self->spawn_xvfb()) {
1250 $main::lxdebug->leave_sub();
1255 if (!$main::openofficeorg_daemon) {
1256 @cmdline = ($main::openofficeorg_writer_bin,
1257 "-minimized", "-norestore", "-nologo", "-nolockcheck",
1259 "file:${filename}.odt",
1260 "macro://" . (split('/', $filename))[-1] .
1261 "/Standard.Conversion.ConvertSelfToPDF()");
1263 if (!$self->spawn_openoffice()) {
1264 $main::lxdebug->leave_sub();
1268 @cmdline = ("./scripts/oo-uno-convert-pdf.py",
1269 $main::openofficeorg_daemon_port,
1277 $form->{"tmpfile"} =~ s/odt$/pdf/;
1279 unlink($filename . ".odt");
1281 $main::lxdebug->leave_sub();
1286 unlink($filename . ".odt", $filename . ".pdf");
1287 $self->{"error"} = "Conversion from OpenDocument to PDF failed. " .
1290 $main::lxdebug->leave_sub();
1295 my ($self, $variable) = @_;
1296 my $form = $self->{"form"};
1297 my $iconv = $self->{"iconv"};
1300 ('order' => ['&', '<', '>', '"', "'",
1302 quotemeta("\n"), quotemeta("\r")],
1308 '\x80' => chr(0xa4), # Euro
1309 quotemeta("\n") => '<text:line-break/>',
1310 quotemeta("\r") => '',
1313 map({ $variable =~ s/$_/$replace{$_}/g; } @{ $replace{"order"} });
1315 # Allow some HTML markup to be converted into the output format's
1316 # corresponding markup code, e.g. bold or italic.
1317 my $rnd = $self->{"rnd"};
1318 my %markup_replace = ("b" => "BOLD", "i" => "ITALIC", "s" => "STRIKETHROUGH",
1319 "u" => "UNDERLINE", "sup" => "SUPER", "sub" => "SUB");
1321 foreach my $key (keys(%markup_replace)) {
1322 my $value = $markup_replace{$key};
1323 $variable =~ s|\<${key}\>|<text:span text:style-name=\"TLXO${rnd}${value}\">|gi;
1324 $variable =~ s|\</${key}\>|</text:span>|gi;
1327 return $iconv->convert($variable);
1330 sub get_mime_type() {
1331 if ($self->{"form"}->{"format"} =~ /pdf/) {
1332 return "application/pdf";
1334 return "application/vnd.oasis.opendocument.text";
1338 sub uses_temp_file {
1343 ##########################################################
1347 ##########################################################
1349 package XMLTemplate;
1353 @ISA = qw(HTMLTemplate);
1356 #evtl auskommentieren
1359 return $type->SUPER::new(@_);
1363 my ($self, $variable) = @_;
1364 my $form = $self->{"form"};
1367 ('order' => ['<', '>', quotemeta("\n")],
1370 quotemeta("\n") => '<br>',
1373 map({ $variable =~ s/$_/$replace{$_}/g; } @{ $replace{"order"} });
1375 # Allow no markup to be converted into the output format
1376 my @markup_replace = ('b', 'i', 's', 'u', 'sub', 'sup');
1378 foreach my $key (@markup_replace) {
1379 $variable =~ s/\<(\/?)${key}\>//g;
1385 sub get_mime_type() {
1388 if ($self->{"form"}->{"format"} =~ /elsterwinston/i) {
1389 return "application/xml ";
1390 } elsif ($self->{"form"}->{"format"} =~ /elstertaxbird/i) {
1391 return "application/x-taxbird";
1397 sub uses_temp_file {
1398 # tempfile needet for XML Output