02470684e723450c8a99629e99d12e2ff9f9f3dd
[BackupPC.git] / lib / BackupPC / CGI / View.pm
1 #============================================================= -*-perl-*-
2 #
3 # BackupPC::CGI::View package
4 #
5 # DESCRIPTION
6 #
7 #   This module implements the View action for the CGI interface.
8 #
9 # AUTHOR
10 #   Craig Barratt  <cbarratt@users.sourceforge.net>
11 #
12 # COPYRIGHT
13 #   Copyright (C) 2003-2007  Craig Barratt
14 #
15 #   This program is free software; you can redistribute it and/or modify
16 #   it under the terms of the GNU General Public License as published by
17 #   the Free Software Foundation; either version 2 of the License, or
18 #   (at your option) any later version.
19 #
20 #   This program is distributed in the hope that it will be useful,
21 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
22 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 #   GNU General Public License for more details.
24 #
25 #   You should have received a copy of the GNU General Public License
26 #   along with this program; if not, write to the Free Software
27 #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28 #
29 #========================================================================
30 #
31 # Version 3.1.0, released 25 Nov 2007.
32 #
33 # See http://backuppc.sourceforge.net.
34 #
35 #========================================================================
36
37 package BackupPC::CGI::View;
38
39 use strict;
40 use BackupPC::CGI::Lib qw(:all);
41 use BackupPC::FileZIO;
42
43 sub action
44 {
45     my $Privileged = CheckPermission($In{host});
46     my $compress = 0;
47     my $fh;
48     my $host = $In{host};
49     my $num  = $In{num};
50     my $type = $In{type};
51     my $linkHosts = 0;
52     my($file, $comment);
53     my $ext = $num ne "" ? ".$num" : "";
54
55     ErrorExit(eval("qq{$Lang->{Invalid_number__num}}"))
56                     if ( $num ne "" && $num !~ /^\d+$/ );
57     if ( $type eq "XferLOG" ) {
58         $file = "$TopDir/pc/$host/SmbLOG$ext";
59         $file = "$TopDir/pc/$host/XferLOG$ext" if ( !-f $file && !-f "$file.z");
60     } elsif ( $type eq "XferLOGbad" ) {
61         $file = "$TopDir/pc/$host/SmbLOG.bad";
62         $file = "$TopDir/pc/$host/XferLOG.bad" if ( !-f $file && !-f "$file.z");
63     } elsif ( $type eq "XferErrbad" ) {
64         $file = "$TopDir/pc/$host/SmbLOG.bad";
65         $file = "$TopDir/pc/$host/XferLOG.bad" if ( !-f $file && !-f "$file.z");
66         $comment = $Lang->{Extracting_only_Errors};
67     } elsif ( $type eq "XferErr" ) {
68         $file = "$TopDir/pc/$host/SmbLOG$ext";
69         $file = "$TopDir/pc/$host/XferLOG$ext" if ( !-f $file && !-f "$file.z");
70         $comment = $Lang->{Extracting_only_Errors};
71     } elsif ( $type eq "RestoreLOG" ) {
72         $file = "$TopDir/pc/$host/RestoreLOG$ext";
73     } elsif ( $type eq "RestoreErr" ) {
74         $file = "$TopDir/pc/$host/RestoreLOG$ext";
75         $comment = $Lang->{Extracting_only_Errors};
76     } elsif ( $type eq "ArchiveLOG" ) {
77         $file = "$TopDir/pc/$host/ArchiveLOG$ext";
78     } elsif ( $type eq "ArchiveErr" ) {
79         $file = "$TopDir/pc/$host/ArchiveLOG$ext";
80         $comment = $Lang->{Extracting_only_Errors};
81     } elsif ( $type eq "config" ) {
82         # Note: only works for Storage::Text
83         $file = $bpc->{storage}->ConfigPath($host);
84     } elsif ( $type eq "hosts" ) {
85         # Note: only works for Storage::Text
86         $file = $bpc->ConfDir() . "/hosts";
87         $linkHosts = 1;
88     } elsif ( $type eq "docs" ) {
89         $file = $bpc->InstallDir() . "/doc/BackupPC.html";
90     } elsif ( $host ne "" ) {
91         if ( !defined($In{num}) ) {
92             # get the latest LOG file
93             $file = ($bpc->sortedPCLogFiles($host))[0];
94             $file =~ s/\.z$//;
95         } else {
96             $file = "$TopDir/pc/$host/LOG$ext";
97         }
98         $linkHosts = 1;
99     } else {
100         $file = "$LogDir/LOG$ext";
101         $linkHosts = 1;
102     }
103     if ( $type ne "docs" && !$Privileged ) {
104         ErrorExit($Lang->{Only_privileged_users_can_view_log_or_config_files});
105     }
106     if ( !-f $file && -f "$file.z" ) {
107         $file .= ".z";
108         $compress = 1;
109     }
110     my($contentPre, $contentSub, $contentPost);
111     $contentPre .= eval("qq{$Lang->{Log_File__file__comment}}");
112     if ( $file ne ""
113             && defined($fh = BackupPC::FileZIO->open($file, 0, $compress)) ) {
114
115         $fh->utf8(1);
116         my $mtimeStr = $bpc->timeStamp((stat($file))[9], 1);
117
118         $contentPre .= eval("qq{$Lang->{Contents_of_log_file}}");
119
120         $contentPre .= "<pre>";
121         if ( $type eq "XferErr" || $type eq "XferErrbad"
122                                 || $type eq "RestoreErr"
123                                 || $type eq "ArchiveErr" ) {
124             $contentSub = sub {
125                 #
126                 # Because the content might be large, we use
127                 # a sub to return the data in 64K chunks.
128                 #
129                 my($skipped, $c, $s);
130                 while ( length($c) < 65536 ) {
131                     $s = $fh->readLine();
132                     if ( $s eq "" ) {
133                         $c .= eval("qq{$Lang->{skipped__skipped_lines}}")
134                                                         if ( $skipped );
135                         last;
136                     }
137                     $s =~ s/[\n\r]+//g;
138                     if ( $s =~ /smb: \\>/
139                             || $s =~ /^\s*(\d+) \(\s*\d+\.\d kb\/s\) (.*)$/
140                             || $s =~ /^tar: dumped \d+ files/
141                             || $s =~ /^\s*added interface/i
142                             || $s =~ /^\s*restore tar file /i
143                             || $s =~ /^\s*restore directory /i
144                             || $s =~ /^\s*tarmode is now/i
145                             || $s =~ /^\s*Total bytes written/i
146                             || $s =~ /^\s*Domain=/i
147                             || $s =~ /^\s*Getting files newer than/i
148                             || $s =~ /^\s*Output is \/dev\/null/
149                             || $s =~ /^\s*\([\d.,]* kb\/s\) \(average [\d\.]* kb\/s\)$/
150                             || $s =~ /^\s+directory \\/
151                             || $s =~ /^\s*Timezone is/
152                             || $s =~ /^\s*creating lame (up|low)case table/i
153                             || $s =~ /^\.\//
154                             || $s =~ /^  / ) {
155                         $skipped++;
156                         next;
157                     }
158                     $c .= eval("qq{$Lang->{skipped__skipped_lines}}")
159                                                          if ( $skipped );
160                     $skipped = 0;
161                     $c .= ${EscHTML($s)} . "\n";
162                 }
163                 return $c;
164             };
165         } elsif ( $linkHosts ) {
166             #
167             # Because the content might be large, we use
168             # a sub to return the data in 64K chunks.
169             #
170             $contentSub = sub {
171                 my($c, $s);
172                 while ( length($c) < 65536 ) {
173                     $s = $fh->readLine();
174                     last if ( $s eq "" );
175                     $s =~ s/[\n\r]+//g;
176                     $s = ${EscHTML($s)};
177                     $s =~ s/\b([\w-.]+)\b/defined($Hosts->{$1})
178                                             ? ${HostLink($1)} : $1/eg;
179                     $c .= $s . "\n";
180                 }
181                 return $c;
182             };
183         } elsif ( $type eq "config" ) {
184             #
185             # Because the content might be large, we use
186             # a sub to return the data in 64K chunks.
187             #
188             $contentSub = sub {
189                 my($c, $s);
190                 while ( length($c) < 65536 ) {
191                     $s = $fh->readLine();
192                     last if ( $s eq "" );
193                     $s =~ s/[\n\r]+//g;
194                     # remove any passwords and user names
195                     $s =~ s/(SmbSharePasswd.*=.*['"]).*(['"])/$1****$2/ig;
196                     $s =~ s/(SmbShareUserName.*=.*['"]).*(['"])/$1****$2/ig;
197                     $s =~ s/(RsyncdPasswd.*=.*['"]).*(['"])/$1****$2/ig;
198                     $s =~ s/(ServerMesgSecret.*=.*['"]).*(['"])/$1****$2/ig;
199                     $s = ${EscHTML($s)};
200                     $s =~ s[(\$Conf\{.*?\})][
201                         my $c = $1;
202                         my $s = lc($c);
203                         $s =~ s{(\W)}{_}g;
204                         "<a href=\"?action=view&type=docs#item_$s\"><tt>$c</tt></a>"
205                     ]eg;
206                     $c .= $s . "\n";
207                 }
208                 return $c;
209             };
210         } elsif ( $type eq "docs" ) {
211             #
212             # Because the content might be large, we use
213             # a sub to return the data in 64K chunks.
214             #
215             $contentSub = sub {
216                 my($c, $s);
217                 while ( length($c) < 65536 ) {
218                     $s = $fh->readLine();
219                     last if ( $s eq "" );
220                     $c .= $s;
221                 }
222                 return $c;
223             };
224             #
225             # Documentation has a different header and no pre or post text,
226             # so just handle it here
227             #
228             Header($Lang->{BackupPC__Documentation}, "", 0, $contentSub);
229             Trailer();
230             return;
231         } else {
232             #
233             # Because the content might be large, we use
234             # a sub to return the data in 64K chunks.
235             #
236             $contentSub = sub {
237                 my($c, $s);
238                 while ( length($c) < 65536 ) {
239                     $s = $fh->readLine();
240                     last if ( $s eq "" );
241                     $s =~ s/[\n\r]+//g;
242                     $s = ${EscHTML($s)};
243                     $c .= $s . "\n";
244                 }
245                 return $c;
246             };
247         }
248     } else {
249         if ( $type eq "docs" ) {
250             ErrorExit(eval("qq{$Lang->{Unable_to_open__file__configuration_problem}}"));
251         }
252         $contentPre .= eval("qq{$Lang->{_pre___Can_t_open_log_file__file}}");
253     }
254     $contentPost .= "</pre>\n" if ( $type ne "docs" );
255     Header(eval("qq{$Lang->{Backup_PC__Log_File__file}}"),
256                     $contentPre, !-f "$TopDir/pc/$host/backups",
257                     $contentSub, $contentPost);
258     Trailer();
259     $fh->close() if ( defined($fh) );
260 }
261
262 1;