Diff for /loncom/interface/domainprefs.pm between versions 1.160.6.118.2.14 and 1.160.6.122

version 1.160.6.118.2.14, 2023/07/05 17:08:22 version 1.160.6.122, 2022/02/27 02:42:30
Line 27 Line 27
 #  #
 #  #
 ###############################################################  ###############################################################
 ###############################################################  ##############################################################
   
 =pod  =pod
   
Line 104  $datatable  - HTML containing form eleme Line 104  $datatable  - HTML containing form eleme
   
 In the case of course requests, radio buttons are displayed for each institutional  In the case of course requests, radio buttons are displayed for each institutional
 affiliate type (and also default, and _LC_adv) for each of the course types   affiliate type (and also default, and _LC_adv) for each of the course types 
 (official, unofficial, community, textbook, and lti).  (official, unofficial, community, and textbook).  In each case the radio buttons 
 In each case the radio buttons allow the selection of one of four values:  allow the selection of one of four values:
   
 0, approval, validate, autolimit=N (where N is blank, or a positive integer).  0, approval, validate, autolimit=N (where N is blank, or a positive integer).
 which have the following effects:  which have the following effects:
Line 167  use Apache::lonmsg(); Line 167  use Apache::lonmsg();
 use Apache::lonconfigsettings;  use Apache::lonconfigsettings;
 use Apache::lonuserutils();  use Apache::lonuserutils();
 use Apache::loncoursequeueadmin();  use Apache::loncoursequeueadmin();
 use Apache::courseprefs();  
 use LONCAPA qw(:DEFAULT :match);  use LONCAPA qw(:DEFAULT :match);
 use LONCAPA::Enrollment;  use LONCAPA::Enrollment;
 use LONCAPA::lonauthcgi();  use LONCAPA::lonauthcgi();
Line 175  use File::Copy; Line 174  use File::Copy;
 use Locale::Language;  use Locale::Language;
 use DateTime::TimeZone;  use DateTime::TimeZone;
 use DateTime::Locale;  use DateTime::Locale;
 use Time::HiRes qw( sleep );  
 use Net::CIDR;  use Net::CIDR;
 use Crypt::CBC;  
   
 my $registered_cleanup;  my $registered_cleanup;
 my $modified_urls;  my $modified_urls;
