Annotation of loncom/cgi/archive.pl, revision 1.3

1.1       raeburn     1: #!/usr/bin/perl
                      2: #
1.3     ! raeburn     3: # $Id: archive.pl,v 1.2 2024/05/21 02:57:17 raeburn Exp $
1.1       raeburn     4: #
                      5: # Copyright Michigan State University Board of Trustees
                      6: #
                      7: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                      8: #
                      9: # LON-CAPA is free software; you can redistribute it and/or modify
                     10: # it under the terms of the GNU General Public License as published by
                     11: # the Free Software Foundation; either version 2 of the License, or
                     12: # (at your option) any later version.
                     13: #
                     14: # LON-CAPA is distributed in the hope that it will be useful,
                     15: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     16: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     17: # GNU General Public License for more details.
                     18: #
                     19: # You should have received a copy of the GNU General Public License
                     20: # along with LON-CAPA; if not, write to the Free Software
                     21: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     22: #
                     23: # /home/httpd/cgi-bin/archive.pl
                     24: #
                     25: # http://www.lon-capa.org/
                     26: #
                     27: # The LearningOnline Network with CAPA
                     28: #
                     29: # A CGI script which creates a compressed archive file of the current
                     30: # directory in Authoring Space, with optional (a) recursion into
1.2       raeburn    31: # sub-directories, and (b) filtering by filetype.
1.1       raeburn    32: # Supported formats are: tar.gz, tar.bz2, tar.xz and zip.
                     33: ####
                     34: use strict;
                     35: use lib '/home/httpd/lib/perl';
                     36: use File::Find;
                     37: use Apache::lonnet;
                     38: use Apache::loncommon;
                     39: use Apache::lonlocal;
                     40: use LONCAPA::loncgi;
                     41: use Cwd;
                     42: use HTML::Entities;
                     43: 
                     44: $|++;
                     45: 
                     46: my $lock;
                     47: 
                     48: our %excluded = (
                     49:                    bak => 1,
                     50:                    save => 1,
                     51:                    log => 1,
                     52:                 );
                     53: 
                     54: our $maxdepth = 0;
                     55: our %included = ();
                     56: our $alltypes = '';
                     57: our $recurse = '';
                     58: our $includeother = '';
                     59: our $prefix = '';
                     60: our $totalfiles = 0;
                     61: our $totalsize = 0;
                     62: our $totalsubdirs = 0;
                     63: our %subdirs = ();
                     64: our $fh;
                     65: 
                     66: if (!&LONCAPA::loncgi::check_cookie_and_load_env()) {
                     67:     &Apache::lonlocal::get_language_handle();
                     68:     print(&LONCAPA::loncgi::missing_cookie_msg());
                     69: } else {
                     70:     &Apache::lonlocal::get_language_handle();
                     71:     my %lt = &Apache::lonlocal::texthash (
                     72:                                             indi => 'Invalid directory name',
1.3     ! raeburn    73:                                             noau => 'Archive creation only available to Author',
1.1       raeburn    74:                                             outo => 'Output of command:',
                     75:                                             comp => 'Archive creation complete.',
                     76:                                             erro => 'An error occurred.',
1.3     ! raeburn    77:                                             cctf => 'Cannot create tar file',
1.1       raeburn    78:                                             dtf  => 'Download tar file',
                     79:                                          );
                     80: # Get the identifier and set a lock
                     81:     my %perlvar=%{&LONCAPA::Configuration::read_conf('loncapa.conf')};
                     82:     my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
                     83:     &Apache::lonlocal::get_language_handle();
                     84:     &Apache::loncommon::content_type(undef,'text/html');
                     85:     my $identifier = $ENV{'QUERY_STRING'};
1.2       raeburn    86:     my ($hashref,$dir,$dirurl,$jsdirurl,$auname,$audom,$allowed,$error,
                     87:         $format,$compress,$fname,$extension,$adload,$url,$mime);
1.1       raeburn    88:     my @posstypes = qw(problem library sty sequence page task rights meta xml html xhtml htm xhtm css js tex txt gif jpg jpeg png svg other);
1.2       raeburn    89:     if (($identifier =~ /^\d+_\d+_\d+$/) && (exists($env{'cgi.'.$identifier.'.archive'}))) {
1.1       raeburn    90:         $hashref = &Apache::lonnet::thaw_unescape($env{'cgi.'.$identifier.'.archive'});
                     91:         if (ref($hashref) eq 'HASH') {
                     92:             $dir = $hashref->{'dir'};
1.2       raeburn    93:             $dir =~ s{\.+}{.}g;
1.1       raeburn    94:             if (-d $dir) {
                     95:                 $dirurl = $dir;
                     96:                 ($auname,$audom) = &Apache::lonnet::constructaccess($dir);
                     97:                 if (($auname ne '') && ($audom ne '')) {
                     98:                     $dirurl =~ s/^\Q$londocroot\E//;
                     99:                     $prefix = $londocroot.$dirurl;
                    100:                     $maxdepth = $prefix =~ tr{/}{};
                    101:                     $jsdirurl = &js_escape($dirurl);
                    102:                     if (($auname eq $env{'user.name'}) && ($audom eq $env{'user.domain'}) &&
1.2       raeburn   103:                         ($env{'environment.canarchive'})) {
1.1       raeburn   104:                         $allowed = 1;
                    105:                         if ($hashref->{'recurse'}) {
                    106:                             $recurse = 1;
                    107:                         } else {
                    108:                             $recurse = 0;
                    109:                         }
                    110:                         if ($hashref->{'types'} eq 'all') {
                    111:                             $alltypes = 1;
                    112:                         } else {
                    113:                             $alltypes = 0;
                    114:                             my %possincluded;
                    115:                             map { $possincluded{$_} = 1; } split(/,/,$hashref->{'types'});
                    116:                             $includeother = 0;
                    117:                             foreach my $type (@posstypes) {
                    118:                                 if ($type eq 'other') {
                    119:                                     if ($possincluded{$type}) {
                    120:                                         $includeother = 1;
                    121:                                     } else {
                    122:                                         $includeother = 0;
                    123:                                     }
                    124:                                 } else {
                    125:                                     if ($possincluded{$type}) {
                    126:                                         $included{$type} = 1;
                    127:                                     } else {
                    128:                                         $excluded{$type} = 1;
                    129:                                     }
                    130:                                 }
                    131:                             }
                    132:                         }
                    133:                         if ((exists($hashref->{'format'}) && $hashref->{'format'} =~ /^zip$/i)) {
                    134:                             $format = lc($hashref->{'format'});
                    135:                         } else {
                    136:                             $format = 'tar';
                    137:                         }
                    138:                         unless ($format eq 'zip') { 
                    139:                             if ((exists($hashref->{'compress'})) && ($hashref->{'compress'} =~ /^(xz|bzip2)$/i)) {
                    140:                                 $compress = lc($hashref->{'compress'});
                    141:                             } else {
                    142:                                 $compress = 'gzip';
                    143:                             }
                    144:                         }
1.2       raeburn   145:                         if ($hashref->{'adload'}) {
                    146:                             $adload = $hashref->{'adload'};
                    147:                         }
                    148:                         if ($hashref->{'fname'}) {
                    149:                             $fname = $hashref->{'fname'};
                    150:                         }
                    151:                         if ($hashref->{'extension'}) {
                    152:                             $extension = $hashref->{'extension'};
                    153:                         }
1.3     ! raeburn   154:                     } else {
        !           155:                         $error = 'noau';
1.1       raeburn   156:                     }
                    157:                 }
                    158:             } else {
                    159:                 $error = 'indi';
                    160:             }
                    161:         } else {
                    162:             $error = 'nohash';
                    163:         }
1.2       raeburn   164: # delete cgi.$identifier.archive from %env if error
                    165:         if ($error) {
                    166:             &Apache::lonnet::delenv('cgi.'.$identifier.'.archive');
                    167:         }
1.1       raeburn   168:     } else {
                    169:         $error = 'noid';
                    170:     }
                    171:     $env{'request.noversionuri'} = '/cgi-bin/archive.pl';
                    172:     my ($brcrum,$title); 
                    173:     if ($error) {
                    174:         $brcrum = [{'href' => '',
                    175:                     'text' => 'Missing information'}];
                    176:     } elsif (!$allowed) {
                    177:         $brcrum = [{'href' => '',
                    178:                     'text' => 'Access denied'}];
                    179:     } else {
                    180: # Breadcrumbs
                    181:         $title = 'Creating archive file';
                    182:         $brcrum = [{'href' => $dirurl,
                    183:                     'text' => 'Authoring Space'},
                    184:                    {'href' => "javascript:gocstr('/adm/cfile?action=archive','$jsdirurl');",
                    185:                     'text' => 'File Operation'},
                    186:                    {'href' => '',
                    187:                     'text' => $title}];
                    188:     }
1.2       raeburn   189: # Set up files to write two and url
                    190:     my ($js,%location_of,$suffix,$namesdest,$filesdest,$filesurl);
                    191:     if ($allowed) {
                    192:         my @tocheck;
1.1       raeburn   193:         if ($format ne '') {
                    194:             push(@tocheck,$format);
                    195:         }
                    196:         if ($compress ne '') {
                    197:             push(@tocheck,$compress);
1.2       raeburn   198:         }
1.1       raeburn   199:         foreach my $program (@tocheck) {
                    200:             foreach my $dir ('/bin/','/usr/bin/','/usr/local/bin/','/sbin/',
                    201:                              '/usr/sbin/') {
                    202:                 if (-x $dir.$program) {
                    203:                     $location_of{$program} = $dir.$program;
                    204:                     last;
                    205:                 }
                    206:             }
                    207:         }
1.2       raeburn   208:         if (($format ne '') && (exists($location_of{$format}))) {
1.1       raeburn   209:             if ($format eq 'zip') {
1.2       raeburn   210:                 $suffix = '.zip';
                    211:                 $mime = 'application/x-zip-compressed';
1.1       raeburn   212:             } else {
1.2       raeburn   213:                 $suffix = '.tar';
                    214:                 if (($compress ne '') &&
                    215:                     (exists($location_of{$compress}))) {
1.1       raeburn   216:                     if ($compress eq 'bzip2') {
1.2       raeburn   217:                         $suffix .= '.bz2';
                    218:                         $mime = 'application/x-bzip2';
1.1       raeburn   219:                     } elsif ($compress eq 'gzip') {
                    220:                         $suffix .= '.gz';
1.2       raeburn   221:                         $mime = 'application/x-gzip';
1.1       raeburn   222:                     } elsif ($compress eq 'xz') {
                    223:                         $suffix .= '.xz';
1.2       raeburn   224:                         $mime = 'application/x-xz';
1.1       raeburn   225:                     }
                    226:                 }
                    227:             }
1.2       raeburn   228:             $namesdest = $perlvar{'lonPrtDir'}.'/'.$env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$identifier.'.txt';
                    229:             $filesdest = $perlvar{'lonPrtDir'}.'/'.$env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$identifier.$suffix;
                    230:             $filesurl = '/prtspool/'.$env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$identifier.$suffix;
                    231:             if ($suffix eq $extension) {
                    232:                 $fname =~ s{\Q$suffix\E$}{};
                    233:             }
                    234:             if ($fname eq '') {
                    235:                 $fname = $env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$identifier.$suffix;
                    236:             } else {
                    237:                 $fname .= $suffix;
                    238:             }
                    239:             my $downloadurl = &Apache::lonnet::absolute_url().$filesurl;
                    240:             my $delarchive = $identifier.$suffix;
                    241:             $js = &js($filesurl,$mime,$fname,$delarchive);
                    242:         }
                    243:     }
                    244:     print &Apache::loncommon::start_page($title,
                    245:                                          '',
                    246:                                          {'bread_crumbs' => $brcrum,})."\n".
                    247:           '<form name="constspace" method="post" action="">'."\n".
                    248:           '<input type="hidden" name="filename" value="" />'."\n";
                    249:     if ($error) {
                    250:         print &mt('Cannot create archive file');
                    251:     } elsif ($allowed) {
                    252:         if (-e $filesdest) {
                    253:             my $mtime = (stat($filesdest))[9];
                    254:             print '<div id="LC_archive_desc">'."\n";
                    255:             if ($mtime) {
                    256:                 print '<p class="LC_warning">'.&mt('Archive file already exists -- created: [_1].',
                    257:                                                    &Apache::lonlocal::locallocaltime($mtime)).'</p>';
                    258:             } else {
                    259:                 print '<p class="LC_warning">'.&mt('Archive file already exists.').'</p>';
                    260:             }
                    261:             print '</div>'."\n";
                    262:             print &archive_link($adload,$filesurl,$suffix);
                    263:             if ($adload) {
                    264:                 print $js;
                    265:             }
                    266:         } elsif (exists($location_of{$format})) {
                    267:             unless ($lock) { $lock=&Apache::lonnet::set_lock(&mt('Creating Archive file for [_1]',$dirurl)); }
1.1       raeburn   268:             if (open($fh,'>',$namesdest)) {
                    269:                 find(
                    270:                      {preprocess => \&filter_files,
                    271:                       wanted     => \&store_names,
                    272:                       no_chdir   => 1,
                    273:                      },$dir);
                    274:                 close($fh);
1.2       raeburn   275:                 if (ref($hashref) eq 'HASH') {
                    276:                     $hashref->{'numfiles'} = $totalfiles;
                    277:                     $hashref->{'numdirs'} = $totalsubdirs;
                    278:                     $hashref->{'bytes'} = $totalsize;
                    279:                     my $storestring = &Apache::lonnet::freeze_escape($hashref);
                    280:                     &Apache::lonnet::appenv({'cgi.'.$identifier.'.archive' => $storestring});
                    281:                 }
                    282:                 &Apache::lonnet::thaw_unescape($env{'cgi.'.$identifier.'.archive'});
1.1       raeburn   283:                 if (($totalfiles) || ($totalsubdirs)) {
1.2       raeburn   284:                     my $freespace;
                    285:                     my @dfargs = ('df','-k','--output=avail','/home');
                    286:                     if (open(my $pipe,'-|',@dfargs)) {
                    287:                         while (my $line = <$pipe>) {
                    288:                             chomp($line);
                    289:                             if ($line =~ /^\d+$/) {
                    290:                                 $freespace = $line;
                    291:                                 last;
                    292:                             }
1.1       raeburn   293:                         }
1.2       raeburn   294:                         close($pipe);
1.1       raeburn   295:                     }
1.2       raeburn   296:                     if (($freespace ne '') && ($totalsize < $freespace*1024)) {
                    297:                         my $showsize = $totalsize/(1024*1024);
                    298:                         if ($showsize <= 0.01) {
                    299:                             $showsize = sprintf("%.3f",$showsize);
                    300:                         } elsif ($showsize <= 0.1) {
                    301:                             $showsize = sprintf("%.2f",$showsize);
                    302:                         } elsif ($showsize < 10) {
                    303:                             $showsize = sprintf("%.1f",$showsize);
                    304:                         } else {
                    305:                             $showsize = sprintf("%.0f",$showsize);
                    306:                         }
                    307:                         print '<div id="LC_archive_desc"><p>'.
                    308:                               &mt('Creating archive file for [quant,_1,file,files] with total size before compression of [_2] MB.',
                    309:                                   $totalfiles,$showsize);
                    310:                         if ($totalsubdirs) {
                    311:                             print '<br />'.&mt('Archive includes [quant,_1,subdirectory,subdirectories].',
                    312:                                                $totalsubdirs);
                    313:                         }
                    314:                         print '</p></div>';
                    315:                         my ($cwd,@args);
                    316:                         if ($format eq 'zip') {
                    317:                             $cwd = &Cwd::getcwd();
                    318:                             @args = ('zip',$filesdest,'-v','-r','.','-i@'.$namesdest);
                    319:                             chdir $prefix;
                    320:                         } else {
                    321:                             @args = ('tar',"--create","--verbose");
                    322:                             if (($compress ne '') && (exists($location_of{$compress}))) {
                    323:                                 push(@args,"--$compress");
                    324:                             }
                    325:                             push(@args,("--file=$filesdest","--directory=$prefix","--files-from=$namesdest"));
                    326:                         }
                    327:                         if (open(my $pipe,'-|',@args)) {
                    328:                             my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin('',$totalfiles); 
                    329:                             while (<$pipe>) {
                    330:                                 &Apache::lonhtmlcommon::Increment_PrgWin('',\%prog_state,'last file');
                    331:                             }
                    332:                             &Apache::lonhtmlcommon::Close_PrgWin('',\%prog_state);
                    333:                             close($pipe);
                    334:                             if (-e $filesdest) {
                    335:                                 my $size = (stat($filesdest))[7];
                    336:                                 &Apache::lonnet::authorarchivelog($hashref,$size,$filesdest,'create');
                    337:                                 print &archive_link($adload,$filesurl,$suffix);
                    338:                                 if ($adload) {
                    339:                                     print $js;
                    340:                                 }
                    341:                             } else {
                    342:                                 print '<p>'.&mt('No archive file available for download').'</p>'."\n"; 
                    343:                             }
                    344:                         } else {
                    345:                             print '<p>'.&mt('Could not call [_1] command',$format).'</p>'."\n";
1.1       raeburn   346:                         }
1.2       raeburn   347:                         if (($format eq 'zip') && ($cwd ne '')) {
                    348:                             chdir $cwd;
1.1       raeburn   349:                         }
1.2       raeburn   350:                     } elsif ($freespace eq '') {
                    351:                         print '<p>'.&mt('No archive file created as the available free space could not be determined.').'</p>'."\n";
1.1       raeburn   352:                     } else {
1.2       raeburn   353:                         print '<p>'.&mt('No archive file created because there is insufficient free space available.').'</p>'."\n";
1.1       raeburn   354:                     }
                    355:                 } else {
                    356:                     print '<p>'.&mt('No files match the requested types so no archive file was created.').'</p>'."\n";
                    357:                 }
                    358:                 unlink($namesdest);
                    359:             } else {
                    360:                 print '<p>'.&mt('Could not store list of files to archive').'</p>'."\n";
                    361:             }
                    362:             if ($lock) { &Apache::lonnet::remove_lock($lock); }
                    363:         } else {
                    364:             print '<p>'.&mt('Could not find location of [_1] command',$format).'</p>'."\n";
                    365:         }
                    366:     }
                    367:     if ($dirurl) {
1.2       raeburn   368:         print '<br />'.
1.1       raeburn   369:               &Apache::lonhtmlcommon::actionbox(['<a href="'.&HTML::Entities::encode($dirurl,'\'"&<>').'">'.
                    370:                                                  &mt('Return to Directory').'</a>']);
                    371:     }
                    372:     print '</form>'.&Apache::loncommon::end_page();
                    373: 
                    374: # Code to delete archive file after successful download
                    375:     %included = ();
                    376:     $alltypes = '';
                    377:     $recurse = '';
                    378:     $includeother = '';
                    379:     $prefix = '';
                    380:     $totalfiles = 0;
                    381:     $totalsize = 0;
                    382:     $totalsubdirs = 0;
                    383:     %excluded = (
                    384:                    bak => 1,
                    385:                    save => 1,
                    386:                    log => 1,
                    387:                 );
                    388: }
                    389: 
                    390: sub filter_files {
                    391:     my @PossibleFiles = @_;
                    392:     my @ChosenFiles;
                    393:     foreach my $file (@PossibleFiles) {
                    394:         if (-d $File::Find::dir."/".$file) {
                    395:             if (!$recurse) {
                    396:                 my $depth = $File::Find::dir =~ tr[/][];
                    397:                 next unless ($depth < $maxdepth-1);
                    398:             }
                    399:             push(@ChosenFiles,$file);
                    400:         } else {
1.2       raeburn   401:             next if ($file =~ /^\./);
1.1       raeburn   402:             my ($extension) = ($file =~ /\.([^.]+)$/);
                    403:             if ((!$excluded{$extension}) && ($alltypes || $includeother || $included{$extension})) {
                    404:                 push(@ChosenFiles,$file);
                    405:             }
                    406:         }
                    407:     }
                    408:     return @ChosenFiles;  
                    409: }
                    410: 
                    411: sub store_names {
                    412:     my $filename = $File::Find::name;
                    413:     if (-d $filename) {
                    414:         unless ("$filename/" eq $prefix) {
                    415:             if ($recurse) {
                    416:                 $subdirs{$filename} = 1;
                    417:                 $totalsubdirs ++;
                    418:             }
                    419:         }
                    420:         next;
                    421:     }
                    422:     $totalfiles ++;
                    423:     $totalsize += -s $filename;
                    424:     $filename =~ s{^$prefix}{}; 
                    425:     print $fh "$filename\n";
                    426: }
                    427: 
