Diff for /loncom/interface/loncommon.pm between versions 1.1124 and 1.1178

version 1.1124, 2013/04/25 17:58:40 version 1.1178, 2014/02/23 20:52:58
Line 75  use DateTime::Locale::Catalog; Line 75  use DateTime::Locale::Catalog;
 use Text::Aspell;  use Text::Aspell;
 use Authen::Captcha;  use Authen::Captcha;
 use Captcha::reCAPTCHA;  use Captcha::reCAPTCHA;
   use Crypt::DES;
   use DynaLoader; # for Crypt::DES version
   
 # ---------------------------------------------- Designs  # ---------------------------------------------- Designs
 use vars qw(%defaultdesign);  use vars qw(%defaultdesign);
Line 1380  sub top_nav_help { Line 1382  sub top_nav_help {
     $text = &mt($text);      $text = &mt($text);
     my $stay_on_page = 1;      my $stay_on_page = 1;
   
     my $link = ($stay_on_page) ? "javascript:helpMenu('display')"      my ($link,$banner_link);
                      : "javascript:helpMenu('open')";      unless ($env{'request.noversionuri'} =~ m{^/adm/helpmenu}) {
     my $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page);          $link = ($stay_on_page) ? "javascript:helpMenu('display')"
                            : "javascript:helpMenu('open')";
           $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page);
       }
     my $title = &mt('Get help');      my $title = &mt('Get help');
       if ($link) {
     return <<"END";          return <<"END";
 $banner_link  $banner_link
  <a href="$link" title="$title">$text</a>  <a href="$link" title="$title">$text</a>
 END  END
       } else {
           return '&nbsp;'.$text.'&nbsp;';
       }
 }  }
   
 sub help_menu_js {  sub help_menu_js {
     my ($text) = @_;      my ($httphost) = @_;
     my $stayOnPage = 1;      my $stayOnPage = 1;
     my $width = 620;      my $width = 620;
     my $height = 600;      my $height = 600;
     my $helptopic=&general_help();      my $helptopic=&general_help();
     my $details_link = '/adm/help/'.$helptopic.'.hlp';      my $details_link = $httphost.'/adm/help/'.$helptopic.'.hlp';
     my $nothing=&Apache::lonhtmlcommon::javascript_nothing();      my $nothing=&Apache::lonhtmlcommon::javascript_nothing();
     my $start_page =      my $start_page =
         &Apache::loncommon::start_page('Help Menu', undef,          &Apache::loncommon::start_page('Help Menu', undef,
        {'frameset'    => 1,         {'frameset'    => 1,
  'js_ready'    => 1,   'js_ready'    => 1,
                                           'use_absolute' => $httphost,
  'add_entries' => {   'add_entries' => {
     'border' => '0',      'border' => '0', 
     'rows'   => "110,*",},});      'rows'   => "110,*",},});
     my $end_page =      my $end_page =
         &Apache::loncommon::end_page({'frameset' => 1,          &Apache::loncommon::end_page({'frameset' => 1,
Line 1435  function helpMenu(target) { Line 1443  function helpMenu(target) {
     return;      return;
 }  }
 function writeHelp(caller) {  function writeHelp(caller) {
     caller.document.writeln('$start_page\\n<frame name="bannerframe" src="'+banner_link+'" />\\n<frame name="bodyframe" src="$details_link" />\\n$end_page')      caller.document.writeln('$start_page\\n<frame name="bannerframe" src="'+banner_link+'" marginwidth="0" marginheight="0" frameborder="0">\\n');
     caller.document.close()      caller.document.writeln('<frame name="bodyframe" src="$details_link" marginwidth="0" marginheight="0" frameborder="0">\\n$end_page');
     caller.focus()      caller.document.close();
       caller.focus();
 }  }
 // END LON-CAPA Internal -->  // END LON-CAPA Internal -->
 // ]]>  // ]]>
Line 1749  RESIZE Line 1758  RESIZE
   
 =head1 Excel and CSV file utility routines  =head1 Excel and CSV file utility routines
   
 =over 4  
   
 =cut  =cut
   
 ###############################################################  ###############################################################
Line 1758  RESIZE Line 1765  RESIZE
   
 =pod  =pod
   
   =over 4
   
 =item * &csv_translate($text)   =item * &csv_translate($text) 
   
 Translate $text to allow it to be output as a 'comma separated values'   Translate $text to allow it to be output as a 'comma separated values' 
Line 2349  Outputs: Line 2358  Outputs:
   
 =item * $clientos  =item * $clientos
   
   =item * $clientmobile
   
   =item * $clientinfo
   
 =back  =back
   
 =back   =back 
Line 2367  sub decode_user_agent { Line 2380  sub decode_user_agent {
     my $clientversion='0';      my $clientversion='0';
     my $clientmathml='';      my $clientmathml='';
     my $clientunicode='0';      my $clientunicode='0';
       my $clientmobile=0;
     for (my $i=0;$i<=$#browsertype;$i++) {      for (my $i=0;$i<=$#browsertype;$i++) {
         my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\:/,$browsertype[$i]);          my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\:/,$browsertype[$i]);
  if (($httpbrowser=~/$match/i)  && ($httpbrowser!~/$notmatch/i)) {   if (($httpbrowser=~/$match/i)  && ($httpbrowser!~/$notmatch/i)) {
Line 2378  sub decode_user_agent { Line 2392  sub decode_user_agent {
  }   }
     }      }
     my $clientos='unknown';      my $clientos='unknown';
       my $clientinfo;
     if (($httpbrowser=~/linux/i) ||      if (($httpbrowser=~/linux/i) ||
         ($httpbrowser=~/unix/i) ||          ($httpbrowser=~/unix/i) ||
         ($httpbrowser=~/ux/i) ||          ($httpbrowser=~/ux/i) ||
Line 2389  sub decode_user_agent { Line 2404  sub decode_user_agent {
         ($httpbrowser=~/powerpc/i)) { $clientos='mac'; }          ($httpbrowser=~/powerpc/i)) { $clientos='mac'; }
     if ($httpbrowser=~/win/i) { $clientos='win'; }      if ($httpbrowser=~/win/i) { $clientos='win'; }
     if ($httpbrowser=~/embed/i) { $clientos='pda'; }      if ($httpbrowser=~/embed/i) { $clientos='pda'; }
       if ($httpbrowser=~/(Android|iPod|iPad|iPhone|webOS|Blackberry|Windows Phone|Opera m(?:ob|in)|Fennec)/i) {
           $clientmobile=lc($1);
       }
       if ($httpbrowser=~ m{Firefox/(\d+\.\d+)}) {
           $clientinfo = 'firefox-'.$1;
       } elsif ($httpbrowser=~ m{chromeframe/(\d+\.\d+)\.}) {
           $clientinfo = 'chromeframe-'.$1;
       }
     return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,      return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
             $clientunicode,$clientos,);              $clientunicode,$clientos,$clientmobile,$clientinfo);
 }  }
   
 ###############################################################  ###############################################################
Line 3060  sub get_related_words { Line 3083  sub get_related_words {
   
 =pod  =pod
   
   =back
   
 =head1 Spell checking  =head1 Spell checking
   
 =over 4  =over 4
Line 3093  Note: This sub assumes that aspell is in Line 3118  Note: This sub assumes that aspell is in
 =cut  =cut
   
   
 =pod  
   
 =back  
   
 =cut  
   
 sub check_spelling {  sub check_spelling {
     my ($wordlist, $language) = @_;      my ($wordlist, $language) = @_;
     my @misspellings;      my @misspellings;
Line 3314  sub screenname { Line 3333  sub screenname {
 # ------------------------------------------------------------- Confirm Wrapper  # ------------------------------------------------------------- Confirm Wrapper
 =pod  =pod
   
 =item confirmwrapper  =item * &confirmwrapper($message)
   
 Wrap messages about completion of operation in box  Wrap messages about completion of operation in box
   
Line 3873  sub get_previous_attempt { Line 3892  sub get_previous_attempt {
                       if ($key =~/$regexp$/ && (defined &$gradesub)) {                        if ($key =~/$regexp$/ && (defined &$gradesub)) {
                           $value = &$gradesub($value);                            $value = &$gradesub($value);
                       }                        }
                       $prevattempts.='<td>'.$value.'&nbsp;</td>';                        $prevattempts.='<td>'. $value.'&nbsp;</td>';
                   } else {                    } else {
                       $prevattempts.='<td>&nbsp;</td>';                        $prevattempts.='<td>&nbsp;</td>';
                   }                    }
Line 3889  sub get_previous_attempt { Line 3908  sub get_previous_attempt {
       if ($key =~/$regexp$/ && (defined &$gradesub)) {        if ($key =~/$regexp$/ && (defined &$gradesub)) {
                   $value = &$gradesub($value);                    $value = &$gradesub($value);
               }                }
       $prevattempts.='<td>'.$value.'&nbsp;</td>';       $prevattempts.='<td>'.$value.'&nbsp;</td>';
           }            }
       }        }
       $prevattempts.= &end_data_table_row().&end_data_table();        $prevattempts.= &end_data_table_row().&end_data_table();
Line 3910  sub get_previous_attempt { Line 3929  sub get_previous_attempt {
 sub format_previous_attempt_value {  sub format_previous_attempt_value {
     my ($key,$value) = @_;      my ($key,$value) = @_;
     if (($key =~ /timestamp/) || ($key=~/duedate/)) {      if (($key =~ /timestamp/) || ($key=~/duedate/)) {
  $value = &Apache::lonlocal::locallocaltime($value);          $value = &Apache::lonlocal::locallocaltime($value);
     } elsif (ref($value) eq 'ARRAY') {      } elsif (ref($value) eq 'ARRAY') {
  $value = '('.join(', ', @{ $value }).')';          $value = &HTML::Entities::encode('('.join(', ', @{ $value }).')','"<>&');
     } elsif ($key =~ /answerstring$/) {      } elsif ($key =~ /answerstring$/) {
         my %answers = &Apache::lonnet::str2hash($value);          my %answers = &Apache::lonnet::str2hash($value);
           my @answer = %answers;
           %answers = map {&HTML::Entities::encode($_, '"<>&')} @answer;
         my @anskeys = sort(keys(%answers));          my @anskeys = sort(keys(%answers));
         if (@anskeys == 1) {          if (@anskeys == 1) {
             my $answer = $answers{$anskeys[0]};              my $answer = $answers{$anskeys[0]};
Line 3937  sub format_previous_attempt_value { Line 3958  sub format_previous_attempt_value {
             }               } 
         }          }
     } else {      } else {
  $value = &unescape($value);          $value = &HTML::Entities::encode(&unescape($value), '"<>&');
     }      }
     return $value;      return $value;
 }  }
Line 4932  sub designparm { Line 4953  sub designparm {
   
 Inputs: $url (usually will be undef).  Inputs: $url (usually will be undef).
   
 Returns: Path to Construction Space containing the resource or   Returns: Path to Authoring Space containing the resource or 
          directory being viewed (or for which action is being taken).            directory being viewed (or for which action is being taken). 
          If $url is provided, and begins /priv/<domain>/<uname>           If $url is provided, and begins /priv/<domain>/<uname>
          the path will be that portion of the $context argument.           the path will be that portion of the $context argument.
Line 4995  Input: (optional) filename from which br Line 5016  Input: (optional) filename from which br
        is appropriate for use in building the breadcrumb trail.         is appropriate for use in building the breadcrumb trail.
   
 Returns: HTML div with CSTR path and recent box  Returns: HTML div with CSTR path and recent box
          To be included on Construction Space pages           To be included on Authoring Space pages
   
 =cut  =cut
   
Line 5026  sub CSTR_pageheader { Line 5047  sub CSTR_pageheader {
     my $output =      my $output =
          '<div>'           '<div>'
         .&Apache::loncommon::help_open_menu('','',3,'Authoring') #FIXME: Broken? Where is it?          .&Apache::loncommon::help_open_menu('','',3,'Authoring') #FIXME: Broken? Where is it?
         .'<b>'.&mt('Construction Space:').'</b> '          .'<b>'.&mt('Authoring Space:').'</b> '
         .'<form name="dirs" method="post" action="'.$formaction          .'<form name="dirs" method="post" action="'.$formaction
         .'" target="_top">' #FIXME lonpubdir: target="_parent"          .'" target="_top">' #FIXME lonpubdir: target="_parent"
         .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv/'.$udom,undef,undef);          .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv/'.$udom,undef,undef);
Line 5114  sub bodytag { Line 5135  sub bodytag {
         $public = 1;          $public = 1;
     }      }
     if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }      if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
       my $httphost = $args->{'use_absolute'};
   
     $function = &get_users_function() if (!$function);      $function = &get_users_function() if (!$function);
     my $img =    &designparm($function.'.img',$domain);      my $img =    &designparm($function.'.img',$domain);
Line 5129  sub bodytag { Line 5151  sub bodytag {
     @design{keys(%$addentries)} = @$addentries{keys(%$addentries)};       @design{keys(%$addentries)} = @$addentries{keys(%$addentries)}; 
   
  # role and realm   # role and realm
     my ($role,$realm) = split(/\./,$env{'request.role'},2);      my ($role,$realm) = split(m{\./},$env{'request.role'},2);
       if ($realm) {
           $realm = '/'.$realm;
       }
     if ($role  eq 'ca') {      if ($role  eq 'ca') {
         my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$});          my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$});
         $realm = &plainname($rname,$rdom);          $realm = &plainname($rname,$rdom);
Line 5155  sub bodytag { Line 5180  sub bodytag {
     my $bodytag = "<body $extra_body_attr>".      my $bodytag = "<body $extra_body_attr>".
  &Apache::lontexconvert::init_math_support($args->{'inherit_jsmath'});   &Apache::lontexconvert::init_math_support($args->{'inherit_jsmath'});
   
     if ($bodyonly) {      &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
   
       if (($bodyonly) || ($no_nav_bar) || ($env{'form.inhibitmenu'} eq 'yes')) {
         return $bodytag;          return $bodytag;
     }       }
   
     my $name = &plainname($env{'user.name'},$env{'user.domain'});  
     if ($public) {      if ($public) {
  undef($role);   undef($role);
     } else {  
  $name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'},  
                                 undef,'LC_menubuttons_link');  
     }      }
           
     my $titleinfo = '<h1>'.$title.'</h1>';      my $titleinfo = '<h1>'.$title.'</h1>';
Line 5180  sub bodytag { Line 5203  sub bodytag {
     }      }
   
     $role = '<span class="LC_nobreak">('.$role.')</span>' if $role;      $role = '<span class="LC_nobreak">('.$role.')</span>' if $role;
     &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);  
   
         if ($no_nav_bar || $env{'form.inhibitmenu'} eq 'yes') {   
             return $bodytag;   
         }   
   
         if ($env{'request.state'} eq 'construct') { $forcereg=1; }          if ($env{'request.state'} eq 'construct') { $forcereg=1; }
   
Line 5192  sub bodytag { Line 5210  sub bodytag {
         #        $titleinfo = &CSTR_pageheader(); #FIXME: Will be removed once all scripts have their own calls          #        $titleinfo = &CSTR_pageheader(); #FIXME: Will be removed once all scripts have their own calls
         #    }          #    }
   
           $bodytag .= Apache::lonhtmlcommon::scripttag(
               Apache::lonmenu::utilityfunctions($httphost), 'start');
   
           my ($left,$right) = Apache::lonmenu::primary_menu();
   
         if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) {          if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) {
              if ($dc_info) {               if ($dc_info) {
                  $dc_info = qq|<span class="LC_cusr_subheading">$dc_info</span>|;                   $dc_info = qq|<span class="LC_cusr_subheading">$dc_info</span>|;
              }               }
              $bodytag .= qq|<div id="LC_nav_bar">$name $role<br />               $bodytag .= qq|<div id="LC_nav_bar">$left $role<br />
                 <em>$realm</em> $dc_info</div>|;                  <em>$realm</em> $dc_info</div>|;
             return $bodytag;              return $bodytag;
         }          }
   
         unless ($env{'request.symb'} =~ m/\.page___\d+___/) {          unless ($env{'request.symb'} =~ m/\.page___\d+___/) {
             $bodytag .= qq|<div id="LC_nav_bar">$name $role</div>|;              $bodytag .= qq|<div id="LC_nav_bar">$left $role</div>|;
         }          }
   
         $bodytag .= Apache::lonhtmlcommon::scripttag(          $bodytag .= $right;
             Apache::lonmenu::utilityfunctions(), 'start');  
   
         $bodytag .= Apache::lonmenu::primary_menu();  
   
         if ($dc_info) {          if ($dc_info) {
             $dc_info = &dc_courseid_toggle($dc_info);              $dc_info = &dc_courseid_toggle($dc_info);
         }          }
         $bodytag .= qq|<div id="LC_realm">$realm $dc_info</div>|;          $bodytag .= qq|<div id="LC_realm">$realm $dc_info</div>|;
   
           #if directed to not display the secondary menu, don't.  
           if ($args->{'no_secondary_menu'}) {
               return $bodytag;
           }
         #don't show menus for public users          #don't show menus for public users
         if (!$public){          if (!$public){
             $bodytag .= Apache::lonmenu::secondary_menu();              $bodytag .= Apache::lonmenu::secondary_menu($httphost);
             $bodytag .= Apache::lonmenu::serverform();              $bodytag .= Apache::lonmenu::serverform();
             $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');              $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');
             if ($env{'request.state'} eq 'construct') {              if ($env{'request.state'} eq 'construct') {
Line 5279  sub make_attr_string { Line 5301  sub make_attr_string {
     }      }
   
     my $attr_string;      my $attr_string;
     foreach my $attr (keys(%$attr_ref)) {      foreach my $attr (sort(keys(%$attr_ref))) {
  $attr_string .= " $attr=\"".$attr_ref->{$attr}.'" ';   $attr_string .= " $attr=\"".$attr_ref->{$attr}.'" ';
     }      }
     return $attr_string;      return $attr_string;
Line 5410  form, .inline { Line 5432  form, .inline {
   vertical-align:middle;    vertical-align:middle;
 }  }
   
   .LC_floatleft {
     float: left;
   }
   
   .LC_floatright {
     float: right;
   }
   
 .LC_400Box {  .LC_400Box {
   width:400px;    width:400px;
 }  }
Line 6485  div.LC_edit_problem_saves { Line 6515  div.LC_edit_problem_saves {
   white-space: nowrap;    white-space: nowrap;
 }  }
   
   .LC_edit_problem_latexhelper{
       text-align: right;
   }
   
   #LC_edit_problem_colorful div{
       margin-left: 40px;
   }
   
 img.stift {  img.stift {
   border-width: 0;    border-width: 0;
   vertical-align: middle;    vertical-align: middle;
Line 6499  div.LC_createcourse { Line 6537  div.LC_createcourse {
 }  }
   
 .LC_dccid {  .LC_dccid {
     float: right;
   margin: 0.2em 0 0 0;    margin: 0.2em 0 0 0;
   padding: 0;    padding: 0;
   font-size: 90%;    font-size: 90%;
Line 6596  fieldset > legend { Line 6635  fieldset > legend {
 }  }
   
 ol.LC_primary_menu {  ol.LC_primary_menu {
   float: right;  
   margin: 0;    margin: 0;
   padding: 0;    padding: 0;
   background-color: $pgbg_or_bgcolor;    background-color: $pgbg_or_bgcolor;
Line 7250  sub headtag { Line 7288  sub headtag {
     my $function = $args->{'function'} || &get_users_function();      my $function = $args->{'function'} || &get_users_function();
     my $domain   = $args->{'domain'}   || &determinedomain();      my $domain   = $args->{'domain'}   || &determinedomain();
     my $bgcolor  = $args->{'bgcolor'}  || &designparm($function.'.pgbg',$domain);      my $bgcolor  = $args->{'bgcolor'}  || &designparm($function.'.pgbg',$domain);
       my $httphost = $args->{'use_absolute'};
     my $url = join(':',$env{'user.name'},$env{'user.domain'},      my $url = join(':',$env{'user.name'},$env{'user.domain'},
    $Apache::lonnet::perlvar{'lonVersion'},     $Apache::lonnet::perlvar{'lonVersion'},
    #time(),     #time(),
Line 7260  sub headtag { Line 7299  sub headtag {
   
     my $result =      my $result =
  '<head>'.   '<head>'.
  &font_settings();   &font_settings($args);
   
     my $inhibitprint = &print_suppression();      my $inhibitprint = &print_suppression();
   
Line 7273  sub headtag { Line 7312  sub headtag {
     if (!$args->{'no_nav_bar'}       if (!$args->{'no_nav_bar'} 
  && !$args->{'only_body'}   && !$args->{'only_body'}
  && !$args->{'frameset'}) {   && !$args->{'frameset'}) {
  $result .= &help_menu_js();   $result .= &help_menu_js($httphost);
         $result.=&modal_window();          $result.=&modal_window();
         $result.=&togglebox_script();          $result.=&togglebox_script();
         $result.=&wishlist_window();          $result.=&wishlist_window();
Line 7308  ADDMETA Line 7347  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.'"';
       if (!$args->{'frameset'}) {
           $result .= ' /';
       }
       $result .= '>' 
         .$inhibitprint          .$inhibitprint
  .$head_extra;   .$head_extra;
       if ($env{'browser.mobile'}) {
           $result .= '
   <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
   <meta name="apple-mobile-web-app-capable" content="yes" />';
       }
     return $result.'</head>';      return $result.'</head>';
 }  }
   
Line 7320  ADDMETA Line 7368  ADDMETA
   
 Returns neccessary <meta> to set the proper encoding  Returns neccessary <meta> to set the proper encoding
   
 Inputs: none  Inputs: optional reference to HASH -- $args passed to &headtag()
   
 =cut  =cut
   
 sub font_settings {  sub font_settings {
       my ($args) = @_;
     my $headerstring='';      my $headerstring='';
     if (!$env{'browser.mathml'} && $env{'browser.unicode'}) {      if ((!$env{'browser.mathml'} && $env{'browser.unicode'}) ||
  $headerstring.=          ((ref($args) eq 'HASH') && ($args->{'browser.unicode'}))) {
     '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';          $headerstring.=
               '<meta http-equiv="Content-Type" content="text/html; charset=utf-8"';
           if (!$args->{'frameset'}) {
       $headerstring.= ' /';
           }
    $headerstring .= '>'."\n";
     }      }
     return $headerstring;      return $headerstring;
 }  }
Line 7420  Inputs: none Line 7474  Inputs: none
 =cut  =cut
   
 sub xml_begin {  sub xml_begin {
       my ($is_frameset) = @_;
     my $output='';      my $output='';
   
     if ($env{'browser.mathml'}) {      if ($env{'browser.mathml'}) {
Line 7431  sub xml_begin { Line 7486  sub xml_begin {
     .'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">'      .'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">'
             .'<html xmlns:math="http://www.w3.org/1998/Math/MathML" '               .'<html xmlns:math="http://www.w3.org/1998/Math/MathML" ' 
     .'xmlns="http://www.w3.org/1999/xhtml">';      .'xmlns="http://www.w3.org/1999/xhtml">';
       } elsif ($is_frameset) {
           $output='<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'."\n".
                   '<html>'."\n";
     } else {      } else {
  $output='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'   $output='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n".
            .'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';                  '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'."\n";
     }      }
     return $output;      return $output;
 }  }
Line 7500  sub start_page { Line 7558  sub start_page {
     my ($result,@advtools);      my ($result,@advtools);
   
     if (! exists($args->{'skip_phases'}{'head'}) ) {      if (! exists($args->{'skip_phases'}{'head'}) ) {
         $result .= &xml_begin() . &headtag($title, $head_extra, $args);          $result .= &xml_begin($args->{'frameset'}) . &headtag($title, $head_extra, $args);
     }      }
           
     if (! exists($args->{'skip_phases'}{'body'}) ) {      if (! exists($args->{'skip_phases'}{'body'}) ) {
Line 7601  function set_wishlistlink(title, path) { Line 7659  function set_wishlistlink(title, path) {
         title = document.title;          title = document.title;
         title = title.replace(/^LON-CAPA /,'');          title = title.replace(/^LON-CAPA /,'');
     }      }
       title = encodeURIComponent(title);
     if (!path) {      if (!path) {
         path = location.pathname;          path = location.pathname;
     }      }
       path = encodeURIComponent(path);
     Win = window.open('/adm/wishlist?mode=newLink&setTitle='+title+'&setPath='+path,      Win = window.open('/adm/wishlist?mode=newLink&setTitle='+title+'&setPath='+path,
                       'wishlistNewLink','width=560,height=350,scrollbars=0');                        'wishlistNewLink','width=560,height=350,scrollbars=0');
 }  }
Line 7644  var modalWindow = { Line 7704  var modalWindow = {
  $(".LCmodal-overlay").click(function(){modalWindow.close();});   $(".LCmodal-overlay").click(function(){modalWindow.close();});
  }   }
 };  };
  var openMyModal = function(source,width,height,scrolling)   var openMyModal = function(source,width,height,scrolling,transparency,style)
  {   {
  modalWindow.windowId = "myModal";   modalWindow.windowId = "myModal";
  modalWindow.width = width;   modalWindow.width = width;
  modalWindow.height = height;   modalWindow.height = height;
  modalWindow.content = "<iframe width='"+width+"' height='"+height+"' frameborder='0' scrolling='"+scrolling+"' allowtransparency='true' src='" + source + "'>&lt/iframe>";   modalWindow.content = "<iframe width='"+width+"' height='"+height+"' frameborder='0' scrolling='"+scrolling+"' allowtransparency='"+transparency+"' src='" + source + "' style='"+style+"'>&lt/iframe>";
  modalWindow.open();   modalWindow.open();
  };   };
 // END LON-CAPA Internal -->  // END LON-CAPA Internal -->
Line 7659  ENDMODAL Line 7719  ENDMODAL
 }  }
   
 sub modal_link {  sub modal_link {
     my ($link,$linktext,$width,$height,$target,$scrolling,$title)=@_;      my ($link,$linktext,$width,$height,$target,$scrolling,$title,$transparency,$style)=@_;
     unless ($width) { $width=480; }      unless ($width) { $width=480; }
     unless ($height) { $height=400; }      unless ($height) { $height=400; }
     unless ($scrolling) { $scrolling='yes'; }      unless ($scrolling) { $scrolling='yes'; }
       unless ($transparency) { $transparency='true'; }
   
     my $target_attr;      my $target_attr;
     if (defined($target)) {      if (defined($target)) {
         $target_attr = 'target="'.$target.'"';          $target_attr = 'target="'.$target.'"';
     }      }
     return <<"ENDLINK";      return <<"ENDLINK";
 <a href="$link" $target_attr title="$title" onclick="javascript:openMyModal('$link',$width,$height,'$scrolling'); return false;">  <a href="$link" $target_attr title="$title" onclick="javascript:openMyModal('$link',$width,$height,'$scrolling','$transparency','$style'); return false;">
            $linktext</a>             $linktext</a>
 ENDLINK  ENDLINK
 }  }
Line 7695  sub modal_adhoc_inner { Line 7757  sub modal_adhoc_inner {
     my ($funcname,$width,$height,$content)=@_;      my ($funcname,$width,$height,$content)=@_;
     my $innerwidth=$width-20;      my $innerwidth=$width-20;
     $content=&js_ready(      $content=&js_ready(
                &start_page('Dialog',undef,{'only_body'=>1,'bgcolor'=>'#FFFFFF'}).                   &start_page('Dialog',undef,{'only_body'=>1,'bgcolor'=>'#FFFFFF'}).
                  &start_scrollbox($width.'px',$innerwidth.'px',$height.'px').                   &start_scrollbox($width.'px',$innerwidth.'px',$height.'px','myModal','#FFFFFF',undef,1).
                     $content.                   $content.
                  &end_scrollbox().                   &end_scrollbox().
                &end_page()                   &end_page()
              );               );
     return &modal_adhoc_script($funcname,$width,$height,$content);      return &modal_adhoc_script($funcname,$width,$height,$content);
 }  }
Line 7818  sub LCprogressbar { Line 7880  sub LCprogressbar {
     $LCcurrentid=$$.'_'.$LCidcnt;      $LCcurrentid=$$.'_'.$LCidcnt;
     my $starting=&mt('Starting');      my $starting=&mt('Starting');
     my $content=(<<ENDPROGBAR);      my $content=(<<ENDPROGBAR);
 <p>  
   <div id="progressbar$LCcurrentid">    <div id="progressbar$LCcurrentid">
     <span class="pblabel">$starting</span>      <span class="pblabel">$starting</span>
   </div>    </div>
 </p>  
 ENDPROGBAR  ENDPROGBAR
     &r_print($r,$content.&LCprogressbar_script($LCcurrentid));      &r_print($r,$content.&LCprogressbar_script($LCcurrentid));
 }  }
Line 7918  sub validate_page { Line 7978  sub validate_page {
   
   
 sub start_scrollbox {  sub start_scrollbox {
     my ($outerwidth,$width,$height,$id,$bgcolor)=@_;      my ($outerwidth,$width,$height,$id,$bgcolor,$cursor,$needjsready) = @_;
     unless ($outerwidth) { $outerwidth='520px'; }      unless ($outerwidth) { $outerwidth='520px'; }
     unless ($width) { $width='500px'; }      unless ($width) { $width='500px'; }
     unless ($height) { $height='200px'; }      unless ($height) { $height='200px'; }
     my ($table_id,$div_id,$tdcol);      my ($table_id,$div_id,$tdcol);
     if ($id ne '') {      if ($id ne '') {
         $table_id = " id='table_$id'";          $table_id = ' id="table_'.$id.'"';
         $div_id = " id='div_$id'";          $div_id = ' id="div_'.$id.'"';
     }      }
     if ($bgcolor ne '') {      if ($bgcolor ne '') {
         $tdcol = "background-color: $bgcolor;";          $tdcol = "background-color: $bgcolor;";
     }      }
       my $nicescroll_js;
       if ($env{'browser.mobile'}) {
           $nicescroll_js = &nicescroll_javascript('div_'.$id,$cursor,$needjsready);
       }
     return <<"END";      return <<"END";
 <table style="width: $outerwidth; border: 1px solid none;"$table_id><tr><td style="width: $width;$tdcol"><div style="overflow:auto; width:$width; height: $height;"$div_id>  $nicescroll_js
   
   <table style="width: $outerwidth; border: 1px solid none;"$table_id><tr><td style="width: $width;$tdcol">
   <div style="overflow:auto; width:$width; height:$height;"$div_id>
 END  END
 }  }
   
Line 7939  sub end_scrollbox { Line 8006  sub end_scrollbox {
     return '</div></td></tr></table>';      return '</div></td></tr></table>';
 }  }
   
   sub nicescroll_javascript {
       my ($id,$cursor,$needjsready,$framecheck,$location) = @_;
       my %options;
       if (ref($cursor) eq 'HASH') {
           %options = %{$cursor};
       }
       unless ($options{'railalign'} =~ /^left|right$/) {
           $options{'railalign'} = 'left';
       }
       unless ($options{'cursorcolor'} =~ /^\#\w+$/) {
           my $function  = &get_users_function();
           $options{'cursorcolor'} = &designparm($function.'.sidebg',$env{'request.role.domain'});
           unless ($options{'cursorcolor'} =~ /^\#\w+$/) {
               $options{'cursorcolor'} = '#00F';
           }
       }
       if ($options{'cursoropacity'} =~ /^[\d.]+$/) {
           unless ($options{'cursoropacity'} >= 0.0 && $options{'cursoropacity'} <=1.0) {
               $options{'cursoropacity'}='1.0';
           }
       } else {
           $options{'cursoropacity'}='1.0';
       }
       if ($options{'cursorfixedheight'} eq 'none') {
           delete($options{'cursorfixedheight'});
       } else {
           unless ($options{'cursorfixedheight'} =~ /^\d+$/) { $options{'cursorfixedheight'}='50'; }
       }
       unless ($options{'railoffset'} =~ /^{[\w\:\d\-,]+}$/) {
           delete($options{'railoffset'});
       }
       my @niceoptions;
       while (my($key,$value) = each(%options)) {
           if ($value =~ /^\{.+\}$/) {
               push(@niceoptions,$key.':'.$value);
           } else {
               push(@niceoptions,$key.':"'.$value.'"');
           }
       }
       my $nicescroll_js = '
   $(document).ready(
         function() {
             $("#'.$id.'").niceScroll({'.join(',',@niceoptions).'});
         }
   );
   ';
       if ($framecheck) {
           $nicescroll_js .= '
   function expand_div(caller) {
       if (top === self) {
           document.getElementById("'.$id.'").style.width = "auto";
           document.getElementById("'.$id.'").style.height = "auto";
       } else {
           try {
               if (parent.frames) {
                   if (parent.frames.length > 1) {
                       var framesrc = parent.frames[1].location.href;
                       var currsrc = framesrc.replace(/\#.*$/,"");
                       if ((caller == "search") || (currsrc == "'.$location.'")) {
                           document.getElementById("'.$id.'").style.width = "auto";
                           document.getElementById("'.$id.'").style.height = "auto";
                       }
                   }
               }
           } catch (e) {
               return;
           }
       }
       return;
   }
   ';
       }
       if ($needjsready) {
           $nicescroll_js = '
   <script type="text/javascript">'."\n".$nicescroll_js."\n</script>\n";
       } else {
           $nicescroll_js = &Apache::lonhtmlcommon::scripttag($nicescroll_js);
       }
       return $nicescroll_js;
   }
   
 sub simple_error_page {  sub simple_error_page {
     my ($r,$title,$msg) = @_;      my ($r,$title,$msg,$args) = @_;
       if (ref($args) eq 'HASH') {
           if (!$args->{'no_auto_mt_msg'}) { $msg = &mt($msg); }
       } else {
           $msg = &mt($msg);
       }
   
     my $page =      my $page =
  &Apache::loncommon::start_page($title).   &Apache::loncommon::start_page($title).
  '<p class="LC_error">'.&mt($msg).'</p>'.   '<p class="LC_error">'.$msg.'</p>'.
  &Apache::loncommon::end_page();   &Apache::loncommon::end_page();
     if (ref($r)) {      if (ref($r)) {
  $r->print($page);   $r->print($page);
Line 8562  sub get_user_info { Line 8716  sub get_user_info {
   
 =item * &get_user_quota()  =item * &get_user_quota()
   
 Retrieves quota assigned for storage of portfolio files for a user    Retrieves quota assigned for storage of user files.
   Default is to report quota for portfolio files.
   
 Incoming parameters:  Incoming parameters:
 1. user's username  1. user's username
 2. user's domain  2. user's domain
   3. quota name - portfolio, author, or course
      (if no quota name provided, defaults to portfolio).
   4. crstype - official, unofficial, textbook or community, if quota name is
      course
   
 Returns:  Returns:
 1. Disk quota (in Mb) assigned to student.  1. Disk quota (in MB) assigned to student.
 2. (Optional) Type of setting: custom or default  2. (Optional) Type of setting: custom or default
    (individually assigned or default for user's      (individually assigned or default for user's 
    institutional status).     institutional status).
Line 8580  Returns: Line 8739  Returns:
   
 If a value has been stored in the user's environment,   If a value has been stored in the user's environment, 
 it will return that, otherwise it returns the maximal default  it will return that, otherwise it returns the maximal default
 defined for the user's instituional status(es) in the domain.  defined for the user's institutional status(es) in the domain.
   
 =cut  =cut
   
Line 8588  defined for the user's instituional stat Line 8747  defined for the user's instituional stat
   
   
 sub get_user_quota {  sub get_user_quota {
     my ($uname,$udom) = @_;      my ($uname,$udom,$quotaname,$crstype) = @_;
     my ($quota,$quotatype,$settingstatus,$defquota);      my ($quota,$quotatype,$settingstatus,$defquota);
     if (!defined($udom)) {      if (!defined($udom)) {
         $udom = $env{'user.domain'};          $udom = $env{'user.domain'};
Line 8603  sub get_user_quota { Line 8762  sub get_user_quota {
         $defquota = 0;           $defquota = 0; 
     } else {      } else {
         my $inststatus;          my $inststatus;
         if ($udom eq $env{'user.domain'} && $uname eq $env{'user.name'}) {          if ($quotaname eq 'course') {
             $quota = $env{'environment.portfolioquota'};              if (($env{'course.'.$udom.'_'.$uname.'.num'} eq $uname) &&
             $inststatus = $env{'environment.inststatus'};                  ($env{'course.'.$udom.'_'.$uname.'.domain'} eq $udom)) {
         } else {                  $quota = $env{'course.'.$udom.'_'.$uname.'.internal.uploadquota'};
             my %userenv =               } else {
                 &Apache::lonnet::get('environment',['portfolioquota',                  my %cenv = &Apache::lonnet::coursedescription("$udom/$uname");
                                      'inststatus'],$udom,$uname);                  $quota = $cenv{'internal.uploadquota'};
             my ($tmp) = keys(%userenv);              }
             if ($tmp !~ /^(con_lost|error|no_such_host)/i) {  
                 $quota = $userenv{'portfolioquota'};  
                 $inststatus = $userenv{'inststatus'};  
             } else {  
                 undef(%userenv);  
             }  
         }  
         ($defquota,$settingstatus) = &default_quota($udom,$inststatus);  
         if ($quota eq '') {  
             $quota = $defquota;  
             $quotatype = 'default';  
         } else {          } else {
             $quotatype = 'custom';              if ($udom eq $env{'user.domain'} && $uname eq $env{'user.name'}) {
                   if ($quotaname eq 'author') {
                       $quota = $env{'environment.authorquota'};
                   } else {
                       $quota = $env{'environment.portfolioquota'};
                   }
                   $inststatus = $env{'environment.inststatus'};
               } else {
                   my %userenv = 
                       &Apache::lonnet::get('environment',['portfolioquota',
                                            'authorquota','inststatus'],$udom,$uname);
                   my ($tmp) = keys(%userenv);
                   if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
                       if ($quotaname eq 'author') {
                           $quota = $userenv{'authorquota'};
                       } else {
                           $quota = $userenv{'portfolioquota'};
                       }
                       $inststatus = $userenv{'inststatus'};
                   } else {
                       undef(%userenv);
                   }
               }
           }
           if ($quota eq '' || wantarray) {
               if ($quotaname eq 'course') {
                   my %domdefs = &Apache::lonnet::get_domain_defaults($udom);
                   if (($crstype eq 'official') || ($crstype eq 'unofficial') || 
                       ($crstype eq 'community') || ($crstype eq 'textbook')) { 
                       $defquota = $domdefs{$crstype.'quota'};
                   }
                   if ($defquota eq '') {
                       $defquota = 500;
                   }
               } else {
                   ($defquota,$settingstatus) = &default_quota($udom,$inststatus,$quotaname);
               }
               if ($quota eq '') {
                   $quota = $defquota;
                   $quotatype = 'default';
               } else {
                   $quotatype = 'custom';
               }
         }          }
     }      }
     if (wantarray) {      if (wantarray) {
Line 8643  Retrieves default quota assigned for sto Line 8833  Retrieves default quota assigned for sto
 given an (optional) user's institutional status.  given an (optional) user's institutional status.
   
 Incoming parameters:  Incoming parameters:
   
 1. domain  1. domain
 2. (Optional) institutional status(es).  This is a : separated list of   2. (Optional) institutional status(es).  This is a : separated list of 
    status types (e.g., faculty, staff, student etc.)     status types (e.g., faculty, staff, student etc.)
    which apply to the user for whom the default is being retrieved.     which apply to the user for whom the default is being retrieved.
    If the institutional status string in undefined, the domain     If the institutional status string in undefined, the domain
    default quota will be returned.      default quota will be returned.
   3.  quota name - portfolio, author, or course
      (if no quota name provided, defaults to portfolio).
   
 Returns:  Returns:
 1. Default disk quota (in Mb) for user portfolios in the domain.  
   1. Default disk quota (in MB) for user portfolios in the domain.
 2. (Optional) institutional type which determined the value of the  2. (Optional) institutional type which determined the value of the
    default quota.     default quota.
   
 If a value has been stored in the domain's configuration db,  If a value has been stored in the domain's configuration db,
 it will return that, otherwise it returns 20 (for backwards   it will return that, otherwise it returns 20 (for backwards 
 compatibility with domains which have not set up a configuration  compatibility with domains which have not set up a configuration
 db file; the original statically defined portfolio quota was 20 Mb).   db file; the original statically defined portfolio quota was 20 MB). 
   
 If the user's status includes multiple types (e.g., staff and student),  If the user's status includes multiple types (e.g., staff and student),
 the largest default quota which applies to the user determines the  the largest default quota which applies to the user determines the
 default quota returned.  default quota returned.
   
 =back  
   
 =cut  =cut
   
 ###############################################  ###############################################
   
   
 sub default_quota {  sub default_quota {
     my ($udom,$inststatus) = @_;      my ($udom,$inststatus,$quotaname) = @_;
     my ($defquota,$settingstatus);      my ($defquota,$settingstatus);
     my %quotahash = &Apache::lonnet::get_dom('configuration',      my %quotahash = &Apache::lonnet::get_dom('configuration',
                                             ['quotas'],$udom);                                              ['quotas'],$udom);
       my $key = 'defaultquota';
       if ($quotaname eq 'author') {
           $key = 'authorquota';
       }
     if (ref($quotahash{'quotas'}) eq 'HASH') {      if (ref($quotahash{'quotas'}) eq 'HASH') {
         if ($inststatus ne '') {          if ($inststatus ne '') {
             my @statuses = map { &unescape($_); } split(/:/,$inststatus);              my @statuses = map { &unescape($_); } split(/:/,$inststatus);
             foreach my $item (@statuses) {              foreach my $item (@statuses) {
                 if (ref($quotahash{'quotas'}{'defaultquota'}) eq 'HASH') {                  if (ref($quotahash{'quotas'}{$key}) eq 'HASH') {
                     if ($quotahash{'quotas'}{'defaultquota'}{$item} ne '') {                      if ($quotahash{'quotas'}{$key}{$item} ne '') {
                         if ($defquota eq '') {                          if ($defquota eq '') {
                             $defquota = $quotahash{'quotas'}{'defaultquota'}{$item};                              $defquota = $quotahash{'quotas'}{$key}{$item};
                             $settingstatus = $item;                              $settingstatus = $item;
                         } elsif ($quotahash{'quotas'}{'defaultquota'}{$item} > $defquota) {                          } elsif ($quotahash{'quotas'}{$key}{$item} > $defquota) {
                             $defquota = $quotahash{'quotas'}{'defaultquota'}{$item};                              $defquota = $quotahash{'quotas'}{$key}{$item};
                             $settingstatus = $item;                              $settingstatus = $item;
                         }                          }
                     }                      }
                 } else {                  } elsif ($key eq 'defaultquota') {
                     if ($quotahash{'quotas'}{$item} ne '') {                      if ($quotahash{'quotas'}{$item} ne '') {
                         if ($defquota eq '') {                          if ($defquota eq '') {
                             $defquota = $quotahash{'quotas'}{$item};                              $defquota = $quotahash{'quotas'}{$item};
Line 8704  sub default_quota { Line 8900  sub default_quota {
             }              }
         }          }
         if ($defquota eq '') {          if ($defquota eq '') {
             if (ref($quotahash{'quotas'}{'defaultquota'}) eq 'HASH') {              if (ref($quotahash{'quotas'}{$key}) eq 'HASH') {
                 $defquota = $quotahash{'quotas'}{'defaultquota'}{'default'};                  $defquota = $quotahash{'quotas'}{$key}{'default'};
             } else {              } elsif ($key eq 'defaultquota') {
                 $defquota = $quotahash{'quotas'}{'default'};                  $defquota = $quotahash{'quotas'}{'default'};
             }              }
             $settingstatus = 'default';              $settingstatus = 'default';
               if ($defquota eq '') {
                   if ($quotaname eq 'author') {
                       $defquota = 500;
                   }
               }
         }          }
     } else {      } else {
         $settingstatus = 'default';          $settingstatus = 'default';
         $defquota = 20;          if ($quotaname eq 'author') {
               $defquota = 500;
           } else {
               $defquota = 20;
           }
     }      }
     if (wantarray) {      if (wantarray) {
         return ($defquota,$settingstatus);          return ($defquota,$settingstatus);
Line 8722  sub default_quota { Line 8927  sub default_quota {
     }      }
 }  }
   
   ###############################################
   
   =pod
   
   =item * &excess_filesize_warning()
   
   Returns warning message if upload of file to authoring space, or copying
   of existing file within authoring space will cause quota for the authoring
   space to be exceeded.
   
   Same, if upload of a file directly to a course/community via Course Editor
   will cause quota for uploaded content for the course to be exceeded.
   
   Inputs: 7 
   1. username or coursenum
   2. domain
   3. context ('author' or 'course')
   4. filename of file for which action is being requested
   5. filesize (kB) of file
   6. action being taken: copy or upload.
   7. quotatype (in course context -- official, unofficial, community or textbook).
   
   Returns: 1 scalar: HTML to display containing warning if quota would be exceeded,
            otherwise return null.
   
   =back
   
   =cut
   
   sub excess_filesize_warning {
       my ($uname,$udom,$context,$filename,$filesize,$action,$quotatype) = @_;
       my $current_disk_usage = 0;
       my $disk_quota = &get_user_quota($uname,$udom,$context,$quotatype); #expressed in MB
       if ($context eq 'author') {
           my $authorspace = $Apache::lonnet::perlvar{'lonDocRoot'}."/priv/$udom/$uname";
           $current_disk_usage = &Apache::lonnet::diskusage($udom,$uname,$authorspace);
       } else {
           foreach my $subdir ('docs','supplemental') {
               $current_disk_usage += &Apache::lonnet::diskusage($udom,$uname,"userfiles/$subdir",1);
           }
       }
       $disk_quota = int($disk_quota * 1000);
       if (($current_disk_usage + $filesize) > $disk_quota) {
           return '<p><span class="LC_warning">'.
                   &mt("Unable to $action [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.",
                       '<span class="LC_filename">'.$filename.'</span>',$filesize).'</span>'.
                  '<br />'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',
                               $disk_quota,$current_disk_usage).
                  '</p>';
       }
       return;
   }
   
   ###############################################
   
   
   
   
 sub get_secgrprole_info {  sub get_secgrprole_info {
     my ($cdom,$cnum,$needroles,$type)  = @_;      my ($cdom,$cnum,$needroles,$type)  = @_;
     my %sections_count = &get_sections($cdom,$cnum);      my %sections_count = &get_sections($cdom,$cnum);
Line 9561  sub ask_for_embedded_content { Line 9824  sub ask_for_embedded_content {
     my $numexisting = 0;      my $numexisting = 0;
     my $numunused = 0;      my $numunused = 0;
     my ($output,$upload_output,$toplevel,$url,$udom,$uname,$getpropath,$cdom,$cnum,      my ($output,$upload_output,$toplevel,$url,$udom,$uname,$getpropath,$cdom,$cnum,
         $fileloc,$filename,$delete_output,$modify_output,$title,$symb,$path);          $fileloc,$filename,$delete_output,$modify_output,$title,$symb,$path,$navmap);
     my $heading = &mt('Upload embedded files');      my $heading = &mt('Upload embedded files');
     my $buttontext = &mt('Upload');      my $buttontext = &mt('Upload');
   
     my ($navmap,$cdom,$cnum);  
     if ($env{'request.course.id'}) {      if ($env{'request.course.id'}) {
         if ($actionurl eq '/adm/dependencies') {          if ($actionurl eq '/adm/dependencies') {
             $navmap = Apache::lonnavmaps::navmap->new();              $navmap = Apache::lonnavmaps::navmap->new();
Line 9616  sub ask_for_embedded_content { Line 9878  sub ask_for_embedded_content {
             if (ref($args) eq 'HASH') {              if (ref($args) eq 'HASH') {
                 $url = $args->{'docs_url'};                  $url = $args->{'docs_url'};
                 $title = $args->{'docs_title'};                  $title = $args->{'docs_title'};
                 $toplevel = "/$url";                  $toplevel = $url; 
                   unless ($toplevel =~ m{^/}) {
                       $toplevel = "/$url";
                   }
                 ($rem) = ($toplevel =~ m{^(.+/)[^/]+$});                  ($rem) = ($toplevel =~ m{^(.+/)[^/]+$});
                 ($path) =                    if ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/portfolio/syllabus\E)}) {
                     ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});                      $path = $1;
                   } else {
                       ($path) =
                           ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});
                   }
                 $fileloc = &Apache::lonnet::filelocation('',$toplevel);                  $fileloc = &Apache::lonnet::filelocation('',$toplevel);
                 $fileloc =~ s{^/}{};                  $fileloc =~ s{^/}{};
                 ($filename) = ($fileloc =~ m{.+/([^/]+)$});                  ($filename) = ($fileloc =~ m{.+/([^/]+)$});
Line 9635  sub ask_for_embedded_content { Line 9904  sub ask_for_embedded_content {
         $fileloc = &Apache::lonnet::filelocation('',$toplevel).'/';          $fileloc = &Apache::lonnet::filelocation('',$toplevel).'/';
         $fileloc =~ s{^/}{};          $fileloc =~ s{^/}{};
     }      }
     foreach my $embed_file (keys(%{$allfiles})) {      foreach my $file (keys(%{$allfiles})) {
         my $absolutepath;          my $embed_file;
           if (($path eq "/uploaded/$cdom/$cnum/portfolio/syllabus") && ($file =~ m{^\Q$path/\E(.+)$})) {
               $embed_file = $1;
           } else {
               $embed_file = $file;
           }
           my ($absolutepath,$cleaned_file);
         if ($embed_file =~ m{^\w+://}) {          if ($embed_file =~ m{^\w+://}) {
             $newfiles{$embed_file} = 1;              $cleaned_file = $embed_file;
             $mapping{$embed_file} = $embed_file;              $newfiles{$cleaned_file} = 1;
               $mapping{$cleaned_file} = $embed_file;
         } else {          } else {
               $cleaned_file = &clean_path($embed_file);
             if ($embed_file =~ m{^/}) {              if ($embed_file =~ m{^/}) {
                 $absolutepath = $embed_file;                  $absolutepath = $embed_file;
                 $embed_file =~ s{^(/+)}{};  
             }              }
             if ($embed_file =~ m{/}) {              if ($cleaned_file =~ m{/}) {
                 my ($path,$fname) = ($embed_file =~ m{^(.+)/([^/]*)$});                  my ($path,$fname) = ($cleaned_file =~ m{^(.+)/([^/]*)$});
                 $path = &check_for_traversal($path,$url,$toplevel);                  $path = &check_for_traversal($path,$url,$toplevel);
                 my $item = $fname;                  my $item = $fname;
                 if ($path ne '') {                  if ($path ne '') {
Line 9663  sub ask_for_embedded_content { Line 9939  sub ask_for_embedded_content {
             } else {              } else {
                 $dependencies{$embed_file} = 1;                  $dependencies{$embed_file} = 1;
                 if ($absolutepath) {                  if ($absolutepath) {
                     $mapping{$embed_file} = $absolutepath;                      $mapping{$cleaned_file} = $absolutepath;
                 } else {                  } else {
                     $mapping{$embed_file} = $embed_file;                      $mapping{$cleaned_file} = $embed_file;
                 }                  }
             }              }
         }          }
Line 9799  sub ask_for_embedded_content { Line 10075  sub ask_for_embedded_content {
                 ($file eq $filename.'.bak') ||                  ($file eq $filename.'.bak') ||
                 ($dependencies{$file})) {                  ($dependencies{$file})) {
             if ($actionurl eq '/adm/dependencies') {              if ($actionurl eq '/adm/dependencies') {
                 next if (($rem ne '') &&                  unless ($toplevel =~ m{^\Q/uploaded/$cdom/$cnum/portfolio/syllabus\E}) {
                          (($env{"httpref.$rem".$file} ne '') ||                      next if (($rem ne '') &&
                           (ref($navmap) &&                               (($env{"httpref.$rem".$file} ne '') ||
                           (($navmap->getResourceByUrl($rem.$file) ne '') ||                                (ref($navmap) &&
                            (($file =~ /^(.*\.s?html?)\.bak$/i) &&                                (($navmap->getResourceByUrl($rem.$file) ne '') ||
                             ($navmap->getResourceByUrl($rem.$1)))))));                                 (($file =~ /^(.*\.s?html?)\.bak$/i) &&
                                   ($navmap->getResourceByUrl($rem.$1)))))));
                   }
             }              }
             $unused{$file} = 1;              $unused{$file} = 1;
         }          }
Line 10013  sub ask_for_embedded_content { Line 10291  sub ask_for_embedded_content {
             $chgcount ++;              $chgcount ++;
         }          }
     }      }
     if ($counter) {      if (($counter) || ($numunused)) {
         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 10037  sub ask_for_embedded_content { Line 10315  sub ask_for_embedded_content {
     return ($output,$counter,$numpathchg);      return ($output,$counter,$numpathchg);
 }  }
   
   =pod
   
   =item * clean_path($name)
   
   Performs clean-up of directories, subdirectories and filename in an
   embedded object, referenced in an HTML file which is being uploaded
   to a course or portfolio, where 
   "Upload embedded images/multimedia files if HTML file" checkbox was
   checked.
   
   Clean-up is similar to replacements in lonnet::clean_filename()
   except each / between sub-directory and next level is preserved.
   
   =cut
   
   sub clean_path {
       my ($embed_file) = @_;
       $embed_file =~s{^/+}{};
       my @contents;
       if ($embed_file =~ m{/}) {
           @contents = split(/\//,$embed_file);
       } else {
           @contents = ($embed_file);
       }
       my $lastidx = scalar(@contents)-1;
       for (my $i=0; $i<=$lastidx; $i++) { 
           $contents[$i]=~s{\\}{/}g;
           $contents[$i]=~s/\s+/\_/g;
           $contents[$i]=~s{[^/\w\.\-]}{}g;
           if ($i == $lastidx) {
               $contents[$i]=~s/\.(\d+)(?=\.)/_$1/g;
           }
       }
       if ($lastidx > 0) {
           return join('/',@contents);
       } else {
           return $contents[0];
       }
   }
   
 sub embedded_file_element {  sub embedded_file_element {
     my ($context,$num,$embed_file,$mapping,$allfiles,$codebase,$type) = @_;      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') &&
Line 10161  sub upload_embedded { Line 10479  sub upload_embedded {
         # Check if extension is valid          # Check if extension is valid
         if (($fname =~ /\.(\w+)$/) &&          if (($fname =~ /\.(\w+)$/) &&
             (&Apache::loncommon::fileembstyle($1) eq 'hdn')) {              (&Apache::loncommon::fileembstyle($1) eq 'hdn')) {
             $output .= &mt('Invalid file extension ([_1]) - reserved for LONCAPA use - rename the file with a different extension and re-upload. ',$1).'<br />';              $output .= &mt('Invalid file extension ([_1]) - reserved for internal use.',$1)
                         .' '.&mt('Rename the file with a different extension and re-upload.').'<br />';
             next;              next;
         } elsif (($fname =~ /\.(\w+)$/) &&          } elsif (($fname =~ /\.(\w+)$/) &&
                  (!defined(&Apache::loncommon::fileembstyle($1)))) {                   (!defined(&Apache::loncommon::fileembstyle($1)))) {
Line 10197  sub upload_embedded { Line 10516  sub upload_embedded {
                 }                  }
             }              }
         } elsif (($context eq 'coursedoc') || ($context eq 'syllabus')) {          } elsif (($context eq 'coursedoc') || ($context eq 'syllabus')) {
               my $extendedsubdir = $dirpath.'/'.$subdir;
               $extendedsubdir =~ s{/+$}{};
             my $result =              my $result =
                 &Apache::lonnet::userfileupload('embedded_item_'.$i,$context,                  &Apache::lonnet::userfileupload('embedded_item_'.$i,$context,$extendedsubdir);
                                                 $dirpath.'/'.$subdir);  
             if ($result !~ m|^/uploaded/|) {              if ($result !~ m|^/uploaded/|) {
                 $output .= '<span class="LC_error">'                  $output .= '<span class="LC_error">'
                            .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'                             .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'
Line 10209  sub upload_embedded { Line 10529  sub upload_embedded {
             } else {              } else {
                 $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.                  $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.
                            $path.$fname.'</span>').'<br />';                             $path.$fname.'</span>').'<br />';
                 &Apache::lonnet::make_public_indefinitely($result);                  if ($context eq 'syllabus') {
                       &Apache::lonnet::make_public_indefinitely($result);
                   }
             }              }
         } else {          } else {
 # Save the file  # Save the file
Line 10357  sub modify_html_refs { Line 10679  sub modify_html_refs {
     }      }
     my (%allfiles,%codebase,$output,$content);      my (%allfiles,%codebase,$output,$content);
     my @changes = &get_env_multiple('form.namechange');      my @changes = &get_env_multiple('form.namechange');
     unless (@changes > 0) {      unless ((@changes > 0) || ($context eq 'syllabus')) {
         if (wantarray) {          if (wantarray) {
             return ('',0,0);               return ('',0,0); 
         } else {          } else {
Line 10422  sub modify_html_refs { Line 10744  sub modify_html_refs {
                         my $numchg = ($content =~ s{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}{$1$newname$2}gi);                          my $numchg = ($content =~ s{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}{$1$newname$2}gi);
                         $count += $numchg;                          $count += $numchg;
                         $allfiles{$newname} = $allfiles{$ref};                          $allfiles{$newname} = $allfiles{$ref};
                           delete($allfiles{$ref});
                     }                      }
                     if ($env{'form.embedded_codebase_'.$i} ne '') {                      if ($env{'form.embedded_codebase_'.$i} ne '') {
                         $codebase = &unescape($env{'form.embedded_codebase_'.$i});                          $codebase = &unescape($env{'form.embedded_codebase_'.$i});
Line 10715  sub decompress_form { Line 11038  sub decompress_form {
         }          }
     }      }
     if ($mimetype =~ m{^application/(x\-)?(compressed|zip)}) {      if ($mimetype =~ m{^application/(x\-)?(compressed|zip)}) {
         my @camtasia = ("$topdir/","$topdir/index.html",          my @camtasia6 = ("$topdir/","$topdir/index.html",
                         "$topdir/media/",                          "$topdir/media/",
                         "$topdir/media/$topdir.mp4",                          "$topdir/media/$topdir.mp4",
                         "$topdir/media/FirstFrame.png",                          "$topdir/media/FirstFrame.png",
                         "$topdir/media/player.swf",                          "$topdir/media/player.swf",
                         "$topdir/media/swfobject.js",                          "$topdir/media/swfobject.js",
                         "$topdir/media/expressInstall.swf");                          "$topdir/media/expressInstall.swf");
         my @diffs = &compare_arrays(\@paths,\@camtasia);          my @camtasia8 = ("$topdir/","$topdir/$topdir.html",
                            "$topdir/$topdir.mp4",
                            "$topdir/$topdir\_config.xml",
                            "$topdir/$topdir\_controller.swf",
                            "$topdir/$topdir\_embed.css",
                            "$topdir/$topdir\_First_Frame.png",
                            "$topdir/$topdir\_player.html",
                            "$topdir/$topdir\_Thumbnails.png",
                            "$topdir/playerProductInstall.swf",
                            "$topdir/scripts/",
                            "$topdir/scripts/config_xml.js",
                            "$topdir/scripts/handlebars.js",
                            "$topdir/scripts/jquery-1.7.1.min.js",
                            "$topdir/scripts/jquery-ui-1.8.15.custom.min.js",
                            "$topdir/scripts/modernizr.js",
                            "$topdir/scripts/player-min.js",
                            "$topdir/scripts/swfobject.js",
                            "$topdir/skins/",
                            "$topdir/skins/configuration_express.xml",
                            "$topdir/skins/express_show/",
                            "$topdir/skins/express_show/player-min.css",
                            "$topdir/skins/express_show/spritesheet.png");
           my @diffs = &compare_arrays(\@paths,\@camtasia6);
         if (@diffs == 0) {          if (@diffs == 0) {
             $is_camtasia = 1;              $is_camtasia = 6;
           } else {
               @diffs = &compare_arrays(\@paths,\@camtasia8);
               if (@diffs == 0) {
                   $is_camtasia = 8;
               }
         }          }
     }      }
     my $output;      my $output;
Line 10736  sub decompress_form { Line 11086  sub decompress_form {
 function camtasiaToggle() {  function camtasiaToggle() {
     for (var i=0; i<document.uploaded_decompress.autoextract_camtasia.length; i++) {      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].checked) {
             if (document.uploaded_decompress.autoextract_camtasia[i].value == 1) {              if (document.uploaded_decompress.autoextract_camtasia[i].value == $is_camtasia) {
   
                 document.getElementById('camtasia_titles').style.display='block';                  document.getElementById('camtasia_titles').style.display='block';
             } else {              } else {
Line 10799  ENDCAM Line 11149  ENDCAM
     if ($is_camtasia) {      if ($is_camtasia) {
         $output .= $lt{'auto'}.'<br />'.          $output .= $lt{'auto'}.'<br />'.
                    '<span class="LC_nobreak">'.$lt{'proa'}.'<label>'.                     '<span class="LC_nobreak">'.$lt{'proa'}.'<label>'.
                    '<input type="radio" name="autoextract_camtasia" value="1" onclick="javascript:camtasiaToggle();" checked="checked" />'.                     '<input type="radio" name="autoextract_camtasia" value="'.$is_camtasia.'" onclick="javascript:camtasiaToggle();" checked="checked" />'.
                    $lt{'yes'}.'</label>&nbsp;<label>'.                     $lt{'yes'}.'</label>&nbsp;<label>'.
                    '<input type="radio" name="autoextract_camtasia" value="0" onclick="javascript:camtasiaToggle();" />'.                     '<input type="radio" name="autoextract_camtasia" value="0" onclick="javascript:camtasiaToggle();" />'.
                    $lt{'no'}.'</label></span><br />'.                     $lt{'no'}.'</label></span><br />'.
Line 11032  sub process_decompression { Line 11382  sub process_decompression {
                                                            \%titles,\%children);                                                             \%titles,\%children);
                         }                          }
                         if ($env{'form.autoextract_camtasia'}) {                          if ($env{'form.autoextract_camtasia'}) {
                               my $version = $env{'form.autoextract_camtasia'};
                             my %displayed;                              my %displayed;
                             my $total = 1;                              my $total = 1;
                             $env{'form.archive_directory'} = [];                              $env{'form.archive_directory'} = [];
Line 11050  sub process_decompression { Line 11401  sub process_decompression {
                                     $env{'form.archive_'.$i} = 'display';                                      $env{'form.archive_'.$i} = 'display';
                                     $env{'form.archive_title_'.$i} = $env{'form.camtasia_foldername'};                                      $env{'form.archive_title_'.$i} = $env{'form.camtasia_foldername'};
                                     $displayed{'folder'} = $i;                                      $displayed{'folder'} = $i;
                                 } elsif ($item eq "$contents[0]/index.html") {                                  } elsif ((($item eq "$contents[0]/index.html") && ($version == 6)) ||
                                            (($item eq "$contents[0]/$contents[0]".'.html') && ($version == 8))) { 
                                     $env{'form.archive_'.$i} = 'display';                                      $env{'form.archive_'.$i} = 'display';
                                     $env{'form.archive_title_'.$i} = $env{'form.camtasia_moviename'};                                      $env{'form.archive_title_'.$i} = $env{'form.camtasia_moviename'};
                                     $displayed{'web'} = $i;                                      $displayed{'web'} = $i;
                                 } else {                                  } else {
                                     if ($item eq "$contents[0]/media") {                                      if ((($item eq "$contents[0]/media") && ($version == 6)) ||
                                           ((($item eq "$contents[0]/scripts") || ($item eq "$contents[0]/skins") ||
                                                ($item eq "$contents[0]/skins/express_show")) && ($version == 8))) {
                                         push(@{$env{'form.archive_directory'}},$i);                                          push(@{$env{'form.archive_directory'}},$i);
                                     }                                      }
                                     $env{'form.archive_'.$i} = 'dependency';                                      $env{'form.archive_'.$i} = 'dependency';
Line 11782  sub cleanup_empty_dirs { Line 12136  sub cleanup_empty_dirs {
   
 =pod  =pod
   
 =item &get_folder_hierarchy()  =item * &get_folder_hierarchy()
   
 Provides hierarchy of names of folders/sub-folders containing the current  Provides hierarchy of names of folders/sub-folders containing the current
 item,  item,
Line 11810  sub get_folder_hierarchy { Line 12164  sub get_folder_hierarchy {
                 my @pcs = split(/,/,$pcslist);                  my @pcs = split(/,/,$pcslist);
                 foreach my $pc (@pcs) {                  foreach my $pc (@pcs) {
                     if ($pc == 1) {                      if ($pc == 1) {
                         push(@pathitems,&mt('Main Course Documents'));                          push(@pathitems,&mt('Main Content'));
                     } else {                      } else {
                         my $res = $navmap->getByMapPc($pc);                          my $res = $navmap->getByMapPc($pc);
                         if (ref($res)) {                          if (ref($res)) {
Line 11825  sub get_folder_hierarchy { Line 12179  sub get_folder_hierarchy {
             }              }
             if ($showitem) {              if ($showitem) {
                 if ($mapres->{ID} eq '0.0') {                  if ($mapres->{ID} eq '0.0') {
                     push(@pathitems,&mt('Main Course Documents'));                      push(@pathitems,&mt('Main Content'));
                 } else {                  } else {
                     my $maptitle = $mapres->compTitle();                      my $maptitle = $mapres->compTitle();
                     $maptitle =~ s/\W+/_/g;                      $maptitle =~ s/\W+/_/g;
Line 11892  sub get_turnedin_filepath { Line 12246  sub get_turnedin_filepath {
                             my $title = $res->compTitle();                              my $title = $res->compTitle();
                             $title =~ s/\W+/_/g;                              $title =~ s/\W+/_/g;
                             if ($title ne '') {                              if ($title ne '') {
                                   if (($pc > 1) && (length($title) > 12)) {
                                       $title = substr($title,0,12);
                                   }
                                 push(@pathitems,$title);                                  push(@pathitems,$title);
                             }                              }
                         }                          }
Line 11900  sub get_turnedin_filepath { Line 12257  sub get_turnedin_filepath {
                 my $maptitle = $mapres->compTitle();                  my $maptitle = $mapres->compTitle();
                 $maptitle =~ s/\W+/_/g;                  $maptitle =~ s/\W+/_/g;
                 if ($maptitle ne '') {                  if ($maptitle ne '') {
                       if (length($maptitle) > 12) {
                           $maptitle = substr($maptitle,0,12);
                       }
                     push(@pathitems,$maptitle);                      push(@pathitems,$maptitle);
                 }                  }
                 unless ($env{'request.state'} eq 'construct') {                  unless ($env{'request.state'} eq 'construct') {
Line 11940  sub get_turnedin_filepath { Line 12300  sub get_turnedin_filepath {
                 $restitle = time;                  $restitle = time;
             }              }
         }          }
           if (length($restitle) > 12) {
               $restitle = substr($restitle,0,12);
           }
         push(@pathitems,$restitle);          push(@pathitems,$restitle);
         $path .= join('/',@pathitems);          $path .= join('/',@pathitems);
     }      }
Line 12877  sub restore_settings { Line 13240  sub restore_settings {
   
 =item * &build_recipient_list()  =item * &build_recipient_list()
   
 Build recipient lists for five types of e-mail:  Build recipient lists for following types of e-mail:
 (a) Error Reports, (b) Package Updates, (c) lonstatus warnings/errors  (a) Error Reports, (b) Package Updates, (c) lonstatus warnings/errors
 (d) Help requests, (e) Course requests needing approval,  generated by  (d) Help requests, (e) Course requests needing approval, (f) loncapa
 lonerrorhandler.pm, CHECKRPMS, loncron, lonsupportreq.pm and  module change checking, student/employee ID conflict checks, as
 loncoursequeueadmin.pm respectively.  generated by lonerrorhandler.pm, CHECKRPMS, loncron,
   lonsupportreq.pm, loncoursequeueadmin.pm, searchcat.pl respectively.
   
 Inputs:  Inputs:
 defmail (scalar - email address of default recipient),   defmail (scalar - email address of default recipient), 
 mailing type (scalar - errormail, packagesmail, or helpdeskmail),   mailing type (scalar: errormail, packagesmail, helpdeskmail,
   requestsmail, updatesmail, or idconflictsmail).
   
 defdom (domain for which to retrieve configuration settings),  defdom (domain for which to retrieve configuration settings),
   
 origmail (scalar - email address of recipient from loncapa.conf,   origmail (scalar - email address of recipient from loncapa.conf, 
 i.e., predates configuration by DC via domainprefs.pm   i.e., predates configuration by DC via domainprefs.pm 
   
Line 13082  sub extract_categories { Line 13449  sub extract_categories {
   
 =pod  =pod
   
 =item *&recurse_categories()  =item * &recurse_categories()
   
 Recursively used to generate breadcrumb trails for course categories.  Recursively used to generate breadcrumb trails for course categories.
   
Line 13153  sub recurse_categories { Line 13520  sub recurse_categories {
   
 =pod  =pod
   
 =item *&assign_categories_table()  =item * &assign_categories_table()
   
 Create a datatable for display of hierarchical categories in a domain,  Create a datatable for display of hierarchical categories in a domain,
 with checkboxes to allow a course to be categorized.   with checkboxes to allow a course to be categorized. 
Line 13230  sub assign_categories_table { Line 13597  sub assign_categories_table {
   
 =pod  =pod
   
 =item *&assign_category_rows()  =item * &assign_category_rows()
   
 Create a datatable row for display of nested categories in a domain,  Create a datatable row for display of nested categories in a domain,
 with checkboxes to allow a course to be categorized,called recursively.  with checkboxes to allow a course to be categorized,called recursively.
Line 13264  sub assign_category_rows { Line 13631  sub assign_category_rows {
             if (ref($cats->[$depth]{$parent}) eq 'ARRAY') {              if (ref($cats->[$depth]{$parent}) eq 'ARRAY') {
                 my $numchildren = @{$cats->[$depth]{$parent}};                  my $numchildren = @{$cats->[$depth]{$parent}};
                 my $css_class = $itemcount%2?' class="LC_odd_row"':'';                  my $css_class = $itemcount%2?' class="LC_odd_row"':'';
                 $text .= '<td><table class="LC_datatable">';                  $text .= '<td><table class="LC_data_table">';
                 for (my $j=0; $j<$numchildren; $j++) {                  for (my $j=0; $j<$numchildren; $j++) {
                     $name = $cats->[$depth]{$parent}[$j];                      $name = $cats->[$depth]{$parent}[$j];
                     $item = &escape($name).':'.&escape($parent).':'.$depth;                      $item = &escape($name).':'.&escape($parent).':'.$depth;
Line 13548  sub check_clone { Line 13915  sub check_clone {
 }  }
   
 sub construct_course {  sub construct_course {
     my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context,$cnum,$category) = @_;      my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context,$cnum,$category,$coderef) = @_;
     my $outcome;      my $outcome;
     my $linefeed =  '<br />'."\n";      my $linefeed =  '<br />'."\n";
     if ($context eq 'auto') {      if ($context eq 'auto') {
Line 13645  sub construct_course { Line 14012  sub construct_course {
                    'plc.users.denied',                     'plc.users.denied',
                    'hidefromcat',                     'hidefromcat',
                    'checkforpriv',                     'checkforpriv',
                    'categories'],                     'categories',
                      'internal.uniquecode'],
                    $$crsudom,$$crsunum);                     $$crsudom,$$crsunum);
           if ($args->{'textbook'}) {
               $cenv{'internal.textbook'} = $args->{'textbook'};
           }
     }      }
   
 #  #
Line 13830  sub construct_course { Line 14201  sub construct_course {
  }   }
     }      }
   
   #
   #  generate and store uniquecode (available to course requester), if course should have one.
   #
       if ($args->{'uniquecode'}) {
           my ($code,$error) = &make_unique_code($$crsudom,$$crsunum);
           if ($code) {
               $cenv{'internal.uniquecode'} = $code;
               my %crsinfo =
                   &Apache::lonnet::courseiddump($$crsudom,'.',1,'.','.',$$crsunum,undef,undef,'.');
               if (ref($crsinfo{$$crsudom.'_'.$$crsunum}) eq 'HASH') {
                   $crsinfo{$$crsudom.'_'.$$crsunum}{'uniquecode'} = $code;
                   my $putres = &Apache::lonnet::courseidput($$crsudom,\%crsinfo,$crsuhome,'notime');
               } 
               if (ref($coderef)) {
                   $$coderef = $code;
               }
           }
       }
   
     if ($args->{'disresdis'}) {      if ($args->{'disresdis'}) {
         $cenv{'pch.roles.denied'}='st';          $cenv{'pch.roles.denied'}='st';
     }      }
Line 13898  sub construct_course { Line 14288  sub construct_course {
     return (1,$outcome);      return (1,$outcome);
 }  }
   
   sub make_unique_code {
       my ($cdom,$cnum) = @_;
       # get lock on uniquecodes db
       my $lockhash = {
                         $cnum."\0".'uniquecodes' => $env{'user.name'}.
                                                     ':'.$env{'user.domain'},
                      };
       my $tries = 0;
       my $gotlock = &Apache::lonnet::newput_dom('uniquecodes',$lockhash,$cdom);
       my ($code,$error);
     
       while (($gotlock ne 'ok') && ($tries<3)) {
           $tries ++;
           sleep 1;
           $gotlock = &Apache::lonnet::newput_dom('uniquecodes',$lockhash,$cdom);
       }
       if ($gotlock eq 'ok') {
           my %currcodes = &Apache::lonnet::dump_dom('uniquecodes',$cdom);
           my $gotcode;
           my $attempts = 0;
           while ((!$gotcode) && ($attempts < 100)) {
               $code = &generate_code();
               if (!exists($currcodes{$code})) {
                   $gotcode = 1;
                   unless (&Apache::lonnet::newput_dom('uniquecodes',{ $code => $cnum },$cdom) eq 'ok') {
                       $error = 'nostore';
                   }
               }
               $attempts ++;
           }
           my @del_lock = ($cnum."\0".'uniquecodes');
           my $dellockoutcome = &Apache::lonnet::del_dom('uniquecodes',\@del_lock,$cdom);
       } else {
           $error = 'nolock';
       }
       return ($code,$error);
   }
   
   sub generate_code {
       my $code;
       my @letts = qw(B C D G H J K M N P Q R S T V W X Z);
       for (my $i=0; $i<6; $i++) {
           my $lettnum = int (rand 2);
           my $item = '';
           if ($lettnum) {
               $item = $letts[int( rand(18) )];
           } else {
               $item = 1+int( rand(8) );
           }
           $code .= $item;
       }
       return $code;
   }
   
 ############################################################  ############################################################
 ############################################################  ############################################################
   
Line 13925  sub group_term { Line 14369  sub group_term {
 }  }
   
 sub course_types {  sub course_types {
     my @types = ('official','unofficial','community');      my @types = ('official','unofficial','community','textbook');
     my %typename = (      my %typename = (
                          official   => 'Official course',                           official   => 'Official course',
                          unofficial => 'Unofficial course',                           unofficial => 'Unofficial course',
                          community  => 'Community',                           community  => 'Community',
                            textbook   => 'Textbook course',
                    );                     );
     return (\@types,\%typename);      return (\@types,\%typename);
 }  }
Line 14062  sub init_user_environment { Line 14507  sub init_user_environment {
 # ------------------------------------ Check browser type and MathML capability  # ------------------------------------ Check browser type and MathML capability
   
     my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,      my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
         $clientunicode,$clientos) = &decode_user_agent($r);          $clientunicode,$clientos,$clientmobile,$clientinfo) = &decode_user_agent($r);
   
 # ------------------------------------------------------------- Get environment  # ------------------------------------------------------------- Get environment
   
Line 14093  sub init_user_environment { Line 14538  sub init_user_environment {
      "browser.mathml"     => $clientmathml,       "browser.mathml"     => $clientmathml,
      "browser.unicode"    => $clientunicode,       "browser.unicode"    => $clientunicode,
      "browser.os"         => $clientos,       "browser.os"         => $clientos,
                "browser.mobile"     => $clientmobile,
                "browser.info"       => $clientinfo,
      "server.domain"      => $Apache::lonnet::perlvar{'lonDefDomain'},       "server.domain"      => $Apache::lonnet::perlvar{'lonDefDomain'},
      "request.course.fn"  => '',       "request.course.fn"  => '',
      "request.course.uri" => '',       "request.course.uri" => '',
Line 14112  sub init_user_environment { Line 14559  sub init_user_environment {
     $env{'browser.interface'}=$form->{'interface'};      $env{'browser.interface'}=$form->{'interface'};
  }   }
   
           if ($form->{'iptoken'}) {
               my $lonhost = $r->dir_config('lonHostID');
               $initial_env{"user.noloadbalance"} = $lonhost;
               $env{'user.noloadbalance'} = $lonhost;
           }
   
         my %is_adv = ( is_adv => $env{'user.adv'} );          my %is_adv = ( is_adv => $env{'user.adv'} );
         my %domdef;          my %domdef;
         unless ($domain eq 'public') {          unless ($domain eq 'public') {
Line 14124  sub init_user_environment { Line 14577  sub init_user_environment {
                                                   undef,\%userenv,\%domdef,\%is_adv);                                                    undef,\%userenv,\%domdef,\%is_adv);
         }          }
   
         foreach my $crstype ('official','unofficial','community') {          foreach my $crstype ('official','unofficial','community','textbook') {
             $userenv{'canrequest.'.$crstype} =              $userenv{'canrequest.'.$crstype} =
                 &Apache::lonnet::usertools_access($username,$domain,$crstype,                  &Apache::lonnet::usertools_access($username,$domain,$crstype,
                                                   'reload','requestcourses',                                                    'reload','requestcourses',
Line 14345  sub parse_supplemental_title { Line 14798  sub parse_supplemental_title {
     return $title;      return $title;
 }  }
   
   sub recurse_supplemental {
       my ($cnum,$cdom,$suppmap,$numfiles,$errors) = @_;
       if ($suppmap) {
           my ($errtext,$fatal) = &LONCAPA::map::mapread('/uploaded/'.$cdom.'/'.$cnum.'/'.$suppmap);
           if ($fatal) {
               $errors ++;
           } else {
               if ($#LONCAPA::map::resources > 0) {
                   foreach my $res (@LONCAPA::map::resources) {
                       my ($title,$src,$ext,$type,$status)=split(/\:/,$res);
                       if (($src ne '') && ($status eq 'res')) {
                           if ($src =~ m{^\Q/uploaded/$cdom/$cnum/\E(supplemental_\d+\.sequence)$}) {
                               ($numfiles,$errors) = &recurse_supplemental($cnum,$cdom,$1,$numfiles,$errors);
                           } else {
                               $numfiles ++;
                           }
                       }
                   }
               }
           }
       }
       return ($numfiles,$errors);
   }
   
 sub symb_to_docspath {  sub symb_to_docspath {
     my ($symb) = @_;      my ($symb) = @_;
     return unless ($symb);      return unless ($symb);
Line 14374  sub symb_to_docspath { Line 14851  sub symb_to_docspath {
                     my $thistitle = $res->title();                      my $thistitle = $res->title();
                     $path .= '&'.                      $path .= '&'.
                              &Apache::lonhtmlcommon::entity_encode($thisurl).'&'.                               &Apache::lonhtmlcommon::entity_encode($thisurl).'&'.
                              &Apache::lonhtmlcommon::entity_encode($thistitle).                               &escape($thistitle).
                              ':'.$res->randompick().                               ':'.$res->randompick().
                              ':'.$res->randomout().                               ':'.$res->randomout().
                              ':'.$res->encrypted().                               ':'.$res->encrypted().
Line 14386  sub symb_to_docspath { Line 14863  sub symb_to_docspath {
         $path =~ s/^\&//;          $path =~ s/^\&//;
         my $maptitle = $mapresobj->title();          my $maptitle = $mapresobj->title();
         if ($mapurl eq 'default') {          if ($mapurl eq 'default') {
             $maptitle = 'Main Course Documents';              $maptitle = 'Main Content';
         }          }
         $path .= (($path ne '')? '&' : '').          $path .= (($path ne '')? '&' : '').
                  &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.                   &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.
                  &Apache::lonhtmlcommon::entity_encode($maptitle).                   &escape($maptitle).
                  ':'.$mapresobj->randompick().                   ':'.$mapresobj->randompick().
                  ':'.$mapresobj->randomout().                   ':'.$mapresobj->randomout().
                  ':'.$mapresobj->encrypted().                   ':'.$mapresobj->encrypted().
Line 14400  sub symb_to_docspath { Line 14877  sub symb_to_docspath {
         my $maptitle = &Apache::lonnet::gettitle($mapurl);          my $maptitle = &Apache::lonnet::gettitle($mapurl);
         my $ispage = (($type eq 'page')? 1 : '');          my $ispage = (($type eq 'page')? 1 : '');
         if ($mapurl eq 'default') {          if ($mapurl eq 'default') {
             $maptitle = 'Main Course Documents';              $maptitle = 'Main Content';
         }          }
         $path = &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.          $path = &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.
                 &Apache::lonhtmlcommon::entity_encode($maptitle).':::::'.$ispage;                  &escape($maptitle).':::::'.$ispage;
     }      }
     unless ($mapurl eq 'default') {      unless ($mapurl eq 'default') {
         $path = 'default&'.          $path = 'default&'.
                 &Apache::lonhtmlcommon::entity_encode('Main Course Documents').                  &escape('Main Content').
                 ':::::&'.$path;                  ':::::&'.$path;
     }      }
     return $path;      return $path;
Line 14420  sub captcha_display { Line 14897  sub captcha_display {
     if ($captcha eq 'original') {      if ($captcha eq 'original') {
         $output = &create_captcha();          $output = &create_captcha();
         unless ($output) {          unless ($output) {
             $error = 'captcha';               $error = 'captcha';
         }          }
     } elsif ($captcha eq 'recaptcha') {      } elsif ($captcha eq 'recaptcha') {
         $output = &create_recaptcha($pubkey);          $output = &create_recaptcha($pubkey);
         unless ($output) {          unless ($output) {
             $error = 'recaptcha';               $error = 'recaptcha';
         }          }
     }      }
     return ($output,$error);      return ($output,$error,$captcha);
 }  }
   
 sub captcha_response {  sub captcha_response {
Line 14504  sub create_captcha { Line 14981  sub create_captcha {
         if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') {          if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') {
             $output = '<input type="hidden" name="crypt" value="'.$md5sum.'" />'."\n".              $output = '<input type="hidden" name="crypt" value="'.$md5sum.'" />'."\n".
                       &mt('Type in the letters/numbers shown below').'&nbsp;'.                        &mt('Type in the letters/numbers shown below').'&nbsp;'.
                      '<input type="text" size="5" name="code" value="" /><br />'.                        '<input type="text" size="5" name="code" value="" autocomplete="off" />'.
                      '<img src="'.$captcha_params{'www_output_dir'}.'/'.$md5sum.'.png" />';                        '<br />'.
                         '<img src="'.$captcha_params{'www_output_dir'}.'/'.$md5sum.'.png" alt="captcha" />';
             last;              last;
         }          }
     }      }
Line 14546  sub check_captcha { Line 15024  sub check_captcha {
   
 sub create_recaptcha {  sub create_recaptcha {
     my ($pubkey) = @_;      my ($pubkey) = @_;
       my $use_ssl;
       if ($ENV{'SERVER_PORT'} == 443) {
           $use_ssl = 1;
       }
     my $captcha = Captcha::reCAPTCHA->new;      my $captcha = Captcha::reCAPTCHA->new;
     return $captcha->get_options_setter({theme => 'white'})."\n".      return $captcha->get_options_setter({theme => 'white'})."\n".
            $captcha->get_html($pubkey).             $captcha->get_html($pubkey,undef,$use_ssl).
            &mt('If either word is hard to read, [_1] will replace them.',             &mt('If either word is hard to read, [_1] will replace them.',
                '<image src="/res/adm/pages/refresh.gif" alt="reCAPTCHA refresh" />').                 '<img src="/res/adm/pages/refresh.gif" alt="reCAPTCHA refresh" />').
            '<br /><br />';             '<br /><br />';
 }  }
   
Line 14571  sub check_recaptcha { Line 15053  sub check_recaptcha {
     return $captcha_chk;      return $captcha_chk;
 }  }
   
   sub emailusername_info {
       my @fields = ('firstname','lastname','institution','web','location','officialemail');
       my %titles = &Apache::lonlocal::texthash (
                        lastname      => 'Last Name',
                        firstname     => 'First Name',
                        institution   => 'School/college/university',
                        location      => "School's city, state/province, country",
                        web           => "School's web address",
                        officialemail => 'E-mail address at institution (if different)',
                    );
       return (\@fields,\%titles);
   }
   
   sub cleanup_html {
       my ($incoming) = @_;
       my $outgoing;
       if ($incoming ne '') {
           $outgoing = $incoming;
           $outgoing =~ s/;/&#059;/g;
           $outgoing =~ s/\#/&#035;/g;
           $outgoing =~ s/\&/&#038;/g;
           $outgoing =~ s/</&#060;/g;
           $outgoing =~ s/>/&#062;/g;
           $outgoing =~ s/\(/&#040/g;
           $outgoing =~ s/\)/&#041;/g;
           $outgoing =~ s/"/&#034;/g;
           $outgoing =~ s/'/&#039;/g;
           $outgoing =~ s/\$/&#036;/g;
           $outgoing =~ s{/}{&#047;}g;
           $outgoing =~ s/=/&#061;/g;
           $outgoing =~ s/\\/&#092;/g
       }
       return $outgoing;
   }
   
   # Use:
   #   my $answer=reply("encrypt:passwd:$udom:$uname:$upass",$tryserver);
   #
   ##################################################
   #          password associated functions         #
   ##################################################
   sub des_keys {
       # Make a new key for DES encryption.
       # Each key has two parts which are returned separately.
       # Please note:  Each key must be passed through the &hex function
       # before it is output to the web browser.  The hex versions cannot
       # be used to decrypt.
       my @hexstr=('0','1','2','3','4','5','6','7',
                   '8','9','a','b','c','d','e','f');
       my $lkey='';
       for (0..7) {
           $lkey.=$hexstr[rand(15)];
       }
       my $ukey='';
       for (0..7) {
           $ukey.=$hexstr[rand(15)];
       }
       return ($lkey,$ukey);
   }
   
   sub des_decrypt {
       my ($key,$cyphertext) = @_;
       my $keybin=pack("H16",$key);
       my $cypher;
       if ($Crypt::DES::VERSION>=2.03) {
           $cypher=new Crypt::DES $keybin;
       } else {
           $cypher=new DES $keybin;
       }
       my $plaintext=
           $cypher->decrypt(unpack("a8",pack("H16",substr($cyphertext,0,16))));
       $plaintext.=
           $cypher->decrypt(unpack("a8",pack("H16",substr($cyphertext,16,16))));
       $plaintext=substr($plaintext,1,ord(substr($plaintext,0,1)) );
       return $plaintext;
   }
   
 =pod  =pod
   
 =back  =back

Removed from v.1.1124  
changed lines
  Added in v.1.1178


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