/[BackupPC]/trunk/lib/BackupPC/SearchLib.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/lib/BackupPC/SearchLib.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 19 by dpavlin, Mon Jul 11 14:32:40 2005 UTC revision 259 by dpavlin, Mon Dec 12 20:59:58 2005 UTC
# Line 4  package BackupPC::SearchLib; Line 4  package BackupPC::SearchLib;
4  use strict;  use strict;
5  use BackupPC::CGI::Lib qw(:all);  use BackupPC::CGI::Lib qw(:all);
6  use BackupPC::Attrib qw(:all);  use BackupPC::Attrib qw(:all);
 use Data::Dumper;  
7  use DBI;  use DBI;
8    use DateTime;
9    use vars qw(%In $MyURL);
10    use Time::HiRes qw/time/;
11    use XML::Writer;
12    use IO::File;
13    
14    my $on_page = 100;
15    my $pager_pages = 10;
16    
17    my $dsn = $Conf{SearchDSN};
18    my $db_user = $Conf{SearchUser} || '';
19    
20    my $hest_index_path = $Conf{HyperEstraierIndex};
21    
22    my $dbh;
23    
24    sub get_dbh {
25            $dbh ||= DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );
26            return $dbh;
27    }
28    
29  sub getUnits() {  sub getUnits() {
30      my @ret = ();          my @ret;
31      my $tmp;  
32      my $dbh = DBI->connect( "dbi:SQLite:dbname=${TopDir}/$Conf{SearchDB}",          my $dbh = get_dbh();
33          "", "", { RaiseError => 1, AutoCommit => 1 } );          my $sth = $dbh->prepare(qq{
34      my $st =                  SELECT
35        $dbh->prepare(                          shares.id       as id,
36          " SELECT shares.ID AS ID, shares.share AS name FROM shares;");                          hosts.name || ':' || shares.name as share
37      $st->execute();                  FROM shares
38      push (@ret, { 'ID' => '', 'name' => '-'});                  JOIN hosts on hostid = hosts.id
39      while ( $tmp = $st->fetchrow_hashref() ) {                  ORDER BY share
40          push( @ret, { 'ID' => $tmp->{'ID'}, 'name' => $tmp->{'name'} } );          } );
41      }          $sth->execute();
42      $dbh->disconnect();          push @ret, { 'id' => '', 'share' => '-'};       # dummy any
43      return @ret;  
44            while ( my $row = $sth->fetchrow_hashref() ) {
45                    push @ret, $row;
46            }
47            return @ret;
48  }  }
49    
50  sub getWhere($) {  sub epoch_to_iso {
51          my ($param)    = @_;          my $t = shift || return;
52          my @conditions;          my $iso = BackupPC::Lib::timeStamp(undef, $t);
53            $iso =~ s/\s/ /g;
54            return $iso;
55    }
56    
57          sub mk_iso_date($$) {  sub dates_from_form($) {
58            my $param = shift || return;
59    
60            sub mk_epoch_date($$) {
61                  my ($name,$suffix) = @_;                  my ($name,$suffix) = @_;
62    
63                  my $yyyy = $param->{ $name . '_year_' . $suffix} || return;                  my $yyyy = $param->{ $name . '_year_' . $suffix} || return undef;
64                  my $mm .= $param->{ $name . '_month_' . $suffix} ||                  my $mm .= $param->{ $name . '_month_' . $suffix} ||
65                          ( $suffix eq 'from' ? 1 : 12);                          ( $suffix eq 'from' ? 1 : 12);
66                  my $dd .= $param->{ $name . '_day_' . $suffix} ||                  my $dd .= $param->{ $name . '_day_' . $suffix} ||
67                          ( $suffix eq 'from' ? 1 : 31);                          ( $suffix eq 'from' ? 1 : 31);
68                  return sprintf("%04d-%02d-%02d", $yyyy, $mm, $dd);  
69                    $yyyy =~ s/\D//g;
70                    $mm =~ s/\D//g;
71                    $dd =~ s/\D//g;
72    
73                    my $h = my $m = my $s = 0;
74                    if ($suffix eq 'to') {
75                            $h = 23;
76                            $m = 59;
77                            $s = 59;
78                    }
79    
80                    my $dt = new DateTime(
81                            year => $yyyy,
82                            month => $mm,
83                            day => $dd,
84                            hour => $h,
85                            minute => $m,
86                            second => $s,
87                    );
88                    print STDERR "mk_epoch_date($name,$suffix) [$yyyy-$mm-$dd] = " . $dt->ymd . " " . $dt->hms . "\n";
89                    return $dt->epoch || 'NULL';
90          }          }
91    
92          my $backup_from = mk_iso_date('search_backup', 'from');          my @ret = (
93          push @conditions, qq{ date(backups.date, 'unixepoch','localtime') >= '$backup_from' } if ($backup_from);                  mk_epoch_date('search_backup', 'from'),
94          my $backup_to = mk_iso_date('search_backup', 'to');                  mk_epoch_date('search_backup', 'to'),
95          push @conditions, qq{ date(backups.date, 'unixepoch','localtime') <= '$backup_to' } if ($backup_to);                  mk_epoch_date('search', 'from'),
96                    mk_epoch_date('search', 'to'),
97            );
98    
99          my $files_from = mk_iso_date('search', 'from');          return @ret;
         push @conditions, qq{ date(files.date, 'unixepoch','localtime') >= '$files_from' } if ($files_from);  
         my $files_to = mk_iso_date('search', 'to');  
         push @conditions, qq{ date(files.date, 'unixepoch','localtime') <= '$files_to' } if ($files_to);  
100    
101          print STDERR "backup: $backup_from - $backup_to files: $files_from - $files_to cond:",join(" | ",@conditions);  }
       
         push( @conditions, ' backups.hostID = ' . $param->{'search_host'} ) if ($param->{'search_host'});  
102    
         push (@conditions, " files.name LIKE '".$param->{'search_filename'}."%'") if ($param->{'search_filename'});  
103    
104          return (  sub getWhere($) {
105                  join(" and ", @conditions),          my $param = shift || return;
106                  $files_from, $files_to,  
107                  $backup_from, $backup_to          my ($backup_from, $backup_to, $files_from, $files_to) = dates_from_form($param);
108          );  
109            my @conditions;
110            push @conditions, qq{ backups.date >= $backup_from } if ($backup_from);
111            push @conditions, qq{ backups.date <= $backup_to } if ($backup_to);
112            push @conditions, qq{ files.date >= $files_from } if ($files_from);
113            push @conditions, qq{ files.date <= $files_to } if ($files_to);
114    
115            print STDERR "backup: $backup_from - $backup_to files: $files_from - $files_to cond:" . join(" and ",@conditions);
116    
117            push( @conditions, ' files.shareid = ' . $param->{'search_share'} ) if ($param->{'search_share'});
118            push (@conditions, " upper(files.path) LIKE upper('%".$param->{'search_filename'}."%')") if ($param->{'search_filename'});
119    
120            return join(" and ", @conditions);
121  }  }
122    
123    my $sort_def = {
124            search => {
125                    default => 'date_a',
126                    sql => {
127                            share_d => 'shares.name DESC',
128                            share_a => 'shares.name ASC',
129                            path_d => 'files.path DESC',
130                            path_a => 'files.path ASC',
131                            num_d => 'files.backupnum DESC',
132                            num_a => 'files.backupnum ASC',
133                            size_d => 'files.size DESC',
134                            size_a => 'files.size ASC',
135                            date_d => 'files.date DESC',
136                            date_a => 'files.date ASC',
137                    },
138                    est => {
139                            share_d => 'sname STRD',
140                            share_a => 'sname STRA',
141                            path_d => 'filepath STRD',
142                            path_a => 'filepath STRA',
143                            num_d => 'backupnum NUMD',
144                            num_a => 'backupnum NUMA',
145                            size_d => 'size NUMD',
146                            size_a => 'size NUMA',
147                            date_d => 'date NUMD',
148                            date_a => 'date NUMA',
149                    }
150            }, burn => {
151                    default => 'date_a',
152                    sql => {
153                            share_d => 'host DESC, share DESC',
154                            share_a => 'host ASC, share ASC',
155                            num_d => 'backupnum DESC',
156                            num_a => 'backupnum ASC',
157                            date_d => 'date DESC',
158                            date_a => 'date ASC',
159                            age_d => 'age DESC',
160                            age_a => 'age ASC',
161                            size_d => 'size DESC',
162                            size_a => 'size ASC',
163                            incsize_d => 'inc_size DESC',
164                            incsize_a => 'inc_size ASC',
165                    }
166            }
167    };
168    
169  sub getFiles($$)  sub getSort($$$) {
170    {          my ($part,$type, $sort_order) = @_;
171        my ($where, $offset) = @_;  
172                  die "unknown part: $part" unless ($sort_def->{$part});
173                  die "unknown type: $type" unless ($sort_def->{$part}->{$type});
174        my $dbh = DBI->connect( "dbi:SQLite:dbname=${TopDir}/$Conf{SearchDB}",  
175          "", "", { RaiseError => 1, AutoCommit => 1 } );          $sort_order ||= $sort_def->{$part}->{'default'};
176        my $sql =            
177          q{            if (my $ret = $sort_def->{$part}->{$type}->{$sort_order}) {
178                  SELECT  files.id                        AS fid,                  return $ret;
179                          hosts.name                      AS hname,          } else {
180                          shares.name                     AS sname,                  # fallback to default sort order
181                          shares.share                    AS sharename,                  return $sort_def->{$part}->{$type}->{ $sort_def->{$part}->{'default'} };
182                          files.backupNum                 AS backupNum,          }
183                          files.name                      AS filename,  }
184                          files.path                      AS filepath,  
185                          shares.share||files.fullpath    AS networkPath,  sub getFiles($) {
186                          date(files.date, 'unixepoch', 'localtime') AS date,          my ($param) = @_;
187                          files.type                      AS filetype,  
188                          files.size                      AS size,          my $offset = $param->{'offset'} || 0;
189                          dvds.name                       AS dvd          $offset *= $on_page;
190    
191            my $dbh = get_dbh();
192    
193            my $sql_cols = qq{
194                    files.id                        AS fid,
195                    hosts.name                      AS hname,
196                    shares.name                     AS sname,
197                    files.backupnum                 AS backupnum,
198                    files.path                      AS filepath,
199                    files.date                      AS date,
200                    files.type                      AS type,
201                    files.size                      AS size
202            };
203    
204            my $sql_from = qq{
205                  FROM files                  FROM files
206                          INNER JOIN shares       ON files.shareID=shares.ID                          INNER JOIN shares       ON files.shareID=shares.ID
207                          INNER JOIN hosts        ON hosts.ID = shares.hostID                          INNER JOIN hosts        ON hosts.ID = shares.hostID
208                          INNER JOIN backups      ON backups.num = files.backupNum                          INNER JOIN backups      ON backups.num = files.backupnum and backups.hostID = hosts.ID AND backups.shareID = files.shareID
209                          LEFT  JOIN dvds         ON dvds.ID = files.dvdid          };
           };  
   
       if (defined($where) && $where ne "")  
         {  
             $sql .= " WHERE ". $where;        
         }  
210    
211        $sql .=          my $sql_where;
212          q{                    my $where = getWhere($param);
213              ORDER BY files.id          $sql_where = " WHERE ". $where if ($where);
214                LIMIT 100  
215                OFFSET ? * 100 + 1          my $order = getSort('search', 'sql', $param->{'sort'});
216    
217            my $sql_order = qq{
218                    ORDER BY $order
219                    LIMIT $on_page
220                    OFFSET ?
221          };          };
222          
223                  my $sql_count = qq{ select count(files.id) $sql_from $sql_where };
224                  my $sql_results = qq{ select $sql_cols $sql_from $sql_where $sql_order };
225        my $st = $dbh->prepare(  
226            $sql          my $sth = $dbh->prepare($sql_count);
227            );              $sth->execute();
228        if (!defined($offset) && $offset ne "")          my ($results) = $sth->fetchrow_array();
229        {  
230          $st->bind_param(1, $offset);          $sth = $dbh->prepare($sql_results);
231        }          $sth->execute( $offset );
232        else  
233        {          if ($sth->rows != $results) {
234          $st->bind_param(1,0);                  my $bug = "$0 BUG: [[ $sql_count ]] = $results while [[ $sql_results ]] = " . $sth->rows;
235        }                  $bug =~ s/\s+/ /gs;
236        $st->execute;                  print STDERR "$bug\n";
         
       my @ret = ();  
       my $tmp;  
         
       while ($tmp = $st->fetchrow_hashref())  
         {  
             push(@ret, {  
                            'hname'       => $tmp->{'hname'},  
                            'sname'       => $tmp->{'sname'},  
                            'sharename'   => $tmp->{'sharename'},  
                            'backupno'    => $tmp->{'backupNum'},  
                            'fname'       => $tmp->{'filename'},  
                            'fpath'       => $tmp->{'filepath'},  
                            'networkpath' => $tmp->{'networkPath'},  
                            'date'        => $tmp->{'date'},  
                            'type'        => $tmp->{'filetype'},  
                            'size'        => $tmp->{'size'},  
                            'id'          => $tmp->{'fid'},  
                            'dvd'         => $tmp->{'dvd'}  
                        }  
             );  
                                   
237          }          }
238    
239            my @ret;
240                
241        $st->finish();          while (my $row = $sth->fetchrow_hashref()) {
242        $dbh->disconnect();                  push @ret, $row;
243        return @ret;          }
244    }      
245            $sth->finish();
246  sub getBackupsNotBurned()          return ($results, \@ret);
247    {  }
248        my $dbh = DBI->connect( "dbi:SQLite:dbname=${TopDir}/$Conf{SearchDB}",  
249          "", "", { RaiseError => 1, AutoCommit => 1 } );        sub getHyperEstraier_url($) {
250        my $sql = q{          my ($use_hest) = @_;
251            SELECT  
252              hosts.ID         AS hostID,          return unless $use_hest;
253              hosts.name       AS host,  
254              backups.num      AS backupno,          use HyperEstraier;
255              backups.type     AS type,          my ($index_path, $index_node_url);
256              backups.date     AS date  
257            FROM backups, shares, files, hosts          if ($use_hest =~ m#^http://#) {
258            WHERE                  $index_node_url = $use_hest;
259              backups.num    = files.backupNum  AND          } else {
260              shares.ID      = files.shareID    AND                            $index_path = $TopDir . '/' . $use_hest;
261              backups.hostID = shares.hostID    AND                  $index_path =~ s#//#/#g;
262              hosts.ID       = backups.hostID   AND          }
263              files.dvdid    IS NULL          return ($index_path, $index_node_url);
264            GROUP BY  }
265              backups.hostID, backups.num  
266        };  sub getFilesHyperEstraier($) {
267        my $st = $dbh -> prepare( $sql );          my ($param) = @_;
268        my @ret = ();  
269        $st -> execute();          my $offset = $param->{'offset'} || 0;
270            $offset *= $on_page;
271        while ( my $tmp = $st -> fetchrow_hashref() )  
272          {                    die "no index_path?" unless ($hest_index_path);
273              push(@ret, {  
274                           'host'     => $tmp->{'host'},          use HyperEstraier;
275                           'hostid'   => $tmp->{'hostID'},  
276                           'backupno' => $tmp->{'backupno'},          my ($index_path, $index_node_url) = getHyperEstraier_url($hest_index_path);
277                           'type'     => $tmp->{'type'},  
278                           'date'     => $tmp->{'date'}          # open the database
279                         }          my $db;
280              );          if ($index_path) {
281                    $db = HyperEstraier::Database->new();
282                    $db->open($index_path, $HyperEstraier::ESTDBREADER);
283            } elsif ($index_node_url) {
284                    $db ||= HyperEstraier::Node->new($index_node_url);
285                    $db->set_auth('admin', 'admin');
286            } else {
287                    die "BUG: unimplemented";
288            }
289    
290            # create a search condition object
291            my $cond = HyperEstraier::Condition->new();
292    
293            my $q = $param->{'search_filename'};
294            my $shareid = $param->{'search_share'};
295    
296            if (length($q) > 0) {
297                    # exact match
298                    $cond->add_attr("filepath ISTRINC $q");
299    
300                    $q =~ s/(.)/$1 /g;
301                    # set the search phrase to the search condition object
302                    $cond->set_phrase($q);
303          }          }
         
       return @ret;        
   }  
304    
305  sub displayBackupsGrid()          my ($backup_from, $backup_to, $files_from, $files_to) = dates_from_form($param);
306    {  
307        my $retHTML = "";          $cond->add_attr("backup_date NUMGE $backup_from") if ($backup_from);
308        my $addForm = 1;          $cond->add_attr("backup_date NUMLE $backup_to") if ($backup_to);
309    
310            $cond->add_attr("date NUMGE $files_from") if ($files_from);
311            $cond->add_attr("date NUMLE $files_to") if ($files_to);
312    
313            $cond->add_attr("shareid NUMEQ $shareid") if ($shareid);
314    
315    #       $cond->set_max( $offset + $on_page );
316            $cond->set_options( $HyperEstraier::Condition::SURE );
317            $cond->set_order( getSort('search', 'est', $param->{'sort'} ) );
318    
319            # get the result of search
320            my @res;
321            my ($result, $hits);
322    
323            if ($index_path) {
324                    $result = $db->search($cond, 0);
325                    $hits = $result->size;
326            } elsif ($index_node_url) {
327                    $result = $db->search($cond, 0);
328                    $hits = $result->doc_num;
329            } else {
330                    die "BUG: unimplemented";
331            }
332    
333            # for each document in result
334            for my $i ($offset .. ($offset + $on_page - 1)) {
335                    last if ($i >= $hits);
336    
337                    my $doc;
338                    if ($index_path) {
339                            my $id = $result->get($i);
340                            $doc = $db->get_doc($id, 0);
341                    } elsif ($index_node_url) {
342                            $doc = $result->get_doc($i);
343                    } else {
344                            die "BUG: unimplemented";
345                    }
346    
347                    my $row;
348                    foreach my $c (qw/fid hname sname backupnum filepath date type size/) {
349                            $row->{$c} = $doc->attr($c);
350                    }
351                    push @res, $row;
352            }
353    
354            return ($hits, \@res);
355    }
356    
357    sub getGzipName($$$)
358    {
359            my ($host, $share, $backupnum) = @_;
360            my $ret = $Conf{GzipSchema};
361            
362            $share =~ s/\//_/g;
363            $ret =~ s/\\h/$host/ge;
364            $ret =~ s/\\s/$share/ge;
365            $ret =~ s/\\n/$backupnum/ge;
366    
367            $ret =~ s/__+/_/g;
368    
369            return $ret;
370            
371    }
372    
373    sub get_tgz_size_by_name($) {
374            my $name = shift;
375    
376            my $tgz = $Conf{InstallDir}.'/'.$Conf{GzipTempDir}.'/'.$name;
377    
378            my $size = -1;
379    
380            if (-f "${tgz}.tar.gz") {
381                    $size = (stat("${tgz}.tar.gz"))[7];
382            } elsif (-d $tgz) {
383                    opendir(my $dir, $tgz) || die "can't opendir $tgz: $!";
384                    my @parts = grep { !/^\./ && !/md5/ && -f "$tgz/$_" } readdir($dir);
385                    $size = 0;
386                    foreach my $part (@parts) {
387                            $size += (stat("$tgz/$part"))[7] || die "can't stat $tgz/$part: $!";
388                    }
389                    closedir $dir;
390            } else {
391                    return -1;
392            }
393    
394            return $size;
395    }
396    
397    sub getGzipSize($$)
398    {
399            my ($hostID, $backupNum) = @_;
400            my $sql;
401            my $dbh = get_dbh();
402            
403            $sql = q{
404                                    SELECT hosts.name  as host,
405                                               shares.name as share,
406                                               backups.num as backupnum
407                                    FROM hosts, backups, shares
408                                    WHERE shares.id=backups.shareid AND
409                                              hosts.id =backups.hostid AND
410                                              hosts.id=? AND
411                                              backups.num=?
412                            };
413            my $sth = $dbh->prepare($sql);
414            $sth->execute($hostID, $backupNum);
415    
416            my $row = $sth->fetchrow_hashref();
417    
418            return get_tgz_size_by_name(
419                    getGzipName($row->{'host'}, $row->{share}, $row->{'backupnum'})
420            );
421    }
422    
423    sub getVolumes($) {
424            my $id = shift;
425    
426            my $max_archive_size = $Conf{MaxArchiveSize} || die "no MaxArchiveSize";
427    
428            my $sth = $dbh->prepare(qq{
429                    select
430                            size
431                    from backup_parts
432                    where backup_id = ?
433                    order by part_nr asc
434            });
435    
436            $sth->execute($id);
437    
438            my $cumulative_size = 0;
439            my $volumes = 1;
440    
441            while(my ($size) = $sth->fetchrow_array) {
442                    if ($cumulative_size + $size > $max_archive_size) {
443                            $volumes++;
444                            $cumulative_size = $size;
445                    } else {
446                            $cumulative_size += $size;
447                    }
448            }
449    
450            return ($volumes,$cumulative_size);
451    }
452    
453    sub getBackupsNotBurned($) {
454    
455            my $param = shift;
456            my $dbh = get_dbh();
457    
458            my $order = getSort('burn', 'sql', $param->{'sort'});
459    
460    print STDERR "## sort=". ($param->{'sort'} || 'no sort param') . " burn sql order: $order\n";
461    
462            my $sql = qq{
463                    SELECT
464                            backups.hostID AS hostID,
465                            hosts.name AS host,
466                            shares.name AS share,
467                            backups.num AS backupnum,
468                            backups.type AS type,
469                            backups.date AS date,
470                            date_part('epoch',now()) - backups.date as age,
471                            backups.size AS size,
472                            backups.id AS id,
473                            backups.inc_size AS inc_size,
474                            backups.parts AS parts
475                    FROM backups
476                    INNER JOIN shares       ON backups.shareID=shares.ID
477                    INNER JOIN hosts        ON backups.hostID = hosts.ID
478                    LEFT OUTER JOIN archive_backup ON archive_backup.backup_id = backups.id
479                    WHERE backups.inc_size > 0 AND backups.inc_deleted is false AND archive_backup.backup_id IS NULL
480                    GROUP BY
481                            backups.hostID,
482                            hosts.name,
483                            shares.name,
484                            backups.num,
485                            backups.shareid,
486                            backups.id,
487                            backups.type,
488                            backups.date,
489                            backups.size,
490                            backups.inc_size,
491                            backups.parts
492                    ORDER BY $order
493            };
494            my $sth = $dbh->prepare( $sql );
495            my @ret;
496            $sth->execute();
497    
498            while ( my $row = $sth->fetchrow_hashref() ) {
499                    $row->{'age'} = sprintf("%0.1f", ( $row->{'age'} / 86400 ) );
500                    #$row->{'age'} = sprintf("%0.1f", ( (time() - $row->{'date'}) / 86400 ) );
501    
502                    my $max_archive_size = $Conf{MaxArchiveSize} || die "no MaxArchiveSize";
503                    if ($row->{size} > $max_archive_size) {
504                            ($row->{volumes}, $row->{inc_size_calc}) = getVolumes($row->{id});
505                    }
506    
507                    $row->{size} = sprintf("%0.2f", $row->{size} / 1024 / 1024);
508    
509                    # do some cluster calculation (approximate)
510                    $row->{inc_size} = int(($row->{inc_size} + 1023 ) / ( 2 * 1024 ) * 2);
511                    $row->{inc_size_calc} ||= $row->{inc_size};
512                    push @ret, $row;
513            }
514                
515        if ($addForm)          return @ret;
516          {  }
517    
518    sub displayBackupsGrid($) {
519    
520            my $param = shift;
521    
522              $retHTML .= <<EOF3;          my $max_archive_size = $Conf{MaxArchiveSize} || die "no MaxArchiveSize";
523  <script language="javascript" type="text/javascript">          my $max_archive_file_size = $Conf{MaxArchiveFileSize}  || die "no MaxFileInSize";
524    
525            my $retHTML .= q{
526                    <form id="forma" method="POST" action="}.$MyURL.q{?action=burn">
527            };
528    
529            $retHTML .= <<'EOF3';
530    <style type="text/css">
531  <!--  <!--
532    DIV#fixedBox {
533            position: absolute;
534            top: 50em;
535            left: -24%;
536            padding: 0.5em;
537            width: 20%;
538            background-color: #E0F0E0;
539            border: 1px solid #00C000;
540    }
541    
542      function checkAll(location)  DIV#fixedBox, DIV#fixedBox INPUT, DIV#fixedBox TEXTAREA {
543      {          font-size: 10pt;
544        for (var i=0;i<document.forma.elements.length;i++)  }
545        {  
546          var e = document.forma.elements[i];  FORM>DIV#fixedBox {
547          if ((e.checked || !e.checked) && e.name != \'all\') {          position: fixed !important;
548              if (eval("document.forma."+location+".checked")) {          left: 0.5em !important;
549                  e.checked = true;          top: auto !important;
550              } else {          bottom: 1em !important;
551                  e.checked = false;          width: 15% !important;
552              }  }
553          }  
554        }  DIV#fixedBox INPUT[type=text], DIV#fixedBox TEXTAREA {
555      }          border: 1px solid #00C000;
556  //-->  }
557  </script>        
558    DIV#fixedBox #note {
559            display: block;
560            width: 100%;
561    }
562    
563    DIV#fixedBox #submitBurner {
564            display: block;
565            width: 100%;
566            margin-top: 0.5em;
567            cursor: pointer;
568    }
569    
570    * HTML {
571            overflow-y: hidden;
572    }
573    
574    * HTML BODY {
575            overflow-y: auto;
576            height: 100%;
577            font-size: 100%;
578    }
579    
580    * HTML DIV#fixedBox {
581            position: absolute;
582    }
583    
584    #mContainer, #gradient, #mask, #progressIndicator {
585            display: block;
586            width: 100%;
587            font-size: 10pt;
588            font-weight: bold;
589            text-align: center;
590            vertical-align: middle;
591            padding: 1px;
592    }
593    
594    #gradient, #mask, #progressIndicator {
595            left: 0;
596            border-width: 1px;
597            border-style: solid;
598            border-color: #000000;
599            color: #404040;
600            margin: 0.4em;
601            position: absolute;
602            margin-left: -1px;
603            margin-top: -1px;
604            margin-bottom: -1px;
605            overflow: hidden;
606    }
607    
608    #mContainer {
609            display: block;
610            position: relative;
611            padding: 0px;
612            margin-top: 0.4em;
613            margin-bottom: 0.5em;
614    }
615    
616    #gradient {
617            z-index: 1;
618            background-color: #FFFF00;
619    }
620    
621    #mask {
622            z-index: 2;
623            background-color: #FFFFFF;
624    }
625    
626    #progressIndicator {
627            z-index: 3;
628            background-color: transparent;
629    }
630    
631    #volumes {
632            padding: 0.4em;
633            display: none;
634            width: 100%;
635            font-size: 80%;
636            color: #ff0000;
637            text-align: center;
638    }
639    -->
640    </style>
641    <script type="text/javascript">
642    <!--
643    
644    var debug_div = null;
645  EOF3  EOF3
646                $retHTML .= q{<form name="forma" method="POST" action="}."$MyURL"."?action=burn\"";  
647                $retHTML.= q{<input type="hidden" value="burn" name="action">};          # take maximum archive size from configuration
648                $retHTML .= q{<input type="hidden" value="results" name="search_results">};          $retHTML .= qq{
649          }  var media_size = $max_archive_size ;
650        $retHTML .= "<table style=\"fview\">";  var max_file_size = $max_archive_file_size;
651        $retHTML .= "<tr> ";  
652        if ($addForm)  };
653          {  
654              $retHTML .= "<td class=\"tableheader\"><input type=\"checkbox\" name=\"allFiles\" onClick=\"checkAll('allFiles');\"></td>";          $retHTML .= <<'EOF3';
655          }  
656        $retHTML .=  "<td class=\"tableheader\">Host</td> <td class=\"tableheader\">Backup no</td> <td class=\"tableheader\">Type</td> <td class=\"tableheader\">date</td></tr>";  function debug(msg) {
657        my @backups = getBackupsNotBurned();          return; // Disable debugging
658        my $backup;  
659            if (! debug_div) debug_div = document.getElementById('debug');
660        if ($addForm)  
661          {          // this will create debug div if it doesn't exist.
662              $retHTML .= "<tr>";          if (! debug_div) {
663              $retHTML .= "<td colspan=7 style=\"tableheader\">";                  debug_div = document.createElement('div');
664              $retHTML .= "<input type=\"submit\" value=\"Burn selected backups on medium\" name=\"submitBurner\">";                  if (document.body) document.body.appendChild(debug_div);
665              $retHTML .= "</td>";                  else debug_div = null;
666              $retHTML .= "</tr>";          }
667                        if (debug_div) {
668          }                  debug_div.appendChild(document.createTextNode(msg));
669        foreach $backup(@backups)                  debug_div.appendChild(document.createElement("br"));
670          {          }
671              my $ftype = "";  }
672                
673              $retHTML .= "<tr>";  
674              if ($addForm)  var element_id_cache = Array();
675                {  
676                    $retHTML .= "<td class=\"fview\"> <input type=\"checkbox\" name=\"fcb"  function element_id(name,element) {
677                      .$backup->{'hostid'}."_".$backup->{'backupno'}          if (! element_id_cache[name]) {
678                    ."\" value=\"".$backup->{'hostid'}."_".$backup->{'backupno'}."\"> </td>";                  element_id_cache[name] = self.document.getElementById(name);
679                }              }
680                        return element_id_cache[name];
681              $retHTML .= "<td class=\"fviewborder\">" . $backup->{'host'} . "</td>";  }
682              $retHTML .= "<td class=\"fviewborder\">" . $backup->{'backupno'} . "</td>";  
683              $retHTML .= "<td class=\"fviewborder\">" . $backup->{'type'} . "</td>";  function checkAll(location) {
684              $retHTML .= "<td class=\"fviewborder\">" . $backup->{'date'} . "<td>";          var f = element_id('forma') || null;
685              $retHTML .= "</tr>";          if (!f) return false;
686          }  
687        $retHTML .= "</table>";          var len = f.elements.length;
688        if ($addForm)          var check_all = element_id('allFiles');
689         {          var suma = check_all.checked ? (parseInt(f.elements['totalsize'].value) || 0) : 0;
690             $retHTML .= "</form>";  
691         }          for (var i = 0; i < len; i++) {
692                    var e = f.elements[i];
693                    if (e.name != 'all' && e.name.substr(0, 3) == 'fcb') {
694                            if (check_all.checked) {
695                                    if (e.checked) continue;
696                                    var el = element_id("fss" + e.name.substr(3));
697                                    var size = parseInt(el.value) || 0;
698                                    debug('suma: '+suma+' size: '+size);
699                                    if ((suma + size) < media_size) {
700                                            suma += size;
701                                            e.checked = true;
702                                    } else {
703                                            break;
704                                    }
705                            } else {
706                                    e.checked = false;
707                            }
708                    }
709            }
710            update_sum(suma);
711    }
712    
713    function update_sum(suma, suma_disp) {
714            if (! suma_disp) suma_disp = suma;
715            suma_disp = Math.floor(suma_disp / 1024);
716            element_id('forma').elements['totalsize_kb'].value = suma_disp;
717            element_id('forma').elements['totalsize'].value = suma;
718            pbar_set(suma, media_size);
719            debug('total size: ' + suma);
720    }
721    
722    function sumiraj(e) {
723            var suma = parseInt(element_id('forma').elements['totalsize'].value) || 0;
724            var len = element_id('forma').elements.length;
725            if (e) {
726                    var size = parseInt( element_id("fss" + e.name.substr(3)).value);
727                    if (e.checked) {
728                            suma += size;
729                    } else {
730                            suma -= size;
731                    }
732    
733                    var volumes = parseInt( element_id("prt" + e.name.substr(3)).value);
734                    if (volumes > 1) {
735                            if (e.checked) {
736                                    element_id("volumes").innerHTML = "This will take "+volumes+" mediums!";
737                                    element_id("volumes").style.display = 'block';
738                                    suma = size;
739                                    update_sum(suma);
740                                    return suma;
741                            } else {
742                                    suma -= size;
743                                    element_id("volumes").style.display = 'none';
744                            }
745                    }
746    
747                    if (suma < 0) suma = 0;
748            } else {
749                    suma = 0;
750                    for (var i = 0; i < len; i++) {
751                            var e = element_id('forma').elements[i];
752                            if (e.name != 'all' && e.checked && e.name.substr(0,3) == 'fcb') {
753                                    var el = element_id("fss" + e.name.substr(3));
754                                    if (el && el.value) suma += parseInt(el.value) || 0;
755                            }
756                    }
757            }
758            update_sum(suma);
759            return suma;
760    }
761    
762    /* progress bar */
763    
764    var _pbar_width = null;
765    var _pbar_warn = 10;    // change color in last 10%
766    
767    function pbar_reset() {
768            element_id("mask").style.left = "0px";
769            _pbar_width = element_id("mContainer").offsetWidth - 2;
770            element_id("mask").style.width = _pbar_width + "px";
771            element_id("mask").style.display = "block";
772            element_id("progressIndicator").style.zIndex  = 10;
773            element_id("progressIndicator").innerHTML = "0";
774    }
775    
776    function dec2hex(d) {
777            var hch = '0123456789ABCDEF';
778            var a = d % 16;
779            var q = (d - a) / 16;
780            return hch.charAt(q) + hch.charAt(a);
781    }
782    
783    function pbar_set(amount, max) {
784            debug('pbar_set('+amount+', '+max+')');
785    
786            if (_pbar_width == null) {
787                    var _mc = element_id("mContainer");
788                    if (_pbar_width == null) _pbar_width = parseInt(_mc.offsetWidth ? (_mc.offsetWidth - 2) : 0) || null;
789                    if (_pbar_width == null) _pbar_width = parseInt(_mc.clientWidth ? (_mc.clientWidth + 2) : 0) || null;
790                    if (_pbar_width == null) _pbar_width = 0;
791            }
792    
793            var pcnt = Math.floor(amount * 100 / max);
794            var p90 = 100 - _pbar_warn;
795            var pcol = pcnt - p90;
796            if (Math.round(pcnt) <= 100) {
797                    if (pcol < 0) pcol = 0;
798                    var e = element_id("submitBurner");
799                    debug('enable_button');
800                    e.disabled = false;
801                    var a = e.getAttributeNode('disabled') || null;
802                    if (a) e.removeAttributeNode(a);
803            } else {
804                    debug('disable button');
805                    pcol = _pbar_warn;
806                    var e = element_id("submitBurner");
807                    if (!e.disabled) e.disabled = true;
808            }
809            var col_g = Math.floor((_pbar_warn - pcol) * 255 / _pbar_warn);
810            var col = '#FF' + dec2hex(col_g) + '00';
811    
812            //debug('pcol: '+pcol+' g:'+col_g+' _pbar_warn:'+ _pbar_warn + ' color: '+col);
813            element_id("gradient").style.backgroundColor = col;
814    
815            element_id("progressIndicator").innerHTML = pcnt + '%';
816            //element_id("progressIndicator").innerHTML = amount;
817    
818            element_id("mask").style.clip = 'rect(' + Array(
819                    '0px',
820                    element_id("mask").offsetWidth + 'px',
821                    element_id("mask").offsetHeight + 'px',
822                    Math.round(_pbar_width * amount / max) + 'px'
823            ).join(' ') + ')';
824    }
825    
826    if (!self.body) self.body = new Object();
827    self.onload = self.document.onload = self.body.onload = function() {
828            //pbar_reset();
829            sumiraj();
830    };
831    
832    // -->
833    </script>
834    <div id="fixedBox">
835    
836    <input type="hidden" name="totalsize"/>
837    Size: <input type="text" name="totalsize_kb" size="7" readonly="readonly" style="text-align:right;" value="0" /> kB
838    
839    <div id="mContainer">
840            <div id="gradient">&nbsp;</div>
841            <div id="mask">&nbsp;</div>
842            <div id="progressIndicator">0%</div>
843    </div>
844    <br/>
845    
846    <div id="volumes">&nbsp;</div>
847    
848    Note:
849    <textarea name="note" cols="10" rows="5" id="note"></textarea>
850    
851    <input type="submit" id="submitBurner" value="Burn selected" name="submitBurner" />
852    
853    </div>
854    <!--
855    <div id="debug" style="float: right; width: 10em; border: 1px #ff0000 solid; background-color: #ffe0e0; -moz-opacity: 0.7;">
856    no debug output yet
857    </div>
858    -->
859    EOF3
860            $retHTML .= q{
861                            <input type="hidden" value="burn" name="action">
862                            <input type="hidden" value="results" name="search_results">
863                            <table style="fview" border="0" cellspacing="0" cellpadding="2">
864                            <tr class="tableheader">
865                            <td class="tableheader">
866                                    <input type="checkbox" name="allFiles" id="allFiles" onClick="checkAll('allFiles');">
867                            </td>
868            } .
869                    sort_header($param, 'Share', 'share', 'center') .
870                    sort_header($param, '#', 'num', 'center') .
871            qq{
872                            <td align="center">Type</td>
873            } .
874                    sort_header($param, 'Date', 'date', 'center') .
875                    sort_header($param, 'Age/days', 'age', 'center') .
876                    sort_header($param, 'Size/Mb', 'size', 'center') .
877                    sort_header($param, 'gzip size/Kb', 'incsize', 'center') .
878            qq{
879                            <td align="center">medias</td></tr>
880            };
881    
882            my @color = (' bgcolor="#e0e0e0"', '');
883    
884            my $i = 0;
885            my $host = '';
886    
887            foreach my $backup ( getBackupsNotBurned($param) ) {
888    
889                    if ($host ne $backup->{'host'}) {
890                            $i++;
891                            $host = $backup->{'host'};
892                    }
893                    my $ftype = "";
894    
895                    my $checkbox_key = $backup->{'hostid'}. '_' .$backup->{'backupnum'} . '_' . $backup->{'id'};
896    
897                    $retHTML .=
898                            '<tr' . $color[$i %2 ] . '>
899                            <td class="fview">';
900    
901                    if (($backup->{'inc_size'} || 0) > 0) {
902                            $retHTML .= '
903                            <input type="checkbox" name="fcb' . $checkbox_key . '" value="' . $checkbox_key . '" onClick="sumiraj(this);">';
904                    }
905    
906                    my $img_url = $Conf{CgiImageDirURL};
907    
908                    $retHTML .=
909                            '</td>' .
910                            '<td align="right">' . $backup->{'host'} . ':' . $backup->{'share'} . '</td>' .
911                            '<td align="center">' . $backup->{'backupnum'} . '</td>' .
912                            '<td align="center">' . $backup->{'type'} . '</td>' .
913                            '<td align="center">' . epoch_to_iso( $backup->{'date'} ) . '</td>' .
914                            '<td align="center">' . $backup->{'age'} . '</td>' .
915                            '<td align="right">' . $backup->{'size'} . '</td>' .
916                            '<td align="right">' . $backup->{'inc_size'} .
917                            '<input type="hidden" id="fss'.$checkbox_key .'" value="'. $backup->{'inc_size_calc'} .'"></td>' .
918                            '<input type="hidden" id="prt'.$checkbox_key .'" value="'. $backup->{'volumes'} .'"></td>' .
919                            '<td align="left">' . ( qq{<img src="$img_url/icon-cd.gif" alt="media">} x $backup->{volumes} ) . '</td>' .
920    
921                            "</tr>\n";
922            }
923    
924            $retHTML .= "</table>";
925            $retHTML .= "</form>";
926                
927        return $retHTML;          return $retHTML;
928      }      
929      
930    }        sub displayGrid($) {
931            my ($param) = @_;
932    
933            my $offset = $param->{'offset'};
934            my $hilite = $param->{'search_filename'};
935    
 sub displayGrid($$$$) {  
         my ($where, $addForm, $offset, $hilite) = @_;  
936          my $retHTML = "";          my $retHTML = "";
937    
938          if ($addForm) {          my $start_t = time();
939                  $retHTML .= qq{<form name="forma" method="POST" action="}.$MyURL.qq{?action=search">};  
940                  $retHTML.= qq{<input type="hidden" value="search" name="action">};          my ($results, $files);
941                  $retHTML .= qq{<input type="hidden" value="results" name="search_results">};          if ($param->{'use_hest'} && length($hilite) > 0) {
942                    ($results, $files) = getFilesHyperEstraier($param);
943            } else {
944                    ($results, $files) = getFiles($param);
945            }
946    
947            my $dur_t = time() - $start_t;
948            my $dur = sprintf("%0.4fs", $dur_t);
949    
950            my ($from, $to) = (($offset * $on_page) + 1, ($offset * $on_page) + $on_page);
951    
952            if ($results <= 0) {
953                    $retHTML .= qq{
954                            <p style="color: red;">No results found...</p>
955                    };
956                    return $retHTML;
957            } else {
958                    # DEBUG
959                    #use Data::Dumper;
960                    #$retHTML .= '<pre>' . Dumper($files) . '</pre>';
961            }
962    
963    
964            $retHTML .= qq{
965            <div>
966            Found <b>$results files</b> showing <b>$from - $to</b> (took $dur)
967            </div>
968            <table style="fview" width="100%" border="0" cellpadding="2" cellspacing="0">
969                    <tr class="fviewheader">
970                    <td></td>
971            };
972    
973            sub sort_header($$$$) {
974                    my ($param, $display, $name, $align) = @_;
975    
976                    my ($sort_what, $sort_direction) = split(/_/,$param->{'sort'},2);
977    
978                    my $old_sort = $param->{'sort'};
979    
980                    my $html = qq{<td align="$align"};
981                    my $arrow = '';
982    
983                    if (lc($sort_what) eq lc($name)) {
984                            my $direction = lc($sort_direction);
985    
986                            # swap direction or fallback to default
987                            $direction =~ tr/ad/da/;
988                            $direction = 'a' unless ($direction =~ /[ad]/);
989    
990                            $param->{'sort'} = $name . '_' . $direction;
991                            $html .= ' style="border: 1px solid #808080;"';
992                    
993                            # add unicode arrow for direction
994                            $arrow .= '&nbsp;';
995                            $arrow .= $direction eq 'a'  ?  '&#9650;'
996                                    : $direction eq 'd'  ?  '&#9660;'
997                                    :                       ''
998                                    ;
999    
1000                    } else {
1001                            $param->{'sort'} = $name . '_a';
1002                    }
1003    
1004                    $html .= '><a href="' . page_uri($param) . '">' . $display . '</a>' . $arrow . '</td>';
1005                    $param->{'sort'} = $old_sort;
1006    
1007                    return $html;
1008          }          }
1009    
1010            $retHTML .=
1011                    sort_header($param, 'Share', 'share', 'center') .
1012                    sort_header($param, 'Type and Name', 'path', 'center') .
1013                    sort_header($param, '#', 'num', 'center') .
1014                    sort_header($param, 'Size', 'size', 'center') .
1015                    sort_header($param, 'Date', 'date', 'center');
1016    
1017          $retHTML .= qq{          $retHTML .= qq{
1018          <table style="fview" width="100%">                  <td align="center">Media</td>
                 <tr>  
                 <td class="tableheader">Host</td>  
                 <td class="tableheader">Type</td>  
                 <td class="tableheader">Name</td>  
                 <td class="tableheader">backup no.</td>  
                 <td class="tableheader">size</td>  
                 <td class="tableheader">date</td>  
                 <td class="tableheader">Media</td>  
1019                  </tr>                  </tr>
1020          };          };
1021          my @files = getFiles($where, $offset);  
1022          my $file;          my $file;
1023    
1024          sub hilite_html($$) {          sub hilite_html($$) {
# Line 297  sub displayGrid($$$$) { Line 1027  sub displayGrid($$$$) {
1027                  return $html;                  return $html;
1028          }          }
1029    
1030          foreach $file (@files) {          sub restore_link($$$$$$) {
1031                  my $ftype = "file";                  my $type = shift;
1032                  $ftype = "dir" if ($file->{'type'} == BPC_FTYPE_DIR);                  my $action = 'RestoreFile';
1033                    $action = 'browse' if (lc($type) eq 'dir');
1034                  $retHTML .= "<tr>";                  return sprintf(qq{<a href="?action=%s&host=%s&num=%d&share=%s&dir=%s">%s</a>}, $action, @_);
1035            }
1036                  foreach my $v ((  
1037                          $file->{'hname'},          my $sth_archived;
1038                          $ftype,          my %archived_cache;
1039                          hilite_html( $file->{'fpath'}, $hilite ),  
1040                          $file->{'backupno'},          sub check_archived($$$) {
1041                          $file->{'size'},                  my ($host, $share, $num) = @_;
1042                          $file->{'date'},  
1043                          $file->{'dvd'}                  if (my $html = $archived_cache{"$host $share $num"}) {
1044                  )) {                          return $html;
1045                          $retHTML .= qq{<td class="fviewborder">$v</td>};                  }
1046    
1047                    $sth_archived ||= $dbh->prepare(qq{
1048                            select
1049                                    dvd_nr, note,
1050                                    count(archive_burned.copy) as copies
1051                            from archive
1052                            inner join archive_burned on archive_burned.archive_id = archive.id
1053                            inner join archive_backup on archive.id = archive_backup.archive_id
1054                            inner join backups on backups.id = archive_backup.backup_id
1055                            inner join hosts on hosts.id = backups.hostid
1056                            inner join shares on shares.id = backups.shareid
1057                            where hosts.name = ? and shares.name = ? and backups.num = ?
1058                            group by dvd_nr, note
1059                    });
1060    
1061                    my @mediums;
1062    
1063                    $sth_archived->execute($host, $share, $num);
1064                    while (my $row = $sth_archived->fetchrow_hashref()) {
1065                            push @mediums, '<abbr title="' .
1066                                    $row->{'note'} .
1067                                    ' [' . $row->{'copies'} . ']' .
1068                                    '">' .$row->{'dvd_nr'} .
1069                                    '</abbr>';
1070                  }                  }
1071    
1072                    my $html = join(", ",@mediums);
1073                    $archived_cache{"$host $share $num"} = $html;
1074                    return $html;
1075            }
1076    
1077            my $i = $offset * $on_page;
1078    
1079            foreach $file (@{ $files }) {
1080                    $i++;
1081    
1082                    my $typeStr  = BackupPC::Attrib::fileType2Text(undef, $file->{'type'});
1083                    $retHTML .= qq{<tr class="fviewborder">};
1084    
1085                    $retHTML .= qq{<td class="fviewborder">$i</td>};
1086    
1087                    $retHTML .=
1088                            qq{<td class="fviewborder" align="right">} . $file->{'hname'} . ':' . $file->{'sname'} . qq{</td>} .
1089                            qq{<td class="fviewborder"><img src="$Conf{CgiImageDirURL}/icon-$typeStr.gif" alt="$typeStr" align="middle">&nbsp;} . hilite_html( $file->{'filepath'}, $hilite ) . qq{</td>} .
1090                            qq{<td class="fviewborder" align="center">} . restore_link( $typeStr, ${EscURI( $file->{'hname'} )}, $file->{'backupnum'}, ${EscURI( $file->{'sname'})}, ${EscURI( $file->{'filepath'} )}, $file->{'backupnum'} ) . qq{</td>} .
1091                            qq{<td class="fviewborder" align="right">} . $file->{'size'} . qq{</td>} .
1092                            qq{<td class="fviewborder">} . epoch_to_iso( $file->{'date'} ) . qq{</td>} .
1093                            qq{<td class="fviewborder">} . check_archived( $file->{'hname'}, $file->{'sname'}, $file->{'backupnum'} ) . qq{</td>};
1094    
1095                  $retHTML .= "</tr>";                  $retHTML .= "</tr>";
1096          }          }
1097          $retHTML .= "</table>";          $retHTML .= "</table>";
1098    
1099          # skip pager          # all variables which has to be transfered
1100          return $retHTML;          foreach my $n (qw/search_day_from search_month_from search_year_from search_day_to search_month_to search_year_to search_backup_day_from search_backup_month_from search_backup_year_from search_backup_day_to search_backup_month_to search_backup_year_to search_filename offset/) {
1101                    $retHTML .= qq{<INPUT TYPE="hidden" NAME="$n" VALUE="$In{$n}">\n};
1102            }
1103    
1104          $retHTML .= "<INPUT TYPE=\"hidden\" VALUE=\"\" NAME=\"offset\">";          my $del = '';
1105          for (my $ii = 1; $ii <= $#files; $ii++) {          my $max_page = int( $results / $on_page );
1106                  $retHTML .= "<a href = \"#\" onclick=\"document.forma.offset.value=$ii;document.forma.submit();\">$ii</a>";          my $page = 0;
1107                  if ($ii < $#files) {  
1108                          $retHTML .= " | ";          sub page_uri($) {
1109                    my $param = shift || die "no param?";
1110    
1111                    my $uri = $MyURL;
1112                    my $del = '?';
1113                    foreach my $k (keys %{ $param }) {
1114                            if ($param->{$k}) {
1115                                    $uri .= $del . $k . '=' . ${EscURI( $param->{$k} )};
1116                                    $del = '&';
1117                            }
1118                  }                  }
1119                    return $uri;
1120          }          }
1121    
1122          $retHTML .= "</form>" if ($addForm);          sub page_link($$$) {
1123                          my ($param,$page,$display) = @_;
1124    
1125                    $param->{'offset'} = $page if (defined($page));
1126    
1127                    my $html = '<a href = "' . page_uri($param) . '">' . $display . '</a>';
1128            }
1129    
1130            $retHTML .= '<div style="text-align: center;">';
1131    
1132            if ($offset > 0) {
1133                    $retHTML .= page_link($param, $offset - 1, '&lt;&lt;') . ' ';
1134            }
1135    
1136            while ($page <= $max_page) {
1137                    if ($page == $offset) {
1138                            $retHTML .= $del . '<b>' . ($page + 1) . '</b>';
1139                    } else {
1140                            $retHTML .= $del . page_link($param, $page, $page + 1);
1141                    }
1142    
1143                    if ($page < $offset - $pager_pages && $page != 0) {
1144                            $retHTML .= " ... ";
1145                            $page = $offset - $pager_pages;
1146                            $del = '';
1147                    } elsif ($page > $offset + $pager_pages && $page != $max_page) {
1148                            $retHTML .= " ... ";
1149                            $page = $max_page;
1150                            $del = '';
1151                    } else {
1152                            $del = ' | ';
1153                            $page++;
1154                    }
1155            }
1156    
1157            if ($offset < $max_page) {
1158                    $retHTML .= ' ' . page_link($param, $offset + 1, '&gt;&gt;');
1159            }
1160    
1161            $retHTML .= "</div>";
1162    
1163          return $retHTML;          return $retHTML;
1164  }  }
1165    

Legend:
Removed from v.19  
changed lines
  Added in v.259

  ViewVC Help
Powered by ViewVC 1.1.26