/[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 79 by dpavlin, Fri Aug 26 23:37:10 2005 UTC revision 267 by dpavlin, Tue Dec 13 01:24:09 2005 UTC
# Line 8  use DBI; Line 8  use DBI;
8  use DateTime;  use DateTime;
9  use vars qw(%In $MyURL);  use vars qw(%In $MyURL);
10  use Time::HiRes qw/time/;  use Time::HiRes qw/time/;
11    use XML::Writer;
12    use IO::File;
13    
14  my $on_page = 100;  my $on_page = 100;
15  my $pager_pages = 10;  my $pager_pages = 10;
# Line 15  my $pager_pages = 10; Line 17  my $pager_pages = 10;
17  my $dsn = $Conf{SearchDSN};  my $dsn = $Conf{SearchDSN};
18  my $db_user = $Conf{SearchUser} || '';  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    
32          my $dbh = DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );          my $dbh = get_dbh();
33          my $sth = $dbh->prepare(qq{ SELECT id, share FROM shares ORDER BY share} );          my $sth = $dbh->prepare(qq{
34                    SELECT
35                            shares.id       as id,
36                            hosts.name || ':' || shares.name as share
37                    FROM shares
38                    JOIN hosts on hostid = hosts.id
39                    ORDER BY share
40            } );
41          $sth->execute();          $sth->execute();
42          push @ret, { 'id' => '', 'share' => '-'};       # dummy any          push @ret, { 'id' => '', 'share' => '-'};       # dummy any
43    
44          while ( my $row = $sth->fetchrow_hashref() ) {          while ( my $row = $sth->fetchrow_hashref() ) {
45                  push @ret, $row;                  push @ret, $row;
46          }          }
         $dbh->disconnect();  
