/[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 6 by dpavlin, Thu Jun 23 09:47:59 2005 UTC revision 225 by dpavlin, Mon Oct 24 14:02:00 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 epoch_to_iso {
51            my $t = shift || return;
52            my $iso = BackupPC::Lib::timeStamp(undef, $t);
53            $iso =~ s/\s/ /g;
54            return $iso;
55  }  }
56    
57    sub dates_from_form($) {
58            my $param = shift || return;
59    
60            sub mk_epoch_date($$) {
61                    my ($name,$suffix) = @_;
62    
63                    my $yyyy = $param->{ $name . '_year_' . $suffix} || return undef;
64                    my $mm .= $param->{ $name . '_month_' . $suffix} ||
65                            ( $suffix eq 'from' ? 1 : 12);
66                    my $dd .= $param->{ $name . '_day_' . $suffix} ||
67                            ( $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(
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 @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($) {  sub getWhere($) {
105      my ($param)    = @_;          my $param = shift || return;
106      my $retSQL     = "";  
107      my @conditions = ();          my ($backup_from, $backup_to, $files_from, $files_to) = dates_from_form($param);
108      my $cond;  
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      if ( defined( $param->{'search_backup_day_from'} ) && $param->{'search_backup_day_from'} ne "") {          push @conditions, qq{ files.date <= $files_to } if ($files_to);
114          push( @conditions,  
115              ' strftime("%d", datetime(backups.date, "unixepoch","localtime")) >= "'          print STDERR "backup: $backup_from - $backup_to files: $files_from - $files_to cond:" . join(" and ",@conditions);
116                . $param->{'search_backup_day_from'} ."\"");  
117      }          push( @conditions, ' files.shareid = ' . $param->{'search_share'} ) if ($param->{'search_share'});
118      if ( defined( $param->{'search_backup_day_to'} ) && $param->{'search_backup_day_to'} ne "") {          push (@conditions, " upper(files.path) LIKE upper('%".$param->{'search_filename'}."%')") if ($param->{'search_filename'});
119          push( @conditions,  
120              ' strftime("%d", datetime(backups.date, "unixepoch","localtime")) <= "'          return join(" and ", @conditions);
121                . $param->{'search_backup_day_from'}  ."\"");  }
122      }  
123      if ( defined( $param->{'search_backup_month_from'} ) && $param->{'search_backup_month_from'} ne "") {  my $sort_def = {
124          push( @conditions,          search => {
125              ' strftime("%m", datetime(backups.date, "unixepoch","localtime")) >= "'                  default => 'date_a',
126                . $param->{'search_backup_month_from'}  ."\"");                  sql => {
127      }                          share_d => 'shares.name DESC',
128      if ( defined( $param->{'search_backup_month_to'} ) && $param->{'search_backup_month_to'} ne "") {                          share_a => 'shares.name ASC',
129          push( @conditions,                          path_d => 'files.path DESC',
130              ' strftime("%m", datetime(backups.date, "unixepoch","localtime")) <= "'                          path_a => 'files.path ASC',
131                . $param->{'search_backup_month_to'}  ."\"");                          num_d => 'files.backupnum DESC',
132      }                          num_a => 'files.backupnum ASC',
133      if ( defined( $param->{'search_backup_year_from'} ) && $param->{'search_backup_year_from'} ne "") {                          size_d => 'files.size DESC',
134          push( @conditions,                          size_a => 'files.size ASC',
135              ' strftime("%Y", datetime(backups.date, "unixepoch","localtime")) >= "'                          date_d => 'files.date DESC',
136                . $param->{'search_backup_year_from'}  ."\"");                          date_a => 'files.date ASC',
137      }                  },
138      if ( defined( $param->{'search_backup_year_to'} ) && $param->{'search_backup_year_to'} ne "") {                  est => {
139          push( @conditions,                          share_d => 'sname STRD',
140              ' strftime("%Y", datetime(backups.date, "unixepoch","localtime")) <= "'                          share_a => 'sname STRA',
141                . $param->{'search_backup_year_to'}  ."\"");                          path_d => 'filepath STRD',
142      }                          path_a => 'filepath STRA',
143                            num_d => 'backupnum NUMD',
144      if ( defined( $param->{'search_day_from'} )   && $param->{'search_day_from'} ne "" ) {                          num_a => 'backupnum NUMA',
145          push( @conditions,                          size_d => 'size NUMD',
146              ' strftime("%d", datetime(files.date, "unixepoch","localtime")) >= "'                          size_a => 'size NUMA',
147                . $param->{'search_day_from'}  ."\"");                          date_d => 'date NUMD',
148      }                          date_a => 'date NUMA',
149      if ( defined( $param->{'search_month_from'} ) && $param->{'search_month_from'} ne "") {                  }
150          push( @conditions,          }, burn => {
151              ' strftime("%m", datetime(files.date, "unixepoch","localtime")) >= "'                  default => 'date_a',
152                . $param->{'search_month_from'}  ."\"");                  sql => {
153      }                          share_d => 'host DESC, share DESC',
154      if ( defined( $param->{'search_year_from'} ) && $param->{'search_year_from'} ne "") {                          share_a => 'host ASC, share ASC',
155          push( @conditions,                          num_d => 'backupnum DESC',
156              ' strftime("%Y", datetime(files.date, "unixepoch","localtime")) >= "'                          num_a => 'backupnum ASC',
157                . $param->{'search_year_from'}  ."\"");                          date_d => 'date DESC',
158      }                          date_a => 'date ASC',
159      if ( defined( $param->{'search_day_to'} )   && $param->{'search_day_to'} ne "" ) {                          age_d => 'age DESC',
160          push( @conditions,                          age_a => 'age ASC',
161              ' strftime("%d", datetime(files.date, "unixepoch","localtime")) <= "'                          size_d => 'size DESC',
162                . $param->{'search_day_to'}  ."\"");                          size_a => 'size ASC',
163      }                          incsize_d => 'inc_size DESC',
164      if ( defined( $param->{'search_month_to'} ) && $param->{'search_month_to'} ne "" ) {                          incsize_a => 'inc_size ASC',
165          push( @conditions,                  }
             ' strftime("%m", datetime(files.date, "unixepoch","localtime")) <= "'  
               . $param->{'search_month_to'} ."\"" );  
     }  
     if ( defined( $param->{'search_year_to'} )&& $param->{'search_year_to'} ne "" )  {  
         push( @conditions,  
             ' strftime("%Y", datetime(files.date, "unixepoch","localtime")) <= "'  
               . $param->{'search_year_to'} ."\"");  
     }  
   
     if ( defined( $param->{'search_host'} ) && $param->{'search_host'} ne "") {  
       push( @conditions, ' backups.hostID = ' . $param->{'search_host'} );  
     }  
   
     if ( defined ($param->{'search_filename'}) && $param->{'search_filename'} ne "") {  
         push (@conditions, " files.name LIKE '".$param->{'search_filename'}."%'");  
         }  
       
     $retSQL = "";  
     foreach $cond(@conditions)  
       {  
           if ($retSQL ne "")  
             {  
                 $retSQL .= " AND ";  
             }  
           $retSQL .= $cond;  
       }        
   
       
     return $retSQL;  
 }  
   
 sub getFiles($)  
   {  
       my ($where) = @_;  
         
       my $dbh = DBI->connect( "dbi:SQLite:dbname=${TopDir}/$Conf{SearchDB}",  
         "", "", { RaiseError => 1, AutoCommit => 1 } );  
       my $sql =            
         q{    
               SELECT files.id                       AS fid,  
                      hosts.name                     AS hname,  
                      shares.name                    AS sname,  
                      shares.share                   AS sharename,  
                      backups.num                    AS backupNum,  
                      files.name                     AS filename,  
                      files.path                     AS filepath,  
                      shares.share||files.fullpath AS networkPath,  
                      date(files.date, 'unixepoch', 'localtime') AS date,  
                      files.type                     AS filetype,  
                      files.size                     AS size,  
                      dvds.name                      AS dvd  
                   FROM  
                      files  
                         INNER JOIN shares  ON files.shareID=shares.ID  
                         INNER JOIN hosts   ON hosts.ID = shares.hostID  
                         INNER JOIN backups ON backups.hostID = hosts.ID  
                         LEFT  JOIN dvds    ON dvds.ID = files.dvdid  
                       
           };  
   
       if (defined($where) && $where ne "")  
         {  
             $sql .= " WHERE ". $where;        
166          }          }
167    };
168    
169          sub getSort($$$) {
170        my $st = $dbh->prepare(          my ($part,$type, $sort_order) = @_;
           $sql  
           );      
171    
172        $st->execute;          die "unknown part: $part" unless ($sort_def->{$part});
173                  die "unknown type: $type" unless ($sort_def->{$part}->{$type});
174        my @ret = ();  
175        my $tmp;          $sort_order ||= $sort_def->{$part}->{'default'};
176          
177        while ($tmp = $st->fetchrow_hashref())          if (my $ret = $sort_def->{$part}->{$type}->{$sort_order}) {
178          {                  return $ret;
179              push(@ret, {          } else {
180                             'hname'       => $tmp->{'hname'},                  # fallback to default sort order
181                             'sname'       => $tmp->{'sname'},                  return $sort_def->{$part}->{$type}->{ $sort_def->{$part}->{'default'} };
                            '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'}  
                        }  
             );  
                                   
182          }          }
183          }
184        $st->finish();  
185        $dbh->disconnect();  sub getFiles($) {
186        return @ret;          my ($param) = @_;
187    }  
188            my $offset = $param->{'offset'} || 0;
189  sub getBackupsNotBurned()          $offset *= $on_page;
190    {  
191        my $dbh = DBI->connect( "dbi:SQLite:dbname=${TopDir}/$Conf{SearchDB}",          my $dbh = get_dbh();
192          "", "", { RaiseError => 1, AutoCommit => 1 } );        
193        my $sql = q{          my $sql_cols = qq{
194            SELECT                  files.id                        AS fid,
195              hosts.ID         AS hostID,                  hosts.name                      AS hname,
196              hosts.name       AS host,                  shares.name                     AS sname,
197              backups.num      AS backupno,                  files.backupnum                 AS backupnum,
198              backups.type     AS type,                  files.path                      AS filepath,
199              backups.date     AS date                  files.date                      AS date,
200            FROM backups, shares, files, hosts                  files.type                      AS type,
201            WHERE                  files.size                      AS size
202              backups.num    = files.backupNum  AND          };
203              shares.ID      = files.shareID    AND            
204              backups.hostID = shares.hostID    AND          my $sql_from = qq{
205              hosts.ID       = backups.hostID   AND                  FROM files
206              files.dvdid    IS NULL                          INNER JOIN shares       ON files.shareID=shares.ID
207            GROUP BY                          INNER JOIN hosts        ON hosts.ID = shares.hostID
208              backups.hostID, backups.num                          INNER JOIN backups      ON backups.num = files.backupnum and backups.hostID = hosts.ID AND backups.shareID = files.shareID
209        };          };
210        my $st = $dbh -> prepare( $sql );  
211        my @ret = ();          my $sql_where;
212        $st -> execute();          my $where = getWhere($param);
213            $sql_where = " WHERE ". $where if ($where);
214        while ( my $tmp = $st -> fetchrow_hashref() )  
215          {                    my $order = getSort('search', 'sql', $param->{'sort'});
216              push(@ret, {  
217                           'host'     => $tmp->{'host'},          my $sql_order = qq{
218                           'hostid'   => $tmp->{'hostID'},                  ORDER BY $order
219                           'backupno' => $tmp->{'backupno'},                  LIMIT $on_page
220                           'type'     => $tmp->{'type'},                  OFFSET ?
221                           'date'     => $tmp->{'date'}          };
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    
226            my $sth = $dbh->prepare($sql_count);
227            $sth->execute();
228            my ($results) = $sth->fetchrow_array();
229    
230            $sth = $dbh->prepare($sql_results);
231            $sth->execute( $offset );
232    
233            if ($sth->rows != $results) {
234                    my $bug = "$0 BUG: [[ $sql_count ]] = $results while [[ $sql_results ]] = " . $sth->rows;
235                    $bug =~ s/\s+/ /gs;
236                    print STDERR "$bug\n";
237          }          }
238    
239            my @ret;
240                
241        return @ret;                while (my $row = $sth->fetchrow_hashref()) {
242    }                  push @ret, $row;
243            }
244        
245            $sth->finish();
246            return ($results, \@ret);
247    }
248    
249    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 . '/' . $index_path;
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  sub displayBackupsGrid()          my $q = $param->{'search_filename'};
294    {          my $shareid = $param->{'search_share'};
295        my $retHTML = "";  
296        my $addForm = 1;          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 $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) {
381                    $size = (stat($tgz))[7];
382            } elsif (-d $tgz) {
383                    opendir(my $dir, $tgz) || die "can't opendir $tgz: $!";
384                    my @parts = grep { !/^\./ && -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            }
391    
392            return $size;
393    }
394    
395    sub getGzipSize($$)
396    {
397            my ($hostID, $backupNum) = @_;
398            my $sql;
399            my $dbh = get_dbh();
400            
401            $sql = q{
402                                    SELECT hosts.name  as host,
403                                               shares.name as share,
404                                               backups.num as backupnum
405                                    FROM hosts, backups, shares
406                                    WHERE shares.id=backups.shareid AND
407                                              hosts.id =backups.hostid AND
408                                              hosts.id=? AND
409                                              backups.num=?
410                            };
411            my $sth = $dbh->prepare($sql);
412            $sth->execute($hostID, $backupNum);
413    
414            my $row = $sth->fetchrow_hashref();
415    
416            return get_tgz_size_by_name(
417                    getGzipName($row->{'host'}, $row->{share}, $row->{'backupnum'})
418            );
419    }
420    
421    sub getBackupsNotBurned($) {
422    
423            my $param = shift;
424            my $dbh = get_dbh();
425    
426            my $order = getSort('burn', 'sql', $param->{'sort'});
427    
428    print STDERR "## sort=". ($param->{'sort'} || 'no sort param') . " burn sql order: $order\n";
429    
430            my $sql = qq{
431                    SELECT
432                            backups.hostID AS hostID,
433                            hosts.name AS host,
434                            shares.name AS share,
435                            backups.num AS backupnum,
436                            backups.type AS type,
437                            backups.date AS date,
438                            date_part('epoch',now()) - backups.date as age,
439                            backups.size AS size,
440                            backups.id AS id,
441                            backups.inc_size AS inc_size,
442                            backups.parts AS parts
443                    FROM backups
444                    INNER JOIN shares       ON backups.shareID=shares.ID
445                    INNER JOIN hosts        ON backups.hostID = hosts.ID
446                    LEFT OUTER JOIN archive_backup ON archive_backup.backup_id = backups.id
447                    WHERE backups.inc_size > 0 AND backups.inc_deleted is false AND archive_backup.backup_id IS NULL
448                    GROUP BY
449                            backups.hostID,
450                            hosts.name,
451                            shares.name,
452                            backups.num,
453                            backups.shareid,
454                            backups.id,
455                            backups.type,
456                            backups.date,
457                            backups.size,
458                            backups.inc_size,
459                            backups.parts
460                    ORDER BY $order
461            };
462            my $sth = $dbh->prepare( $sql );
463            my @ret;
464            $sth->execute();
465    
466            while ( my $row = $sth->fetchrow_hashref() ) {
467                    $row->{'age'} = sprintf("%0.1f", ( $row->{'age'} / 86400 ) );
468                    #$row->{'age'} = sprintf("%0.1f", ( (time() - $row->{'date'}) / 86400 ) );
469                    $row->{'size'} = sprintf("%0.2f", $row->{'size'} / 1024 / 1024);
470    
471                    # do some cluster calculation (approximate) and convert to kB
472                    $row->{'inc_size'} = int(($row->{'inc_size'} + 1023 ) / ( 2 * 1024 ) * 2);
473                    push @ret, $row;
474            }
475                
476        if ($addForm)          return @ret;      
477          {  }
478    
479    sub displayBackupsGrid($) {
480    
481            my $param = shift;
482    
483            my $retHTML .= q{
484                    <form id="forma" method="POST" action="}.$MyURL.q{?action=burn">
485            };
486    
487              $retHTML .= <<EOF3;          $retHTML .= <<'EOF3';
488  <script language="javascript" type="text/javascript">  <style type="text/css">
489  <!--  <!--
490    DIV#fixedBox {
491            position: absolute;
492            top: 50em;
493            left: -24%;
494            padding: 0.5em;
495            width: 20%;
496            background-color: #E0F0E0;
497            border: 1px solid #00C000;
498    }
499    
500      function checkAll(location)  DIV#fixedBox, DIV#fixedBox INPUT, DIV#fixedBox TEXTAREA {
501      {          font-size: 10pt;
502        for (var i=0;i<document.forma.elements.length;i++)  }
503        {  
504          var e = document.forma.elements[i];  FORM>DIV#fixedBox {
505          if ((e.checked || !e.checked) && e.name != \'all\') {          position: fixed !important;
506              if (eval("document.forma."+location+".checked")) {          left: 0.5em !important;
507                  e.checked = true;          top: auto !important;
508              } else {          bottom: 1em !important;
509                  e.checked = false;          width: 15% !important;
510              }  }
511          }  
512        }  DIV#fixedBox INPUT[type=text], DIV#fixedBox TEXTAREA {
513      }          border: 1px solid #00C000;
514  //-->  }
515  </script>        
516  EOF3  DIV#fixedBox #note {
517                $retHTML .= q{<form name="forma" method="POST" action="}."$MyURL"."?action=burn\"";          display: block;
518                $retHTML.= q{<input type="hidden" value="burn" name="action">};          width: 100%;
519                $retHTML .= q{<input type="hidden" value="results" name="search_results">};  }
520          }  
521        $retHTML .= "<table style=\"fview\">";  DIV#fixedBox #submitBurner {
522        $retHTML .= "<tr> ";          display: block;
523        if ($addForm)          width: 100%;
524          {          margin-top: 0.5em;
525              $retHTML .= "<td class=\"tableheader\"><input type=\"checkbox\" name=\"allFiles\" onClick=\"checkAll('allFiles');\"></td>";          cursor: pointer;
526          }  }
527        $retHTML .=  "<td class=\"tableheader\">Host</td> <td class=\"tableheader\">Backup no</td> <td class=\"tableheader\">Type</td> <td class=\"tableheader\">date</td></tr>";  
528        my @backups = getBackupsNotBurned();  * HTML {
529        my $backup;          overflow-y: hidden;
530    }
531        if ($addForm)  
532          {  * HTML BODY {
533              $retHTML .= "<tr>";          overflow-y: auto;
534              $retHTML .= "<td colspan=7 style=\"tableheader\">";          height: 100%;
535              $retHTML .= "<input type=\"submit\" value=\"Burn selected backups on medium\" name=\"submitBurner\">";          font-size: 100%;
536              $retHTML .= "</td>";  }
537              $retHTML .= "</tr>";  
538                * HTML DIV#fixedBox {
539          }          position: absolute;
540        foreach $backup(@backups)  }
541          {  
542              my $ftype = "";  #mContainer, #gradient, #mask, #progressIndicator {
543                        display: block;
544              $retHTML .= "<tr>";          width: 100%;
545              if ($addForm)          font-size: 10pt;
546                {          font-weight: bold;
547                    $retHTML .= "<td class=\"fview\"> <input type=\"checkbox\" name=\"fcb"          text-align: center;
548                      .$backup->{'hostid'}."_".$backup->{'backupno'}          vertical-align: middle;
549                    ."\" value=\"".$backup->{'hostid'}."_".$backup->{'backupno'}."\"> </td>";          padding: 1px;
550                }      }
551                
552              $retHTML .= "<td class=\"fviewborder\">" . $backup->{'host'} . "</td>";  #gradient, #mask, #progressIndicator {
553              $retHTML .= "<td class=\"fviewborder\">" . $backup->{'backupno'} . "</td>";          left: 0;
554              $retHTML .= "<td class=\"fviewborder\">" . $backup->{'type'} . "</td>";          border-width: 1px;
555              $retHTML .= "<td class=\"fviewborder\">" . $backup->{'date'} . "<td>";          border-style: solid;
556              $retHTML .= "</tr>";          border-color: #000000;
557          }          color: #404040;
558        $retHTML .= "</table>";          margin: 0.4em;
559        if ($addForm)          position: absolute;
560         {          margin-left: -1px;
561             $retHTML .= "</form>";          margin-top: -1px;
562         }          margin-bottom: -1px;
563                  overflow: hidden;
564        return $retHTML;  }
565      
566      #mContainer {
567    }                display: block;
568            position: relative;
569  sub displayGrid($$)          padding: 0px;
570    {          margin-top: 0.4em;
571        my ($where, $addForm) = @_;          margin-bottom: 0.5em;
572        my $retHTML = "";  }
573          
574        if ($addForm)  #gradient {
575          {          z-index: 1;
576        $retHTML .= <<EOF3;          background-color: #FFFF00;
577  <script language="javascript" type="text/javascript">  }
578    
579    #mask {
580            z-index: 2;
581            background-color: #FFFFFF;
582    }
583    
584    #progressIndicator {
585            z-index: 3;
586            background-color: transparent;
587    }
588    
589    #parts {
590            padding: 0.4em;
591            display: none;
592            width: 100%;
593            font-size: 80%;
594            color: #ff0000;
595            text-align: center;
596    }
597    -->
598    </style>
599    <script type="text/javascript">
600  <!--  <!--
601    
602      function checkAll(location)  var debug_div = null;
603      {  EOF3
604        for (var i=0;i<document.forma.elements.length;i++)  
605        {          # take maximum archive size from configuration
606          var e = document.forma.elements[i];          $retHTML .= 'var media_size = '. $Conf{MaxArchiveSize} .';';
607          if ((e.checked || !e.checked) && e.name != \'all\') {  
608              if (eval("document.forma."+location+".checked")) {          $retHTML .= <<'EOF3';
609                  e.checked = true;  
610              } else {  function debug(msg) {
611                  e.checked = false;          return; // Disable debugging
612              }  
613          }          if (! debug_div) debug_div = document.getElementById('debug');
614        }  
615      }          // this will create debug div if it doesn't exist.
616            if (! debug_div) {
617                    debug_div = document.createElement('div');
618                    if (document.body) document.body.appendChild(debug_div);
619                    else debug_div = null;
620            }
621            if (debug_div) {
622                    debug_div.appendChild(document.createTextNode(msg));
623                    debug_div.appendChild(document.createElement("br"));
624            }
625    }
626    
627    
628    var element_id_cache = Array();
629    
630    function element_id(name,element) {
631            if (! element_id_cache[name]) {
632                    element_id_cache[name] = self.document.getElementById(name);
633            }
634            return element_id_cache[name];
635    }
636    
637    function checkAll(location) {
638            var f = element_id('forma') || null;
639            if (!f) return false;
640    
641            var len = f.elements.length;
642            var check_all = element_id('allFiles');
643            var suma = check_all.checked ? (parseInt(f.elements['totalsize'].value) || 0) : 0;
644    
645            for (var i = 0; i < len; i++) {
646                    var e = f.elements[i];
647                    if (e.name != 'all' && e.name.substr(0, 3) == 'fcb') {
648                            if (check_all.checked) {
649                                    if (e.checked) continue;
650                                    var el = element_id("fss" + e.name.substr(3));
651                                    var size = parseInt(el.value) || 0;
652                                    debug('suma: '+suma+' size: '+size);
653                                    if ((suma + size) < media_size) {
654                                            suma += size;
655                                            e.checked = true;
656                                    } else {
657                                            break;
658                                    }
659                            } else {
660                                    e.checked = false;
661                            }
662                    }
663            }
664            update_sum(suma);
665    }
666    
667    function update_sum(suma, suma_disp) {
668            if (! suma_disp) suma_disp = suma;
669            element_id('forma').elements['totalsize'].value = suma_disp;
670            pbar_set(suma, media_size);
671            debug('total size: ' + suma);
672    }
673    
674    function sumiraj(e) {
675            var suma = parseInt(element_id('forma').elements['totalsize'].value) || 0;
676            var len = element_id('forma').elements.length;
677            if (e) {
678                    var size = parseInt( element_id("fss" + e.name.substr(3)).value);
679                    if (e.checked) {
680                            suma += size;
681                    } else {
682                            suma -= size;
683                    }
684    
685                    var parts = parseInt( element_id("prt" + e.name.substr(3)).value);
686                    if (suma > media_size && suma == size && parts > 1) {
687                            element_id("parts").innerHTML = "This will take "+parts+" mediums!";
688                            element_id("parts").style.display = 'block';
689                            update_sum(media_size, suma);
690                            suma = media_size;
691                            return suma;
692                    } else {
693                            element_id("parts").style.display = 'none';
694                    }
695    
696                    if (suma < 0) suma = 0;
697            } else {
698                    suma = 0;
699                    for (var i = 0; i < len; i++) {
700                            var e = element_id('forma').elements[i];
701                            if (e.name != 'all' && e.checked && e.name.substr(0,3) == 'fcb') {
702                                    var el = element_id("fss" + e.name.substr(3));
703                                    if (el && el.value) suma += parseInt(el.value) || 0;
704                            }
705                    }
706            }
707            update_sum(suma);
708            return suma;
709    }
710    
711    /* progress bar */
712    
713    var _pbar_width = null;
714    var _pbar_warn = 10;    // change color in last 10%
715    
716    function pbar_reset() {
717            element_id("mask").style.left = "0px";
718            _pbar_width = element_id("mContainer").offsetWidth - 2;
719            element_id("mask").style.width = _pbar_width + "px";
720            element_id("mask").style.display = "block";
721            element_id("progressIndicator").style.zIndex  = 10;
722            element_id("progressIndicator").innerHTML = "0";
723    }
724    
725    function dec2hex(d) {
726            var hch = '0123456789ABCDEF';
727            var a = d % 16;
728            var q = (d - a) / 16;
729            return hch.charAt(q) + hch.charAt(a);
730    }
731    
732    function pbar_set(amount, max) {
733            debug('pbar_set('+amount+', '+max+')');
734    
735            if (_pbar_width == null) {
736                    var _mc = element_id("mContainer");
737                    if (_pbar_width == null) _pbar_width = parseInt(_mc.offsetWidth ? (_mc.offsetWidth - 2) : 0) || null;
738                    if (_pbar_width == null) _pbar_width = parseInt(_mc.clientWidth ? (_mc.clientWidth + 2) : 0) || null;
739                    if (_pbar_width == null) _pbar_width = 0;
740            }
741    
742            var pcnt = Math.floor(amount * 100 / max);
743            var p90 = 100 - _pbar_warn;
744            var pcol = pcnt - p90;
745            if (Math.round(pcnt) <= 100) {
746                    if (pcol < 0) pcol = 0;
747                    var e = element_id("submitBurner");
748                    debug('enable_button');
749                    e.disabled = false;
750                    var a = e.getAttributeNode('disabled') || null;
751                    if (a) e.removeAttributeNode(a);
752            } else {
753                    debug('disable button');
754                    pcol = _pbar_warn;
755                    var e = element_id("submitBurner");
756                    if (!e.disabled) e.disabled = true;
757            }
758            var col_g = Math.floor((_pbar_warn - pcol) * 255 / _pbar_warn);
759            var col = '#FF' + dec2hex(col_g) + '00';
760    
761            //debug('pcol: '+pcol+' g:'+col_g+' _pbar_warn:'+ _pbar_warn + ' color: '+col);
762            element_id("gradient").style.backgroundColor = col;
763    
764            element_id("progressIndicator").innerHTML = pcnt + '%';
765            //element_id("progressIndicator").innerHTML = amount;
766    
767            element_id("mask").style.clip = 'rect(' + Array(
768                    '0px',
769                    element_id("mask").offsetWidth + 'px',
770                    element_id("mask").offsetHeight + 'px',
771                    Math.round(_pbar_width * amount / max) + 'px'
772            ).join(' ') + ')';
773    }
774    
775    if (!self.body) self.body = new Object();
776    self.onload = self.document.onload = self.body.onload = function() {
777            //pbar_reset();
778            sumiraj();
779    };
780    
781    // -->
782    </script>
783    <div id="fixedBox">
784    
785    Size: <input type="text" name="totalsize" size="7" readonly="readonly" style="text-align:right;" value="0" /> kB
786    
787  //-->  <div id="mContainer">
788  </script>                <div id="gradient">&nbsp;</div>
789            <div id="mask">&nbsp;</div>
790            <div id="progressIndicator">0%</div>
791    </div>
792    <br/>
793    
794    <div id="parts">&nbsp;</div>
795    
796    Note:
797    <textarea name="note" cols="10" rows="5" id="note"></textarea>
798    
799    <input type="submit" id="submitBurner" value="Burn selected" name="submitBurner" />
800    
801    </div>
802    <!--
803    <div id="debug" style="float: right; width: 10em; border: 1px #ff0000 solid; background-color: #ffe0e0; -moz-opacity: 0.7;">
804    no debug output yet
805    </div>
806    -->
807  EOF3  EOF3
808                $retHTML .= q{<form name="forma" method="POST" action="}."$MyURL"."?action=burn\"";          $retHTML .= q{
809                $retHTML.= q{<input type="hidden" value="burn" name="action">};                          <input type="hidden" value="burn" name="action">
810                $retHTML .= q{<input type="hidden" value="results" name="search_results">};                          <input type="hidden" value="results" name="search_results">
811          }                          <table style="fview" border="0" cellspacing="0" cellpadding="2">
812        $retHTML .= "<table style=\"fview\">";                          <tr class="tableheader">
813        $retHTML .= "<tr> ";                          <td class="tableheader">
814        if ($addForm)                                  <input type="checkbox" name="allFiles" id="allFiles" onClick="checkAll('allFiles');">
815          {                          </td>
816              $retHTML .= "<td class=\"tableheader\"><input type=\"checkbox\" name=\"allFiles\" onClick=\"checkAll('allFiles');\"></td>";          } .
817          }                  sort_header($param, 'Share', 'share', 'center') .
818        $retHTML .=  "<td class=\"tableheader\">Host</td> <td class=\"tableheader\">Name</td> <td class=\"tableheader\">Type</td> <td class=\"tableheader\">backup no.</td> <td class=\"tableheader\">size</td> <td class=\"tableheader\">date</td>  <td class=\"tableheader\">Media</td></tr>";                  sort_header($param, '#', 'num', 'center') .
819        my @files = getFiles($where);          qq{
820        my $file;                          <td align="center">Type</td>
821            } .
822        if ($addForm)                  sort_header($param, 'Date', 'date', 'center') .
823          {                  sort_header($param, 'Age/days', 'age', 'center') .
824              $retHTML .= "<tr>";                  sort_header($param, 'Size/Mb', 'size', 'center') .
825              $retHTML .= "<td colspan=7 style=\"tableheader\">";                  sort_header($param, 'gzip size/Kb', 'incsize', 'center') .
826              $retHTML .= "<input type=\"submit\" value=\"Burn selected files on medium\" name=\"submitBurner\">";          qq{
827              $retHTML .= "</td>";                          </tr>
828              $retHTML .= "</tr>";          };
829                
830          }          my @color = (' bgcolor="#e0e0e0"', '');
831        foreach $file(@files)  
832          {          my $i = 0;
833              my $ftype = "";          my $host = '';
834                
835              if ($file->{'type'} == BPC_FTYPE_DIR)          foreach my $backup ( getBackupsNotBurned($param) ) {
836                {  
837                    $ftype = "dir";                  if ($host ne $backup->{'host'}) {
838                }                          $i++;
839              else                          $host = $backup->{'host'};
840                {                  }
841                    $ftype = "file";                  my $ftype = "";
842                }  
843              $retHTML .= "<tr>";                  my $checkbox_key = $backup->{'hostid'}. '_' .$backup->{'backupnum'} . '_' . $backup->{'id'};
844              if ($addForm)  
845                {                  $retHTML .=
846                    $retHTML .= "<td class=\"fview\"> <input type=\"checkbox\" name=\"fcb"                          '<tr' . $color[$i %2 ] . '>
847                      .$file->{'id'}                          <td class="fview">';
848                    ."\" value=\"".$file->{'id'}."\"> </td>";  
849                }                      if (($backup->{'inc_size'} || 0) > 0) {
850                                        $retHTML .= '
851              $retHTML .= "<td class=\"fviewborder\">" . $file->{'hname'} ."</td>";                          <input type="checkbox" name="fcb' . $checkbox_key . '" value="' . $checkbox_key . '" onClick="sumiraj(this);">';
852              $retHTML .= "<td class=\"fviewborder\">" . $file->{'fname'} . "</td>";                  }
853              $retHTML .= "<td class=\"fviewborder\">" . $ftype . "</td>";  
854              $retHTML .= "<td class=\"fviewborder\">" . $file->{'backupno'} . "</td>";                  $retHTML .=
855              $retHTML .= "<td class=\"fviewborder\">" . $file->{'size'} . "</td>";                          '</td>' .
856              $retHTML .= "<td class=\"fviewborder\">" . $file->{'date'} . "</td>";                          '<td align="right">' . $backup->{'host'} . ':' . $backup->{'share'} . '</td>' .
857              $retHTML .= "<td class=\"fviewborder\">" . $file->{'dvd'} . "</td>";                          '<td align="center">' . $backup->{'backupnum'} . '</td>' .
858              $retHTML .= "</tr>";                          '<td align="center">' . $backup->{'type'} . '</td>' .
859          }                          '<td align="center">' . epoch_to_iso( $backup->{'date'} ) . '</td>' .
860        $retHTML .= "</table>";                          '<td align="center">' . $backup->{'age'} . '</td>' .
861        if ($addForm)                          '<td align="right">' . $backup->{'size'} . '</td>' .
862         {                          '<td align="right">' . $backup->{'inc_size'} .
863             $retHTML .= "</form>";                          '<input type="hidden" id="fss'.$checkbox_key .'" value="'. $backup->{'inc_size'} .'"></td>' .
864         }                          '<input type="hidden" id="prt'.$checkbox_key .'" value="'. $backup->{'parts'} .'"></td>' .
865    
866                            "</tr>\n";
867            }
868    
869            $retHTML .= "</table>";
870            $retHTML .= "</form>";
871                
872        return $retHTML;          return $retHTML;
873    }  }      
874    
875    sub displayGrid($) {
876            my ($param) = @_;
877    
878            my $offset = $param->{'offset'};
879            my $hilite = $param->{'search_filename'};
880    
881            my $retHTML = "";
882    
883            my $start_t = time();
884    
885            my ($results, $files);
886            if ($param->{'use_hest'} && length($hilite) > 0) {
887                    ($results, $files) = getFilesHyperEstraier($param);
888            } else {
889                    ($results, $files) = getFiles($param);
890            }
891    
892            my $dur_t = time() - $start_t;
893            my $dur = sprintf("%0.4fs", $dur_t);
894    
895            my ($from, $to) = (($offset * $on_page) + 1, ($offset * $on_page) + $on_page);
896    
897            if ($results <= 0) {
898                    $retHTML .= qq{
899                            <p style="color: red;">No results found...</p>
900                    };
901                    return $retHTML;
902            } else {
903                    # DEBUG
904                    #use Data::Dumper;
905                    #$retHTML .= '<pre>' . Dumper($files) . '</pre>';
906            }
907    
908    
909            $retHTML .= qq{
910            <div>
911            Found <b>$results files</b> showing <b>$from - $to</b> (took $dur)
912            </div>
913            <table style="fview" width="100%" border="0" cellpadding="2" cellspacing="0">
914                    <tr class="fviewheader">
915                    <td></td>
916            };
917    
918            sub sort_header($$$$) {
919                    my ($param, $display, $name, $align) = @_;
920    
921                    my ($sort_what, $sort_dir) = split(/_/,$param->{'sort'},2);
922    
923                    my $old_sort = $param->{'sort'};
924    
925                    my $html = qq{<td align="$align"};
926                    if (lc($sort_what) eq lc($name)) {
927                            my $dir = lc($sort_dir);
928                            $dir =~ tr/ad/da/;
929                            $param->{'sort'} = $name . '_' . $dir;
930                            $html .= ' style="border: 1px solid #808080;"';
931                    } else {
932                            $param->{'sort'} = $name . '_a';
933                    }
934                    $html .= '<a href="' . page_uri($param) . '">' . $display . '</a></td>';
935                    $param->{'sort'} = $old_sort;
936    
937                    return $html;
938            }
939    
940            $retHTML .=
941                    sort_header($param, 'Share', 'share', 'center') .
942                    sort_header($param, 'Type and Name', 'path', 'center') .
943                    sort_header($param, '#', 'num', 'center') .
944                    sort_header($param, 'Size', 'size', 'center') .
945                    sort_header($param, 'Date', 'date', 'center');
946    
947            $retHTML .= qq{
948                    <td align="center">Media</td>
949                    </tr>
950            };
951    
952            my $file;
953    
954            sub hilite_html($$) {
955                    my ($html, $search) = @_;
956                    $html =~ s#($search)#<b>$1</b>#gis;
957                    return $html;
958            }
959    
960            sub restore_link($$$$$$) {
961                    my $type = shift;
962                    my $action = 'RestoreFile';
963                    $action = 'browse' if (lc($type) eq 'dir');
964                    return sprintf(qq{<a href="?action=%s&host=%s&num=%d&share=%s&dir=%s">%s</a>}, $action, @_);
965            }
966    
967            my $sth_archived;
968            my %archived_cache;
969    
970            sub check_archived($$$) {
971                    my ($host, $share, $num) = @_;
972    
973                    if (my $html = $archived_cache{"$host $share $num"}) {
974                            return $html;
975                    }
976    
977                    $sth_archived ||= $dbh->prepare(qq{
978                            select
979                                    dvd_nr, note,
980                                    count(archive_burned.copy) as copies
981                            from archive
982                            inner join archive_burned on archive_burned.archive_id = archive.id
983                            inner join archive_backup on archive.id = archive_backup.archive_id
984                            inner join backups on backups.id = archive_backup.backup_id
985                            inner join hosts on hosts.id = backups.hostid
986                            inner join shares on shares.id = backups.shareid
987                            where hosts.name = ? and shares.name = ? and backups.num = ?
988                            group by dvd_nr, note
989                    });
990    
991                    my @mediums;
992    
993                    $sth_archived->execute($host, $share, $num);
994                    while (my $row = $sth_archived->fetchrow_hashref()) {
995                            push @mediums, '<abbr title="' .
996                                    $row->{'note'} .
997                                    ' [' . $row->{'copies'} . ']' .
998                                    '">' .$row->{'dvd_nr'} .
999                                    '</abbr>';
1000                    }
1001    
1002                    my $html = join(", ",@mediums);
1003                    $archived_cache{"$host $share $num"} = $html;
1004                    return $html;
1005            }
1006    
1007            my $i = $offset * $on_page;
1008    
1009            foreach $file (@{ $files }) {
1010                    $i++;
1011    
1012                    my $typeStr  = BackupPC::Attrib::fileType2Text(undef, $file->{'type'});
1013                    $retHTML .= qq{<tr class="fviewborder">};
1014    
1015                    $retHTML .= qq{<td class="fviewborder">$i</td>};
1016    
1017                    $retHTML .=
1018                            qq{<td class="fviewborder" align="right">} . $file->{'hname'} . ':' . $file->{'sname'} . qq{</td>} .
1019                            qq{<td class="fviewborder"><img src="$Conf{CgiImageDirURL}/icon-$typeStr.gif" alt="$typeStr" align="middle">&nbsp;} . hilite_html( $file->{'filepath'}, $hilite ) . qq{</td>} .
1020                            qq{<td class="fviewborder" align="center">} . restore_link( $typeStr, ${EscURI( $file->{'hname'} )}, $file->{'backupnum'}, ${EscURI( $file->{'sname'})}, ${EscURI( $file->{'filepath'} )}, $file->{'backupnum'} ) . qq{</td>} .
1021                            qq{<td class="fviewborder" align="right">} . $file->{'size'} . qq{</td>} .
1022                            qq{<td class="fviewborder">} . epoch_to_iso( $file->{'date'} ) . qq{</td>} .
1023                            qq{<td class="fviewborder">} . check_archived( $file->{'hname'}, $file->{'sname'}, $file->{'backupnum'} ) . qq{</td>};
1024    
1025                    $retHTML .= "</tr>";
1026            }
1027            $retHTML .= "</table>";
1028    
1029            # all variables which has to be transfered
1030            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/) {
1031                    $retHTML .= qq{<INPUT TYPE="hidden" NAME="$n" VALUE="$In{$n}">\n};
1032            }
1033    
1034            my $del = '';
1035            my $max_page = int( $results / $on_page );
1036            my $page = 0;
1037    
1038            sub page_uri($) {
1039                    my $param = shift || die "no param?";
1040    
1041                    my $uri = $MyURL;
1042                    my $del = '?';
1043                    foreach my $k (keys %{ $param }) {
1044                            if ($param->{$k}) {
1045                                    $uri .= $del . $k . '=' . ${EscURI( $param->{$k} )};
1046                                    $del = '&';
1047                            }
1048                    }
1049                    return $uri;
1050            }
1051    
1052            sub page_link($$$) {
1053                    my ($param,$page,$display) = @_;
1054    
1055                    $param->{'offset'} = $page if (defined($page));
1056    
1057                    my $html = '<a href = "' . page_uri($param) . '">' . $display . '</a>';
1058            }
1059    
1060            $retHTML .= '<div style="text-align: center;">';
1061    
1062            if ($offset > 0) {
1063                    $retHTML .= page_link($param, $offset - 1, '&lt;&lt;') . ' ';
1064            }
1065    
1066            while ($page <= $max_page) {
1067                    if ($page == $offset) {
1068                            $retHTML .= $del . '<b>' . ($page + 1) . '</b>';
1069                    } else {
1070                            $retHTML .= $del . page_link($param, $page, $page + 1);
1071                    }
1072    
1073                    if ($page < $offset - $pager_pages && $page != 0) {
1074                            $retHTML .= " ... ";
1075                            $page = $offset - $pager_pages;
1076                            $del = '';
1077                    } elsif ($page > $offset + $pager_pages && $page != $max_page) {
1078                            $retHTML .= " ... ";
1079                            $page = $max_page;
1080                            $del = '';
1081                    } else {
1082                            $del = ' | ';
1083                            $page++;
1084                    }
1085            }
1086    
1087            if ($offset < $max_page) {
1088                    $retHTML .= ' ' . page_link($param, $offset + 1, '&gt;&gt;');
1089            }
1090    
1091            $retHTML .= "</div>";
1092    
1093            return $retHTML;
1094    }
1095    
1096  1;  1;

Legend:
Removed from v.6  
changed lines
  Added in v.225

  ViewVC Help
Powered by ViewVC 1.1.26