Line 221  sub handler { Line 218  sub handler {
                 'serverstatuses','requestcourses','helpsettings',                  'serverstatuses','requestcourses','helpsettings',
                 'coursedefaults','usersessions','loadbalancing',                  'coursedefaults','usersessions','loadbalancing',
                 'requestauthor','selfenrollment','inststatus',                  'requestauthor','selfenrollment','inststatus',
                 'passwords','ltitools','toolsec','lti','ltisec',                  'passwords','wafproxy','ipaccess'],$dom);
                 'wafproxy','ipaccess'],$dom);  
     my %encconfig =  
         &Apache::lonnet::get_dom('encconfig',['ltitools','lti','linkprot'],$dom,undef,1);  
     my ($checked_is_home,$is_home);  
     if (ref($domconfig{'ltitools'}) eq 'HASH') {  
         if (ref($encconfig{'ltitools'}) eq 'HASH') {  
             my $home = &Apache::lonnet::domain($dom,'primary');  
             unless (($home eq 'no_host') || ($home eq '')) {  
                 my @ids=&Apache::lonnet::current_machine_ids();  
                 if (grep(/^\Q$home\E$/,@ids)) {  
                     $is_home = 1;  
                 }  
             }  
             $checked_is_home = 1;  
             foreach my $id (keys(%{$domconfig{'ltitools'}})) {  
                 if ((ref($domconfig{'ltitools'}{$id}) eq 'HASH') &&  
                     (ref($encconfig{'ltitools'}{$id}) eq 'HASH')) {  
                     $domconfig{'ltitools'}{$id}{'key'} = $encconfig{'ltitools'}{$id}{'key'};  
                     if (($is_home) && ($phase eq 'process')) {  
                         $domconfig{'ltitools'}{$id}{'secret'} = $encconfig{'ltitools'}{$id}{'secret'};  
                     }  
                 }  
             }  
         }  
     }  
     if (ref($domconfig{'lti'}) eq 'HASH') {  
         if (ref($encconfig{'lti'}) eq 'HASH') {  
             unless ($checked_is_home) {  
                 my $home = &Apache::lonnet::domain($dom,'primary');  
                 unless (($home eq 'no_host') || ($home eq '')) {  
                     my @ids=&Apache::lonnet::current_machine_ids();  
                     if (grep(/^\Q$home\E$/,@ids)) {  
                         $is_home = 1;  
                     }  
                 }  
                 $checked_is_home = 1;  
             }  
             foreach my $id (keys(%{$domconfig{'lti'}})) {  
                 if ((ref($domconfig{'lti'}{$id}) eq 'HASH') &&  
                     (ref($encconfig{'lti'}{$id}) eq 'HASH')) {  
                     $domconfig{'lti'}{$id}{'key'} = $encconfig{'lti'}{$id}{'key'};  
                     if (($is_home) && ($phase eq 'process')) {  
                         $domconfig{'lti'}{$id}{'secret'} = $encconfig{'lti'}{$id}{'secret'};  
                     }  
                 }  
             }  
         }  
     }  
     if (ref($domconfig{'ltisec'}) eq 'HASH') {  
         if (ref($domconfig{'ltisec'}{'linkprot'}) eq 'HASH') {  
             if (ref($encconfig{'linkprot'}) eq 'HASH') {  
                 foreach my $id (keys(%{$domconfig{'ltisec'}{'linkprot'}})) {  
                     unless ($id =~ /^\d+$/) {  
                         delete($domconfig{'ltisec'}{'linkprot'}{$id});  
                     }  
                     if ((ref($domconfig{'ltisec'}{'linkprot'}{$id}) eq 'HASH') &&  
                         (ref($encconfig{'linkprot'}{$id}) eq 'HASH')) {  
                         foreach my $item ('key','secret') {  
                             $domconfig{'ltisec'}{'linkprot'}{$id}{$item} = $encconfig{'linkprot'}{$id}{$item};  
                         }  
                     }  
                 }  
             }  
         }  
     }  
     my @prefs_order = ('rolecolors','login','ipaccess','defaults','wafproxy','passwords',      my @prefs_order = ('rolecolors','login','ipaccess','defaults','wafproxy','passwords',
                        'quotas','autoenroll','autoupdate','autocreate','directorysrch',                         'quotas','autoenroll','autoupdate','autocreate','directorysrch',
                        'contacts','usercreation','selfcreation','usermodification',                         'contacts','usercreation','selfcreation','usermodification',
                        'scantron','requestcourses','requestauthor','coursecategories',                         'scantron','requestcourses','requestauthor','coursecategories',
                        'serverstatuses','helpsettings','coursedefaults',                         'serverstatuses','helpsettings','coursedefaults',
                        'ltitools','selfenrollment','usersessions','lti');                         'selfenrollment','usersessions');
     my %existing;      my %existing;
     if (ref($domconfig{'loadbalancing'}) eq 'HASH') {      if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
         %existing = %{$domconfig{'loadbalancing'}};          %existing = %{$domconfig{'loadbalancing'}};
Line 368  sub handler { Line 300  sub handler {
                       modify => \&modify_passwords,                        modify => \&modify_passwords,
                     },                      },
         'quotas' =>           'quotas' => 
                     { text => 'Blogs, personal pages/timezones, webDAV/quotas, portfolio',                      { text => 'Blogs, personal web pages, webDAV/quotas, portfolios',
                       help => 'Domain_Configuration_Quotas',                        help => 'Domain_Configuration_Quotas',
                       header => [{col1 => 'User affiliation',                        header => [{col1 => 'User affiliation',
                                   col2 => 'Available tools',                                    col2 => 'Available tools',
Line 576  sub handler { Line 508  sub handler {
                   print => \&print_loadbalancing,                    print => \&print_loadbalancing,
                   modify => \&modify_loadbalancing,                    modify => \&modify_loadbalancing,
                  },                   },
         'ltitools' =>           'ipaccess' =>
                  {text => 'External Tools (LTI)',  
                   help => 'Domain_Configuration_LTI_Tools',  
                   header => [{col1 => 'Encryption of shared secrets',  
                               col2 => 'Settings'},  
                              {col1 => 'Rules for shared secrets',  
                               col2 => 'Settings'},  
                              {col1 => 'Providers',  
                               col2 => 'Settings',}],  
                   print => \&print_ltitools,  
                   modify => \&modify_ltitools,  
                  },  
         'lti' =>  
                  {text => 'LTI Link Protection and LTI Consumers',  
                   help => 'Domain_Configuration_LTI_Provider',  
                   header => [{col1 => 'Encryption of shared secrets',  
                               col2 => 'Settings'},  
                              {col1 => 'Rules for shared secrets',  
                               col2 => 'Settings'},  
                              {col1 => 'Link Protectors',  
                               col2 => 'Settings'},  
                              {col1 => 'Consumers',  
                               col2 => 'Settings'},],  
                   print => \&print_lti,  
                   modify => \&modify_lti,  
                  },  
         'ipaccess' =>  
                        {text => 'IP-based access control',                         {text => 'IP-based access control',
                         help => 'Domain_Configuration_IP_Access',                          help => 'Domain_Configuration_IP_Access',
                         header => [{col1 => 'Setting',                          header => [{col1 => 'Setting',
Line 617  sub handler { Line 523  sub handler {
                             header => [{col1 => 'Log-in Service',                              header => [{col1 => 'Log-in Service',
                                         col2 => 'Server Setting',},                                          col2 => 'Server Setting',},
                                        {col1 => 'Log-in Page Items',                                         {col1 => 'Log-in Page Items',
                                         col2 => 'Settings'},                                          col2 => ''},
                                        {col1 => 'Log-in Help',                                         {col1 => 'Log-in Help',
                                         col2 => 'Value'},                                          col2 => 'Value'},
                                        {col1 => 'Custom HTML in document head',                                         {col1 => 'Custom HTML in document head',
Line 797  sub process_changes { Line 703  sub process_changes {
         $output = &modify_usersessions($dom,$lastactref,%domconfig);          $output = &modify_usersessions($dom,$lastactref,%domconfig);
     } elsif ($action eq 'loadbalancing') {      } elsif ($action eq 'loadbalancing') {
         $output = &modify_loadbalancing($dom,%domconfig);          $output = &modify_loadbalancing($dom,%domconfig);
     } elsif ($action eq 'ltitools') {  
         $output = &modify_ltitools($r,$dom,$action,$lastactref,%domconfig);  
     } elsif ($action eq 'lti') {  
         $output = &modify_lti($r,$dom,$action,$lastactref,%domconfig);  
     } elsif ($action eq 'passwords') {      } elsif ($action eq 'passwords') {
         $output = &modify_passwords($r,$dom,$confname,$lastactref,%domconfig);          $output = &modify_passwords($r,$dom,$confname,$lastactref,%domconfig);
     } elsif ($action eq 'wafproxy') {      } elsif ($action eq 'wafproxy') {
Line 820  sub print_config_box { Line 722  sub print_config_box {
     } elsif ($action eq 'defaults') {      } elsif ($action eq 'defaults') {
         $output = &defaults_javascript($settings);           $output = &defaults_javascript($settings); 
     } elsif ($action eq 'passwords') {      } elsif ($action eq 'passwords') {
         $output = &passwords_javascript($action);          $output = &passwords_javascript();
     } elsif ($action eq 'helpsettings') {      } elsif ($action eq 'helpsettings') {
         my (%privs,%levelscurrent);          my (%privs,%levelscurrent);
         my %full=();          my %full=();
Line 837  sub print_config_box { Line 739  sub print_config_box {
         $output =          $output =
             &Apache::lonuserutils::custom_roledefs_js($context,$crstype,$formname,\%full,              &Apache::lonuserutils::custom_roledefs_js($context,$crstype,$formname,\%full,
                                                       \@templateroles);                                                        \@templateroles);
     } elsif ($action eq 'ltitools') {  
         $output .= &Apache::lonconfigsettings::ltitools_javascript($settings);  
     } elsif ($action eq 'lti') {  
         $output .= &passwords_javascript('ltisecrets')."\n".  
                    &lti_javascript($dom,$settings);  
     } elsif ($action eq 'wafproxy') {      } elsif ($action eq 'wafproxy') {
         $output .= &wafproxy_javascript($dom);          $output .= &wafproxy_javascript($dom);
     } elsif ($action eq 'autoupdate') {      } elsif ($action eq 'autoupdate') {
Line 868  sub print_config_box { Line 765  sub print_config_box {
     if ($numheaders > 1) {      if ($numheaders > 1) {
         my $colspan = '';          my $colspan = '';
         my $rightcolspan = '';          my $rightcolspan = '';
         my $leftnobr = '';          my $leftnobr = '';  
         if (($action eq 'rolecolors') || ($action eq 'defaults') ||          if (($action eq 'rolecolors') || ($action eq 'defaults') ||
             ($action eq 'directorysrch') ||              ($action eq 'directorysrch') ||
             (($action eq 'login') && ($numheaders < 5))) {              (($action eq 'login') && ($numheaders < 5))) {
Line 892  sub print_config_box { Line 789  sub print_config_box {
         if (($action eq 'autoupdate') || ($action eq 'usercreation') || ($action eq 'selfcreation') ||          if (($action eq 'autoupdate') || ($action eq 'usercreation') || ($action eq 'selfcreation') ||
             ($action eq 'usermodification') || ($action eq 'defaults') || ($action eq 'coursedefaults') ||              ($action eq 'usermodification') || ($action eq 'defaults') || ($action eq 'coursedefaults') ||
             ($action eq 'selfenrollment') || ($action eq 'usersessions') || ($action eq 'directorysrch') ||              ($action eq 'selfenrollment') || ($action eq 'usersessions') || ($action eq 'directorysrch') ||
             ($action eq 'helpsettings') || ($action eq 'contacts') || ($action eq 'wafproxy') ||              ($action eq 'helpsettings') || ($action eq 'contacts') || ($action eq 'wafproxy')) {
             ($action eq 'lti') || ($action eq 'ltitools')) {  
             $output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);              $output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'passwords') {          } elsif ($action eq 'passwords') {
             $output .= $item->{'print'}->('top',$dom,$confname,$settings,\$rowtotal);              $output .= $item->{'print'}->('top',$dom,$confname,$settings,\$rowtotal);
Line 928  sub print_config_box { Line 824  sub print_config_box {
         if (($action eq 'autoupdate') || ($action eq 'usercreation') ||          if (($action eq 'autoupdate') || ($action eq 'usercreation') ||
             ($action eq 'selfcreation') || ($action eq 'selfenrollment') ||              ($action eq 'selfcreation') || ($action eq 'selfenrollment') ||
             ($action eq 'usersessions') || ($action eq 'coursecategories') ||              ($action eq 'usersessions') || ($action eq 'coursecategories') ||
             ($action eq 'contacts') || ($action eq 'passwords') ||               ($action eq 'contacts') || ($action eq 'passwords') || ($action eq 'defaults')) {
             ($action eq 'defaults') || ($action eq 'lti') ||  
             ($action eq 'ltitools')) {  
             if ($action eq 'coursecategories') {              if ($action eq 'coursecategories') {
                 $output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal);                  $output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal);
                 $colspan = ' colspan="2"';                  $colspan = ' colspan="2"';
Line 1186  sub print_login { Line 1080  sub print_login {
         %lt = &login_file_options();          %lt = &login_file_options();
         $switchserver = &check_switchserver($dom,$confname);          $switchserver = &check_switchserver($dom,$confname);
     }      }
   
     if ($caller eq 'service') {      if ($caller eq 'service') {
         my %servers = &Apache::lonnet::internet_dom_servers($dom);          my %servers = &Apache::lonnet::internet_dom_servers($dom);
         my $choice = $choices{'disallowlogin'};          my $choice = $choices{'disallowlogin'};
Line 1516  sub print_login { Line 1411  sub print_login {
                       '<table><tr><th>'.$choices{'hostid'}.'</th>'.                        '<table><tr><th>'.$choices{'hostid'}.'</th>'.
                       '<th>'.$choices{'samllanding'}.'</th>'.                        '<th>'.$choices{'samllanding'}.'</th>'.
                       '<th>'.$choices{'samloptions'}.'</th></tr>'."\n";                        '<th>'.$choices{'samloptions'}.'</th></tr>'."\n";
         my (%saml,%samltext,%samlimg,%samlalt,%samlurl,%samltitle,%samlwindow,%samlnotsso,%styleon,%styleoff);          my (%saml,%samltext,%samlimg,%samlalt,%samlurl,%samltitle,%samlnotsso,%styleon,%styleoff);
         foreach my $lonhost (keys(%domservers)) {          foreach my $lonhost (keys(%domservers)) {
             $samlurl{$lonhost} = '/adm/sso';              $samlurl{$lonhost} = '/adm/sso';
             $styleon{$lonhost} = 'display:none';              $styleon{$lonhost} = 'display:none';
             $styleoff{$lonhost} = '';              $styleoff{$lonhost} = '';
         }          }
         if ((ref($settings) eq 'HASH') && (ref($settings->{'saml'}) eq 'HASH')) {          if (ref($settings->{'saml'}) eq 'HASH') {
             foreach my $lonhost (keys(%{$settings->{'saml'}})) {              foreach my $lonhost (keys(%{$settings->{'saml'}})) {
                 if (ref($settings->{'saml'}{$lonhost}) eq 'HASH') {                  if (ref($settings->{'saml'}{$lonhost}) eq 'HASH') {
                     $saml{$lonhost} = 1;                      $saml{$lonhost} = 1;
Line 1531  sub print_login { Line 1426  sub print_login {
                     $samlalt{$lonhost} = $settings->{'saml'}{$lonhost}{'alt'};                      $samlalt{$lonhost} = $settings->{'saml'}{$lonhost}{'alt'};
                     $samlurl{$lonhost} = $settings->{'saml'}{$lonhost}{'url'};                      $samlurl{$lonhost} = $settings->{'saml'}{$lonhost}{'url'};
                     $samltitle{$lonhost} = $settings->{'saml'}{$lonhost}{'title'};                      $samltitle{$lonhost} = $settings->{'saml'}{$lonhost}{'title'};
                     $samlwindow{$lonhost} = $settings->{'saml'}{$lonhost}{'window'};  
                     $samlnotsso{$lonhost} = $settings->{'saml'}{$lonhost}{'notsso'};                      $samlnotsso{$lonhost} = $settings->{'saml'}{$lonhost}{'notsso'};
                     $styleon{$lonhost} = '';                      $styleon{$lonhost} = '';
                     $styleoff{$lonhost} = 'display:none';                      $styleoff{$lonhost} = 'display:none';
Line 1549  sub print_login { Line 1443  sub print_login {
                 $samlon = $samloff;                  $samlon = $samloff;
                 $samloff = ' ';                  $samloff = ' ';
             }              }
             my $samlwinon = '';  
             my $samlwinoff = ' checked="checked"';  
             if ($samlwindow{$lonhost}) {  
                 $samlwinon = $samlwinoff;  
                 $samlwinoff = '';  
             }  
             my $css_class = $itemcount%2?' class="LC_odd_row"':'';              my $css_class = $itemcount%2?' class="LC_odd_row"':'';
             $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.$domservers{$lonhost}.'</span></td>'.              $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.$domservers{$lonhost}.'</span></td>'.
                           '<td><span class="LC_nobreak"><label><input type="radio" name="saml_'.$lonhost.'"'.$samloff.                            '<td><span class="LC_nobreak"><label><input type="radio" name="saml_'.$lonhost.'"'.$samloff.
Line 1564  sub print_login { Line 1452  sub print_login {
                           'onclick="toggleSamlOptions(this.form,'."'$lonhost'".');" value="1" />'.                            'onclick="toggleSamlOptions(this.form,'."'$lonhost'".');" value="1" />'.
                           &mt('Yes').'</label></span></td>'.                            &mt('Yes').'</label></span></td>'.
                           '<td id="samloptionson_'.$lonhost.'" style="'.$styleon{$lonhost}.'" width="100%">'.                            '<td id="samloptionson_'.$lonhost.'" style="'.$styleon{$lonhost}.'" width="100%">'.
                           '<table width="100%"><tr><th colspan="3" align="center">'.&mt('SSO').'</th></tr>'.                            '<table><tr><th colspan="5" align="center">'.&mt('SSO').'</th><th align="center">'.
                             '<span class="LC_nobreak">'.&mt('Non-SSO').'</span></th></tr>'.
                           '<tr><th>'.&mt('Text').'</th><th>'.&mt('Image').'</th>'.                            '<tr><th>'.&mt('Text').'</th><th>'.&mt('Image').'</th>'.
                           '<th>'.&mt('Alt Text').'</th></tr>'.                            '<th>'.&mt('Alt Text').'</th><th>'.&mt('URL').'</th>'.
                           '<tr'.$css_class.'><td><input type="text" name="saml_text_'.$lonhost.'" size="20" value="'.                            '<th>'.&mt('Tool Tip').'</th><th>'.&mt('Text').'</th></tr>'.
                             '<tr'.$css_class.'><td><input type="text" name="saml_text_'.$lonhost.'" size="8" value="'.
                           $samltext{$lonhost}.'" /></td><td>';                            $samltext{$lonhost}.'" /></td><td>';
             if ($samlimg{$lonhost}) {              if ($samlimg{$lonhost}) {
                 $datatable .= '<img src="'.$samlimg{$lonhost}.'" /><br />'.                  $datatable .= '<img src="'.$samlimg{$lonhost}.'" /><br />'.
Line 1584  sub print_login { Line 1474  sub print_login {
                 $datatable .= '<input type="file" name="saml_img_'.$lonhost.'" />';                  $datatable .= '<input type="file" name="saml_img_'.$lonhost.'" />';
             }              }
             $datatable .= '</td>'.              $datatable .= '</td>'.
                           '<td><input type="text" name="saml_alt_'.$lonhost.'" size="25" '.                            '<td><input type="text" name="saml_alt_'.$lonhost.'" size="20" '.
                           'value="'.$samlalt{$lonhost}.'" /></td></tr></table><br />'.                            'value="'.$samlalt{$lonhost}.'" /></td>'.
                           '<table width="100%"><tr><th colspan="3" align="center">'.&mt('SSO').'</th><th align="center">'.                            '<td><input type="text" name="saml_url_'.$lonhost.'" size="8" '.
                           '<span class="LC_nobreak">'.&mt('Non-SSO').'</span></th></tr>'.  
                           '<tr><th>'.&mt('URL').'</th><th>'.&mt('Tool Tip').'</th>'.  
                           '<th>'.&mt('Pop-up if iframe').'</th><th>'.&mt('Text').'</th></tr>'.  
                           '<tr'.$css_class.'>'.  
                           '<td><input type="text" name="saml_url_'.$lonhost.'" size="30" '.  
                           'value="'.$samlurl{$lonhost}.'" /></td>'.                            'value="'.$samlurl{$lonhost}.'" /></td>'.
                           '<td><textarea name="saml_title_'.$lonhost.'" rows="3" cols="20">'.                            '<td><textarea name="saml_title_'.$lonhost.'" rows="3" cols="15">'.
                           $samltitle{$lonhost}.'</textarea></td>'.                            $samltitle{$lonhost}.'</textarea></td>'.
                           '<td><label><input type="radio" name="saml_window_'.$lonhost.'" value=""'.$samlwinoff.'>'.                            '<td><input type="text" name="saml_notsso_'.$lonhost.'" size="8" '.
                           &mt('No').'</label>'.('&nbsp;'x2).'<label><input type="radio" '.  
                           'name="saml_window_'.$lonhost.'" value="1"'.$samlwinon.'>'.&mt('Yes').'</label></td>'.  
                           '<td><input type="text" name="saml_notsso_'.$lonhost.'" size="12" '.  
                           'value="'.$samlnotsso{$lonhost}.'" /></td></tr>'.                            'value="'.$samlnotsso{$lonhost}.'" /></td></tr>'.
                           '</table></td>'.                            '</table></td>'.
                           '<td id="samloptionsoff_'.$lonhost.'" style="'.$styleoff{$lonhost}.'" width="100%">&nbsp;</td></tr>';                            '<td id="samloptionsoff_'.$lonhost.'" style="'.$styleoff{$lonhost}.'" width="100%">&nbsp;</td></tr>';
Line 1997  sub display_color_options { Line 1879  sub display_color_options {
                 $logincolors =                  $logincolors =
                     &login_text_colors($img,$role,$logintext,$phase,$choices,                      &login_text_colors($img,$role,$logintext,$phase,$choices,
                                        $designs,$defaults);                                         $designs,$defaults);
             } else {              } else { 
                 if ($img ne 'domlogo') {                  if ($img ne 'domlogo') {
                     $datatable.= &logo_display_options($img,$defaults,$designs);                      $datatable.= &logo_display_options($img,$defaults,$designs);
                 }                  }
Line 2262  sub print_quotas { Line 2144  sub print_quotas {
     my $typecount = 0;      my $typecount = 0;
     my ($css_class,%titles);      my ($css_class,%titles);
     if ($context eq 'requestcourses') {      if ($context eq 'requestcourses') {
         @usertools = ('official','unofficial','community','textbook','lti');          @usertools = ('official','unofficial','community','textbook');
         @options =('norequest','approval','validate','autolimit');          @options =('norequest','approval','validate','autolimit');
         %validations = &Apache::lonnet::auto_courserequest_checks($dom);          %validations = &Apache::lonnet::auto_courserequest_checks($dom);
         %titles = &courserequest_titles();          %titles = &courserequest_titles();
Line 2271  sub print_quotas { Line 2153  sub print_quotas {
         @options = ('norequest','approval','automatic');          @options = ('norequest','approval','automatic');
         %titles = &authorrequest_titles();          %titles = &authorrequest_titles();
     } else {      } else {
         @usertools = ('aboutme','blog','webdav','portfolio','timezone');          @usertools = ('aboutme','blog','webdav','portfolio');
         %titles = &tool_titles();          %titles = &tool_titles();
     }      }
     if (ref($types) eq 'ARRAY') {      if (ref($types) eq 'ARRAY') {
Line 2375  sub print_quotas { Line 2257  sub print_quotas {
                         }                          }
                     } else {                      } else {
                         my $checked = 'checked="checked" ';                          my $checked = 'checked="checked" ';
                         if ($item eq 'timezone') {  
                             $checked = '';  
                         }  
                         if (ref($settings) eq 'HASH') {                          if (ref($settings) eq 'HASH') {
                             if (ref($settings->{$item}) eq 'HASH') {                              if (ref($settings->{$item}) eq 'HASH') {
                                 if (!$settings->{$item}->{$type}) {                                  if ($settings->{$item}->{$type} == 0) {
                                     $checked = '';                                      $checked = '';
                                 } elsif ($settings->{$item}->{$type} == 1) {                                  } elsif ($settings->{$item}->{$type} == 1) {
                                     $checked =  'checked="checked" ';                                      $checked =  'checked="checked" ';
Line 2729  sub print_studentcode { Line 2608  sub print_studentcode {
     my ($settings,$rowtotal) = @_;      my ($settings,$rowtotal) = @_;
     my $rownum = 0;       my $rownum = 0; 
     my ($output,%current);      my ($output,%current);
     my @crstypes = ('official','unofficial','community','textbook','lti');      my @crstypes = ('official','unofficial','community','textbook');
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if (ref($settings->{'uniquecode'}) eq 'HASH') {          if (ref($settings->{'uniquecode'}) eq 'HASH') {
             foreach my $type (@crstypes) {              foreach my $type (@crstypes) {
Line 2979  $jstext{'templates'}; Line 2858  $jstext{'templates'};
 ENDSCRIPT  ENDSCRIPT
 }  }
   
 sub ltitools_javascript {  
     my ($settings) = @_;  
     my $togglejs = &ltitools_toggle_js();  
     unless (ref($settings) eq 'HASH') {  
         return $togglejs;  
     }  
     my (%ordered,$total,%jstext);  
     $total = 0;  
     foreach my $item (keys(%{$settings})) {  
         if (ref($settings->{$item}) eq 'HASH') {  
             my $num = $settings->{$item}{'order'};  
             $ordered{$num} = $item;  
         }  
     }  
     $total = scalar(keys(%{$settings}));  
     my @jsarray = ();  
     foreach my $item (sort {$a <=> $b } (keys(%ordered))) {  
         push(@jsarray,$ordered{$item});  
     }  
     my $jstext = '    var ltitools = Array('."'".join("','",@jsarray)."'".');'."\n";  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
 function reorderLTITools(form,item) {  
     var changedVal;  
 $jstext  
     var newpos = 'ltitools_add_pos';  
     var maxh = 1 + $total;  
     var current = new Array;  
     var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;  
     if (item == newpos) {  
         changedVal = newitemVal;  
     } else {  
         changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;  
         current[newitemVal] = newpos;  
     }  
     for (var i=0; i<ltitools.length; i++) {  
         var elementName = 'ltitools_'+ltitools[i];  
         if (elementName != item) {  
             if (form.elements[elementName]) {  
                 var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;  
                 current[currVal] = elementName;  
             }  
         }  
     }  
     var oldVal;  
     for (var j=0; j<maxh; j++) {  
         if (current[j] == undefined) {  
             oldVal = j;  
         }  
     }  
     if (oldVal < changedVal) {  
         for (var k=oldVal+1; k<=changedVal ; k++) {  
            var elementName = current[k];  
            form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;  
         }  
     } else {  
         for (var k=changedVal; k<oldVal; k++) {  
             var elementName = current[k];  
             form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;  
         }  
     }  
     return;  
 }  
   
 // ]]>  
 </script>  
   
 $togglejs  
   
 ENDSCRIPT  
 }  
   
 sub ltitools_toggle_js {  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
   
 function toggleLTITools(form,setting,item) {  
     var radioname = '';  
     var divid = '';  
     if ((setting == 'passback') || (setting == 'roster')) {  
         radioname = 'ltitools_'+setting+'_'+item;  
         divid = 'ltitools_'+setting+'time_'+item;  
         var num = form.elements[radioname].length;  
         if (num) {  
             var setvis = '';  
             for (var i=0; i<num; i++) {  
                 if (form.elements[radioname][i].checked) {  
                     if (form.elements[radioname][i].value == '1') {  
                         if (document.getElementById(divid)) {  
                             document.getElementById(divid).style.display = 'inline-block';  
                         }  
                         setvis = 1;  
                     }  
                     break;  
                 }  
             }  
         }  
         if (!setvis) {  
             if (document.getElementById(divid)) {  
                 document.getElementById(divid).style.display = 'none';  
             }  
         }  
     }  
     if (setting == 'user') {  
         divid = 'ltitools_'+setting+'_div_'+item;  
         var checkid = 'ltitools_'+setting+'_field_'+item;  
         if (document.getElementById(divid)) {  
             if (document.getElementById(checkid)) {  
                 if (document.getElementById(checkid).checked) {  
                     document.getElementById(divid).style.display = 'inline-block';  
                 } else {  
                     document.getElementById(divid).style.display = 'none';  
                 }  
             }  
         }  
     }  
     return;  
 }  
 // ]]>  
 </script>  
   
 ENDSCRIPT  
 }  
   
 sub wafproxy_javascript {  sub wafproxy_javascript {
     my ($dom) = @_;      my ($dom) = @_;
     return <<"ENDSCRIPT";      return <<"ENDSCRIPT";
Line 3220  function toggleWAF() { Line 2973  function toggleWAF() {
 ENDSCRIPT  ENDSCRIPT
 }  }
   
 sub lti_javascript {  
     my ($dom,$settings) = @_;  
     my $togglejs = &lti_toggle_js($dom);  
     my $linkprot_js = &Apache::courseprefs::linkprot_javascript();  
     unless (ref($settings) eq 'HASH') {  
         return $togglejs.'  
 <script type="text/javascript">  
 // <![CDATA[  
   
 '.$linkprot_js.'  
   
 // ]]>  
 </script>  
 ';  
     }  
     my (%ordered,$total,%jstext);  
     $total = scalar(keys(%{$settings}));  
     foreach my $item (keys(%{$settings})) {  
         if (ref($settings->{$item}) eq 'HASH') {  
             my $num = $settings->{$item}{'order'};  
             if ($num eq '') {  
                 $num = $total - 1;  
             }  
             $ordered{$num} = $item;  
         }  
     }  
     my @jsarray = ();  
     foreach my $item (sort {$a <=> $b } (keys(%ordered))) {  
         push(@jsarray,$ordered{$item});  
     }  
     my $jstext = '    var lti = Array('."'".join("','",@jsarray)."'".');'."\n";  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
 function reorderLTI(form,item) {  
     var changedVal;  
 $jstext  
     var newpos = 'lti_pos_add';  
     var maxh = 1 + $total;  
     var current = new Array;  
     var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;  
     if (item == newpos) {  
         changedVal = newitemVal;  
     } else {  
         changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;  
         current[newitemVal] = newpos;  
     }  
     for (var i=0; i<lti.length; i++) {  
         var elementName = 'lti_pos_'+lti[i];  
         if (elementName != item) {  
             if (form.elements[elementName]) {  
                 var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;  
                 current[currVal] = elementName;  
             }  
         }  
     }  
     var oldVal;  
     for (var j=0; j<maxh; j++) {  
         if (current[j] == undefined) {  
             oldVal = j;  
         }  
     }  
     if (oldVal < changedVal) {  
         for (var k=oldVal+1; k<=changedVal ; k++) {  
            var elementName = current[k];  
            form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;  
         }  
     } else {  
         for (var k=changedVal; k<oldVal; k++) {  
             var elementName = current[k];  
             form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;  
         }  
     }  
     return;  
 }  
   
 $linkprot_js  
   
 // ]]>  
 </script>  
   
 $togglejs  
   
 ENDSCRIPT  
 }  
   
 sub lti_toggle_js {  
     my ($dom) = @_;  
     my %lcauthparmtext = &Apache::lonlocal::texthash (  
                             localauth => 'Local auth argument',  
                             krb       => 'Kerberos domain',  
                          );  
     my $crsincalert = &mt('"User\'s identity sent" needs to be set to "Yes" first,[_1] before setting "Course\'s identity sent" to "Yes"',"\n");  
     &js_escape(\$crsincalert);  
     my %servers = &Apache::lonnet::get_servers($dom,'library');  
     my $primary = &Apache::lonnet::domain($dom,'primary');  
     my $course_servers = "'".join("','",keys(%servers))."'";  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
   
 function toggleLTI(form,setting,item) {  
     if ((setting == 'requser') || (setting == 'crsinc')) {  
         var usrfieldsets = document.getElementsByClassName('ltioption_usr_'+item);  
         var setvis = '';  
         var radioname = 'lti_requser_'+item;  
         var num = form.elements[radioname].length;  
         if (num) {  
             for (var i=0; i<num; i++) {  
                 if (form.elements[radioname][i].checked) {  
                     if (form.elements[radioname][i].value == '1') {  
                         setvis = 1;  
                         break;  
                     }  
                 }  
             }  
         }  
         if (usrfieldsets.length) {  
             for (var j=0; j<usrfieldsets.length; j++) {  
                 if (setvis) {  
                     usrfieldsets[j].style.display = 'block';  
                 } else {  
                     usrfieldsets[j].style.display = 'none';  
                 }  
             }  
         }  
         var crsfieldsets = document.getElementsByClassName('ltioption_crs_'+item);  
         if (crsfieldsets.length) {  
             radioname = 'lti_crsinc_'+item;  
             var num = form.elements[radioname].length;  
             if (num) {  
                 var crsvis = '';  
                 for (var i=0; i<num; i++) {  
                     if (form.elements[radioname][i].checked) {  
                         if (form.elements[radioname][i].value == '1') {  
                             if (setvis == '') {  
                                 if (setting == 'crsinc'){  
                                     alert("$crsincalert");  
                                     form.elements[radioname][0].checked = true;  
                                 }  
                             } else {  
                                 crsvis = 1;  
                             }  
                             break;  
                         }  
                     }  
                 }  
                 setvis = crsvis;  
             }  
             for (var j=0; j<crsfieldsets.length; j++) {  
                 if (setvis) {  
                     crsfieldsets[j].style.display = 'block';  
                 } else {  
                     crsfieldsets[j].style.display = 'none';  
                 }  
             }  
         }  
     } else if ((setting == 'user') || (setting == 'crs') || (setting == 'passback') || (setting == 'callback')) {  
         var radioname = '';  
         var divid = '';  
         if (setting == 'user') {  
             radioname = 'lti_mapuser_'+item;  
             divid = 'lti_userfield_'+item;  
         } else if (setting == 'crs') {  
             radioname = 'lti_mapcrs_'+item;  
             divid = 'lti_crsfield_'+item;  
         } else if (setting == 'callback') {  
             radioname = 'lti_callback_'+item;  
             divid = 'lti_callbackfield_'+item;  
         } else {  
             radioname = 'lti_passback_'+item;  
             divid =  'lti_passback_'+item;  
         }  
         var num = form.elements[radioname].length;  
         if (num) {  
             var setvis = '';  
             for (var i=0; i<num; i++) {  
                if (form.elements[radioname][i].checked) {  
                    if ((setting == 'passback') || (setting == 'callback')) {  
                        if (form.elements[radioname][i].value == '1') {  
                            if (document.getElementById(divid)) {  
                                document.getElementById(divid).style.display = 'inline-block';  
                            }  
                            setvis = 1;  
                            break;  
                        }  
                    } else {  
                        if (form.elements[radioname][i].value == 'other') {  
                            if (document.getElementById(divid)) {  
                                document.getElementById(divid).style.display = 'inline-block';  
                            }  
                            setvis = 1;  
                            break;  
                        }  
                    }  
                }  
             }  
             if (!setvis) {  
                 if (document.getElementById(divid)) {  
                     document.getElementById(divid).style.display = 'none';  
                 }  
             }  
         }  
     } else if ((setting == 'sec') || (setting == 'secsrc')) {  
         var numsec = form.elements['lti_crssec_'+item].length;  
         if (numsec) {  
             var setvis = '';  
             for (var i=0; i<numsec; i++) {  
                 if (form.elements['lti_crssec_'+item][i].checked) {  
                     if (form.elements['lti_crssec_'+item][i].value == '1') {  
                         if (document.getElementById('lti_crssecfield_'+item)) {  
                             document.getElementById('lti_crssecfield_'+item).style.display = 'inline-block';  
                             setvis = 1;  
                             var numsrcsec = form.elements['lti_crssecsrc_'+item].length;  
                             if (numsrcsec) {  
                                 var setsrcvis = '';  
                                 for (var j=0; j<numsrcsec; j++) {  
                                     if (form.elements['lti_crssecsrc_'+item][j].checked) {  
                                         if (form.elements['lti_crssecsrc_'+item][j].value == 'other') {  
                                             if (document.getElementById('lti_secsrcfield_'+item)) {  
                                                 document.getElementById('lti_secsrcfield_'+item).style.display = 'inline-block';  
                                                 setsrcvis = 1;  
                                             }  
                                         }  
                                     }  
                                 }  
                                 if (!setsrcvis) {  
                                     if (document.getElementById('lti_secsrcfield_'+item)) {  
                                         document.getElementById('lti_secsrcfield_'+item).style.display = 'none';  
                                     }  
                                 }  
                             }  
                         }  
                     }  
                 }  
             }  
             if (!setvis) {  
                 if (document.getElementById('lti_crssecfield_'+item)) {  
                     document.getElementById('lti_crssecfield_'+item).style.display = 'none';  
                 }  
                 if (document.getElementById('lti_secsrcfield_'+item)) {  
                     document.getElementById('lti_secsrcfield_'+item).style.display = 'none';  
                 }  
             }  
         }  
     } else if (setting == 'lcauth') {  
         var numauth = form.elements['lti_lcauth_'+item].length;  
         if (numauth) {  
             for (var i=0; i<numauth; i++) {  
                 if (form.elements['lti_lcauth_'+item][i].checked) {  
                     if (document.getElementById('lti_'+setting+'_parmrow_'+item)) {  
                         if ((form.elements['lti_'+setting+'_'+item][i].value == 'internal') || (form.elements['lti_'+setting+'_'+item][i].value == 'lti')) {  
                             document.getElementById('lti_'+setting+'_parmrow_'+item).style.display = 'none';  
                         } else {  
                             document.getElementById('lti_'+setting+'_parmrow_'+item).style.display = 'table-row';  
                             if (document.getElementById('lti_'+setting+'_parmtext_'+item)) {  
                                 if (form.elements['lti_'+setting+'_'+item][i].value == 'localauth') {  
                                     document.getElementById('lti_'+setting+'_parmtext_'+item).innerHTML = "$lcauthparmtext{'localauth'}";  
                                 } else {  
                                     document.getElementById('lti_'+setting+'_parmtext_'+item).innerHTML = "$lcauthparmtext{'krb'}";  
                                 }  
                             }  
                         }  
                     }  
                 }  
             }  
         }  
     } else if (setting == 'lcmenu') {  
         var menus = new Array('lti_topmenu_'+item,'lti_inlinemenu_'+item);  
         var divid = 'lti_menufield_'+item;  
         var setvis = '';  
         for (var i=0; i<menus.length; i++) {  
             var radioname = menus[i];  
             var num = form.elements[radioname].length;  
             if (num) {  
                 for (var j=0; j<num; j++) {  
                     if (form.elements[radioname][j].checked) {  
                         if (form.elements[radioname][j].value == '1') {  
                             if (document.getElementById(divid)) {  
                                 document.getElementById(divid).style.display = 'inline-block';  
                             }  
                             setvis = 1;  
                             break;  
                         }  
                     }  
                 }  
             }  
             if (setvis == 1) {  
                 break;  
             }  
         }  
         if (!setvis) {  
             if (document.getElementById(divid)) {  
                 document.getElementById(divid).style.display = 'none';  
             }  
         }  
     }  
     return;  
 }  
   
 // ]]>  
 </script>  
   
 ENDSCRIPT  
 }  
   
 sub autoupdate_javascript {  sub autoupdate_javascript {
     return <<"ENDSCRIPT";      return <<"ENDSCRIPT";
 <script type="text/javascript">  <script type="text/javascript">
Line 3836  sub print_autoupdate { Line 3283  sub print_autoupdate {
                 $updateoff = ' ';                  $updateoff = ' ';
             }              }
         }          }
         $enable = '<tr class="LC_odd_row">'.          $enable = '<tr class="LC_odd_row">'. 
                   '<td>'.$choices{'run'}.'</td>'.                    '<td>'.&mt($choices{'run'}).'</td>'.
                   '<td class="LC_left_item"><span class="LC_nobreak"><label>'.                    '<td class="LC_left_item"><span class="LC_nobreak"><label>'.
                   '<input type="radio" name="autoupdate_run"'.                    '<input type="radio" name="autoupdate_run"'.
                   $updateoff.'value="0" />'.&mt('No').'</label>&nbsp;'.                    $updateoff.'value="0" />'.&mt('No').'</label>&nbsp;'.
Line 4471  sub print_contacts { Line 3918  sub print_contacts {
             my $optionsprefix = 'LC_options_helpdesk_';              my $optionsprefix = 'LC_options_helpdesk_';
   
             my $onclicktypes = "toggleHelpdeskRow(this.form,'overrides','$customclass','$optionsprefix');";              my $onclicktypes = "toggleHelpdeskRow(this.form,'overrides','$customclass','$optionsprefix');";
   
             $datatable .= &insttypes_row($settings,$types,$usertypes,$dom,              $datatable .= &insttypes_row($settings,$types,$usertypes,$dom,
                                          $numinrow,$othertitle,'overrides',                                           $numinrow,$othertitle,'overrides',
                                          \$rownum,$onclicktypes,$customclass);                                           \$rownum,$onclicktypes,$customclass);
Line 4687  sub print_helpsettings { Line 4135  sub print_helpsettings {
             push(@jsarray,('notinc','notexc'));              push(@jsarray,('notinc','notexc'));
         }          }
         my $hiddenstr = join("','",@jsarray);          my $hiddenstr = join("','",@jsarray);
           $datatable .= &helpsettings_javascript(\@roles_by_num,$maxnum,$hiddenstr,$formname);
         my $context = 'domprefs';          my $context = 'domprefs';
         my $crstype = 'Course';          my $crstype = 'Course';
         my $prefix = 'helproles_';          my $prefix = 'helproles_';
Line 5057  sub radiobutton_prefs { Line 4506  sub radiobutton_prefs {
                 $checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').'</label>';                  $checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').'</label>';
         } else {          } else {
             $datatable .=              $datatable .=
                 '<label><input type="radio" name="'.              '<label><input type="radio" name="'.
                 $item.'" '.$checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').              $item.'" '.$checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').
                 '</label>&nbsp;<label><input type="radio" name="'.$item.'" '.              '</label>&nbsp;<label><input type="radio" name="'.$item.'" '.
                 $checkedoff{$item}.' value="0"'.$onclick.' />'.&mt('No').'</label>';              $checkedoff{$item}.' value="0"'.$onclick.' />'.&mt('No').'</label>';
         }          }
         $datatable .= '</span>'.$additional.'</td></tr>';          $datatable .= '</span>'.$additional.'</td></tr>';
         $itemcount ++;          $itemcount ++;
Line 5068  sub radiobutton_prefs { Line 4517  sub radiobutton_prefs {
     return ($datatable,$itemcount);      return ($datatable,$itemcount);
 }  }
   
 sub print_ltitools {  
     my ($position,$dom,$settings,$rowtotal) = @_;  
     my (%rules,%encrypt,%privkeys,%linkprot);  
     if (ref($settings) eq 'HASH') {  
         if ($position eq 'top') {  
             if (exists($settings->{'encrypt'})) {  
                 if (ref($settings->{'encrypt'}) eq 'HASH') {  
                     foreach my $key (keys(%{$settings->{'encrypt'}})) {  
                         $encrypt{'toolsec_'.$key} = $settings->{'encrypt'}{$key};  
                     }  
                 }  
             }  
             if (exists($settings->{'private'})) {  
                 if (ref($settings->{'private'}) eq 'HASH') {  
                     if (ref($settings->{'private'}) eq 'HASH') {  
                         if (ref($settings->{'private'}{'keys'}) eq 'ARRAY') {  
                             map { $privkeys{$_} = 1; } (@{$settings->{'private'}{'keys'}});  
                         }  
                     }  
                 }  
             }  
         } elsif ($position eq 'middle') {  
             if (exists($settings->{'rules'})) {  
                 if (ref($settings->{'rules'}) eq 'HASH') {  
                     %rules = %{$settings->{'rules'}};  
                 }  
             }  
         } else {  
             foreach my $key ('encrypt','private','rules') {  
                 if (exists($settings->{$key})) {  
                     delete($settings->{$key});  
                 }  
             }  
         }  
     }  
     my $datatable;  
     my $itemcount = 1;  
     if ($position eq 'top') {  
         $datatable = &secrets_form($dom,'toolsec',\%encrypt,\%privkeys,$rowtotal);  
     } elsif ($position eq 'middle') {  
         $datatable = &password_rules('toolsecrets',\$itemcount,\%rules);  
         $$rowtotal += $itemcount;  
     } else {  
         $datatable = &Apache::courseprefs::print_ltitools($dom,'',$settings,\$rowtotal,'','','domain');  
     }  
     return $datatable;  
 }  
   
 sub ltitools_names {  
     my %lt = &Apache::lonlocal::texthash(  
                                           'title'          => 'Title',  
                                           'version'        => 'Version',  
                                           'msgtype'        => 'Message Type',  
                                           'sigmethod'      => 'Signature Method',  
                                           'url'            => 'URL',  
                                           'key'            => 'Key',  
                                           'lifetime'       => 'Nonce lifetime (s)',  
                                           'secret'         => 'Secret',  
                                           'icon'           => 'Icon',  
                                           'user'           => 'User',  
                                           'fullname'       => 'Full Name',  
                                           'firstname'      => 'First Name',  
                                           'lastname'       => 'Last Name',  
                                           'email'          => 'E-mail',  
                                           'roles'          => 'Role',  
                                           'window'         => 'Window',  
                                           'tab'            => 'Tab',  
                                           'iframe'         => 'iFrame',  
                                           'height'         => 'Height',  
                                           'width'          => 'Width',  
                                           'linktext'       => 'Default Link Text',  
                                           'explanation'    => 'Default Explanation',  
                                           'passback'       => 'Tool can return grades:',  
                                           'roster'         => 'Tool can retrieve roster:',  
                                           'crstarget'      => 'Display target',  
                                           'crslabel'       => 'Course label',  
                                           'crstitle'       => 'Course title',  
                                           'crslinktext'    => 'Link Text',  
                                           'crsexplanation' => 'Explanation',  
                                           'crsappend'      => 'Provider URL',  
                                         );  
     return %lt;  
 }  
   
 sub secrets_form {  
     my ($dom,$context,$encrypt,$privkeys,$rowtotal) = @_;  
     my @ids=&Apache::lonnet::current_machine_ids();  
     my %servers = &Apache::lonnet::get_servers($dom,'library');  
     my $primary = &Apache::lonnet::domain($dom,'primary');  
     my ($css_class,$extra,$numshown,$itemcount,$output);  
     $itemcount = 0;  
     foreach my $hostid (sort(keys(%servers))) {  
         my ($showextra,$divsty,$switch);  
         if ($hostid eq $primary) {  
             if ($context eq 'ltisec') {  
                 if (($encrypt->{'ltisec_consumers'}) || ($encrypt->{'ltisec_domlinkprot'})) {  
                     $showextra = 1;  
                 }  
                 if ($encrypt->{'ltisec_crslinkprot'}) {  
                     $showextra = 1;  
                 }  
             } else {  
                 if (($encrypt->{'toolsec_crs'}) || ($encrypt->{'toolsec_dom'})) {  
                     $showextra = 1;  
                 }  
             }  
             unless (grep(/^\Q$hostid\E$/,@ids)) {  
                 $switch = 1;  
             }  
             if ($showextra) {  
                 $numshown ++;  
                 $divsty = 'display:inline-block';  
             } else {  
                 $divsty = 'display:none';  
             }  
             $extra .= '<fieldset id="'.$context.'_info_'.$hostid.'" style="'.$divsty.'">'.  
                       '<legend>'.$hostid.'</legend>';  
             if ($switch) {  
                 my $switchserver = '<a href="/adm/switchserver?otherserver='.$hostid.'&amp;role='.  
                                    &HTML::Entities::encode($env{'request.role'},'\'<>"&').  
                                    '&amp;destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';  
                 if (exists($privkeys->{$hostid})) {  
                     $extra .= '<div id="'.$context.'_divcurrprivkey_'.$hostid.'" style="display:inline-block" />'.  
                               '<span class="LC_nobreak">'.  
                               &mt('Encryption Key').': ['.&mt('not shown').'] '.('&nbsp;'x2).'</span></div>'.  
                               '<span class="LC_nobreak">'.&mt('Change?').  
                               '<label><input type="radio" value="0" name="'.$context.'_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$context','$hostid'".');" checked="checked" />'.&mt('No').'</label>'.  
                               ('&nbsp;'x2).  
                               '<label><input type="radio" value="1" name="'.$context.'_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$context','$hostid'".');" />'.&mt('Yes').  
                               '</label>&nbsp;&nbsp;</span><div id="'.$context.'_divchgprivkey_'.$hostid.'" style="display:none" />'.  
                               '<span class="LC_nobreak"> - '.&mt('submit from server ([_1]): [_2].',$hostid,$switchserver).  
                               '</span></div>';  
                 } else {  
                     $extra .= '<span class="LC_nobreak">'.  
                               &mt('Key required').' - '.&mt('submit from server ([_1]): [_2].',$hostid,$switchserver).  
                               '</span>'."\n";  
                 }  
             } elsif (exists($privkeys->{$hostid})) {  
                 $extra .= '<div id="'.$context.'_divcurrprivkey_'.$hostid.'" style="display:inline-block" /><span class="LC_nobreak">'.  
                           &mt('Encryption Key').': ['.&mt('not shown').'] '.('&nbsp;'x2).'</span></div>'.  
                           '<span class="LC_nobreak">'.&mt('Change?').  
                           '<label><input type="radio" value="0" name="'.$context.'_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$context','$hostid'".');" checked="checked" />'.&mt('No').'</label>'.  
                           ('&nbsp;'x2).  
                           '<label><input type="radio" value="1" name="'.$context.'_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$context','$hostid'".');" />'.&mt('Yes').  
                           '</label>&nbsp;&nbsp;</span><div id="'.$context.'_divchgprivkey_'.$hostid.'" style="display:none" />'.  
                           '<span class="LC_nobreak">'.&mt('New Key').':'.  
                           '<input type="password" size="20" name="'.$context.'_privkey_'.$hostid.'" value="" autocomplete="new-password" />'.  
                           '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.'.$context.'_privkey_'.$hostid.'.type='."'text'".' } else { this.form.'.$context.'_privkey_'.$hostid.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'.  
                           '</span></div>';  
             } else {  
                 $extra .= '<span class="LC_nobreak">'.&mt('Encryption Key').':'.  
                           '<input type="password" size="20" name="'.$context.'_privkey_'.$hostid.'" value="" autocomplete="new-password" />'.  
                           '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.'.$context.'_privkey_'.$hostid.'.type='."'text'".' } else { this.form.'.$context.'_privkey_'.$hostid.'.type='."'password'".' }" />'.&mt('Visible input').'</label>';  
             }  
             $extra .= '</fieldset>';  
         }  
     }  
     my (%choices,@toggles,%defaultchecked);  
     if ($context eq 'ltisec') {  
         %choices = &Apache::lonlocal::texthash (  
                                                   ltisec_crslinkprot => 'Encrypt stored link protection secrets defined in courses',  
                                                   ltisec_domlinkprot => 'Encrypt stored link protection secrets defined in domain',  
                                                   ltisec_consumers   => 'Encrypt stored consumer secrets defined in domain',  
                                                );  
         @toggles = qw(ltisec_crslinkprot ltisec_domlinkprot ltisec_consumers);  
         %defaultchecked = (  
                            'ltisec_crslinkprot' => 'off',  
                            'ltisec_domlinkprot' => 'off',  
                            'ltisec_consumers'   => 'off',  
                           );  
     } else {  
         %choices = &Apache::lonlocal::texthash (  
                                                   toolsec_crs => 'Encrypt stored external tool secrets defined in courses',  
                                                   toolsec_dom => 'Encrypt stored external tool secrets defined in domain',  
                                                );  
         @toggles = qw(toolsec_crs toolsec_dom);  
         %defaultchecked = (  
                            'toolsec_crs' => 'off',  
                            'toolsec_dom' => 'off',  
                           );  
     }  
     my ($onclick,$itemcount);  
     $onclick = 'javascript:toggleLTIEncKey(this.form,'."'$context'".');';  
     ($output,$itemcount) = &radiobutton_prefs($encrypt,\@toggles,\%defaultchecked,  
                                               \%choices,$itemcount,$onclick,'','left','no');  
   
     $css_class = $itemcount%2?' class="LC_odd_row"':'';  
     my $noprivkeysty = 'display:inline-block';  
     if ($numshown) {  
         $noprivkeysty = 'display:none';  
     }  
     $output .= '<tr '.$css_class.'><td><span class="LC_nobreak">'.&mt('Encryption Key(s)').'</td>'.  
                '<td><div id="'.$context.'_noprivkey" style="'.$noprivkeysty.'" >'.  
                '<span class="LC_nobreak">'.&mt('Not in use').'</span></div>'.  
                $extra.  
                '</td></tr>';  
     $itemcount ++;  
     $$rowtotal += $itemcount;  
     return $output;  
 }  
   
 sub print_lti {  
     my ($position,$dom,$settings,$rowtotal) = @_;  
     my $itemcount = 1;  
     my ($datatable,$css_class);  
     my (%rules,%encrypt,%privkeys,%linkprot);  
     if (ref($settings) eq 'HASH') {  
         if ($position eq 'top') {  
             if (exists($settings->{'encrypt'})) {  
                 if (ref($settings->{'encrypt'}) eq 'HASH') {  
                     foreach my $key (keys(%{$settings->{'encrypt'}})) {  
                         if ($key eq 'consumers') {  
                             $encrypt{'ltisec_'.$key} = $settings->{'encrypt'}{$key};  
                         } else {  
                             $encrypt{'ltisec_'.$key.'linkprot'} = $settings->{'encrypt'}{$key};  
                         }  
                     }  
                 }  
             }  
             if (exists($settings->{'private'})) {  
                 if (ref($settings->{'private'}) eq 'HASH') {  
                     if (ref($settings->{'private'}) eq 'HASH') {  
                         if (ref($settings->{'private'}{'keys'}) eq 'ARRAY') {  
                             map { $privkeys{$_} = 1; } (@{$settings->{'private'}{'keys'}});  
                         }  
                     }  
                 }  
             }  
         } elsif ($position eq 'middle') {  
             if (exists($settings->{'rules'})) {  
                 if (ref($settings->{'rules'}) eq 'HASH') {  
                     %rules = %{$settings->{'rules'}};  
                 }  
             }  
         } elsif ($position eq 'lower') {  
             if (exists($settings->{'linkprot'})) {  
                 if (ref($settings->{'linkprot'}) eq 'HASH') {  
                     %linkprot = %{$settings->{'linkprot'}};  
                     if ($linkprot{'lock'}) {  
                         delete($linkprot{'lock'});  
                     }  
                 }  
             }  
         } else {  
             foreach my $key ('encrypt','private','rules','linkprot') {  
                 if (exists($settings->{$key})) {  
                     delete($settings->{$key});  
                 }  
             }  
         }  
     }  
     if ($position eq 'top') {  
         $datatable = &secrets_form($dom,'ltisec',\%encrypt,\%privkeys,$rowtotal);  
     } elsif ($position eq 'middle') {  
         $datatable = &password_rules('ltisecrets',\$itemcount,\%rules);  
         $$rowtotal += $itemcount;  
     } elsif ($position eq 'lower') {  
          $datatable .= &Apache::courseprefs::print_linkprotection($dom,'',$settings,$rowtotal,'','','domain');  
     } else {  
         my ($switchserver,$switchmessage);  
         $switchserver = &check_switchserver($dom);  
         $switchmessage = &mt("submit from domain's primary library server: [_1].",$switchserver);  
         my $maxnum = 0;  
         my %ordered;  
         if (ref($settings) eq 'HASH') {  
             foreach my $item (keys(%{$settings})) {  
                 if (ref($settings->{$item}) eq 'HASH') {  
                     my $num = $settings->{$item}{'order'};  
                     if ($num eq '') {  
                         $num = scalar(keys(%{$settings}));  
                     }  
                     $ordered{$num} = $item;  
                 }  
             }  
         }  
         $maxnum = scalar(keys(%ordered));  
         my %lt = &lti_names();  
         if (keys(%ordered)) {  
             my @items = sort { $a <=> $b } keys(%ordered);  
             for (my $i=0; $i<@items; $i++) {  
                 $css_class = $itemcount%2?' class="LC_odd_row"':'';  
                 my $item = $ordered{$items[$i]};  
                 my ($key,$secret,$usable,$lifetime,$consumer,$requser,$crsinc,$current);  
                 if (ref($settings->{$item}) eq 'HASH') {  
                     $key = $settings->{$item}->{'key'};  
                     $usable = $settings->{$item}->{'usable'};  
                     $lifetime = $settings->{$item}->{'lifetime'};  
                     $consumer = $settings->{$item}->{'consumer'};  
                     $requser = $settings->{$item}->{'requser'};  
                     $crsinc = $settings->{$item}->{'crsinc'};  
                     $current = $settings->{$item};  
                 }  
                 my $onclickrequser = ' onclick="toggleLTI(this.form,'."'requser','$i'".');"';  
                 my %checkedrequser = (  
                                        yes => ' checked="checked"',  
                                        no  => '',  
                                      );  
                 if (!$requser) {  
                     $checkedrequser{'no'} = $checkedrequser{'yes'};  
                     $checkedrequser{'yes'} = '';  
                 }  
                 my $onclickcrsinc = ' onclick="toggleLTI(this.form,'."'crsinc','$i'".');"';  
                 my %checkedcrsinc = (  
                                       yes => ' checked="checked"',  
                                       no  => '',  
                                     );  
                 if (!$crsinc) {  
                     $checkedcrsinc{'no'} = $checkedcrsinc{'yes'};  
                     $checkedcrsinc{'yes'} = '';  
                 }  
                 my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_".$item."'".');"';  
                 $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'  
                              .'<select name="lti_pos_'.$item.'"'.$chgstr.'>';  
                 for (my $k=0; $k<=$maxnum; $k++) {  
                     my $vpos = $k+1;  
                     my $selstr;  
                     if ($k == $i) {  
                         $selstr = ' selected="selected" ';  
                     }  
                     $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';  
                 }  
                 $datatable .= '</select>'.('&nbsp;'x2).  
                     '<label><input type="checkbox" name="lti_del" value="'.$item.'" />'.  
                     &mt('Delete?').'</label></span></td>'.  
                     '<td colspan="2">'.  
                     '<fieldset><legend>'.&mt('Required settings').'</legend>'.  
                     '<span class="LC_nobreak">'.$lt{'consumer'}.  
                     ':<input type="text" size="15" name="lti_consumer_'.$i.'" value="'.$consumer.'" /></span> '.  
                     ('&nbsp;'x2).  
                     '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_'.$i.'">'.  
                     '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '.  
                     ('&nbsp;'x2).  
                     '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" name="lti_lifetime_'.$i.'"'.  
                     'value="'.$lifetime.'" size="3" /></span><br /><br />';  
                 if ($key ne '') {  
                     $datatable .= '<span class="LC_nobreak">'.$lt{'key'};  
                     if ($switchserver) {  
                         $datatable .= ': ['.&mt('[_1] to view/edit',$switchserver).']';  
                     } else {  
                         $datatable .= ':<input type="text" size="25" name="lti_key_'.$i.'" value="'.$key.'" autocomplete="off" />';  
                     }  
                     $datatable .= '</span> '.('&nbsp;'x2);  
                 } elsif (!$switchserver) {  
                     $datatable .= '<span class="LC_nobreak">'.$lt{'key'}.':'.  
                                   '<input type="text" size="25" name="lti_key_'.$i.'" value="'.$key.'" autocomplete="off" />'.  
                                   '</span> '.('&nbsp;'x2);  
                 }  
                 if ($switchserver) {  
                     if ($usable ne '') {  
                         $datatable .= '<div id="lti_divcurrsecret_'.$i.'" style="display:inline-block" /><span class="LC_nobreak">'.  
                                       $lt{'secret'}.': ['.&mt('not shown').'] '.('&nbsp;'x2).'</span></div>'.  
                                       '<span class="LC_nobreak">'.&mt('Change secret?').  
                                       '<label><input type="radio" value="0" name="lti_changesecret_'.$i.'" onclick="javascript:toggleChgSecret(this.form,'."'$i','secret','lti'".');" checked="checked" />'.&mt('No').'</label>'.  
                                       ('&nbsp;'x2).  
                                      '<label><input type="radio" value="1" name="lti_changesecret_'.$i.'" onclick="javascript:toggleChgSecret(this.form,'."'$i','secret','lti'".');" />'.&mt('Yes').'</label>'.('&nbsp;'x2).  
                                       '</span><div id="lti_divchgsecret_'.$i.'" style="display:none" />'.  
                                       '<span class="LC_nobreak"> - '.$switchmessage.'</span>'.  
                                       '</div>';  
                     } elsif ($key eq '') {  
                         $datatable .= '<span class="LC_nobreak">'.&mt('Key and Secret are required').' - '.$switchmessage.'</span>'."\n";  
                     } else {  
                         $datatable .= '<span class="LC_nobreak">'.&mt('Secret required').' - '.$switchmessage.'</span>'."\n";  
                     }  
                 } else {  
                     if ($usable ne '') {  
                         $datatable .= '<div id="lti_divcurrsecret_'.$i.'" style="display:inline-block" /><span class="LC_nobreak">'.  
                                       $lt{'secret'}.': ['.&mt('not shown').'] '.('&nbsp;'x2).'</span></div>'.  
                                       '<span class="LC_nobreak">'.&mt('Change?').  
                                       '<label><input type="radio" value="0" name="lti_changesecret_'.$i.'" onclick="javascript:toggleChgSecret(this.form,'."'$i','secret','lti'".');" checked="checked" />'.&mt('No').'</label>'.  
                                       ('&nbsp;'x2).  
                                       '<label><input type="radio" value="1" name="lti_changesecret_'.$i.'" onclick="javascript:toggleChgSecret(this.form,'."'$i','secret','lti'".');" />'.&mt('Yes').  
                                       '</label>&nbsp;&nbsp;</span><div id="lti_divchgsecret_'.$i.'" style="display:none" />'.  
                                       '<span class="LC_nobreak">'.&mt('New Secret').':'.  
                                       '<input type="password" size="20" name="lti_secret_'.$i.'" value="" autocomplete="new-password" />'.  
                                       '<label><input type="checkbox" name="lti_visible_'.$i.'" id="lti_visible_'.$i.'" onclick="if (this.checked) { this.form.lti_secret_'.$i.'.type='."'text'".' } else { this.form.lti_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label></span></div>';  
                     } else {  
                         $datatable .=  
                             '<span class="LC_nobreak">'.$lt{'secret'}.':'.  
                             '<input type="password" size="20" name="lti_secret_'.$i.'" value="" autocomplete="new-password" />'.  
                             '<label><input type="checkbox" name="lti_visible_'.$i.'" id="lti_visible_'.$i.'" onclick="if (this.checked) { this.form.lti_secret_'.$i.'.type='."'text'".' } else { this.form.lti_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label>';  
                     }  
                 }  
                 $datatable .= '<br /><br />'.  
                     '<span class="LC_nobreak">'.$lt{'requser'}.':'.  
                     '<label><input type="radio" name="lti_requser_'.$i.'" value="1"'.$onclickrequser.$checkedrequser{yes}.' />'.&mt('Yes').'</label>&nbsp;'."\n".  
                     '<label><input type="radio" name="lti_requser_'.$i.'" value="0"'.$onclickrequser.$checkedrequser{no}.' />'.&mt('No').'</label></span>'."\n".  
                     '<br /><br />'.  
                     '<span class="LC_nobreak">'.$lt{'crsinc'}.':'.  
                     '<label><input type="radio" name="lti_crsinc_'.$i.'" value="1"'.$onclickcrsinc.$checkedcrsinc{yes}.' />'.&mt('Yes').'</label>&nbsp;'."\n".  
                     '<label><input type="radio" name="lti_crsinc_'.$i.'" value="0"'.$onclickcrsinc.$checkedcrsinc{no}.' />'.&mt('No').'</label></span>'."\n".  
                     ('&nbsp;'x4).  
                     '<input type="hidden" name="lti_id_'.$i.'" value="'.$item.'" /></span>'.  
                     '</fieldset>'.&lti_options($i,$current,$itemcount,%lt).'</td></tr>';  
                 $itemcount ++;  
             }  
         }  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_add'".');"';  
         $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".  
                       '<input type="hidden" name="lti_maxnum" value="'.$maxnum.'" />'."\n".  
                       '<select name="lti_pos_add"'.$chgstr.'>';  
         for (my $k=0; $k<$maxnum+1; $k++) {  
             my $vpos = $k+1;  
             my $selstr;  
             if ($k == $maxnum) {  
                 $selstr = ' selected="selected" ';  
             }  
             $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';  
         }  
         $datatable .= '</select>&nbsp;'."\n".  
                       '<input type="checkbox" name="lti_add" value="1" />'.&mt('Add').'</span></td>'."\n".  
                       '<td colspan="2">'.  
                       '<fieldset><legend>'.&mt('Required settings').'</legend>'.  
                       '<span class="LC_nobreak">'.$lt{'consumer'}.  
                       ':<input type="text" size="15" name="lti_consumer_add" value="" /></span> '."\n".  
                       ('&nbsp;'x2).  
                       '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_add">'.  
                       '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n".  
                       ('&nbsp;'x2).  
                       '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="3" name="lti_lifetime_add" value="300" /></span><br /><br />'."\n";  
         if ($switchserver) {  
             $datatable .= '<span class="LC_nobreak">'.&mt('Key and Secret are required').' - '.$switchmessage.'</span>'."\n";  
         } else {  
             $datatable .= '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="lti_key_add" value="" autocomplete="off" /></span> '."\n".  
                           ('&nbsp;'x2).  
                           '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="lti_secret_add" value="" autocomplete="new-password" />'.  
                           '<label><input type="checkbox" name="lti_add_visible" id="lti_add_visible" onclick="if (this.checked) { this.form.lti_secret_add.type='."'text'".' } else { this.form.lti_secret_add.type='."'password'".' }" />'.&mt('Visible input').'</label></span> '."\n";  
         }  
         $datatable .= '<br /><br />'.  
                       '<span class="LC_nobreak">'.$lt{'requser'}.':'.  
                       '<label><input type="radio" name="lti_requser_add" value="1" onclick="toggleLTI(this.form,'."'requser','add'".');" checked="checked" />'.&mt('Yes').'</label>&nbsp;'."\n".  
                       '<label><input type="radio" name="lti_requser_add" value="0" onclick="toggleLTI(this.form,'."'requser','add'".');" />'.&mt('No').'</label></span>'."\n".  
                       '<br /><br />'.  
                       '<span class="LC_nobreak">'.$lt{'crsinc'}.':'.  
                       '<label><input type="radio" name="lti_crsinc_add" value="1" onclick="toggleLTI(this.form,'."'crsinc','add'".');" checked="checked" />'.&mt('Yes').'</label>&nbsp;'."\n".  
                       '<label><input type="radio" name="lti_crsinc_add" value="0" onclick="toggleLTI(this.form,'."'crsinc','add'".');" />'.&mt('No').'</label></span>'."\n".  
                       '</fieldset>'.&lti_options('add',undef,$itemcount,%lt).  
                       '</td>'."\n".  
                       '</tr>'."\n";  
         $itemcount ++;  
     }  
     $$rowtotal += $itemcount;  
     return $datatable;  
 }  
   
 sub lti_names {  
     my %lt = &Apache::lonlocal::texthash(  
                                           'version'   => 'LTI Version',  
                                           'url'       => 'URL',  
                                           'key'       => 'Key',  
                                           'lifetime'  => 'Nonce lifetime (s)',  
                                           'consumer'  => 'Consumer',  
                                           'secret'    => 'Secret',  
                                           'requser'   => "User's identity sent",  
                                           'crsinc'    => "Course's identity sent",  
                                           'email'     => 'Email address',  
                                           'sourcedid' => 'User ID',  
                                           'other'     => 'Other',  
                                           'passback'  => 'Can return grades to Consumer:',  
                                           'roster'    => 'Can retrieve roster from Consumer:',  
                                           'topmenu'   => 'Display LON-CAPA page header',  
                                           'inlinemenu'=> 'Display LON-CAPA inline menu',  
                                         );  
     return %lt;  
 }  
   
 sub lti_options {  
     my ($num,$current,$itemcount,%lt) = @_;  
     my (%checked,%rolemaps,$crssecsrc,$userfield,$cidfield,$callback);  
     $checked{'mapuser'}{'sourcedid'} = ' checked="checked"';  
     $checked{'mapcrs'}{'course_offering_sourcedid'} = ' checked="checked"';  
     $checked{'storecrs'}{'Y'} = ' checked="checked"';  
     $checked{'makecrs'}{'N'} = ' checked="checked"';  
     $checked{'mapcrstype'} = {};  
     $checked{'makeuser'} = {};  
     $checked{'selfenroll'} = {};  
     $checked{'crssec'} = {};  
     $checked{'crssecsrc'} = {};  
     $checked{'lcauth'} = {};  
     $checked{'menuitem'} = {};  
     if ($num eq 'add') {  
         $checked{'lcauth'}{'lti'} = ' checked="checked"';  
     }  
     my $userfieldsty = 'none';  
     my $crsfieldsty = 'none';  
     my $crssecfieldsty = 'none';  
     my $secsrcfieldsty = 'none';  
     my $callbacksty = 'none';  
     my $passbacksty = 'none';  
     my $optionsty = 'block';  
     my $crssty = 'block';  
     my $lcauthparm;  
     my $lcauthparmstyle = 'display:none';  
     my $lcauthparmtext;  
     my $menusty;  
     my $numinrow = 4;  
     my %menutitles = &ltimenu_titles();  
   
     if (ref($current) eq 'HASH') {  
         if (!$current->{'requser'}) {  
             $optionsty = 'none';  
             $crssty = 'none';  
         } elsif (!$current->{'crsinc'}) {  
             $crssty = 'none';  
         }  
         if (($current->{'mapuser'} ne '') && ($current->{'mapuser'} ne 'lis_person_sourcedid')) {  
             $checked{'mapuser'}{'sourcedid'} = '';  
             if ($current->{'mapuser'} eq 'lis_person_contact_email_primary') {  
                 $checked{'mapuser'}{'email'} = ' checked="checked"';  
             } else {  
                 $checked{'mapuser'}{'other'} = ' checked="checked"';  
                 $userfield = $current->{'mapuser'};  
                 $userfieldsty = 'inline-block';  
             }  
         }  
         if (($current->{'mapcrs'} ne '') && ($current->{'mapcrs'} ne 'course_offering_sourcedid')) {  
             $checked{'mapcrs'}{'course_offering_sourcedid'} = '';  
             if ($current->{'mapcrs'} eq 'context_id') {  
                 $checked{'mapcrs'}{'context_id'} = ' checked="checked"';  
             } else {  
                 $checked{'mapcrs'}{'other'} = ' checked="checked"';  
                 $cidfield = $current->{'mapcrs'};  
                 $crsfieldsty = 'inline-block';  
             }  
         }  
         if (ref($current->{'mapcrstype'}) eq 'ARRAY') {  
             foreach my $type (@{$current->{'mapcrstype'}}) {  
                 $checked{'mapcrstype'}{$type} = ' checked="checked"';  
             }  
         }  
         if (!$current->{'storecrs'}) {  
             $checked{'storecrs'}{'N'} = $checked{'storecrs'}{'Y'};  
             $checked{'storecrs'}{'Y'} = '';  
         }  
         if ($current->{'makecrs'}) {  
             $checked{'makecrs'}{'Y'} = '  checked="checked"';  
         }  
         if (ref($current->{'makeuser'}) eq 'ARRAY') {  
             foreach my $role (@{$current->{'makeuser'}}) {  
                 $checked{'makeuser'}{$role} = ' checked="checked"';  
             }  
         }  
         if ($current->{'lcauth'} =~ /^(internal|localauth|krb4|krb5|lti)$/) {  
             $checked{'lcauth'}{$1} = ' checked="checked"';  
             unless (($current->{'lcauth'} eq 'lti') || ($current->{'lcauth'} eq 'internal')) {  
                 $lcauthparm = $current->{'lcauthparm'};  
                 $lcauthparmstyle = 'display:table-row';  
                 if ($current->{'lcauth'} eq 'localauth') {  
                     $lcauthparmtext = &mt('Local auth argument');  
                 } else {  
                     $lcauthparmtext = &mt('Kerberos domain');  
                 }  
             }  
         }  
         if (ref($current->{'selfenroll'}) eq 'ARRAY') {  
             foreach my $role (@{$current->{'selfenroll'}}) {  
                 $checked{'selfenroll'}{$role} = ' checked="checked"';  
             }  
         }  
         if (ref($current->{'maproles'}) eq 'HASH') {  
             %rolemaps = %{$current->{'maproles'}};  
         }  
         if ($current->{'section'} ne '') {  
             $checked{'crssec'}{'Y'} = '  checked="checked"';  
             $crssecfieldsty = 'inline-block';  
             if ($current->{'section'} eq 'course_section_sourcedid') {  
                 $checked{'crssecsrc'}{'sourcedid'} = ' checked="checked"';  
             } else {  
                 $checked{'crssecsrc'}{'other'} = ' checked="checked"';  
                 $crssecsrc = $current->{'section'};  
                 $secsrcfieldsty = 'inline-block';  
             }  
         } else {  
             $checked{'crssec'}{'N'} = ' checked="checked"';  
         }  
         if ($current->{'callback'} ne '') {  
             $callback = $current->{'callback'};  
             $checked{'callback'}{'Y'} = ' checked="checked"';  
             $callbacksty = 'inline-block';  
         } else {  
             $checked{'callback'}{'N'} = ' checked="checked"';  
         }  
         if ($current->{'topmenu'}) {  
             $checked{'topmenu'}{'Y'} = ' checked="checked"';  
         } else {  
             $checked{'topmenu'}{'N'} = ' checked="checked"';  
         }  
         if ($current->{'inlinemenu'}) {  
             $checked{'inlinemenu'}{'Y'} = ' checked="checked"';  
         } else {  
             $checked{'inlinemenu'}{'N'} = ' checked="checked"';  
         }  
         if (($current->{'topmenu'}) || ($current->{'inlinemenu'})) {  
             $menusty = 'inline-block';  
             if (ref($current->{'lcmenu'}) eq 'ARRAY') {  
                 foreach my $item (@{$current->{'lcmenu'}}) {  
                     if (exists($menutitles{$item})) {  
                         $checked{'menuitem'}{$item} = ' checked="checked"';  
                     }  
                 }  
             }  
         } else {  
             $menusty = 'none';  
         }  
     } else {  
         $checked{'makecrs'}{'N'} = ' checked="checked"';  
         $checked{'crssec'}{'N'} = ' checked="checked"';  
         $checked{'callback'}{'N'} = ' checked="checked"';  
         $checked{'topmenu'}{'N'} = ' checked="checked"';  
         $checked{'inlinemenu'}{'Y'} = ' checked="checked"';  
         $checked{'menuitem'}{'grades'} = ' checked="checked"';  
         $menusty = 'inline-block';  
     }  
     my @coursetypes = ('official','unofficial','community','textbook','lti');  
     my %coursetypetitles = &Apache::lonlocal::texthash (  
                                official   => 'Official',  
                                unofficial => 'Unofficial',  
                                community  => 'Community',  
                                textbook   => 'Textbook',  
                                lti        => 'LTI Provider',  
     );  
     my @authtypes = ('internal','krb4','krb5','localauth');  
     my %shortauth = (  
                      internal => 'int',  
                      krb4 => 'krb4',  
                      krb5 => 'krb5',  
                      localauth  => 'loc'  
                     );  
     my %authnames = &authtype_names();  
     my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator);  
     my @lticourseroles = qw(Learner Instructor TeachingAssistant Mentor);  
     my @courseroles = ('cc','in','ta','ep','st');  
     my $onclickuser = ' onclick="toggleLTI(this.form,'."'user','$num'".');"';  
     my $onclickcrs = ' onclick="toggleLTI(this.form,'."'crs','$num'".');"';  
     my $onclicksec = ' onclick="toggleLTI(this.form,'."'sec','$num'".');"';  
     my $onclickcallback = ' onclick="toggleLTI(this.form,'."'callback','$num'".');"';  
     my $onclicksecsrc = ' onclick="toggleLTI(this.form,'."'secsrc','$num'".')"';  
     my $onclicklcauth = ' onclick="toggleLTI(this.form,'."'lcauth','$num'".')"';  
     my $onclickmenu = ' onclick="toggleLTI(this.form,'."'lcmenu','$num'".');"';  
     my $output = '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Logout options').'</legend>'.  
                  '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('Callback to logout LON-CAPA on log out from Consumer').':&nbsp;'.  
                  '<label><input type="radio" name="lti_callback_'.$num.'" value="0"'.  
                  $checked{'callback'}{'N'}.$onclickcallback.' />'.&mt('No').'</label>'.('&nbsp;'x2).  
                  '<label><input type="radio" name="lti_callback_'.$num.'" value="1"'.  
                  $checked{'callback'}{'Y'}.$onclickcallback.' />'.&mt('Yes').'</label></span></div>'.  
                  '<div class="LC_floatleft" style="display:'.$callbacksty.';" id="lti_callbackfield_'.$num.'">'.  
                  '<span class="LC_nobreak">'.&mt('Parameter').': '.  
                  '<input type="text" name="lti_callbackparam_'.$num.'" value="'.$callback.'" /></span>'.  
                  '</div><div style="padding:0;clear:both;margin:0;border:0"></div></fieldset>'.  
                  '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Mapping users').'</legend>'.  
                  '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('LON-CAPA username').':&nbsp;';  
     foreach my $option ('sourcedid','email','other') {  
         $output .= '<label><input type="radio" name="lti_mapuser_'.$num.'" value="'.$option.'"'.  
                    $checked{'mapuser'}{$option}.$onclickuser.' />'.$lt{$option}.'</label>'.  
                    ($option eq 'other' ? '' : ('&nbsp;'x2) );  
     }  
     $output .= '</span></div>'.  
                '<div class="LC_floatleft" style="display:'.$userfieldsty.';" id="lti_userfield_'.$num.'">'.  
                '<input type="text" name="lti_customuser_'.$num.'" '.  
                'value="'.$userfield.'" /></div></fieldset>'.  
                '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Roles which may create user accounts').'</legend>';  
     foreach my $ltirole (@ltiroles) {  
         $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="lti_makeuser_'.$num.'" value="'.$ltirole.'"'.  
                    $checked{'makeuser'}{$ltirole}.' />'.$ltirole.'</label>&nbsp;</span> ';  
     }  
     $output .= '</fieldset>'.  
                '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('New user accounts created for LTI users').'</legend>'.  
                '<table>'.  
                &modifiable_userdata_row('lti','instdata_'.$num,$current,$numinrow,$itemcount).  
                '</table>'.  
                '<table class="LC_nested"><tr><td class="LC_left_item">LON-CAPA Authentication</td>'.  
                '<td class="LC_left_item">';  
     foreach my $auth ('lti',@authtypes) {  
         my $authtext;  
         if ($auth eq 'lti') {  
             $authtext = &mt('None');  
         } else {  
             $authtext = $authnames{$shortauth{$auth}};  
         }  
         $output .= '<span class="LC_nobreak"><label><input type="radio" name="lti_lcauth_'.$num.  
                    '" value="'.$auth.'"'.$checked{'lcauth'}{$auth}.$onclicklcauth.' />'.  
                    $authtext.'</label></span> &nbsp;';  
     }  
     $output .= '</td></tr>'.  
                '<tr id="lti_lcauth_parmrow_'.$num.'" style="'.$lcauthparmstyle.'">'.  
                '<td class="LC_right_item" colspan="2"><span class="LC_nobreak">'.  
                '<span id="lti_lcauth_parmtext_'.$num.'">'.$lcauthparmtext.'</span>'.  
                '<input type="text" name="lti_lcauthparm_'.$num.'" value="" /></span></td></tr>'.  
                '</table></fieldset>'.  
                '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.  
                &mt('LON-CAPA menu items (Course Coordinator can override)').'</legend>'.  
                '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'topmenu'}.':&nbsp;'.  
                '<label><input type="radio" name="lti_topmenu_'.$num.'" value="0"'.  
                $checked{'topmenu'}{'N'}.$onclickmenu.' />'.&mt('No').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_topmenu_'.$num.'" value="1"'.  
                $checked{'topmenu'}{'Y'}.$onclickmenu.' />'.&mt('Yes').'</label></span></div>'.  
                '<div style="padding:0;clear:both;margin:0;border:0"></div>'.  
                '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'inlinemenu'}.':&nbsp;'.  
                '<label><input type="radio" name="lti_inlinemenu_'.$num.'" value="0"'.  
                $checked{'inlinemenu'}{'N'}.$onclickmenu.' />'.&mt('No').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_inlinemenu_'.$num.'" value="1"'.  
                $checked{'inlinemenu'}{'Y'}.$onclickmenu.' />'.&mt('Yes').'</label></span></div>';  
      $output .='<div style="padding:0;clear:both;margin:0;border:0"></div>'.  
                '<div class="LC_floatleft" style="display:'.$menusty.';" id="lti_menufield_'.$num.'">'.  
                '<span class="LC_nobreak">'.&mt('Menu items').':&nbsp;';  
     foreach my $type ('fullname','coursetitle','role','logout','grades') {  
         $output .= '<label><input type="checkbox" name="lti_menuitem_'.$num.'" value="'.$type.'"'.  
                    $checked{'menuitem'}{$type}.' />'.$menutitles{$type}.'</label>'.  
                    ('&nbsp;'x2);  
     }  
     $output .= '</span></div></fieldset>'.  
                '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Mapping courses').'</legend>'.  
                '<div class="LC_floatleft"><span class="LC_nobreak">'.  
                &mt('Unique course identifier').':&nbsp;';  
     foreach my $option ('course_offering_sourcedid','context_id','other') {  
         $output .= '<label><input type="radio" name="lti_mapcrs_'.$num.'" value="'.$option.'"'.  
                    $checked{'mapcrs'}{$option}.$onclickcrs.' />'.$option.'</label>'.  
                    ($option eq 'other' ? '' : ('&nbsp;'x2) );  
     }  
     $output .= '</span></div><div class="LC_floatleft" style="display:'.$crsfieldsty.';" id="lti_crsfield_'.$num.'">'.  
                '<input type="text" name="lti_mapcrsfield_'.$num.'" value="'.$cidfield.'" />'.  
                '</div><div style="padding:0;clear:both;margin:0;border:0"></div>'.  
                '<span class="LC_nobreak">'.&mt('LON-CAPA course type(s)').':&nbsp;';  
     foreach my $type (@coursetypes) {  
         $output .= '<label><input type="checkbox" name="lti_mapcrstype_'.$num.'" value="'.$type.'"'.  
                    $checked{'mapcrstype'}{$type}.' />'.$coursetypetitles{$type}.'</label>'.  
                    ('&nbsp;'x2);  
     }  
     $output .= '</span><br /><br />'.  
                '<span class="LC_nobreak">'.&mt('Store mapping of course identifier to LON-CAPA CourseID').':&nbsp;'.  
                '<label><input type="radio" name="lti_storecrs_'.$num.'" value="0"'.  
                $checked{'storecrs'}{'N'}.' />'.&mt('No').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_storecrs_'.$num.'" value="1"'.  
                $checked{'storecrs'}{'Y'}.' />'.&mt('Yes').'</label></span>'.  
                '</fieldset>'.  
                '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Mapping course roles').'</legend><table><tr>';  
     foreach my $ltirole (@lticourseroles) {  
         my ($selected,$selectnone);  
         if ($rolemaps{$ltirole} eq '') {  
             $selectnone = ' selected="selected"';  
         }  
         $output .= '<td style="text-align: center">'.$ltirole.'<br />'.  
                    '<select name="lti_maprole_'.$ltirole.'_'.$num.'">'.  
                    '<option value=""'.$selectnone.'>'.&mt('Select').'</option>';  
         foreach my $role (@courseroles) {  
             unless ($selectnone) {  
                 if ($rolemaps{$ltirole} eq $role) {  
                     $selected = ' selected="selected"';  
                 } else {  
                     $selected = '';  
                 }  
             }  
             $output .= '<option value="'.$role.'"'.$selected.'>'.  
                        &Apache::lonnet::plaintext($role,'Course').  
                        '</option>';  
         }  
         $output .= '</select></td>';  
     }  
     $output .= '</tr></table></fieldset>'.  
                '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Creating courses').'</legend>'.  
                '<span class="LC_nobreak">'.&mt('Course created (if absent) on Instructor access').':&nbsp;'.  
                '<label><input type="radio" name="lti_makecrs_'.$num.'" value="0"'.  
                $checked{'makecrs'}{'N'}.' />'.&mt('No').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_makecrs_'.$num.'" value="1"'.  
                $checked{'makecrs'}{'Y'}.' />'.&mt('Yes').'</label></span>'.  
                '</fieldset>'.  
                '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Roles which may self-enroll').'</legend>';  
     foreach my $lticrsrole (@lticourseroles) {  
         $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="lti_selfenroll_'.$num.'" value="'.$lticrsrole.'"'.  
                    $checked{'selfenroll'}{$lticrsrole}.' />'.$lticrsrole.'</label>&nbsp;</span> ';  
     }  
     $output .= '</fieldset>'.  
                '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Course options').'</legend>'.  
                '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('Assign users to sections').':&nbsp;'.  
                '<label><input type="radio" name="lti_crssec_'.$num.'" value="0"'.  
                $checked{'crssec'}{'N'}.$onclicksec.' />'.&mt('No').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_crssec_'.$num.'" value="1"'.  
                $checked{'crssec'}{'Y'}.$onclicksec.' />'.&mt('Yes').'</label></span></div>'.  
                '<div class="LC_floatleft" style="display:'.$crssecfieldsty.';" id="lti_crssecfield_'.$num.'">'.  
                '<span class="LC_nobreak">'.&mt('From').':<label>'.  
                '<input type="radio" name="lti_crssecsrc_'.$num.'" value="course_section_sourcedid"'.  
                $checked{'crssecsrc'}{'sourcedid'}.$onclicksecsrc.' />'.  
                &mt('Standard field').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_crssecsrc_'.$num.'" value="other"'.  
                $checked{'crssecsrc'}{'other'}.$onclicksecsrc.' />'.&mt('Other').  
                '</label></span></div><div class="LC_floatleft" style="display:'.$secsrcfieldsty.';" id="lti_secsrcfield_'.$num.'">'.  
                '<input type="text" name="lti_customsection_'.$num.'" value="'.$crssecsrc.'" />'.  
                '</div><div style="padding:0;clear:both;margin:0;border:0"></div>';  
     my ($pb1p1chk,$pb1p0chk,$onclickpb);  
     foreach my $extra ('roster','passback') {  
         my $checkedon = '';  
         my $checkedoff = ' checked="checked"';  
         if ($extra eq 'passback') {  
             $pb1p1chk = ' checked="checked"';  
             $pb1p0chk = '';  
             $onclickpb = ' onclick="toggleLTI(this.form,'."'passback','$num'".');"';  
         } else {  
             $onclickpb = '';  
         }  
         if (ref($current) eq 'HASH') {  
             if (($current->{$extra})) {  
                 $checkedon = $checkedoff;  
                 $checkedoff = '';  
                 if ($extra eq 'passback') {  
                     $passbacksty = 'inline-block';  
                 }  
                 if ($current->{'passbackformat'} eq '1.0') {  
                     $pb1p0chk =  ' checked="checked"';  
                     $pb1p1chk = '';  
                 }  
             }  
         }  
         $output .= $lt{$extra}.'&nbsp;'.  
                    '<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="0"'.$checkedoff.$onclickpb.' />'.  
                    &mt('No').'</label>'.('&nbsp;'x2).  
                    '<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="1"'.$checkedon.$onclickpb.' />'.  
                    &mt('Yes').'</label><br />';  
     }  
     $output .= '<div class="LC_floatleft" style="display:'.$passbacksty.';" id="lti_passback_'.$num.'">'.  
                '<span class="LC_nobreak">'.&mt('Grade format').  
                '<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.1"'.$pb1p1chk.' />'.  
                &mt('Outcomes Service (1.1)').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.0"'.$pb1p0chk.'/>'.  
                &mt('Outcomes Extension (1.0)').'</label></span></div>'.  
                '<div style="padding:0;clear:both;margin:0;border:0"></div></fieldset>';  
     $output .= '</span></div></fieldset>';  
 #        '<fieldset><legend>'.&mt('Assigning author roles').'</legend>';  
 #  
 #    $output .= '</fieldset>'.  
 #        '<fieldset><legend>'.&mt('Assigning domain roles').'</legend>';  
     return $output;  
 }  
   
 sub ltimenu_titles {  
     return &Apache::lonlocal::texthash(  
                                         fullname    => 'Full name',  
                                         coursetitle => 'Course title',  
                                         role        => 'Role',  
                                         logout      => 'Logout',  
                                         grades      => 'Grades',  
     );  
 }  
   
   
   
 sub print_coursedefaults {  sub print_coursedefaults {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($css_class,$datatable,%checkedon,%checkedoff,%defaultchecked,@toggles);      my ($css_class,$datatable,%checkedon,%checkedoff,%defaultchecked,@toggles);
Line 5928  sub print_coursedefaults { Line 4532  sub print_coursedefaults {
         postsubmit           => 'Disable submit button/keypress following student submission',          postsubmit           => 'Disable submit button/keypress following student submission',
         canclone             => "People who may clone a course (besides course's owner and coordinators)",          canclone             => "People who may clone a course (besides course's owner and coordinators)",
         mysqltables          => 'Lifetime (s) of "Temporary" MySQL tables (student performance data) on homeserver',          mysqltables          => 'Lifetime (s) of "Temporary" MySQL tables (student performance data) on homeserver',
         ltiauth              => 'Student username in LTI launch of deep-linked URL can be accepted without re-authentication',  
         domexttool           => 'External Tools defined in the domain may be used in courses/communities (by type)',  
         exttool              => 'External Tools can be defined and configured in courses/communities (by type)',  
     );      );
     my %staticdefaults = (      my %staticdefaults = (
                            anonsurvey_threshold => 10,                             anonsurvey_threshold => 10,
                            uploadquota          => 500,                             uploadquota          => 500,
                            postsubmit           => 60,                             postsubmit           => 60,
                            mysqltables          => 172800,                             mysqltables          => 172800,
                            domexttool           => 1,  
                            exttool              => 0,  
                          );                           );
     if ($position eq 'top') {      if ($position eq 'top') {
         %defaultchecked = (          %defaultchecked = (
Line 6024  sub print_coursedefaults { Line 4623  sub print_coursedefaults {
                     if ($checked) {                      if ($checked) {
                         $show = 'block';                          $show = 'block';
                     }                      }
                     $additional = '<div id="cloneinstcode" style="display:'.$show.';" />'.                      $additional = '<div id="cloneinstcode" style="display:'.$show.'" />'.
                                   &mt('Institutional codes for new and cloned course have identical:').                                    &mt('Institutional codes for new and cloned course have identical:').
                                   '<br />';                                    '<br />';
                     foreach my $item (@code_order) {                      foreach my $item (@code_order) {
Line 6054  sub print_coursedefaults { Line 4653  sub print_coursedefaults {
         my ($currdefresponder,%defcredits,%curruploadquota,%deftimeout,%currmysql);          my ($currdefresponder,%defcredits,%curruploadquota,%deftimeout,%currmysql);
         my $currusecredits = 0;          my $currusecredits = 0;
         my $postsubmitclient = 1;          my $postsubmitclient = 1;
         my $ltiauth = 0;  
         my %domexttool;  
         my %exttool;  
         my @types = ('official','unofficial','community','textbook');          my @types = ('official','unofficial','community','textbook');
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if ($settings->{'ltiauth'}) {  
                 $ltiauth = 1;  
             }  
             if (ref($settings->{'domexttool'}) eq 'HASH') {  
                 foreach my $type (@types) {  
                     if ($settings->{'domexttool'}->{$type}) {  
                         $domexttool{$type} = ' checked="checked"';  
                     }  
                 }  
             } else {  
                 foreach my $type (@types) {  
                     if ($staticdefaults{'domexttool'}) {  
                         $domexttool{$type} = ' checked="checked"';  
                     }  
                 }  
             }  
             if (ref($settings->{'exttool'}) eq 'HASH') {  
                 foreach my $type (@types) {  
                     if ($settings->{'exttool'}->{$type}) {  
                         $exttool{$type} = ' checked="checked"';  
                     }  
                 }  
             }  
             $currdefresponder = $settings->{'anonsurvey_threshold'};              $currdefresponder = $settings->{'anonsurvey_threshold'};
             if (ref($settings->{'uploadquota'}) eq 'HASH') {              if (ref($settings->{'uploadquota'}) eq 'HASH') {
                 foreach my $type (keys(%{$settings->{'uploadquota'}})) {                  foreach my $type (keys(%{$settings->{'uploadquota'}})) {
Line 6133  sub print_coursedefaults { Line 4706  sub print_coursedefaults {
         } else {          } else {
             foreach my $type (@types) {              foreach my $type (@types) {
                 $deftimeout{$type} = $staticdefaults{'postsubmit'};                  $deftimeout{$type} = $staticdefaults{'postsubmit'};
                 if ($staticdefaults{'domexttool'}) {  
                     $domexttool{$type} = ' checked="checked"';  
                 }  
             }              }
         }          }
         if (!$currdefresponder) {          if (!$currdefresponder) {
Line 6230  sub print_coursedefaults { Line 4800  sub print_coursedefaults {
         }          }
         $datatable .= '</tr></table></td></tr>'."\n";          $datatable .= '</tr></table></td></tr>'."\n";
         $itemcount ++;          $itemcount ++;
         %defaultchecked = ('ltiauth' => 'off');  
         @toggles = ('ltiauth');  
         $current = {  
                        'ltiauth' => $ltiauth,  
                    };  
         ($table,$itemcount) =  
             &radiobutton_prefs($current,\@toggles,\%defaultchecked,  
                                \%choices,$itemcount,undef,undef,'left');  
         $datatable .= $table;  
         $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';  
         $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.  
                       $choices{'domexttool'}.  
                       '</span></td>'.  
                       '<td style="text-align: right" class="LC_right_item">'.  
                       '<table><tr>';  
         foreach my $type (@types) {  
             $datatable .= '<td style="text-align: left">'.  
                           '<span class="LC_nobreak">'.  
                           '<input type="checkbox" name="domexttool"'.  
                           ' value="'.$type.'"'.$domexttool{$type}.' />'.  
                           &mt($type).'</span></td>'."\n";  
         }  
         $datatable .= '</tr></table></td></tr>'."\n";  
         $itemcount ++;  
         $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';  
         $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.  
                       $choices{'exttool'}.  
                       '</span></td>'.  
                       '<td style="text-align: right" class="LC_right_item">'.  
                       '<table><tr>';  
         foreach my $type (@types) {  
             $datatable .= '<td style="text-align: left">'.  
                           '<span class="LC_nobreak">'.  
                           '<input type="checkbox" name="exttool"'.  
                           ' value="'.$type.'"'.$exttool{$type}.' />'.  
                           &mt($type).'</span></td>'."\n";  
         }  
         $datatable .= '</tr></table></td></tr>'."\n";  
     }      }
     $$rowtotal += $itemcount;      $$rowtotal += $itemcount;
     return $datatable;      return $datatable;
Line 6783  sub print_passwords { Line 5316  sub print_passwords {
             $itemcount ++;              $itemcount ++;
         }          }
     } elsif ($position eq 'lower') {      } elsif ($position eq 'lower') {
         $datatable .= &password_rules('passwords',\$itemcount,$settings);          my ($min,$max,%chars,$numsaved);
           $min = $Apache::lonnet::passwdmin;
           if (ref($settings) eq 'HASH') {
               if ($settings->{min}) {
                   $min = $settings->{min};
               }
               if ($settings->{max}) {
                   $max = $settings->{max};
               }
               if (ref($settings->{chars}) eq 'ARRAY') {
                   map { $chars{$_} = 1; } (@{$settings->{chars}});
               }
               if ($settings->{numsaved}) {
                   $numsaved = $settings->{numsaved};
               }
           }
           my %rulenames = &Apache::lonlocal::texthash(
                                                        uc => 'At least one upper case letter',
                                                        lc => 'At least one lower case letter',
                                                        num => 'At least one number',
                                                        spec => 'At least one non-alphanumeric',
                                                      );
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td>'.$titles{'min'}.'</td>'.
                         '<td class="LC_left_item"><span class="LC_nobreak">'.
                         '<input type="text" name="passwords_min" value="'.$min.'" size="3" '.
                         'onblur="javascript:warnIntPass(this);" />'.
                         '<span class="LC_fontsize_small"> '.&mt('(Enter an integer: 7 or larger)').'</span>'.
                         '</span></td></tr>';
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td>'.$titles{'max'}.'</td>'.
                         '<td class="LC_left_item"><span class="LC_nobreak">'.
                         '<input type="text" name="passwords_max" value="'.$max.'" size="3" '.
                         'onblur="javascript:warnIntPass(this);" />'.
                         '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no maximum)').'</span>'.
                         '</span></td></tr>';
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td>'.$titles{'chars'}.'<br />'.
                         '<span class="LC_nobreak LC_fontsize_small">'.&mt('(Leave unchecked if not required)').
                         '</span></td>';
           my $numinrow = 2;
           my @possrules = ('uc','lc','num','spec');
           $datatable .= '<td class="LC_left_item"><table>';
           for (my $i=0; $i<@possrules; $i++) {
               my ($rem,$checked);
               if ($chars{$possrules[$i]}) {
                   $checked = ' checked="checked"';
               }
               $rem = $i%($numinrow);
               if ($rem == 0) {
                   if ($i > 0) {
                       $datatable .= '</tr>';
                   }
                   $datatable .= '<tr>';
               }
               $datatable .= '<td><span class="LC_nobreak"><label>'.
                             '<input type="checkbox" name="passwords_chars" value="'.$possrules[$i].'"'.$checked.' />'.
                             $rulenames{$possrules[$i]}.'</label></span></td>';
           }
           my $rem = @possrules%($numinrow);
           my $colsleft = $numinrow - $rem;
           if ($colsleft > 1 ) {
               $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
                             '&nbsp;</td>';
           } elsif ($colsleft == 1) {
               $datatable .= '<td class="LC_left_item">&nbsp;</td>';
           }
           $datatable .='</table></td></tr>';
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td>'.$titles{'numsaved'}.'</td>'.
                         '<td class="LC_left_item"><span class="LC_nobreak">'.
                         '<input type="text" name="passwords_numsaved" value="'.$numsaved.'" size="3" '.
                         'onblur="javascript:warnIntPass(this);" />'.
                         '<span class="LC_fontsize_small"> '.&mt('(Leave blank to not save previous passwords)').'</span>'.
                         '</span></td></tr>';
     } else {      } else {
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);          my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
         my %ownerchg = (          my %ownerchg = (
Line 6843  sub print_passwords { Line 5453  sub print_passwords {
     return $datatable;      return $datatable;
 }  }
   
 sub password_rules {  
     my ($prefix,$itemcountref,$settings) = @_;  
     my ($min,$max,%chars,$numsaved,$numinrow);  
     my %titles;  
     if ($prefix eq 'passwords') {  
         %titles = &Apache::lonlocal::texthash (  
             min            => 'Minimum password length',  
             max            => 'Maximum password length',  
             chars          => 'Required characters',  
         );  
     } elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {  
         %titles = &Apache::lonlocal::texthash (  
             min            => 'Minimum secret length',  
             max            => 'Maximum secret length',  
             chars          => 'Required characters',  
         );  
     }  
     $min = $Apache::lonnet::passwdmin;  
     my $datatable;  
     my $itemcount;  
     if (ref($itemcountref)) {  
         $itemcount = $$itemcountref;  
     }  
     if (ref($settings) eq 'HASH') {  
         if ($settings->{min}) {  
             $min = $settings->{min};  
         }  
         if ($settings->{max}) {  
             $max = $settings->{max};  
         }  
         if (ref($settings->{chars}) eq 'ARRAY') {  
             map { $chars{$_} = 1; } (@{$settings->{chars}});  
         }  
         if ($prefix eq 'passwords') {  
             if ($settings->{numsaved}) {  
                 $numsaved = $settings->{numsaved};  
             }  
         }  
     }  
     my %rulenames = &Apache::lonlocal::texthash(  
                                                  uc => 'At least one upper case letter',  
                                                  lc => 'At least one lower case letter',  
                                                  num => 'At least one number',  
                                                  spec => 'At least one non-alphanumeric',  
                                                );  
     my $css_class = $itemcount%2?' class="LC_odd_row"':'';  
     $datatable .= '<tr'.$css_class.'><td>'.$titles{'min'}.'</td>'.  
                   '<td class="LC_left_item"><span class="LC_nobreak">'.  
                   '<input type="text" name="'.$prefix.'_min" value="'.$min.'" size="3" '.  
                   'onblur="javascript:warnInt'.$prefix.'(this);" />'.  
                   '<span class="LC_fontsize_small"> '.&mt('(Enter an integer: 7 or larger)').'</span>'.  
                   '</span></td></tr>';  
     $itemcount ++;  
     $css_class = $itemcount%2?' class="LC_odd_row"':'';  
     $datatable .= '<tr'.$css_class.'><td>'.$titles{'max'}.'</td>'.  
                   '<td class="LC_left_item"><span class="LC_nobreak">'.  
                   '<input type="text" name="'.$prefix.'_max" value="'.$max.'" size="3" '.  
                   'onblur="javascript:warnInt'.$prefix.'(this);" />'.  
                   '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no maximum)').'</span>'.  
                   '</span></td></tr>';  
     $itemcount ++;  
     $css_class = $itemcount%2?' class="LC_odd_row"':'';  
     $datatable .= '<tr'.$css_class.'><td>'.$titles{'chars'}.'<br />'.  
                   '<span class="LC_nobreak LC_fontsize_small">'.&mt('(Leave unchecked if not required)').  
                   '</span></td>';  
     my $numinrow = 2;  
     my @possrules = ('uc','lc','num','spec');  
     $datatable .= '<td class="LC_left_item"><table>';  
     for (my $i=0; $i<@possrules; $i++) {  
         my ($rem,$checked);  
         if ($chars{$possrules[$i]}) {  
             $checked = ' checked="checked"';  
         }  
         $rem = $i%($numinrow);  
         if ($rem == 0) {  
             if ($i > 0) {  
                 $datatable .= '</tr>';  
             }  
             $datatable .= '<tr>';  
         }  
         $datatable .= '<td><span class="LC_nobreak"><label>'.  
                       '<input type="checkbox" name="'.$prefix.'_chars" value="'.$possrules[$i].'"'.$checked.' />'.  
                       $rulenames{$possrules[$i]}.'</label></span></td>';  
     }  
     my $rem = @possrules%($numinrow);  
     my $colsleft = $numinrow - $rem;  
     if ($colsleft > 1 ) {  
         $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.  
                       '&nbsp;</td>';  
     } elsif ($colsleft == 1) {  
         $datatable .= '<td class="LC_left_item">&nbsp;</td>';  
     }  
     $datatable .='</table></td></tr>';  
     $itemcount ++;  
     if ($prefix eq 'passwords') {  
         $titles{'numsaved'} = &mt('Number of previous passwords to save and disallow reuse');  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'numsaved'}.'</td>'.  
                       '<td class="LC_left_item"><span class="LC_nobreak">'.  
                       '<input type="text" name="'.$prefix.'_numsaved" value="'.$numsaved.'" size="3" '.  
                       'onblur="javascript:warnInt'.$prefix.'(this);" />'.  
                       '<span class="LC_fontsize_small"> '.&mt('(Leave blank to not save previous passwords)').'</span>'.  
                       '</span></td></tr>';  
         $itemcount ++;  
     }  
     if (ref($itemcountref)) {  
         $$itemcountref += $itemcount;  
     }  
     return $datatable;  
 }  
   
 sub print_wafproxy {  sub print_wafproxy {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my $css_class;      my $css_class;
Line 7289  sub print_usersessions { Line 5788  sub print_usersessions {
                                       $other_insts,$curroffloadnow,$curroffloadoth,$rowtotal);                                        $other_insts,$curroffloadnow,$curroffloadoth,$rowtotal);
         } else {          } else {
             $datatable .= '<tr'.$css_class.'><td colspan="2">'.              $datatable .= '<tr'.$css_class.'><td colspan="2">'.
                           &mt('Nothing to set here, as the cluster to which this domain belongs only contains one server.').                            &mt('Nothing to set here, as the cluster to which this domain belongs only contains one server.');
                           '</td></tr>';  
         }          }
     } else {      } else {
         if (keys(%by_location) == 0) {          if (keys(%by_location) == 0) {
             $datatable .= '<tr'.$css_class.'><td colspan="2">'.              $datatable .= '<tr'.$css_class.'><td colspan="2">'.
                           &mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.').                            &mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.');
                           '</td></tr>';  
         } else {          } else {
             my %lt = &usersession_titles();              my %lt = &usersession_titles();
             my $numinrow = 5;              my $numinrow = 5;
Line 8012  sub loadbalance_rule_row { Line 6509  sub loadbalance_rule_row {
     }      }
     my $space;      my $space;
     if ($islast && $num == 1) {      if ($islast && $num == 1) {
         $space = '<div style="display:inline-block;">&nbsp;</div>';          $space = '<div display="inline-block">&nbsp;</div>';
     }      }
     my $output =      my $output =
         '<tr class="'.$css_class.'" id="balanceruletr_'.$balnum.'_'.$num.'"><td valign="top">'.$space.          '<tr class="'.$css_class.'" id="balanceruletr_'.$balnum.'_'.$num.'"><td valign="top">'.$space.
Line 8151  sub tool_titles { Line 6648  sub tool_titles {
                      blog       => 'Blog',                       blog       => 'Blog',
                      webdav     => 'WebDAV',                       webdav     => 'WebDAV',
                      portfolio  => 'Portfolio',                       portfolio  => 'Portfolio',
                      timezone   => 'Can set time zone',  
                      official   => 'Official courses (with institutional codes)',                       official   => 'Official courses (with institutional codes)',
                      unofficial => 'Unofficial courses',                       unofficial => 'Unofficial courses',
                      community  => 'Communities',                       community  => 'Communities',
Line 8166  sub courserequest_titles { Line 6662  sub courserequest_titles {
                                    unofficial => 'Unofficial',                                     unofficial => 'Unofficial',
                                    community  => 'Communities',                                     community  => 'Communities',
                                    textbook   => 'Textbook',                                     textbook   => 'Textbook',
                                    lti        => 'LTI Provider',  
                                    norequest  => 'Not allowed',                                     norequest  => 'Not allowed',
                                    approval   => 'Approval by Dom. Coord.',                                     approval   => 'Approval by Dom. Coord.',
                                    validate   => 'With validation',                                     validate   => 'With validation',
Line 8280  sub print_usercreation { Line 6775  sub print_usercreation {
         }          }
     } else {      } else {
         my @contexts = ('author','course','domain');          my @contexts = ('author','course','domain');
         my @authtypes = ('int','krb4','krb5','loc','lti');          my @authtypes = ('int','krb4','krb5','loc');
         my %checked;          my %checked;
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if (ref($settings->{'authtypes'}) eq 'HASH') {              if (ref($settings->{'authtypes'}) eq 'HASH') {
Line 8842  sub noninst_users { Line 7337  sub noninst_users {
 sub captcha_choice {  sub captcha_choice {
     my ($context,$settings,$itemcount,$customcss,$rowstyle) = @_;      my ($context,$settings,$itemcount,$customcss,$rowstyle) = @_;
     my ($keyentry,$currpub,$currpriv,%checked,$rowname,$pubtext,$privtext,      my ($keyentry,$currpub,$currpriv,%checked,$rowname,$pubtext,$privtext,
         $vertext,$currver);          $vertext,$currver); 
     my %lt = &captcha_phrases();      my %lt = &captcha_phrases();
     $keyentry = 'hidden';      $keyentry = 'hidden';
     my $colspan=2;      my $colspan=2;
Line 9024  sub authtype_names { Line 7519  sub authtype_names {
                       krb4   => 'Kerberos 4',                        krb4   => 'Kerberos 4',
                       krb5   => 'Kerberos 5',                        krb5   => 'Kerberos 5',
                       loc    => 'Local',                        loc    => 'Local',
                       lti    => 'LTI',  
                   );                    );
     return %lt;      return %lt;
 }  }
Line 9093  sub print_defaults { Line 7587  sub print_defaults {
                           '<td><span class="LC_nobreak">'.$titles->{$item}.                            '<td><span class="LC_nobreak">'.$titles->{$item}.
                           '</span></td><td class="LC_right_item" colspan="3">';                            '</span></td><td class="LC_right_item" colspan="3">';
             if ($item eq 'auth_def') {              if ($item eq 'auth_def') {
                 my @authtypes = ('internal','krb4','krb5','localauth','lti');                  my @authtypes = ('internal','krb4','krb5','localauth');
                 my %shortauth = (                  my %shortauth = (
                                  internal => 'int',                                   internal => 'int',
                                  krb4 => 'krb4',                                   krb4 => 'krb4',
                                  krb5 => 'krb5',                                   krb5 => 'krb5',
                                  localauth  => 'loc',                                   localauth  => 'loc'
                                  lti => 'lti',  
                                 );                                  );
                 my %authnames = &authtype_names();                  my %authnames = &authtype_names();
                 foreach my $auth (@authtypes) {                  foreach my $auth (@authtypes) {
Line 9120  sub print_defaults { Line 7613  sub print_defaults {
             } elsif ($item eq 'lang_def') {              } elsif ($item eq 'lang_def') {
                 my $includeempty = 1;                  my $includeempty = 1;
                 $datatable .= &Apache::loncommon::select_language($item,$defaults{$item},$includeempty);                  $datatable .= &Apache::loncommon::select_language($item,$defaults{$item},$includeempty);
             } elsif ($item eq 'portal_def') {  
                 $datatable .= '<input type="text" name="'.$item.'" value="'.  
                               $defaults{$item}.'" size="25" onkeyup="portalExtras(this);" />';  
                 my $portalsty = 'none';  
                 if ($defaults{$item}) {  
                     $portalsty = 'block';  
                 }  
                 foreach my $field ('email','web') {  
                     my $checkedoff = ' checked="checked"';  
                     my $checkedon;  
                     if ($defaults{$item.'_'.$field}) {  
                         $checkedon = $checkedoff;  
                         $checkedoff = '';  
                     }  
                     $datatable .= '<div id="'.$item.'_'.$field.'_div" style="display:'.$portalsty.'">'.  
                               '<span class="LC_nobreak">'.$titles->{$field}.'&nbsp;'.  
                               '<label><input type="radio" name="'.$item.'_'.$field.'" value="1"'.$checkedon.'/>'.&mt('Yes').'</label>'.  
                               ('&nbsp;'x2).  
                               '<label><input type="radio" name="'.$item.'_'.$field.'" value="0"'.$checkedoff.'/>'.&mt('No').'</label>'.  
                               '</div>';  
                 }  
             } else {              } else {
                 $datatable .= '<input type="text" name="'.$item.'" value="'.$defaults{$item}.'" />';                  my $size;
                   if ($item eq 'portal_def') {
                       $size = ' size="25"';
                   }
                   $datatable .= '<input type="text" name="'.$item.'" value="'.
                                 $defaults{$item}.'"'.$size.' />';
             }              }
             $datatable .= '</td></tr>';              $datatable .= '</td></tr>';
             $rownum ++;              $rownum ++;
Line 9238  sub defaults_titles { Line 7715  sub defaults_titles {
                    'timezone_def'  => 'Default timezone',                     'timezone_def'  => 'Default timezone',
                    'datelocale_def' => 'Default locale for dates',                     'datelocale_def' => 'Default locale for dates',
                    'portal_def'     => 'Portal/Default URL',                     'portal_def'     => 'Portal/Default URL',
                    'email'          => 'Email links use portal URL',  
                    'web'            => 'Public web links use portal URL',  
                    'intauth_cost'   => 'Encryption cost for bcrypt (positive integer)',                     'intauth_cost'   => 'Encryption cost for bcrypt (positive integer)',
                    'intauth_check'  => 'Check bcrypt cost if authenticated',                     'intauth_check'  => 'Check bcrypt cost if authenticated',
                    'intauth_switch' => 'Existing crypt-based switched to bcrypt on authentication',                     'intauth_switch' => 'Existing crypt-based switched to bcrypt on authentication',
Line 9472  sub legacy_scantronformat { Line 7947  sub legacy_scantronformat {
     my ($url,$error);      my ($url,$error);
     my @statinfo = &Apache::lonnet::stat_file($newurl);      my @statinfo = &Apache::lonnet::stat_file($newurl);
     if ((!@statinfo) || ($statinfo[0] eq 'no_such_dir')) {      if ((!@statinfo) || ($statinfo[0] eq 'no_such_dir')) {
         my $modified = [];  
         (my $result,$url) =          (my $result,$url) =
             &Apache::lonconfigsettings::publishlogo($r,'copy',$legacyfile,$dom,$confname,              &publishlogo($r,'copy',$legacyfile,$dom,$confname,'scantron',
                                                     'scantron','','',$newfile,$modified);                           '','',$newfile);
         if ($result eq 'ok') {          if ($result ne 'ok') {
             &update_modify_urls($r,$modified);  
         } else {  
             $error = &mt("An error occurred publishing the [_1] bubblesheet format file in RES space. Error was: [_2].",$newfile,$result);              $error = &mt("An error occurred publishing the [_1] bubblesheet format file in RES space. Error was: [_2].",$newfile,$result);
         }          }
     }      }
Line 9925  sub serverstatus_pages { Line 8397  sub serverstatus_pages {
 sub defaults_javascript {  sub defaults_javascript {
     my ($settings) = @_;      my ($settings) = @_;
     return unless (ref($settings) eq 'HASH');      return unless (ref($settings) eq 'HASH');
     my $portal_js = <<"ENDPORTAL";  
   
 function portalExtras(caller) {  
     var x = caller.value;  
     var y = new Array('email','web');  
     for (var i=0; i<y.length; i++) {  
         if (document.getElementById('portal_def_'+y[i]+'_div')) {  
             var z = document.getElementById('portal_def_'+y[i]+'_div');  
             if (x.length > 0) {  
                 z.style.display = 'block';  
             } else {  
                 z.style.display = 'none';  
             }  
         }  
     }  
 }  
 ENDPORTAL  
     if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) {      if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) {
         my $maxnum = scalar(@{$settings->{'inststatusorder'}});          my $maxnum = scalar(@{$settings->{'inststatusorder'}});
         if ($maxnum eq '') {          if ($maxnum eq '') {
Line 9995  $jstext Line 8450  $jstext
     return;      return;
 }  }
   
 $portal_js  
   
 // ]]>  
 </script>  
   
 ENDSCRIPT  
     } else {  
 return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
 $portal_js  
 // ]]>  // ]]>
 </script>  </script>
   
 ENDSCRIPT  ENDSCRIPT
     }      }
     return;  
 }  }
   
 sub passwords_javascript {  sub passwords_javascript {
     my ($prefix) = @_;      my %intalert = &Apache::lonlocal::texthash (
     my %intalert;          authcheck => 'Warning: disallowing login for an authenticated user if the stored cost is less than the default will require a password reset by/for the user.',
     if ($prefix eq 'passwords') {          authcost => 'Warning: bcrypt encryption cost for internal authentication must be an integer.',
         %intalert = &Apache::lonlocal::texthash (          passmin => 'Warning: minimum password length must be a positive integer greater than 6.',
             authcheck => 'Warning: disallowing login for an authenticated user if the stored cost is less than the default will require a password reset by/for the user.',          passmax => 'Warning: maximum password length must be a positive integer (or blank).',
             authcost => 'Warning: bcrypt encryption cost for internal authentication must be an integer.',          passexp => 'Warning: days before password expiration must be a positive integer (or blank).',
             passmin => 'Warning: minimum password length must be a positive integer greater than 6.',          passnum => 'Warning: number of previous passwords to save must be a positive integer (or blank).',
             passmax => 'Warning: maximum password length must be a positive integer (or blank).',      );
             passnum => 'Warning: number of previous passwords to save must be a positive integer (or blank).',  
         );  
     } elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {  
         %intalert = &Apache::lonlocal::texthash (  
             passmin => 'Warning: minimum secret length must be a positive integer greater than 6.',  
             passmax => 'Warning: maximum secret length must be a positive integer (or blank).',  
         );  
     }  
     &js_escape(\%intalert);      &js_escape(\%intalert);
     my $defmin = $Apache::lonnet::passwdmin;      my $defmin = $Apache::lonnet::passwdmin;
     my $intauthjs;      my $intauthjs = <<"ENDSCRIPT";
     if ($prefix eq 'passwords') { $intauthjs = <<"ENDSCRIPT";  
   
 function warnIntAuth(field) {  function warnIntAuth(field) {
     if (field.name == 'intauth_check') {      if (field.name == 'intauth_check') {
Line 10054  function warnIntAuth(field) { Line 8488  function warnIntAuth(field) {
     return;      return;
 }  }
   
 ENDSCRIPT  function warnIntPass(field) {
   
      }  
   
      $intauthjs .= <<"ENDSCRIPT";  
   
 function warnInt$prefix(field) {  
     field.value.replace(/^\s+/,'');      field.value.replace(/^\s+/,'');
     field.value.replace(/\s+\$/,'');      field.value.replace(/\s+\$/,'');
     var regexdigit=/^\\d+\$/;      var regexdigit=/^\\d+\$/;
     if (field.name == '${prefix}_min') {      if (field.name == 'passwords_min') {
         if (field.value == '') {          if (field.value == '') {
             alert('$intalert{passmin}');              alert('$intalert{passmin}');
             field.value = '$defmin';              field.value = '$defmin';
Line 10084  function warnInt$prefix(field) { Line 8512  function warnInt$prefix(field) {
             field.value = '';              field.value = '';
         }          }
         if (field.value != '') {          if (field.value != '') {
             if (!regexdigit.test(field.value)) {              if (field.name == 'passwords_expire') {
                 if (field.name == '${prefix}_max') {                  var regexpposnum=/^\\d+(|\\.\\d*)\$/;
                     alert('$intalert{passmax}');                  if (!regexpposnum.test(field.value)) {
                       alert('$intalert{passexp}');
                       field.value = '';
                 } else {                  } else {
                     if (field.name == '${prefix}_numsaved') {                      var expval = parseFloat(field.value);
                         alert('$intalert{passnum}');                      if (expval == 0) {
                           alert('$intalert{passexp}');
                           field.value = '';
                       }
                   }
               } else {
                   if (!regexdigit.test(field.value)) {
                       if (field.name == 'passwords_max') {
                           alert('$intalert{passmax}');
                       } else {
                           if (field.name == 'passwords_numsaved') {
                               alert('$intalert{passnum}');
                           }
                     }                      }
                       field.value = '';
                 }                  }
                 field.value = '';  
             }              }
         }          }
     }      }
Line 10335  sub build_category_rows { Line 8777  sub build_category_rows {
   
 sub modifiable_userdata_row {  sub modifiable_userdata_row {
     my ($context,$item,$settings,$numinrow,$rowcount,$usertypes,$fieldsref,$titlesref,      my ($context,$item,$settings,$numinrow,$rowcount,$usertypes,$fieldsref,$titlesref,
         $rowid,$customcss,$rowstyle,$itemdesc) = @_;          $rowid,$customcss,$rowstyle) = @_;
     my ($role,$rolename,$statustype);      my ($role,$rolename,$statustype);
     $role = $item;      $role = $item;
     if ($context eq 'cancreate') {      if ($context eq 'cancreate') {
Line 10356  sub modifiable_userdata_row { Line 8798  sub modifiable_userdata_row {
         } else {          } else {
             $rolename = $role;              $rolename = $role;
         }          }
     } elsif ($context eq 'lti') {  
         $rolename = &mt('Institutional data used (if available)');  
     } else {      } else {
         if ($role eq 'cr') {          if ($role eq 'cr') {
             $rolename = &mt('Custom role');              $rolename = &mt('Custom role');
Line 10395  sub modifiable_userdata_row { Line 8835  sub modifiable_userdata_row {
     if ($rowid) {      if ($rowid) {
         $rowid = ' id="'.$rowid.'"';          $rowid = ' id="'.$rowid.'"';
     }      }
   
     $output = '<tr '.$css_class.$rowid.'>'.      $output = '<tr '.$css_class.$rowid.'>'.
               '<td><span class="LC_nobreak">'.$rolename.'</span></td>'.                '<td><span class="LC_nobreak">'.$rolename.'</span></td>'.
               '<td class="LC_left_item" colspan="2"><table>';                '<td class="LC_left_item" colspan="2"><table>';
     my $rem;      my $rem;
     my %checks;      my %checks;
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         my $hashref;          if (ref($settings->{$context}) eq 'HASH') {
         if ($context eq 'lti') {  
             if (ref($settings) eq 'HASH') {  
                 $hashref = $settings->{'instdata'};  
             }  
         } elsif (ref($settings->{$context}) eq 'HASH') {  
             if (ref($settings->{$context}->{$role}) eq 'HASH') {              if (ref($settings->{$context}->{$role}) eq 'HASH') {
                 $hashref = $settings->{'lti_instdata'};                  my $hashref = $settings->{$context}->{$role};
             }                  if ($role eq 'emailusername') {
             if ($role eq 'emailusername') {                      if ($statustype) {
                 if ($statustype) {                          if (ref($settings->{$context}->{$role}->{$statustype}) eq 'HASH') {
                     if (ref($settings->{$context}->{$role}->{$statustype}) eq 'HASH') {                              $hashref = $settings->{$context}->{$role}->{$statustype};
                         $hashref = $settings->{$context}->{$role}->{$statustype};                              if (ref($hashref) eq 'HASH') { 
                                   foreach my $field (@fields) {
                                       if ($hashref->{$field}) {
                                           $checks{$field} = $hashref->{$field};
                                       }
                                   }
                               }
                           }
                     }                      }
                 }                  } else {
             }                      if (ref($hashref) eq 'HASH') {
         }                          foreach my $field (@fields) {
         if (ref($hashref) eq 'HASH') {                              if ($hashref->{$field}) {
             foreach my $field (@fields) {                                  $checks{$field} = ' checked="checked" ';
                 if ($hashref->{$field}) {                              }
                     if ($role eq 'emailusername') {                          }
                         $checks{$field} = $hashref->{$field};  
                     } else {  
                         $checks{$field} = ' checked="checked" ';  
                     }                      }
                 }                  }
             }              }
         }          }
     }      }
   
     my $total = scalar(@fields);      my $total = scalar(@fields);
     for (my $i=0; $i<$total; $i++) {      for (my $i=0; $i<$total; $i++) {
         $rem = $i%($numinrow);          $rem = $i%($numinrow);
Line 10443  sub modifiable_userdata_row { Line 8884  sub modifiable_userdata_row {
         unless ($role eq 'emailusername') {          unless ($role eq 'emailusername') {
             if (exists($checks{$fields[$i]})) {              if (exists($checks{$fields[$i]})) {
                 $check = $checks{$fields[$i]};                  $check = $checks{$fields[$i]};
             } elsif ($context ne 'lti') {              } else {
                 if ($role eq 'st') {                  if ($role eq 'st') {
                     if (ref($settings) ne 'HASH') {                      if (ref($settings) ne 'HASH') {
                         $check = ' checked="checked" ';                           $check = ' checked="checked" '; 
Line 10453  sub modifiable_userdata_row { Line 8894  sub modifiable_userdata_row {
         }          }
         $output .= '<td class="LC_left_item">'.          $output .= '<td class="LC_left_item">'.
                    '<span class="LC_nobreak">';                     '<span class="LC_nobreak">';
         my $prefix = 'canmodify';  
         if ($role eq 'emailusername') {          if ($role eq 'emailusername') {
             unless ($checks{$fields[$i]} =~ /^(required|optional)$/) {              unless ($checks{$fields[$i]} =~ /^(required|optional)$/) {
                 $checks{$fields[$i]} = 'omit';                  $checks{$fields[$i]} = 'omit';
Line 10464  sub modifiable_userdata_row { Line 8904  sub modifiable_userdata_row {
                     $checked='checked="checked" ';                      $checked='checked="checked" ';
                 }                  }
                 $output .= '<label>'.                  $output .= '<label>'.
                            '<input type="radio" name="'.$prefix.'_'.$item.'_'.$fields[$i].'" value="'.$option.'" '.$checked.'/>'.                             '<input type="radio" name="canmodify_'.$item.'_'.$fields[$i].'" value="'.$option.'" '.$checked.'/>'.
                            &mt($option).'</label>'.('&nbsp;' x2);                             &mt($option).'</label>'.('&nbsp;' x2);
             }              }
             $output .= '<i>'.$fieldtitles{$fields[$i]}.'</i>';              $output .= '<i>'.$fieldtitles{$fields[$i]}.'</i>';
         } else {          } else {
             if ($context eq 'lti') {  
                 $prefix = 'lti';  
             }  
             $output .= '<label>'.              $output .= '<label>'.
                        '<input type="checkbox" name="'.$prefix.'_'.$role.'" '.                         '<input type="checkbox" name="canmodify_'.$role.'" '.
                        'value="'.$fields[$i].'"'.$check.'/>'.$fieldtitles{$fields[$i]}.                         'value="'.$fields[$i].'"'.$check.'/>'.$fieldtitles{$fields[$i]}.
                        '</label>';                         '</label>';
         }          }
Line 10560  sub insttypes_row { Line 8997  sub insttypes_row {
                 $output .= '<td class="LC_left_item">'.                  $output .= '<td class="LC_left_item">'.
                            '<span class="LC_nobreak"><label>'.                             '<span class="LC_nobreak"><label>'.
                            '<input type="checkbox" name="'.$context.'" '.                             '<input type="checkbox" name="'.$context.'" '.
                            'value="'.$types->[$i].'"'.$check.$onclick.' />'.                             'value="'.$types->[$i].'"'.$check.$onclick.'/>'.
                            $usertypes->{$types->[$i]}.'</label></span></td>';                             $usertypes->{$types->[$i]}.'</label></span></td>';
             }              }
         }          }
Line 10676  sub modify_login { Line 9113  sub modify_login {
     my ($r,$dom,$confname,$lastactref,%domconfig) = @_;      my ($r,$dom,$confname,$lastactref,%domconfig) = @_;
     my ($resulttext,$errors,$colchgtext,%changes,%colchanges,%newfile,%newurl,      my ($resulttext,$errors,$colchgtext,%changes,%colchanges,%newfile,%newurl,
         %curr_loginvia,%loginhash,@currlangs,@newlangs,$addedfile,%title,@offon,          %curr_loginvia,%loginhash,@currlangs,@newlangs,$addedfile,%title,@offon,
         %currsaml,%saml,%samltext,%samlimg,%samlalt,%samlurl,%samltitle,%samlwindow,%samlnotsso);          %currsaml,%saml,%samltext,%samlimg,%samlalt,%samlurl,%samltitle,%samlnotsso);
     %title = ( coursecatalog => 'Display course catalog',      %title = ( coursecatalog => 'Display course catalog',
                adminmail => 'Display administrator E-mail address',                 adminmail => 'Display administrator E-mail address',
                helpdesk  => 'Display "Contact Helpdesk" link',                 helpdesk  => 'Display "Contact Helpdesk" link',
Line 10700  sub modify_login { Line 9137  sub modify_login {
                     $samlalt{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'alt'};                      $samlalt{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'alt'};
                     $samlimg{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'img'};                      $samlimg{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'img'};
                     $samltitle{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'title'};                      $samltitle{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'title'};
                     $samlwindow{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'window'};  
                     $samlnotsso{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'notsso'};                      $samlnotsso{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'notsso'};
                 }                  }
             }              }
Line 10843  sub modify_login { Line 9279  sub modify_login {
                 if ($addedfile ne '') {                  if ($addedfile ne '') {
                     push(@allnew,$addedfile);                      push(@allnew,$addedfile);
                 }                  }
                 my $modified = [];  
                 foreach my $lang (@allnew) {                  foreach my $lang (@allnew) {
                     my $formelem = 'loginhelpurl_'.$lang;                      my $formelem = 'loginhelpurl_'.$lang;
                     if ($lang eq $env{'form.loginhelpurl_add_lang'}) {                      if ($lang eq $env{'form.loginhelpurl_add_lang'}) {
                         $formelem = 'loginhelpurl_add_file';                          $formelem = 'loginhelpurl_add_file';
                     }                      }
                     (my $result,$newurl{$lang}) =                      (my $result,$newurl{$lang}) = &publishlogo($r,'upload',$formelem,$dom,$confname,
                         &Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname,                                                                 "help/$lang",'','',$newfile{$lang});
                                                                 "help/$lang",'','',$newfile{$lang},  
                                                                 $modified);  
                     if ($result eq 'ok') {                      if ($result eq 'ok') {
                         $loginhash{'login'}{'helpurl'}{$lang} = $newurl{$lang};                          $loginhash{'login'}{'helpurl'}{$lang} = $newurl{$lang};
                         $changes{'helpurl'}{$lang} = 1;                          $changes{'helpurl'}{$lang} = 1;
Line 10865  sub modify_login { Line 9298  sub modify_login {
                         }                          }
                     }                      }
                 }                  }
                 &update_modify_urls($r,$modified);  
             } else {              } else {
                 $error = &mt("Upload of custom log-in help file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2].  Error was: [_3].",$confname,$dom,$author_ok);                  $error = &mt("Upload of custom log-in help file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2].  Error was: [_3].",$confname,$dom,$author_ok);
             }              }
Line 10923  sub modify_login { Line 9355  sub modify_login {
             if ($switchserver) {              if ($switchserver) {
                 $error = &mt("Upload of custom markup is not permitted to this server: [_1]",$switchserver);                  $error = &mt("Upload of custom markup is not permitted to this server: [_1]",$switchserver);
             } elsif ($author_ok eq 'ok') {              } elsif ($author_ok eq 'ok') {
                 my $modified = [];  
                 foreach my $lonhost (@newhosts) {                  foreach my $lonhost (@newhosts) {
                     my $formelem = 'loginheadtag_'.$lonhost;                      my $formelem = 'loginheadtag_'.$lonhost;
                     (my $result,$newheadtagurls{$lonhost}) =                      (my $result,$newheadtagurls{$lonhost}) = &publishlogo($r,'upload',$formelem,$dom,$confname,
                         &Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname,                                                                            "login/headtag/$lonhost",'','',
                                                                 "login/headtag/$lonhost",'','',                                                                            $env{'form.loginheadtag_'.$lonhost.'.filename'});
                                                                 $env{'form.loginheadtag_'.$lonhost.'.filename'},  
                                                                 $modified);  
                     if ($result eq 'ok') {                      if ($result eq 'ok') {
                         $loginhash{'login'}{'headtag'}{$lonhost}{'url'} = $newheadtagurls{$lonhost};                          $loginhash{'login'}{'headtag'}{$lonhost}{'url'} = $newheadtagurls{$lonhost};
                         $changes{'headtag'}{$lonhost} = 1;                          $changes{'headtag'}{$lonhost} = 1;
Line 10947  sub modify_login { Line 9376  sub modify_login {
                         }                          }
                     }                      }
                 }                  }
                 &update_modify_urls($r,$modified);  
             } else {              } else {
                 $error = &mt("Upload of custom markup file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2].  Error was: [_3].",$confname,$dom,$author_ok);                  $error = &mt("Upload of custom markup file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2].  Error was: [_3].",$confname,$dom,$author_ok);
             }              }
Line 10966  sub modify_login { Line 9394  sub modify_login {
             if ($env{'form.saml_img_'.$lonhost.'.filename'}) {              if ($env{'form.saml_img_'.$lonhost.'.filename'}) {
                 push(@newsamlimgs,$lonhost);                  push(@newsamlimgs,$lonhost);
             }              }
             foreach my $item ('text','alt','url','title','window','notsso') {              foreach my $item ('text','alt','url','title','notsso') {
                 $env{'form.saml_'.$item.'_'.$lonhost} =~ s/^\s+|\s+$//g;                  $env{'form.saml_'.$item.'_'.$lonhost} =~ s/^\s+|\s+$//g;
             }              }
             if ($saml{$lonhost}) {              if ($saml{$lonhost}) {
                 if ($env{'form.saml_window_'.$lonhost} ne '1') {  
                     $env{'form.saml_window_'.$lonhost} = '';  
                 }  
                 if (grep(/^\Q$lonhost\E$/,@delsamlimg)) {                  if (grep(/^\Q$lonhost\E$/,@delsamlimg)) {
 #FIXME Need to obsolete published image  #FIXME Need to obsolete published image
                     delete($currsaml{$lonhost}{'img'});                      delete($currsaml{$lonhost}{'img'});
Line 10990  sub modify_login { Line 9415  sub modify_login {
                 if ($env{'form.saml_title_'.$lonhost} ne $samltitle{$lonhost}) {                  if ($env{'form.saml_title_'.$lonhost} ne $samltitle{$lonhost}) {
                     $changes{'saml'}{$lonhost} = 1;                      $changes{'saml'}{$lonhost} = 1;
                 }                  }
                 if ($env{'form.saml_window_'.$lonhost} ne $samlwindow{$lonhost}) {  
                     $changes{'saml'}{$lonhost} = 1;  
                 }  
                 if ($env{'form.saml_notsso_'.$lonhost} ne $samlnotsso{$lonhost}) {                  if ($env{'form.saml_notsso_'.$lonhost} ne $samlnotsso{$lonhost}) {
                     $changes{'saml'}{$lonhost} = 1;                      $changes{'saml'}{$lonhost} = 1;
                 }                  }
             } else {              } else {
                 $changes{'saml'}{$lonhost} = 1;                  $changes{'saml'}{$lonhost} = 1;
             }              }
             foreach my $item ('text','alt','url','title','window','notsso') {              foreach my $item ('text','alt','url','title','notsso') {
                 $currsaml{$lonhost}{$item} = $env{'form.saml_'.$item.'_'.$lonhost};                  $currsaml{$lonhost}{$item} = $env{'form.saml_'.$item.'_'.$lonhost};
             }              }
         } else {          } else {
Line 11022  sub modify_login { Line 9444  sub modify_login {
             if ($switchserver) {              if ($switchserver) {
                 $error = &mt("Upload of SSO Button Image is not permitted to this server: [_1].",$switchserver);                  $error = &mt("Upload of SSO Button Image is not permitted to this server: [_1].",$switchserver);
             } elsif ($author_ok eq 'ok') {              } elsif ($author_ok eq 'ok') {
                 my $modified = [];  
                 foreach my $lonhost (@newsamlimgs) {                  foreach my $lonhost (@newsamlimgs) {
                     my $formelem = 'saml_img_'.$lonhost;                      my $formelem = 'saml_img_'.$lonhost;
                     my ($result,$imgurl) =                      my ($result,$imgurl) = &publishlogo($r,'upload',$formelem,$dom,$confname,
                         &Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname,                                                          "login/saml/$lonhost",'','',
                                                                 "login/saml/$lonhost",'','',                                                          $env{'form.saml_img_'.$lonhost.'.filename'});
                                                                 $env{'form.saml_img_'.$lonhost.'.filename'},  
                                                                 $modified);  
                     if ($result eq 'ok') {                      if ($result eq 'ok') {
                         $currsaml{$lonhost}{'img'} = $imgurl;                          $currsaml{$lonhost}{'img'} = $imgurl;
                         $loginhash{'login'}{'saml'}{$lonhost}{'img'} = $imgurl;                          $loginhash{'login'}{'saml'}{$lonhost}{'img'} = $imgurl;
Line 11040  sub modify_login { Line 9459  sub modify_login {
                         $errors .= '<li><span class="LC_error">'.$puberror.'</span></li>';                          $errors .= '<li><span class="LC_error">'.$puberror.'</span></li>';
                     }                      }
                 }                  }
                 &update_modify_urls($r,$modified);  
             } else {              } else {
                 $error = &mt("Upload of SSO button image file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2].  Error was: [_3].",$confname,$dom,$author_ok);                  $error = &mt("Upload of SSO button image file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2].  Error was: [_3].",$confname,$dom,$author_ok);
             }              }
Line 11204  sub modify_login { Line 9622  sub modify_login {
                                        alt    => 'Alt text for button image',                                         alt    => 'Alt text for button image',
                                        url    => 'SSO URL',                                         url    => 'SSO URL',
                                        title  => 'Tooltip for SSO link',                                         title  => 'Tooltip for SSO link',
                                        window => 'Pop-up window if iframe',  
                                        notsso => 'Text for non-SSO log-in',                                         notsso => 'Text for non-SSO log-in',
                                     );                                      );
                         foreach my $lonhost (sort(keys(%{$changes{$item}}))) {                          foreach my $lonhost (sort(keys(%{$changes{$item}}))) {
                             if (ref($currsaml{$lonhost}) eq 'HASH') {                              if (ref($currsaml{$lonhost}) eq 'HASH') {
                                 $resulttext .= '<li>'.&mt("$title{$item} in use for [_1]","<b>$lonhost</b>").                                  $resulttext .= '<li>'.&mt("$title{$item} in use for [_1]","<b>$lonhost</b>").
                                                '<ul>';                                                 '<ul>';
                                 foreach my $key ('text','img','alt','url','title','window','notsso') {                                  foreach my $key ('text','img','alt','url','title','notsso') {
                                     if ($currsaml{$lonhost}{$key} eq '') {                                      if ($currsaml{$lonhost}{$key} eq '') {
                                         $resulttext .= '<li>'.&mt("$notlt{$key} not in use").'</li>';                                          $resulttext .= '<li>'.&mt("$notlt{$key} not in use").'</li>';
                                     } else {                                      } else {
                                         my $value = "'$currsaml{$lonhost}{$key}'";                                          my $value = "'$currsaml{$lonhost}{$key}'";
                                         if ($key eq 'img') {                                          if ($key eq 'img') {
                                             $value = '<img src="'.$currsaml{$lonhost}{$key}.'" />';                                              $value = '<img src="'.$currsaml{$lonhost}{$key}.'" />';
                                         } elsif ($key eq 'window') {  
                                             $value = 'On';  
                                         }                                          }
                                         $resulttext .= '<li>'.&mt("$notlt{$key} set to: [_1]",                                          $resulttext .= '<li>'.&mt("$notlt{$key} set to: [_1]",
                                                                   $value).'</li>';                                                                    $value).'</li>';
Line 11717  sub modify_colors { Line 10132  sub modify_colors {
             $domconfig->{$role} = {};              $domconfig->{$role} = {};
         }          }
         foreach my $img (@images) {          foreach my $img (@images) {
             if ($role eq 'login') {              if ($role eq 'login') { 
                 if (($img eq 'img') || ($img eq 'logo')) {                    if (($img eq 'img') || ($img eq 'logo')) {  
                     if (defined($env{'form.login_showlogo_'.$img})) {                      if (defined($env{'form.login_showlogo_'.$img})) {
                         $confhash->{$role}{'showlogo'}{$img} = 1;                          $confhash->{$role}{'showlogo'}{$img} = 1;
Line 11745  sub modify_colors { Line 10160  sub modify_colors {
                         $error = &mt("Upload of [_1] image for $role page(s) is not permitted to this server: [_2]",$choices{$img},$switchserver);                          $error = &mt("Upload of [_1] image for $role page(s) is not permitted to this server: [_2]",$choices{$img},$switchserver);
                     } else {                      } else {
                         if ($author_ok eq 'ok') {                          if ($author_ok eq 'ok') {
                             my $modified = [];  
                             my ($result,$logourl) =                               my ($result,$logourl) = 
                                 &Apache::lonconfigsettings::publishlogo($r,'upload',$role.'_'.$img,                                  &publishlogo($r,'upload',$role.'_'.$img,
                                                                         $dom,$confname,$img,$width,$height,                                             $dom,$confname,$img,$width,$height);
                                                                         '',$modified);  
                             if ($result eq 'ok') {                              if ($result eq 'ok') {
                                 $confhash->{$role}{$img} = $logourl;                                  $confhash->{$role}{$img} = $logourl;
                                 $changes{$role}{'images'}{$img} = 1;                                  $changes{$role}{'images'}{$img} = 1;
                                 &update_modify_urls($r,$modified);  
                             } else {                              } else {
                                 $error = &mt("Upload of [_1] image for $role page(s) failed because an error occurred publishing the file in RES space. Error was: [_2].",$choices{img},$result);                                  $error = &mt("Upload of [_1] image for $role page(s) failed because an error occurred publishing the file in RES space. Error was: [_2].",$choices{img},$result);
                             }                              }
Line 11775  sub modify_colors { Line 10187  sub modify_colors {
 # is confname an author?  # is confname an author?
                         if ($switchserver eq '') {                          if ($switchserver eq '') {
                             if ($author_ok eq 'ok') {                              if ($author_ok eq 'ok') {
                                 my $modified = [];  
                                 my ($result,$logourl) =                                   my ($result,$logourl) = 
                                     &Apache::lonconfigsettings::publishlogo($r,'copy',$domconfig->{$role}{$img},                                 &publishlogo($r,'copy',$domconfig->{$role}{$img},
                                                                             $dom,$confname,$img,$width,$height,                                              $dom,$confname,$img,$width,$height);
                                                                             '',$modified);  
                                 if ($result eq 'ok') {                                  if ($result eq 'ok') {
                                     $confhash->{$role}{$img} = $logourl;                                      $confhash->{$role}{$img} = $logourl;
     $changes{$role}{'images'}{$img} = 1;      $changes{$role}{'images'}{$img} = 1;
                                     &update_modify_urls($r,$modified);  
                                 }                                  }
                             }                              }
                         }                          }
Line 12077  sub check_authorstatus { Line 10486  sub check_authorstatus {
     return $author_ok;      return $author_ok;
 }  }
   
 sub update_modify_urls {  sub publishlogo {
     my ($r,$modified) = @_;      my ($r,$action,$formname,$dom,$confname,$subdir,$thumbwidth,$thumbheight,$savefileas) = @_;
     if ((ref($modified) eq 'ARRAY') && (@{$modified})) {      my ($output,$fname,$logourl);
         push(@{$modified_urls},$modified);      if ($action eq 'upload') {
         unless ($registered_cleanup) {          $fname=$env{'form.'.$formname.'.filename'};
             my $handlers = $r->get_handlers('PerlCleanupHandler');          chop($env{'form.'.$formname});
             $r->set_handlers('PerlCleanupHandler' => [\&notifysubscribed,@{$handlers}]);      } else {
             $registered_cleanup=1;          ($fname) = ($formname =~ /([^\/]+)$/);
       }
       if ($savefileas ne '') {
           $fname = $savefileas;
       }
       $fname=&Apache::lonnet::clean_filename($fname);
   # See if there is anything left
       unless ($fname) { return ('error: no uploaded file'); }
       $fname="$subdir/$fname";
       my $docroot=$r->dir_config('lonDocRoot');
       my $filepath="$docroot/priv";
       my $relpath = "$dom/$confname";
       my ($fnamepath,$file,$fetchthumb);
       $file=$fname;
       if ($fname=~m|/|) {
           ($fnamepath,$file) = ($fname =~ m|^(.*)/([^/]+)$|);
       }
       my @parts=split(/\//,"$filepath/$relpath/$fnamepath");
       my $count;
       for ($count=5;$count<=$#parts;$count++) {
           $filepath.="/$parts[$count]";
           if ((-e $filepath)!=1) {
               mkdir($filepath,02770);
           }
       }
       # Check for bad extension and disallow upload
       if ($file=~/\.(\w+)$/ &&
           (&Apache::loncommon::fileembstyle($1) eq 'hdn')) {
           $output = 
               &mt('Invalid file extension ([_1]) - reserved for internal use.',$1); 
       } elsif ($file=~/\.(\w+)$/ &&
           !defined(&Apache::loncommon::fileembstyle($1))) {
           $output = &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1);
       } elsif ($file=~/\.(\d+)\.(\w+)$/) {
           $output = &mt('Filename not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2);
       } elsif (-d "$filepath/$file") {
           $output = &mt('Filename is a directory name - rename the file and re-upload');
       } else {
           my $source = $filepath.'/'.$file;
           my $logfile;
           if (!open($logfile,">>",$source.'.log')) {
               return (&mt('No write permission to Authoring Space'));
           }
           print $logfile
   "\n================= Publish ".localtime()." ================\n".
   $env{'user.name'}.':'.$env{'user.domain'}."\n";
   # Save the file
           if (!open(FH,">",$source)) {
               &Apache::lonnet::logthis('Failed to create '.$source);
               return (&mt('Failed to create file'));
           }
           if ($action eq 'upload') {
               if (!print FH ($env{'form.'.$formname})) {
                   &Apache::lonnet::logthis('Failed to write to '.$source);
                   return (&mt('Failed to write file'));
               }
           } else {
               my $original = &Apache::lonnet::filelocation('',$formname);
               if(!copy($original,$source)) {
                   &Apache::lonnet::logthis('Failed to copy '.$original.' to '.$source);
                   return (&mt('Failed to write file'));
               }
           }
           close(FH);
           chmod(0660, $source); # Permissions to rw-rw---.
   
           my $targetdir=$docroot.'/res/'.$dom.'/'.$confname .'/'.$fnamepath;
           my $copyfile=$targetdir.'/'.$file;
   
           my @parts=split(/\//,$targetdir);
           my $path="/$parts[1]/$parts[2]/$parts[3]/$parts[4]";
           for (my $count=5;$count<=$#parts;$count++) {
               $path.="/$parts[$count]";
               if (!-e $path) {
                   print $logfile "\nCreating directory ".$path;
                   mkdir($path,02770);
               }
           }
           my $versionresult;
           if (-e $copyfile) {
               $versionresult = &logo_versioning($targetdir,$file,$logfile);
           } else {
               $versionresult = 'ok';
           }
           if ($versionresult eq 'ok') {
               if (copy($source,$copyfile)) {
                   print $logfile "\nCopied original source to ".$copyfile."\n";
                   $output = 'ok';
                   $logourl = '/res/'.$dom.'/'.$confname.'/'.$fname;
                   push(@{$modified_urls},[$copyfile,$source]);
                   my $metaoutput = 
                       &write_metadata($dom,$confname,$formname,$targetdir,$file,$logfile);
                   unless ($registered_cleanup) {
                       my $handlers = $r->get_handlers('PerlCleanupHandler');
                       $r->set_handlers('PerlCleanupHandler' => [\&notifysubscribed,@{$handlers}]);
                       $registered_cleanup=1;
                   }
               } else {
                   print $logfile "\nUnable to write ".$copyfile.':'.$!."\n";
                   $output = &mt('Failed to copy file to RES space').", $!";
               }
               if (($thumbwidth =~ /^\d+$/) && ($thumbheight =~ /^\d+$/)) {
                   my $inputfile = $filepath.'/'.$file;
                   my $outfile = $filepath.'/'.'tn-'.$file;
                   my ($fullwidth,$fullheight) = &check_dimensions($inputfile);
                   if ($fullwidth ne '' && $fullheight ne '') { 
                       if ($fullwidth > $thumbwidth && $fullheight > $thumbheight) {
                           my $thumbsize = $thumbwidth.'x'.$thumbheight;
                           my @args = ('convert','-sample',$thumbsize,$inputfile,$outfile);
                           system({$args[0]} @args);
                           chmod(0660, $filepath.'/tn-'.$file);
                           if (-e $outfile) {
                               my $copyfile=$targetdir.'/tn-'.$file;
                               if (copy($outfile,$copyfile)) {
                                   print $logfile "\nCopied source to ".$copyfile."\n";
                                   my $thumb_metaoutput = 
                                       &write_metadata($dom,$confname,$formname,
                                                       $targetdir,'tn-'.$file,$logfile);
                                   push(@{$modified_urls},[$copyfile,$outfile]);
                                   unless ($registered_cleanup) {
                                       my $handlers = $r->get_handlers('PerlCleanupHandler');
                                       $r->set_handlers('PerlCleanupHandler' => [\&notifysubscribed,@{$handlers}]);
                                       $registered_cleanup=1;
                                   }
                               } else {
                                   print $logfile "\nUnable to write ".$copyfile.
                                                  ':'.$!."\n";
                               }
                           }
                       }
                   }
               }
           } else {
               $output = $versionresult;
           }
       }
       return ($output,$logourl);
   }
   
   sub logo_versioning {
       my ($targetdir,$file,$logfile) = @_;
       my $target = $targetdir.'/'.$file;
       my ($maxversion,$fn,$extn,$output);
       $maxversion = 0;
       if ($file =~ /^(.+)\.(\w+)$/) {
           $fn=$1;
           $extn=$2;
       }
       opendir(DIR,$targetdir);
       while (my $filename=readdir(DIR)) {
           if ($filename=~/\Q$fn\E\.(\d+)\.\Q$extn\E$/) {
               $maxversion=($1>$maxversion)?$1:$maxversion;
           }
       }
       $maxversion++;
       print $logfile "\nCreating old version ".$maxversion."\n";
       my $copyfile=$targetdir.'/'.$fn.'.'.$maxversion.'.'.$extn;
       if (copy($target,$copyfile)) {
           print $logfile "Copied old target to ".$copyfile."\n";
           $copyfile=$copyfile.'.meta';
           if (copy($target.'.meta',$copyfile)) {
               print $logfile "Copied old target metadata to ".$copyfile."\n";
               $output = 'ok';
           } else {
               print $logfile "Unable to write metadata ".$copyfile.':'.$!."\n";
               $output = &mt('Failed to copy old meta').", $!, ";
           }
       } else {
           print $logfile "Unable to write ".$copyfile.':'.$!."\n";
           $output = &mt('Failed to copy old target').", $!, ";
       }
       return $output;
   }
   
   sub write_metadata {
       my ($dom,$confname,$formname,$targetdir,$file,$logfile) = @_;
       my (%metadatafields,%metadatakeys,$output);
       $metadatafields{'title'}=$formname;
       $metadatafields{'creationdate'}=time;
       $metadatafields{'lastrevisiondate'}=time;
       $metadatafields{'copyright'}='public';
       $metadatafields{'modifyinguser'}=$env{'user.name'}.':'.
                                            $env{'user.domain'};
       $metadatafields{'authorspace'}=$confname.':'.$dom;
       $metadatafields{'domain'}=$dom;
       {
           print $logfile "\nWrite metadata file for ".$targetdir.'/'.$file;
           my $mfh;
           if (open($mfh,">",$targetdir.'/'.$file.'.meta')) {
               foreach (sort(keys(%metadatafields))) {
                   unless ($_=~/\./) {
                       my $unikey=$_;
                       $unikey=~/^([A-Za-z]+)/;
                       my $tag=$1;
                       $tag=~tr/A-Z/a-z/;
                       print $mfh "\n\<$tag";
                       foreach (split(/\,/,$metadatakeys{$unikey})) {
                           my $value=$metadatafields{$unikey.'.'.$_};
                           $value=~s/\"/\'\'/g;
                           print $mfh ' '.$_.'="'.$value.'"';
                       }
                       print $mfh '>'.
                           &HTML::Entities::encode($metadatafields{$unikey},'<>&"')
                               .'</'.$tag.'>';
                   }
               }
               $output = 'ok';
               print $logfile "\nWrote metadata";
               close($mfh);
           } else {
               print $logfile "\nFailed to open metadata file";
               $output = &mt('Could not write metadata');
         }          }
     }      }
       return $output;
 }  }
   
 sub notifysubscribed {  sub notifysubscribed {
Line 12137  sub subscribed_hosts { Line 10758  sub subscribed_hosts {
   
 sub check_switchserver {  sub check_switchserver {
     my ($dom,$confname) = @_;      my ($dom,$confname) = @_;
     my ($allowed,$switchserver,$home);      my ($allowed,$switchserver);
     if ($confname eq '') {      my $home = &Apache::lonnet::homeserver($confname,$dom);
       if ($home eq 'no_host') {
         $home = &Apache::lonnet::domain($dom,'primary');          $home = &Apache::lonnet::domain($dom,'primary');
     } else {  
         $home = &Apache::lonnet::homeserver($confname,$dom);  
         if ($home eq 'no_host') {  
             $home = &Apache::lonnet::domain($dom,'primary');  
         }  
     }      }
     my @ids=&Apache::lonnet::current_machine_ids();      my @ids=&Apache::lonnet::current_machine_ids();
     foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }      foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }
     if (!$allowed) {      if (!$allowed) {
  $switchserver='<a href="/adm/switchserver?otherserver='.$home.'&amp;role='.   $switchserver='<a href="/adm/switchserver?otherserver='.$home.'&amp;role=dc./'.$dom.'/&amp;destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';
                       &HTML::Entities::encode($env{'request.role'},'\'<>"&').  
                       '&amp;destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';  
     }      }
     return $switchserver;      return $switchserver;
 }  }
Line 12168  sub modify_quotas { Line 10783  sub modify_quotas {
         $context = $action;          $context = $action;
     }      }
     if ($context eq 'requestcourses') {      if ($context eq 'requestcourses') {
         @usertools = ('official','unofficial','community','textbook','lti');          @usertools = ('official','unofficial','community','textbook');
         @options =('norequest','approval','validate','autolimit');          @options =('norequest','approval','validate','autolimit');
         %validations = &Apache::lonnet::auto_courserequest_checks($dom);          %validations = &Apache::lonnet::auto_courserequest_checks($dom);
         %titles = &courserequest_titles();          %titles = &courserequest_titles();
Line 12183  sub modify_quotas { Line 10798  sub modify_quotas {
         @usertools = ('author');          @usertools = ('author');
         %titles = &authorrequest_titles();          %titles = &authorrequest_titles();
     } else {      } else {
         @usertools = ('aboutme','blog','webdav','portfolio','timezone');          @usertools = ('aboutme','blog','webdav','portfolio');
         %titles = &tool_titles();          %titles = &tool_titles();
     }      }
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);      my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
Line 12217  sub modify_quotas { Line 10832  sub modify_quotas {
         my @approvalnotify = &Apache::loncommon::get_env_multiple('form.'.$context.'notifyapproval');          my @approvalnotify = &Apache::loncommon::get_env_multiple('form.'.$context.'notifyapproval');
         @approvalnotify = sort(@approvalnotify);          @approvalnotify = sort(@approvalnotify);
         $confhash{'notify'}{'approval'} = join(',',@approvalnotify);          $confhash{'notify'}{'approval'} = join(',',@approvalnotify);
         my @crstypes = ('official','unofficial','community','textbook','lti');          my @crstypes = ('official','unofficial','community','textbook');
         my @hasuniquecode = &Apache::loncommon::get_env_multiple('form.uniquecode');          my @hasuniquecode = &Apache::loncommon::get_env_multiple('form.uniquecode');
         foreach my $type (@hasuniquecode) {          foreach my $type (@hasuniquecode) {
             if (grep(/^\Q$type\E$/,@crstypes)) {              if (grep(/^\Q$type\E$/,@crstypes)) {
Line 12339  sub modify_quotas { Line 10954  sub modify_quotas {
                                             &Apache::lonnet::logthis($error);                                              &Apache::lonnet::logthis($error);
                                             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';                                              $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
                                         }                                          }
                                     }                                      } 
                                 } elsif ($domconfig{$action}{$type}{$key}{'image'}) {                                  } elsif ($domconfig{$action}{$type}{$key}{'image'}) {
                                     $confhash{$type}{$key}{'image'} =                                       $confhash{$type}{$key}{'image'} = 
                                         $domconfig{$action}{$type}{$key}{'image'};                                          $domconfig{$action}{$type}{$key}{'image'};
Line 12874  sub process_textbook_image { Line 11489  sub process_textbook_image {
             $error = &mt('Upload of textbook image is not permitted to this server: [_1]',              $error = &mt('Upload of textbook image is not permitted to this server: [_1]',
                          $switchserver);                           $switchserver);
         } elsif ($author_ok eq 'ok') {          } elsif ($author_ok eq 'ok') {
             my $modified = [];  
             my ($result,$imageurl) =              my ($result,$imageurl) =
                 &Apache::lonconfigsettings::publishlogo($r,'upload',$caller,$dom,$confname,                  &publishlogo($r,'upload',$caller,$dom,$confname,
                                                         "$type/$cdom/$cnum/cover",$width,$height,                               "$type/$cdom/$cnum/cover",$width,$height);
                                                         '',$modified);  
             if ($result eq 'ok') {              if ($result eq 'ok') {
                 $url = $imageurl;                  $url = $imageurl;
                 &update_modify_urls($r,$modified);  
             } else {              } else {
                 $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result);                  $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result);
             }              }
Line 12894  sub process_textbook_image { Line 11506  sub process_textbook_image {
     return ($url,$error);      return ($url,$error);
 }  }
   
 sub modify_ltitools {  
     my ($r,$dom,$action,$lastactref,%domconfig) = @_;  
     my (%currtoolsec,%secchanges,%newtoolsec,%newkeyset);  
     &fetch_secrets($dom,'toolsec',\%domconfig,\%currtoolsec,\%secchanges,\%newtoolsec,\%newkeyset);  
   
     my $confname = $dom.'-domainconfig';  
     my $servadm = $r->dir_config('lonAdmEMail');  
     my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);  
   
     my ($resulttext,$ltitoolsoutput,$is_home,$errors,%ltitoolschg,%newtoolsenc,%newltitools);  
     my $toolserror =  
         &Apache::courseprefs::process_ltitools($r,$dom,$confname,$domconfig{'ltitools'},\%ltitoolschg,'domain',  
                                                $lastactref,$configuserok,$switchserver,$author_ok);  
   
     my $home = &Apache::lonnet::domain($dom,'primary');  
     unless (($home eq 'no_host') || ($home eq '')) {  
         my @ids=&Apache::lonnet::current_machine_ids();  
         foreach my $id (@ids) { if ($id eq $home) { $is_home=1; last; } }  
     }  
   
     if (keys(%ltitoolschg)) {  
         foreach my $id (keys(%ltitoolschg)) {  
             if (ref($ltitoolschg{$id}) eq 'HASH') {  
                 foreach my $inner (keys(%{$ltitoolschg{$id}})) {  
                     if (($inner eq 'secret') || ($inner eq 'key')) {  
                         if ($is_home) {  
                             $newtoolsenc{$id}{$inner} = $ltitoolschg{$id}{$inner};  
                         }  
                     }  
                 }  
             }  
         }  
         $ltitoolsoutput = &Apache::courseprefs::store_ltitools($dom,'','domain',\%ltitoolschg,$domconfig{'ltitools'});  
         if (keys(%ltitoolschg)) {  
             %newltitools = %ltitoolschg;  
         }  
     }  
     if (ref($domconfig{'ltitools'}) eq 'HASH') {  
         foreach my $id (%{$domconfig{'ltitools'}}) {  
             next if ($id !~ /^\d+$/);  
             unless (exists($ltitoolschg{$id})) {  
                 if (ref($domconfig{'ltitools'}{$id}) eq 'HASH') {  
                     foreach my $inner (keys(%{$domconfig{'ltitools'}{$id}})) {  
                         if (($inner eq 'secret') || ($inner eq 'key')) {  
                             if ($is_home) {  
                                 $newtoolsenc{$id}{$inner} = $domconfig{'ltitools'}{$id}{$inner};  
                             }  
                         } else {  
                             $newltitools{$id}{$inner} = $domconfig{'ltitools'}{$id}{$inner};  
                         }  
                     }  
                 } else {  
                     $newltitools{$id} = $domconfig{'ltitools'}{$id};  
                 }  
             }  
         }  
     }  
     if ($toolserror) {  
         $errors = '<li>'.$toolserror.'</li>';  
     }  
     if ((keys(%ltitoolschg) == 0) && (keys(%secchanges) == 0)) {  
         $resulttext = &mt('No changes made.');  
         if ($errors) {  
             $resulttext .= '<br />'.&mt('The following errors occurred: ').'<ul>'.  
                                  $errors.'</ul>';  
         }  
         return $resulttext;  
     }  
     my %ltitoolshash = (  
                           $action => { %newltitools }  
                        );  
     if (keys(%secchanges)) {  
         $ltitoolshash{'toolsec'} = \%newtoolsec;  
     }  
     my $putresult = &Apache::lonnet::put_dom('configuration',\%ltitoolshash,$dom);  
     if ($putresult eq 'ok') {  
         my %keystore;  
         if ($is_home) {  
             my %toolsenchash = (  
                                    $action => { %newtoolsenc }  
                                );  
             &Apache::lonnet::put_dom('encconfig',\%toolsenchash,$dom,undef,1);  
             my $cachetime = 24*60*60;  
             &Apache::lonnet::do_cache_new('ltitoolsenc',$dom,\%newtoolsenc,$cachetime);  
             &store_security($dom,'ltitools',\%secchanges,\%newkeyset,\%keystore,$lastactref);  
         }  
         $resulttext = &mt('Changes made:').'<ul>';  
         if (keys(%secchanges) > 0) {  
             $resulttext .= &lti_security_results($dom,'ltitools',\%secchanges,\%newtoolsec,\%newkeyset,\%keystore);  
         }  
         if (keys(%ltitoolschg) > 0) {  
             $resulttext .= $ltitoolsoutput;  
         }  
         my $cachetime = 24*60*60;  
         &Apache::lonnet::do_cache_new('ltitools',$dom,\%newltitools,$cachetime);  
         if (ref($lastactref) eq 'HASH') {  
             $lastactref->{'ltitools'} = 1;  
         }  
     } else {  
         $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';  
     }  
     if ($errors) {  
         $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.  
                        $errors.'</ul></p>';  
     }  
     return $resulttext;  
 }  
   
 sub fetch_secrets {  
     my ($dom,$context,$domconfig,$currsec,$secchanges,$newsec,$newkeyset) = @_;  
     my %keyset;  
     %{$currsec} = ();  
     $newsec->{'private'}{'keys'} = [];  
     $newsec->{'encrypt'} = {};  
     $newsec->{'rules'} = {};  
     if ($context eq 'ltisec') {  
         $newsec->{'linkprot'} = {};  
     }  
     if (ref($domconfig->{$context}) eq 'HASH') {  
         %{$currsec} = %{$domconfig->{$context}};  
         if ($context eq 'ltisec') {  
             if (ref($currsec->{'linkprot'}) eq 'HASH') {  
                 foreach my $id (keys(%{$currsec->{'linkprot'}})) {  
                     unless ($id =~ /^\d+$/) {  
                         delete($currsec->{'linkprot'}{$id});  
                     }  
                 }  
             }  
         }  
         if (ref($currsec->{'private'}) eq 'HASH') {  
             if (ref($currsec->{'private'}{'keys'}) eq 'ARRAY') {  
                 $newsec->{'private'}{'keys'} = $currsec->{'private'}{'keys'};  
                 map { $keyset{$_} = 1; } @{$currsec->{'private'}{'keys'}};  
             }  
         }  
     }  
     my @items= ('crs','dom');  
     if ($context eq 'ltisec') {  
         push(@items,'consumers');  
     }  
     foreach my $item (@items) {  
         my $formelement;  
         if (($context eq 'toolsec') || ($item eq 'consumers')) {  
             $formelement = 'form.'.$context.'_'.$item;  
         } else {  
             $formelement = 'form.'.$context.'_'.$item.'linkprot';  
         }  
         if ($env{$formelement}) {  
             $newsec->{'encrypt'}{$item} = 1;  
             if (ref($currsec->{'encrypt'}) eq 'HASH') {  
                 unless ($currsec->{'encrypt'}{$item}) {  
                     $secchanges->{'encrypt'} = 1;  
                 }  
             } else {  
                 $secchanges->{'encrypt'} = 1;  
             }  
         } elsif (ref($currsec->{'encrypt'}) eq 'HASH') {  
             if ($currsec->{'encrypt'}{$item}) {  
                 $secchanges->{'encrypt'} = 1;  
             }  
         }  
     }  
     my $secrets;  
     if ($context eq 'ltisec') {  
         $secrets = 'ltisecrets';  
     } else {  
         $secrets = 'toolsecrets';  
     }  
     unless (exists($currsec->{'rules'})) {  
         $currsec->{'rules'} = {};  
     }  
     &password_rule_changes($secrets,$newsec->{'rules'},$currsec->{'rules'},$secchanges);  
   
     my @ids=&Apache::lonnet::current_machine_ids();  
     my %servers = &Apache::lonnet::get_servers($dom,'library');  
   
     foreach my $hostid (keys(%servers)) {  
         if (($hostid ne '') && (grep(/^\Q$hostid\E$/,@ids))) {  
             my $keyitem = 'form.'.$context.'_privkey_'.$hostid;  
             if (exists($env{$keyitem})) {  
                 $env{$keyitem} =~ s/(`)/'/g;  
                 if ($keyset{$hostid}) {  
                     if ($env{'form.'.$context.'_changeprivkey_'.$hostid}) {  
                         if ($env{$keyitem} ne '') {  
                             $secchanges->{'private'} = 1;  
                             $newkeyset->{$hostid} = $env{$keyitem};  
                         }  
                     }  
                 } elsif ($env{$keyitem} ne '') {  
                     unless (grep(/^\Q$hostid\E$/,@{$newsec->{'private'}{'keys'}})) {  
                         push(@{$newsec->{'private'}{'keys'}},$hostid);  
                     }  
                     $secchanges->{'private'} = 1;  
                     $newkeyset->{$hostid} = $env{$keyitem};  
                 }  
             }  
         }  
     }  
 }  
   
 sub store_security {  
     my ($dom,$context,$secchanges,$newkeyset,$keystore) = @_;  
     return unless ((ref($secchanges) eq 'HASH') && (ref($newkeyset) eq 'HASH') &&  
                    (ref($keystore) eq 'HASH'));  
     if (keys(%{$secchanges})) {  
         if ($secchanges->{'private'}) {  
             my $who = &escape($env{'user.name'}.':'.$env{'user.domain'});  
             foreach my $hostid (keys(%{$newkeyset})) {  
                 my $storehash = {  
                                    key => $newkeyset->{$hostid},  
                                    who => $env{'user.name'}.':'.$env{'user.domain'},  
                                 };  
                 $keystore->{$hostid} = &Apache::lonnet::store_dom($storehash,$context,'private',  
                                                                   $dom,$hostid);  
             }  
         }  
     }  
 }  
   
 sub lti_security_results {  
     my ($dom,$context,$secchanges,$newsec,$newkeyset,$keystore) = @_;  
     my $output;  
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);  
     my $needs_update;  
     foreach my $item (keys(%{$secchanges})) {  
         if ($item eq 'encrypt') {  
             $needs_update = 1;  
             my %encrypted;  
             if ($context eq 'lti') {  
                 %encrypted = (  
                               crs  => {  
                                         on => &mt('Encryption of stored link protection secrets defined in courses enabled'),  
                                         off => &mt('Encryption of stored link protection secrets defined in courses disabled'),  
                                       },  
                               dom => {  
                                        on => &mt('Encryption of stored link protection secrets defined in domain enabled'),  
                                        off => &mt('Encryption of stored link protection secrets defined in domain disabled'),  
                                      },  
                               consumers => {  
                                              on => &mt('Encryption of stored consumer secrets defined in domain enabled'),  
                                              off => &mt('Encryption of stored consumer secrets defined in domain disabled'),  
                                            },  
                              );  
             } else {  
                 %encrypted = (  
                               crs  => {  
                                         on => &mt('Encryption of stored external tool secrets defined in courses enabled'),  
                                         off => &mt('Encryption of stored external tool secrets defined in courses disabled'),  
                                       },  
                               dom => {  
                                        on => &mt('Encryption of stored external tool secrets defined in domain enabled'),  
                                        off => &mt('Encryption of stored external tool secrets defined in domain disabled'),  
                                      },  
                              );  
   
             }  
             my @types= ('crs','dom');  
             if ($context eq 'lti') {  
                 foreach my $type (@types) {  
                     undef($domdefaults{'linkprotenc_'.$type});  
                 }  
                 push(@types,'consumers');  
                 undef($domdefaults{'ltienc_consumers'});  
             } elsif ($context eq 'ltitools') {  
                 foreach my $type (@types) {  
                     undef($domdefaults{'toolenc_'.$type});  
                 }  
             }  
             foreach my $type (@types) {  
                 my $shown = $encrypted{$type}{'off'};  
                 if (ref($newsec->{$item}) eq 'HASH') {  
                     if ($newsec->{$item}{$type}) {  
                         if ($context eq 'lti') {  
                             if ($type eq 'consumers') {  
                                 $domdefaults{'ltienc_consumers'} = 1;  
                             } else {  
                                 $domdefaults{'linkprotenc_'.$type} = 1;  
                             }  
                         } elsif ($context eq 'ltitools') {  
                             $domdefaults{'toolenc_'.$type} = 1;  
                         }  
                         $shown = $encrypted{$type}{'on'};  
                     }  
                 }  
                 $output .= '<li>'.$shown.'</li>';  
             }  
         } elsif ($item eq 'rules') {  
             my %titles = &Apache::lonlocal::texthash(  
                                       min   => 'Minimum password length',  
                                       max   => 'Maximum password length',  
                                       chars => 'Required characters',  
                          );  
             foreach my $rule ('min','max') {  
                 if ($newsec->{rules}{$rule} eq '') {  
                     if ($rule eq 'min') {  
                         $output .= '<li>'.&mt('[_1] not set.',$titles{$rule});  
                                    ' '.&mt('Default of [_1] will be used',  
                                            $Apache::lonnet::passwdmin).'</li>';  
                     } else {  
                         $output .= '<li>'.&mt('[_1] set to none',$titles{$rule}).'</li>';  
                     }  
                 } else {  
                     $output .= '<li>'.&mt('[_1] set to [_2]',$titles{$rule},$newsec->{rules}{$rule}).'</li>';  
                 }  
             }  
             if (ref($newsec->{'rules'}{'chars'}) eq 'ARRAY') {  
                 if (@{$newsec->{'rules'}{'chars'}} > 0) {  
                     my %rulenames = &Apache::lonlocal::texthash(  
                                              uc => 'At least one upper case letter',  
                                              lc => 'At least one lower case letter',  
                                              num => 'At least one number',  
                                              spec => 'At least one non-alphanumeric',  
                                     );  
                     my $needed = '<ul><li>'.  
                                  join('</li><li>',map {$rulenames{$_} } @{$newsec->{'rules'}{'chars'}}).  
                                  '</li></ul>';  
                     $output .= '<li>'.&mt('[_1] set to: [_2]',$titles{'chars'},$needed).'</li>';  
                 } else {  
                     $output .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';  
                 }  
             } else {  
                 $output .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';  
             }  
         } elsif ($item eq 'private') {  
             $needs_update = 1;  
             if ($context eq 'lti') {  
                 undef($domdefaults{'ltiprivhosts'});  
             } elsif ($context eq 'ltitools') {  
                 undef($domdefaults{'toolprivhosts'});  
             }  
             if (keys(%{$newkeyset})) {  
                 my @privhosts;  
                 foreach my $hostid (sort(keys(%{$newkeyset}))) {  
                     if ($keystore->{$hostid} eq 'ok') {  
                         $output .= '<li>'.&mt('Encryption key for storage of shared secrets saved for [_1]',$hostid).'</li>';  
                         unless (grep(/^\Q$hostid\E$/,@privhosts)) {  
                             push(@privhosts,$hostid);  
                         }  
                     }  
                 }  
                 if (@privhosts) {  
                     if ($context eq 'lti') {  
                         $domdefaults{'ltiprivhosts'} = \@privhosts;  
                     } elsif ($context eq 'ltitools') {  
                         $domdefaults{'toolprivhosts'} = \@privhosts;  
                     }  
                 }  
             }  
         } elsif ($item eq 'linkprot') {  
             next;  
         }  
     }  
     if ($needs_update) {  
         my $cachetime = 24*60*60;  
         &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);  
     }  
     return $output;  
 }  
   
 sub modify_lti {  
     my ($r,$dom,$action,$lastactref,%domconfig) = @_;  
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);  
     my ($newid,@allpos,%changes,%confhash,%ltienc,$errors,$resulttext);  
     my (%posslti,%posslticrs,%posscrstype);  
     my @courseroles = ('cc','in','ta','ep','st');  
     my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator);  
     my @lticourseroles = qw(Instructor TeachingAssistant Mentor Learner);  
     my @coursetypes = ('official','unofficial','community','textbook','placement','lti');  
     my %coursetypetitles = &Apache::lonlocal::texthash (  
                                official   => 'Official',  
                                unofficial => 'Unofficial',  
                                community  => 'Community',  
                                textbook   => 'Textbook',  
                                placement  => 'Placement Test',  
                                lti        => 'LTI Provider',  
     );  
     my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();  
     my %lt = &lti_names();  
     map { $posslti{$_} = 1; } @ltiroles;  
     map { $posslticrs{$_} = 1; } @lticourseroles;  
     map { $posscrstype{$_} = 1; } @coursetypes;  
   
     my %menutitles = &ltimenu_titles();  
     my (%currltisec,%secchanges,%newltisec,%newltienc,%newkeyset);  
   
     &fetch_secrets($dom,'ltisec',\%domconfig,\%currltisec,\%secchanges,\%newltisec,\%newkeyset);  
   
     my (%linkprotchg,$linkprotoutput,$is_home);  
     my $proterror = &Apache::courseprefs::process_linkprot($dom,'',$currltisec{'linkprot'},  
                                                            \%linkprotchg,'domain');  
     my $home = &Apache::lonnet::domain($dom,'primary');  
     unless (($home eq 'no_host') || ($home eq '')) {  
         my @ids=&Apache::lonnet::current_machine_ids();  
         foreach my $id (@ids) { if ($id eq $home) { $is_home=1; } }  
     }  
   
     if (keys(%linkprotchg)) {  
         $secchanges{'linkprot'} = 1;  
         my %oldlinkprot;  
         if (ref($currltisec{'linkprot'}) eq 'HASH') {  
             %oldlinkprot = %{$currltisec{'linkprot'}};  
         }  
         foreach my $id (keys(%linkprotchg)) {  
             if (ref($linkprotchg{$id}) eq 'HASH') {  
                 foreach my $inner (keys(%{$linkprotchg{$id}})) {  
                     if (($inner eq 'secret') || ($inner eq 'key')) {  
                         if ($is_home) {  
                             $newltienc{$id}{$inner} = $linkprotchg{$id}{$inner};  
                         }  
                     }  
                 }  
             } else {  
                 $newltisec{'linkprot'}{$id} = $linkprotchg{$id};  
             }  
         }  
         $linkprotoutput = &Apache::courseprefs::store_linkprot($dom,'','domain',\%linkprotchg,\%oldlinkprot);  
         if (keys(%linkprotchg)) {  
             %{$newltisec{'linkprot'}} = %linkprotchg;  
         }  
     }  
     if (ref($currltisec{'linkprot'}) eq 'HASH') {  
         foreach my $id (%{$currltisec{'linkprot'}}) {  
             next if ($id !~ /^\d+$/);  
             unless (exists($linkprotchg{$id})) {  
                 if (ref($currltisec{'linkprot'}{$id}) eq 'HASH') {  
                     foreach my $inner (keys(%{$currltisec{'linkprot'}{$id}})) {  
                         if (($inner eq 'secret') || ($inner eq 'key')) {  
                             if ($is_home) {  
                                 $newltienc{$id}{$inner} = $currltisec{'linkprot'}{$id}{$inner};  
                             }  
                         } else {  
                             $newltisec{'linkprot'}{$id}{$inner} = $currltisec{'linkprot'}{$id}{$inner};  
                         }  
                     }  
                 } else {  
                     $newltisec{'linkprot'}{$id} = $currltisec{'linkprot'}{$id};  
                 }  
             }  
         }  
     }  
     if ($proterror) {  
         $errors .= '<li>'.$proterror.'</li>';  
     }  
     my (@items,%deletions,%itemids);  
     if ($env{'form.lti_add'}) {  
         my $consumer = $env{'form.lti_consumer_add'};  
         $consumer =~ s/(`)/'/g;  
         ($newid,my $error) = &get_lti_id($dom,$consumer);  
         if ($newid) {  
             $itemids{'add'} = $newid;  
             push(@items,'add');  
             $changes{$newid} = 1;  
         } else {  
             my $error = &mt('Failed to acquire unique ID for new LTI configuration');  
             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';  
         }  
     }  
     if (ref($domconfig{$action}) eq 'HASH') {  
         my @todelete = &Apache::loncommon::get_env_multiple('form.lti_del');  
         if (@todelete) {  
             map { $deletions{$_} = 1; } @todelete;  
         }  
         my $maxnum = $env{'form.lti_maxnum'};  
         for (my $i=0; $i<$maxnum; $i++) {  
             my $itemid = $env{'form.lti_id_'.$i};  
             $itemid =~ s/\D+//g;  
             if (ref($domconfig{$action}{$itemid}) eq 'HASH') {  
                 if ($deletions{$itemid}) {  
                     $changes{$itemid} = $domconfig{$action}{$itemid}{'consumer'};  
                 } else {  
                     push(@items,$i);  
                     $itemids{$i} = $itemid;  
                 }  
             }  
         }  
     }  
     my (%keystore,$secstored);  
     if ($is_home) {  
         &store_security($dom,'lti',\%secchanges,\%newkeyset,\%keystore);  
     }  
   
     my ($cipher,$privnum);  
     if ((@items > 0) && ($is_home)) {  
         ($cipher,$privnum) = &get_priv_creds($dom,$home,$secchanges{'encrypt'},  
                                              $newltisec{'encrypt'},$keystore{$home});  
     }  
     foreach my $idx (@items) {  
         my $itemid = $itemids{$idx};  
         next unless ($itemid);  
         my %currlti;  
         unless ($idx eq 'add') {  
             if (ref($domconfig{$action}) eq 'HASH') {  
                 if (ref($domconfig{$action}{$itemid}) eq 'HASH') {  
                     %currlti = %{$domconfig{$action}{$itemid}};  
                 }  
             }  
         }  
         my $position = $env{'form.lti_pos_'.$itemid};  
         $position =~ s/\D+//g;  
         if ($position ne '') {  
             $allpos[$position] = $itemid;  
         }  
         foreach my $item ('consumer','lifetime','requser','crsinc') {  
             my $formitem = 'form.lti_'.$item.'_'.$idx;  
             $env{$formitem} =~ s/(`)/'/g;  
             if ($item eq 'lifetime') {  
                 $env{$formitem} =~ s/[^\d.]//g;  
             }  
             if ($env{$formitem} ne '') {  
                 $confhash{$itemid}{$item} = $env{$formitem};  
                 unless (($idx eq 'add') || ($changes{$itemid})) {  
                     if ($currlti{$item} ne $confhash{$itemid}{$item}) {  
                         $changes{$itemid} = 1;  
                     }  
                 }  
             }  
         }  
         if ($env{'form.lti_version_'.$idx} eq 'LTI-1p0') {  
             $confhash{$itemid}{'version'} = $env{'form.lti_version_'.$idx};  
         }  
         if ($confhash{$itemid}{'requser'}) {  
             if ($env{'form.lti_mapuser_'.$idx} eq 'sourcedid') {  
                 $confhash{$itemid}{'mapuser'} = 'lis_person_sourcedid';  
             } elsif ($env{'form.lti_mapuser_'.$idx} eq 'email') {  
                 $confhash{$itemid}{'mapuser'} = 'lis_person_contact_email_primary';  
             } elsif ($env{'form.lti_mapuser_'.$idx} eq 'other') {  
                 my $mapuser = $env{'form.lti_customuser_'.$idx};  
                 $mapuser =~ s/(`)/'/g;  
                 $mapuser =~ s/^\s+|\s+$//g;  
                 $confhash{$itemid}{'mapuser'} = $mapuser;  
             }  
             my @possmakeuser = &Apache::loncommon::get_env_multiple('form.lti_makeuser_'.$idx);  
             my @makeuser;  
             foreach my $ltirole (sort(@possmakeuser)) {  
                 if ($posslti{$ltirole}) {  
                     push(@makeuser,$ltirole);  
                 }  
             }  
             $confhash{$itemid}{'makeuser'} = \@makeuser;  
             if (@makeuser) {  
                 my $lcauth = $env{'form.lti_lcauth_'.$idx};  
                 if ($lcauth =~ /^(internal|krb4|krb5|localauth)$/) {  
                     $confhash{$itemid}{'lcauth'} = $lcauth;  
                     if ($lcauth ne 'internal') {  
                         my $lcauthparm = $env{'form.lti_lcauthparm_'.$idx};  
                         $lcauthparm =~ s/^(\s+|\s+)$//g;  
                         $lcauthparm =~ s/`//g;  
                         if ($lcauthparm ne '') {  
                             $confhash{$itemid}{'lcauthparm'} = $lcauthparm;  
                         }  
                     }  
                 } else {  
                     $confhash{$itemid}{'lcauth'} = 'lti';  
                 }  
             }  
             my @possinstdata =  &Apache::loncommon::get_env_multiple('form.lti_instdata_'.$idx);  
             if (@possinstdata) {  
                 foreach my $field (@possinstdata) {  
                     if (exists($fieldtitles{$field})) {  
                         push(@{$confhash{$itemid}{'instdata'}});  
                     }  
                 }  
             }  
             if ($env{'form.lti_callback_'.$idx}) {  
                 if ($env{'form.lti_callbackparam_'.$idx}) {  
                     my $callback = $env{'form.lti_callbackparam_'.$idx};  
                     $callback =~ s/^\s+|\s+$//g;  
                     $confhash{$itemid}{'callback'} = $callback;  
                 }  
             }  
             foreach my $field ('topmenu','inlinemenu') {  
                 if ($env{'form.lti_'.$field.'_'.$idx}) {  
                     $confhash{$itemid}{$field} = 1;  
                 }  
             }  
             if ($env{'form.lti_topmenu_'.$idx} || $env{'form.lti_inlinemenu_'.$idx}) {  
                 $confhash{$itemid}{lcmenu} = [];  
                 my @possmenu = &Apache::loncommon::get_env_multiple('form.lti_menuitem_'.$idx);  
                 foreach my $field (@possmenu) {  
                     if (exists($menutitles{$field})) {  
                         if ($field eq 'grades') {  
                             next unless ($env{'form.lti_inlinemenu_'.$idx});  
                         }  
                         push(@{$confhash{$itemid}{lcmenu}},$field);  
                     }  
                 }  
             }  
             if ($confhash{$itemid}{'crsinc'}) {  
                 if (($env{'form.lti_mapcrs_'.$idx} eq 'course_offering_sourcedid') ||  
                     ($env{'form.lti_mapcrs_'.$idx} eq 'context_id'))  {  
                     $confhash{$itemid}{'mapcrs'} = $env{'form.lti_mapcrs_'.$idx};  
                 } elsif ($env{'form.lti_mapcrs_'.$idx} eq 'other') {  
                     my $mapcrs = $env{'form.lti_mapcrsfield_'.$idx};  
                     $mapcrs =~ s/(`)/'/g;  
                     $mapcrs =~ s/^\s+|\s+$//g;  
                     $confhash{$itemid}{'mapcrs'} = $mapcrs;  
                 }  
                 my @posstypes = &Apache::loncommon::get_env_multiple('form.lti_mapcrstype_'.$idx);  
                 my @crstypes;  
                 foreach my $type (sort(@posstypes)) {  
                     if ($posscrstype{$type}) {  
                         push(@crstypes,$type);  
                     }  
                 }  
                 $confhash{$itemid}{'mapcrstype'} = \@crstypes;  
                 if ($env{'form.lti_storecrs_'.$idx}) {  
                     $confhash{$itemid}{'storecrs'} = 1;  
                 }  
                 if ($env{'form.lti_makecrs_'.$idx}) {  
                     $confhash{$itemid}{'makecrs'} = 1;  
                 }  
                 foreach my $ltirole (@lticourseroles) {  
                     my $possrole = $env{'form.lti_maprole_'.$ltirole.'_'.$idx};  
                     if (grep(/^\Q$possrole\E$/,@courseroles)) {  
                         $confhash{$itemid}{'maproles'}{$ltirole} = $possrole;  
                     }  
                 }  
                 my @possenroll = &Apache::loncommon::get_env_multiple('form.lti_selfenroll_'.$idx);  
                 my @selfenroll;  
                 foreach my $type (sort(@possenroll)) {  
                     if ($posslticrs{$type}) {  
                         push(@selfenroll,$type);  
                     }  
                 }  
                 $confhash{$itemid}{'selfenroll'} = \@selfenroll;  
                 if ($env{'form.lti_crssec_'.$idx}) {  
                     if ($env{'form.lti_crssecsrc_'.$idx} eq 'course_section_sourcedid') {  
                         $confhash{$itemid}{'section'} = $env{'form.lti_crssecsrc_'.$idx};  
                     } elsif ($env{'form.lti_crssecsrc_'.$idx} eq 'other') {  
                         my $section = $env{'form.lti_customsection_'.$idx};  
                         $section =~ s/(`)/'/g;  
                         $section =~ s/^\s+|\s+$//g;  
                         if ($section ne '') {  
                             $confhash{$itemid}{'section'} = $section;  
                         }  
                     }  
                 }  
                 foreach my $field ('passback','roster') {  
                     if ($env{'form.lti_'.$field.'_'.$idx}) {  
                         $confhash{$itemid}{$field} = 1;  
                     }  
                 }  
                 if ($env{'form.lti_passback_'.$idx}) {  
                     if ($env{'form.lti_passbackformat_'.$idx} eq '1.0') {  
                         $confhash{$itemid}{'passbackformat'} = '1.0';  
                     } else {  
                         $confhash{$itemid}{'passbackformat'} = '1.1';  
                     }  
                 }  
             }  
             unless (($idx eq 'add') || ($changes{$itemid})) {  
                 if ($confhash{$itemid}{'crsinc'}) {  
                     foreach my $field ('mapcrs','storecrs','makecrs','section','passback','roster') {  
                         if ($currlti{$field} ne $confhash{$itemid}{$field}) {  
                             $changes{$itemid} = 1;  
                         }  
                     }  
                     unless ($changes{$itemid}) {  
                         if ($currlti{'passback'} eq $confhash{$itemid}{'passback'}) {  
                             if ($currlti{'passbackformat'} ne $confhash{$itemid}{'passbackformat'}) {  
                                 $changes{$itemid} = 1;  
                             }  
                         }  
                     }  
                     foreach my $field ('mapcrstype','selfenroll') {  
                         unless ($changes{$itemid}) {  
                             if (ref($currlti{$field}) eq 'ARRAY') {  
                                 if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {  
                                     my @diffs = &Apache::loncommon::compare_arrays($currlti{$field},  
                                                                                    $confhash{$itemid}{$field});  
                                     if (@diffs) {  
                                         $changes{$itemid} = 1;  
                                     }  
                                 } elsif (@{$currlti{$field}} > 0) {  
                                     $changes{$itemid} = 1;  
                                 }  
                             } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') {  
                                 if (@{$confhash{$itemid}{$field}} > 0) {  
                                     $changes{$itemid} = 1;  
                                 }  
                             }  
                         }  
                     }  
                     unless ($changes{$itemid}) {  
                         if (ref($currlti{'maproles'}) eq 'HASH') {  
                             if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {  
                                 foreach my $ltirole (keys(%{$currlti{'maproles'}})) {  
                                     if ($currlti{'maproles'}{$ltirole} ne  
                                         $confhash{$itemid}{'maproles'}{$ltirole}) {  
                                         $changes{$itemid} = 1;  
                                         last;  
                                     }  
                                 }  
                                 unless ($changes{$itemid}) {  
                                     foreach my $ltirole (keys(%{$confhash{$itemid}{'maproles'}})) {  
                                         if ($confhash{$itemid}{'maproles'}{$ltirole} ne  
                                             $currlti{'maproles'}{$ltirole}) {  
                                             $changes{$itemid} = 1;  
                                             last;  
                                         }  
                                     }  
                                 }  
                             } elsif (keys(%{$currlti{'maproles'}}) > 0) {  
                                 $changes{$itemid} = 1;  
                             }  
                         } elsif (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {  
                             unless ($changes{$itemid}) {  
                                 if (keys(%{$confhash{$itemid}{'maproles'}}) > 0) {  
                                     $changes{$itemid} = 1;  
                                 }  
                             }  
                         }  
                     }  
                 }  
                 unless ($changes{$itemid}) {  
                     foreach my $field ('mapuser','lcauth','lcauthparm','topmenu','inlinemenu','callback') {  
                         if ($currlti{$field} ne $confhash{$itemid}{$field}) {  
                             $changes{$itemid} = 1;  
                         }  
                     }  
                     unless ($changes{$itemid}) {  
                         foreach my $field ('makeuser','lcmenu') {  
                             if (ref($currlti{$field}) eq 'ARRAY') {  
                                 if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {  
                                     my @diffs = &Apache::loncommon::compare_arrays($currlti{$field},  
                                                                                    $confhash{$itemid}{$field});  
                                     if (@diffs) {  
                                         $changes{$itemid} = 1;  
                                     }  
                                 } elsif (@{$currlti{$field}} > 0) {  
                                     $changes{$itemid} = 1;  
                                 }  
                             } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') {  
                                 if (@{$confhash{$itemid}{$field}} > 0) {  
                                     $changes{$itemid} = 1;  
                                 }  
                             }  
                         }  
                     }  
                 }  
             }  
         }  
         if ($is_home) {  
             my $keyitem = 'form.lti_key_'.$idx;  
             $env{$keyitem} =~ s/(`)/'/g;  
             if ($env{$keyitem} ne '') {  
                 $ltienc{$itemid}{'key'} = $env{$keyitem};  
                 unless ($changes{$itemid}) {  
                     if ($currlti{'key'} ne $env{$keyitem}) {  
                         $changes{$itemid} = 1;  
                     }  
                 }  
             }  
             my $secretitem = 'form.lti_secret_'.$idx;  
             $env{$secretitem} =~ s/(`)/'/g;  
             if ($currlti{'usable'}) {  
                 if ($env{'form.lti_changesecret_'.$idx}) {  
                     if ($env{$secretitem} ne '') {  
                         if ($privnum && $cipher) {  
                             $ltienc{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});  
                             $confhash{$itemid}{'cipher'} = $privnum;  
                         } else {  
                             $ltienc{$itemid}{'secret'} = $env{$secretitem};  
                         }  
                         $changes{$itemid} = 1;  
                     }  
                 } else {  
                     $ltienc{$itemid}{'secret'} = $currlti{'secret'};  
                     $confhash{$itemid}{'cipher'} = $currlti{'cipher'};  
                 }  
                 if (ref($ltienc{$itemid}) eq 'HASH') {  
                     if (($ltienc{$itemid}{'key'} ne '') && ($ltienc{$itemid}{'secret'} ne '')) {  
                         $confhash{$itemid}{'usable'} = 1;  
                     }  
                 }  
             } elsif ($env{$secretitem} ne '') {  
                 if ($privnum && $cipher) {  
                     $ltienc{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});  
                     $confhash{$itemid}{'cipher'} = $privnum;  
                 } else {  
                     $ltienc{$itemid}{'secret'} = $env{$secretitem};  
                 }  
                 if (ref($ltienc{$itemid}) eq 'HASH') {  
                     if (($ltienc{$itemid}{'key'} ne '') && ($ltienc{$itemid}{'key'} ne '')) {  
                         $confhash{$itemid}{'usable'} = 1;  
                     }  
                 }  
                 $changes{$itemid} = 1;  
             }  
         }  
         unless ($changes{$itemid}) {  
             foreach my $key (keys(%currlti)) {  
                 if (ref($currlti{$key}) eq 'HASH') {  
                     if (ref($confhash{$itemid}{$key}) eq 'HASH') {  
                         foreach my $innerkey (keys(%{$currlti{$key}})) {  
                             unless (exists($confhash{$itemid}{$key}{$innerkey})) {  
                                 $changes{$itemid} = 1;  
                                 last;  
                             }  
                         }  
                     } elsif (keys(%{$currlti{$key}}) > 0) {  
                         $changes{$itemid} = 1;  
                     }  
                 }  
                 last if ($changes{$itemid});  
             }  
         }  
     }  
     if (@allpos > 0) {  
         my $idx = 0;  
         foreach my $itemid (@allpos) {  
             if ($itemid ne '') {  
                 $confhash{$itemid}{'order'} = $idx;  
                 if (ref($domconfig{$action}) eq 'HASH') {  
                     if (ref($domconfig{$action}{$itemid}) eq 'HASH') {  
                         if ($domconfig{$action}{$itemid}{'order'} ne $idx) {  
                             $changes{$itemid} = 1;  
                         }  
                     }  
                 }  
                 $idx ++;  
             }  
         }  
     }  
   
     if ((keys(%changes) == 0) && (keys(%secchanges) == 0)) {  
         return &mt('No changes made.');  
     }  
   
     my %ltihash = (  
                       $action => { %confhash }  
                   );  
     my %ltienchash;  
   
     if ($is_home) {  
         %ltienchash = (  
                          $action => { %ltienc }  
                       );  
     }  
     if (keys(%secchanges)) {  
         $ltihash{'ltisec'} = \%newltisec;  
         if ($secchanges{'linkprot'}) {  
             if ($is_home) {  
                 $ltienchash{'linkprot'} = \%newltienc;  
             }  
         }  
     }  
     my $putresult = &Apache::lonnet::put_dom('configuration',\%ltihash,$dom);  
     if ($putresult eq 'ok') {  
         if (keys(%ltienchash)) {  
             &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom,undef,1);  
         }  
         $resulttext = &mt('Changes made:').'<ul>';  
         if (keys(%secchanges) > 0) {  
             $resulttext .= &lti_security_results($dom,'lti',\%secchanges,\%newltisec,\%newkeyset,\%keystore);  
             if (exists($secchanges{'linkprot'})) {  
                 $resulttext .= $linkprotoutput;  
             }  
         }  
         if (keys(%changes) > 0) {  
             my $cachetime = 24*60*60;  
             &Apache::lonnet::do_cache_new('lti',$dom,\%confhash,$cachetime);  
             if (ref($lastactref) eq 'HASH') {  
                 $lastactref->{'lti'} = 1;  
             }  
             my %bynum;  
             foreach my $itemid (sort(keys(%changes))) {  
                 if (ref($confhash{$itemid}) eq 'HASH') {  
                     my $position = $confhash{$itemid}{'order'};  
                     $bynum{$position} = $itemid;  
                 }  
             }  
             foreach my $pos (sort { $a <=> $b } keys(%bynum)) {  
                 my $itemid = $bynum{$pos};  
                 if (ref($confhash{$itemid}) eq 'HASH') {  
                     $resulttext .= '<li><b>'.$confhash{$itemid}{'consumer'}.'</b><ul>';  
                     my $position = $pos + 1;  
                     $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';  
                     foreach my $item ('version','lifetime') {  
                         if ($confhash{$itemid}{$item} ne '') {  
                             $resulttext .= '<li>'.$lt{$item}.':&nbsp;'.$confhash{$itemid}{$item}.'</li>';  
                         }  
                     }  
                     if ($ltienc{$itemid}{'key'} ne '') {  
                         $resulttext .= '<li>'.$lt{'key'}.':&nbsp;'.$ltienc{$itemid}{'key'}.'</li>';  
                     }  
                     if ($ltienc{$itemid}{'secret'} ne '') {  
                         $resulttext .= '<li>'.$lt{'secret'}.':&nbsp;['.&mt('not shown').']</li>';  
                     }  
                     if ($confhash{$itemid}{'requser'}) {  
                         if ($confhash{$itemid}{'callback'}) {  
                             $resulttext .= '<li>'.&mt('Callback setting').': '.$confhash{$itemid}{'callback'}.'</li>';  
                         } else {  
                             $resulttext .= '<li>'.&mt('Callback to logout LON-CAPA on log out from Consumer').'</li>';  
                         }  
                         if ($confhash{$itemid}{'mapuser'}) {  
                             my $shownmapuser;  
                             if ($confhash{$itemid}{'mapuser'} eq 'lis_person_sourcedid') {  
                                 $shownmapuser = $lt{'sourcedid'}.' (lis_person_sourcedid)';  
                             } elsif ($confhash{$itemid}{'mapuser'} eq 'lis_person_contact_email_primary') {  
                                 $shownmapuser = $lt{'email'}.' (lis_person_contact_email_primary)';  
                             } else {  
                                 $shownmapuser = &mt('Other').' ('.$confhash{$itemid}{'mapuser'}.')';  
                             }  
                             $resulttext .= '<li>'.&mt('LON-CAPA username').': '.$shownmapuser.'</li>';  
                         }  
                         if (ref($confhash{$itemid}{'makeuser'}) eq 'ARRAY') {  
                             if (@{$confhash{$itemid}{'makeuser'}} > 0) {  
                                 $resulttext .= '<li>'.&mt('Following roles may create user accounts: [_1]',  
                                                           join(', ',@{$confhash{$itemid}{'makeuser'}})).'<br />';  
                                 if ($confhash{$itemid}{'lcauth'} eq 'lti') {  
                                     $resulttext .= &mt('New users will only be able to authenticate via LTI').'</li>';  
                                 } else {  
                                     $resulttext .= &mt('New users will be assigned LON-CAPA authentication: [_1]',  
                                                        $confhash{$itemid}{'lcauth'});  
                                     if ($confhash{$itemid}{'lcauth'} eq 'internal') {  
                                         $resulttext .= '; '.&mt('a randomly generated password will be created');  
                                     } elsif ($confhash{$itemid}{'lcauth'} eq 'localauth') {  
                                         if ($confhash{$itemid}{'lcauthparm'} ne '') {  
                                             $resulttext .= ' '.&mt('with argument: [_1]',$confhash{$itemid}{'lcauthparm'});  
                                         }  
                                     } else {  
                                         $resulttext .= '; '.&mt('Kerberos domain: [_1]',$confhash{$itemid}{'lcauthparm'});  
                                     }  
                                 }  
                                 $resulttext .= '</li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt('User account creation not permitted.').'</li>';  
                             }  
                         }  
                         if (ref($confhash{$itemid}{'instdata'}) eq 'ARRAY') {  
                             if (@{$confhash{$itemid}{'instdata'}} > 0) {  
                                 $resulttext .= '<li>'.&mt('Institutional data will be used when creating a new user for: [_1]',  
                                                           join(', ',map { $fieldtitles{$_}; } @{$confhash{$itemid}{'instdata'}})).'</li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt('No institutional data used when creating a new user.').'</li>';  
                             }  
                         }  
                         foreach my $item ('topmenu','inlinemenu') {  
                             $resulttext .= '<li>'.$lt{$item}.':&nbsp;';  
                             if ($confhash{$itemid}{$item}) {  
                                 $resulttext .= &mt('Yes');  
                             } else {  
                                 $resulttext .= &mt('No');  
                             }  
                             $resulttext .= '</li>';  
                         }  
                         if (ref($confhash{$itemid}{'lcmenu'}) eq 'ARRAY') {  
                             if (@{$confhash{$itemid}{'lcmenu'}} > 0) {  
                                 $resulttext .= '<li>'.&mt('Menu items:').' '.  
                                                join(', ', map { $menutitles{$_}; } (@{$confhash{$itemid}{'lcmenu'}})).'</li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt('No menu items displayed in header or online menu').'</li>';  
                             }  
                         }  
                         if ($confhash{$itemid}{'crsinc'}) {  
                             if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {  
                                 my $rolemaps;  
                                 foreach my $role (@ltiroles) {  
                                     if ($confhash{$itemid}{'maproles'}{$role}) {  
                                         $rolemaps .= ('&nbsp;'x2).$role.'='.  
                                                      &Apache::lonnet::plaintext($confhash{$itemid}{'maproles'}{$role},  
                                                                                 'Course').',';  
                                     }  
                                 }  
                                 if ($rolemaps) {  
                                     $rolemaps =~ s/,$//;  
                                     $resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>';  
                                 }  
                             }  
                             if ($confhash{$itemid}{'mapcrs'}) {  
                                 $resulttext .= '<li>'.&mt('Unique course identifier').': '.$confhash{$itemid}{'mapcrs'}.'</li>';  
                             }  
                             if (ref($confhash{$itemid}{'mapcrstype'}) eq 'ARRAY') {  
                                 if (@{$confhash{$itemid}{'mapcrstype'}} > 0) {  
                                     $resulttext .= '<li>'.&mt('Mapping for the following LON-CAPA course types: [_1]',  
                                                    join(', ',map { $coursetypetitles{$_}; } @coursetypes)).  
                                                    '</li>';  
                                 } else {  
                                     $resulttext .= '<li>'.&mt('No mapping to LON-CAPA courses').'</li>';  
                                 }  
                             }  
                             if ($confhash{$itemid}{'storecrs'}) {  
                                 $resulttext .= '<li>'.&mt('Store mapping of course identifier to LON-CAPA CourseID').': '.$confhash{$itemid}{'storecrs'}.'</li>';  
                             }  
                             if ($confhash{$itemid}{'makecrs'}) {  
                                 $resulttext .= '<li>'.&mt('Instructor may create course (if absent).').'</li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt('Instructor may not create course (if absent).').'</li>';  
                             }  
                             if (ref($confhash{$itemid}{'selfenroll'}) eq 'ARRAY') {  
                                 if (@{$confhash{$itemid}{'selfenroll'}} > 0) {  
                                     $resulttext .= '<li>'.&mt('Self-enrollment for following roles: [_1]',  
                                                               join(', ',@{$confhash{$itemid}{'selfenroll'}})).  
                                                    '</li>';  
                                 } else {  
                                     $resulttext .= '<li>'.&mt('Self-enrollment not permitted').'</li>';  
                                 }  
                             }  
                             if ($confhash{$itemid}{'section'}) {  
                                 if ($confhash{$itemid}{'section'} eq 'course_section_sourcedid') {  
                                     $resulttext .= '<li>'.&mt('User section from standard field:').  
                                                          ' (course_section_sourcedid)'.'</li>';  
                                 } else {  
                                     $resulttext .= '<li>'.&mt('User section from:').' '.  
                                                           $confhash{$itemid}{'section'}.'</li>';  
                                 }  
                             } else {  
                                 $resulttext .= '<li>'.&mt('No section assignment').'</li>';  
                             }  
                             foreach my $item ('passback','roster','topmenu','inlinemenu') {  
                                 $resulttext .= '<li>'.$lt{$item}.':&nbsp;';  
                                 if ($confhash{$itemid}{$item}) {  
                                     $resulttext .= &mt('Yes');  
                                     if ($item eq 'passback') {  
                                         if ($confhash{$itemid}{'passbackformat'} eq '1.0') {  
                                             $resulttext .= '&nbsp;('.&mt('Outcomes Extension (1.0)').')';  
                                         } elsif ($confhash{$itemid}{'passbackformat'} eq '1.1') {  
                                             $resulttext .= '&nbsp;('.&mt('Outcomes Service (1.1)').')';  
                                         }  
                                     }  
                                 } else {  
                                     $resulttext .= &mt('No');  
                                 }  
                                 $resulttext .= '</li>';  
                             }  
                             if (ref($confhash{$itemid}{'lcmenu'}) eq 'ARRAY') {  
                                 if (@{$confhash{$itemid}{'lcmenu'}} > 0) {  
                                     $resulttext .= '<li>'.&mt('Menu items:').' '.  
                                                    join(', ', map { $menutitles{$_}; } (@{$confhash{$itemid}{'lcmenu'}})).'</li>';  
                                 } else {  
                                     $resulttext .= '<li>'.&mt('No menu items displayed in header or online menu').'</li>';  
                                 }  
                             }  
                         }  
                     }  
                     $resulttext .= '</ul></li>';  
                 }  
             }  
             if (keys(%deletions)) {  
                 foreach my $itemid (sort { $a <=> $b } keys(%deletions)) {  
                     $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';  
                 }  
             }  
         }  
         $resulttext .= '</ul>';  
         if (ref($lastactref) eq 'HASH') {  
             if (($secchanges{'encrypt'}) || ($secchanges{'private'})) {  
                 $lastactref->{'domdefaults'} = 1;  
             }  
         }  
     } else {  
         $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';  
     }  
     if ($errors) {  
         $resulttext .= &mt('The following errors occurred: ').'<ul>'.  
                        $errors.'</ul>';  
     }  
     return $resulttext;  
 }  
   
 sub get_priv_creds {  
     my ($dom,$home,$encchg,$encrypt,$storedsec) = @_;  
     my ($needenc,$cipher,$privnum);  
     my %domdefs = &Apache::lonnet::get_domain_defaults($dom);  
     if (($encchg) && (ref($encrypt) eq 'HASH')) {  
         $needenc = $encrypt->{'consumers'}  
     } else {  
         $needenc = $domdefs{'ltienc_consumers'};  
     }  
     if ($needenc) {  
         if (($storedsec eq 'ok') || ((ref($domdefs{'ltiprivhosts'}) eq 'ARRAY') &&  
                                      (grep(/^\Q$home\E$/,@{$domdefs{'ltiprivhosts'}})))) {  
                         my %privhash  = &Apache::lonnet::restore_dom('lti','private',$dom,$home,1);  
             my $privkey = $privhash{'key'};  
             $privnum = $privhash{'version'};  
             if (($privnum) && ($privkey ne '')) {  
                 $cipher = Crypt::CBC->new({'key'     => $privkey,  
                                           'cipher'  => 'DES'});  
             }  
         }  
     }  
     return ($cipher,$privnum);  
 }  
   
 sub get_lti_id {  
     my ($domain,$consumer) = @_;  
     # get lock on lti db  
     my $lockhash = {  
                       lock => $env{'user.name'}.  
                               ':'.$env{'user.domain'},  
                    };  
     my $tries = 0;  
     my $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain);  
     my ($id,$error);  
   
     while (($gotlock ne 'ok') && ($tries<10)) {  
         $tries ++;  
         sleep (0.1);  
         $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain);  
     }  
     if ($gotlock eq 'ok') {  
         my %currids = &Apache::lonnet::dump_dom('lti',$domain);  
         if ($currids{'lock'}) {  
             delete($currids{'lock'});  
             if (keys(%currids)) {  
                 my @curr = sort { $a <=> $b } keys(%currids);  
                 if ($curr[-1] =~ /^\d+$/) {  
                     $id = 1 + $curr[-1];  
                 }  
             } else {  
                 $id = 1;  
             }  
             if ($id) {  
                 unless (&Apache::lonnet::newput_dom('lti',{ $id => $consumer },$domain) eq 'ok') {  
                     $error = 'nostore';  
                 }  
             } else {  
                 $error = 'nonumber';  
             }  
         }  
         my $dellockoutcome = &Apache::lonnet::del_dom('lti',['lock'],$domain);  
     } else {  
         $error = 'nolock';  
     }  
     return ($id,$error);  
 }  
   
 sub modify_autoenroll {  sub modify_autoenroll {
     my ($dom,$lastactref,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,%changes);      my ($resulttext,%changes);
Line 14781  sub modify_contacts { Line 12265  sub modify_contacts {
                     $contacts_hash{'contacts'}{'overrides'}{$type}{'include'} = $includeloc{$type}.':'.&escape($includestr{$type});                      $contacts_hash{'contacts'}{'overrides'}{$type}{'include'} = $includeloc{$type}.':'.&escape($includestr{$type});
                     $newsetting{'override_'.$type}{'include'} = $contacts_hash{'contacts'}{'overrides'}{$type}{'include'};                      $newsetting{'override_'.$type}{'include'} = $contacts_hash{'contacts'}{'overrides'}{$type}{'include'};
                 }                  }
             }              }    
         }          }
     }      }
     if (keys(%currsetting) > 0) {      if (keys(%currsetting) > 0) {
Line 15231  sub modify_contacts { Line 12715  sub modify_contacts {
         }          }
     } else {      } else {
         $resulttext = '<span class="LC_error">'.          $resulttext = '<span class="LC_error">'.
             &mt('An error occurred: [_1]',$putresult).'</span>';              &mt('An error occurred: [_1].',$putresult).'</span>';
     }      }
     return $resulttext;      return $resulttext;
 }  }
Line 15403  sub modify_passwords { Line 12887  sub modify_passwords {
     }      }
     if ($env{'form.passwords_customfile.filename'} ne '') {      if ($env{'form.passwords_customfile.filename'} ne '') {
         my $servadm = $r->dir_config('lonAdmEMail');          my $servadm = $r->dir_config('lonAdmEMail');
           my $servadm = $r->dir_config('lonAdmEMail');
         my ($configuserok,$author_ok,$switchserver) =          my ($configuserok,$author_ok,$switchserver) =
             &config_check($dom,$confname,$servadm);              &config_check($dom,$confname,$servadm);
         my $error;          my $error;
Line 15411  sub modify_passwords { Line 12896  sub modify_passwords {
                 $error = &mt("Upload of file containing domain-specific text is not permitted to this server: [_1]",$switchserver);                  $error = &mt("Upload of file containing domain-specific text is not permitted to this server: [_1]",$switchserver);
             } else {              } else {
                 if ($author_ok eq 'ok') {                  if ($author_ok eq 'ok') {
                     my $modified = [];  
                     my ($result,$customurl) =                      my ($result,$customurl) =
                         &Apache::lonconfigsettings::publishlogo($r,'upload','passwords_customfile',$dom,                          &publishlogo($r,'upload','passwords_customfile',$dom,
                                                                 $confname,'customtext/resetpw','','',$customfn,                                       $confname,'customtext/resetpw','','',$customfn);
                                                                 $modified);  
                     if ($result eq 'ok') {                      if ($result eq 'ok') {
                         $newvalues{'resetcustom'} = $customurl;                          $newvalues{'resetcustom'} = $customurl;
                         $changes{'reset'} = 1;                          $changes{'reset'} = 1;
                         &update_modify_urls($r,$modified);  
                     } else {                      } else {
                         $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$customfn,$result);                          $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$customfn,$result);
                     }                      }
Line 15472  sub modify_passwords { Line 12954  sub modify_passwords {
             $updatedefaults = 1;              $updatedefaults = 1;
         }          }
     }      }
     &password_rule_changes('passwords',\%newvalues,\%current,\%changes);      foreach my $rule ('min','max','numsaved') {
           $env{'form.passwords_'.$rule} =~ s/^\s+|\s+$//g;
           my $ruleok;
           if ($rule eq 'min') {
               if ($env{'form.passwords_'.$rule} =~ /^\d+$/) {
                   if ($env{'form.passwords_'.$rule} >= $Apache::lonnet::passwdmin) {
                       $ruleok = 1;
                   }
               }
           } elsif (($env{'form.passwords_'.$rule} =~ /^\d+$/) &&
                    ($env{'form.passwords_'.$rule} ne '0')) {
               $ruleok = 1;
           }
           if ($ruleok) {
               $newvalues{$rule} = $env{'form.passwords_'.$rule};
               if (exists($current{$rule})) {
                   if ($newvalues{$rule} ne $current{$rule}) {
                       $changes{'rules'} = 1;
                   }
               } elsif ($rule eq 'min') {
                   if ($staticdefaults{$rule} ne $newvalues{$rule}) {
                       $changes{'rules'} = 1;
                   }
               } else {
                   $changes{'rules'} = 1;
               }
           } elsif (exists($current{$rule})) {
               $changes{'rules'} = 1;
           }
       }
       my @posschars = &Apache::loncommon::get_env_multiple('form.passwords_chars');
       my @chars;
       foreach my $item (sort(@posschars)) {
           if ($item =~ /^(uc|lc|num|spec)$/) {
               push(@chars,$item);
           }
       }
       $newvalues{'chars'} = \@chars;
       unless ($changes{'rules'}) {
           if (ref($current{'chars'}) eq 'ARRAY') {
               my @diffs = &Apache::loncommon::compare_arrays($current{'chars'},\@chars);
               if (@diffs > 0) {
                   $changes{'rules'} = 1;
               }
           } else {
               if (@chars > 0) {
                   $changes{'rules'} = 1;
               }
           }
       }
     my %crsownerchg = (      my %crsownerchg = (
                         by => [],                          by => [],
                         for => [],                          for => [],
Line 15732  sub modify_passwords { Line 13263  sub modify_passwords {
     return $resulttext;      return $resulttext;
 }  }
   
 sub password_rule_changes {  
     my ($prefix,$newvalues,$current,$changes) = @_;  
     return unless ((ref($newvalues) eq 'HASH') &&  
                    (ref($current) eq 'HASH') &&  
                    (ref($changes) eq 'HASH'));  
     my (@rules,%staticdefaults);  
     if ($prefix eq 'passwords') {  
         @rules = ('min','max','numsaved');  
     } elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {  
         @rules = ('min','max');  
     }  
     $staticdefaults{'min'} = $Apache::lonnet::passwdmin;  
     foreach my $rule (@rules) {  
         $env{'form.'.$prefix.'_'.$rule} =~ s/^\s+|\s+$//g;  
         my $ruleok;  
         if ($rule eq 'min') {  
             if ($env{'form.'.$prefix.'_'.$rule} =~ /^\d+$/) {  
                 if ($env{'form.'.$prefix.'_'.$rule} >= $staticdefaults{$rule}) {  
                     $ruleok = 1;  
                 }  
             }  
         } elsif (($env{'form.'.$prefix.'_'.$rule} =~ /^\d+$/) &&  
                  ($env{'form.'.$prefix.'_'.$rule} ne '0')) {  
             $ruleok = 1;  
         }  
         if ($ruleok) {  
             $newvalues->{$rule} = $env{'form.'.$prefix.'_'.$rule};  
             if (exists($current->{$rule})) {  
                 if ($newvalues->{$rule} ne $current->{$rule}) {  
                     $changes->{'rules'} = 1;  
                 }  
             } elsif ($rule eq 'min') {  
                 if ($staticdefaults{$rule} ne $newvalues->{$rule}) {  
                     $changes->{'rules'} = 1;  
                 }  
             } else {  
                 $changes->{'rules'} = 1;  
             }  
         } elsif (exists($current->{$rule})) {  
             $changes->{'rules'} = 1;  
         }  
     }  
     my @posschars = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_chars');  
     my @chars;  
     foreach my $item (sort(@posschars)) {  
         if ($item =~ /^(uc|lc|num|spec)$/) {  
             push(@chars,$item);  
         }  
     }  
     $newvalues->{'chars'} = \@chars;  
     unless ($changes->{'rules'}) {  
         if (ref($current->{'chars'}) eq 'ARRAY') {  
             my @diffs = &Apache::loncommon::compare_arrays($current->{'chars'},\@chars);  
             if (@diffs > 0) {  
                 $changes->{'rules'} = 1;  
             }  
         } else {  
             if (@chars > 0) {  
                 $changes->{'rules'} = 1;  
             }  
         }  
     }  
     return;  
 }  
   
 sub modify_usercreation {  sub modify_usercreation {
     my ($dom,%domconfig) = @_;      my ($dom,%domconfig) = @_;
     my ($resulttext,%curr_usercreation,%changes,%authallowed,%cancreate,%save_usercreate);      my ($resulttext,%curr_usercreation,%changes,%authallowed,%cancreate,%save_usercreate);
Line 15881  sub modify_usercreation { Line 13347  sub modify_usercreation {
     }      }
   
     my @authen_contexts = ('author','course','domain');      my @authen_contexts = ('author','course','domain');
     my @authtypes = ('int','krb4','krb5','loc','lti');      my @authtypes = ('int','krb4','krb5','loc');
     my %authhash;      my %authhash;
     foreach my $item (@authen_contexts) {      foreach my $item (@authen_contexts) {
         my @authallowed =  &Apache::loncommon::get_env_multiple('form.'.$item.'_auth');          my @authallowed =  &Apache::loncommon::get_env_multiple('form.'.$item.'_auth');
Line 16096  sub modify_selfcreation { Line 13562  sub modify_selfcreation {
 # Populate $cancreate{'selfcreate'} array reference with types of user, for which self-creation of user accounts  # Populate $cancreate{'selfcreate'} array reference with types of user, for which self-creation of user accounts
 # is permitted.  # is permitted.
 #  #
   
     my ($emailrules,$emailruleorder) = &Apache::lonnet::inst_userrules($dom,'email');      my ($emailrules,$emailruleorder) = &Apache::lonnet::inst_userrules($dom,'email');
   
     my (@statuses,%email_rule);      my (@statuses,%email_rule);
Line 17073  sub modify_defaults { Line 14540  sub modify_defaults {
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);      my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
     my @items = ('auth_def','auth_arg_def','lang_def','timezone_def','datelocale_def',      my @items = ('auth_def','auth_arg_def','lang_def','timezone_def','datelocale_def',
                  'portal_def');                   'portal_def');
     my @authtypes = ('internal','krb4','krb5','localauth','lti');      my @authtypes = ('internal','krb4','krb5','localauth');
     foreach my $item (@items) {      foreach my $item (@items) {
         $newvalues{$item} = $env{'form.'.$item};          $newvalues{$item} = $env{'form.'.$item};
         if ($item eq 'auth_def') {          if ($item eq 'auth_def') {
Line 17110  sub modify_defaults { Line 14577  sub modify_defaults {
             }              }
         } elsif ($item eq 'portal_def') {          } elsif ($item eq 'portal_def') {
             if ($newvalues{$item} ne '') {              if ($newvalues{$item} ne '') {
                 if ($newvalues{$item} =~ /^https?\:\/\/(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])\/?$/) {                  unless ($newvalues{$item} =~ /^https?\:\/\/(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])\/?$/) {
                     foreach my $field ('email','web') {  
                         if ($env{'form.'.$item.'_'.$field}) {  
                             $newvalues{$item.'_'.$field} = $env{'form.'.$item.'_'.$field};  
                         }  
                     }  
                 } else {  
                     push(@errors,$item);                      push(@errors,$item);
                 }                  }
             }              }
         }          }
         if (grep(/^\Q$item\E$/,@errors)) {          if (grep(/^\Q$item\E$/,@errors)) {
             $newvalues{$item} = $domdefaults{$item};              $newvalues{$item} = $domdefaults{$item};
             if ($item eq 'portal_def') {  
                 if ($domdefaults{$item}) {  
                     foreach my $field ('email','web') {  
                         if (exists($domdefaults{$item.'_'.$field})) {  
                             $newvalues{$item.'_'.$field} = $domdefaults{$item.'_'.$field};  
                         }  
                     }  
                 }  
             }  
         } elsif ($domdefaults{$item} ne $newvalues{$item}) {          } elsif ($domdefaults{$item} ne $newvalues{$item}) {
             $changes{$item} = 1;              $changes{$item} = 1;
         }          }
         if ($item eq 'portal_def') {  
             unless (grep(/^\Q$item\E$/,@errors)) {  
                 if ($newvalues{$item} eq '') {  
                     foreach my $field ('email','web') {  
                         if (exists($domdefaults{$item.'_'.$field})) {  
                             delete($domdefaults{$item.'_'.$field});  
                         }  
                     }  
                 } else {  
                     unless ($changes{$item}) {  
                         foreach my $field ('email','web') {  
                             if ($domdefaults{$item.'_'.$field} ne $newvalues{$item.'_'.$field}) {  
                                 $changes{$item} = 1;  
                                 last;  
                             }  
                         }  
                     }  
                     foreach my $field ('email','web') {  
                         if ($newvalues{$item.'_'.$field}) {  
                             $domdefaults{$item.'_'.$field} = $newvalues{$item.'_'.$field};  
                         } elsif (exists($domdefaults{$item.'_'.$field})) {  
                             delete($domdefaults{$item.'_'.$field});  
                         }  
                     }  
                 }  
             }  
         }  
         $domdefaults{$item} = $newvalues{$item};          $domdefaults{$item} = $newvalues{$item};
     }      }
     my %staticdefaults = (      my %staticdefaults = (
Line 17358  sub modify_defaults { Line 14783  sub modify_defaults {
                                           krb4       => 'krb4',                                            krb4       => 'krb4',
                                           krb5       => 'krb5',                                            krb5       => 'krb5',
                                           localauth  => 'loc',                                            localauth  => 'loc',
                                           lti        => 'lti',  
                         );                          );
                         $value = $authnames{$shortauth{$value}};                          $value = $authnames{$shortauth{$value}};
                     }                      }
                     $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$item},$value).'</li>';                      $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$item},$value).'</li>';
                     $mailmsgtext .= "$title->{$item} set to $value\n";                      $mailmsgtext .= "$title->{$item} set to $value\n";  
                     if ($item eq 'portal_def') {  
                         if ($env{'form.'.$item} ne '') {  
                             foreach my $field ('email','web') {  
                                 $value = $env{'form.'.$item.'_'.$field};  
                                 if ($value) {  
                                     $value = &mt('Yes');  
                                 } else {  
                                     $value = &mt('No');  
                                 }  
                                 $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$field},$value).'</li>';  
                             }  
                         }  
                     }  
                 }                  }
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
Line 17431  sub modify_scantron { Line 14842  sub modify_scantron {
                 $error = &mt("Upload of bubblesheet format file is not permitted to this server: [_1]",$switchserver);                  $error = &mt("Upload of bubblesheet format file is not permitted to this server: [_1]",$switchserver);
             } else {              } else {
                 if ($author_ok eq 'ok') {                  if ($author_ok eq 'ok') {
                     my $modified = [];  
                     my ($result,$scantronurl) =                      my ($result,$scantronurl) =
                         &Apache::lonconfigsettings::publishlogo($r,'upload','scantronformat',$dom,                          &publishlogo($r,'upload','scantronformat',$dom,
                                                                 $confname,'scantron','','',$custom,                                       $confname,'scantron','','',$custom);
                                                                 $modified);  
                     if ($result eq 'ok') {                      if ($result eq 'ok') {
                         $confhash{'scantron'}{'scantronformat'} = $scantronurl;                          $confhash{'scantron'}{'scantronformat'} = $scantronurl;
                         $changes{'scantronformat'} = 1;                          $changes{'scantronformat'} = 1;
                         &update_modify_urls($r,$modified);  
                     } else {                      } else {
                         $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$custom,$result);                          $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$custom,$result);
                     }                      }
Line 17591  sub modify_scantron { Line 14999  sub modify_scantron {
         $resulttext = &mt('No changes made to bubblesheet format settings');          $resulttext = &mt('No changes made to bubblesheet format settings');
     }      }
     if ($errors) {      if ($errors) {
         $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.          $resulttext .= &mt('The following errors occurred: ').'<ul>'.
                        $errors.'</ul></p>';                         $errors.'</ul>';
     }      }
     return $resulttext;      return $resulttext;
 }  }
Line 18323  sub modify_coursedefaults { Line 15731  sub modify_coursedefaults {
                            'uselcmath'       => 'on',                             'uselcmath'       => 'on',
                            'usejsme'         => 'on',                             'usejsme'         => 'on',
                            'inline_chem'     => 'on',                             'inline_chem'     => 'on',
                            'ltiauth'         => 'off',  
                          );                           );
     my @toggles = ('uselcmath','usejsme','inline_chem','ltiauth');      my @toggles = ('uselcmath','usejsme','inline_chem');
     my @numbers = ('anonsurvey_threshold','uploadquota_official','uploadquota_unofficial',      my @numbers = ('anonsurvey_threshold','uploadquota_official','uploadquota_unofficial',
                    'uploadquota_community','uploadquota_textbook','mysqltables_official',                     'uploadquota_community','uploadquota_textbook','mysqltables_official',
                    'mysqltables_unofficial','mysqltables_community','mysqltables_textbook');                     'mysqltables_unofficial','mysqltables_community','mysqltables_textbook');
Line 18335  sub modify_coursedefaults { Line 15742  sub modify_coursedefaults {
                            uploadquota          => 500,                             uploadquota          => 500,
                            postsubmit           => 60,                             postsubmit           => 60,
                            mysqltables          => 172800,                             mysqltables          => 172800,
                            domexttool           => 1,  
                          );                           );
     my %texoptions = (      my %texoptions = (
                         MathJax  => 'MathJax',                          MathJax  => 'MathJax',
Line 18527  sub modify_coursedefaults { Line 15933  sub modify_coursedefaults {
                 $changes{'postsubmit'} = 1;                  $changes{'postsubmit'} = 1;
             }              }
         }          }
         my (%newdomexttool,%newexttool,%olddomexttool,%oldexttool);  
         map { $newdomexttool{$_} = 1; } &Apache::loncommon::get_env_multiple('form.domexttool');  
         map { $newexttool{$_} = 1; } &Apache::loncommon::get_env_multiple('form.exttool');  
         if (ref($domconfig{'coursedefaults'}{'domexttool'}) eq 'HASH') {  
             %olddomexttool = %{$domconfig{'coursedefaults'}{'domexttool'}};  
         } else {  
            foreach my $type (@types) {  
                if ($staticdefaults{'domexttool'}) {  
                    $olddomexttool{$type} = 1;  
                } else {  
                    $olddomexttool{$type} = 0;  
                }  
             }  
         }  
         if (ref($domconfig{'coursedefaults'}{'exttool'}) eq 'HASH') {  
             %oldexttool = %{$domconfig{'coursedefaults'}{'exttool'}};  
         } else {  
             foreach my $type (@types) {  
                if ($staticdefaults{'exttool'}) {  
                    $oldexttool{$type} = 1;  
                } else {  
                    $oldexttool{$type} = 0;  
                }  
             }  
         }  
         foreach my $type (@types) {  
             unless ($newdomexttool{$type}) {  
                 $newdomexttool{$type} = 0;  
             }  
             unless ($newexttool{$type}) {  
                 $newexttool{$type} = 0;  
             }  
             if ($newdomexttool{$type} != $olddomexttool{$type}) {  
                 $changes{'domexttool'} = 1;  
             }  
             if ($newexttool{$type} != $oldexttool{$type}) {  
                 $changes{'exttool'} = 1;  
             }  
         }  
         $defaultshash{'coursedefaults'}{'domexttool'} = \%newdomexttool;  
         $defaultshash{'coursedefaults'}{'exttool'} = \%newexttool;  
     }      }
     my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,      my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
                                              $dom);                                               $dom);
Line 18577  sub modify_coursedefaults { Line 15942  sub modify_coursedefaults {
             if (($changes{'uploadquota'}) || ($changes{'postsubmit'}) ||              if (($changes{'uploadquota'}) || ($changes{'postsubmit'}) ||
                 ($changes{'coursecredits'}) || ($changes{'uselcmath'}) || ($changes{'usejsme'}) ||                  ($changes{'coursecredits'}) || ($changes{'uselcmath'}) || ($changes{'usejsme'}) ||
                 ($changes{'canclone'}) || ($changes{'mysqltables'}) || ($changes{'texengine'}) ||                  ($changes{'canclone'}) || ($changes{'mysqltables'}) || ($changes{'texengine'}) ||
                 ($changes{'inline_chem'}) || ($changes{'ltiauth'}) || ($changes{'domexttool'}) ||                  ($changes{'inline_chem'})) {
                 ($changes{'exttool'})) {                  foreach my $item ('uselcmath','usejsme','inline_chem','texengine') {
                 foreach my $item ('uselcmath','usejsme','inline_chem','texengine','ltiauth') {  
                     if ($changes{$item}) {                      if ($changes{$item}) {
                         $domdefaults{$item}=$defaultshash{'coursedefaults'}{$item};                          $domdefaults{$item}=$defaultshash{'coursedefaults'}{$item};
                     }                      }
Line 18622  sub modify_coursedefaults { Line 15986  sub modify_coursedefaults {
                         $domdefaults{'canclone'}=$defaultshash{'coursedefaults'}{'canclone'};                          $domdefaults{'canclone'}=$defaultshash{'coursedefaults'}{'canclone'};
                     }                      }
                 }                  }
                 if ($changes{'domexttool'}) {  
                     if (ref($defaultshash{'coursedefaults'}{'domexttool'}) eq 'HASH') {  
                         foreach my $type (@types) {  
                             $domdefaults{$type.'domexttool'}=$defaultshash{'coursedefaults'}{'domexttool'}{$type};  
                         }  
                     }  
                 }  
                 if ($changes{'exttool'}) {  
                     if (ref($defaultshash{'coursedefaults'}{'exttool'}) eq 'HASH') {  
                         foreach my $type (@types) {  
                             $domdefaults{$type.'exttool'}=$defaultshash{'coursedefaults'}{'exttool'}{$type};  
                         }  
                     }  
                 }  
                 my $cachetime = 24*60*60;                  my $cachetime = 24*60*60;
                 &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);                  &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
                 if (ref($lastactref) eq 'HASH') {                  if (ref($lastactref) eq 'HASH') {
Line 18675  sub modify_coursedefaults { Line 16025  sub modify_coursedefaults {
                                        '<li>'.&mt('Official courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'official'}.'</b>').'</li>'.                                         '<li>'.&mt('Official courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'official'}.'</b>').'</li>'.
                                        '<li>'.&mt('Unofficial courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'unofficial'}.'</b>').'</li>'.                                         '<li>'.&mt('Unofficial courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'unofficial'}.'</b>').'</li>'.
                                        '<li>'.&mt('Textbook courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'textbook'}.'</b>').'</li>'.                                         '<li>'.&mt('Textbook courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'textbook'}.'</b>').'</li>'.
   
                                        '<li>'.&mt('Communities: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'community'}.'</b>').'</li>'.                                         '<li>'.&mt('Communities: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'community'}.'</b>').'</li>'.
                                        '</ul>'.                                         '</ul>'.
                                        '</li>';                                         '</li>';
Line 18757  sub modify_coursedefaults { Line 16108  sub modify_coursedefaults {
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('By default, only course owner and coordinators may clone a course.').'</li>';                          $resulttext .= '<li>'.&mt('By default, only course owner and coordinators may clone a course.').'</li>';
                     }                      }
                 } elsif ($item eq 'ltiauth') {  
                     if ($env{'form.'.$item} eq '1') {  
                         $resulttext .= '<li>'.&mt('LTI launch of deep-linked URL need not require re-authentication').'</li>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('LTI launch of deep-linked URL will require re-authentication').'</li>';  
                     }  
                 } elsif ($item eq 'domexttool') {  
                     my @noyes = (&mt('no'),&mt('yes'));  
                     if (ref($defaultshash{'coursedefaults'}{'domexttool'}) eq 'HASH') {  
                         $resulttext .= '<li>'.&mt('External Tools defined in the domain may be used as follows:').'<ul>'.  
                                        '<li>'.&mt('Official courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'official'}].'</b>').'</li>'.  
                                        '<li>'.&mt('Unofficial courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'unofficial'}].'</b>').'</li>'.  
                                        '<li>'.&mt('Textbook courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'textbook'}].'</b>').'</li>'.  
                                        '<li>'.&mt('Placement tests: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'placement'}].'</b>').'</li>'.  
                                        '<li>'.&mt('Communities: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'community'}].'</b>').'</li>'.  
                                        '</ul>'.  
                                        '</li>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('External Tools defined in the domain may be used in all course types, by default').'</li>';  
                     }  
                 } elsif ($item eq 'exttool') {  
                     my @noyes = (&mt('no'),&mt('yes'));  
                     if (ref($defaultshash{'coursedefaults'}{'exttool'}) eq 'HASH') {  
                         $resulttext .= '<li>'.&mt('External Tools can be defined and configured in course containers as follows:').'<ul>'.  
                                        '<li>'.&mt('Official courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'official'}].'</b>').'</li>'.  
                                        '<li>'.&mt('Unofficial courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'unofficial'}].'</b>').'</li>'.  
                                        '<li>'.&mt('Textbook courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'textbook'}].'</b>').'</li>'.  
                                        '<li>'.&mt('Placement tests: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'placement'}].'</b>').'</li>'.  
                                        '<li>'.&mt('Communities: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'community'}].'</b>').'</li>'.  
                                        '</ul>'.  
                                        '</li>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('External Tools can not be defined in any course types, by default').'</li>';  
                     }  
                 }                  }
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
Line 19349  sub modify_wafproxy { Line 16666  sub modify_wafproxy {
                     }                      }
                 }                  }
             }              }
             $output .= '</ul>';  
         } else {          } else {
             $output = '<span class="LC_error">'.              $output = '<span class="LC_error">'.
                       &mt('An error occurred: [_1]',$putresult).'</span>';                        &mt('An error occurred: [_1]',$putresult).'</span>';
Line 19703  sub modify_usersessions { Line 17019  sub modify_usersessions {
                                         }                                          }
                                     } else {                                      } else {
                                         if ($type eq 'version') {                                          if ($type eq 'version') {
                                             $newvalue .= ' '.&mt('(or later)');                                              $newvalue .= ' '.&mt('(or later)'); 
                                         }                                          }
                                         $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>';                                          $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>';
                                     }                                      }
Line 20586  function updateNewSpares(formname,lonhos Line 17902  function updateNewSpares(formname,lonhos
 function checkNewSpares(lonhost,type) {  function checkNewSpares(lonhost,type) {
     var newSpare = document.getElementById('newspare_'+type+'_'+lonhost);      var newSpare = document.getElementById('newspare_'+type+'_'+lonhost);
     var chosen =  newSpare.options[newSpare.selectedIndex].value;      var chosen =  newSpare.options[newSpare.selectedIndex].value;
     if (chosen != '') {      if (chosen != '') { 
         var othertype;          var othertype;
         var othernewSpare;          var othernewSpare;
         if (type == 'primary') {          if (type == 'primary') {
Line 20720  function toggleDisplay(domForm,caller) { Line 18036  function toggleDisplay(domForm,caller) {
         var dispval = 'block';          var dispval = 'block';
         var selfcreateRegExp = /^cancreate_emailverified/;          var selfcreateRegExp = /^cancreate_emailverified/;
         if (caller == 'emailoptions') {          if (caller == 'emailoptions') {
             optionsElement = domForm.cancreate_email;              optionsElement = domForm.cancreate_email; 
         }          }
         if (caller == 'studentsubmission') {          if (caller == 'studentsubmission') {
             optionsElement = domForm.postsubmit;              optionsElement = domForm.postsubmit;
Line 20775  sub devalidate_remote_domconfs { Line 18091  sub devalidate_remote_domconfs {
     my %servers = &Apache::lonnet::internet_dom_servers($dom);      my %servers = &Apache::lonnet::internet_dom_servers($dom);
     my %thismachine;      my %thismachine;
     map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids();      map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids();
     my @posscached = ('domainconfig','domdefaults','ltitools','usersessions',      my @posscached = ('domainconfig','domdefaults','usersessions',
                       'directorysrch','passwdconf','cats','proxyalias','proxysaml',                        'directorysrch','passwdconf','cats','proxyalias','proxysaml',
                       'ipaccess');                        'ipaccess');
     my %cache_by_lonhost;      my %cache_by_lonhost;

Removed from v.1.160.6.118.2.14  
changed lines
  Added in v.1.160.6.122


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