47          return @ret;          return @ret;
48  }  }
49    
50  sub epoch_to_iso {  sub epoch_to_iso {
51          my $t = shift || return;          my $t = shift || return;
52          my $iso = BackupPC::Lib::timeStamp($t);          my $iso = BackupPC::Lib::timeStamp(undef, $t);
53          $iso =~ s/\s/ /g;          $iso =~ s/\s/ /g;
54          return $iso;          return $iso;
55  }  }
56    
57  sub getWhere($) {  sub dates_from_form($) {
58          my ($param)    = @_;          my $param = shift || return;
         my @conditions;  
59    
60          sub mk_epoch_date($$) {          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    
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(                  my $dt = new DateTime(
81                          year => $yyyy,                          year => $yyyy,
82                          month => $mm,                          month => $mm,
83                          day => $dd                          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';                  return $dt->epoch || 'NULL';
90          }          }
91    
92          my $backup_from = mk_epoch_date('search_backup', 'from');          my @ret = (
93                    mk_epoch_date('search_backup', 'from'),
94                    mk_epoch_date('search_backup', 'to'),
95                    mk_epoch_date('search', 'from'),
96                    mk_epoch_date('search', 'to'),
97            );
98    
99            return @ret;
100    
101    }
102    
103    
104    sub getWhere($) {
105            my $param = shift || return;
106    
107            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);          push @conditions, qq{ backups.date >= $backup_from } if ($backup_from);
         my $backup_to = mk_epoch_date('search_backup', 'to');  
111          push @conditions, qq{ backups.date <= $backup_to } if ($backup_to);          push @conditions, qq{ backups.date <= $backup_to } if ($backup_to);
   
         my $files_from = mk_epoch_date('search', 'from');  
112          push @conditions, qq{ files.date >= $files_from } if ($files_from);          push @conditions, qq{ files.date >= $files_from } if ($files_from);
         my $files_to = mk_epoch_date('search', 'to');  
113          push @conditions, qq{ files.date <= $files_to } if ($files_to);          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(" | ",@conditions);          print STDERR "backup: $backup_from - $backup_to files: $files_from - $files_to cond:" . join(" and ",@conditions);
       
         push( @conditions, ' files.shareid = ' . $param->{'search_share'} ) if ($param->{'search_share'});  
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'});          push (@conditions, " upper(files.path) LIKE upper('%".$param->{'search_filename'}."%')") if ($param->{'search_filename'});
119    
120          return (          return join(" and ", @conditions);
121                  join(" and ", @conditions),  }
122                  $files_from, $files_to,  
123                  $backup_from, $backup_to  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 getSort($$$) {
170            my ($part,$type, $sort_order) = @_;
171    
172            die "unknown part: $part" unless ($sort_def->{$part});
173            die "unknown type: $type" unless ($sort_def->{$part}->{$type});
174    
175            $sort_order ||= $sort_def->{$part}->{'default'};
176    
177            if (my $ret = $sort_def->{$part}->{$type}->{$sort_order}) {
178                    return $ret;
179            } else {
180                    # fallback to default sort order
181                    return $sort_def->{$part}->{$type}->{ $sort_def->{$part}->{'default'} };
182            }
183  }  }
184    
185    sub getFiles($) {
186            my ($param) = @_;
187    
188  sub getFiles($$) {          my $offset = $param->{'offset'} || 0;
189          my ($where, $offset) = @_;          $offset *= $on_page;
190    
191          my $dbh = DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );          my $dbh = get_dbh();
192    
193          my $sql_cols = qq{          my $sql_cols = qq{
194                  files.id                        AS fid,                  files.id                        AS fid,
195                  hosts.name                      AS hname,                  hosts.name                      AS hname,
196                  shares.name                     AS sname,                  shares.name                     AS sname,
197                  shares.share                    AS sharename,                  files.backupnum                 AS backupnum,
                 files.backupNum                 AS backupNum,  
                 files.name                      AS filename,  
198                  files.path                      AS filepath,                  files.path                      AS filepath,
199                  files.date                      AS date,                  files.date                      AS date,
200                  files.type                      AS filetype,                  files.type                      AS type,
201                  files.size                      AS size,                  files.size                      AS size
                 -- dvds.name                    AS dvd  
                 null                            AS dvd  
202          };          };
203    
204          my $sql_from = qq{          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 and backups.hostID = hosts.ID AND backups.shareID = shares.ID                          INNER JOIN backups      ON backups.num = files.backupnum and backups.hostID = hosts.ID AND backups.shareID = files.shareID
         };  
   
         my $sql_dvd_from = qq{  
                         -- LEFT  JOIN dvds              ON dvds.ID = files.dvdid  
209          };          };
210    
211          my $sql_where;          my $sql_where;
212            my $where = getWhere($param);
213          $sql_where = " WHERE ". $where if ($where);          $sql_where = " WHERE ". $where if ($where);
214    
215            my $order = getSort('search', 'sql', $param->{'sort'});
216    
217          my $sql_order = qq{          my $sql_order = qq{
218                  ORDER BY files.date                  ORDER BY $order
219                  LIMIT $on_page                  LIMIT $on_page
220                  OFFSET ?                  OFFSET ?
221          };          };
222    
223          my $sql_count = qq{ select count(files.id) $sql_from $sql_where };          my $sql_count = qq{ select count(files.id) $sql_from $sql_where };
224          my $sql_results = qq{ select $sql_cols $sql_from $sql_dvd_from $sql_where $sql_order };          my $sql_results = qq{ select $sql_cols $sql_from $sql_where $sql_order };
   
         $offset ||= 0;  
         $offset = ($offset * $on_page);  
225    
226          my $sth = $dbh->prepare($sql_count);          my $sth = $dbh->prepare($sql_count);
227          $sth->execute();          $sth->execute();
# Line 143  sub getFiles($$) { Line 239  sub getFiles($$) {
239          my @ret;          my @ret;
240                
241          while (my $row = $sth->fetchrow_hashref()) {          while (my $row = $sth->fetchrow_hashref()) {
242                  push(@ret, {                  push @ret, $row;
                         'hname'         => $row->{'hname'},  
                         'sname'         => $row->{'sname'},  
                         'sharename'     => $row->{'sharename'},  
                         'backupno'      => $row->{'backupnum'},  
                         'fname'         => $row->{'filename'},  
                         'fpath'         => $row->{'filepath'},  
                         'networkpath'   => $row->{'networkpath'},  
                         'date'          => $row->{'date'},  
                         'type'          => $row->{'filetype'},  
                         'size'          => $row->{'size'},  
                         'id'            => $row->{'fid'},  
                         'dvd'           => $row->{'dvd'}  
                 });  
243          }          }
244            
245          $sth->finish();          $sth->finish();
         $dbh->disconnect();  
246          return ($results, \@ret);          return ($results, \@ret);
247  }  }
248    
249  sub getBackupsNotBurned() {  sub getHyperEstraier_url($) {
250            my ($use_hest) = @_;
251    
252            return unless $use_hest;
253    
254            use HyperEstraier;
255            my ($index_path, $index_node_url);
256    
257            if ($use_hest =~ m#^http://#) {
258                    $index_node_url = $use_hest;
259            } else {
260                    $index_path = $TopDir . '/' . $use_hest;
261                    $index_path =~ s#//#/#g;
262            }
263            return ($index_path, $index_node_url);
264    }
265    
266    sub getFilesHyperEstraier($) {
267            my ($param) = @_;
268    
269            my $offset = $param->{'offset'} || 0;
270            $offset *= $on_page;
271    
272            die "no index_path?" unless ($hest_index_path);
273    
274            use HyperEstraier;
275    
276            my ($index_path, $index_node_url) = getHyperEstraier_url($hest_index_path);
277    
278            # 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            }
304    
305            my ($backup_from, $backup_to, $files_from, $files_to) = dates_from_form($param);
306    
307            $cond->add_attr("backup_date NUMGE $backup_from") if ($backup_from);
308            $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 $dbh = DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );                  my $row;
348          my $sql = q{                  foreach my $c (qw/fid hname sname backupnum filepath date type size/) {
349          SELECT                          $row->{$c} = $doc->attr($c);
350                  backups.hostID          AS hostid,                  }
351                  min(hosts.name)         AS host,                  push @res, $row;
352                  backups.num             AS backupno,          }
353                  min(backups.type)       AS type,  
354                  min(backups.date)       AS date,          return ($hits, \@res);
355                  min(backups.size)       AS size  }
356          FROM files  
357                  INNER JOIN shares       ON files.shareID=shares.ID  sub getGzipName($$$)
358                  INNER JOIN hosts        ON hosts.ID = shares.hostID  {
359                  INNER JOIN backups      ON backups.num = files.backupNum and backups.hostID = hosts.ID AND backups.shareID = shares.ID          my ($host, $share, $backupnum) = @_;
360          WHERE          my $ret = $Conf{GzipSchema};
361                  files.dvdid     IS NULL          
362          GROUP BY          $share =~ s/\//_/g;
363                  backups.hostID, backups.num          $ret =~ s/\\h/$host/ge;
364          ORDER BY min(backups.date)          $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 );          my $sth = $dbh->prepare( $sql );
495          my @ret;          my @ret;
496          $sth->execute();          $sth->execute();
497    
498          while ( my $row = $sth->fetchrow_hashref() ) {          while ( my $row = $sth->fetchrow_hashref() ) {
499                  $row->{'age'} = sprintf("%0.1f", ( (time() - $row->{'date'}) / 86400 ) );                  $row->{'age'} = sprintf("%0.1f", ( $row->{'age'} / 86400 ) );
500                  $row->{'size'} = sprintf("%0.2f", $row->{'size'} / 1024 / 1024);                  #$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 )  * 2);
511                    $row->{inc_size_calc} ||= $row->{inc_size};
512                  push @ret, $row;                  push @ret, $row;
513          }          }
514                
515          return @ret;                return @ret;
516  }  }
517    
518  sub displayBackupsGrid()  sub displayBackupsGrid($) {
519    {  
520        my $retHTML = "";          my $param = shift;
521        my $addForm = 1;  
522                  my $max_archive_size = $Conf{MaxArchiveSize} || die "no MaxArchiveSize";
523        if ($addForm) {          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    DIV#fixedBox, DIV#fixedBox INPUT, DIV#fixedBox TEXTAREA {
543            font-size: 10pt;
544    }
545    
546    FORM>DIV#fixedBox {
547            position: fixed !important;
548            left: 0.5em !important;
549            top: auto !important;
550            bottom: 1em !important;
551            width: 15% !important;
552    }
553    
554    DIV#fixedBox INPUT[type=text], DIV#fixedBox TEXTAREA {
555            border: 1px solid #00C000;
556    }
557    
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              $retHTML .= <<EOF3;  #progressIndicator {
627  <script language="javascript" type="text/javascript">          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      function checkAll(location)  var debug_div = null;
     {  
       for (var i=0;i<document.forma.elements.length;i++)  
       {  
         var e = document.forma.elements[i];  
         if ((e.checked || !e.checked) && e.name != \'all\') {  
             if (eval("document.forma."+location+".checked")) {  
                 e.checked = true;  
             } else {  
                 e.checked = false;  
             }  
         }  
       }  
     }  
 //-->  
 </script>        
