Diff for /loncom/interface/loncommon.pm between versions 1.1029 and 1.1073

version 1.1029, 2011/12/04 16:27:05 version 1.1073, 2012/04/25 21:22:01
Line 154  sub ssi_with_retries { Line 154  sub ssi_with_retries {
 # ----------------------------------------------- Filetypes/Languages/Copyright  # ----------------------------------------------- Filetypes/Languages/Copyright
 my %language;  my %language;
 my %supported_language;  my %supported_language;
   my %latex_language; # For choosing hyphenation in <transl..>
   my %latex_language_bykey; # for choosing hyphenation from metadata
 my %cprtag;  my %cprtag;
 my %scprtag;  my %scprtag;
 my %fe; my %fd; my %fm;  my %fe; my %fd; my %fm;
Line 186  BEGIN { Line 188  BEGIN {
             while (my $line = <$fh>) {              while (my $line = <$fh>) {
                 next if ($line=~/^\#/);                  next if ($line=~/^\#/);
                 chomp($line);                  chomp($line);
                 my ($key,$two,$country,$three,$enc,$val,$sup)=(split(/\t/,$line));                  my ($key,$two,$country,$three,$enc,$val,$sup,$latex)=(split(/\t/,$line));
                 $language{$key}=$val.' - '.$enc;                  $language{$key}=$val.' - '.$enc;
                 if ($sup) {                  if ($sup) {
                     $supported_language{$key}=$sup;                      $supported_language{$key}=$sup;
                 }                  }
    if ($latex) {
       $latex_language_bykey{$key} = $latex;
       $latex_language{$two} = $latex;
    }
             }              }
             close($fh);              close($fh);
         }          }
Line 1186  sub help_open_topic { Line 1192  sub help_open_topic {
     my ($topic, $text, $stayOnPage, $width, $height, $imgid) = @_;      my ($topic, $text, $stayOnPage, $width, $height, $imgid) = @_;
     $text = "" if (not defined $text);      $text = "" if (not defined $text);
     $stayOnPage = 0 if (not defined $stayOnPage);      $stayOnPage = 0 if (not defined $stayOnPage);
     $width = 350 if (not defined $width);      $width = 500 if (not defined $width);
     $height = 400 if (not defined $height);      $height = 400 if (not defined $height);
     my $filename = $topic;      my $filename = $topic;
     $filename =~ s/ /_/g;      $filename =~ s/ /_/g;
Line 1197  sub help_open_topic { Line 1203  sub help_open_topic {
     $topic=~s/\W/\_/g;      $topic=~s/\W/\_/g;
   
     if (!$stayOnPage) {      if (!$stayOnPage) {
  $link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";   $link = "javascript:openMyModal('/adm/help/${filename}.hlp',$width,$height,'yes');";
       } elsif ($stayOnPage eq 'popup') {
           $link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
     } else {      } else {
  $link = "/adm/help/${filename}.hlp";   $link = "/adm/help/${filename}.hlp";
     }      }
Line 1230  sub help_open_topic { Line 1238  sub help_open_topic {
 # This is a quicky function for Latex cheatsheet editing, since it   # This is a quicky function for Latex cheatsheet editing, since it 
 # appears in at least four places  # appears in at least four places
 sub helpLatexCheatsheet {  sub helpLatexCheatsheet {
     my ($topic,$text,$not_author) = @_;      my ($topic,$text,$not_author,$stayOnPage) = @_;
     my $out;      my $out;
     my $addOther = '';      my $addOther = '';
     if ($topic) {      if ($topic) {
  $addOther = '<span>'.&Apache::loncommon::help_open_topic($topic,&mt($text),   $addOther = '<span>'.&help_open_topic($topic,&mt($text),$stayOnPage, undef, 600).'</span> ';
        undef, undef, 600).  
    '</span> ';  
     }      }
     $out = '<span>' # Start cheatsheet      $out = '<span>' # Start cheatsheet
   .$addOther    .$addOther
           .'<span>'            .'<span>'
   .&Apache::loncommon::help_open_topic('Greek_Symbols',&mt('Greek Symbols'),    .&help_open_topic('Greek_Symbols',&mt('Greek Symbols'),$stayOnPage,undef,600)
        undef,undef,600)  
   .'</span> <span>'    .'</span> <span>'
   .&Apache::loncommon::help_open_topic('Other_Symbols',&mt('Other Symbols'),    .&help_open_topic('Other_Symbols',&mt('Other Symbols'),$stayOnPage,undef,600)
        undef,undef,600)  
   .'</span>';    .'</span>';
     unless ($not_author) {      unless ($not_author) {
         $out .= ' <span>'          $out .= ' <span>'
        .&Apache::loncommon::help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),         .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600)
                                             undef,undef,600)  
        .'</span>';         .'</span>';
     }      }
     $out .= '</span>'; # End cheatsheet      $out .= '</span>'; # End cheatsheet
Line 1371  function helpMenu(target) { Line 1374  function helpMenu(target) {
     return;      return;
 }  }
 function writeHelp(caller) {  function writeHelp(caller) {
     caller.document.writeln('$start_page<frame name="bannerframe"  src="'+banner_link+'" /><frame name="bodyframe" src="$details_link" /> $end_page')      caller.document.writeln('$start_page\\n<frame name="bannerframe" src="'+banner_link+'" />\\n<frame name="bodyframe" src="$details_link" />\\n$end_page')
     caller.document.close()      caller.document.close()
     caller.focus()      caller.focus()
 }  }
Line 1745  Inputs: $workbook Line 1748  Inputs: $workbook
   
 Returns: $format, a hash reference.  Returns: $format, a hash reference.
   
   
 =cut  =cut
   
 ###############################################################  ###############################################################
Line 2853  database which holds them. Line 2857  database which holds them.
   
 Uses global $thesaurus_db_file.  Uses global $thesaurus_db_file.
   
   
 =cut  =cut
   
 ###############################################################  ###############################################################
Line 3124  sub noteswrapper { Line 3129  sub noteswrapper {
 # ------------------------------------------------------------- Aboutme Wrapper  # ------------------------------------------------------------- Aboutme Wrapper
   
 sub aboutmewrapper {  sub aboutmewrapper {
     my ($link,$username,$domain,$target)=@_;      my ($link,$username,$domain,$target,$class)=@_;
     if (!defined($username)  && !defined($domain)) {      if (!defined($username)  && !defined($domain)) {
         return;          return;
     }      }
     return '<a href="/adm/'.$domain.'/'.$username.'/aboutme?forcestudent=1"'.      return '<a href="/adm/'.$domain.'/'.$username.'/aboutme?forcestudent=1"'.
  ($target?' target="$target"':'').' title="'.&mt("View this user's personal information page").'">'.$link.'</a>';   ($target?' target="'.$target.'"':'').($class?' class="'.$class.'"':'').' title="'.&mt("View this user's personal information page").'">'.$link.'</a>';
 }  }
   
 # ------------------------------------------------------------ Syllabus Wrapper  # ------------------------------------------------------------ Syllabus Wrapper
Line 3230  sub languagedescription { Line 3235  sub languagedescription {
     ($supported_language{$code}?' ('.&mt('interface available').')':'');      ($supported_language{$code}?' ('.&mt('interface available').')':'');
 }  }
   
   =pod
   
   =item * &plainlanguagedescription
   
   Returns both the plain language description (e.g. 'Creoles and Pidgins, English-based (Other)')
   and the language character encoding (e.g. ISO) separated by a ' - ' string.
   
   =cut
   
 sub plainlanguagedescription {  sub plainlanguagedescription {
     my $code=shift;      my $code=shift;
     return $language{$code};      return $language{$code};
 }  }
   
   =pod
   
   =item * &supportedlanguagecode
   
   Returns the supported language code (e.g. sptutf maps to pt) given a language
   code.
   
   =cut
   
 sub supportedlanguagecode {  sub supportedlanguagecode {
     my $code=shift;      my $code=shift;
     return $supported_language{$code};      return $supported_language{$code};
Line 3242  sub supportedlanguagecode { Line 3265  sub supportedlanguagecode {
   
 =pod  =pod
   
   =item * &latexlanguage()
   
   Given a language key code returns the correspondnig language to use
   to select the correct hyphenation on LaTeX printouts.  This is undef if there
   is no supported hyphenation for the language code.
   
   =cut
   
   sub latexlanguage {
       my $code = shift;
       return $latex_language{$code};
   }
   
   =pod
   
   =item * &latexhyphenation()
   
   Same as above but what's supplied is the language as it might be stored
   in the metadata.
   
   =cut
   
   sub latexhyphenation {
       my $key = shift;
       return $latex_language_bykey{$key};
   }
   
   =pod
   
 =item * &copyrightids()   =item * &copyrightids() 
   
 returns list of all copyrights  returns list of all copyrights
Line 3938  sub findallcourses { Line 3990  sub findallcourses {
         $udom = $env{'user.domain'};          $udom = $env{'user.domain'};
     }      }
     if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {      if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
         my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1});          my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname);
         my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname,'.',undef,  
                                               $extra);  
         if (!%roles) {          if (!%roles) {
             %roles = (              %roles = (
                        cc => 1,                         cc => 1,
Line 3965  sub findallcourses { Line 4015  sub findallcourses {
             if ($tstart) {              if ($tstart) {
                 next if ($tstart > $now);                  next if ($tstart > $now);
             }              }
             my ($cdom,$cnum,$sec,$cnumpart,$secpart,$role,$realsec);              my ($cdom,$cnum,$sec,$cnumpart,$secpart,$role);
             (undef,$cdom,$cnumpart,$secpart) = split(/\//,$entry);              (undef,$cdom,$cnumpart,$secpart) = split(/\//,$entry);
               my $value = $trole.'/'.$cdom.'/';
             if ($secpart eq '') {              if ($secpart eq '') {
                 ($cnum,$role) = split(/_/,$cnumpart);                   ($cnum,$role) = split(/_/,$cnumpart); 
                 $sec = 'none';                  $sec = 'none';
                 $realsec = '';                  $value .= $cnum.'/';
             } else {              } else {
                 $cnum = $cnumpart;                  $cnum = $cnumpart;
                 ($sec,$role) = split(/_/,$secpart);                  ($sec,$role) = split(/_/,$secpart);
                 $realsec = $sec;                  $value .= $cnum.'/'.$sec;
               }
               if (ref($courses{$cdom.'_'.$cnum}{$sec}) eq 'ARRAY') {
                   unless (grep(/^\Q$value\E$/,@{$courses{$cdom.'_'.$cnum}{$sec}})) {
                       push(@{$courses{$cdom.'_'.$cnum}{$sec}},$value);
                   }
               } else {
                   @{$courses{$cdom.'_'.$cnum}{$sec}} = ($value);
             }              }
             $courses{$cdom.'_'.$cnum}{$sec} = $trole.'/'.$cdom.'/'.$cnum.'/'.$realsec;  
         }          }
     } else {      } else {
         foreach my $key (keys(%env)) {          foreach my $key (keys(%env)) {
Line 3994  sub findallcourses { Line 4051  sub findallcourses {
                     if ($now>$endtime) { $active=0; }                      if ($now>$endtime) { $active=0; }
                 }                  }
                 if ($active) {                  if ($active) {
                       my $value = $role.'/'.$cdom.'/'.$cnum.'/';
                     if ($sec eq '') {                      if ($sec eq '') {
                         $sec = 'none';                          $sec = 'none';
                       } else {
                           $value .= $sec;
                       }
                       if (ref($courses{$cdom.'_'.$cnum}{$sec}) eq 'ARRAY') {
                           unless (grep(/^\Q$value\E$/,@{$courses{$cdom.'_'.$cnum}{$sec}})) {
                               push(@{$courses{$cdom.'_'.$cnum}{$sec}},$value);
                           }
                       } else {
                           @{$courses{$cdom.'_'.$cnum}{$sec}} = ($value);
                     }                      }
                     $courses{$cdom.'_'.$cnum}{$sec} =   
                                      $role.'/'.$cdom.'/'.$cnum.'/'.$sec;  
                 }                  }
             }              }
         }          }
Line 4009  sub findallcourses { Line 4074  sub findallcourses {
 ###############################################  ###############################################
   
 sub blockcheck {  sub blockcheck {
     my ($setters,$activity,$uname,$udom) = @_;      my ($setters,$activity,$uname,$udom,$url) = @_;
   
     if (!defined($udom)) {      if (!defined($udom)) {
         $udom = $env{'user.domain'};          $udom = $env{'user.domain'};
Line 4021  sub blockcheck { Line 4086  sub blockcheck {
     # If uname and udom are for a course, check for blocks in the course.      # If uname and udom are for a course, check for blocks in the course.
   
     if (&Apache::lonnet::is_course($udom,$uname)) {      if (&Apache::lonnet::is_course($udom,$uname)) {
         my %records = &Apache::lonnet::dump('comm_block',$udom,$uname);          my ($startblock,$endblock,$triggerblock) = 
         my ($startblock,$endblock)=&get_blocks($setters,$activity,$udom,$uname);              &get_blocks($setters,$activity,$udom,$uname,$url);
         return ($startblock,$endblock);          return ($startblock,$endblock,$triggerblock);
     }      }
   
     my $startblock = 0;      my $startblock = 0;
     my $endblock = 0;      my $endblock = 0;
       my $triggerblock = '';
     my %live_courses = &findallcourses(undef,$uname,$udom);      my %live_courses = &findallcourses(undef,$uname,$udom);
   
     # If uname is for a user, and activity is course-specific, i.e.,      # If uname is for a user, and activity is course-specific, i.e.,
Line 4091  sub blockcheck { Line 4157  sub blockcheck {
             if ($otheruser) {              if ($otheruser) {
                 # Resource belongs to user other than current user.                  # Resource belongs to user other than current user.
                 # Assemble privs for that user, and check for 'evb' priv.                  # Assemble privs for that user, and check for 'evb' priv.
                 my ($trole,$tdom,$tnum,$tsec);                  my (%allroles,%userroles);
                 my $entry = $live_courses{$course}{$sec};                  if (ref($live_courses{$course}{$sec}) eq 'ARRAY') {
                 if ($entry =~ /^cr/) {                      foreach my $entry (@{$live_courses{$course}{$sec}}) { 
                     ($trole,$tdom,$tnum,$tsec) =                           my ($trole,$tdom,$tnum,$tsec);
                       ($entry =~ m|^(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_username)/?(\w*)$|);                          if ($entry =~ /^cr/) {
                 } else {                              ($trole,$tdom,$tnum,$tsec) = 
                     ($trole,$tdom,$tnum,$tsec) = split(/\//,$entry);                                  ($entry =~ m|^(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_username)/?(\w*)$|);
                 }                          } else {
                 my ($spec,$area,$trest,%allroles,%userroles);                             ($trole,$tdom,$tnum,$tsec) = split(/\//,$entry);
                 $area = '/'.$tdom.'/'.$tnum;                          }
                 $trest = $tnum;                          my ($spec,$area,$trest);
                 if ($tsec ne '') {                          $area = '/'.$tdom.'/'.$tnum;
                     $area .= '/'.$tsec;                          $trest = $tnum;
                     $trest .= '/'.$tsec;                          if ($tsec ne '') {
                 }                              $area .= '/'.$tsec;
                 $spec = $trole.'.'.$area;                              $trest .= '/'.$tsec;
                 if ($trole =~ /^cr/) {                          }
                     &Apache::lonnet::custom_roleprivs(\%allroles,$trole,                          $spec = $trole.'.'.$area;
                                                       $tdom,$spec,$trest,$area);                          if ($trole =~ /^cr/) {
                 } else {                              &Apache::lonnet::custom_roleprivs(\%allroles,$trole,
                     &Apache::lonnet::standard_roleprivs(\%allroles,$trole,                                                                $tdom,$spec,$trest,$area);
                                                        $tdom,$spec,$trest,$area);                          } else {
                 }                              &Apache::lonnet::standard_roleprivs(\%allroles,$trole,
                 my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles);                                                                  $tdom,$spec,$trest,$area);
                 if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) {                          }
                     if ($1) {                      }
                         $no_userblock = 1;                      my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles);
                         last;                      if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) {
                           if ($1) {
                               $no_userblock = 1;
                               last;
                           }
                     }                      }
                 }                  }
             } else {              } else {
Line 4138  sub blockcheck { Line 4208  sub blockcheck {
         # Retrieve blocking times and identity of locker for course          # Retrieve blocking times and identity of locker for course
         # of specified user, unless user has 'evb' privilege.          # of specified user, unless user has 'evb' privilege.
                   
         my ($start,$end)=&get_blocks($setters,$activity,$cdom,$cnum);          my ($start,$end,$trigger) = 
               &get_blocks($setters,$activity,$cdom,$cnum,$url);
         if (($start != 0) &&           if (($start != 0) && 
             (($startblock == 0) || ($startblock > $start))) {              (($startblock == 0) || ($startblock > $start))) {
             $startblock = $start;              $startblock = $start;
               if ($trigger ne '') {
                   $triggerblock = $trigger;
               }
         }          }
         if (($end != 0)  &&          if (($end != 0)  &&
             (($endblock == 0) || ($endblock < $end))) {              (($endblock == 0) || ($endblock < $end))) {
             $endblock = $end;              $endblock = $end;
               if ($trigger ne '') {
                   $triggerblock = $trigger;
               }
         }          }
     }      }
     return ($startblock,$endblock);      return ($startblock,$endblock,$triggerblock);
 }  }
   
 sub get_blocks {  sub get_blocks {
     my ($setters,$activity,$cdom,$cnum) = @_;      my ($setters,$activity,$cdom,$cnum,$url) = @_;
     my $startblock = 0;      my $startblock = 0;
     my $endblock = 0;      my $endblock = 0;
       my $triggerblock = '';
     my $course = $cdom.'_'.$cnum;      my $course = $cdom.'_'.$cnum;
     $setters->{$course} = {};      $setters->{$course} = {};
     $setters->{$course}{'staff'} = [];      $setters->{$course}{'staff'} = [];
     $setters->{$course}{'times'} = [];      $setters->{$course}{'times'} = [];
     my %records = &Apache::lonnet::dump('comm_block',$cdom,$cnum);      $setters->{$course}{'triggers'} = [];
     foreach my $record (keys(%records)) {      my (@blockers,%triggered);
         my ($start,$end) = ($record =~ m/^(\d+)____(\d+)$/);      my $now = time;
         if ($start <= time && $end >= time) {      my %commblocks = &Apache::lonnet::get_comm_blocks($cdom,$cnum);
             my ($staff_name,$staff_dom,$title,$blocks) =      if ($activity eq 'docs') {
                 &parse_block_record($records{$record});          @blockers = &Apache::lonnet::has_comm_blocking('bre',undef,$url,\%commblocks);
             if ($blocks->{$activity} eq 'on') {          foreach my $block (@blockers) {
                 push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]);              if ($block =~ /^firstaccess____(.+)$/) {
                 push(@{$$setters{$course}{'times'}}, [$start,$end]);                  my $item = $1;
                 if ( ($startblock == 0) || ($startblock > $start) ) {                  my $type = 'map';
                     $startblock = $start;                  my $timersymb = $item;
                   if ($item eq 'course') {
                       $type = 'course';
                   } elsif ($item =~ /___\d+___/) {
                       $type = 'resource';
                   } else {
                       $timersymb = &Apache::lonnet::symbread($item);
                   }
                   my $start = $env{'course.'.$cdom.'_'.$cnum.'.firstaccess.'.$timersymb};
                   my $end = $start + $env{'course.'.$cdom.'_'.$cnum.'.timerinterval.'.$timersymb};
                   $triggered{$block} = {
                                          start => $start,
                                          end   => $end,
                                          type  => $type,
                                        };
               }
           }
       } else {
           foreach my $block (keys(%commblocks)) {
               if ($block =~ m/^(\d+)____(\d+)$/) { 
                   my ($start,$end) = ($1,$2);
                   if ($start <= time && $end >= time) {
                       if (ref($commblocks{$block}) eq 'HASH') {
                           if (ref($commblocks{$block}{'blocks'}) eq 'HASH') {
                               if ($commblocks{$block}{'blocks'}{$activity} eq 'on') {
                                   unless(grep(/^\Q$block\E$/,@blockers)) {
                                       push(@blockers,$block);
                                   }
                               }
                           }
                       }
                   }
               } elsif ($block =~ /^firstaccess____(.+)$/) {
                   my $item = $1;
                   my $timersymb = $item; 
                   my $type = 'map';
                   if ($item eq 'course') {
                       $type = 'course';
                   } elsif ($item =~ /___\d+___/) {
                       $type = 'resource';
                   } else {
                       $timersymb = &Apache::lonnet::symbread($item);
                 }                  }
                 if ( ($endblock == 0) || ($endblock < $end) ) {                  my $start = $env{'course.'.$cdom.'_'.$cnum.'.firstaccess.'.$timersymb};
                     $endblock = $end;                  my $end = $start + $env{'course.'.$cdom.'_'.$cnum.'.timerinterval.'.$timersymb}; 
                   if ($start && $end) {
                       if (($start <= time) && ($end >= time)) {
                           unless (grep(/^\Q$block\E$/,@blockers)) {
                               push(@blockers,$block);
                               $triggered{$block} = {
                                                      start => $start,
                                                      end   => $end,
                                                      type  => $type,
                                                    };
                           }
                       }
                 }                  }
             }              }
         }          }
     }      }
     return ($startblock,$endblock);      foreach my $blocker (@blockers) {
           my ($staff_name,$staff_dom,$title,$blocks) =
               &parse_block_record($commblocks{$blocker});
           push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]);
           my ($start,$end,$triggertype);
           if ($blocker =~ m/^(\d+)____(\d+)$/) {
               ($start,$end) = ($1,$2);
           } elsif (ref($triggered{$blocker}) eq 'HASH') {
               $start = $triggered{$blocker}{'start'};
               $end = $triggered{$blocker}{'end'};
               $triggertype = $triggered{$blocker}{'type'};
           }
           if ($start) {
               push(@{$$setters{$course}{'times'}}, [$start,$end]);
               if ($triggertype) {
                   push(@{$$setters{$course}{'triggers'}},$triggertype);
               } else {
                   push(@{$$setters{$course}{'triggers'}},0);
               }
               if ( ($startblock == 0) || ($startblock > $start) ) {
                   $startblock = $start;
                   if ($triggertype) {
                       $triggerblock = $blocker;
                   }
               }
               if ( ($endblock == 0) || ($endblock < $end) ) {
                  $endblock = $end;
                  if ($triggertype) {
                      $triggerblock = $blocker;
                  }
               }
           }
       }
       return ($startblock,$endblock,$triggerblock);
 }  }
   
 sub parse_block_record {  sub parse_block_record {
Line 4201  sub parse_block_record { Line 4364  sub parse_block_record {
 }  }
   
 sub blocking_status {  sub blocking_status {
   my ($activity,$uname,$udom) = @_;      my ($activity,$uname,$udom,$url) = @_;
   my %setters;      my %setters;
   
   # check for active blocking  
   my ($startblock,$endblock)=&blockcheck(\%setters,$activity,$uname,$udom);  
   
   my $blocked = $startblock && $endblock ? 1 : 0;  # check for active blocking
       my ($startblock,$endblock,$triggerblock) = 
   # caller just wants to know whether a block is active          &blockcheck(\%setters,$activity,$uname,$udom,$url);
   if (!wantarray) { return $blocked; }      my $blocked = 0;
       if ($startblock && $endblock) {
   # build a link to a popup window containing the details          $blocked = 1;
   my $querystring  = "?activity=$activity";      }
   # $uname and $udom decide whose portfolio the user is trying to look at  
      $querystring .= "&amp;udom=$udom"      if $udom;  # caller just wants to know whether a block is active
      $querystring .= "&amp;uname=$uname"    if $uname;      if (!wantarray) { return $blocked; }
   
   my $output .= <<'END_MYBLOCK';  # build a link to a popup window containing the details
     function openWindow(url, wdwName, w, h, toolbar,scrollbar) {      my $querystring  = "?activity=$activity";
         var options = "width=" + w + ",height=" + h + ",";  # $uname and $udom decide whose portfolio the user is trying to look at
         options += "resizable=yes,scrollbars="+scrollbar+",status=no,";      if ($activity eq 'port') {
         options += "menubar=no,toolbar="+toolbar+",location=no,directories=no";          $querystring .= "&amp;udom=$udom"      if $udom;
         var newWin = window.open(url, wdwName, options);          $querystring .= "&amp;uname=$uname"    if $uname;
         newWin.focus();      } elsif ($activity eq 'docs') {
     }          $querystring .= '&amp;url='.&HTML::Entities::encode($url,'&"');
       }
   
       my $output .= <<'END_MYBLOCK';
   function openWindow(url, wdwName, w, h, toolbar,scrollbar) {
       var options = "width=" + w + ",height=" + h + ",";
       options += "resizable=yes,scrollbars="+scrollbar+",status=no,";
       options += "menubar=no,toolbar="+toolbar+",location=no,directories=no";
       var newWin = window.open(url, wdwName, options);
       newWin.focus();
   }
 END_MYBLOCK  END_MYBLOCK
   
   $output = Apache::lonhtmlcommon::scripttag($output);      $output = Apache::lonhtmlcommon::scripttag($output);
       
   my $popupUrl = "/adm/blockingstatus/$querystring";      my $popupUrl = "/adm/blockingstatus/$querystring";
   my $text = mt('Communication Blocked');      my $text = &mt('Communication Blocked');
       if ($activity eq 'docs') {
   $output .= <<"END_BLOCK";          $text = &mt('Content Access Blocked');
       } elsif ($activity eq 'printout') {
           $text = &mt('Printing Blocked');
       }
       $output .= <<"END_BLOCK";
 <div class='LC_comblock'>  <div class='LC_comblock'>
   <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'    <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'
   title='$text'>    title='$text'>
Line 4244  END_MYBLOCK Line 4418  END_MYBLOCK
   
 END_BLOCK  END_BLOCK
   
   return ($blocked, $output);      return ($blocked, $output);
 }  }
   
 ###############################################  ###############################################
Line 4761  sub bodytag { Line 4935  sub bodytag {
     if ($public) {      if ($public) {
  undef($role);   undef($role);
     } else {      } else {
  $name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'});   $name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'},
                                   undef,'LC_menubuttons_link');
     }      }
           
     my $titleinfo = '<h1>'.$title.'</h1>';      my $titleinfo = '<h1>'.$title.'</h1>';
Line 4838  sub bodytag { Line 5013  sub bodytag {
 sub dc_courseid_toggle {  sub dc_courseid_toggle {
     my ($dc_info) = @_;      my ($dc_info) = @_;
     return ' <span id="dccidtext" class="LC_cusr_subheading LC_nobreak">'.      return ' <span id="dccidtext" class="LC_cusr_subheading LC_nobreak">'.
            '<a href="javascript:showCourseID();">'.             '<a href="javascript:showCourseID();" class="LC_menubuttons_link">'.
            &mt('(More ...)').'</a></span>'.             &mt('(More ...)').'</a></span>'.
            '<div id="dccid" class="LC_dccid">'.$dc_info.'</div>';             '<div id="dccid" class="LC_dccid">'.$dc_info.'</div>';
 }  }
Line 4943  sub standard_css { Line 5118  sub standard_css {
     my $mono                 = 'monospace';      my $mono                 = 'monospace';
     my $data_table_head      = $sidebg;      my $data_table_head      = $sidebg;
     my $data_table_light     = '#FAFAFA';      my $data_table_light     = '#FAFAFA';
     my $data_table_dark      = '#F0F0F0';      my $data_table_dark      = '#E0E0E0';
     my $data_table_darker    = '#CCCCCC';      my $data_table_darker    = '#CCCCCC';
     my $data_table_highlight = '#FFFF00';      my $data_table_highlight = '#FFFF00';
     my $mail_new             = '#FFBB77';      my $mail_new             = '#FFBB77';
Line 4983  body { Line 5158  body {
 a:focus,  a:focus,
 a:focus img {  a:focus img {
   color: red;    color: red;
   background: yellow;  
 }  }
   
 form, .inline {  form, .inline {
Line 5078  div.LC_confirm_box .LC_success img { Line 5252  div.LC_confirm_box .LC_success img {
 }  }
   
 .LC_discussion {  .LC_discussion {
   background: $tabbg;    background: $data_table_dark;
   border: 1px solid black;    border: 1px solid black;
   margin: 2px;    margin: 2px;
 }  }
   
 .LC_disc_action_links_bar {  
   background: $tabbg;  
   border: none;  
   margin: 4px;  
 }  
   
 .LC_disc_action_left {  .LC_disc_action_left {
     background: $sidebg;
   text-align: left;    text-align: left;
     padding: 4px;
     margin: 2px;
 }  }
   
 .LC_disc_action_right {  .LC_disc_action_right {
     background: $sidebg;
   text-align: right;    text-align: right;
     padding: 4px;
     margin: 2px;
 }  }
   
 .LC_disc_new_item {  .LC_disc_new_item {
   background: white;    background: white;
   border: 2px solid red;    border: 2px solid red;
   margin: 2px;    margin: 4px;
     padding: 4px;
 }  }
   
 .LC_disc_old_item {  .LC_disc_old_item {
   background: white;    background: white;
   border: 1px solid black;    margin: 4px;
   margin: 2px;    padding: 4px;
 }  }
   
 table.LC_pastsubmission {  table.LC_pastsubmission {
Line 5228  td.LC_table_cell_checkbox { Line 5403  td.LC_table_cell_checkbox {
   vertical-align: middle;    vertical-align: middle;
 }  }
   
 li.LC_menubuttons_inline_text img,a {  li.LC_menubuttons_inline_text img {
   cursor:pointer;    cursor:pointer;
   text-decoration: none;    text-decoration: none;
 }  }
Line 6030  div.LC_edit_problem_footer { Line 6205  div.LC_edit_problem_footer {
   font-weight: normal;    font-weight: normal;
   font-size:  medium;    font-size:  medium;
   margin: 2px;    margin: 2px;
     background-color: $sidebg;
 }  }
   
 div.LC_edit_problem_header,  div.LC_edit_problem_header,
Line 6046  div.LC_edit_problem_header_title { Line 6222  div.LC_edit_problem_header_title {
   font-size: larger;    font-size: larger;
   background: $tabbg;    background: $tabbg;
   padding: 3px;    padding: 3px;
     margin: 0 0 5px 0;
 }  }
   
 table.LC_edit_problem_header_title {  table.LC_edit_problem_header_title {
Line 6083  div.LC_createcourse { Line 6260  div.LC_createcourse {
   display:none;    display:none;
 }  }
   
 a:hover,  
 ol.LC_primary_menu a:hover,  ol.LC_primary_menu a:hover,
 ol#LC_MenuBreadcrumbs a:hover,  ol#LC_MenuBreadcrumbs a:hover,
 ol#LC_PathBreadcrumbs a:hover,  ol#LC_PathBreadcrumbs a:hover,
Line 6317  ul.LC_TabContent li.active a { Line 6493  ul.LC_TabContent li.active a {
   background:#FFFFFF;    background:#FFFFFF;
   outline: none;    outline: none;
 }  }
   
   ul.LC_TabContent li.goback {
     float: left;
     border-left: none;
   }
   
 #maincoursedoc {  #maincoursedoc {
   clear:both;    clear:both;
 }  }
Line 6566  a#LC_content_toolbar_changefolder_toggle Line 6748  a#LC_content_toolbar_changefolder_toggle
   background-image:url(/res/adm/pages/open-all-folders.gif);    background-image:url(/res/adm/pages/open-all-folders.gif);
 }  }
   
   a#LC_content_toolbar_edittoplevel {
     background-image:url(/res/adm/pages/edittoplevel.gif);
   }
   
 ul#LC_toolbar li a:hover {  ul#LC_toolbar li a:hover {
   background-position: bottom center;    background-position: bottom center;
 }  }
Line 6634  ul.LC_funclist li { Line 6820  ul.LC_funclist li {
   display: none;    display: none;
 }  }
   
   .LCmodal-overlay {
    position:fixed;
    top:0;
    right:0;
    bottom:0;
    left:0;
    height:100%;
    width:100%;
    margin:0;
    padding:0;
    background:#999;
    opacity:.75;
    filter: alpha(opacity=75);
    -moz-opacity: 0.75;
    z-index:101;
   }
   
   * html .LCmodal-overlay {   
    position: absolute;
    height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
   }
   
   .LCmodal-window {
    position:fixed;
    top:50%;
    left:50%;
    margin:0;
    padding:0;
    z-index:102;
    }
   
   * html .LCmodal-window {
    position:absolute;
   }
   
   .LCclose-window {
    position:absolute;
    width:32px;
    height:32px;
    right:8px;
    top:8px;
    background:transparent url('/res/adm/pages/process-stop.png') no-repeat scroll right top;
    text-indent:-99999px;
    overflow:hidden;
    cursor:pointer;
   }
   
 END  END
 }  }
   
Line 6682  sub headtag { Line 6915  sub headtag {
  '<head>'.   '<head>'.
  &font_settings();   &font_settings();
   
       my $inhibitprint = &print_suppression();
   
     if (!$args->{'frameset'}) {      if (!$args->{'frameset'}) {
  $result .= &Apache::lonhtmlcommon::htmlareaheaders();   $result .= &Apache::lonhtmlcommon::htmlareaheaders();
     }      }
Line 6692  sub headtag { Line 6927  sub headtag {
  && !$args->{'only_body'}   && !$args->{'only_body'}
  && !$args->{'frameset'}) {   && !$args->{'frameset'}) {
  $result .= &help_menu_js();   $result .= &help_menu_js();
           $result.=&modal_window();
           $result.=&togglebox_script();
           $result.=&wishlist_window();
           $result.=&LCprogressbarUpdate_script();
       } else {
           if ($args->{'add_modal'}) {
              $result.=&modal_window();
           }
           if ($args->{'add_wishlist'}) {
              $result.=&wishlist_window();
           }
           if ($args->{'add_togglebox'}) {
              $result.=&togglebox_script();
           }
           if ($args->{'add_progressbar'}) {
              $result.=&LCprogressbarUpdate_script();
           }
     }      }
   
     if (ref($args->{'redirect'})) {      if (ref($args->{'redirect'})) {
  my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};   my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};
  $url = &Apache::lonenc::check_encrypt($url);   $url = &Apache::lonenc::check_encrypt($url);
Line 6711  ADDMETA Line 6962  ADDMETA
     if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }      if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
     $result .= '<title> LON-CAPA '.$title.'</title>'      $result .= '<title> LON-CAPA '.$title.'</title>'
  .'<link rel="stylesheet" type="text/css" href="'.$url.'" />'   .'<link rel="stylesheet" type="text/css" href="'.$url.'" />'
           .$inhibitprint
  .$head_extra;   .$head_extra;
     return $result.'</head>';      return $result.'</head>';
 }  }
Line 6736  sub font_settings { Line 6988  sub font_settings {
   
 =pod  =pod
   
   =item * &print_suppression()
   
   In course context returns css which causes the body to be blank when media="print",
   if printout generation is unavailable for the current resource.
   
   This could be because:
   
   (a) printstartdate is in the future
   
   (b) printenddate is in the past
   
   (c) there is an active exam block with "printout"
   functionality blocked
   
   Users with pav, pfo or evb privileges are exempt.
   
   Inputs: none
   
   =cut
   
   
   sub print_suppression {
       my $noprint;
       if ($env{'request.course.id'}) {
           my $scope = $env{'request.course.id'};
           if ((&Apache::lonnet::allowed('pav',$scope)) ||
               (&Apache::lonnet::allowed('pfo',$scope))) {
               return;
           }
           if ($env{'request.course.sec'} ne '') {
               $scope .= "/$env{'request.course.sec'}";
               if ((&Apache::lonnet::allowed('pav',$scope)) ||
                   (&Apache::lonnet::allowed('pfo',$scope))) {
                   return;
               }
           }
           my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
           my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
           my $blocked = &blocking_status('printout',$cnum,$cdom);
           if ($blocked) {
               my $checkrole = "cm./$cdom/$cnum";
               if ($env{'request.course.sec'} ne '') {
                   $checkrole .= "/$env{'request.course.sec'}";
               }
               unless ((&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) &&
                       ($env{'request.role'} !~ m{^st\./$cdom/$cnum})) {
                   $noprint = 1;
               }
           }
           unless ($noprint) {
               my $symb = &Apache::lonnet::symbread();
               if ($symb ne '') {
                   my $navmap = Apache::lonnavmaps::navmap->new();
                   if (ref($navmap)) {
                       my $res = $navmap->getBySymb($symb);
                       if (ref($res)) {
                           if (!$res->resprintable()) {
                               $noprint = 1;
                           }
                       }
                   }
               }
           }
           if ($noprint) {
               return <<"ENDSTYLE";
   <style type="text/css" media="print">
       body { display:none }
   </style>
   ENDSTYLE
           }
       }
       return;
   }
   
   =pod
   
 =item * &xml_begin()  =item * &xml_begin()
   
 Returns the needed doctype and <html>  Returns the needed doctype and <html>
Line 6818  $args - additional optional args support Line 7146  $args - additional optional args support
 sub start_page {  sub start_page {
     my ($title,$head_extra,$args) = @_;      my ($title,$head_extra,$args) = @_;
     #&Apache::lonnet::logthis("start_page ".join(':',caller(0)));      #&Apache::lonnet::logthis("start_page ".join(':',caller(0)));
 #SD  
 #I don't see why we copy certain elements of %$args to %head_args  
 #head args is passed to headtag() and this routine only reads those  
 #keys that are needed. There doesn't happen any writes or any processing  
 #of other keys.  
 #proposal: just pass $args to headtag instead of \%head_args and delete   
 #marked lines  
 #<- MARK  
     my %head_args;  
     foreach my $arg ('redirect','force_register','domain','function',  
      'bgcolor','frameset','no_nav_bar','only_body',  
      'no_auto_mt_title') {  
  if (defined($args->{$arg})) {  
     $head_args{$arg} = $args->{$arg};  
  }  
     }  
 #MARK ->  
   
     $env{'internal.start_page'}++;      $env{'internal.start_page'}++;
     my $result;      my $result;
   
     if (! exists($args->{'skip_phases'}{'head'}) ) {      if (! exists($args->{'skip_phases'}{'head'}) ) {
         $result .=           $result .= &xml_begin() . &headtag($title, $head_extra, $args);
                   &xml_begin() . &headtag($title,$head_extra,\%head_args);  
 #replace prev line by  
 #                 &xml_begin() . &headtag($title, $head_extra, $args);  
     }      }
           
     if (! exists($args->{'skip_phases'}{'body'}) ) {      if (! exists($args->{'skip_phases'}{'body'}) ) {
Line 6909  sub end_page { Line 7217  sub end_page {
  }   }
  $result .= &Apache::lonxml::xmlend($target,$parser);   $result .= &Apache::lonxml::xmlend($target,$parser);
     }      }
   
     if ($args->{'frameset'}) {      if ($args->{'frameset'}) {
  $result .= '</frameset>';   $result .= '</frameset>';
     } else {      } else {
Line 6928  sub end_page { Line 7235  sub end_page {
     return $result;      return $result;
 }  }
   
   sub wishlist_window {
       return(<<'ENDWISHLIST');
   <script type="text/javascript">
   // <![CDATA[
   // <!-- BEGIN LON-CAPA Internal
   function set_wishlistlink(title, path) {
       if (!title) {
           title = document.title;
           title = title.replace(/^LON-CAPA /,'');
       }
       if (!path) {
           path = location.pathname;
       }
       Win = window.open('/adm/wishlist?mode=newLink&setTitle='+title+'&setPath='+path,
                         'wishlistNewLink','width=560,height=350,scrollbars=0');
   }
   // END LON-CAPA Internal -->
   // ]]>
   </script>
   ENDWISHLIST
   }
   
   sub modal_window {
       return(<<'ENDMODAL');
   <script type="text/javascript">
   // <![CDATA[
   // <!-- BEGIN LON-CAPA Internal
   var modalWindow = {
    parent:"body",
    windowId:null,
    content:null,
    width:null,
    height:null,
    close:function()
    {
           $(".LCmodal-window").remove();
           $(".LCmodal-overlay").remove();
    },
    open:function()
    {
    var modal = "";
    modal += "<div class=\"LCmodal-overlay\"></div>";
    modal += "<div id=\"" + this.windowId + "\" class=\"LCmodal-window\" style=\"width:" + this.width + "px; height:" + this.height + "px; margin-top:-" + (this.height / 2) + "px; margin-left:-" + (this.width / 2) + "px;\">";
    modal += this.content;
    modal += "</div>";
   
    $(this.parent).append(modal);
   
    $(".LCmodal-window").append("<a class=\"LCclose-window\"></a>");
    $(".LCclose-window").click(function(){modalWindow.close();});
    $(".LCmodal-overlay").click(function(){modalWindow.close();});
    }
   };
    var openMyModal = function(source,width,height,scrolling)
    {
    modalWindow.windowId = "myModal";
    modalWindow.width = width;
    modalWindow.height = height;
    modalWindow.content = "<iframe width='"+width+"' height='"+height+"' frameborder='0' scrolling='"+scrolling+"' allowtransparency='true' src='" + source + "'>&lt/iframe>";
    modalWindow.open();
    };
   // END LON-CAPA Internal -->
   // ]]>
   </script>
   ENDMODAL
   }
   
   sub modal_link {
       my ($link,$linktext,$width,$height,$target,$scrolling,$title)=@_;
       unless ($width) { $width=480; }
       unless ($height) { $height=400; }
       unless ($scrolling) { $scrolling='yes'; }
       return '<a href="'.$link.'" target="'.$target.'" title="'.$title.'" onclick="openMyModal(\''.$link.'\','.$width.','.$height.',\''.$scrolling.'\'); return false;">'.
              $linktext.'</a>';
   }
   
   sub modal_adhoc_script {
       my ($funcname,$width,$height,$content)=@_;
       return (<<ENDADHOC);
   <script type="text/javascript">
   // <![CDATA[
           var $funcname = function()
           {
                   modalWindow.windowId = "myModal";
                   modalWindow.width = $width;
                   modalWindow.height = $height;
                   modalWindow.content = '$content';
                   modalWindow.open();
           };  
   // ]]>
   </script>
   ENDADHOC
   }
   
   sub modal_adhoc_inner {
       my ($funcname,$width,$height,$content)=@_;
       my $innerwidth=$width-20;
       $content=&js_ready(
                  &start_page('Dialog',undef,{'only_body'=>1,'bgcolor'=>'#FFFFFF'}).
                    &start_scrollbox($width.'px',$innerwidth.'px',$height.'px').
                       $content.
                    &end_scrollbox().
                  &end_page()
                );
       return &modal_adhoc_script($funcname,$width,$height,$content);
   }
   
   sub modal_adhoc_window {
       my ($funcname,$width,$height,$content,$linktext)=@_;
       return &modal_adhoc_inner($funcname,$width,$height,$content).
              "<a href=\"javascript:$funcname();void(0);\">".$linktext."</a>";
   }
   
   sub modal_adhoc_launch {
       my ($funcname,$width,$height,$content)=@_;
       return &modal_adhoc_inner($funcname,$width,$height,$content).(<<ENDLAUNCH);
   <script type="text/javascript">
   // <![CDATA[
   $funcname();
   // ]]>
   </script>
   ENDLAUNCH
   }
   
   sub modal_adhoc_close {
       return (<<ENDCLOSE);
   <script type="text/javascript">
   // <![CDATA[
   modalWindow.close();
   // ]]>
   </script>
   ENDCLOSE
   }
   
   sub togglebox_script {
      return(<<ENDTOGGLE);
   <script type="text/javascript"> 
   // <![CDATA[
   function LCtoggleDisplay(id,hidetext,showtext) {
      link = document.getElementById(id + "link").childNodes[0];
      with (document.getElementById(id).style) {
         if (display == "none" ) {
             display = "inline";
             link.nodeValue = hidetext;
           } else {
             display = "none";
             link.nodeValue = showtext;
          }
      }
   }
   // ]]>
   </script>
   ENDTOGGLE
   }
   
   sub start_togglebox {
       my ($id,$heading,$headerbg,$hidetext,$showtext)=@_;
       unless ($heading) { $heading=''; } else { $heading.=' '; }
       unless ($showtext) { $showtext=&mt('show'); }
       unless ($hidetext) { $hidetext=&mt('hide'); }
       unless ($headerbg) { $headerbg='#FFFFFF'; }
       return &start_data_table().
              &start_data_table_header_row().
              '<td bgcolor="'.$headerbg.'">'.$heading.
              '[<a id="'.$id.'link" href="javascript:LCtoggleDisplay(\''.$id.'\',\''.$hidetext.'\',\''.
              $showtext.'\')">'.$showtext.'</a>]</td>'.
              &end_data_table_header_row().
              '<tr id="'.$id.'" style="display:none""><td>';
   }
   
   sub end_togglebox {
       return '</td></tr>'.&end_data_table();
   }
   
   sub LCprogressbar_script {
      my ($id)=@_;
      return(<<ENDPROGRESS);
   <script type="text/javascript">
   // <![CDATA[
   \$('#progressbar$id').progressbar({
     value: 0,
     change: function(event, ui) {
       var newVal = \$(this).progressbar('option', 'value');
       \$('.pblabel', this).text(LCprogressTxt);
     }
   });
   // ]]>
   </script>
   ENDPROGRESS
   }
   
   sub LCprogressbarUpdate_script {
      return(<<ENDPROGRESSUPDATE);
   <style type="text/css">
   .ui-progressbar { position:relative; }
   .pblabel { position: absolute; width: 100%; text-align: center; line-height: 1.9em; }
   </style>
   <script type="text/javascript">
   // <![CDATA[
   var LCprogressTxt='---';
   
   function LCupdateProgress(percent,progresstext,id) {
      LCprogressTxt=progresstext;
      \$('#progressbar'+id).progressbar('value',percent);
   }
   // ]]>
   </script>
   ENDPROGRESSUPDATE
   }
   
   my $LClastpercent;
   my $LCidcnt;
   my $LCcurrentid;
   
   sub LCprogressbar {
       my ($r)=(@_);
       $LClastpercent=0;
       $LCidcnt++;
       $LCcurrentid=$$.'_'.$LCidcnt;
       my $starting=&mt('Starting');
       my $content=(<<ENDPROGBAR);
   <p>
     <div id="progressbar$LCcurrentid">
       <span class="pblabel">$starting</span>
     </div>
   </p>
   ENDPROGBAR
       &r_print($r,$content.&LCprogressbar_script($LCcurrentid));
   }
   
   sub LCprogressbarUpdate {
       my ($r,$val,$text)=@_;
       unless ($val) { 
          if ($LClastpercent) {
              $val=$LClastpercent;
          } else {
              $val=0;
          }
       }
       if ($val<0) { $val=0; }
       if ($val>100) { $val=0; }
       $LClastpercent=$val;
       unless ($text) { $text=$val.'%'; }
       $text=&js_ready($text);
       &r_print($r,<<ENDUPDATE);
   <script type="text/javascript">
   // <![CDATA[
   LCupdateProgress($val,'$text','$LCcurrentid');
   // ]]>
   </script>
   ENDUPDATE
   }
   
   sub LCprogressbarClose {
       my ($r)=@_;
       $LClastpercent=0;
       &r_print($r,<<ENDCLOSE);
   <script type="text/javascript">
   // <![CDATA[
   \$("#progressbar$LCcurrentid").hide('slow'); 
   // ]]>
   </script>
   ENDCLOSE
   }
   
   sub r_print {
       my ($r,$to_print)=@_;
       if ($r) {
         $r->print($to_print);
         $r->rflush();
       } else {
         print($to_print);
       }
   }
   
 sub html_encode {  sub html_encode {
     my ($result) = @_;      my ($result) = @_;
   
Line 6935  sub html_encode { Line 7517  sub html_encode {
           
     return $result;      return $result;
 }  }
   
 sub js_ready {  sub js_ready {
     my ($result) = @_;      my ($result) = @_;
   
Line 6986  sub start_scrollbox { Line 7569  sub start_scrollbox {
 }  }
   
 sub end_scrollbox {  sub end_scrollbox {
     return '</td></tr></table>';      return '</div></td></tr></table>';
 }  }
   
 sub simple_error_page {  sub simple_error_page {
Line 7208  role status: active, previous or future. Line 7791  role status: active, previous or future.
   
 sub check_user_status {  sub check_user_status {
     my ($udom,$uname,$cdom,$crs,$role,$sec) = @_;      my ($udom,$uname,$cdom,$crs,$role,$sec) = @_;
     my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1});      my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname);
     my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname,'.',undef,$extra);  
     my @uroles = keys %userinfo;      my @uroles = keys %userinfo;
     my $srchstr;      my $srchstr;
     my $active_chk = 'none';      my $active_chk = 'none';
Line 8265  sub get_standard_codeitems { Line 8847  sub get_standard_codeitems {
   
 =item * sorted_slots()  =item * sorted_slots()
   
 Sorts an array of slot names in order of slot start time (earliest first).   Sorts an array of slot names in order of an optional sort key,
   default sort is by slot start time (earliest first). 
   
 Inputs:  Inputs:
   
Line 8275  slotsarr  - Reference to array of unsort Line 8858  slotsarr  - Reference to array of unsort
   
 slots     - Reference to hash of hash, where outer hash keys are slot names.  slots     - Reference to hash of hash, where outer hash keys are slot names.
   
   sortkey   - Name of key in inner hash to be sorted on (e.g., starttime).
   
 =back  =back
   
 Returns:  Returns:
   
 =over 4  =over 4
   
 sorted   - An array of slot names sorted by the start time of the slot.  sorted   - An array of slot names sorted by a specified sort key 
              (default sort key is start time of the slot).
 =back  
   
 =back  =back
   
Line 8291  sorted   - An array of slot names sorted Line 8875  sorted   - An array of slot names sorted
   
   
 sub sorted_slots {  sub sorted_slots {
     my ($slotsarr,$slots) = @_;      my ($slotsarr,$slots,$sortkey) = @_;
       if ($sortkey eq '') {
           $sortkey = 'starttime';
       }
     my @sorted;      my @sorted;
     if ((ref($slotsarr) eq 'ARRAY') && (ref($slots) eq 'HASH')) {      if ((ref($slotsarr) eq 'ARRAY') && (ref($slots) eq 'HASH')) {
         @sorted =          @sorted =
             sort {              sort {
                      if (ref($slots->{$a}) && ref($slots->{$b})) {                       if (ref($slots->{$a}) && ref($slots->{$b})) {
                          return $slots->{$a}{'starttime'} <=> $slots->{$b}{'starttime'}                           return $slots->{$a}{$sortkey} <=> $slots->{$b}{$sortkey}
                      }                       }
                      if (ref($slots->{$a})) { return -1;}                       if (ref($slots->{$a})) { return -1;}
                      if (ref($slots->{$b})) { return 1;}                       if (ref($slots->{$b})) { return 1;}
Line 8307  sub sorted_slots { Line 8894  sub sorted_slots {
     return @sorted;      return @sorted;
 }  }
   
   =pod
   
   =item * get_future_slots()
   
   Inputs:
   
   =over 4
   
   cnum - course number
   
   cdom - course domain
   
   now - current UNIX time
   
   symb - optional symb
   
   =back
   
   Returns:
   
   =over 4
   
   sorted_reservable - ref to array of student_schedulable slots currently 
                       reservable, ordered by end date of reservation period.
   
   reservable_now - ref to hash of student_schedulable slots currently
                    reservable.
   
       Keys in inner hash are:
       (a) symb: either blank or symb to which slot use is restricted.
       (b) endreserve: end date of reservation period. 
   
   sorted_future - ref to array of student_schedulable slots reservable in
                   the future, ordered by start date of reservation period.
   
   future_reservable - ref to hash of student_schedulable slots reservable
                       in the future.
   
       Keys in inner hash are:
       (a) symb: either blank or symb to which slot use is restricted.
       (b) startreserve:  start date of reservation period.
   
   =back
   
   =cut
   
   sub get_future_slots {
       my ($cnum,$cdom,$now,$symb) = @_;
       my (%reservable_now,%future_reservable,@sorted_reservable,@sorted_future);
       my %slots = &Apache::lonnet::get_course_slots($cnum,$cdom);
       foreach my $slot (keys(%slots)) {
           next unless($slots{$slot}->{'type'} eq 'schedulable_student');
           if ($symb) {
               next if (($slots{$slot}->{'symb'} ne '') && 
                        ($slots{$slot}->{'symb'} ne $symb));
           }
           if (($slots{$slot}->{'starttime'} > $now) &&
               ($slots{$slot}->{'endtime'} > $now)) {
               if (($slots{$slot}->{'allowedsections'}) || ($slots{$slot}->{'allowedusers'})) {
                   my $userallowed = 0;
                   if ($slots{$slot}->{'allowedsections'}) {
                       my @allowed_sec = split(',',$slots{$slot}->{'allowedsections'});
                       if (!defined($env{'request.role.sec'})
                           && grep(/^No section assigned$/,@allowed_sec)) {
                           $userallowed=1;
                       } else {
                           if (grep(/^\Q$env{'request.role.sec'}\E$/,@allowed_sec)) {
                               $userallowed=1;
                           }
                       }
                       unless ($userallowed) {
                           if (defined($env{'request.course.groups'})) {
                               my @groups = split(/:/,$env{'request.course.groups'});
                               foreach my $group (@groups) {
                                   if (grep(/^\Q$group\E$/,@allowed_sec)) {
                                       $userallowed=1;
                                       last;
                                   }
                               }
                           }
                       }
                   }
                   if ($slots{$slot}->{'allowedusers'}) {
                       my @allowed_users = split(',',$slots{$slot}->{'allowedusers'});
                       my $user = $env{'user.name'}.':'.$env{'user.domain'};
                       if (grep(/^\Q$user\E$/,@allowed_users)) {
                           $userallowed = 1;
                       }
                   }
                   next unless($userallowed);
               }
               my $startreserve = $slots{$slot}->{'startreserve'};
               my $endreserve = $slots{$slot}->{'endreserve'};
               my $symb = $slots{$slot}->{'symb'};
               if (($startreserve < $now) &&
                   (!$endreserve || $endreserve > $now)) {
                   my $lastres = $endreserve;
                   if (!$lastres) {
                       $lastres = $slots{$slot}->{'starttime'};
                   }
                   $reservable_now{$slot} = {
                                              symb       => $symb,
                                              endreserve => $lastres
                                            };
               } elsif (($startreserve > $now) &&
                        (!$endreserve || $endreserve > $startreserve)) {
                   $future_reservable{$slot} = {
                                                 symb         => $symb,
                                                 startreserve => $startreserve
                                               };
               }
           }
       }
       my @unsorted_reservable = keys(%reservable_now);
       if (@unsorted_reservable > 0) {
           @sorted_reservable = 
               &sorted_slots(\@unsorted_reservable,\%reservable_now,'endreserve');
       }
       my @unsorted_future = keys(%future_reservable);
       if (@unsorted_future > 0) {
           @sorted_future =
               &sorted_slots(\@unsorted_future,\%future_reservable,'startreserve');
       }
       return (\@sorted_reservable,\%reservable_now,\@sorted_future,\%future_reservable);
   }
   
 =pod  =pod
   
   =back
   
 =head1 HTTP Helpers  =head1 HTTP Helpers
   
 =over 4  =over 4
Line 8448  sub get_env_multiple { Line 9162  sub get_env_multiple {
   
 sub ask_for_embedded_content {  sub ask_for_embedded_content {
     my ($actionurl,$state,$allfiles,$codebase,$args)=@_;      my ($actionurl,$state,$allfiles,$codebase,$args)=@_;
     my (%subdependencies,%dependencies,%mapping,%existing,%newfiles,%pathchanges);      my (%subdependencies,%dependencies,%mapping,%existing,%newfiles,%pathchanges,
     my $num = 0;          %currsubfile,%unused);
       my $counter = 0;
       my $numnew = 0;
     my $numremref = 0;      my $numremref = 0;
     my $numinvalid = 0;      my $numinvalid = 0;
     my $numpathchg = 0;      my $numpathchg = 0;
     my $numexisting = 0;      my $numexisting = 0;
     my ($output,$upload_output,$toplevel,$url,$udom,$uname,$getpropath);      my $numunused = 0;
       my ($output,$upload_output,$toplevel,$url,$udom,$uname,$getpropath,$cdom,$cnum,
           $fileloc,$filename,$delete_output,$modify_output,$title,$symb,$path);
       my $heading = &mt('Upload embedded files');
       my $buttontext = &mt('Upload');
   
     if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {      if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {
         my $current_path='/';          my $current_path='/';
         if ($env{'form.currentpath'}) {          if ($env{'form.currentpath'}) {
Line 8482  sub ask_for_embedded_content { Line 9203  sub ask_for_embedded_content {
         }          }
     } elsif ($actionurl eq '/adm/coursedocs') {      } elsif ($actionurl eq '/adm/coursedocs') {
         if (ref($args) eq 'HASH') {          if (ref($args) eq 'HASH') {
            $url = $args->{'docs_url'};              $url = $args->{'docs_url'};
            $toplevel = $url;              $toplevel = $url;
           }
       } elsif ($actionurl eq '/adm/dependencies') {
           if ($env{'request.course.id'} ne '') {
               $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
               $cnum =  $env{'course.'.$env{'request.course.id'}.'.num'};
               if (ref($args) eq 'HASH') {
                   $url = $args->{'docs_url'};
                   $title = $args->{'docs_title'};
                   $toplevel = "/$url";
                   ($path) =  
                       ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});
                   $fileloc = &Apache::lonnet::filelocation('',$toplevel);
                   $fileloc =~ s{^/}{};
                   ($filename) = ($fileloc =~ m{.+/([^/]+)$});
                   $heading = &mt('Status of dependencies in [_1]',"$title ($filename)");
               }
         }          }
     }      }
     my $now = time();      my $now = time();
Line 8522  sub ask_for_embedded_content { Line 9259  sub ask_for_embedded_content {
             }              }
         }          }
     }      }
       my $dirptr = 16384;
     foreach my $path (keys(%subdependencies)) {      foreach my $path (keys(%subdependencies)) {
         my %currsubfile;          $currsubfile{$path} = {};
         if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {           if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) { 
             my ($sublistref,$listerror) =              my ($sublistref,$listerror) =
                 &Apache::lonnet::dirlist($url.$path,$udom,$uname,$getpropath);                  &Apache::lonnet::dirlist($url.$path,$udom,$uname,$getpropath);
             if (ref($sublistref) eq 'ARRAY') {              if (ref($sublistref) eq 'ARRAY') {
                 foreach my $line (@{$sublistref}) {                  foreach my $line (@{$sublistref}) {
                     my ($file_name,$rest) = split(/\&/,$line,2);                      my ($file_name,$rest) = split(/\&/,$line,2);
                     $currsubfile{$file_name} = 1;                      $currsubfile{$path}{$file_name} = 1;
                 }                  }
             }              }
         } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) {          } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) {
             if (opendir(my $dir,$url.'/'.$path)) {              if (opendir(my $dir,$url.'/'.$path)) {
                 my @subdir_list = grep(!/^\./,readdir($dir));                  my @subdir_list = grep(!/^\./,readdir($dir));
                 map {$currsubfile{$_} = 1;} @subdir_list;                  map {$currsubfile{$path}{$_} = 1;} @subdir_list;
               }
           } elsif ($actionurl eq '/adm/dependencies') {
               if ($env{'request.course.id'} ne '') {
                   my ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});
                   if ($dir ne '') {
                       my ($sublistref,$listerror) =
                           &Apache::lonnet::dirlist($dir.$path,$cdom,$cnum,$getpropath,undef,'/');
                       if (ref($sublistref) eq 'ARRAY') {
                           foreach my $line (@{$sublistref}) {
                               my ($file_name,$dom,undef,$testdir,undef,undef,undef,undef,$size,
                                   undef,$mtime)=split(/\&/,$line,12);
                               unless (($testdir&$dirptr) ||
                                       ($file_name =~ /^\.\.?$/)) {
                                   $currsubfile{$path}{$file_name} = [$size,$mtime];
                               }
                           }
                       }
                   }
             }              }
         }          }
         foreach my $file (keys(%{$subdependencies{$path}})) {          foreach my $file (keys(%{$subdependencies{$path}})) {
             if ($currsubfile{$file}) {              if (exists($currsubfile{$path}{$file})) {
                 my $item = $path.'/'.$file;                  my $item = $path.'/'.$file;
                 unless ($mapping{$item} eq $item) {                  unless ($mapping{$item} eq $item) {
                     $pathchanges{$item} = 1;                      $pathchanges{$item} = 1;
Line 8551  sub ask_for_embedded_content { Line 9307  sub ask_for_embedded_content {
                 $newfiles{$path.'/'.$file} = 1;                  $newfiles{$path.'/'.$file} = 1;
             }              }
         }          }
           if ($actionurl eq '/adm/dependencies') {
               foreach my $path (keys(%currsubfile)) {
                   if (ref($currsubfile{$path}) eq 'HASH') {
                       foreach my $file (keys(%{$currsubfile{$path}})) {
                            unless ($subdependencies{$path}{$file}) {
                                $unused{$path.'/'.$file} = 1; 
                            }
                       }
                   }
               }
           }
     }      }
     my %currfile;      my %currfile;
     if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {      if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {
Line 8567  sub ask_for_embedded_content { Line 9334  sub ask_for_embedded_content {
             my @dir_list = grep(!/^\./,readdir($dir));              my @dir_list = grep(!/^\./,readdir($dir));
             map {$currfile{$_} = 1;} @dir_list;              map {$currfile{$_} = 1;} @dir_list;
         }          }
       } elsif ($actionurl eq '/adm/dependencies') {
           if ($env{'request.course.id'} ne '') {
               my ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});
               if ($dir ne '') {
                   my ($dirlistref,$listerror) =
                       &Apache::lonnet::dirlist($dir,$cdom,$cnum,$getpropath,undef,'/');
                   if (ref($dirlistref) eq 'ARRAY') {
                       foreach my $line (@{$dirlistref}) {
                           my ($file_name,$dom,undef,$testdir,undef,undef,undef,undef,
                               $size,undef,$mtime)=split(/\&/,$line,12);
                           unless (($testdir&$dirptr) ||
                                   ($file_name =~ /^\.\.?$/)) {
                               $currfile{$file_name} = [$size,$mtime];
                           }
                       }
                   }
               }
           }
     }      }
     foreach my $file (keys(%dependencies)) {      foreach my $file (keys(%dependencies)) {
         if ($currfile{$file}) {          if (exists($currfile{$file})) {
             unless ($mapping{$file} eq $file) {              unless ($mapping{$file} eq $file) {
                 $pathchanges{$file} = 1;                  $pathchanges{$file} = 1;
             }              }
Line 8579  sub ask_for_embedded_content { Line 9364  sub ask_for_embedded_content {
             $newfiles{$file} = 1;              $newfiles{$file} = 1;
         }          }
     }      }
       foreach my $file (keys(%currfile)) {
           unless (($file eq $filename) ||
                   ($file eq $filename.'.bak') ||
                   ($dependencies{$file})) {
               $unused{$file} = 1;
           }
       }
     foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%newfiles)) {      foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%newfiles)) {
           if ($actionurl eq '/adm/dependencies') {
               next if ($embed_file =~ m{^\w+://});
           }
         $upload_output .= &start_data_table_row().          $upload_output .= &start_data_table_row().
                           '<td><span class="LC_filename">'.$embed_file.'</span>';                            '<td><img src="'.&icon($embed_file).'" />&nbsp;'.
                             '<span class="LC_filename">'.$embed_file.'</span>';
         unless ($mapping{$embed_file} eq $embed_file) {          unless ($mapping{$embed_file} eq $embed_file) {
             $upload_output .= '<br /><span class="LC_info" style="font-size:smaller;">'.&mt('changed from: [_1]',$mapping{$embed_file}).'</span>';              $upload_output .= '<br /><span class="LC_info" style="font-size:smaller;">'.&mt('changed from: [_1]',$mapping{$embed_file}).'</span>';
         }          }
         $upload_output .= '</td><td>';          $upload_output .= '</td><td>';
         if ($args->{'ignore_remote_references'}          if ($args->{'ignore_remote_references'} && $embed_file =~ m{^\w+://}) { 
             && $embed_file =~ m{^\w+://}) {  
             $upload_output.='<span class="LC_warning">'.&mt("URL points to other server.").'</span>';              $upload_output.='<span class="LC_warning">'.&mt("URL points to other server.").'</span>';
             $numremref++;              $numremref++;
         } elsif ($args->{'error_on_invalid_names'}          } elsif ($args->{'error_on_invalid_names'}
Line 8596  sub ask_for_embedded_content { Line 9391  sub ask_for_embedded_content {
             $upload_output.='<span class="LC_warning">'.&mt('Invalid characters').'</span>';              $upload_output.='<span class="LC_warning">'.&mt('Invalid characters').'</span>';
             $numinvalid++;              $numinvalid++;
         } else {          } else {
             $upload_output .= &embedded_file_element('upload_embedded',$num,              $upload_output .= &embedded_file_element('upload_embedded',$counter,
                                                      $embed_file,\%mapping,                                                       $embed_file,\%mapping,
                                                      $allfiles,$codebase);                                                       $allfiles,$codebase,'upload');
             $num++;              $counter ++;
               $numnew ++;
         }          }
         $upload_output .= '</td>'.&Apache::loncommon::end_data_table_row()."\n";          $upload_output .= '</td>'.&Apache::loncommon::end_data_table_row()."\n";
     }      }
     foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%existing)) {      foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%existing)) {
         $upload_output .= &start_data_table_row().          if ($actionurl eq '/adm/dependencies') {
                           '<td><span class="LC_filename">'.$embed_file.'</span></td>'.              my ($size,$mtime) = &get_dependency_details(\%currfile,\%currsubfile,$embed_file);
                           '<td><span class="LC_warning">'.&mt('Already exists').'</span></td>'.              $modify_output .= &start_data_table_row().
                           &Apache::loncommon::end_data_table_row()."\n";                                '<td><a href="'.$path.'/'.$embed_file.'" style="text-decoration:none;">'.
                                 '<img src="'.&icon($embed_file).'" border="0" />'.
                                 '&nbsp;<span class="LC_filename">'.$embed_file.'</span></a></td>'.
                                 '<td>'.$size.'</td>'.
                                 '<td>'.$mtime.'</td>'.
                                 '<td><label><input type="checkbox" name="mod_upload_dep" '.
                                 'onclick="toggleBrowse('."'$counter'".')" id="mod_upload_dep_'.
                                 $counter.'" value="'.$counter.'" />'.&mt('Yes').'</label>'.
                                 '<div id="moduploaddep_'.$counter.'" style="display:none;">'.
                                 &embedded_file_element('upload_embedded',$counter,
                                                        $embed_file,\%mapping,
                                                        $allfiles,$codebase,'modify').
                                 '</div></td>'.
                                 &end_data_table_row()."\n";
               $counter ++;
           } else {
               $upload_output .= &start_data_table_row().
                                 '<td><span class="LC_filename">'.$embed_file.'</span></td>';
                                 '<td><span class="LC_warning">'.&mt('Already exists').'</span></td>'.
                                 &Apache::loncommon::end_data_table_row()."\n";
           }
       }
       my $delidx = $counter;
       foreach my $oldfile (sort {lc($a) cmp lc($b)} keys(%unused)) {
           my ($size,$mtime) = &get_dependency_details(\%currfile,\%currsubfile,$oldfile);
           $delete_output .= &start_data_table_row().
                             '<td><img src="'.&icon($oldfile).'" />'.
                             '&nbsp;<span class="LC_filename">'.$oldfile.'</span></td>'.
                             '<td>'.$size.'</td>'.
                             '<td>'.$mtime.'</td>'.
                             '<td><label><input type="checkbox" name="del_upload_dep" '.
                             ' value="'.$delidx.'" />'.&mt('Yes').'</label>'.
                             &embedded_file_element('upload_embedded',$delidx,
                                                    $oldfile,\%mapping,$allfiles,
                                                    $codebase,'delete').'</td>'.
                             &end_data_table_row()."\n"; 
           $numunused ++;
           $delidx ++;
     }      }
     if ($upload_output) {      if ($upload_output) {
         $upload_output = &start_data_table().          $upload_output = &start_data_table().
                          $upload_output.                           $upload_output.
                          &end_data_table()."\n";                           &end_data_table()."\n";
     }      }
       if ($modify_output) {
           $modify_output = &start_data_table().
                            &start_data_table_header_row().
                            '<th>'.&mt('File').'</th>'.
                            '<th>'.&mt('Size (KB)').'</th>'.
                            '<th>'.&mt('Modified').'</th>'.
                            '<th>'.&mt('Upload replacement?').'</th>'.
                            &end_data_table_header_row().
                            $modify_output.
                            &end_data_table()."\n";
       }
       if ($delete_output) {
           $delete_output = &start_data_table().
                            &start_data_table_header_row().
                            '<th>'.&mt('File').'</th>'.
                            '<th>'.&mt('Size (KB)').'</th>'.
                            '<th>'.&mt('Modified').'</th>'.
                            '<th>'.&mt('Delete?').'</th>'.
                            &end_data_table_header_row().
                            $delete_output.
                            &end_data_table()."\n";
       }
     my $applies = 0;      my $applies = 0;
     if ($numremref) {      if ($numremref) {
         $applies ++;          $applies ++;
Line 8624  sub ask_for_embedded_content { Line 9479  sub ask_for_embedded_content {
     if ($numexisting) {      if ($numexisting) {
         $applies ++;          $applies ++;
     }      }
     if ($num) {      if ($counter || $numunused) {
         $output = '<form name="upload_embedded" action="'.$actionurl.'"'.          $output = '<form name="upload_embedded" action="'.$actionurl.'"'.
                   ' method="post" enctype="multipart/form-data">'."\n".                    ' method="post" enctype="multipart/form-data">'."\n".
                   $state.                    $state.'<h3>'.$heading.'</h3>'; 
                   '<h3>'.&mt('Upload embedded files').          if ($actionurl eq '/adm/dependencies') {
                   ':</h3>'.$upload_output.'<br />'."\n".              if ($numnew) {
                   '<input type ="hidden" name="number_embedded_items" value="'.                  $output .= '<h4>'.&mt('Missing dependencies').'</h4>'.
                   $num.'" />'."\n";                             '<p>'.&mt('The following files need to be uploaded.').'</p>'."\n".
         if ($actionurl eq '') {                             $upload_output.'<br />'."\n";
               }
               if ($numexisting) {
                   $output .= '<h4>'.&mt('Uploaded dependencies (in use)').'</h4>'.
                              '<p>'.&mt('Upload a new file to replace the one currently in use.').'</p>'."\n".
                              $modify_output.'<br />'."\n";
                              $buttontext = &mt('Save changes');
               }
               if ($numunused) {
                   $output .= '<h4>'.&mt('Unused files').'</h4>'.
                              '<p>'.&mt('The following uploaded files are no longer used.').'</p>'."\n".
                              $delete_output.'<br />'."\n";
                              $buttontext = &mt('Save changes');
               }
           } else {
               $output .= $upload_output.'<br />'."\n";
           }
           $output .= '<input type ="hidden" name="number_embedded_items" value="'.
                      $counter.'" />'."\n";
           if ($actionurl eq '/adm/dependencies') { 
               $output .= '<input type ="hidden" name="number_newemb_items" value="'.
                          $numnew.'" />'."\n";
           } elsif ($actionurl eq '') {
             $output .=  '<input type="hidden" name="phase" value="three" />';              $output .=  '<input type="hidden" name="phase" value="three" />';
         }          }
     } elsif ($applies) {      } elsif ($applies) {
Line 8660  sub ask_for_embedded_content { Line 9537  sub ask_for_embedded_content {
         $output .= $upload_output.'<br />';          $output .= $upload_output.'<br />';
     }      }
     my ($pathchange_output,$chgcount);      my ($pathchange_output,$chgcount);
     $chgcount = $num;      $chgcount = $counter;
     if (keys(%pathchanges) > 0) {      if (keys(%pathchanges) > 0) {
         foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%pathchanges)) {          foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%pathchanges)) {
             if ($num) {              if ($counter) {
                 $output .= &embedded_file_element('pathchange',$chgcount,                  $output .= &embedded_file_element('pathchange',$chgcount,
                                                   $embed_file,\%mapping,                                                    $embed_file,\%mapping,
                                                   $allfiles,$codebase);                                                    $allfiles,$codebase,'change');
             } else {              } else {
                 $pathchange_output .=                   $pathchange_output .= 
                     &start_data_table_row().                      &start_data_table_row().
Line 8675  sub ask_for_embedded_content { Line 9552  sub ask_for_embedded_content {
                     '<td>'.$mapping{$embed_file}.'</td>'.                      '<td>'.$mapping{$embed_file}.'</td>'.
                     '<td>'.$embed_file.                      '<td>'.$embed_file.
                     &embedded_file_element('pathchange',$numpathchg,$embed_file,                      &embedded_file_element('pathchange',$numpathchg,$embed_file,
                                            \%mapping,$allfiles,$codebase).                                             \%mapping,$allfiles,$codebase,'change').
                     '</td>'.&end_data_table_row();                      '</td>'.&end_data_table_row();
             }              }
             $numpathchg ++;              $numpathchg ++;
             $chgcount ++;              $chgcount ++;
         }          }
     }      }
     if ($num) {      if ($counter) {
         if ($numpathchg) {          if ($numpathchg) {
             $output .= '<input type ="hidden" name="number_pathchange_items" value="'.              $output .= '<input type ="hidden" name="number_pathchange_items" value="'.
                        $numpathchg.'" />'."\n";                         $numpathchg.'" />'."\n";
Line 8692  sub ask_for_embedded_content { Line 9569  sub ask_for_embedded_content {
             $output .= '<input type="hidden" name="phase" value="three" />'."\n";              $output .= '<input type="hidden" name="phase" value="three" />'."\n";
         } elsif ($actionurl eq '/adm/portfolio' || $actionurl eq '/adm/coursegrp_portfolio') {          } elsif ($actionurl eq '/adm/portfolio' || $actionurl eq '/adm/coursegrp_portfolio') {
             $output .= '<input type="hidden" name="action" value="upload_embedded" />';              $output .= '<input type="hidden" name="action" value="upload_embedded" />';
           } elsif ($actionurl eq '/adm/dependencies') {
               $output .= '<input type="hidden" name="action" value="process_changes" />';
         }          }
         $output .=  '<input type ="submit" value="'.&mt('Upload Listed Files').'" />'."\n".          $output .=  '<input type ="submit" value="'.$buttontext.'" />'."\n".'</form>'."\n";
                     &mt('(only files for which a location has been provided will be uploaded)').'</form>'."\n";  
     } elsif ($numpathchg) {      } elsif ($numpathchg) {
         my %pathchange = ();          my %pathchange = ();
         $output .= &modify_html_form('pathchange',$actionurl,$state,\%pathchange,$pathchange_output);          $output .= &modify_html_form('pathchange',$actionurl,$state,\%pathchange,$pathchange_output);
Line 8702  sub ask_for_embedded_content { Line 9580  sub ask_for_embedded_content {
             $output .= '<p>'.&mt('or').'</p>';               $output .= '<p>'.&mt('or').'</p>'; 
         }           } 
     }      }
     return ($output,$num,$numpathchg);      return ($output,$counter,$numpathchg);
 }  }
   
 sub embedded_file_element {  sub embedded_file_element {
     my ($context,$num,$embed_file,$mapping,$allfiles,$codebase) = @_;      my ($context,$num,$embed_file,$mapping,$allfiles,$codebase,$type) = @_;
     return unless ((ref($mapping) eq 'HASH') && (ref($allfiles) eq 'HASH') &&      return unless ((ref($mapping) eq 'HASH') && (ref($allfiles) eq 'HASH') &&
                    (ref($codebase) eq 'HASH'));                     (ref($codebase) eq 'HASH'));
     my $output;      my $output;
     if ($context eq 'upload_embedded') {      if (($context eq 'upload_embedded') && ($type ne 'delete')) {
        $output = '<input name="embedded_item_'.$num.'" type="file" value="" />'."\n";         $output = '<input name="embedded_item_'.$num.'" type="file" value="" />'."\n";
     }      }
     $output .= '<input name="embedded_orig_'.$num.'" type="hidden" value="'.      $output .= '<input name="embedded_orig_'.$num.'" type="hidden" value="'.
Line 8737  sub embedded_file_element { Line 9615  sub embedded_file_element {
     return $output;      return $output;
 }  }
   
   sub get_dependency_details {
       my ($currfile,$currsubfile,$embed_file) = @_;
       my ($size,$mtime,$showsize,$showmtime);
       if ((ref($currfile) eq 'HASH') && (ref($currsubfile))) {
           if ($embed_file =~ m{/}) {
               my ($path,$fname) = split(/\//,$embed_file);
               if (ref($currsubfile->{$path}{$fname}) eq 'ARRAY') {
                   ($size,$mtime) = @{$currsubfile->{$path}{$fname}};
               }
           } else {
               if (ref($currfile->{$embed_file}) eq 'ARRAY') {
                   ($size,$mtime) = @{$currfile->{$embed_file}};
               }
           }
           $showsize = $size/1024.0;
           $showsize = sprintf("%.1f",$showsize);
           if ($mtime > 0) {
               $showmtime = &Apache::lonlocal::locallocaltime($mtime);
           }
       }
       return ($showsize,$showmtime);
   }
   
   sub ask_embedded_js {
       return <<"END";
   <script type="text/javascript"">
   // <![CDATA[
   function toggleBrowse(counter) {
       var chkboxid = document.getElementById('mod_upload_dep_'+counter);
       var fileid = document.getElementById('embedded_item_'+counter);
       var uploaddivid = document.getElementById('moduploaddep_'+counter);
       if (chkboxid.checked == true) {
           uploaddivid.style.display='block';
       } else {
           uploaddivid.style.display='none';
           fileid.value = '';
       }
   }
   // ]]>
   </script>
   
   END
   }
   
 sub upload_embedded {  sub upload_embedded {
     my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota,      my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota,
         $current_disk_usage,$hiddenstate,$actionurl) = @_;          $current_disk_usage,$hiddenstate,$actionurl) = @_;
Line 8795  sub upload_embedded { Line 9717  sub upload_embedded {
             $output .= &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2).'<br />';              $output .= &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2).'<br />';
             next;              next;
         }          }
   
         $env{'form.embedded_item_'.$i.'.filename'}=$fname;          $env{'form.embedded_item_'.$i.'.filename'}=$fname;
         if ($context eq 'portfolio') {          if ($context eq 'portfolio') {
             my $result;              my $result;
Line 8852  sub upload_embedded { Line 9773  sub upload_embedded {
             if (!open($fh,'>'.$dest)) {              if (!open($fh,'>'.$dest)) {
                 &Apache::lonnet::logthis('Failed to create '.$dest);                  &Apache::lonnet::logthis('Failed to create '.$dest);
                 $output .= '<span class="LC_error">'.                  $output .= '<span class="LC_error">'.
                            &mt('An error occurred while trying to upload [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).                             &mt('An error occurred while trying to upload [_1] for embedded element [_2].',
                                  $orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
                            '</span><br />';                             '</span><br />';
             } else {              } else {
                 if (!print $fh $env{'form.embedded_item_'.$i}) {                  if (!print $fh $env{'form.embedded_item_'.$i}) {
                     &Apache::lonnet::logthis('Failed to write to '.$dest);                      &Apache::lonnet::logthis('Failed to write to '.$dest);
                     $output .= '<span class="LC_error">'.                      $output .= '<span class="LC_error">'.
                               &mt('An error occurred while writing the file [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).                                &mt('An error occurred while writing the file [_1] for embedded element [_2].',
                                     $orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
                               '</span><br />';                                '</span><br />';
                 } else {                  } else {
                     $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.                      $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.
Line 8880  sub upload_embedded { Line 9803  sub upload_embedded {
     }      }
     $output .= &modify_html_form('upload_embedded',$actionurl,$hiddenstate,\%pathchange);      $output .= &modify_html_form('upload_embedded',$actionurl,$hiddenstate,\%pathchange);
     $returnflag = 'ok';      $returnflag = 'ok';
     if (keys(%pathchange) > 0) {      my $numpathchgs = scalar(keys(%pathchange));
       if ($numpathchgs > 0) {
         if ($context eq 'portfolio') {          if ($context eq 'portfolio') {
             $output .= '<p>'.&mt('or').'</p>';              $output .= '<p>'.&mt('or').'</p>';
         } elsif ($context eq 'testbank') {          } elsif ($context eq 'testbank') {
             $output .=  '<p>'.&mt('Or [_1]continue[_2] the testbank import without modifying the reference(s).','<a href="javascript:document.testbankForm.submit();">','</a>').'</p>';              $output .=  '<p>'.&mt('Or [_1]continue[_2] the testbank import without modifying the reference(s).',
                                     '<a href="javascript:document.testbankForm.submit();">','</a>').'</p>';
             $returnflag = 'modify_orightml';              $returnflag = 'modify_orightml';
         }          }
     }      }
     return ($output.$footer,$returnflag);      return ($output.$footer,$returnflag,$numpathchgs);
 }  }
   
 sub modify_html_form {  sub modify_html_form {
Line 8923  sub modify_html_form { Line 9848  sub modify_html_form {
                     '<input type="hidden" name="embedded_orig_'.$i.'" value="'.                      '<input type="hidden" name="embedded_orig_'.$i.'" value="'.
                     &escape($env{'form.embedded_orig_'.$i}).'" /></td>'.                      &escape($env{'form.embedded_orig_'.$i}).'" /></td>'.
                     &end_data_table_row();                      &end_data_table_row();
             }               }
         }          }
     } else {      } else {
         $modifyform = $pathchgtable;          $modifyform = $pathchgtable;
Line 8934  sub modify_html_form { Line 9859  sub modify_html_form {
         }          }
     }      }
     if ($modifyform) {      if ($modifyform) {
           if ($actionurl eq '/adm/dependencies') {
               $hiddenstate .= '<input type="hidden" name="action" value="modifyhrefs" />';
           }
         return '<h3>'.&mt('Changes in content of HTML file required').'</h3>'."\n".          return '<h3>'.&mt('Changes in content of HTML file required').'</h3>'."\n".
                '<p>'.&mt('Changes need to be made to the reference(s) used for one or more of the dependencies, if your HTML file is to work correctly:').'<ol>'."\n".                 '<p>'.&mt('Changes need to be made to the reference(s) used for one or more of the dependencies, if your HTML file is to work correctly:').'<ol>'."\n".
                '<li>'.&mt('For consistency between the reference(s) and the location of the corresponding stored file within LON-CAPA.').'</li>'."\n".                 '<li>'.&mt('For consistency between the reference(s) and the location of the corresponding stored file within LON-CAPA.').'</li>'."\n".
Line 8962  sub modify_html_refs { Line 9890  sub modify_html_refs {
         $container = $env{'form.container'};          $container = $env{'form.container'};
     } elsif ($context eq 'coursedoc') {      } elsif ($context eq 'coursedoc') {
         $container = $env{'form.primaryurl'};          $container = $env{'form.primaryurl'};
       } elsif ($context eq 'manage_dependencies') {
           (undef,undef,$container) = &Apache::lonnet::decode_symb($env{'form.symb'});
           $container = "/$container";
     } else {      } else {
         $container = $Apache::lonnet::perlvar{'lonDocRoot'}.$env{'form.filename'};          $container = $Apache::lonnet::perlvar{'lonDocRoot'}.$env{'form.filename'};
     }      }
     my (%allfiles,%codebase,$output,$content);      my (%allfiles,%codebase,$output,$content);
     my @changes = &get_env_multiple('form.namechange');      my @changes = &get_env_multiple('form.namechange');
     return unless (@changes > 0);      unless (@changes > 0) {
     if (($context eq 'portfolio') || ($context eq 'coursedoc')) {          if (wantarray) {
         return unless ($container =~ m{^/uploaded/\Q$udom\E/\Q$uname\E/});              return ('',0,0); 
           } else {
               return;
           }
       }
       if (($context eq 'portfolio') || ($context eq 'coursedoc') || 
           ($context eq 'manage_dependencies')) {
           unless ($container =~ m{^/uploaded/\Q$udom\E/\Q$uname\E/}) {
               if (wantarray) {
                   return ('',0,0);
               } else {
                   return;
               }
           } 
         $content = &Apache::lonnet::getfile($container);          $content = &Apache::lonnet::getfile($container);
         return if ($content eq '-1');          if ($content eq '-1') {
               if (wantarray) {
                   return ('',0,0);
               } else {
                   return;
               }
           }
     } else {      } else {
         return unless ($container =~ /^\Q$dir_root\E/);           unless ($container =~ /^\Q$dir_root\E/) {
               if (wantarray) {
                   return ('',0,0);
               } else {
                   return;
               }
           } 
         if (open(my $fh,"<$container")) {          if (open(my $fh,"<$container")) {
             $content = join('', <$fh>);              $content = join('', <$fh>);
             close($fh);              close($fh);
         } else {          } else {
             return;              if (wantarray) {
                   return ('',0,0);
               } else {
                   return;
               }
         }          }
     }      }
     my ($count,$codebasecount) = (0,0);      my ($count,$codebasecount) = (0,0);
Line 9012  sub modify_html_refs { Line 9972  sub modify_html_refs {
             }              }
             if ($count || $codebasecount) {              if ($count || $codebasecount) {
                 my $saveresult;                  my $saveresult;
                 if ($context eq 'portfolio' || $context eq 'coursedoc') {                  if (($context eq 'portfolio') || ($context eq 'coursedoc') || 
                       ($context eq 'manage_dependencies')) {
                     my $url = &Apache::lonnet::store_edited_file($container,$content,$udom,$uname,\$saveresult);                      my $url = &Apache::lonnet::store_edited_file($container,$content,$udom,$uname,\$saveresult);
                     if ($url eq $container) {                      if ($url eq $container) {
                         my ($fname) = ($container =~ m{/([^/]+)$});                          my ($fname) = ($container =~ m{/([^/]+)$});
                         $output = '<p>'.&mt('Updated [quant,_1,reference] in [_2].',                          $output = '<p>'.&mt('Updated [quant,_1,reference] in [_2].',
                                             $count,'<span class="LC_filename">'.                                              $count,'<span class="LC_filename">'.
                                             $fname.'</span>').'</p>';                                               $fname.'</span>').'</p>';
                     } else {                      } else {
                          $output = '<p class="LC_error">'.                           $output = '<p class="LC_error">'.
                                    &mt('Error: update failed for: [_1].',                                     &mt('Error: update failed for: [_1].',
Line 9045  sub modify_html_refs { Line 10006  sub modify_html_refs {
                      ' to modify references: '.$parse_result);                       ' to modify references: '.$parse_result);
         }          }
     }      }
     return $output;      if (wantarray) {
           return ($output,$count,$codebasecount);
       } else {
           return $output;
       }
 }  }
   
 sub check_for_existing {  sub check_for_existing {
Line 9201  sub check_for_traversal { Line 10166  sub check_for_traversal {
     return $cleanpath;      return $cleanpath;
 }  }
   
   sub is_archive_file {
       my ($mimetype) = @_;
       if (($mimetype eq 'application/octet-stream') ||
           ($mimetype eq 'application/x-stuffit') ||
           ($mimetype =~ m{^application/(x\-)?(compressed|tar|zip|tgz|gz|gtar|gzip|gunzip|bz|bz2|bzip2)})) {
           return 1;
       }
       return;
   }
   
   sub decompress_form {
       my ($mimetype,$archiveurl,$action,$noextract,$hiddenelements,$dirlist) = @_;
       my %lt = &Apache::lonlocal::texthash (
           this => 'This file is an archive file.',
           camt => 'This file is a Camtasia archive file.',
           itsc => 'Its contents are as follows:',
           youm => 'You may wish to extract its contents.',
           extr => 'Extract contents',
           auto => 'LON-CAPA can process the files automatically, or you can decide how each should be handled.',
           proa => 'Process automatically?',
           yes  => 'Yes',
           no   => 'No',
           fold => 'Title for folder containing movie',
           movi => 'Title for page containing embedded movie', 
       );
       my $fileloc = &Apache::lonnet::filelocation(undef,$archiveurl);
       my ($is_camtasia,$topdir,%toplevel,@paths);
       my $info = &list_archive_contents($fileloc,\@paths);
       if (@paths) {
           foreach my $path (@paths) {
               $path =~ s{^/}{};
               if ($path =~ m{^([^/]+)/$}) {
                   $topdir = $1;
               }
               if ($path =~ m{^([^/]+)/}) {
                   $toplevel{$1} = $path;
               } else {
                   $toplevel{$path} = $path;
               }
           }
       }
       if ($mimetype =~ m{^application/(x\-)?(compressed|zip)}) {
           my @camtasia = ("$topdir/","$topdir/index.html",
                           "$topdir/media/",
                           "$topdir/media/$topdir.mp4",
                           "$topdir/media/FirstFrame.png",
                           "$topdir/media/player.swf",
                           "$topdir/media/swfobject.js",
                           "$topdir/media/expressInstall.swf");
           my @diffs = &compare_arrays(\@paths,\@camtasia);
           if (@diffs == 0) {
               $is_camtasia = 1;
           }
       }
       my $output;
       if ($is_camtasia) {
           $output = <<"ENDCAM";
   <script type="text/javascript" language="Javascript">
   // <![CDATA[
   
   function camtasiaToggle() {
       for (var i=0; i<document.uploaded_decompress.autoextract_camtasia.length; i++) {
           if (document.uploaded_decompress.autoextract_camtasia[i].checked) {
               if (document.uploaded_decompress.autoextract_camtasia[i].value == 1) {
   
                   document.getElementById('camtasia_titles').style.display='block';
               } else {
                   document.getElementById('camtasia_titles').style.display='none';
               }
           }
       }
       return;
   }
   
   // ]]>
   </script>
   <p>$lt{'camt'}</p>
   ENDCAM
       } else {
           $output = '<p>'.$lt{'this'};
           if ($info eq '') {
               $output .= ' '.$lt{'youm'}.'</p>'."\n";
           } else {
               $output .= ' '.$lt{'itsc'}.'</p>'."\n".
                          '<div><pre>'.$info.'</pre></div>';
           }
       }
       $output .= '<form name="uploaded_decompress" action="'.$action.'" method="post">'."\n";
       my $duplicates;
       my $num = 0;
       if (ref($dirlist) eq 'ARRAY') {
           foreach my $item (@{$dirlist}) {
               if (ref($item) eq 'ARRAY') {
                   if (exists($toplevel{$item->[0]})) {
                       $duplicates .= 
                           &start_data_table_row().
                           '<td><label><input type="radio" name="archive_overwrite_'.$num.'" '.
                           'value="0" checked="checked" />'.&mt('No').'</label>'.
                           '&nbsp;<label><input type="radio" name="archive_overwrite_'.$num.'" '.
                           'value="1" />'.&mt('Yes').'</label>'.
                           '<input type="hidden" name="archive_overwrite_name_'.$num.'" value="'.$item->[0].'" /></td>'."\n".
                           '<td>'.$item->[0].'</td>';
                       if ($item->[2]) {
                           $duplicates .= '<td>'.&mt('Directory').'</td>';
                       } else {
                           $duplicates .= '<td>'.&mt('File').'</td>';
                       }
                       $duplicates .= '<td>'.$item->[3].'</td>'.
                                      '<td>'.
                                      &Apache::lonlocal::locallocaltime($item->[4]).
                                      '</td>'.
                                      &end_data_table_row();
                       $num ++;
                   }
               }
           }
       }
       my $itemcount;
       if (@paths > 0) {
           $itemcount = scalar(@paths);
       } else {
           $itemcount = 1;
       }
       if ($is_camtasia) {
           $output .= $lt{'auto'}.'<br />'.
                      '<span class="LC_nobreak">'.$lt{'proa'}.'<label>'.
                      '<input type="radio" name="autoextract_camtasia" value="1" onclick="javascript:camtasiaToggle();" checked="checked" />'.
                      $lt{'yes'}.'</label>&nbsp;<label>'.
                      '<input type="radio" name="autoextract_camtasia" value="0" onclick="javascript:camtasiaToggle();" />'.
                      $lt{'no'}.'</label></span><br />'.
                      '<div id="camtasia_titles" style="display:block">'.
                      &Apache::lonhtmlcommon::start_pick_box().
                      &Apache::lonhtmlcommon::row_title($lt{'fold'}).
                      '<input type="textbox" name="camtasia_foldername" value="'.$env{'form.comment'}.'" />'."\n".
                      &Apache::lonhtmlcommon::row_closure().
                      &Apache::lonhtmlcommon::row_title($lt{'movi'}).
                      '<input type="textbox" name="camtasia_moviename" value="" />'."\n".
                      &Apache::lonhtmlcommon::row_closure(1).
                      &Apache::lonhtmlcommon::end_pick_box().
                      '</div>';
       }
       $output .= 
           '<input type="hidden" name="archive_overwrite_total" value="'.$num.'" />'.
           '<input type="hidden" name="archive_itemcount" value="'.$itemcount.'" />'.
           "\n";
       if ($duplicates ne '') {
           $output .= '<p><span class="LC_warning">'.
                      &mt('Warning: decompression of the archive will overwrite the following items which already exist:').'</span><br />'.  
                      &start_data_table().
                      &start_data_table_header_row().
                      '<th>'.&mt('Overwrite?').'</th>'.
                      '<th>'.&mt('Name').'</th>'.
                      '<th>'.&mt('Type').'</th>'.
                      '<th>'.&mt('Size').'</th>'.
                      '<th>'.&mt('Last modified').'</th>'.
                      &end_data_table_header_row().
                      $duplicates.
                      &end_data_table().
                      '</p>';
       }
       $output .= '<input type="hidden" name="archiveurl" value="'.$archiveurl.'" />'."\n";
       if (ref($hiddenelements) eq 'HASH') {
           foreach my $hidden (sort(keys(%{$hiddenelements}))) {
               $output .= '<input type="hidden" name="'.$hidden.'" value="'.$hiddenelements->{$hidden}.'" />'."\n";
           }
       }
       $output .= <<"END";
   <br />
   <input type="submit" name="decompress" value="$lt{'extr'}" />
   </form>
   $noextract
   END
       return $output;
   }
   
   sub decompression_utility {
       my ($program) = @_;
       my @utilities = ('tar','gunzip','bunzip2','unzip'); 
       my $location;
       if (grep(/^\Q$program\E$/,@utilities)) { 
           foreach my $dir ('/bin/','/usr/bin/','/usr/local/bin/','/sbin/',
                            '/usr/sbin/') {
               if (-x $dir.$program) {
                   $location = $dir.$program;
                   last;
               }
           }
       }
       return $location;
   }
   
   sub list_archive_contents {
       my ($file,$pathsref) = @_;
       my (@cmd,$output);
       my $needsregexp;
       if ($file =~ /\.zip$/) {
           @cmd = (&decompression_utility('unzip'),"-l");
           $needsregexp = 1;
       } elsif (($file =~ m/\.tar\.gz$/) ||
                ($file =~ /\.tgz$/)) {
           @cmd = (&decompression_utility('tar'),"-ztf");
       } elsif ($file =~ /\.tar\.bz2$/) {
           @cmd = (&decompression_utility('tar'),"-jtf");
       } elsif ($file =~ m|\.tar$|) {
           @cmd = (&decompression_utility('tar'),"-tf");
       }
       if (@cmd) {
           undef($!);
           undef($@);
           if (open(my $fh,"-|", @cmd, $file)) {
               while (my $line = <$fh>) {
                   $output .= $line;
                   chomp($line);
                   my $item;
                   if ($needsregexp) {
                       ($item) = ($line =~ /^\s*\d+\s+[\d\-]+\s+[\d:]+\s*(.+)$/); 
                   } else {
                       $item = $line;
                   }
                   if ($item ne '') {
                       unless (grep(/^\Q$item\E$/,@{$pathsref})) {
                           push(@{$pathsref},$item);
                       } 
                   }
               }
               close($fh);
           }
       }
       return $output;
   }
   
   sub decompress_uploaded_file {
       my ($file,$dir) = @_;
       &Apache::lonnet::appenv({'cgi.file' => $file});
       &Apache::lonnet::appenv({'cgi.dir' => $dir});
       my $result = &Apache::lonnet::ssi_body('/cgi-bin/decompress.pl');
       my ($handle) = ($env{'user.environment'} =~m{/([^/]+)\.id$});
       my $lonidsdir = $Apache::lonnet::perlvar{'lonIDsDir'};
       &Apache::lonnet::transfer_profile_to_env($lonidsdir,$handle,1);
       my $decompressed = $env{'cgi.decompressed'};
       &Apache::lonnet::delenv('cgi.file');
       &Apache::lonnet::delenv('cgi.dir');
       &Apache::lonnet::delenv('cgi.decompressed');
       return ($decompressed,$result);
   }
   
   sub process_decompression {
       my ($docudom,$docuname,$file,$destination,$dir_root,$hiddenelem) = @_;
       my ($dir,$error,$warning,$output);
       if ($file !~ /\.(zip|tar|bz2|gz|tar.gz|tar.bz2|tgz)$/) {
           $error = &mt('File name not a supported archive file type.').
                    '<br />'.&mt('File name should end with one of: [_1].',
                                 '.zip, .tar, .bz2, .gz, .tar.gz, .tar.bz2, .tgz');
       } else {
           my $docuhome = &Apache::lonnet::homeserver($docuname,$docudom);
           if ($docuhome eq 'no_host') {
               $error = &mt('Could not determine home server for course.');
           } else {
               my @ids=&Apache::lonnet::current_machine_ids();
               my $currdir = "$dir_root/$destination";
               if (grep(/^\Q$docuhome\E$/,@ids)) {
                   $dir = &LONCAPA::propath($docudom,$docuname).
                          "$dir_root/$destination";
               } else {
                   $dir = $Apache::lonnet::perlvar{'lonDocRoot'}.
                          "$dir_root/$docudom/$docuname/$destination";
                   unless (&Apache::lonnet::repcopy_userfile("$dir/$file") eq 'ok') {
                       $error = &mt('Archive file not found.');
                   }
               }
               my (@to_overwrite,@to_skip);
               if ($env{'form.archive_overwrite_total'} > 0) {
                   my $total = $env{'form.archive_overwrite_total'};
                   for (my $i=0; $i<$total; $i++) {
                       if ($env{'form.archive_overwrite_'.$i} == 1) {
                           push(@to_overwrite,$env{'form.archive_overwrite_name_'.$i});
                       } elsif ($env{'form.archive_overwrite_'.$i} == 0) {
                           push(@to_skip,$env{'form.archive_overwrite_name_'.$i});
                       }
                   }
               }
               my $numskip = scalar(@to_skip);
               if (($numskip > 0) && 
                   ($numskip == $env{'form.archive_itemcount'})) {
                   $warning = &mt('All items in the archive file already exist, and no overwriting of existing files has been requested.');         
               } elsif ($dir eq '') {
                   $error = &mt('Directory containing archive file unavailable.');
               } elsif (!$error) {
                   my ($decompressed,$display);
                   if ($numskip > 0) {
                       my $tempdir = time.'_'.$$.int(rand(10000));
                       mkdir("$dir/$tempdir",0755);
                       system("mv $dir/$file $dir/$tempdir/$file");
                       ($decompressed,$display) = 
                           &decompress_uploaded_file($file,"$dir/$tempdir");
                       foreach my $item (@to_skip) {
                           if (($item ne '') && ($item !~ /\.\./)) {
                               if (-f "$dir/$tempdir/$item") { 
                                   unlink("$dir/$tempdir/$item");
                               } elsif (-d "$dir/$tempdir/$item") {
                                   system("rm -rf $dir/$tempdir/$item");
                               }
                           }
                       }
                       system("mv $dir/$tempdir/* $dir");
                       rmdir("$dir/$tempdir");   
                   } else {
                       ($decompressed,$display) = 
                           &decompress_uploaded_file($file,$dir);
                   }
                   if ($decompressed eq 'ok') {
                       $output = '<p class="LC_info">'.
                                 &mt('Files extracted successfully from archive.').
                                 '</p>'."\n";
                       my ($warning,$result,@contents);
                       my ($newdirlistref,$newlisterror) =
                           &Apache::lonnet::dirlist($currdir,$docudom,
                                                    $docuname,1);
                       my (%is_dir,%changes,@newitems);
                       my $dirptr = 16384;
                       if (ref($newdirlistref) eq 'ARRAY') {
                           foreach my $dir_line (@{$newdirlistref}) {
                               my ($item,undef,undef,$testdir)=split(/\&/,$dir_line,5);
                               unless (($item =~ /^\.+$/) || ($item eq $file) || 
                                       ((@to_skip > 0) && (grep(/^\Q$item\E$/,@to_skip)))) {
                                   push(@newitems,$item);
                                   if ($dirptr&$testdir) {
                                       $is_dir{$item} = 1;
                                   }
                                   $changes{$item} = 1;
                               }
                           }
                       }
                       if (keys(%changes) > 0) {
                           foreach my $item (sort(@newitems)) {
                               if ($changes{$item}) {
                                   push(@contents,$item);
                               }
                           }
                       }
                       if (@contents > 0) {
                           my $wantform;
                           unless ($env{'form.autoextract_camtasia'}) {
                               $wantform = 1;
                           }
                           my (%children,%parent,%dirorder,%titles);
                           my ($count,$datatable) = &get_extracted($docudom,$docuname,
                                                                   $currdir,\%is_dir,
                                                                   \%children,\%parent,
                                                                   \@contents,\%dirorder,
                                                                   \%titles,$wantform);
                           if ($datatable ne '') {
                               $output .= &archive_options_form('decompressed',$datatable,
                                                                $count,$hiddenelem);
                               my $startcount = 6;
                               $output .= &archive_javascript($startcount,$count,
                                                              \%titles,\%children);
                           }
                           if ($env{'form.autoextract_camtasia'}) {
                               my %displayed;
                               my $total = 1;
                               $env{'form.archive_directory'} = [];
                               foreach my $i (sort { $a <=> $b } keys(%dirorder)) {
                                   my $path = join('/',map { $titles{$_}; } @{$dirorder{$i}});
                                   $path =~ s{/$}{};
                                   my $item;
                                   if ($path ne '') {
                                       $item = "$path/$titles{$i}";
                                   } else {
                                       $item = $titles{$i};
                                   }
                                   $env{'form.archive_content_'.$i} = "$dir_root/$destination/$item";
                                   if ($item eq $contents[0]) {
                                       push(@{$env{'form.archive_directory'}},$i);
                                       $env{'form.archive_'.$i} = 'display';
                                       $env{'form.archive_title_'.$i} = $env{'form.camtasia_foldername'};
                                       $displayed{'folder'} = $i;
                                   } elsif ($item eq "$contents[0]/index.html") {
                                       $env{'form.archive_'.$i} = 'display';
                                       $env{'form.archive_title_'.$i} = $env{'form.camtasia_moviename'};
                                       $displayed{'web'} = $i;
                                   } else {
                                       if ($item eq "$contents[0]/media") {
                                           push(@{$env{'form.archive_directory'}},$i);
                                       }
                                       $env{'form.archive_'.$i} = 'dependency';
                                   }
                                   $total ++;
                               }
                               for (my $i=1; $i<$total; $i++) {
                                   next if ($i == $displayed{'web'});
                                   next if ($i == $displayed{'folder'});
                                   $env{'form.archive_dependent_on_'.$i} = $displayed{'web'};
                               }
                               $env{'form.phase'} = 'decompress_cleanup';
                               $env{'form.archivedelete'} = 1;
                               $env{'form.archive_count'} = $total-1;
                               $output .=
                                   &process_extracted_files('coursedocs',$docudom,
                                                            $docuname,$destination,
                                                            $dir_root,$hiddenelem);
                           }
                       } else {
                           $warning = &mt('No new items extracted from archive file.');
                       }
                   } else {
                       $output = $display;
                       $error = &mt('An error occurred during extraction from the archive file.');
                   }
               }
           }
       }
       if ($error) {
           $output .= '<p class="LC_error">'.&mt('Not extracted.').'<br />'.
                      $error.'</p>'."\n";
       }
       if ($warning) {
           $output .= '<p class="LC_warning">'.$warning.'</p>'."\n";
       }
       return $output;
   }
   
   sub get_extracted {
       my ($docudom,$docuname,$currdir,$is_dir,$children,$parent,$contents,$dirorder,
           $titles,$wantform) = @_;
       my $count = 0;
       my $depth = 0;
       my $datatable;
       my @hierarchy;
       return unless ((ref($is_dir) eq 'HASH') && (ref($children) eq 'HASH') &&
                      (ref($parent) eq 'HASH') && (ref($contents) eq 'ARRAY') &&
                      (ref($dirorder) eq 'HASH') && (ref($titles) eq 'HASH'));
       foreach my $item (@{$contents}) {
           $count ++;
           @{$dirorder->{$count}} = @hierarchy;
           $titles->{$count} = $item;
           &archive_hierarchy($depth,$count,$parent,$children);
           if ($wantform) {
               $datatable .= &archive_row($is_dir->{$item},$item,
                                          $currdir,$depth,$count);
           }
           if ($is_dir->{$item}) {
               $depth ++;
               push(@hierarchy,$count);
               $parent->{$depth} = $count;
               $datatable .=
                   &recurse_extracted_archive("$currdir/$item",$docudom,$docuname,
                                              \$depth,\$count,\@hierarchy,$dirorder,
                                              $children,$parent,$titles,$wantform);
               $depth --;
               pop(@hierarchy);
           }
       }
       return ($count,$datatable);
   }
   
   sub recurse_extracted_archive {
       my ($currdir,$docudom,$docuname,$depth,$count,$hierarchy,$dirorder,
           $children,$parent,$titles,$wantform) = @_;
       my $result='';
       unless ((ref($depth)) && (ref($count)) && (ref($hierarchy) eq 'ARRAY') &&
               (ref($children) eq 'HASH') && (ref($parent) eq 'HASH') &&
               (ref($dirorder) eq 'HASH')) {
           return $result;
       }
       my $dirptr = 16384;
       my ($newdirlistref,$newlisterror) =
           &Apache::lonnet::dirlist($currdir,$docudom,$docuname,1);
       if (ref($newdirlistref) eq 'ARRAY') {
           foreach my $dir_line (@{$newdirlistref}) {
               my ($item,undef,undef,$testdir)=split(/\&/,$dir_line,5);
               unless ($item =~ /^\.+$/) {
                   $$count ++;
                   @{$dirorder->{$$count}} = @{$hierarchy};
                   $titles->{$$count} = $item;
                   &archive_hierarchy($$depth,$$count,$parent,$children);
   
                   my $is_dir;
                   if ($dirptr&$testdir) {
                       $is_dir = 1;
                   }
                   if ($wantform) {
                       $result .= &archive_row($is_dir,$item,$currdir,$$depth,$$count);
                   }
                   if ($is_dir) {
                       $$depth ++;
                       push(@{$hierarchy},$$count);
                       $parent->{$$depth} = $$count;
                       $result .=
                           &recurse_extracted_archive("$currdir/$item",$docudom,
                                                      $docuname,$depth,$count,
                                                      $hierarchy,$dirorder,$children,
                                                      $parent,$titles,$wantform);
                       $$depth --;
                       pop(@{$hierarchy});
                   }
               }
           }
       }
       return $result;
   }
   
   sub archive_hierarchy {
       my ($depth,$count,$parent,$children) =@_;
       if ((ref($parent) eq 'HASH') && (ref($children) eq 'HASH')) {
           if (exists($parent->{$depth})) {
                $children->{$parent->{$depth}} .= $count.':';
           }
       }
       return;
   }
   
   sub archive_row {
       my ($is_dir,$item,$currdir,$depth,$count) = @_;
       my ($name) = ($item =~ m{([^/]+)$});
       my %choices = &Apache::lonlocal::texthash (
                                          'display'    => 'Add as file',
                                          'dependency' => 'Include as dependency',
                                          'discard'    => 'Discard',
                                         );
       if ($is_dir) {
           $choices{'display'} = &mt('Add as folder'); 
       }
       my $output = &start_data_table_row().'<td align="right">'.$count.'</td>'."\n";
       my $offset = 0;
       foreach my $action ('display','dependency','discard') {
           $offset ++;
           if ($action ne 'display') {
               $offset ++;
           }  
           $output .= '<td><span class="LC_nobreak">'.
                      '<label><input type="radio" name="archive_'.$count.
                      '" id="archive_'.$action.'_'.$count.'" value="'.$action.'"';
           my $text = $choices{$action};
           if ($is_dir) {
               $output .= ' onclick="javascript:propagateCheck(this.form,'."'$count'".');"';
               if ($action eq 'display') {
                   $text = &mt('Add as folder');
               }
           } else {
               $output .= ' onclick="javascript:dependencyCheck(this.form,'."$count,$offset".');"';
   
           }
           $output .= ' />&nbsp;'.$choices{$action}.'</label></span>';
           if ($action eq 'dependency') {
               $output .= '<div id="arc_depon_'.$count.'" style="display:none;">'."\n".
                          &mt('Used by:').'&nbsp;<select name="archive_dependent_on_'.$count.'" '.
                          'onchange="propagateSelect(this.form,'."$count,$offset".')">'."\n".
                          '<option value=""></option>'."\n".
                          '</select>'."\n".
                          '</div>';
           } elsif ($action eq 'display') {
               $output .= '<div id="arc_title_'.$count.'" style="display:none;">'."\n".
                          &mt('Title:').'&nbsp;<input type="text" name="archive_title_'.$count.'" id="archive_title_'.$count.'" />'."\n".
                          '</div>';
           }
           $output .= '</td>';
       }
       $output .= '<td><input type="hidden" name="archive_content_'.$count.'" value="'.
                  &HTML::Entities::encode("$currdir/$item",'"<>&').'" />'.('&nbsp;' x 2);
       for (my $i=0; $i<$depth; $i++) {
           $output .= ('<img src="/adm/lonIcons/whitespace1.gif" class="LC_docs_spacer" alt="" />' x2)."\n";
       }
       if ($is_dir) {
           $output .= '<img src="/adm/lonIcons/navmap.folder.open.gif" alt="" />&nbsp;'."\n".
                      '<input type="hidden" name="archive_directory" value="'.$count.'" />'."\n";
       } else {
           $output .= '<input type="hidden" name="archive_file" value="'.$count.'" />'."\n";
       }
       $output .= '&nbsp;'.$name.'</td>'."\n".
                  &end_data_table_row();
       return $output;
   }
   
   sub archive_options_form {
       my ($form,$display,$count,$hiddenelem) = @_;
       my %lt = &Apache::lonlocal::texthash(
                  perm => 'Permanently remove archive file?',
                  hows => 'How should each extracted item be incorporated in the course?',
                  cont => 'Content actions for all',
                  addf => 'Add as folder/file',
                  incd => 'Include as dependency for a displayed file',
                  disc => 'Discard',
                  no   => 'No',
                  yes  => 'Yes',
                  save => 'Save',
       );
       my $output = <<"END";
   <form name="$form" method="post" action="">
   <p><span class="LC_nobreak">$lt{'perm'}&nbsp;
   <label>
     <input type="radio" name="archivedelete" value="0" checked="checked" />$lt{'no'}
   </label>
   &nbsp;
   <label>
     <input type="radio" name="archivedelete" value="1" />$lt{'yes'}</label>
   </span>
   </p>
   <input type="hidden" name="phase" value="decompress_cleanup" />
   <br />$lt{'hows'}
   <div class="LC_columnSection">
     <fieldset>
       <legend>$lt{'cont'}</legend>
       <input type="button" value="$lt{'addf'}" onclick="javascript:checkAll(document.$form,'display');" /> 
       &nbsp;&nbsp;<input type="button" value="$lt{'incd'}" onclick="javascript:checkAll(document.$form,'dependency');" />
       &nbsp;&nbsp;<input type="button" value="$lt{'disc'}" onclick="javascript:checkAll(document.$form,'discard');" />
     </fieldset>
   </div>
   END
       return $output.
              &start_data_table()."\n".
              $display."\n".
              &end_data_table()."\n".
              '<input type="hidden" name="archive_count" value="'.$count.'" />'.
              $hiddenelem.
              '<br /><input type="submit" name="archive_submit" value="'.$lt{'save'}.'" />'.
              '</form>';
   }
   
   sub archive_javascript {
       my ($startcount,$numitems,$titles,$children) = @_;
       return unless ((ref($titles) eq 'HASH') && (ref($children) eq 'HASH'));
       my $maintitle = $env{'form.comment'};
       my $scripttag = <<START;
   <script type="text/javascript">
   // <![CDATA[
   
   function checkAll(form,prefix) {
       var idstr =  new RegExp("^archive_"+prefix+"_\\\\d+\$");
       for (var i=0; i < form.elements.length; i++) {
           var id = form.elements[i].id;
           if ((id != '') && (id != undefined)) {
               if (idstr.test(id)) {
                   if (form.elements[i].type == 'radio') {
                       form.elements[i].checked = true;
                       var nostart = i-$startcount;
                       var offset = nostart%7;
                       var count = (nostart-offset)/7;    
                       dependencyCheck(form,count,offset);
                   }
               }
           }
       }
   }
   
   function propagateCheck(form,count) {
       if (count > 0) {
           var startelement = $startcount + ((count-1) * 7);
           for (var j=1; j<6; j++) {
               if ((j != 2) && (j != 4)) {
                   var item = startelement + j; 
                   if (form.elements[item].type == 'radio') {
                       if (form.elements[item].checked) {
                           containerCheck(form,count,j);
                           break;
                       }
                   }
               }
           }
       }
   }
   
   numitems = $numitems
   var titles = new Array(numitems);
   var parents = new Array(numitems);
   for (var i=0; i<numitems; i++) {
       parents[i] = new Array;
   }
   var maintitle = '$maintitle';
   
   START
   
       foreach my $container (sort { $a <=> $b } (keys(%{$children}))) {
           my @contents = split(/:/,$children->{$container});
           for (my $i=0; $i<@contents; $i ++) {
               $scripttag .= 'parents['.$container.']['.$i.'] = '.$contents[$i]."\n";
           }
       }
   
       foreach my $key (sort { $a <=> $b } (keys(%{$titles}))) {
           $scripttag .= "titles[$key] = '".$titles->{$key}."';\n";
       }
   
       $scripttag .= <<END;
   
   function containerCheck(form,count,offset) {
       if (count > 0) {
           dependencyCheck(form,count,offset);
           var item = (offset+$startcount)+7*(count-1);
           form.elements[item].checked = true;
           if(Object.prototype.toString.call(parents[count]) === '[object Array]') {
               if (parents[count].length > 0) {
                   for (var j=0; j<parents[count].length; j++) {
                       containerCheck(form,parents[count][j],offset);
                   }
               }
           }
       }
   }
   
   function dependencyCheck(form,count,offset) {
       if (count > 0) {
           var chosen = (offset+$startcount)+7*(count-1);
           var depitem = $startcount + ((count-1) * 7) + 4;
           var currtype = form.elements[depitem].type;
           if (form.elements[chosen].value == 'dependency') {
               document.getElementById('arc_depon_'+count).style.display='block'; 
               form.elements[depitem].options.length = 0;
               form.elements[depitem].options[0] = new Option('Select','',true,true);
               for (var i=1; i<count; i++) {
                   var startelement = $startcount + (i-1) * 7;
                   for (var j=1; j<6; j++) {
                       if ((j != 2) && (j!= 4)) {
                           var item = startelement + j;
                           if (form.elements[item].type == 'radio') {
                               if (form.elements[item].checked) {
                                   if (form.elements[item].value == 'display') {
                                       var n = form.elements[depitem].options.length;
                                       form.elements[depitem].options[n] = new Option(titles[i],i,false,false);
                                   }
                               }
                           }
                       }
                   }
               }
           } else {
               document.getElementById('arc_depon_'+count).style.display='none';
               form.elements[depitem].options.length = 0;
               form.elements[depitem].options[0] = new Option('Select','',true,true);
           }
           titleCheck(form,count,offset);
       }
   }
   
   function propagateSelect(form,count,offset) {
       if (count > 0) {
           var item = (1+offset+$startcount)+7*(count-1);
           var picked = form.elements[item].options[form.elements[item].selectedIndex].value; 
           if (Object.prototype.toString.call(parents[count]) === '[object Array]') {
               if (parents[count].length > 0) {
                   for (var j=0; j<parents[count].length; j++) {
                       containerSelect(form,parents[count][j],offset,picked);
                   }
               }
           }
       }
   }
   
   function containerSelect(form,count,offset,picked) {
       if (count > 0) {
           var item = (offset+$startcount)+7*(count-1);
           if (form.elements[item].type == 'radio') {
               if (form.elements[item].value == 'dependency') {
                   if (form.elements[item+1].type == 'select-one') {
                       for (var i=0; i<form.elements[item+1].options.length; i++) {
                           if (form.elements[item+1].options[i].value == picked) {
                               form.elements[item+1].selectedIndex = i;
                               break;
                           }
                       }
                   }
                   if (Object.prototype.toString.call(parents[count]) === '[object Array]') {
                       if (parents[count].length > 0) {
                           for (var j=0; j<parents[count].length; j++) {
                               containerSelect(form,parents[count][j],offset,picked);
                           }
                       }
                   }
               }
           }
       }
   }
   
   function titleCheck(form,count,offset) {
       if (count > 0) {
           var chosen = (offset+$startcount)+7*(count-1);
           var depitem = $startcount + ((count-1) * 7) + 2;
           var currtype = form.elements[depitem].type;
           if (form.elements[chosen].value == 'display') {
               document.getElementById('arc_title_'+count).style.display='block';
               if ((count==1) && ((parents[count].length > 0) || (numitems == 1))) {
                   document.getElementById('archive_title_'+count).value=maintitle;
               }
           } else {
               document.getElementById('arc_title_'+count).style.display='none';
               if (currtype == 'text') { 
                   document.getElementById('archive_title_'+count).value='';
               }
           }
       }
       return;
   }
   
   // ]]>
   </script>
   END
       return $scripttag;
   }
   
   sub process_extracted_files {
       my ($context,$docudom,$docuname,$destination,$dir_root,$hiddenelem) = @_;
       my $numitems = $env{'form.archive_count'};
       return unless ($numitems);
       my @ids=&Apache::lonnet::current_machine_ids();
       my ($prefix,$pathtocheck,$dir,$ishome,$error,$warning,%toplevelitems,%is_dir,
           %folders,%containers,%mapinner,%prompttofetch);
       my $docuhome = &Apache::lonnet::homeserver($docuname,$docudom);
       if (grep(/^\Q$docuhome\E$/,@ids)) {
           $prefix = &LONCAPA::propath($docudom,$docuname);
           $pathtocheck = "$dir_root/$destination";
           $dir = $dir_root;
           $ishome = 1;
       } else {
           $prefix = $Apache::lonnet::perlvar{'lonDocRoot'};
           $pathtocheck = "$dir_root/$docudom/$docuname/$destination";
           $dir = "$dir_root/$docudom/$docuname";    
       }
       my $currdir = "$dir_root/$destination";
       (my $docstype,$mapinner{'0'}) = ($destination =~ m{^(docs|supplemental)/(\w+)/});
       if ($env{'form.folderpath'}) {
           my @items = split('&',$env{'form.folderpath'});
           $folders{'0'} = $items[-2];
           $containers{'0'}='sequence';
       } elsif ($env{'form.pagepath'}) {
           my @items = split('&',$env{'form.pagepath'});
           $folders{'0'} = $items[-2];
           $containers{'0'}='page';
       }
       my @archdirs = &get_env_multiple('form.archive_directory');
       if ($numitems) {
           for (my $i=1; $i<=$numitems; $i++) {
               my $path = $env{'form.archive_content_'.$i};
               if ($path =~ m{^\Q$pathtocheck\E/([^/]+)$}) {
                   my $item = $1;
                   $toplevelitems{$item} = $i;
                   if (grep(/^\Q$i\E$/,@archdirs)) {
                       $is_dir{$item} = 1;
                   }
               }
           }
       }
       my ($output,%children,%parent,%titles,%dirorder,$result);
       if (keys(%toplevelitems) > 0) {
           my @contents = sort(keys(%toplevelitems));
           (my $count,undef) = &get_extracted($docudom,$docuname,$currdir,\%is_dir,\%children,
                                              \%parent,\@contents,\%dirorder,\%titles);
       }
       my (%referrer,%orphaned,%todelete,%todeletedir,%newdest,%newseqid);
       if ($numitems) {
           for (my $i=1; $i<=$numitems; $i++) {
               my $path = $env{'form.archive_content_'.$i};
               if ($path =~ /^\Q$pathtocheck\E/) {
                   if ($env{'form.archive_'.$i} eq 'discard') {
                       if ($prefix ne '' && $path ne '') {
                           if (-e $prefix.$path) {
                               if ((@archdirs > 0) && 
                                   (grep(/^\Q$i\E$/,@archdirs))) {
                                   $todeletedir{$prefix.$path} = 1;
                               } else {
                                   $todelete{$prefix.$path} = 1;
                               }
                           }
                       }
                   } elsif ($env{'form.archive_'.$i} eq 'display') {
                       my ($docstitle,$title,$url,$outer);
                       ($title) = ($path =~ m{/([^/]+)$});
                       $docstitle = $env{'form.archive_title_'.$i};
                       if ($docstitle eq '') {
                           $docstitle = $title;
                       }
                       $outer = 0;
                       if (ref($dirorder{$i}) eq 'ARRAY') {
                           if (@{$dirorder{$i}} > 0) {
                               foreach my $item (reverse(@{$dirorder{$i}})) {
                                   if ($env{'form.archive_'.$item} eq 'display') {
                                       $outer = $item;
                                       last;
                                   }
                               }
                           }
                       }
                       my ($errtext,$fatal) = 
                           &LONCAPA::map::mapread('/uploaded/'.$docudom.'/'.$docuname.
                                                  '/'.$folders{$outer}.'.'.
                                                  $containers{$outer});
                       next if ($fatal);
                       if ((@archdirs > 0) && (grep(/^\Q$i\E$/,@archdirs))) {
                           if ($context eq 'coursedocs') {
                               $mapinner{$i} = time;
                               $folders{$i} = 'default_'.$mapinner{$i};
                               $containers{$i} = 'sequence';
                               my $url = '/uploaded/'.$docudom.'/'.$docuname.'/'.
                                         $folders{$i}.'.'.$containers{$i};
                               my $newidx = &LONCAPA::map::getresidx();
                               $LONCAPA::map::resources[$newidx]=
                                   $docstitle.':'.$url.':false:normal:res';
                               push(@LONCAPA::map::order,$newidx);
                               my ($outtext,$errtext) =
                                   &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'.
                                                           $docuname.'/'.$folders{$outer}.
                                                           '.'.$containers{$outer},1);
                               $newseqid{$i} = $newidx;
                               unless ($errtext) {
                                   $result .=  '<li>'.&mt('Folder: [_1] added to course',$docstitle).'</li>'."\n";
                               }
                           }
                       } else {
                           if ($context eq 'coursedocs') {
                               my $newidx=&LONCAPA::map::getresidx();
                               my $url = '/uploaded/'.$docudom.'/'.$docuname.'/'.
                                         $docstype.'/'.$mapinner{$outer}.'/'.$newidx.'/'.
                                         $title;
                               if (!-e "$prefix$dir/$docstype/$mapinner{$outer}") {
                                   mkdir("$prefix$dir/$docstype/$mapinner{$outer}",0755);
                               }
                               if (!-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") {
                                   mkdir("$prefix$dir/$docstype/$mapinner{$outer}/$newidx");
                               }
                               if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") {
                                   system("mv $prefix$path $prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title");
                                   $newdest{$i} = "$prefix$dir/$docstype/$mapinner{$outer}/$newidx";
                                   unless ($ishome) {
                                       my $fetch = "$newdest{$i}/$title";
                                       $fetch =~ s/^\Q$prefix$dir\E//;
                                       $prompttofetch{$fetch} = 1;
                                   }
                               }
                               $LONCAPA::map::resources[$newidx]=
                                   $docstitle.':'.$url.':false:normal:res';
                               push(@LONCAPA::map::order, $newidx);
                               my ($outtext,$errtext)=
                                   &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'.
                                                           $docuname.'/'.$folders{$outer}.
                                                           '.'.$containers{$outer},1);
                               unless ($errtext) {
                                   if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title") {
                                       $result .= '<li>'.&mt('File: [_1] added to course',$docstitle).'</li>'."\n";
                                   }
                               }
                           }
                       }
                   } elsif ($env{'form.archive_'.$i} eq 'dependency') {
                       my ($title) = ($path =~ m{/([^/]+)$});
                       $referrer{$i} = $env{'form.archive_dependent_on_'.$i};
                       if ($env{'form.archive_'.$referrer{$i}} eq 'display') {
                           if (ref($dirorder{$i}) eq 'ARRAY') {
                               my ($itemidx,$fullpath,$relpath);
                               for (my $j=0; $j<@{$dirorder{$i}}; $j++) {
                                   if (ref($dirorder{$referrer{$i}}) eq 'ARRAY') {
                                       my $container = $dirorder{$referrer{$i}}->[-1];
                                       for (my $j=0; $j<@{$dirorder{$i}}; $j++) {
                                           if ($dirorder{$i}->[$j] eq $container) {
                                               $itemidx = $j;
                                           }
                                       }
                                   }
                               }
                               if ($itemidx ne '') {
                                   if (grep(/^\Q$referrer{$i}\E$/,@archdirs)) {
                                       if ($mapinner{$referrer{$i}}) {
                                           $fullpath = "$prefix$dir/$docstype/$mapinner{$referrer{$i}}";
                                           for (my $j=$itemidx; $j<@{$dirorder{$i}}; $j++) {
                                               if (grep(/^\Q$dirorder{$i}->[$j]\E$/,@archdirs)) {
                                                   unless (defined($newseqid{$dirorder{$i}->[$j]})) {
                                                       $fullpath .= '/'.$titles{$dirorder{$i}->[$j]};
                                                       $relpath .= '/'.$titles{$dirorder{$i}->[$j]};
                                                       if (!-e $fullpath) {
                                                           mkdir($fullpath,0755);
                                                       }
                                                   }
                                               } else {
                                                   last;
                                               }
                                           }
                                       }
                                   } elsif ($newdest{$referrer{$i}}) {
                                       $fullpath = $newdest{$referrer{$i}};
                                       for (my $j=$itemidx; $j<@{$dirorder{$i}}; $j++) {
                                           if ($env{'form.archive_'.$dirorder{$i}->[$j]} eq 'discard') {
                                               $orphaned{$i} = $env{'form.archive_'.$dirorder{$i}->[$j]};
                                               last;
                                           } elsif (grep(/^\Q$dirorder{$i}->[$j]\E$/,@archdirs)) {
                                               unless (defined($newseqid{$dirorder{$i}->[$j]})) {
                                                   $fullpath .= '/'.$titles{$dirorder{$i}->[$j]};
                                                   $relpath .= '/'.$titles{$dirorder{$i}->[$j]};
                                                   if (!-e $fullpath) {
                                                       mkdir($fullpath,0755);
                                                   }
                                               }
                                           } else {
                                               last;
                                           }
                                       }
                                   }
                                   if ($fullpath ne '') {
                                       if (-e "$prefix$path") {
                                           system("mv $prefix$path $fullpath/$title");
                                       }
                                       if (-e "$fullpath/$title") {
                                           my $showpath;
                                           if ($relpath ne '') {
                                               $showpath = "$relpath/$title";
                                           } else {
                                               $showpath = "/$title";
                                           } 
                                           $result .= '<li>'.&mt('[_1] included as a dependency',$showpath).'</li>'."\n";
                                       } 
                                       unless ($ishome) {
                                           my $fetch = "$fullpath/$title";
                                           $fetch =~ s/^\Q$prefix$dir\E//; 
                                           $prompttofetch{$fetch} = 1;
                                       }
                                   }
                               }
                           }
                       } elsif ($env{'form.archive_'.$referrer{$i}} eq 'discard') {
                           $warning .= &mt('[_1] is a dependency of [_2], which was discarded.',
                                           $path,$env{'form.archive_content_'.$referrer{$i}}).'<br />';
                       }
                   }
               } else {
                   $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',$path).'<br />'; 
               }
           }
           if (keys(%todelete)) {
               foreach my $key (keys(%todelete)) {
                   unlink($key);
               }
           }
           if (keys(%todeletedir)) {
               foreach my $key (keys(%todeletedir)) {
                   rmdir($key);
               }
           }
           foreach my $dir (sort(keys(%is_dir))) {
               if (($pathtocheck ne '') && ($dir ne ''))  {
                   &cleanup_empty_dirs($prefix."$pathtocheck/$dir");
               }
           }
           if ($result ne '') {
               $output .= '<ul>'."\n".
                          $result."\n".
                          '</ul>';
           }
           unless ($ishome) {
               my $replicationfail;
               foreach my $item (keys(%prompttofetch)) {
                   my $fetchresult= &Apache::lonnet::reply('fetchuserfile:'.$item,$docuhome);
                   unless ($fetchresult eq 'ok') {
                       $replicationfail .= '<li>'.$item.'</li>'."\n";
                   }
               }
               if ($replicationfail) {
                   $output .= '<p class="LC_error">'.
                              &mt('Course home server failed to retrieve:').'<ul>'.
                              $replicationfail.
                              '</ul></p>';
               }
           }
       } else {
           $warning = &mt('No items found in archive.');
       }
       if ($error) {
           $output .= '<p class="LC_error">'.&mt('Not extracted.').'<br />'.
                      $error.'</p>'."\n";
       }
       if ($warning) {
           $output .= '<p class="LC_warning">'.$warning.'</p>'."\n";
       }
       return $output;
   }
   
   sub cleanup_empty_dirs {
       my ($path) = @_;
       if (($path ne '') && (-d $path)) {
           if (opendir(my $dirh,$path)) {
               my @dircontents = grep(!/^\./,readdir($dirh));
               my $numitems = 0;
               foreach my $item (@dircontents) {
                   if (-d "$path/$item") {
                       &recurse_dirs("$path/$item");
                       if (-e "$path/$item") {
                           $numitems ++;
                       }
                   } else {
                       $numitems ++;
                   }
               }
               if ($numitems == 0) {
                   rmdir($path);
               }
               closedir($dirh);
           }
       }
       return;
   }
   
   =pod
   
   =item &get_folder_hierarchy()
   
   Provides hierarchy of names of folders/sub-folders containing the current
   item,
   
   Inputs: 3
        - $navmap - navmaps object
   
        - $map - url for map (either the trigger itself, or map containing
                              the resource, which is the trigger).
   
        - $showitem - 1 => show title for map itself; 0 => do not show.
   
   Outputs: 1 @pathitems - array of folder/subfolder names.
   
   =cut
   
   sub get_folder_hierarchy {
       my ($navmap,$map,$showitem) = @_;
       my @pathitems;
       if (ref($navmap)) {
           my $mapres = $navmap->getResourceByUrl($map);
           if (ref($mapres)) {
               my $pcslist = $mapres->map_hierarchy();
               if ($pcslist ne '') {
                   my @pcs = split(/,/,$pcslist);
                   foreach my $pc (@pcs) {
                       if ($pc == 1) {
                           push(@pathitems,&mt('Main Course Documents'));
                       } else {
                           my $res = $navmap->getByMapPc($pc);
                           if (ref($res)) {
                               my $title = $res->compTitle();
                               $title =~ s/\W+/_/g;
                               if ($title ne '') {
                                   push(@pathitems,$title);
                               }
                           }
                       }
                   }
               }
               if ($showitem) {
                   if ($mapres->{ID} eq '0.0') {
                       push(@pathitems,&mt('Main Course Documents'));
                   } else {
                       my $maptitle = $mapres->compTitle();
                       $maptitle =~ s/\W+/_/g;
                       if ($maptitle ne '') {
                           push(@pathitems,$maptitle);
                       }
                   }
               }
           }
       }
       return @pathitems;
   }
   
 =pod  =pod
   
 =item * &get_turnedin_filepath()  =item * &get_turnedin_filepath()
Line 11346  sub init_user_environment { Line 13467  sub init_user_environment {
   
 # See if old ID present, if so, remove  # See if old ID present, if so, remove
   
     my ($filename,$cookie,$userroles);      my ($filename,$cookie,$userroles,$firstaccenv,$timerintenv);
     my $now=time;      my $now=time;
   
     if ($public) {      if ($public) {
Line 11384  sub init_user_environment { Line 13505  sub init_user_environment {
           
 # Initialize roles  # Initialize roles
   
  $userroles=&Apache::lonnet::rolesinit($domain,$username,$authhost);   ($userroles,$firstaccenv,$timerintenv) = 
               &Apache::lonnet::rolesinit($domain,$username,$authhost);
     }      }
 # ------------------------------------ Check browser type and MathML capability  # ------------------------------------ Check browser type and MathML capability
   
Line 11459  sub init_user_environment { Line 13581  sub init_user_environment {
         }          }
   
  $env{'user.environment'} = "$lonids/$cookie.id";   $env{'user.environment'} = "$lonids/$cookie.id";
   
  if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id",   if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id",
  &GDBM_WRCREAT(),0640)) {   &GDBM_WRCREAT(),0640)) {
     &_add_to_env(\%disk_env,\%initial_env);      &_add_to_env(\%disk_env,\%initial_env);
     &_add_to_env(\%disk_env,\%userenv,'environment.');      &_add_to_env(\%disk_env,\%userenv,'environment.');
     &_add_to_env(\%disk_env,$userroles);      &_add_to_env(\%disk_env,$userroles);
               if (ref($firstaccenv) eq 'HASH') {
                   &_add_to_env(\%disk_env,$firstaccenv);
               }
               if (ref($timerintenv) eq 'HASH') {
                   &_add_to_env(\%disk_env,$timerintenv);
               }
     if (ref($args->{'extra_env'})) {      if (ref($args->{'extra_env'})) {
  &_add_to_env(\%disk_env,$args->{'extra_env'});   &_add_to_env(\%disk_env,$args->{'extra_env'});
     }      }
Line 11500  sub get_symb { Line 13628  sub get_symb {
     my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url)));      my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url)));
     if ($symb eq '') {      if ($symb eq '') {
         if (!$silent) {          if (!$silent) {
             $request->print("Unable to handle ambiguous references:$url:.");              if (ref($request)) { 
                   $request->print("Unable to handle ambiguous references:$url:.");
               }
             return ();              return ();
         }          }
     }      }

Removed from v.1.1029  
changed lines
  Added in v.1.1073


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