1.2       raeburn   428: sub archive_link {
                    429:     my ($adload,$filesurl,$suffix) = @_;
                    430:     if ($adload) {
                    431:         return
                    432: '<button id="LC_download_button" onclick="return false">'.&mt('Download').'</button></p>'."\n".
                    433: '<div style="display:none; width:100%;" id="LC_dload_progress" >'."\n".
                    434: '<div id="LC_dl_progressbar"></div>'."\n".
                    435: '</div>'."\n".
                    436: '<span id="LC_download_result"></span>'."\n";
                    437:     } else {
                    438:         return
                    439: '<p><a href="'.$filesurl.'">'.&mt('Download [_1] file',$suffix).'</a></p>'."\n";
                    440:     }
                    441: }
                    442: 
1.1       raeburn   443: sub js {
1.2       raeburn   444:     my ($url,$mime,$fname,$delarchive) = @_;
                    445:     &js_escape(\$url);
                    446:     &js_escape(\$mime);
                    447:     &js_escape(\$fname);
                    448:     my %js_lt = &Apache::lonlocal::texthash (
                    449:                                               afdo => 'Archive file download complete.',
                    450:                                               diun => 'Download is unavailable.',
                    451:                                               tfbr => 'The archive file has been removed.',
                    452:                                               ynrd => 'You do not have rights to download the archive file.',
                    453:     );
                    454:     &js_escape(\%js_lt);
                    455:     return <<"END";
                    456: <script type="text/javascript">
                    457: // <![CDATA[
                    458: 
                    459: function showProgress(event) {
                    460:     if (event.lengthComputable) {
                    461:         var complete = 0;
                    462:         if (event.total > 0) {
                    463:             complete = Math.round( (event.loaded / event.total) * 100);
                    464:         }
                    465:         \$( "#LC_dl_progressbar" ).progressbar({
                    466:            value: complete
                    467:         });
                    468:         if (complete == '100') {
                    469:             if (document.getElementById('LC_dload_progress')) {
                    470:                 document.getElementById('LC_dload_progress').style.display = 'none';
                    471:             }
                    472:         }
                    473:     }
                    474: }
                    475: 
                    476: function cleanUp(event) {
                    477:     showProgress(event);
                    478:     if (event.lengthComputable) {
                    479:         var complete = 0;
                    480:         if (event.total > 0) {
                    481:             complete = Math.round( (event.loaded / event.total) * 100);
                    482:         }
                    483:         if (complete == 100) {
                    484:             var dbtn = document.querySelector('#LC_download_button');
                    485:             if (dbtn !== null) {
                    486:                 dbtn.style.display = 'none';
                    487:             }
                    488:             var http = new XMLHttpRequest();
                    489:             var lcurl = "/adm/cfile";
                    490:             var params = 'delarchive=$delarchive';
                    491:             var result;
                    492:             http.open("POST",lcurl, true);
                    493:             http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
                    494:             http.onreadystatechange = function() {
                    495:                 if ((http.readyState == 4) && (http.status == 200)) {
                    496:                     if (http.responseText.length > 0) {
                    497:                         if (http.responseText == 1) {
                    498:                             if (document.getElementById('LC_archive_desc')) {
                    499:                                 document.getElementById('LC_archive_desc').style.display = 'none';
                    500:                             }
                    501:                             if (document.getElementById('LC_download_result')) {
                    502:                                 document.getElementById('LC_download_result').innerHTML = '$js_lt{afdo}<br />';
                    503:                             }
                    504:                         }
                    505:                     }
                    506:                 }
                    507:             }
                    508:             http.send(params);
                    509:         }
                    510:     }
                    511: }
                    512: 
                    513: function filecheck(file, callback) {
                    514:     const xhr = new XMLHttpRequest();
                    515:     xhr.open('HEAD',file,true);
                    516:     xhr.onreadystatechange = function() {
                    517:         if (this.readyState >= 2) {
                    518:             callback(this.status);
                    519:             this.abort();
                    520:         }
                    521:     };
                    522:     xhr.send();
                    523: }
                    524: 
                    525: function download(file,callback) {
                    526:     if (document.getElementById('LC_dload_progress')) {
                    527:         document.getElementById('LC_dload_progress').style.display = 'block';
                    528:     }
                    529:     const xhr = new XMLHttpRequest();
                    530:     xhr.responseType = 'blob';
                    531:     xhr.open('GET', file);
                    532:     xhr.addEventListener('progress',showProgress);
                    533:     xhr.addEventListener('load', function () {
                    534:         callback(xhr.response);
                    535:     });
                    536:     xhr.addEventListener("loadend", cleanUp);
                    537:     xhr.send();
                    538: }
1.1       raeburn   539: 
1.2       raeburn   540: function save(object,mime,name) {
                    541:     var a = document.createElement('a');
                    542:     var url = URL.createObjectURL(object);
                    543:     a.href = url;
                    544:     a.type = mime;
                    545:     a.download = name;
                    546:     a.click();
                    547: }
1.1       raeburn   548: 
1.2       raeburn   549: var dbtn = document.querySelector('#LC_download_button');
                    550: if (dbtn !== null) {
                    551:     dbtn.addEventListener('click', function () {
                    552:         filecheck('$url',function (response) {
                    553:             if (response == 200) {
                    554:                 download('$url', function (file) {
                    555:                     save(file,'$mime','$fname');
                    556:                 });
                    557:             } else if ((response == 404) || (response == 403) || (response == 406)) {
                    558:                 dbtn.style.display = 'none';
                    559:                 if (document.getElementById('LC_dload_progress')) {
                    560:                     document.getElementById('LC_dload_progress').style.display = 'none';
                    561:                 }
                    562:                 if (document.getElementById('LC_download_result')) {
                    563:                     if (response == 404) {
                    564:                         document.getElementById('LC_download_result').innerHTML = '$js_lt{diun} $js_lt{tfbr}<br />';
                    565:                     } else {
                    566:                         document.getElementById('LC_download_result').innerHTML = '$js_lt{diun} $js_lt{ynrd}<br />';
                    567:                     }
                    568:                 }
                    569:             }
                    570:         });
                    571:     });
1.1       raeburn   572: }
                    573: 
1.2       raeburn   574: // ]]>
                    575: </script>
1.1       raeburn   576: 
1.2       raeburn   577: END
                    578: 
                    579: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>