645  EOF3  EOF3
646                $retHTML .= q{<form name="forma" method="GET" action="}."$MyURL"."?action=burn\"";  
647                $retHTML.= q{<input type="hidden" value="burn" name="action">};          # take maximum archive size from configuration
               $retHTML .= q{<input type="hidden" value="results" name="search_results">};  
         }  
648          $retHTML .= qq{          $retHTML .= qq{
649                  <table style="fview" border="1" cellspacing="1" cellpadding="3">  var media_size = $max_archive_size ;
650                  <tr class="tableheader">  var max_file_size = $max_archive_file_size;
651          };  
652    };
653    
654            $retHTML .= <<'EOF3';
655    
656          if ($addForm) {  function debug(msg) {
657              $retHTML .= "<td class=\"tableheader\"><input type=\"checkbox\" name=\"allFiles\" onClick=\"checkAll('allFiles');\"></td>";  //      return; // Disable debugging
658    
659            if (! debug_div) debug_div = document.getElementById('debug');
660    
661            // this will create debug div if it doesn't exist.
662            if (! debug_div) {
663                    debug_div = document.createElement('div');
664                    if (document.body) document.body.appendChild(debug_div);
665                    else debug_div = null;
666          }          }
667          $retHTML .=  qq{          if (debug_div) {
668                  <td align="center">Host</td>                  debug_div.appendChild(document.createTextNode(msg));
669                  <td align="center">Backup no</td>                  debug_div.appendChild(document.createElement("br"));
670                  <td align="center">Type</td>          }
671                  <td align="center">date</td>  }
                 <td align="center">age/days</td>  
                 <td align="center">size/MB</td>  
                 </tr>  
         };  
