/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 129 - (show annotations)
Thu Sep 22 14:25:51 2005 UTC (18 years, 7 months ago) by dpavlin
File size: 20169 byte(s)
checkAll now selects just hosts up to one full media

1 #!/usr/bin/perl
2 package BackupPC::SearchLib;
3
4 use strict;
5 use BackupPC::CGI::Lib qw(:all);
6 use BackupPC::Attrib qw(:all);
7 use DBI;
8 use DateTime;
9 use vars qw(%In $MyURL);
10 use Time::HiRes qw/time/;
11
12 my $on_page = 100;
13 my $pager_pages = 10;
14
15 my $dsn = $Conf{SearchDSN};
16 my $db_user = $Conf{SearchUser} || '';
17
18 my $hest_index_path = $Conf{HyperEstraierIndex};
19
20 my $dbh;
21
22 sub get_dbh {
23 $dbh ||= DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );
24 return $dbh;
25 }
26
27 sub getUnits() {
28 my @ret;
29
30 my $dbh = get_dbh();
31 my $sth = $dbh->prepare(qq{
32 SELECT
33 shares.id as id,
34 hosts.name || ':' || shares.name as share
35 FROM shares
36 JOIN hosts on hostid = hosts.id
37 ORDER BY share
38 } );
39 $sth->execute();
40 push @ret, { 'id' => '', 'share' => '-'}; # dummy any
41
42 while ( my $row = $sth->fetchrow_hashref() ) {
43 push @ret, $row;
44 }
45 return @ret;
46 }
47
48 sub epoch_to_iso {
49 my $t = shift || return;
50 my $iso = BackupPC::Lib::timeStamp(undef, $t);
51 $iso =~ s/\s/ /g;
52 return $iso;
53 }
54
55 sub dates_from_form($) {
56 my $param = shift || return;
57
58 sub mk_epoch_date($$) {
59 my ($name,$suffix) = @_;
60
61 my $yyyy = $param->{ $name . '_year_' . $suffix} || return undef;
62 my $mm .= $param->{ $name . '_month_' . $suffix} ||
63 ( $suffix eq 'from' ? 1 : 12);
64 my $dd .= $param->{ $name . '_day_' . $suffix} ||
65 ( $suffix eq 'from' ? 1 : 31);
66
67 $yyyy =~ s/\D//g;
68 $mm =~ s/\D//g;
69 $dd =~ s/\D//g;
70
71 my $dt = new DateTime(
72 year => $yyyy,
73 month => $mm,
74 day => $dd
75 );
76 print STDERR "mk_epoch_date($name,$suffix) [$yyyy-$mm-$dd] = " . $dt->ymd . " " . $dt->hms . "\n";
77 return $dt->epoch || 'NULL';
78 }
79
80 my @ret = (
81 mk_epoch_date('search_backup', 'from'),
82 mk_epoch_date('search_backup', 'to'),
83 mk_epoch_date('search', 'from'),
84 mk_epoch_date('search', 'to'),
85 );
86
87 return @ret;
88
89 }
90
91
92 sub getWhere($) {
93 my $param = shift || return;
94
95 my ($backup_from, $backup_to, $files_from, $files_to) = dates_from_form($param);
96
97 my @conditions;
98 push @conditions, qq{ backups.date >= $backup_from } if ($backup_from);
99 push @conditions, qq{ backups.date <= $backup_to } if ($backup_to);
100 push @conditions, qq{ files.date >= $files_from } if ($files_from);
101 push @conditions, qq{ files.date <= $files_to } if ($files_to);
102
103 print STDERR "backup: $backup_from - $backup_to files: $files_from - $files_to cond:" . join(" | ",@conditions);
104
105 push( @conditions, ' files.shareid = ' . $param->{'search_share'} ) if ($param->{'search_share'});
106 push (@conditions, " upper(files.path) LIKE upper('%".$param->{'search_filename'}."%')") if ($param->{'search_filename'});
107
108 return join(" and ", @conditions);
109 }
110
111
112 sub getFiles($) {
113 my ($param) = @_;
114
115 my $offset = $param->{'offset'} || 0;
116 $offset *= $on_page;
117
118 my $dbh = get_dbh();
119
120 my $sql_cols = qq{
121 files.id AS fid,
122 hosts.name AS hname,
123 shares.name AS sname,
124 files.backupnum AS backupnum,
125 files.path AS filepath,
126 files.date AS date,
127 files.type AS type,
128 files.size AS size
129 };
130
131 my $sql_from = qq{
132 FROM files
133 INNER JOIN shares ON files.shareID=shares.ID
134 INNER JOIN hosts ON hosts.ID = shares.hostID
135 INNER JOIN backups ON backups.num = files.backupnum and backups.hostID = hosts.ID AND backups.shareID = files.shareID
136 };
137
138 my $sql_where;
139 my $where = getWhere($param);
140 $sql_where = " WHERE ". $where if ($where);
141
142 my $sql_order = qq{
143 ORDER BY files.date
144 LIMIT $on_page
145 OFFSET ?
146 };
147
148 my $sql_count = qq{ select count(files.id) $sql_from $sql_where };
149 my $sql_results = qq{ select $sql_cols $sql_from $sql_where $sql_order };
150
151 my $sth = $dbh->prepare($sql_count);
152 $sth->execute();
153 my ($results) = $sth->fetchrow_array();
154
155 $sth = $dbh->prepare($sql_results);
156 $sth->execute( $offset );
157
158 if ($sth->rows != $results) {
159 my $bug = "$0 BUG: [[ $sql_count ]] = $results while [[ $sql_results ]] = " . $sth->rows;
160 $bug =~ s/\s+/ /gs;
161 print STDERR "$bug\n";
162 }
163
164 my @ret;
165
166 while (my $row = $sth->fetchrow_hashref()) {
167 push @ret, $row;
168 }
169
170 $sth->finish();
171 return ($results, \@ret);
172 }
173
174 sub getHyperEstraier_url($) {
175 my ($use_hest) = @_;
176
177 return unless $use_hest;
178
179 use HyperEstraier;
180 my ($index_path, $index_node_url);
181
182 if ($use_hest =~ m#^http://#) {
183 $index_node_url = $use_hest;
184 } else {
185 $index_path = $TopDir . '/' . $index_path;
186 $index_path =~ s#//#/#g;
187 }
188 return ($index_path, $index_node_url);
189 }
190
191 sub getFilesHyperEstraier($) {
192 my ($param) = @_;
193
194 my $offset = $param->{'offset'} || 0;
195 $offset *= $on_page;
196
197 die "no index_path?" unless ($hest_index_path);
198
199 use HyperEstraier;
200
201 my ($index_path, $index_node_url) = getHyperEstraier_url($hest_index_path);
202
203 # open the database
204 my $db;
205 if ($index_path) {
206 $db = HyperEstraier::Database->new();
207 $db->open($index_path, $HyperEstraier::ESTDBREADER);
208 } elsif ($index_node_url) {
209 $db ||= HyperEstraier::Node->new($index_node_url);
210 $db->set_auth('admin', 'admin');
211 } else {
212 die "BUG: unimplemented";
213 }
214
215 # create a search condition object
216 my $cond = HyperEstraier::Condition->new();
217
218 my $q = $param->{'search_filename'};
219 my $shareid = $param->{'search_share'};
220
221 if (length($q) > 0) {
222 # exact match
223 $cond->add_attr("filepath ISTRINC $q");
224
225 $q =~ s/(.)/$1 /g;
226 # set the search phrase to the search condition object
227 $cond->set_phrase($q);
228 }
229
230 my ($backup_from, $backup_to, $files_from, $files_to) = dates_from_form($param);
231
232 $cond->add_attr("backup_date NUMGE $backup_from") if ($backup_from);
233 $cond->add_attr("backup_date NUMLE $backup_to") if ($backup_to);
234
235 $cond->add_attr("date NUMGE $files_from") if ($files_from);
236 $cond->add_attr("date NUMLE $files_to") if ($files_to);
237
238 $cond->add_attr("shareid NUMEQ $shareid") if ($shareid);
239
240 # $cond->set_max( $offset + $on_page );
241 $cond->set_options( $HyperEstraier::Condition::SURE );
242 $cond->set_order( 'date NUMA' );
243
244 # get the result of search
245 my @res;
246 my ($result, $hits);
247
248 if ($index_path) {
249 $result = $db->search($cond, 0);
250 $hits = $result->size;
251 } elsif ($index_node_url) {
252 $result = $db->search($cond, 0);
253 $hits = $result->doc_num;
254 } else {
255 die "BUG: unimplemented";
256 }
257
258 # for each document in result
259 for my $i ($offset .. ($offset + $on_page - 1)) {
260 last if ($i >= $hits);
261
262 my $doc;
263 if ($index_path) {
264 my $id = $result->get($i);
265 $doc = $db->get_doc($id, 0);
266 } elsif ($index_node_url) {
267 $doc = $result->get_doc($i);
268 } else {
269 die "BUG: unimplemented";
270 }
271
272 my $row;
273 foreach my $c (qw/fid hname sname backupnum fiilename filepath date type size/) {
274 $row->{$c} = $doc->attr($c);
275 }
276 push @res, $row;
277 }
278
279 return ($hits, \@res);
280 }
281
282 sub getGzipName($$$)
283 {
284 my ($host, $share, $backupnum) = @_;
285 my $ret = $Conf{GzipSchema};
286
287 $share =~ s/\//_/g;
288 $ret =~ s/\\h/$host/ge;
289 $ret =~ s/\\s/$share/ge;
290 $ret =~ s/\\n/$backupnum/ge;
291
292 return $ret;
293
294 }
295
296 sub getBackupsNotBurned() {
297
298 my $dbh = get_dbh();
299
300 my $sql = q{
301 SELECT
302 backups.hostID AS hostID,
303 hosts.name AS host,
304 shares.name AS share,
305 backups.id AS backupnum,
306 backups.type AS type,
307 backups.date AS date,
308 backups.size AS size
309 FROM backups
310 INNER JOIN shares ON backups.shareID=shares.ID
311 INNER JOIN hosts ON backups.hostID = hosts.ID
312 LEFT OUTER JOIN archive_backup ON archive_backup.backup_id = backups.id AND archive_backup.backup_id IS NULL
313 WHERE backups.size > 0
314 GROUP BY
315 backups.hostID,
316 hosts.name,
317 shares.name,
318 backups.num,
319 backups.shareid,
320 backups.id,
321 backups.type,
322 backups.date,
323 backups.size
324 ORDER BY backups.date
325 };
326 my $sth = $dbh->prepare( $sql );
327 my @ret;
328 $sth->execute();
329
330 while ( my $row = $sth->fetchrow_hashref() ) {
331 $row->{'age'} = sprintf("%0.1f", ( (time() - $row->{'date'}) / 86400 ) );
332 $row->{'size'} = sprintf("%0.2f", $row->{'size'} / 1024 / 1024);
333 my (undef,undef,undef,undef,undef,undef,undef,$fs_size,undef,undef,undef,undef,undef) =
334 stat( $Conf{InstallDir}.'/'.$Conf{GzipTempDir}.'/'.
335 getGzipName($row->{'host'}, $row->{share}, $row->{'backupnum'}));
336 $row->{'fs_size'} = $fs_size;
337 push @ret, $row;
338 }
339
340 return @ret;
341 }
342
343 sub displayBackupsGrid() {
344
345 my $retHTML .= q{
346 <form id="forma" method="POST" action=};
347 $retHTML .= "\"".$MyURL."\"";
348 $retHTML .= q{?action=burn>
349 };
350
351 $retHTML .= <<'EOF3';
352 <style>
353 <!--
354
355 div#fixedBox {
356 position: absolute;
357 bottom: 1em;
358 left: 0.5em;
359 padding: 0.5em;
360 width: 10em;
361 background: #e0f0e0;
362 border: 1px solid #00ff00;
363 }
364 @media screen {
365 div#fixedBox {
366 position: fixed;
367 }
368 /* Don't do this at home */
369 * html {
370 overflow-y: hidden;
371 }
372 * html body {
373 overflow-y: auto;
374 height: 100%;
375 padding: 0 1em 0 12em;
376 font-size: 100%;
377 }
378 * html div#fixedBox {
379 position: absolute;
380 }
381 /* All done. */
382 }
383
384 #mContainer {
385 position: relative;
386 width: 100%;
387 height: 1.1em;
388 padding: 0px;
389 border: 1px solid #000000;
390 }
391
392 #gradient {
393 position: absolute;
394 top: 0px;
395 left: 0px;
396 width: 100%;
397 height: 100%;
398 display: block;
399 background-color: #ffff00;
400 }
401
402 #mask {
403 position: absolute;
404 top: 0px;
405 left: 0px;
406 width: 100%;
407 height: 100%;
408 display: block;
409 font-size: 1px;
410 background-color: #FFFFFF;
411 overflow: hidden;
412 }
413
414 #progressIndicator {
415 position: absolute;
416 top: 0px;
417 left: 0px;
418 width: 100%;
419 height: 100%;
420 display: block;
421 font-weight: bold;
422 color: #404040;
423 font-size: 10pt;
424 text-align: center;
425 }
426
427 -->
428 </style>
429 <script language="javascript" type="text/javascript">
430 <!--
431
432 var debug_div = null;
433 var media_size = 4400 * 1024;
434
435 function debug(msg) {
436 // return; // Disable debugging
437
438 if (! debug_div) debug_div = document.getElementById('debug');
439
440 // this will create debug div if it doesn't exist.
441 if (! debug_div) {
442 debug_div = document.createElement('div');
443 if (document.body) document.body.appendChild(debug_div);
444 else debug_div = null;
445 }
446 if (debug_div) {
447 debug_div.appendChild(document.createTextNode(msg));
448 debug_div.appendChild(document.createElement("br"));
449 }
450 }
451
452
453 var element_id_cache = Array();
454
455 function element_id(name,element) {
456 if (! element_id_cache[name]) {
457 element_id_cache[name] = self.document.getElementById(name);
458 }
459 return element_id_cache[name];
460 }
461
462 function checkAll(location) {
463 var len = element_id('forma').elements.length;
464 var check_all = element_id('allFiles');
465 var suma = 0;
466
467 for (var i = 0; i < len; i++) {
468
469 var e = element_id('forma').elements[i];
470 if (e.name != 'all' && e.name.substr(0,3) == 'fcb') {
471 if (check_all.checked) {
472 var el = element_id("fss" + e.name.substr(3));
473 var size = parseInt(el.value) || 0;
474 debug('suma: '+suma+' size: '+size);
475 if ((suma + size) < media_size) {
476 suma += size;
477 e.checked = true;
478 } else {
479 break;
480 }
481 } else {
482 e.checked = false;
483 }
484 }
485 }
486 update_sum(suma);
487 }
488
489 function update_sum(suma) {
490 element_id('forma').totalsize.value = suma;
491 pbar_set(suma, media_size);
492 debug('total size: '+suma);
493 }
494
495 function sumiraj(e) {
496 var suma = parseInt(element_id('forma').totalsize.value) || 0;
497 var len = element_id('forma').elements.length;
498 if (e) {
499 var size = parseInt( element_id("fss" + e.name.substr(3)).value );
500 if (e.checked) {
501 suma += size;
502 } else {
503 suma -= size;
504 }
505 } else {
506 suma = 0;
507 for (var i = 0; i < len; i++) {
508 var e = element_id('forma').elements[i];
509 if (e.name != 'all' && e.checked && e.name.substr(0,3) == 'fcb') {
510 var el = element_id("fss" + e.name.substr(3));
511 if (el && el.value) suma += parseInt(el.value) || 0;
512 }
513 }
514 }
515 update_sum(suma);
516 return suma;
517 }
518
519 /* progress bar */
520
521 var _pbar_width = 0;
522 var _pbar_warn = 10; // change color in last 10%
523
524 function pbar_reset() {
525 element_id("mask").style.left = "0px";
526 _pbar_width = element_id("mContainer").offsetWidth - 2;
527 element_id("mask").style.width = _pbar_width + "px";
528 element_id("progressIndicator").style.zIndex = 10;
529 element_id("mask").style.display = "block";
530 element_id("progressIndicator").innerHTML = "0";
531 }
532
533 function dec2hex(d) {
534 var hch="0123456789ABCDEF";
535 var a=d%16;
536 var q=(d-a)/16;
537 return hch.charAt(q)+hch.charAt(a);
538 }
539
540
541 function pbar_set(amount, max) {
542
543 debug('pbar_set( '+amount+' , '+max+' )');
544
545 curWidth = parseInt(element_id("mask").offsetWidth);
546 curLeft = parseInt(element_id("mask").offsetLeft);
547
548
549 var pcnt = Math.floor( amount * 100 / max );
550 var p90 = 100 - _pbar_warn;
551 var pcol = pcnt - p90;
552 if (pcol < _pbar_warn) {
553 if (pcol < 0) pcol = 0;
554 var e = element_id("submitBurner");
555 if (e && e.disabled) {
556 debug('enable_button');
557 var a = e.getAttributeNode('disabled') || null;
558 if (a) e.removeAttributeNode(a);
559 }
560 } else if (pcol > _pbar_warn) {
561 debug('disable button');
562 pcol = _pbar_warn;
563 var e = element_id("submitBurner");
564 if (! e.disabled) e.disabled = true;
565 }
566 var col_g = Math.floor( ( _pbar_warn - pcol ) * 255 / _pbar_warn );
567 var col = '#ff' + dec2hex( col_g ) + '00';
568
569 //debug('pcol: '+pcol+' g:'+col_g+' _pbar_warn:'+ _pbar_warn + ' color: '+col);
570 element_id("gradient").style.backgroundColor = col;
571
572 var size = parseInt( _pbar_width * amount / max );
573
574 curWidth = _pbar_width - size;
575 curLeft = size ;
576
577 //debug('size: '+size+' curWidth '+curWidth+' curLeft: '+curLeft);
578
579 element_id("progressIndicator").innerHTML = pcnt + '%';
580 //element_id("progressIndicator").innerHTML = amount;
581
582 if (curLeft > _pbar_width) {
583 element_id("mask").style.display = "none";
584 return;
585 } else {
586 element_id("mask").style.display = "";
587 }
588
589 //if(parseInt(element_id("mask").offsetWidth)>10)
590 element_id("mask").style.width = curWidth + "px";
591 element_id("mask").style.left = curLeft + "px";
592
593 }
594
595 if (!self.body) self.body = new Object();
596 self.onload = self.document.onload = self.body.onload = function() {
597 pbar_reset();
598 sumiraj();
599 }
600
601 //-->
602 </script>
603 <div id="fixedBox">
604
605 Size:
606 <input type="text" name="totalsize" size="7" readonly>
607
608 <div id="mContainer">
609 <div id="gradient"></div>
610 <div id="mask"></div>
611 <div id="progressIndicator">&nbsp;</div>
612 </div>
613
614 <br/>
615 Note:
616 <br/>
617 <textarea name="note" cols="10" rows="5">
618 </textarea>
619 <br/>
620 <input type="submit" id="submitBurner" value="Burn selected" name="submitBurner">
621
622 </div>
623 <div id="debug" style="float: right; width: 10em; border: 1px #ff0000 solid; background-color: #ffe0e0; -moz-opacity: 0.7;">
624 no debug output yet
625 </div>
626 EOF3
627 $retHTML .= q{
628 <input type="hidden" value="burn" name="action">
629 <input type="hidden" value="results" name="search_results">
630 <table style="fview" border="0" cellspacing="0" cellpadding="2">
631 <tr class="tableheader">
632 <td class="tableheader">
633 <input type="checkbox" name="allFiles" id="allFiles" onClick="checkAll('allFiles');">
634 </td>
635 <td align="center">Share</td>
636 <td align="center">Backup no</td>
637 <td align="center">Type</td>
638 <td align="center">date</td>
639 <td align="center">age/days</td>
640 <td align="center">size/MB</td>
641 <td align="center">gzip size</td>
642 </tr>
643
644 };
645
646 my @color = (' bgcolor="#e0e0e0"', '');
647
648 my $i = 0;
649 my $host = '';
650
651 foreach my $backup ( getBackupsNotBurned() ) {
652
653 if ($host ne $backup->{'host'}) {
654 $i++;
655 $host = $backup->{'host'};
656 }
657 my $ftype = "";
658
659 $retHTML .=
660 '<tr' . $color[$i %2 ] . '>
661 <td class="fview">';
662 # FIXME
663 $backup->{'fs_size'} = int($backup->{'size'} * 1024);
664 if (($backup->{'fs_size'} || 0) > 0) {
665 $retHTML .= '
666 <input type="checkbox" name="fcb' .
667 $backup->{'hostid'}.'_'.$backup->{'backupnum'} .
668 '" value="' . $backup->{'hostid'}.'_'.$backup->{'backupnum'} .
669 '" onClick="sumiraj(this);">';
670 }
671 $retHTML .=
672 '</td>' .
673 '<td align="right">' . $backup->{'host'} . ':' . $backup->{'share'} . '</td>' .
674 '<td align="center">' . $backup->{'backupnum'} . '</td>' .
675 '<td align="center">' . $backup->{'type'} . '</td>' .
676 '<td align="center">' . epoch_to_iso( $backup->{'date'} ) . '</td>' .
677 '<td align="center">' . $backup->{'age'} . '</td>' .
678 '<td align="right">' . $backup->{'size'} . '</td>' .
679 '<td align="right">' . $backup->{'fs_size'} .
680 '<input type="hidden" iD="fss'.$backup->{'hostid'}.'_'.$backup->{'backupnum'} . '" value="'. $backup->{'fs_size'} .'"></td>' .
681
682 "</tr>\n";
683 }
684
685 $retHTML .= "</table>";
686 $retHTML .= "</form>";
687
688 return $retHTML;
689 }
690
691 sub displayGrid($) {
692 my ($param) = @_;
693
694 my $offset = $param->{'offset'};
695 my $hilite = $param->{'search_filename'};
696
697 my $retHTML = "";
698
699 my $start_t = time();
700
701 my ($results, $files);
702 if ($param->{'use_hest'} && length($hilite) > 0) {
703 ($results, $files) = getFilesHyperEstraier($param);
704 } else {
705 ($results, $files) = getFiles($param);
706 }
707
708 my $dur_t = time() - $start_t;
709 my $dur = sprintf("%0.4fs", $dur_t);
710
711 my ($from, $to) = (($offset * $on_page) + 1, ($offset * $on_page) + $on_page);
712
713 if ($results <= 0) {
714 $retHTML .= qq{
715 <p style="color: red;">No results found...</p>
716 };
717 return $retHTML;
718 } else {
719 # DEBUG
720 #use Data::Dumper;
721 #$retHTML .= '<pre>' . Dumper($files) . '</pre>';
722 }
723
724
725 $retHTML .= qq{
726 <div>
727 Found <b>$results files</b> showing <b>$from - $to</b> (took $dur)
728 </div>
729 <table style="fview" width="100%" border="0" cellpadding="2" cellspacing="0">
730 <tr class="fviewheader">
731 <td></td>
732 <td align="center">Share</td>
733 <td align="center">Type and Name</td>
734 <td align="center">#</td>
735 <td align="center">Size</td>
736 <td align="center">Date</td>
737 <td align="center">Media</td>
738 </tr>
739 };
740
741 my $file;
742
743 sub hilite_html($$) {
744 my ($html, $search) = @_;
745 $html =~ s#($search)#<b>$1</b>#gis;
746 return $html;
747 }
748
749 sub restore_link($$$$$$) {
750 my $type = shift;
751 my $action = 'RestoreFile';
752 $action = 'browse' if (lc($type) eq 'dir');
753 return sprintf(qq{<a href="?action=%s&host=%s&num=%d&share=%s&dir=%s">%s</a>}, $action, @_);
754 }
755
756 my $i = $offset * $on_page;
757
758 foreach $file (@{ $files }) {
759 $i++;
760
761 my $typeStr = BackupPC::Attrib::fileType2Text(undef, $file->{'type'});
762 $retHTML .= qq{<tr class="fviewborder">};
763
764 $retHTML .= qq{<td class="fviewborder">$i</td>};
765
766 $retHTML .=
767 qq{<td class="fviewborder" align="right">} . $file->{'hname'} . ':' . $file->{'sname'} . qq{</td>} .
768 qq{<td class="fviewborder"><img src="$Conf{CgiImageDirURL}/icon-$typeStr.gif" alt="$typeStr" align="middle">&nbsp;} . hilite_html( $file->{'filepath'}, $hilite ) . qq{</td>} .
769 qq{<td class="fviewborder" align="center">} . restore_link( $typeStr, ${EscURI( $file->{'hname'} )}, $file->{'backupnum'}, ${EscURI( $file->{'sname'})}, ${EscURI( $file->{'filepath'} )}, $file->{'backupnum'} ) . qq{</td>} .
770 qq{<td class="fviewborder" align="right">} . $file->{'size'} . qq{</td>} .
771 qq{<td class="fviewborder">} . epoch_to_iso( $file->{'date'} ) . qq{</td>} .
772 qq{<td class="fviewborder">} . '?' . qq{</td>};
773
774 $retHTML .= "</tr>";
775 }
776 $retHTML .= "</table>";
777
778 # all variables which has to be transfered
779 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/) {
780 $retHTML .= qq{<INPUT TYPE="hidden" NAME="$n" VALUE="$In{$n}">\n};
781 }
782
783 my $del = '';
784 my $max_page = int( $results / $on_page );
785 my $page = 0;
786
787 sub page_link($$$) {
788 my ($param,$page,$display) = @_;
789
790 $param->{'offset'} = $page;
791
792 my $html = '<a href = "' . $MyURL;
793 my $del = '?';
794 foreach my $k (keys %{ $param }) {
795 if ($param->{$k}) {
796 $html .= $del . $k . '=' . ${EscURI( $param->{$k} )};
797 $del = '&';
798 }
799 }
800 $html .= '">' . $display . '</a>';
801 }
802
803 $retHTML .= '<div style="text-align: center;">';
804
805 if ($offset > 0) {
806 $retHTML .= page_link($param, $offset - 1, '&lt;&lt;') . ' ';
807 }
808
809 while ($page <= $max_page) {
810 if ($page == $offset) {
811 $retHTML .= $del . '<b>' . ($page + 1) . '</b>';
812 } else {
813 $retHTML .= $del . page_link($param, $page, $page + 1);
814 }
815
816 if ($page < $offset - $pager_pages && $page != 0) {
817 $retHTML .= " ... ";
818 $page = $offset - $pager_pages;
819 $del = '';
820 } elsif ($page > $offset + $pager_pages && $page != $max_page) {
821 $retHTML .= " ... ";
822 $page = $max_page;
823 $del = '';
824 } else {
825 $del = ' | ';
826 $page++;
827 }
828 }
829
830 if ($offset < $max_page) {
831 $retHTML .= ' ' . page_link($param, $offset + 1, '&gt;&gt;');
832 }
833
834 $retHTML .= "</div>";
835
836 return $retHTML;
837 }
838
839 1;

  ViewVC Help
Powered by ViewVC 1.1.26