672    
         my @backups = getBackupsNotBurned();  
         my $backup;  
673    
674          if ($addForm) {  var element_id_cache = Array();
675                  $retHTML .= qq{  
676                          <tr><td colspan=7 style="tableheader">  function element_id(name,element) {
677                          <input type="submit" value="Burn selected backups on medium" name="submitBurner">          if (! element_id_cache[name]) {
678                          </td></tr>                  element_id_cache[name] = self.document.getElementById(name);
679                  };          }
680            return element_id_cache[name];
681    }
682    
683    function checkAll(location) {
684            var f = element_id('forma') || null;
685            if (!f) return false;
686    
687            var len = f.elements.length;
688            var check_all = element_id('allFiles');
689            var suma = check_all.checked ? (parseInt(f.elements['totalsize'].value) || 0) : 0;
690    
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          foreach $backup(@backups) {  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                  my $ftype = "";  function update_size(name, checked, suma) {
723                        var size = parseInt( element_id("fss" + name).value);
724                  $retHTML .= "<tr>";  
725                  if ($addForm) {          if (checked) {
726                          $retHTML .= '<td class="fview"><input type="checkbox" name="fcb' .                  suma += size;
727                                  $backup->{'hostid'}.'_'.$backup->{'backupno'} .          } else {
728                                  '" value="' . $backup->{'hostid'}.'_'.$backup->{'backupno'} .                  suma -= size;
                                 '"></td>';  
                 }            
               
                 $retHTML .= '<td class="fviewborder">' . $backup->{'host'} . '</td>' .  
                         '<td class="fviewborder">' . $backup->{'backupno'} . '</td>' .  
                         '<td class="fviewborder">' . $backup->{'type'} . '</td>' .  
                         '<td class="fviewborder">' . epoch_to_iso( $backup->{'date'} ) . '</td>' .  
                         '<td class="fviewborder">' . $backup->{'age'} . '</td>' .  
                         '<td class="fviewborder">' . $backup->{'size'} . '</td>' .  
                         '</tr>';  
729          }          }
730    
731          $retHTML .= "</table>";          var volumes = parseInt( element_id("prt" + name).value);
732            debug('update_size('+name+','+checked+') suma: '+suma+' volumes: '+volumes);
733            if (volumes > 1) {
734                    if (checked) {
735                            element_id("volumes").innerHTML = "This will take "+volumes+" mediums!";
736                            element_id("volumes").style.display = 'block';
737                            suma = size;
738                            update_sum(suma);
739                    } else {
740                            suma -= size;
741                            element_id("volumes").style.display = 'none';
742                    }
743            }
744    
745            return suma;
746    }
747    
748          if ($addForm) {  function sumiraj(e) {
749                  $retHTML .= "</form>";          var suma = parseInt(element_id('forma').elements['totalsize'].value) || 0;
750            var len = element_id('forma').elements.length;
751            if (e) {
752                    suma = update_size(e.name.substr(3), e.checked, suma);
753                    if (suma < 0) suma = 0;
754            } else {
755                    suma = 0;
756                    for (var i = 0; i < len; i++) {
757                            var fel = element_id('forma').elements[i];
758                            if (fel.name != 'all' && fel.checked && fel.name.substr(0,3) == 'fcb') {
759                                    suma = update_size(fel.name.substr(3), fel.checked, suma);
760                            }
761                    }
762          }          }
763            update_sum(suma);
764            return suma;
765    }
766    
767    /* progress bar */
768    
769    var _pbar_width = null;
770    var _pbar_warn = 10;    // change color in last 10%
771    
772    function pbar_reset() {
773            element_id("mask").style.left = "0px";
774            _pbar_width = element_id("mContainer").offsetWidth - 2;
775            element_id("mask").style.width = _pbar_width + "px";
776            element_id("mask").style.display = "block";
777            element_id("progressIndicator").style.zIndex  = 10;
778            element_id("progressIndicator").innerHTML = "0";
779    }
780    
781    function dec2hex(d) {
782            var hch = '0123456789ABCDEF';
783            var a = d % 16;
784            var q = (d - a) / 16;
785            return hch.charAt(q) + hch.charAt(a);
786    }
787    
788    function pbar_set(amount, max) {
789            debug('pbar_set('+amount+', '+max+')');
790    
791            if (_pbar_width == null) {
792                    var _mc = element_id("mContainer");
793                    if (_pbar_width == null) _pbar_width = parseInt(_mc.offsetWidth ? (_mc.offsetWidth - 2) : 0) || null;
794                    if (_pbar_width == null) _pbar_width = parseInt(_mc.clientWidth ? (_mc.clientWidth + 2) : 0) || null;
795                    if (_pbar_width == null) _pbar_width = 0;
796            }
797    
798            var pcnt = Math.floor(amount * 100 / max);
799            var p90 = 100 - _pbar_warn;
800            var pcol = pcnt - p90;
801            if (Math.round(pcnt) <= 100) {
802                    if (pcol < 0) pcol = 0;
803                    var e = element_id("submitBurner");
804                    debug('enable_button');
805                    e.disabled = false;
806                    var a = e.getAttributeNode('disabled') || null;
807                    if (a) e.removeAttributeNode(a);
808            } else {
809                    debug('disable button');
810                    pcol = _pbar_warn;
811                    var e = element_id("submitBurner");
812                    if (!e.disabled) e.disabled = true;
813            }
814            var col_g = Math.floor((_pbar_warn - pcol) * 255 / _pbar_warn);
815            var col = '#FF' + dec2hex(col_g) + '00';
816    
817            //debug('pcol: '+pcol+' g:'+col_g+' _pbar_warn:'+ _pbar_warn + ' color: '+col);
818            element_id("gradient").style.backgroundColor = col;
819    
820            element_id("progressIndicator").innerHTML = pcnt + '%';
821            //element_id("progressIndicator").innerHTML = amount;
822    
823            element_id("mask").style.clip = 'rect(' + Array(
824                    '0px',
825                    element_id("mask").offsetWidth + 'px',
826                    element_id("mask").offsetHeight + 'px',
827                    Math.round(_pbar_width * amount / max) + 'px'
828            ).join(' ') + ')';
829    }
830    
831    if (!self.body) self.body = new Object();
832    self.onload = self.document.onload = self.body.onload = function() {
833            //pbar_reset();
834            sumiraj();
835    };
836    
837    // -->
838    </script>
839    <div id="fixedBox">
840    
841    <input type="hidden" name="totalsize"/>
842    Size: <input type="text" name="totalsize_kb" size="7" readonly="readonly" style="text-align:right;" value="0" /> kB
843    
844    <div id="mContainer">
845            <div id="gradient">&nbsp;</div>
846            <div id="mask">&nbsp;</div>
847            <div id="progressIndicator">0%</div>
848    </div>
849    <br/>
850    
851    <div id="volumes">&nbsp;</div>
852    
853    Note:
854    <textarea name="note" cols="10" rows="5" id="note"></textarea>
855    
856    <input type="submit" id="submitBurner" value="Burn selected" name="submitBurner" />
857    
858    </div>
859    <!--
860    <div id="debug" style="float: right; width: 10em; border: 1px #ff0000 solid; background-color: #ffe0e0; -moz-opacity: 0.7;">
861    no debug output yet
862    </div>
863    -->
864    EOF3
865            $retHTML .= q{
866                            <input type="hidden" value="burn" name="action">
867                            <input type="hidden" value="results" name="search_results">
868                            <table style="fview" border="0" cellspacing="0" cellpadding="2">
869                            <tr class="tableheader">
870                            <td class="tableheader">
871                                    <input type="checkbox" name="allFiles" id="allFiles" onClick="checkAll('allFiles');">
872                            </td>
873            } .
874                    sort_header($param, 'Share', 'share', 'center') .
875                    sort_header($param, '#', 'num', 'center') .
876            qq{
877                            <td align="center">Type</td>
878            } .
879                    sort_header($param, 'Date', 'date', 'center') .
880                    sort_header($param, 'Age/days', 'age', 'center') .
881                    sort_header($param, 'Size/Mb', 'size', 'center') .
882                    sort_header($param, 'gzip size/Kb', 'incsize', 'center') .
883            qq{
884                            <td align="center">medias</td></tr>
885            };
886    
887            my @color = (' bgcolor="#e0e0e0"', '');
888    
889            my $i = 0;
890            my $host = '';
891    
892            foreach my $backup ( getBackupsNotBurned($param) ) {
893    
894                    if ($host ne $backup->{'host'}) {
895                            $i++;
896                            $host = $backup->{'host'};
897                    }
898                    my $ftype = "";
899    
900                    my $checkbox_key = $backup->{'hostid'}. '_' .$backup->{'backupnum'} . '_' . $backup->{'id'};
901    
902                    $retHTML .=
903                            '<tr' . $color[$i %2 ] . '>
904                            <td class="fview">';
905    
906                    if (($backup->{'inc_size'} || 0) > 0) {
907                            $retHTML .= '
908                            <input type="checkbox" name="fcb' . $checkbox_key . '" value="' . $checkbox_key . '" onClick="sumiraj(this);">';
909                    }
910    
911                    my $img_url = $Conf{CgiImageDirURL};
912    
913                    $retHTML .=
914                            '</td>' .
915                            '<td align="right">' . $backup->{'host'} . ':' . $backup->{'share'} . '</td>' .
916                            '<td align="center">' . $backup->{'backupnum'} . '</td>' .
917                            '<td align="center">' . $backup->{'type'} . '</td>' .
918                            '<td align="center">' . epoch_to_iso( $backup->{'date'} ) . '</td>' .
919                            '<td align="center">' . $backup->{'age'} . '</td>' .
920                            '<td align="right">' . $backup->{'size'} . '</td>' .
921                            '<td align="right">' . sprintf("%0.1f", $backup->{'inc_size'} / 1024 ) .
922                            '<input type="hidden" id="fss'.$checkbox_key .'" value="'. $backup->{'inc_size_calc'} .'"></td>' .
923                            '<input type="hidden" id="prt'.$checkbox_key .'" value="'. $backup->{'volumes'} .'"></td>' .
924                            '<td align="left">' . ( qq{<img src="$img_url/icon-cd.gif" alt="media">} x $backup->{volumes} ) . '</td>' .
925    
926                            "</tr>\n";
927            }
928    
929            $retHTML .= "</table>";
930            $retHTML .= "</form>";
931                
932          return $retHTML;          return $retHTML;
933  }        }      
934    
935  sub displayGrid($$$$) {  sub displayGrid($) {
936          my ($where, $addForm, $offset, $hilite) = @_;          my ($param) = @_;
937    
938            my $offset = $param->{'offset'};
939            my $hilite = $param->{'search_filename'};
940    
941          my $retHTML = "";          my $retHTML = "";
942    
943          my $start_t = time();          my $start_t = time();
944    
945          my ($results, $files) = getFiles($where, $offset);          my ($results, $files);
946            if ($param->{'use_hest'} && length($hilite) > 0) {
947                    ($results, $files) = getFilesHyperEstraier($param);
948            } else {
949                    ($results, $files) = getFiles($param);
950            }
951    
952          my $dur_t = time() - $start_t;          my $dur_t = time() - $start_t;
953          my $dur = sprintf("%0.4fs", $dur_t);          my $dur = sprintf("%0.4fs", $dur_t);
# Line 314  sub displayGrid($$$$) { Line 966  sub displayGrid($$$$) {
966          }          }
967    
968    
         if ($addForm) {  
                 $retHTML .= qq{<form name="forma" method="GET" action="$MyURL">};  
                 $retHTML.= qq{<input type="hidden" value="search" name="action">};  
                 $retHTML .= qq{<input type="hidden" value="results" name="search_results">};  
         }  
   
   
969          $retHTML .= qq{          $retHTML .= qq{
970          <div>          <div>
971          Found <b>$results files</b> showing <b>$from - $to</b> (took $dur)          Found <b>$results files</b> showing <b>$from - $to</b> (took $dur)
972          </div>          </div>
973          <table style="fview" width="100%" border="0" cellpadding="2" cellspacing="0">          <table style="fview" width="100%" border="0" cellpadding="2" cellspacing="0">
974                  <tr class="fviewheader">                  <tr class="fviewheader">
975                  <td align="center">Share</td>                  <td></td>
976                  <td align="center">Type and Name</td>          };
977                  <td align="center">#</td>  
978                  <td align="center">Size</td>          sub sort_header($$$$) {
979                  <td align="center">Date</td>                  my ($param, $display, $name, $align) = @_;
980    
981                    my ($sort_what, $sort_direction) = split(/_/,$param->{'sort'},2);
982    
983                    my $old_sort = $param->{'sort'};
984    
985                    my $html = qq{<td align="$align"};
986                    my $arrow = '';
987    
988                    if (lc($sort_what) eq lc($name)) {
989                            my $direction = lc($sort_direction);
990    
991                            # swap direction or fallback to default
992                            $direction =~ tr/ad/da/;
993                            $direction = 'a' unless ($direction =~ /[ad]/);
994    
995                            $param->{'sort'} = $name . '_' . $direction;
996                            $html .= ' style="border: 1px solid #808080;"';
997                    
998                            # add unicode arrow for direction
999                            $arrow .= '&nbsp;';
1000                            $arrow .= $direction eq 'a'  ?  '&#9650;'
1001                                    : $direction eq 'd'  ?  '&#9660;'
1002                                    :                       ''
1003                                    ;
1004    
1005                    } else {
1006                            $param->{'sort'} = $name . '_a';
1007                    }
1008    
1009                    $html .= '><a href="' . page_uri($param) . '">' . $display . '</a>' . $arrow . '</td>';
1010                    $param->{'sort'} = $old_sort;
1011    
1012                    return $html;
1013            }
1014    
1015            $retHTML .=
1016                    sort_header($param, 'Share', 'share', 'center') .
1017                    sort_header($param, 'Type and Name', 'path', 'center') .
1018                    sort_header($param, '#', 'num', 'center') .
1019                    sort_header($param, 'Size', 'size', 'center') .
1020                    sort_header($param, 'Date', 'date', 'center');
1021    
1022            $retHTML .= qq{
1023                  <td align="center">Media</td>                  <td align="center">Media</td>
1024                  </tr>                  </tr>
1025          };          };
# Line 351  sub displayGrid($$$$) { Line 1039  sub displayGrid($$$$) {
1039                  return sprintf(qq{<a href="?action=%s&host=%s&num=%d&share=%s&dir=%s">%s</a>}, $action, @_);                  return sprintf(qq{<a href="?action=%s&host=%s&num=%d&share=%s&dir=%s">%s</a>}, $action, @_);
1040          }          }
1041    
1042            my $sth_archived;
1043            my %archived_cache;
1044    
1045            sub check_archived($$$) {
1046                    my ($host, $share, $num) = @_;
1047    
1048                    if (my $html = $archived_cache{"$host $share $num"}) {
1049                            return $html;
1050                    }
1051    
1052                    $sth_archived ||= $dbh->prepare(qq{
1053                            select
1054                                    dvd_nr, note,
1055                                    count(archive_burned.copy) as copies
1056                            from archive
1057                            inner join archive_burned on archive_burned.archive_id = archive.id
1058                            inner join archive_backup on archive.id = archive_backup.archive_id
1059                            inner join backups on backups.id = archive_backup.backup_id
1060                            inner join hosts on hosts.id = backups.hostid
1061                            inner join shares on shares.id = backups.shareid
1062                            where hosts.name = ? and shares.name = ? and backups.num = ?
1063                            group by dvd_nr, note
1064                    });
1065    
1066                    my @mediums;
1067    
1068                    $sth_archived->execute($host, $share, $num);
1069                    while (my $row = $sth_archived->fetchrow_hashref()) {
1070                            push @mediums, '<abbr title="' .
1071                                    $row->{'note'} .
1072                                    ' [' . $row->{'copies'} . ']' .
1073                                    '">' .$row->{'dvd_nr'} .
1074                                    '</abbr>';
1075                    }
1076    
1077                    my $html = join(", ",@mediums);
1078                    $archived_cache{"$host $share $num"} = $html;
1079                    return $html;
1080            }
1081    
1082            my $i = $offset * $on_page;
1083    
1084          foreach $file (@{ $files }) {          foreach $file (@{ $files }) {
1085                    $i++;
1086    
1087                  my $typeStr  = BackupPC::Attrib::fileType2Text(undef, $file->{'type'});                  my $typeStr  = BackupPC::Attrib::fileType2Text(undef, $file->{'type'});
1088                  $retHTML .= qq{<tr class="fviewborder">};                  $retHTML .= qq{<tr class="fviewborder">};
1089    
1090                    $retHTML .= qq{<td class="fviewborder">$i</td>};
1091    
1092                  $retHTML .=                  $retHTML .=
1093                          qq{<td class="fviewborder" align="right">} . $file->{'sharename'} . qq{</td>} .                          qq{<td class="fviewborder" align="right">} . $file->{'hname'} . ':' . $file->{'sname'} . qq{</td>} .
1094                          qq{<td class="fviewborder"><img src="$Conf{CgiImageDirURL}/icon-$typeStr.gif" alt="$typeStr">&nbsp;} . hilite_html( $file->{'fpath'}, $hilite ) . qq{</td>} .                          qq{<td class="fviewborder"><img src="$Conf{CgiImageDirURL}/icon-$typeStr.gif" alt="$typeStr" align="middle">&nbsp;} . hilite_html( $file->{'filepath'}, $hilite ) . qq{</td>} .
1095                          qq{<td class="fviewborder" align="center">} . restore_link( $typeStr, ${EscURI( $file->{'hname'} )}, $file->{'backupno'}, ${EscURI( $file->{'sname'})}, ${EscURI( $file->{'fpath'} )}, $file->{'backupno'} ) . qq{</td>} .                          qq{<td class="fviewborder" align="center">} . restore_link( $typeStr, ${EscURI( $file->{'hname'} )}, $file->{'backupnum'}, ${EscURI( $file->{'sname'})}, ${EscURI( $file->{'filepath'} )}, $file->{'backupnum'} ) . qq{</td>} .
1096                          qq{<td class="fviewborder" align="right">} . $file->{'size'} . qq{</td>} .                          qq{<td class="fviewborder" align="right">} . $file->{'size'} . qq{</td>} .
1097                          qq{<td class="fviewborder">} . epoch_to_iso( $file->{'date'} ) . qq{</td>} .                          qq{<td class="fviewborder">} . epoch_to_iso( $file->{'date'} ) . qq{</td>} .
1098                          qq{<td class="fviewborder">} . $file->{'dvd'} . qq{</td>};                          qq{<td class="fviewborder">} . check_archived( $file->{'hname'}, $file->{'sname'}, $file->{'backupnum'} ) . qq{</td>};
1099    
1100                  $retHTML .= "</tr>";                  $retHTML .= "</tr>";
1101          }          }
# Line 376  sub displayGrid($$$$) { Line 1110  sub displayGrid($$$$) {
1110          my $max_page = int( $results / $on_page );          my $max_page = int( $results / $on_page );
1111          my $page = 0;          my $page = 0;
1112    
1113          my $link_fmt = '<a href = "#" onclick="document.forma.offset.value=%d;document.forma.submit();">%s</a>';          sub page_uri($) {
1114                    my $param = shift || die "no param?";
1115    
1116                    my $uri = $MyURL;
1117                    my $del = '?';
1118                    foreach my $k (keys %{ $param }) {
1119                            if ($param->{$k}) {
1120                                    $uri .= $del . $k . '=' . ${EscURI( $param->{$k} )};
1121                                    $del = '&';
1122                            }
1123                    }
1124                    return $uri;
1125            }
1126    
1127            sub page_link($$$) {
1128                    my ($param,$page,$display) = @_;
1129    
1130                    $param->{'offset'} = $page if (defined($page));
1131    
1132                    my $html = '<a href = "' . page_uri($param) . '">' . $display . '</a>';
1133            }
1134    
1135          $retHTML .= '<div style="text-align: center;">';          $retHTML .= '<div style="text-align: center;">';
1136    
1137          if ($offset > 0) {          if ($offset > 0) {
1138                  $retHTML .= sprintf($link_fmt, $offset - 1, '&lt;&lt;') . ' ';                  $retHTML .= page_link($param, $offset - 1, '&lt;&lt;') . ' ';
1139          }          }
1140    
1141          while ($page <= $max_page) {          while ($page <= $max_page) {
1142                  if ($page == $offset) {                  if ($page == $offset) {
1143                          $retHTML .= $del . '<b>' . ($page + 1) . '</b>';                          $retHTML .= $del . '<b>' . ($page + 1) . '</b>';
1144                  } else {                  } else {
1145                          $retHTML .= $del . sprintf($link_fmt, $page, $page + 1);                          $retHTML .= $del . page_link($param, $page, $page + 1);
1146                  }                  }
1147    
1148                  if ($page < $offset - $pager_pages && $page != 0) {                  if ($page < $offset - $pager_pages && $page != 0) {
# Line 406  sub displayGrid($$$$) { Line 1160  sub displayGrid($$$$) {
1160          }          }
1161    
1162          if ($offset < $max_page) {          if ($offset < $max_page) {
1163                  $retHTML .= ' ' . sprintf($link_fmt, $offset + 1, '&gt;&gt;');                  $retHTML .= ' ' . page_link($param, $offset + 1, '&gt;&gt;');
1164          }          }
1165    
1166          $retHTML .= "</div>";          $retHTML .= "</div>";
1167    
         $retHTML .= "</form>" if ($addForm);  
   
1168          return $retHTML;          return $retHTML;
1169  }  }
1170    

Legend:
Removed from v.79  
changed lines
  Added in v.267

  ViewVC Help
Powered by ViewVC 1.1.26