Diff for /loncom/interface/domainprefs.pm between versions 1.160.6.104 and 1.347

version 1.160.6.104, 2020/02/09 05:18:20 version 1.347, 2019/01/28 21:36:45
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, and textbook).  In each case the radio buttons   (official, unofficial, community, textbook, placement, and lti).  
 allow the selection of one of four values:  In each case the radio buttons 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 170  use Apache::loncoursequeueadmin(); Line 170  use Apache::loncoursequeueadmin();
 use LONCAPA qw(:DEFAULT :match);  use LONCAPA qw(:DEFAULT :match);
 use LONCAPA::Enrollment;  use LONCAPA::Enrollment;
 use LONCAPA::lonauthcgi();  use LONCAPA::lonauthcgi();
   use LONCAPA::SSL;
 use File::Copy;  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 );
   
 my $registered_cleanup;  my $registered_cleanup;
 my $modified_urls;  my $modified_urls;
Line 216  sub handler { Line 218  sub handler {
                 'contacts','defaults','scantron','coursecategories',                  'contacts','defaults','scantron','coursecategories',
                 'serverstatuses','requestcourses','helpsettings',                  'serverstatuses','requestcourses','helpsettings',
                 'coursedefaults','usersessions','loadbalancing',                  'coursedefaults','usersessions','loadbalancing',
                 'requestauthor','selfenrollment','inststatus','passwords'],$dom);                  'requestauthor','selfenrollment','inststatus',
     my @prefs_order = ('rolecolors','login','defaults','passwords','quotas','autoenroll',                  'ltitools','ssl','trust','lti'],$dom);
       my %encconfig =
           &Apache::lonnet::get_dom('encconfig',['ltitools','lti'],$dom);
       if (ref($domconfig{'ltitools'}) eq 'HASH') {
           if (ref($encconfig{'ltitools'}) eq 'HASH') {
               foreach my $id (keys(%{$domconfig{'ltitools'}})) {
                   if ((ref($domconfig{'ltitools'}{$id}) eq 'HASH') &&
                       (ref($encconfig{'ltitools'}{$id}) eq 'HASH')) {
                       foreach my $item ('key','secret') {
                           $domconfig{'ltitools'}{$id}{$item} = $encconfig{'ltitools'}{$id}{$item};
                       }
                   }
               }
           }
       }
       if (ref($domconfig{'lti'}) eq 'HASH') {
           if (ref($encconfig{'lti'}) eq 'HASH') {
               foreach my $id (keys(%{$domconfig{'lti'}})) {
                   if ((ref($domconfig{'lti'}{$id}) eq 'HASH') &&
                       (ref($encconfig{'lti'}{$id}) eq 'HASH')) {
                       foreach my $item ('key','secret') {
                           $domconfig{'lti'}{$id}{$item} = $encconfig{'lti'}{$id}{$item};
                       }
                   }
               }
           }
       }
       my @prefs_order = ('rolecolors','login','defaults','quotas','autoenroll',
                        'autoupdate','autocreate','directorysrch','contacts',                         'autoupdate','autocreate','directorysrch','contacts',
                        'usercreation','selfcreation','usermodification','scantron',                         'usercreation','selfcreation','usermodification','scantron',
                        'requestcourses','requestauthor','coursecategories',                         'requestcourses','requestauthor','coursecategories',
                        'serverstatuses','helpsettings','coursedefaults',                         'serverstatuses','helpsettings','coursedefaults',
                        'selfenrollment','usersessions');                         'ltitools','selfenrollment','usersessions','ssl','trust','lti');
     my %existing;      my %existing;
     if (ref($domconfig{'loadbalancing'}) eq 'HASH') {      if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
         %existing = %{$domconfig{'loadbalancing'}};          %existing = %{$domconfig{'loadbalancing'}};
Line 262  sub handler { Line 291  sub handler {
                       help => 'Domain_Configuration_LangTZAuth',                        help => 'Domain_Configuration_LangTZAuth',
                       header => [{col1 => 'Setting',                        header => [{col1 => 'Setting',
                                   col2 => 'Value'},                                    col2 => 'Value'},
                                    {col1 => 'Internal Authentication',
                                     col2 => 'Value'},
                                  {col1 => 'Institutional user types',                                   {col1 => 'Institutional user types',
                                   col2 => 'Name displayed'}],                                    col2 => 'Name displayed'}],
                       print => \&print_defaults,                        print => \&print_defaults,
                       modify => \&modify_defaults,                        modify => \&modify_defaults,
                     },                      },
         'passwords' =>  
                     { text => 'Passwords (Internal authentication)',  
                       help => 'Domain_Configuration_Passwords',  
                       header => [{col1 => 'Resetting Forgotten Password',  
                                   col2 => 'Settings'},  
                                  {col1 => 'Encryption of Stored Passwords (Internal Auth)',  
                                   col2 => 'Settings'},  
                                  {col1 => 'Rules for LON-CAPA Passwords',  
                                   col2 => 'Settings'},  
                                  {col1 => 'Course Owner Changing Student Passwords',  
                                   col2 => 'Settings'}],  
                       print => \&print_passwords,  
                       modify => \&modify_passwords,  
                     },  
         'quotas' =>           'quotas' => 
                     { text => 'Blogs, personal web pages, webDAV/quotas, portfolios',                      { text => 'Blogs, personal web pages, webDAV/quotas, portfolios',
                       help => 'Domain_Configuration_Quotas',                        help => 'Domain_Configuration_Quotas',
Line 335  sub handler { Line 352  sub handler {
                                 col2 => 'Value',},                                  col2 => 'Value',},
                                {col1 => 'Recipient(s) for notifications',                                 {col1 => 'Recipient(s) for notifications',
                                 col2 => 'Value',},                                  col2 => 'Value',},
                                  {col1 => 'Nightly status check e-mail',
                                   col2 => 'Settings',},
                                {col1 => 'Ask helpdesk form settings',                                 {col1 => 'Ask helpdesk form settings',
                                 col2 => 'Value',},],                                  col2 => 'Value',},],
                     print => \&print_contacts,                      print => \&print_contacts,
Line 465  sub handler { Line 484  sub handler {
                   print => \&print_selfenrollment,                    print => \&print_selfenrollment,
                   modify => \&modify_selfenrollment,                    modify => \&modify_selfenrollment,
                  },                   },
           'privacy' => 
                    {text   => 'User Privacy',
                     help   => 'Domain_Configuration_User_Privacy',
                     header => [{col1 => 'Setting',
                                 col2 => 'Value',}],
                     print => \&print_privacy,
                     modify => \&modify_privacy,
                    },
         'usersessions' =>          'usersessions' =>
                  {text  => 'User session hosting/offloading',                   {text  => 'User session hosting/offloading',
                   help  => 'Domain_Configuration_User_Sessions',                    help  => 'Domain_Configuration_User_Sessions',
Line 488  sub handler { Line 515  sub handler {
                   print => \&print_loadbalancing,                    print => \&print_loadbalancing,
                   modify => \&modify_loadbalancing,                    modify => \&modify_loadbalancing,
                  },                   },
           'ltitools' => 
                    {text => 'External Tools (LTI)',
                     help => 'Domain_Configuration_LTI_Tools',
                     header => [{col1 => 'Setting',
                                 col2 => 'Value',}],
                     print => \&print_ltitools,
                     modify => \&modify_ltitools,
                    },
           'ssl' =>
                    {text  => 'LON-CAPA Network (SSL)',
                     help  => 'Domain_Configuration_Network_SSL',
                     header => [{col1 => 'Server',
                                 col2 => 'Certificate Status'},
                                {col1 => 'Connections to other servers',
                                 col2 => 'Rules'},
                                {col1 => 'Connections from other servers',
                                 col2 => 'Rules'},
                                {col1 => "Replicating domain's published content",
                                 col2 => 'Rules'}],
                     print => \&print_ssl,
                     modify => \&modify_ssl,
                    },
           'trust' =>
                    {text   => 'Trust Settings',
                     help   => 'Domain_Configuration_Trust',
                     header => [{col1 => "Access to this domain's content by others",
                                 col2 => 'Rules'},
                                {col1 => "Access to other domain's content by this domain",
                                 col2 => 'Rules'},
                                {col1 => "Enrollment in this domain's courses by others",
                                 col2 => 'Rules',},
                                {col1 => "Co-author roles in this domain for others",
                                 col2 => 'Rules',},
                                {col1 => "Co-author roles for this domain's users elsewhere",
                                 col2 => 'Rules',},
                                {col1 => "Domain roles in this domain assignable to others",
                                 col2 => 'Rules'},
                                {col1 => "Course catalog for this domain displayed elsewhere",
                                 col2 => 'Rules'},
                                {col1 => "Requests for creation of courses in this domain by others",
                                 col2 => 'Rules'},
                                {col1 => "Users in other domains can send messages to this domain",
                                 col2 => 'Rules'},],
                     print => \&print_trust,
                     modify => \&modify_trust,
                    },
             'lti' =>
                    {text => 'LTI Provider',
                     help => 'Domain_Configuration_LTI_Provider',
                     header => [{col1 => 'Setting',
                                 col2 => 'Value',}],
                     print => \&print_lti,
                     modify => \&modify_lti,
                    },
     );      );
     if (keys(%servers) > 1) {      if (keys(%servers) > 1) {
         $prefs{'login'}  = { text   => 'Log-in page options',          $prefs{'login'}  = { text   => 'Log-in page options',
Line 670  sub process_changes { Line 751  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 'passwords') {      } elsif ($action eq 'ltitools') {
         $output = &modify_passwords($r,$dom,$confname,$lastactref,%domconfig);          $output = &modify_ltitools($r,$dom,$action,$lastactref,%domconfig);
       } elsif ($action eq 'ssl') {
           $output = &modify_ssl($dom,$lastactref,%domconfig);
       } elsif ($action eq 'trust') {
           $output = &modify_trust($dom,$lastactref,%domconfig);
       } elsif ($action eq 'lti') {
           $output = &modify_lti($r,$dom,$action,$lastactref,%domconfig);
     }      }
     return $output;      return $output;
 }  }
Line 684  sub print_config_box { Line 771  sub print_config_box {
         $output = &coursecategories_javascript($settings);          $output = &coursecategories_javascript($settings);
     } elsif ($action eq 'defaults') {      } elsif ($action eq 'defaults') {
         $output = &defaults_javascript($settings);           $output = &defaults_javascript($settings); 
     } elsif ($action eq 'passwords') {  
         $output = &passwords_javascript();  
     } elsif ($action eq 'helpsettings') {      } elsif ($action eq 'helpsettings') {
         my (%privs,%levelscurrent);          my (%privs,%levelscurrent);
         my %full=();          my %full=();
Line 700  sub print_config_box { Line 785  sub print_config_box {
         &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent);          &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent);
         my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);          my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);
         $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 .= &ltitools_javascript($settings);
       } elsif ($action eq 'lti') {
           $output .= &lti_javascript($settings);
     }      }
     $output .=      $output .=
          '<table class="LC_nested_outer">           '<table class="LC_nested_outer">
           <tr>            <tr>
            <th align="left" valign="middle"><span class="LC_nobreak">'.             <th class="LC_left_item LC_middle"><span class="LC_nobreak">'.
            &mt($item->{text}).'&nbsp;'.             &mt($item->{text}).'&nbsp;'.
            &Apache::loncommon::help_open_topic($item->{'help'}).'</span></th>'."\n".             &Apache::loncommon::help_open_topic($item->{'help'}).'</span></th>'."\n".
           '</tr>';            '</tr>';
Line 718  sub print_config_box { Line 807  sub print_config_box {
     if ($numheaders > 1) {      if ($numheaders > 1) {
         my $colspan = '';          my $colspan = '';
         my $rightcolspan = '';          my $rightcolspan = '';
         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 < 4))) {              (($action eq 'login') && ($numheaders < 4))) {
Line 727  sub print_config_box { Line 815  sub print_config_box {
         if ($action eq 'usersessions') {          if ($action eq 'usersessions') {
             $rightcolspan = ' colspan="3"';               $rightcolspan = ' colspan="3"'; 
         }          }
         if ($action eq 'passwords') {  
             $leftnobr = ' LC_nobreak';  
         }  
         $output .= '          $output .= '
           <tr>            <tr>
            <td>             <td>
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">               <tr class="LC_info_row">
               <td class="LC_left_item'.$leftnobr.'"'.$colspan.'>'.&mt($item->{'header'}->[0]->{'col1'}).'</td>                <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[0]->{'col1'}).'</td>
               <td class="LC_right_item"'.$rightcolspan.'>'.&mt($item->{'header'}->[0]->{'col2'}).'</td>                <td class="LC_right_item"'.$rightcolspan.'>'.&mt($item->{'header'}->[0]->{'col2'}).'</td>
              </tr>';               </tr>';
         $rowtotal ++;          $rowtotal ++;
         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 'ssl') ||
             ($action eq 'helpsettings') || ($action eq 'contacts')) {              ($action eq 'directorysrch') || ($action eq 'trust') || ($action eq 'helpsettings') ||
               ($action eq 'contacts')) {
             $output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);              $output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'passwords') {  
             $output .= $item->{'print'}->('top',$dom,$confname,$settings,\$rowtotal);  
         } elsif ($action eq 'coursecategories') {          } elsif ($action eq 'coursecategories') {
             $output .= $item->{'print'}->('top',$dom,$item,$settings,\$rowtotal);              $output .= $item->{'print'}->('top',$dom,$item,$settings,\$rowtotal);
         } elsif ($action eq 'scantron') {          } elsif ($action eq 'scantron') {
Line 776  sub print_config_box { Line 860  sub print_config_box {
             $rowtotal ++;              $rowtotal ++;
         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 'trust') || ($action eq 'contacts') || ($action eq 'defaults')) {
             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"';
             } elsif ($action eq 'passwords') {              } elsif ($action eq 'trust') {
                 $output .= $item->{'print'}->('middle',$dom,$confname,$settings,\$rowtotal);                  $output .= $item->{'print'}->('shared',$dom,$settings,\$rowtotal);
             } else {              } else {
                 $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);                  $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);
             }              }
             $output .= '              if ($action eq 'trust') {
                   $output .= '
               </table>
             </td>
            </tr>';
                   my @trusthdrs = qw(2 3 4 5 6 7);
                   my @prefixes = qw(enroll othcoau coaurem domroles catalog reqcrs);
                   for (my $i=0; $i<@trusthdrs; $i++) {
                       $output .= '
            <tr>
              <td>
               <table class="LC_nested">
                <tr class="LC_info_row">
                 <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[$trusthdrs[$i]]->{'col1'}).'</td>
                 <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[$trusthdrs[$i]]->{'col2'}).'</td></tr>'.
                              $item->{'print'}->($prefixes[$i],$dom,$settings,\$rowtotal).'
               </table>
             </td>
            </tr>';
                   }
                   $output .= '
            <tr>
              <td>
               <table class="LC_nested">
                <tr class="LC_info_row">
                 <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[8]->{'col1'}).'</td>
                 <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[8]->{'col2'}).'</td></tr>'.
                              $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
               } else {
                   $output .= '
            </table>             </table>
           </td>            </td>
          </tr>           </tr>
Line 794  sub print_config_box { Line 907  sub print_config_box {
            <td>             <td>
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">               <tr class="LC_info_row">
               <td class="LC_left_item'.$leftnobr.'"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>                <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
               <td class="LC_right_item">'.&mt($item->{'header'}->[2]->{'col2'}).'</td>                <td class="LC_right_item">'.&mt($item->{'header'}->[2]->{'col2'}).'</td>
              </tr>'."\n";               </tr>'."\n";
             if ($action eq 'coursecategories') {                  if ($action eq 'coursecategories') {
                 $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal);                      $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal);
             } elsif ($action eq 'passwords') {                  } elsif ($action eq 'contacts') {
                 $output .= $item->{'print'}->('lower',$dom,$confname,$settings,\$rowtotal).'                      $output .= $item->{'print'}->('lower',$dom,$settings,\$rowtotal).'
              </tr>               </tr>
             </table>              </table>
            </td>             </td>
Line 810  sub print_config_box { Line 923  sub print_config_box {
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">               <tr class="LC_info_row">
               <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>                <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>
               <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'."\n".                <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'.
               $item->{'print'}->('bottom',$dom,$confname,$settings,\$rowtotal).'                             $item->{'print'}->('bottom',$dom,$settings,\$rowtotal).'
             </table>              </table>
           </td>            </td>
          </tr>           </tr>
          <tr>';           <tr>';
             } else {                  } else {
                 $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);                      $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
                   }
             }              }
             $rowtotal ++;              $rowtotal ++;
         } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') ||          } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') ||
Line 826  sub print_config_box { Line 940  sub print_config_box {
             $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);              $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'scantron') {          } elsif ($action eq 'scantron') {
             $output .= $item->{'print'}->($r,'bottom',$dom,$confname,$settings,\$rowtotal);              $output .= $item->{'print'}->($r,'bottom',$dom,$confname,$settings,\$rowtotal);
           } elsif ($action eq 'ssl') {
               $output .= $item->{'print'}->('connto',$dom,$settings,\$rowtotal).'
               </table>
             </td>
            </tr>
            <tr>
              <td>
               <table class="LC_nested">
                <tr class="LC_info_row">
                 <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
                 <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col2'}).'</td></tr>'.
                              $item->{'print'}->('connfrom',$dom,$settings,\$rowtotal).'
               </table>
             </td>
            </tr>
            <tr>
              <td>
               <table class="LC_nested">
                <tr class="LC_info_row">
                 <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>
                 <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'.
                              $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'login') {          } elsif ($action eq 'login') {
             if ($numheaders == 4) {              if ($numheaders == 4) {
                 $output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal).'                  $output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal).'
Line 896  sub print_config_box { Line 1032  sub print_config_box {
            <td>             <td>
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">               <tr class="LC_info_row">
               <td class="LC_left_item"'.$colspan.' valign="top">'.&mt($item->{'header'}->[4]->{'col1'}).'</td>                <td class="LC_left_item"'.$colspan.' style="vertical-align: top">'.&mt($item->{'header'}->[4]->{'col1'}).'</td>
               <td class="LC_right_item" valign="top">'.&mt($item->{'header'}->[4]->{'col2'}).'</td>                <td class="LC_right_item" style="vertical-align: top">'.&mt($item->{'header'}->[4]->{'col2'}).'</td>
              </tr>'.               </tr>'.
             &print_validation_rows('requestcourses',$dom,$settings,\$rowtotal);              &print_validation_rows('requestcourses',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'requestauthor') {          } elsif ($action eq 'requestauthor') {
Line 912  sub print_config_box { Line 1048  sub print_config_box {
            <td>             <td>
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">               <tr class="LC_info_row">
               <td class="LC_left_item"'.$colspan.' valign="top">'.                <td class="LC_left_item"'.$colspan.' style="vertical-align: top">'.
                &mt($item->{'header'}->[2]->{'col1'}).'</td>                 &mt($item->{'header'}->[2]->{'col1'}).'</td>
               <td class="LC_right_item" valign="top">'.                <td class="LC_right_item" style="vertical-align: top">'.
                &mt($item->{'header'}->[2]->{'col2'}).'</td>                 &mt($item->{'header'}->[2]->{'col2'}).'</td>
              </tr>'.               </tr>'.
             &print_rolecolors($phase,'author',$dom,$confname,$settings,\$rowtotal).'              &print_rolecolors($phase,'author',$dom,$confname,$settings,\$rowtotal).'
Line 942  sub print_config_box { Line 1078  sub print_config_box {
               <td class="LC_left_item" colspan="2">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';                <td class="LC_left_item" colspan="2">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';
         } elsif ($action eq 'serverstatuses') {          } elsif ($action eq 'serverstatuses') {
             $output .= '              $output .= '
               <td class="LC_left_item" valign="top">'.&mt($item->{'header'}->[0]->{'col1'}).                <td class="LC_left_item" style="vertical-align: top">'.&mt($item->{'header'}->[0]->{'col1'}).
               '<br />('.&mt('Automatic access for Dom. Coords.').')</td>';                '<br />('.&mt('Automatic access for Dom. Coords.').')</td>';
   
         } else {          } else {
             $output .= '              $output .= '
               <td class="LC_left_item" valign="top">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';                <td class="LC_left_item" style="vertical-align: top">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';
         }          }
         if (defined($item->{'header'}->[0]->{'col3'})) {          if (defined($item->{'header'}->[0]->{'col3'})) {
             $output .= '<td class="LC_left_item" valign="top">'.              $output .= '<td class="LC_left_item" style="vertical-align: top">'.
                        &mt($item->{'header'}->[0]->{'col2'});                         &mt($item->{'header'}->[0]->{'col2'});
             if ($action eq 'serverstatuses') {              if ($action eq 'serverstatuses') {
                 $output .= '<br />(<tt>'.&mt('user1:domain1,user2:domain2 etc.').'</tt>)';                  $output .= '<br />(<tt>'.&mt('user1:domain1,user2:domain2 etc.').'</tt>)';
             }               } 
         } else {          } else {
             $output .= '<td class="LC_right_item" valign="top">'.              $output .= '<td class="LC_right_item" style="vertical-align: top">'.
                        &mt($item->{'header'}->[0]->{'col2'});                         &mt($item->{'header'}->[0]->{'col2'});
         }          }
         $output .= '</td>';          $output .= '</td>';
         if ($item->{'header'}->[0]->{'col3'}) {          if ($item->{'header'}->[0]->{'col3'}) {
             if (defined($item->{'header'}->[0]->{'col4'})) {              if (defined($item->{'header'}->[0]->{'col4'})) {
                 $output .= '<td class="LC_left_item" valign="top">'.                  $output .= '<td class="LC_left_item" style="vertical-align: top">'.
                             &mt($item->{'header'}->[0]->{'col3'});                              &mt($item->{'header'}->[0]->{'col3'});
             } else {              } else {
                 $output .= '<td class="LC_right_item" valign="top">'.                  $output .= '<td class="LC_right_item" style="vertical-align: top">'.
                            &mt($item->{'header'}->[0]->{'col3'});                             &mt($item->{'header'}->[0]->{'col3'});
             }              }
             if ($action eq 'serverstatuses') {              if ($action eq 'serverstatuses') {
Line 974  sub print_config_box { Line 1110  sub print_config_box {
             $output .= '</td>';              $output .= '</td>';
         }          }
         if ($item->{'header'}->[0]->{'col4'}) {          if ($item->{'header'}->[0]->{'col4'}) {
             $output .= '<td class="LC_right_item" valign="top">'.              $output .= '<td class="LC_right_item" style="vertical-align: top">'.
                        &mt($item->{'header'}->[0]->{'col4'});                         &mt($item->{'header'}->[0]->{'col4'});
         }          }
         $output .= '</tr>';          $output .= '</tr>';
Line 982  sub print_config_box { Line 1118  sub print_config_box {
         if ($action eq 'quotas') {          if ($action eq 'quotas') {
             $output .= &print_quotas($dom,$settings,\$rowtotal,$action);              $output .= &print_quotas($dom,$settings,\$rowtotal,$action);
         } elsif (($action eq 'autoenroll') || ($action eq 'autocreate') ||           } elsif (($action eq 'autoenroll') || ($action eq 'autocreate') || 
                  ($action eq 'serverstatuses') || ($action eq 'loadbalancing')) {                   ($action eq 'serverstatuses') || ($action eq 'loadbalancing') || 
                    ($action eq 'ltitools') || ($action eq 'lti')) {
             $output .= $item->{'print'}->($dom,$settings,\$rowtotal);              $output .= $item->{'print'}->($dom,$settings,\$rowtotal);
         }          }
     }      }
Line 1004  sub print_login { Line 1141  sub print_login {
         my $choice = $choices{'disallowlogin'};          my $choice = $choices{'disallowlogin'};
         $css_class = ' class="LC_odd_row"';          $css_class = ' class="LC_odd_row"';
         $datatable .= '<tr'.$css_class.'><td>'.$choice.'</td>'.          $datatable .= '<tr'.$css_class.'><td>'.$choice.'</td>'.
                       '<td align="right"><table><tr><th>'.$choices{'hostid'}.'</th>'.                        '<td style="text-align: right"><table><tr><th>'.$choices{'hostid'}.'</th>'.
                       '<th>'.$choices{'server'}.'</th>'.                        '<th>'.$choices{'server'}.'</th>'.
                       '<th>'.$choices{'serverpath'}.'</th>'.                        '<th>'.$choices{'serverpath'}.'</th>'.
                       '<th>'.$choices{'custompath'}.'</th>'.                        '<th>'.$choices{'custompath'}.'</th>'.
Line 1285  sub print_login { Line 1422  sub print_login {
         my $choice = $choices{'headtag'};          my $choice = $choices{'headtag'};
         $css_class = ' class="LC_odd_row"';          $css_class = ' class="LC_odd_row"';
         $datatable .= '<tr'.$css_class.'><td colspan="2">'.$choice.'</td>'.          $datatable .= '<tr'.$css_class.'><td colspan="2">'.$choice.'</td>'.
                       '<td align="left"><table><tr><th>'.$choices{'hostid'}.'</th>'.                        '<td style="text-align: left"><table><tr><th>'.$choices{'hostid'}.'</th>'.
                       '<th>'.$choices{'current'}.'</th>'.                        '<th>'.$choices{'current'}.'</th>'.
                       '<th>'.$choices{'action'}.'</th>'.                        '<th>'.$choices{'action'}.'</th>'.
                       '<th>'.$choices{'exempt'}.'</th></tr>'."\n";                        '<th>'.$choices{'exempt'}.'</th></tr>'."\n";
Line 1642  sub display_color_options { Line 1779  sub display_color_options {
                   '<table border="0"><tr>';                    '<table border="0"><tr>';
   
     foreach my $item (@{$bgs}) {      foreach my $item (@{$bgs}) {
         $datatable .= '<td align="center">'.$choices->{$item};          $datatable .= '<td style="text-align: center">'.$choices->{$item};
  my $color = $designs->{'bgs'}{$item} ? $designs->{'bgs'}{$item} : $defaults->{'bgs'}{$item};   my $color = $designs->{'bgs'}{$item} ? $designs->{'bgs'}{$item} : $defaults->{'bgs'}{$item};
         if ($designs->{'bgs'}{$item}) {          if ($designs->{'bgs'}{$item}) {
             $datatable .= '&nbsp;';              $datatable .= '&nbsp;';
Line 1670  sub display_color_options { Line 1807  sub display_color_options {
                   '<table border="0"><tr>';                    '<table border="0"><tr>';
     foreach my $item (@{$links}) {      foreach my $item (@{$links}) {
  my $color = $designs->{'links'}{$item} ? $designs->{'links'}{$item} : $defaults->{'links'}{$item};   my $color = $designs->{'links'}{$item} ? $designs->{'links'}{$item} : $defaults->{'links'}{$item};
         $datatable .= '<td align="center">'.$choices->{$item}."\n";          $datatable .= '<td style="text-align: center">'.$choices->{$item}."\n";
         if ($designs->{'links'}{$item}) {          if ($designs->{'links'}{$item}) {
             $datatable.='&nbsp;';              $datatable.='&nbsp;';
         }          }
Line 1731  sub login_text_colors { Line 1868  sub login_text_colors {
     my ($img,$role,$logintext,$phase,$choices,$designs,$defaults) = @_;      my ($img,$role,$logintext,$phase,$choices,$designs,$defaults) = @_;
     my $color_menu = '<table border="0"><tr>';      my $color_menu = '<table border="0"><tr>';
     foreach my $item (@{$logintext}) {      foreach my $item (@{$logintext}) {
         $color_menu .= '<td align="center">'.$choices->{$item};          $color_menu .= '<td style="text-align: center">'.$choices->{$item};
         my $color = $designs->{'logintext'}{$item} ? $designs->{'logintext'}{$item} : $defaults->{'logintext'}{$item};          my $color = $designs->{'logintext'}{$item} ? $designs->{'logintext'}{$item} : $defaults->{'logintext'}{$item};
         $color_menu .= '<br /><input type="text" class="colorchooser" size="8" name="'.$role.'_'.$item.'" value="'.$color.          $color_menu .= '<br /><input type="text" class="colorchooser" size="8" name="'.$role.'_'.$item.'" value="'.$color.
                       '" onblur = "javascript:colchg_span('."'css_".$role.'_'.$item."'".',this);" /></td>';                        '" onblur = "javascript:colchg_span('."'css_".$role.'_'.$item."'".',this);" /></td>';
Line 1764  sub image_changes { Line 1901  sub image_changes {
                        $role.'_del_'.$img.'" value="1" />'.&mt('Delete?').                         $role.'_del_'.$img.'" value="1" />'.&mt('Delete?').
                        '</label>&nbsp;'.&mt('Replace:').'</span><br />';                         '</label>&nbsp;'.&mt('Replace:').'</span><br />';
         } else {          } else {
             $output .= '<td valign="middle">'.$logincolors.&mt('Upload:').'<br />';              $output .= '<td class="LC_middle">'.$logincolors.&mt('Upload:').'<br />';
         }          }
     }      }
     return $output;      return $output;
Line 1783  sub print_quotas { Line 1920  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');          @usertools = ('official','unofficial','community','textbook','placement','lti');
         @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 2247  sub print_studentcode { Line 2384  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');      my @crstypes = ('official','unofficial','community','textbook','placement','lti');
     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 2343  sub print_textbookcourses { Line 2480  sub print_textbookcourses {
                               ('&nbsp;'x2).                                ('&nbsp;'x2).
                               '<span class="LC_nobreak">'.&mt('Thumbnail:');                                '<span class="LC_nobreak">'.&mt('Thumbnail:');
                 if ($image) {                  if ($image) {
                     $datatable .= '<span class="LC_nobreak">'.                      $datatable .= $imgsrc.
                                   $imgsrc.  
                                   '<label><input type="checkbox" name="'.$type.'_image_del"'.                                    '<label><input type="checkbox" name="'.$type.'_image_del"'.
                                   ' value="'.$key.'" />'.&mt('Delete?').'</label></span> '.                                    ' value="'.$key.'" />'.&mt('Delete?').'</label></span> '.
                                   '<span class="LC_nobreak">&nbsp;'.&mt('Replace:').'&nbsp;';                                    '<span class="LC_nobreak">&nbsp;'.&mt('Replace:').'&nbsp;';
Line 2498  $jstext{'templates'}; Line 2634  $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 lti_javascript {
       my ($settings) = @_;
       my $togglejs = &lti_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 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;
   }
   // ]]>
   </script>
   
   $togglejs
   
   ENDSCRIPT
   }
   
   sub lti_toggle_js {
       my %lcauthparmtext = &Apache::lonlocal::texthash (
                               localauth => 'Local auth argument',
                               krb       => 'Kerberos domain',
                            );
       return <<"ENDSCRIPT";
   <script type="text/javascript">
   // <![CDATA[
   
   function toggleLTI(form,setting,item) {
       if (setting == 'requser') {
           var fieldsets = document.getElementsByClassName('ltioption_'+item);
           if (fieldsets.length) {
               var radioname = 'lti_'+setting+'_'+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') {
                              setvis = 1;
                              break;
                           }
                       }
                   }
                   for (var j=0; j<fieldsets.length; j++) { 
                       if (setvis) {
                           fieldsets[j].style.display = 'block';
                       } else {
                           fieldsets[j].style.display = 'none';
                       }
                   }
               }
           }
       } else if ((setting == 'user') || (setting == 'crs') || (setting == 'passback')) {
           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 {
               radioname = 'lti_passbackformat_'+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') {
                          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 print_autoenroll {  sub print_autoenroll {
     my ($dom,$settings,$rowtotal) = @_;      my ($dom,$settings,$rowtotal) = @_;
     my $autorun = &Apache::lonnet::auto_run(undef,$dom),      my $autorun = &Apache::lonnet::auto_run(undef,$dom),
Line 2859  sub print_contacts { Line 3372  sub print_contacts {
     my $datatable;      my $datatable;
     my @contacts = ('adminemail','supportemail');      my @contacts = ('adminemail','supportemail');
     my (%checked,%to,%otheremails,%bccemails,%includestr,%includeloc,%currfield,      my (%checked,%to,%otheremails,%bccemails,%includestr,%includeloc,%currfield,
         $maxsize,$fields,$fieldtitles,$fieldoptions,$possoptions,@mailings);          $maxsize,$fields,$fieldtitles,$fieldoptions,$possoptions,@mailings,%lonstatus);
     if ($position eq 'top') {      if ($position eq 'top') {
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             foreach my $item (@contacts) {              foreach my $item (@contacts) {
Line 2870  sub print_contacts { Line 3383  sub print_contacts {
         }          }
     } elsif ($position eq 'middle') {      } elsif ($position eq 'middle') {
         @mailings = ('errormail','packagesmail','lonstatusmail','requestsmail',          @mailings = ('errormail','packagesmail','lonstatusmail','requestsmail',
                      'updatesmail','idconflictsmail','hostipmail');                       'updatesmail','idconflictsmail');
         foreach my $type (@mailings) {          foreach my $type (@mailings) {
             $otheremails{$type} = '';              $otheremails{$type} = '';
         }          }
       } elsif ($position eq 'lower') {
           if (ref($settings) eq 'HASH') {
               if (ref($settings->{'lonstatus'}) eq 'HASH') {
                   %lonstatus = %{$settings->{'lonstatus'}};
               }
           }
     } else {      } else {
         @mailings = ('helpdeskmail','otherdomsmail');          @mailings = ('helpdeskmail','otherdomsmail');
         foreach my $type (@mailings) {          foreach my $type (@mailings) {
Line 2886  sub print_contacts { Line 3405  sub print_contacts {
         ($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields();          ($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields();
     }      }
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         unless ($position eq 'top') {          unless (($position eq 'top') || ($position eq 'lower')) {
             foreach my $type (@mailings) {              foreach my $type (@mailings) {
                 if (exists($settings->{$type})) {                  if (exists($settings->{$type})) {
                     if (ref($settings->{$type}) eq 'HASH') {                      if (ref($settings->{$type}) eq 'HASH') {
Line 2947  sub print_contacts { Line 3466  sub print_contacts {
             $checked{'requestsmail'}{'adminemail'} = ' checked="checked" ';              $checked{'requestsmail'}{'adminemail'} = ' checked="checked" ';
             $checked{'updatesmail'}{'adminemail'} = ' checked="checked" ';              $checked{'updatesmail'}{'adminemail'} = ' checked="checked" ';
             $checked{'idconflictsmail'}{'adminemail'} = ' checked="checked" ';              $checked{'idconflictsmail'}{'adminemail'} = ' checked="checked" ';
             $checked{'hostipmail'}{'adminemail'} = ' checked="checked" ';  
         } elsif ($position eq 'bottom') {          } elsif ($position eq 'bottom') {
             $checked{'helpdeskmail'}{'supportemail'} = ' checked="checked" ';              $checked{'helpdeskmail'}{'supportemail'} = ' checked="checked" ';
             $checked{'otherdomsmail'}{'supportemail'} = ' checked="checked" ';              $checked{'otherdomsmail'}{'supportemail'} = ' checked="checked" ';
Line 3019  sub print_contacts { Line 3537  sub print_contacts {
         $datatable .= '</td></tr>'."\n";          $datatable .= '</td></tr>'."\n";
         $rownum ++;          $rownum ++;
     }      }
     unless ($position eq 'top') {      unless (($position eq 'top') || ($position eq 'lower')) {
         foreach my $type (@mailings) {          foreach my $type (@mailings) {
             $css_class = $rownum%2?' class="LC_odd_row"':'';              $css_class = $rownum%2?' class="LC_odd_row"':'';
             $datatable .= '<tr'.$css_class.'>'.              $datatable .= '<tr'.$css_class.'>'.
Line 3066  sub print_contacts { Line 3584  sub print_contacts {
     }      }
     if ($position eq 'middle') {      if ($position eq 'middle') {
         my %choices;          my %choices;
         $choices{'reporterrors'} = &mt('E-mail error reports to [_1]',          my $corelink = &core_link_msu();
                                        &Apache::loncommon::modal_link('http://loncapa.org/core.html',          $choices{'reporterrors'} = &mt('E-mail error reports to [_1]',$corelink);
                                        &mt('LON-CAPA core group - MSU'),600,500));  
         $choices{'reportupdates'} = &mt('E-mail record of completed LON-CAPA updates to [_1]',          $choices{'reportupdates'} = &mt('E-mail record of completed LON-CAPA updates to [_1]',
                                         &Apache::loncommon::modal_link('http://loncapa.org/core.html',                                          $corelink);
                                         &mt('LON-CAPA core group - MSU'),600,500));          $choices{'reportstatus'} = &mt('E-mail status if errors above threshold to [_1]',$corelink);
         my @toggles = ('reporterrors','reportupdates');          my @toggles = ('reporterrors','reportupdates','reportstatus');
         my %defaultchecked = ('reporterrors'  => 'on',          my %defaultchecked = ('reporterrors'  => 'on',
                               'reportupdates' => 'on');                                'reportupdates' => 'on',
                                 'reportstatus'  => 'on');
         (my $reports,$rownum) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,          (my $reports,$rownum) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,
                                                    \%choices,$rownum);                                                     \%choices,$rownum);
         $datatable .= $reports;          $datatable .= $reports;
       } elsif ($position eq 'lower') {
           $css_class = $rownum%2?' class="LC_odd_row"':'';
           my ($threshold,$sysmail,%excluded,%weights);
           my ($defaults,$names) = &Apache::loncommon::lon_status_items();
           if ($lonstatus{'threshold'} =~ /^\d+$/) {
               $threshold = $lonstatus{'threshold'};
           } else {
               $threshold = $defaults->{'threshold'};
           }
           if ($lonstatus{'sysmail'} =~ /^\d+$/) {
               $sysmail = $lonstatus{'sysmail'};
           } else {
               $sysmail = $defaults->{'sysmail'};
           }
           if (ref($lonstatus{'weights'}) eq 'HASH') {
               foreach my $type ('E','W','N','U') {
                   if ($lonstatus{'weights'}{$type} =~ /^\d+$/) {
                       $weights{$type} = $lonstatus{'weights'}{$type};
                   } else {
                       $weights{$type} = $defaults->{$type};
                   }
               }
           } else {
               foreach my $type ('E','W','N','U') {
                   $weights{$type} = $defaults->{$type};
               }
           }
           if (ref($lonstatus{'excluded'}) eq 'ARRAY') {
               if (@{$lonstatus{'excluded'}} > 0) {
                   map {$excluded{$_} = 1; } @{$lonstatus{'excluded'}};
               }
           }
           $datatable .= '<tr'.$css_class.'>'.
                         '<td class="LC_left_item"><span class="LC_nobreak">'.
                         $titles->{'errorthreshold'}.
                         '</span></td><td class="LC_left_item">'.
                         '<input type="text" name="errorthreshold" value="'.
                         $threshold.'" size="5" /></td></tr>';
           $rownum ++;
           $css_class = $rownum%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'>'.
                         '<td class="LC_left_item">'.
                         '<span class="LC_nobreak">'.$titles->{'errorweights'}.
                         '</span></td><td class="LC_left_item"><table><tr>';
           foreach my $type ('E','W','N','U') {
               $datatable .= '<td>'.$names->{$type}.'<br />'.
                             '<input type="text" name="errorweights_'.$type.'" value="'.
                             $weights{$type}.'" size="5" /></td>';
           }
           $datatable .= '</tr></table></tr>';
           $rownum ++;
           $css_class = $rownum%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td class="LC_left_item">'.
                         $titles->{'errorexcluded'}.'</td>'.
                         '<td class="LC_left_item"><table>';
           my $numinrow = 4;
           my @ids = sort(values(%Apache::lonnet::serverhomeIDs));
           for (my $i=0; $i<@ids; $i++) {
               my $rem = $i%($numinrow);
               if ($rem == 0) {
                   if ($i > 0) {
                       $datatable .= '</tr>';
                   }
                   $datatable .= '<tr>';
               }
               my $check;
               if ($excluded{$ids[$i]}) {
                   $check = ' checked="checked" ';
               }
               $datatable .= '<td class="LC_left_item">'.
                             '<span class="LC_nobreak"><label>'.
                             '<input type="checkbox" name="errorexcluded" '.
                             'value="'.$ids[$i].'"'.$check.' />'.
                             $ids[$i].'</label></span></td>';
           }
           my $colsleft = $numinrow - @ids%($numinrow);
           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 .= '</tr></table></td></tr>';
           $rownum ++;
           $css_class = $rownum%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'>'.
                         '<td class="LC_left_item"><span class="LC_nobreak">'.
                         $titles->{'errorsysmail'}.
                         '</span></td><td class="LC_left_item">'.
                         '<input type="text" name="errorsysmail" value="'.
                         $sysmail.'" size="5" /></td></tr>';
           $rownum ++;
     } elsif ($position eq 'bottom') {      } elsif ($position eq 'bottom') {
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);          my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
         my (@posstypes,%usertypeshash);          my (@posstypes,%usertypeshash);
Line 3105  sub print_contacts { Line 3715  sub print_contacts {
                             $includeloc{'override_'.$key} = '';                              $includeloc{'override_'.$key} = '';
                             $includestr{'override_'.$key} = '';                              $includestr{'override_'.$key} = '';
                             if ($settings->{'overrides'}{$key}{'include'} ne '') {                              if ($settings->{'overrides'}{$key}{'include'} ne '') {
                                 ($includeloc{'override_'.$key},$includestr{'override_'.$key}) =                                  ($includeloc{'override_'.$key},$includestr{'override_'.$key}) = 
                                     split(/:/,$settings->{'overrides'}{$key}{'include'},2);                                      split(/:/,$settings->{'overrides'}{$key}{'include'},2);
                                 $includestr{'override_'.$key} = &unescape($includestr{'override_'.$key});                                  $includestr{'override_'.$key} = &unescape($includestr{'override_'.$key});
                             }                              }
Line 3117  sub print_contacts { Line 3727  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 3151  sub print_contacts { Line 3761  sub print_contacts {
     return $datatable;      return $datatable;
 }  }
   
   sub core_link_msu {
       return &Apache::loncommon::modal_link('http://loncapa.org/core.html',
                                             &mt('LON-CAPA core group - MSU'),600,500);
   }
   
 sub overridden_helpdesk {  sub overridden_helpdesk {
     my ($checked,$otheremails,$bccemails,$includeloc,$includestr,$type,$rowid,      my ($checked,$otheremails,$bccemails,$includeloc,$includestr,$type,$rowid,
         $typetitle,$css_class,$rowstyle,$contacts,$short_titles) = @_;          $typetitle,$css_class,$rowstyle,$contacts,$short_titles) = @_;
Line 3179  sub overridden_helpdesk { Line 3794  sub overridden_helpdesk {
             }              }
             my $title;              my $title;
             if (ref($short_titles) eq 'HASH') {              if (ref($short_titles) eq 'HASH') {
                 $title = $short_titles->{$item};                  $title = $short_titles->{$item}; 
             }              }
             $output .= '<label>'.              $output .= '<label>'.
                        '<input type="checkbox" name="override_'.$type.'"'.$check.                         '<input type="checkbox" name="override_'.$type.'"'.$check.
Line 3258  function toggleHelpdeskRow(form,checkbox Line 3873  function toggleHelpdeskRow(form,checkbox
     return;      return;
 }  }
   
   
 // ]]>  // ]]>
 </script>  </script>
   
Line 3329  sub print_helpsettings { Line 3945  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 3363  sub print_helpsettings { Line 3978  sub print_helpsettings {
             my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);              my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);
             $css_class = $itemcount%2?' class="LC_odd_row"':'';              $css_class = $itemcount%2?' class="LC_odd_row"':'';
             my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$num."_pos'".');"';              my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$num."_pos'".');"';
             $datatable .= '<tr '.$css_class.'><td valign="top"><b>'.$role.'</b><br />'.              $datatable .= '<tr '.$css_class.'><td style="vertical-align: top"><b>'.$role.'</b><br />'.
                           '<select name="helproles_'.$num.'_pos"'.$chgstr.'>';                            '<select name="helproles_'.$num.'_pos"'.$chgstr.'>';
             for (my $k=0; $k<=$maxnum; $k++) {              for (my $k=0; $k<=$maxnum; $k++) {
                 my $vpos = $k+1;                  my $vpos = $k+1;
Line 3402  sub print_helpsettings { Line 4017  sub print_helpsettings {
         &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent);          &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent);
         my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);          my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);
         my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$count."_pos'".');"';          my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$count."_pos'".');"';
         $datatable .= '<tr '.$css_class.'><td valign="top"><span class="LC_nobreak"><label>'.          $datatable .= '<tr '.$css_class.'><td style="vertical-align: top"><span class="LC_nobreak"><label>'.
                       '<input type="hidden" name="helproles_maxnum" value="'.$maxnum.'" />'."\n".                        '<input type="hidden" name="helproles_maxnum" value="'.$maxnum.'" />'."\n".
                       '<select name="helproles_'.$count.'_pos"'.$chgstr.'>';                        '<select name="helproles_'.$count.'_pos"'.$chgstr.'>';
         for (my $k=0; $k<$maxnum+1; $k++) {          for (my $k=0; $k<$maxnum+1; $k++) {
Line 3683  sub radiobutton_prefs { Line 4298  sub radiobutton_prefs {
     foreach my $item (@{$toggles}) {      foreach my $item (@{$toggles}) {
         $css_class = $itemcount%2?' class="LC_odd_row"':'';          $css_class = $itemcount%2?' class="LC_odd_row"':'';
         $datatable .=          $datatable .=
             '<tr'.$css_class.'><td valign="top">'.              '<tr'.$css_class.'><td style="vertical-align: top">'.
             '<span class="LC_nobreak">'.$choices->{$item}.              '<span class="LC_nobreak">'.$choices->{$item}.
             '</span></td>';              '</span></td>';
         if ($align eq 'left') {          if ($align eq 'left') {
Line 3705  sub radiobutton_prefs { Line 4320  sub radiobutton_prefs {
     return ($datatable,$itemcount);      return ($datatable,$itemcount);
 }  }
   
   sub print_ltitools {
       my ($dom,$settings,$rowtotal) = @_;
       my $rownum = 0;
       my $css_class;
       my $itemcount = 1;
       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'};
                   $ordered{$num} = $item;
               }
           }
       }
       my $confname = $dom.'-domainconfig';
       my $switchserver = &check_switchserver($dom,$confname);
       my $maxnum = scalar(keys(%ordered));
       my $datatable;
       my %lt = &ltitools_names();
       my @courseroles = ('cc','in','ta','ep','st');
       my @ltiroles = qw(Instructor ContentDeveloper TeachingAssistant Learner);
       my @fields = ('fullname','firstname','lastname','email','roles','user');
       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 ($title,$key,$secret,$url,$lifetime,$imgsrc,%sigsel);
               if (ref($settings->{$item}) eq 'HASH') {
                   $title = $settings->{$item}->{'title'};
                   $url = $settings->{$item}->{'url'};
                   $key = $settings->{$item}->{'key'};
                   $secret = $settings->{$item}->{'secret'};
                   $lifetime = $settings->{$item}->{'lifetime'};
                   my $image = $settings->{$item}->{'image'};
                   if ($image ne '') {
                       $imgsrc = '<img src="'.$image.'" alt="'.&mt('Tool Provider icon').'" />';
                   }
                   if ($settings->{$item}->{'sigmethod'} eq 'HMAC-256') {
                       $sigsel{'HMAC-256'} = ' selected="selected"';
                   } else {
                       $sigsel{'HMAC-SHA1'} = ' selected="selected"';
                   }
               }
               my $chgstr = ' onchange="javascript:reorderLTITools(this.form,'."'ltitools_".$item."'".');"';
               $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
                            .'<select name="ltitools_'.$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="ltitools_del" value="'.$item.'" />'.
                   &mt('Delete?').'</label></span></td>'.
                   '<td colspan="2">'.
                   '<fieldset><legend>'.&mt('Required settings').'</legend>'.
                   '<span class="LC_nobreak">'.$lt{'title'}.':<input type="text" size="20" name="ltitools_title_'.$i.'" value="'.$title.'" /></span> '.
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'version'}.':<select name="ltitools_version_'.$i.'">'.
                   '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '.
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'msgtype'}.':<select name="ltitools_msgtype_'.$i.'">'.
                   '<option value="basic-lti-launch-request" selected="selected">Launch</option></select></span> '.
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'sigmethod'}.':<select name="ltitools_sigmethod_'.$i.'">'.
                   '<option value="HMAC-SHA1"'.$sigsel{'HMAC-SHA1'}.'>HMAC-SHA1</option>'.
                   '<option value="HMAC-SHA256"'.$sigsel{'HMAC-SHA256'}.'>HMAC-SHA256</option></select></span>'.
                   '<br /><br />'.
                   '<span class="LC_nobreak">'.$lt{'url'}.':<input type="text" size="40" name="ltitools_url_'.$i.'"'.
                   ' value="'.$url.'" /></span>'.
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'key'}.':'.
                   '<input type="text" size="25" name="ltitools_key_'.$i.'" value="'.$key.'" /></span> '.
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'lifetime'}.':'.
                   '<input type="text" size="5" name="ltitools_lifetime_'.$i.'" value="'.$lifetime.'" /></span> '.
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'secret'}.':'.
                   '<input type="password" size="20" name="ltitools_secret_'.$i.'" value="'.$secret.'" />'.
                   '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.ltitools_secret_'.$i.'.type='."'text'".' } else { this.form.ltitools_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'.
                   '<input type="hidden" name="ltitools_id_'.$i.'" value="'.$item.'" /></span>'.
                   '</fieldset>'.
                   '<fieldset><legend>'.&mt('Optional settings').'</legend>'.
                   '<span class="LC_nobreak">'.&mt('Display target:');
               my %currdisp;
               if (ref($settings->{$item}->{'display'}) eq 'HASH') {
                   if ($settings->{$item}->{'display'}->{'target'} eq 'window') {
                       $currdisp{'window'} = ' checked="checked"';
                   } elsif ($settings->{$item}->{'display'}->{'target'} eq 'tab') {
                       $currdisp{'tab'} = ' checked="checked"';
                   } else {
                       $currdisp{'iframe'} = ' checked="checked"';
                   }
                   if ($settings->{$item}->{'display'}->{'width'} =~ /^(\d+)$/) {
                       $currdisp{'width'} = $1;
                   }
                   if ($settings->{$item}->{'display'}->{'height'} =~ /^(\d+)$/) {
                        $currdisp{'height'} = $1;
                   }
                   $currdisp{'linktext'} = $settings->{$item}->{'display'}->{'linktext'};
                   $currdisp{'explanation'} = $settings->{$item}->{'display'}->{'explanation'};
               } else {
                   $currdisp{'iframe'} = ' checked="checked"';
               }
               foreach my $disp ('iframe','tab','window') {
                   $datatable .= '<label><input type="radio" name="ltitools_target_'.$i.'" value="'.$disp.'"'.$currdisp{$disp}.' />'.
                                 $lt{$disp}.'</label>'.('&nbsp;'x2);
               }
               $datatable .= ('&nbsp;'x4);
               foreach my $dimen ('width','height') {
                   $datatable .= '<label>'.$lt{$dimen}.'&nbsp;'.
                                 '<input type="text" name="ltitools_'.$dimen.'_'.$i.'" size="5" value="'.$currdisp{$dimen}.'" /></label>'.
                                 ('&nbsp;'x2);
               }
               $datatable .= '</span><br />'.
                             '<div class="LC_left_float">'.$lt{'linktext'}.'<br />'.
                             '<input type="text" name="ltitools_linktext_'.$i.'" size="25" value="'.$currdisp{'linktext'}.'" /></div>'.
                             '<div class="LC_left_float">'.$lt{'explanation'}.'<br />'.
                             '<textarea name="ltitools_explanation_'.$i.'" rows="5" cols="40">'.$currdisp{'explanation'}.
                             '</textarea></div><div style=""></div><br />';
               my %units = (
                             'passback' => 'days',
                             'roster'   => 'seconds',
                           );
               foreach my $extra ('passback','roster') {
                   my $validsty = 'none';
                   my $currvalid;
                   my $checkedon = '';
                   my $checkedoff = ' checked="checked"';
                   if ($settings->{$item}->{$extra}) {
                       $checkedon = $checkedoff;
                       $checkedoff = '';
                       $validsty = 'inline-block';
                       if ($settings->{$item}->{$extra.'valid'} =~ /^\d+\.?\d*$/) {
                           $currvalid = $settings->{$item}->{$extra.'valid'};
                       }
                   }
                   my $onclick = ' onclick="toggleLTITools(this.form,'."'$extra','$i'".');"';
                   $datatable .= '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{$extra}.'&nbsp;'.
                                 '<label><input type="radio" name="ltitools_'.$extra.'_'.$i.'" value="0"'.$checkedoff.$onclick.' />'.
                                 &mt('No').'</label>'.('&nbsp;'x2).
                                 '<label><input type="radio" name="ltitools_'.$extra.'_'.$i.'" value="1"'.$checkedon.$onclick.' />'.
                                 &mt('Yes').'</label></span></div>'.
                                 '<div class="LC_floatleft" style="display:'.$validsty.';" id="ltitools_'.$extra.'time_'.$i.'">'.
                                 '<span class="LC_nobreak">'.
                                 &mt("at least [_1] $units{$extra} after launch",
                                     '<input type="text" name="ltitools_'.$extra.'valid_'.$i.'" value="'.$currvalid.'" />').
                                 '</span></div><div style="padding:0;clear:both;margin:0;border:0"></div>';
               }
               $datatable .= '<span class="LC_nobreak">'.$lt{'icon'}.':&nbsp;';
               if ($imgsrc) {
                   $datatable .= $imgsrc.
                                 '<label><input type="checkbox" name="ltitools_image_del"'.
                                 ' value="'.$item.'" />'.&mt('Delete?').'</label></span> '.
                                 '<span class="LC_nobreak">&nbsp;'.&mt('Replace:').'&nbsp;';
               } else {
                   $datatable .= '('.&mt('if larger than 21x21 pixels, image will be scaled').')&nbsp;';
               }
               if ($switchserver) {
                   $datatable .= &mt('Upload to library server: [_1]',$switchserver);
               } else {
                   $datatable .= '<input type="file" name="ltitools_image_'.$i.'" value="" />';
               }
               $datatable .= '</span></fieldset>';
               my (%checkedfields,%rolemaps,$userincdom);
               if (ref($settings->{$item}) eq 'HASH') {
                   if (ref($settings->{$item}->{'fields'}) eq 'HASH') {
                       %checkedfields = %{$settings->{$item}->{'fields'}};
                   }
                   $userincdom = $settings->{$item}->{'incdom'};
                   if (ref($settings->{$item}->{'roles'}) eq 'HASH') {
                       %rolemaps = %{$settings->{$item}->{'roles'}};
                       $checkedfields{'roles'} = 1;
                   }
               }
               $datatable .= '<fieldset><legend>'.&mt('User data sent on launch').'</legend>'.
                             '<span class="LC_nobreak">';
               my $userfieldstyle = 'display:none;';
               my $seluserdom = '';
               my $unseluserdom = ' selected="selected"';
               foreach my $field (@fields) {
                   my ($checked,$onclick,$id,$spacer);
                   if ($checkedfields{$field}) {
                       $checked = ' checked="checked"';
                   }
                   if ($field eq 'user') {
                       $id = ' id="ltitools_user_field_'.$i.'"';
                       $onclick = ' onclick="toggleLTITools(this.form,'."'$field','$i'".')"';
                       if ($checked) {
                           $userfieldstyle = 'display:inline-block';
                           if ($userincdom) {
                               $seluserdom = $unseluserdom;
                               $unseluserdom = '';
                           }
                       }
                   } else {
                       $spacer = ('&nbsp;' x2);
                   }
                   $datatable .= '<label>'.
                                 '<input type="checkbox" name="ltitools_fields_'.$i.'" value="'.$field.'"'.$id.$checked.$onclick.' />'.
                                 $lt{$field}.'</label>'.$spacer;
               }
               $datatable .= '</span>';
               $datatable .= '<div style="'.$userfieldstyle.'" id="ltitools_user_div_'.$i.'">'.
                             '<span class="LC_nobreak"> : '.
                             '<select name="ltitools_userincdom_'.$i.'">'.
                             '<option value="">'.&mt('Select').'</option>'.
                             '<option value="0"'.$unseluserdom.'>'.&mt('username').'</option>'.
                             '<option value="1"'.$seluserdom.'>'.&mt('username:domain').'</option>'.
                             '</select></span></div>';
               $datatable .= '</fieldset>'.
                             '<fieldset><legend>'.&mt('Role mapping').'</legend><table><tr>';
               foreach my $role (@courseroles) {
                   my ($selected,$selectnone);
                   if (!$rolemaps{$role}) {
                       $selectnone = ' selected="selected"';
                   }
                   $datatable .= '<td style="text-align: center">'. 
                                 &Apache::lonnet::plaintext($role,'Course').'<br />'.
                                 '<select name="ltitools_roles_'.$role.'_'.$i.'">'.
                                 '<option value=""'.$selectnone.'>'.&mt('Select').'</option>';
                   foreach my $ltirole (@ltiroles) {
                       unless ($selectnone) {
                           if ($rolemaps{$role} eq $ltirole) {
                               $selected = ' selected="selected"';
                           } else {
                               $selected = '';
                           }
                       }
                       $datatable .= '<option value="'.$ltirole.'"'.$selected.'>'.$ltirole.'</option>';
                   }
                   $datatable .= '</select></td>';
               }
               $datatable .= '</tr></table></fieldset>';
               my %courseconfig;
               if (ref($settings->{$item}) eq 'HASH') {
                   if (ref($settings->{$item}->{'crsconf'}) eq 'HASH') {
                       %courseconfig = %{$settings->{$item}->{'crsconf'}};
                   }
               }
               $datatable .= '<fieldset><legend>'.&mt('Configurable in course').'</legend><span class="LC_nobreak">';
               foreach my $item ('label','title','target','linktext','explanation','append') {
                   my $checked;
                   if ($courseconfig{$item}) {
                       $checked = ' checked="checked"';
                   }
                   $datatable .= '<label>'.
                          '<input type="checkbox" name="ltitools_courseconfig_'.$i.'" value="'.$item.'"'.$checked.' />'.
                          $lt{'crs'.$item}.'</label>'.('&nbsp;' x2)."\n";
               }
               $datatable .= '</span></fieldset>'.
                             '<fieldset><legend>'.&mt('Custom items sent on launch').'</legend>'.
                             '<table><tr><th>'.&mt('Action').'</th><th>'.&mt('Name').'</th><th>'.&mt('Value').'</th></tr>';
               if (ref($settings->{$item}->{'custom'}) eq 'HASH') {
                   my %custom = %{$settings->{$item}->{'custom'}};
                   if (keys(%custom) > 0) {
                       foreach my $key (sort(keys(%custom))) {
                           $datatable .= '<tr><td><span class="LC_nobreak">'.
                                         '<label><input type="checkbox" name="ltitools_customdel_'.$i.'" value="'.
                                         $key.'" />'.&mt('Delete').'</label></span></td><td>'.$key.'</td>'.
                                         '<td><input type="text" name="ltitools_customval_'.$key.'_'.$i.'"'.
                                         ' value="'.$custom{$key}.'" /></td></tr>';
                       }
                   }
               }
               $datatable .= '<tr><td><span class="LC_nobreak">'.
                             '<label><input type="checkbox" name="ltitools_customadd" value="'.$i.'" />'.
                             &mt('Add').'</label></span></td><td><input type="text" name="ltitools_custom_name_'.$i.'" />'.
                             '</td><td><input type="text" name="ltitools_custom_value_'.$i.'" /></td></tr>';
               $datatable .= '</table></fieldset></td></tr>'."\n";
               $itemcount ++;
           }
       }
       $css_class = $itemcount%2?' class="LC_odd_row"':'';
       my $chgstr = ' onchange="javascript:reorderLTITools(this.form,'."'ltitools_add_pos'".');"';
       $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".
                     '<input type="hidden" name="ltitools_maxnum" value="'.$maxnum.'" />'."\n".
                     '<select name="ltitools_add_pos"'.$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="ltitools_add" value="1" />'.&mt('Add').'</span></td>'."\n".
                     '<td colspan="2">'.
                     '<fieldset><legend>'.&mt('Required settings').'</legend>'.
                     '<span class="LC_nobreak">'.$lt{'title'}.':<input type="text" size="20" name="ltitools_add_title" value="" /></span> '."\n".
                     ('&nbsp;'x2).
                     '<span class="LC_nobreak">'.$lt{'version'}.':<select name="ltitools_add_version">'.
                     '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n".
                     ('&nbsp;'x2).
                     '<span class="LC_nobreak">'.$lt{'msgtype'}.':<select name="ltitools_add_msgtype">'.
                     '<option value="basic-lti-launch-request" selected="selected">Launch</option></select></span> '.
                     '<span class="LC_nobreak">'.$lt{'sigmethod'}.':<select name="ltitools_add_sigmethod">'.
                     '<option value="HMAC-SHA1" selected="selected">HMAC-SHA1</option>'.
                     '<option value="HMAC-SHA256">HMAC-SHA256</option></select></span>'.
                     '<br />'.
                     '<span class="LC_nobreak">'.$lt{'url'}.':<input type="text" size="40" name="ltitools_add_url" value="" /></span> '."\n".
                     ('&nbsp;'x2).
                     '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="ltitools_add_key" value="" /></span> '."\n".
                     ('&nbsp;'x2).
                     '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="5" name="ltitools_add_lifetime" value="300" /></span> '."\n".
                     ('&nbsp;'x2).
                     '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="ltitools_add_secret" value="" />'.
                     '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.ltitools_add_secret.type='."'text'".' } else { this.form.ltitools_add_secret.type='."'password'".' }" />'.&mt('Visible input').'</label></span> '."\n".
                     '</fieldset>'.
                     '<fieldset><legend>'.&mt('Optional settings').'</legend>'.
                     '<span class="LC_nobreak">'.&mt('Display target:');
       my %defaultdisp;
       $defaultdisp{'iframe'} = ' checked="checked"';
       foreach my $disp ('iframe','tab','window') {
           $datatable .= '<label><input type="radio" name="ltitools_add_target" value="'.$disp.'"'.$defaultdisp{$disp}.' />'.
                         $lt{$disp}.'</label>'.('&nbsp;'x2);
       }
       $datatable .= ('&nbsp;'x4);
       foreach my $dimen ('width','height') {
           $datatable .= '<label>'.$lt{$dimen}.'&nbsp;'.
                         '<input type="text" name="ltitools_add_'.$dimen.'" size="5" /></label>'.
                         ('&nbsp;'x2);
       }
       $datatable .= '</span><br />'.
                     '<div class="LC_left_float">'.$lt{'linktext'}.'<br />'.
                     '<input type="text" name="ltitools_add_linktext" size="5" /></div>'.
                     '<div class="LC_left_float">'.$lt{'explanation'}.'<br />'.
                     '<textarea name="ltitools_add_explanation" rows="5" cols="40"></textarea>'.
                     '</div><div style=""></div><br />';
       my %units = (
                     'passback' => 'days',
                     'roster'   => 'seconds',
                   );
       my %defaulttimes = (
                        'passback' => '7',
                        'roster'   => '300',
                      );
       foreach my $extra ('passback','roster') {
           my $onclick = ' onclick="toggleLTITools(this.form,'."'$extra','add'".');"';
           $datatable .= '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{$extra}.'&nbsp;'.
                         '<label><input type="radio" name="ltitools_'.$extra.'_add" value="0" checked="checked"'.$onclick.' />'.
                         &mt('No').'</label></span>'.('&nbsp;'x2).'<span class="LC_nobreak">'.
                         '<label><input type="radio" name="ltitools_'.$extra.'_add" value="1"'.$onclick.' />'.
                         &mt('Yes').'</label></span></div>'.
                         '<div class="LC_floatleft" style="display:none;" id="ltitools_'.$extra.'time_add">'.
                         '<span class="LC_nobreak">'.
                         &mt("at least [_1] $units{$extra} after launch",
                             '<input type="text" name="ltitools_'.$extra.'valid_add" value="'.$defaulttimes{$extra}.'" />').
                         '</span></div><div style="padding:0;clear:both;margin:0;border:0"></div>';
       }
       $datatable .= '<span class="LC_nobreak">'.$lt{'icon'}.':&nbsp;'.
                     '('.&mt('if larger than 21x21 pixels, image will be scaled').')&nbsp;';
       if ($switchserver) {
           $datatable .= &mt('Upload to library server: [_1]',$switchserver);
       } else {
           $datatable .= '<input type="file" name="ltitools_add_image" value="" />';
       }
       $datatable .= '</span></fieldset>'.
                     '<fieldset><legend>'.&mt('User data sent on launch').'</legend>'.
                     '<span class="LC_nobreak">';
       foreach my $field (@fields) {
           my ($id,$onclick,$spacer);
           if ($field eq 'user') {
               $id = ' id="ltitools_user_field_add"';
               $onclick = ' onclick="toggleLTITools(this.form,'."'$field','add'".')"';
           } else {
               $spacer = ('&nbsp;' x2);
           }
           $datatable .= '<label>'.
                         '<input type="checkbox" name="ltitools_add_fields" value="'.$field.'"'.$id.$onclick.' />'.
                         $lt{$field}.'</label>'.$spacer;
       }
       $datatable .= '</span>'.
                     '<div style="display:none;" id="ltitools_user_div_add">'.
                     '<span class="LC_nobreak"> : '.
                     '<select name="ltitools_userincdom_add">'.
                     '<option value="" selected="selected">'.&mt('Select').'</option>'.
                     '<option value="0">'.&mt('username').'</option>'.
                     '<option value="1">'.&mt('username:domain').'</option>'.
                     '</select></span></div></fieldset>';
       $datatable .= '<fieldset><legend>'.&mt('Role mapping').'</legend><table><tr>';
       foreach my $role (@courseroles) {
           my ($checked,$checkednone);
           $datatable .= '<td style="text-align: center">'.
                         &Apache::lonnet::plaintext($role,'Course').'<br />'.
                         '<select name="ltitools_add_roles_'.$role.'">'.
                         '<option value="" selected="selected">'.&mt('Select').'</option>';
           foreach my $ltirole (@ltiroles) {
               $datatable .= '<option value="'.$ltirole.'">'.$ltirole.'</option>';
           }
           $datatable .= '</select></td>';
       }
       $datatable .= '</tr></table></fieldset>'.
                     '<fieldset><legend>'.&mt('Configurable in course').'</legend><span class="LC_nobreak">';
       foreach my $item ('label','title','target','linktext','explanation','append') {
           $datatable .= '<label>'.
                         '<input type="checkbox" name="ltitools_courseconfig" value="'.$item.'" checked="checked" />'.
                         $lt{'crs'.$item}.'</label>'.('&nbsp;' x2)."\n";
       }
       $datatable .= '</span></fieldset>'.
                     '<fieldset><legend>'.&mt('Custom items sent on launch').'</legend>'.
                     '<table><tr><th>'.&mt('Action').'</th><th>'.&mt('Name').'</th><th>'.&mt('Value').'</th></tr>'.
                     '<tr><td><span class="LC_nobreak">'.
                     '<label><input type="checkbox" name="ltitools_add_custom" value="1" />'.
                     &mt('Add').'</label></span></td><td><input type="text" name="ltitools_add_custom_name" />'.
                     '</td><td><input type="text" name="ltitools_add_custom_value" /></td></tr>'.
                     '</table></fieldset>'."\n".
                     '</td>'."\n".
                     '</tr>'."\n";
       $itemcount ++;
       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 print_lti {
       my ($dom,$settings,$rowtotal) = @_;
       my $itemcount = 1;
       my $maxnum = 0;
       my $css_class;
       my %ordered;
       if (ref($settings) eq 'HASH') {
           foreach my $item (keys(%{$settings})) {
               if (ref($settings->{$item}) eq 'HASH') {
                   my $num = $settings->{$item}{'order'};
                   $ordered{$num} = $item;
               }
           }
       }
       my $maxnum = scalar(keys(%ordered));
       my $datatable;
       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,$lifetime,$consumer,$requser,$current);
               if (ref($settings->{$item}) eq 'HASH') {
                   $key = $settings->{$item}->{'key'};
                   $secret = $settings->{$item}->{'secret'};
                   $lifetime = $settings->{$item}->{'lifetime'};
                   $consumer = $settings->{$item}->{'consumer'};
                   $requser = $settings->{$item}->{'requser'};
                   $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 $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>'.
                   ('&nbsp;'x2).
                    '<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{'key'}.
                   ':<input type="text" size="25" name="lti_key_'.$i.'" value="'.$key.'" /></span> '.
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'secret'}.':'.
                   '<input type="password" size="20" name="lti_secret_'.$i.'" value="'.$secret.'" />'.
                   '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.lti_secret_'.$i.'.type='."'text'".' } else { this.form.lti_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'.
                   '<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> '."\n".
                     ('&nbsp;'x2).
                     '<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{'key'}.':<input type="text" size="25" name="lti_key_add" value="" /></span> '."\n".
                     ('&nbsp;'x2).
                     '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="lti_secret_add" value="" />'.
                     '<label><input type="checkbox" name="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".
                     '</fieldset>'.&lti_options('add',undef,$itemcount,%lt).
                     '</td>'."\n".
                     '</tr>'."\n";
       $$rowtotal ++;
       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",
                                             '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);
       $checked{'mapuser'}{'sourcedid'} = ' checked="checked"';
       $checked{'mapcrs'}{'course_offering_sourcedid'} = ' 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 $passbacksty = 'none';
       my $optionsty = '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';
           }
           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->{'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->{'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{'topmenu'}{'N'} = ' checked="checked"';
           $checked{'inlinemenu'}{'Y'} = ' checked="checked"'; 
           $checked{'menuitem'}{'grades'} = ' checked="checked"';
           $menusty = 'inline-block'; 
       }
       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 @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 $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_'.$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_'.$num.'" style="display:'.$optionsty.'"><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_'.$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_'.$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_'.$num.'" style="display:'.$optionsty.'"><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></fieldset>'.
                  '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><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_'.$num.'" style="display:'.$optionsty.'"><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_'.$num.'" style="display:'.$optionsty.'"><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></fieldset>'.
                  '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Course defaults (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><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);
     my $itemcount = 1;      my $itemcount = 1;
     my %choices =  &Apache::lonlocal::texthash (      my %choices =  &Apache::lonlocal::texthash (
           canuse_pdfforms      => 'Course/Community users can create/upload PDF forms',
         uploadquota          => 'Default quota for files uploaded directly to course/community using Course Editor (MB)',          uploadquota          => 'Default quota for files uploaded directly to course/community using Course Editor (MB)',
         anonsurvey_threshold => 'Responder count needed before showing submissions for anonymous surveys',          anonsurvey_threshold => 'Responder count needed before showing submissions for anonymous surveys',
         coursecredits        => 'Credits can be specified for courses',          coursecredits        => 'Credits can be specified for courses',
Line 3721  sub print_coursedefaults { Line 5272  sub print_coursedefaults {
         mysqltables          => 'Lifetime (s) of "Temporary" MySQL tables (student performance data) on homeserver',          mysqltables          => 'Lifetime (s) of "Temporary" MySQL tables (student performance data) on homeserver',
     );      );
     my %staticdefaults = (      my %staticdefaults = (
                              texengine            => 'MathJax',
                            anonsurvey_threshold => 10,                             anonsurvey_threshold => 10,
                            uploadquota          => 500,                             uploadquota          => 500,
                            postsubmit           => 60,                             postsubmit           => 60,
Line 3728  sub print_coursedefaults { Line 5280  sub print_coursedefaults {
                          );                           );
     if ($position eq 'top') {      if ($position eq 'top') {
         %defaultchecked = (          %defaultchecked = (
                               'canuse_pdfforms' => 'off',
                             'uselcmath'       => 'on',                              'uselcmath'       => 'on',
                             'usejsme'         => 'on',                              'usejsme'         => 'on',
                             'canclone'        => 'none',                              'canclone'        => 'none',
                           );                            );
         @toggles = ('uselcmath','usejsme');          @toggles = ('canuse_pdfforms','uselcmath','usejsme');
         my $deftex = $Apache::lonnet::deftex;          my $deftex = $staticdefaults{'texengine'};
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if ($settings->{'texengine'}) {              if ($settings->{'texengine'}) {
                 if ($settings->{'texengine'} =~ /^(MathJax|mimetex|tth)$/) {                  if ($settings->{'texengine'} =~ /^(MathJax|mimetex|tth)$/) {
Line 3765  sub print_coursedefaults { Line 5318  sub print_coursedefaults {
         $datatable = $mathdisp.$datatable;          $datatable = $mathdisp.$datatable;
         $css_class = $itemcount%2?' class="LC_odd_row"':'';          $css_class = $itemcount%2?' class="LC_odd_row"':'';
         $datatable .=          $datatable .=
             '<tr'.$css_class.'><td valign="top">'.              '<tr'.$css_class.'><td style="vertical-align: top">'.
             '<span class="LC_nobreak">'.$choices{'canclone'}.              '<span class="LC_nobreak">'.$choices{'canclone'}.
             '</span></td><td class="LC_left_item">';              '</span></td><td class="LC_left_item">';
         my $currcanclone = 'none';          my $currcanclone = 'none';
Line 3809  sub print_coursedefaults { Line 5362  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 3839  sub print_coursedefaults { Line 5392  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 @types = ('official','unofficial','community','textbook');          my @types = ('official','unofficial','community','textbook','placement');
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             $currdefresponder = $settings->{'anonsurvey_threshold'};              $currdefresponder = $settings->{'anonsurvey_threshold'};
             if (ref($settings->{'uploadquota'}) eq 'HASH') {              if (ref($settings->{'uploadquota'}) eq 'HASH') {
Line 3917  sub print_coursedefaults { Line 5470  sub print_coursedefaults {
         $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.          $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
                       $choices{'uploadquota'}.                        $choices{'uploadquota'}.
                       '</span></td>'.                        '</span></td>'.
                       '<td align="right" class="LC_right_item">'.                        '<td style="text-align: right" class="LC_right_item">'.
                       '<table><tr>';                        '<table><tr>';
         foreach my $type (@types) {          foreach my $type (@types) {
             $datatable .= '<td align="center">'.&mt($type).'<br />'.              $datatable .= '<td style="text-align: center">'.&mt($type).'<br />'.
                            '<input type="text" name="uploadquota_'.$type.'"'.                             '<input type="text" name="uploadquota_'.$type.'"'.
                            ' value="'.$curruploadquota{$type}.'" size="5" /></td>';                             ' value="'.$curruploadquota{$type}.'" size="5" /></td>';
         }          }
Line 3935  sub print_coursedefaults { Line 5488  sub print_coursedefaults {
                          '<i>'.&mt('Default credits').'</i><br /><table><tr>';                           '<i>'.&mt('Default credits').'</i><br /><table><tr>';
         foreach my $type (@types) {          foreach my $type (@types) {
             next if ($type eq 'community');              next if ($type eq 'community');
             $additional .= '<td align="center">'.&mt($type).'<br />'.              $additional .= '<td style="text-align: center">'.&mt($type).'<br />'.
                            '<input type="text" name="'.$type.'_credits"'.                             '<input type="text" name="'.$type.'_credits"'.
                            ' value="'.$defcredits{$type}.'" size="3" /></td>';                             ' value="'.$defcredits{$type}.'" size="3" /></td>';
         }          }
Line 3959  sub print_coursedefaults { Line 5512  sub print_coursedefaults {
                       '<i>'.&mt('Enter 0 to remain disabled until page reload.').'</i><br />'.                        '<i>'.&mt('Enter 0 to remain disabled until page reload.').'</i><br />'.
                       '<table><tr>';                        '<table><tr>';
         foreach my $type (@types) {          foreach my $type (@types) {
             $additional .= '<td align="center">'.&mt($type).'<br />'.              $additional .= '<td style="text-align: center">'.&mt($type).'<br />'.
                            '<input type="text" name="'.$type.'_timeout" value="'.                             '<input type="text" name="'.$type.'_timeout" value="'.
                            $deftimeout{$type}.'" size="5" /></td>';                             $deftimeout{$type}.'" size="5" /></td>';
         }          }
Line 3977  sub print_coursedefaults { Line 5530  sub print_coursedefaults {
         $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.          $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
                       $choices{'mysqltables'}.                        $choices{'mysqltables'}.
                       '</span></td>'.                        '</span></td>'.
                       '<td align="right" class="LC_right_item">'.                        '<td style="text-align: right" class="LC_right_item">'.
                       '<table><tr>';                        '<table><tr>';
         foreach my $type (@types) {          foreach my $type (@types) {
             $datatable .= '<td align="center">'.&mt($type).'<br />'.              $datatable .= '<td style="text-align: center">'.&mt($type).'<br />'.
                            '<input type="text" name="mysqltables_'.$type.'"'.                             '<input type="text" name="mysqltables_'.$type.'"'.
                            ' value="'.$currmysql{$type}.'" size="8" /></td>';                             ' value="'.$currmysql{$type}.'" size="8" /></td>';
         }          }
Line 3996  sub print_selfenrollment { Line 5549  sub print_selfenrollment {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($css_class,$datatable);      my ($css_class,$datatable);
     my $itemcount = 1;      my $itemcount = 1;
     my @types = ('official','unofficial','community','textbook');      my @types = ('official','unofficial','community','textbook','placement');
     if (($position eq 'top') || ($position eq 'middle')) {      if (($position eq 'top') || ($position eq 'middle')) {
         my ($rowsref,$titlesref) = &Apache::lonuserutils::get_selfenroll_titles();          my ($rowsref,$titlesref) = &Apache::lonuserutils::get_selfenroll_titles();
         my %descs = &Apache::lonuserutils::selfenroll_default_descs();          my %descs = &Apache::lonuserutils::selfenroll_default_descs();
Line 4217  sub print_validation_rows { Line 5770  sub print_validation_rows {
     return $datatable;      return $datatable;
 }  }
   
 sub print_passwords {  sub print_usersessions {
     my ($position,$dom,$confname,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($datatable,$css_class);      my ($css_class,$datatable,$itemcount,%checked,%choices);
     my $itemcount = 0;      my (%by_ip,%by_location,@intdoms,@instdoms);
     my %titles = &Apache::lonlocal::texthash (      &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
         captcha        => '"Forgot Password" CAPTCHA validation',  
         link           => 'Reset link expiration (hours)',      my @alldoms = &Apache::lonnet::all_domains();
         case           => 'Case-sensitive usernames/e-mail',      my %serverhomes = %Apache::lonnet::serverhomeIDs;
         prelink        => 'Information required (form 1)',      my %servers = &Apache::lonnet::internet_dom_servers($dom);
         postlink       => 'Information required (form 2)',      my %altids = &id_for_thisdom(%servers);
         emailsrc       => 'LON-CAPA e-mail address type(s)',  
         customtext     => 'Domain specific text (HTML)',  
         intauth_cost   => 'Encryption cost for bcrypt (positive integer)',  
         intauth_check  => 'Check bcrypt cost if authenticated',  
         intauth_switch => 'Existing crypt-based switched to bcrypt on authentication',  
         permanent      => 'Permanent e-mail address',  
         critical       => 'Critical notification address',  
         notify         => 'Notification address',  
         min            => 'Minimum password length',  
         max            => 'Maximum password length',  
         chars          => 'Required characters',  
         numsaved       => 'Number of previous passwords to save and disallow reuse',  
     );  
     if ($position eq 'top') {      if ($position eq 'top') {
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);          if (keys(%serverhomes) > 1) {
         my $shownlinklife = 2;              my %spareid = &current_offloads_to($dom,$settings,\%servers);
         my $prelink = 'both';              my $curroffloadnow;
         my (%casesens,%postlink,%emailsrc,$nostdtext,$customurl);              if (ref($settings) eq 'HASH') {
         if (ref($settings) eq 'HASH') {                  if (ref($settings->{'offloadnow'}) eq 'HASH') {
             if ($settings->{resetlink} =~ /^\d+(|\.\d*)$/) {                      $curroffloadnow = $settings->{'offloadnow'};
                 $shownlinklife = $settings->{resetlink};  
             }  
             if (ref($settings->{resetcase}) eq 'ARRAY') {  
                 map { $casesens{$_} = 1; } (@{$settings->{resetcase}});  
             }  
             if ($settings->{resetprelink} =~ /^(both|either)$/) {  
                 $prelink = $settings->{resetprelink};  
             }  
             if (ref($settings->{resetpostlink}) eq 'HASH') {  
                 %postlink = %{$settings->{resetpostlink}};  
             }  
             if (ref($settings->{resetemail}) eq 'ARRAY') {  
                 map { $emailsrc{$_} = 1; } (@{$settings->{resetemail}});  
             }  
             if ($settings->{resetremove}) {  
                 $nostdtext = 1;  
             }  
             if ($settings->{resetcustom}) {  
                 $customurl = $settings->{resetcustom};  
             }  
         } else {  
             if (ref($types) eq 'ARRAY') {  
                 foreach my $item (@{$types}) {  
                     $casesens{$item} = 1;  
                     $postlink{$item} = ['username','email'];  
                 }                  }
             }              }
             $casesens{'default'} = 1;              $datatable .= &spares_row($dom,\%servers,\%spareid,\%serverhomes,\%altids,$curroffloadnow,$rowtotal);
             $postlink{'default'} = ['username','email'];          } else {
             $prelink = 'both';              $datatable .= '<tr'.$css_class.'><td colspan="2">'.
             %emailsrc = (                            &mt('Nothing to set here, as the cluster to which this domain belongs only contains one server.').
                           permanent => 1,                            '</td></tr>';
                           critical  => 1,  
                           notify    => 1,  
             );  
         }          }
         $datatable = &captcha_choice('passwords',$settings,$$rowtotal);      } else {
         $itemcount ++;          my %titles = &usersession_titles();
         $css_class = $itemcount%2?' class="LC_odd_row"':'';          my ($prefix,@types);
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'link'}.'</td>'.          if ($position eq 'bottom') {
                       '<td class="LC_left_item">'.              $prefix = 'remote';
                       '<input type="textbox" value="'.$shownlinklife.'" '.              @types = ('version','excludedomain','includedomain');
                       'name="passwords_link" size="3" /></td></tr>';          } else {
         $itemcount ++;              $prefix = 'hosted';
         $css_class = $itemcount%2?' class="LC_odd_row"':'';              @types = ('excludedomain','includedomain');
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'case'}.'</td>'.  
                       '<td class="LC_left_item">';  
         if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {  
             foreach my $item (@{$types}) {  
                 my $checkedcase;  
                 if ($casesens{$item}) {  
                     $checkedcase = ' checked="checked"';  
                 }  
                 $datatable .= '<span class="LC_nobreak"><label>'.  
                               '<input type="checkbox" name="passwords_case_sensitive" value="'.  
                               $item.'"'.$checkedcase.' />'.$usertypes->{$item}.'</label>'.  
                               '</span>&nbsp;&nbsp; ';  
             }  
         }          }
         my $checkedcase;          ($datatable,$itemcount) = &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles);
         if ($casesens{'default'}) {      }
             $checkedcase = ' checked="checked"';      $$rowtotal += $itemcount;
         }      return $datatable;
         $datatable .= '<span class="LC_nobreak"><label><input type="checkbox" '.  }
                       'name="passwords_case_sensitive" value="default"'.$checkedcase.' />'.  
                       $othertitle.'</label></span></td>';  sub rules_by_location {
         $itemcount ++;      my ($settings,$prefix,$by_location,$by_ip,$types,$titles) = @_; 
         $css_class = $itemcount%2?' class="LC_odd_row"':'';      my ($datatable,$itemcount,$css_class);
         my %checkedpre = (      if (keys(%{$by_location}) == 0) {
                              both => ' checked="checked"',          $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
                              either => '',          $datatable = '<tr'.$css_class.'><td colspan="2">'.
                          );                       &mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.').
         if ($prelink eq 'either') {                       '</td></tr>';
             $checkedpre{either} = ' checked="checked"';          $itemcount = 1;
             $checkedpre{both} = '';      } else {
           $itemcount = 0;
           my $numinrow = 5;
           my (%current,%checkedon,%checkedoff);
           my @locations = sort(keys(%{$by_location}));
           foreach my $type (@{$types}) {
               $checkedon{$type} = '';
               $checkedoff{$type} = ' checked="checked"';
         }          }
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'prelink'}.'</td>'.          if (ref($settings) eq 'HASH') {
                       '<td class="LC_left_item"><span class="LC_nobreak">'.              if (ref($settings->{$prefix}) eq 'HASH') {
                       '<label><input type="radio" name="passwords_prelink" value="both"'.$checkedpre{'both'}.' />'.                  foreach my $key (keys(%{$settings->{$prefix}})) {
                       &mt('Both username and e-mail address').'</label></span>&nbsp;&nbsp; '.                      $current{$key} = $settings->{$prefix}{$key};
                       '<span class="LC_nobreak"><label>'.                      if ($key eq 'version') {
                       '<input type="radio" name="passwords_prelink" value="either"'.$checkedpre{'either'}.' />'.                          if ($current{$key} ne '') {
                       &mt('Either username or e-mail address').'</label></span></td></tr>';                              $checkedon{$key} = ' checked="checked"';
         $itemcount ++;                              $checkedoff{$key} = '';
         $css_class = $itemcount%2?' class="LC_odd_row"':'';                          }
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'postlink'}.'</td>'.                      } elsif (ref($current{$key}) eq 'ARRAY') {
                       '<td class="LC_left_item">';                          $checkedon{$key} = ' checked="checked"';
         my %postlinked;                          $checkedoff{$key} = '';
         if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {  
             foreach my $item (@{$types}) {  
                 undef(%postlinked);  
                 $datatable .= '<fieldset style="display: inline-block;">'.  
                               '<legend>'.$usertypes->{$item}.'</legend>';  
                 if (ref($postlink{$item}) eq 'ARRAY') {  
                     map { $postlinked{$_} = 1; } (@{$postlink{$item}});  
                 }  
                 foreach my $field ('email','username') {  
                     my $checked;  
                     if ($postlinked{$field}) {  
                         $checked = ' checked="checked"';  
                     }                      }
                     $datatable .= '<span class="LC_nobreak"><label>'.  
                                   '<input type="checkbox" name="passwords_postlink_'.$item.'" value="'.  
                                   $field.'"'.$checked.' />'.$field.'</label>'.  
                                   '<span>&nbsp;&nbsp; ';  
                 }                  }
                 $datatable .= '</fieldset>';  
             }  
         }  
         if (ref($postlink{'default'}) eq 'ARRAY') {  
             map { $postlinked{$_} = 1; } (@{$postlink{'default'}});  
         }  
         $datatable .= '<fieldset style="display: inline-block;">'.  
                       '<legend>'.$othertitle.'</legend>';  
         foreach my $field ('email','username') {  
             my $checked;  
             if ($postlinked{$field}) {  
                 $checked = ' checked="checked"';  
             }              }
             $datatable .= '<span class="LC_nobreak"><label>'.  
                           '<input type="checkbox" name="passwords_postlink_default" value="'.  
                           $field.'"'.$checked.' />'.$field.'</label>'.  
                           '<span>&nbsp;&nbsp; ';  
         }  
         $datatable .= '</fieldset></td></tr>';  
         $itemcount ++;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'emailsrc'}.'</td>'.  
                       '<td class="LC_left_item">';  
         foreach my $type ('permanent','critical','notify') {  
             my $checkedemail;  
             if ($emailsrc{$type}) {  
                 $checkedemail = ' checked="checked"';  
             }  
             $datatable .= '<span class="LC_nobreak"><label>'.  
                           '<input type="checkbox" name="passwords_emailsrc" value="'.  
                           $type.'"'.$checkedemail.' />'.$titles{$type}.'</label>'.  
                           '<span>&nbsp;&nbsp; ';  
         }  
         $datatable .= '</td></tr>';  
         $itemcount ++;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         my $switchserver = &check_switchserver($dom,$confname);  
         my ($showstd,$noshowstd);  
         if ($nostdtext) {  
             $noshowstd = ' checked="checked"';  
         } else {  
             $showstd = ' checked="checked"';  
         }          }
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'customtext'}.'</td>'.          foreach my $type (@{$types}) {
                       '<td class="LC_left_item"><span class="LC_nobreak">'.              next if ($type ne 'version' && !@locations);
                       &mt('Retain standard text:').              $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
                       '<label><input type="radio" name="passwords_stdtext" value="1"'.$showstd.' />'.              $datatable .= '<tr'.$css_class.'>
                       &mt('Yes').'</label>'.'&nbsp;'.                             <td><span class="LC_nobreak">'.$titles->{$type}.'</span><br />
                       '<label><input type="radio" name="passwords_stdtext" value="0"'.$noshowstd.' />'.                             <span class="LC_nobreak">&nbsp;
                       &mt('No').'</label></span><br />'.                             <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedoff{$type}.' value="0" />'.&mt('Not in use').'</label>&nbsp;
                       '<span class="LC_fontsize_small">'.                             <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedon{$type}.' value="1" />'.&mt('In use').'</label></span></td><td>';
                       &mt('(If you use the same account ...  reset a password from this page.)').'</span><br /><br />'.              if ($type eq 'version') {
                       &mt('Include custom text:');                  my @lcversions = &Apache::lonnet::all_loncaparevs();
         if ($customurl) {                  my $selector = '<select name="'.$prefix.'_version">';
             my $link =  &Apache::loncommon::modal_link($customurl,&mt('custom text'),600,500,                  foreach my $version (@lcversions) {
                                                        undef,undef,undef,undef,'background-color:#ffffff');                      my $selected = '';
             $datatable .= '<span class="LC_nobreak">&nbsp;'.$link.                      if ($current{'version'} eq $version) {
                           '<label><input type="checkbox" name="passwords_custom_del"'.                          $selected = ' selected="selected"';
                           ' value="1" />'.&mt('Delete?').'</label></span>'.  
                           ' <span class="LC_nobreak">&nbsp;'.&mt('Replace:').'</span>';  
         }  
         if ($switchserver) {  
             $datatable .= '<span class="LC_nobreak">&nbsp;'.&mt('Upload to library server: [_1]',$switchserver).'</span>';  
         } else {  
             $datatable .='<span class="LC_nobreak">&nbsp;'.  
                          '<input type="file" name="passwords_customfile" /></span>';  
         }  
         $datatable .= '</td></tr>';  
     } elsif ($position eq 'middle') {  
         my %domconf = &Apache::lonnet::get_dom('configuration',['defaults'],$dom);  
         my @items = ('intauth_cost','intauth_check','intauth_switch');  
         my %defaults;  
         if (ref($domconf{'defaults'}) eq 'HASH') {  
             %defaults = %{$domconf{'defaults'}};  
             if ($defaults{'intauth_cost'} !~ /^\d+$/) {  
                 $defaults{'intauth_cost'} = 10;  
             }  
             if ($defaults{'intauth_check'} !~ /^(0|1|2)$/) {  
                 $defaults{'intauth_check'} = 0;  
             }  
             if ($defaults{'intauth_switch'} !~ /^(0|1|2)$/) {  
                 $defaults{'intauth_switch'} = 0;  
             }  
         } else {  
             %defaults = (  
                           'intauth_cost'   => 10,  
                           'intauth_check'  => 0,  
                           'intauth_switch' => 0,  
                         );  
         }  
         foreach my $item (@items) {  
             if ($itemcount%2) {  
                 $css_class = '';  
             } else {  
                 $css_class = ' class="LC_odd_row" ';  
             }  
             $datatable .= '<tr'.$css_class.'>'.  
                           '<td><span class="LC_nobreak">'.$titles{$item}.  
                           '</span></td><td class="LC_left_item" colspan="3">';  
             if ($item eq 'intauth_switch') {  
                 my @options = (0,1,2);  
                 my %optiondesc = &Apache::lonlocal::texthash (  
                                    0 => 'No',  
                                    1 => 'Yes',  
                                    2 => 'Yes, and copy existing passwd file to passwd.bak file',  
                                  );  
                 $datatable .= '<table width="100%">';  
                 foreach my $option (@options) {  
                     my $checked = ' ';  
                     if ($defaults{$item} eq $option) {  
                         $checked = ' checked="checked"';  
                     }                      }
                     $datatable .= '<tr><td class="LC_left_item"><span class="LC_nobreak">'.                      $selector .= ' <option value="'.$version.'"'.
                                   '<label><input type="radio" name="'.$item.                                   $selected.'>'.$version.'</option>';
                                   '" value="'.$option.'"'.$checked.' />'.  
                                   $optiondesc{$option}.'</label></span></td></tr>';  
                 }                  }
                 $datatable .= '</table>';                  $selector .= '</select> ';
             } elsif ($item eq 'intauth_check') {                  $datatable .= &mt('remote server must be version: [_1] or later',$selector);
                 my @options = (0,1,2);              } else {
                 my %optiondesc = &Apache::lonlocal::texthash (                  $datatable.= '<div><input type="button" value="'.&mt('check all').'" '.
                                    0 => 'No',                               'onclick="javascript:checkAll(document.display.'.$prefix.'_'.$type.')"'.
                                    1 => 'Yes, allow login then update passwd file using default cost (if higher)',                               ' />'.('&nbsp;'x2).
                                    2 => 'Yes, disallow login if stored cost is less than domain default',                               '<input type="button" value="'.&mt('uncheck all').'" '.
                                  );                               'onclick="javascript:uncheckAll(document.display.'.$prefix.'_'.$type.')" />'.
                 $datatable .= '<table width="100%">';                               "\n".
                 foreach my $option (@options) {                               '</div><div><table>';
                     my $checked = ' ';                  my $rem;
                     my $onclick;                  for (my $i=0; $i<@locations; $i++) {
                     if ($defaults{$item} eq $option) {                      my ($showloc,$value,$checkedtype);
                         $checked = ' checked="checked"';                      if (ref($by_location->{$locations[$i]}) eq 'ARRAY') {
                     }                          my $ip = $by_location->{$locations[$i]}->[0];
                     if ($option == 2) {                          if (ref($by_ip->{$ip}) eq 'ARRAY') {
                         $onclick = ' onclick="javascript:warnIntAuth(this);"';                              $value = join(':',@{$by_ip->{$ip}});
                               $showloc = join(', ',@{$by_ip->{$ip}});
                               if (ref($current{$type}) eq 'ARRAY') {
                                   foreach my $loc (@{$by_ip->{$ip}}) {
                                       if (grep(/^\Q$loc\E$/,@{$current{$type}})) {
                                           $checkedtype = ' checked="checked"';
                                           last;
                                       }
                                   }
                               }
                           }
                     }                      }
                     $datatable .= '<tr><td class="LC_left_item"><span class="LC_nobreak">'.                      $rem = $i%($numinrow);
                                   '<label><input type="radio" name="'.$item.                      if ($rem == 0) {
                                   '" value="'.$option.'"'.$checked.$onclick.' />'.                          if ($i > 0) {
                                   $optiondesc{$option}.'</label></span></td></tr>';                              $datatable .= '</tr>';
                           }
                           $datatable .= '<tr>';
                       }
                       $datatable .= '<td class="LC_left_item">'.
                                     '<span class="LC_nobreak"><label>'.
                                     '<input type="checkbox" name="'.$prefix.'_'.$type.
                                     '" value="'.$value.'"'.$checkedtype.' />'.$showloc.
                                     '</label></span></td>';
                 }                  }
                 $datatable .= '</table>';                  $rem = @locations%($numinrow);
             } else {                  my $colsleft = $numinrow - $rem;
                 $datatable .= '<input type="text" name="'.$item.'" value="'.                  if ($colsleft > 1 ) {
                               $defaults{$item}.'" size="3" onblur="javascript:warnIntAuth(this);" />';                      $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
                                     '&nbsp;</td>';
                   } elsif ($colsleft == 1) {
                       $datatable .= '<td class="LC_left_item">&nbsp;</td>';
                   }
                   $datatable .= '</tr></table>';
             }              }
             $datatable .= '</td></tr>';              $datatable .= '</td></tr>';
             $itemcount ++;              $itemcount ++;
         }          }
     } elsif ($position eq 'lower') {  
         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 {  
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);  
         my %ownerchg = (  
                           by  => {},  
                           for => {},  
                        );  
         my %ownertitles = &Apache::lonlocal::texthash (  
                             by  => 'Course owner status(es) allowed',  
                             for => 'Student status(es) allowed',  
                           );  
         if (ref($settings) eq 'HASH') {  
             if (ref($settings->{crsownerchg}) eq 'HASH') {  
                 if (ref($settings->{crsownerchg}{'by'}) eq 'ARRAY') {  
                     map { $ownerchg{by}{$_} = 1; } (@{$settings->{crsownerchg}{'by'}});  
                 }  
                 if (ref($settings->{crsownerchg}{'for'}) eq 'ARRAY') {  
                     map { $ownerchg{for}{$_} = 1; } (@{$settings->{crsownerchg}{'for'}});  
                 }  
             }  
         }  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr '.$css_class.'>'.  
                       '<td>'.  
                       &mt('Requirements').'<ul>'.  
                       '<li>'.&mt("Course 'type' is not a Community").'</li>'.  
                       '<li>'.&mt('User is Course Coordinator and also course owner').'</li>'.  
                       '<li>'.&mt("Student's only active roles are student role(s) in course(s) owned by this user").'</li>'.  
                       '<li>'.&mt('User, course, and student share same domain').'</li>'.  
                       '</ul>'.  
                       '</td>'.  
                       '<td class="LC_left_item">';  
         foreach my $item ('by','for') {  
             $datatable .= '<fieldset style="display: inline-block;">'.  
                           '<legend>'.$ownertitles{$item}.'</legend>';  
             if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {  
                 foreach my $type (@{$types}) {  
                     my $checked;  
                     if ($ownerchg{$item}{$type}) {  
                         $checked = ' checked="checked"';  
                     }  
                     $datatable .= '<span class="LC_nobreak"><label>'.  
                                   '<input type="checkbox" name="passwords_crsowner_'.$item.'" value="'.  
                                   $type.'"'.$checked.' />'.$usertypes->{$type}.'</label>'.  
                                   '</span>&nbsp;&nbsp; ';  
                 }  
             }  
             my $checked;  
             if ($ownerchg{$item}{'default'}) {  
                 $checked = ' checked="checked"';  
             }  
             $datatable .= '<span class="LC_nobreak"><label><input type="checkbox" '.  
                           'name="passwords_crsowner_'.$item.'" value="default"'.$checked.' />'.  
                           $othertitle.'</label></span></fieldset>';  
         }  
         $datatable .= '</td></tr>';  
     }      }
     return $datatable;      return ($datatable,$itemcount);
 }  }
   
 sub print_usersessions {  sub print_ssl {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($css_class,$datatable,%checked,%choices);      my ($css_class,$datatable);
     my (%by_ip,%by_location,@intdoms);  
     &build_location_hashes(\@intdoms,\%by_ip,\%by_location);  
   
     my @alldoms = &Apache::lonnet::all_domains();  
     my %serverhomes = %Apache::lonnet::serverhomeIDs;  
     my %servers = &Apache::lonnet::internet_dom_servers($dom);  
     my %altids = &id_for_thisdom(%servers);  
     my $itemcount = 1;      my $itemcount = 1;
     if ($position eq 'top') {      if ($position eq 'top') {
         if (keys(%serverhomes) > 1) {          my $primary_id = &Apache::lonnet::domain($dom,'primary');
             my %spareid = &current_offloads_to($dom,$settings,\%servers);          my $intdom = &Apache::lonnet::internet_dom($primary_id);
             my $curroffloadnow;          my $same_institution;
             if (ref($settings) eq 'HASH') {          if ($intdom ne '') {
                 if (ref($settings->{'offloadnow'}) eq 'HASH') {              my $internet_names = &Apache::lonnet::get_internet_names($Apache::lonnet::perlvar{'lonHostID'});
                     $curroffloadnow = $settings->{'offloadnow'};              if (ref($internet_names) eq 'ARRAY') {
                   if (grep(/^\Q$intdom\E$/,@{$internet_names})) {
                       $same_institution = 1;
                 }                  }
             }              }
             $datatable .= &spares_row($dom,\%servers,\%spareid,\%serverhomes,\%altids,$curroffloadnow,$rowtotal);          }
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable = '<tr'.$css_class.'><td colspan="2">';
           if ($same_institution) {
               my %domservers = &Apache::lonnet::get_servers($dom);
               $datatable .= &LONCAPA::SSL::print_certstatus(\%domservers,'web','domprefs');
         } else {          } else {
             $datatable .= '<tr'.$css_class.'><td colspan="2">'.              $datatable .= &mt("You need to be logged into one of your own domain's servers to display information about the status of LON-CAPA SSL certificates.");
                           &mt('Nothing to set here, as the cluster to which this domain belongs only contains one server.');  
         }          }
           $datatable .= '</td></tr>';
           $itemcount ++;
     } else {      } else {
         if (keys(%by_location) == 0) {          my %titles = &ssl_titles();
             $datatable .= '<tr'.$css_class.'><td colspan="2">'.          my (%by_ip,%by_location,@intdoms,@instdoms);
                           &mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.');          &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
         } else {          my @alldoms = &Apache::lonnet::all_domains();
             my %lt = &usersession_titles();          my %serverhomes = %Apache::lonnet::serverhomeIDs;
             my $numinrow = 5;          my @domservers = &Apache::lonnet::get_servers($dom);
             my $prefix;          my %servers = &Apache::lonnet::internet_dom_servers($dom);
             my @types;          my %altids = &id_for_thisdom(%servers);
             if ($position eq 'bottom') {          if (($position eq 'connto') || ($position eq 'connfrom')) {
                 $prefix = 'remote';              my $legacy;
                 @types = ('version','excludedomain','includedomain');              unless (ref($settings) eq 'HASH') {
             } else {                  my $name;
                 $prefix = 'hosted';                  if ($position eq 'connto') {
                 @types = ('excludedomain','includedomain');                      $name = 'loncAllowInsecure';
             }                  } else {
             my (%current,%checkedon,%checkedoff);                      $name = 'londAllowInsecure';
             my @lcversions = &Apache::lonnet::all_loncaparevs();                  }
             my @locations = sort(keys(%by_location));                  my $primarylibserv = &Apache::lonnet::domain($dom,'primary');
             foreach my $type (@types) {                  my @ids=&Apache::lonnet::current_machine_ids();
                 $checkedon{$type} = '';                  if (($primarylibserv ne '') && (!grep(/^\Q$primarylibserv\E$/,@ids))) {
                 $checkedoff{$type} = ' checked="checked"';                      my %what = (
             }                                     $name => 1,
             if (ref($settings) eq 'HASH') {                                 );
                 if (ref($settings->{$prefix}) eq 'HASH') {                      my ($result,$returnhash) =
                     foreach my $key (keys(%{$settings->{$prefix}})) {                          &Apache::lonnet::get_remote_globals($primarylibserv,\%what);
                         $current{$key} = $settings->{$prefix}{$key};                      if ($result eq 'ok') {
                         if ($key eq 'version') {                          if (ref($returnhash) eq 'HASH') {
                             if ($current{$key} ne '') {                              $legacy = $returnhash->{$name};
                                 $checkedon{$key} = ' checked="checked"';  
                                 $checkedoff{$key} = '';  
                             }  
                         } elsif (ref($current{$key}) eq 'ARRAY') {  
                             $checkedon{$key} = ' checked="checked"';  
                             $checkedoff{$key} = '';  
                         }                          }
                     }                      }
                   } else {
                       $legacy = $Apache::lonnet::perlvar{$name};
                 }                  }
             }              }
             foreach my $type (@types) {              foreach my $type ('dom','intdom','other') {
                 next if ($type ne 'version' && !@locations);                  my %checked;
                 $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';                  $css_class = $itemcount%2?' class="LC_odd_row"':'';
                 $datatable .= '<tr'.$css_class.'>                  $datatable .= '<tr'.$css_class.'><td>'.$titles{$type}.'</td>'.
                                <td><span class="LC_nobreak">'.$lt{$type}.'</span><br />                                '<td class="LC_right_item">';
                                <span class="LC_nobreak">&nbsp;                  my $skip; 
                                <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedoff{$type}.' value="0" />'.&mt('Not in use').'</label>&nbsp;                  if ($type eq 'dom') {
                                <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedon{$type}.' value="1" />'.&mt('In use').'</label></span></td><td>';                      unless (keys(%servers) > 1) {
                 if ($type eq 'version') {                          $datatable .= &mt('Nothing to set here, as there are no other servers/VMs');    
                     my $selector = '<select name="'.$prefix.'_version">';                          $skip = 1;
                     foreach my $version (@lcversions) {  
                         my $selected = '';  
                         if ($current{'version'} eq $version) {  
                             $selected = ' selected="selected"';  
                         }  
                         $selector .= ' <option value="'.$version.'"'.  
                                      $selected.'>'.$version.'</option>';  
                     }                      }
                     $selector .= '</select> ';                  }
                     $datatable .= &mt('remote server must be version: [_1] or later',$selector);                  if ($type eq 'intdom') {
                 } else {                      unless (@instdoms > 1) {
                     $datatable.= '<div><input type="button" value="'.&mt('check all').'" '.                          $datatable .= &mt('Nothing to set here, as there are no other domains for this institution');
                                  'onclick="javascript:checkAll(document.display.'.$prefix.'_'.$type.')"'.                          $skip = 1;
                                  ' />'.('&nbsp;'x2).                      } 
                                  '<input type="button" value="'.&mt('uncheck all').'" '.                  } elsif ($type eq 'other') {
                                  'onclick="javascript:uncheckAll(document.display.'.$prefix.'_'.$type.')" />'.                      if (keys(%by_location) == 0) {
                                  "\n".                          $datatable .= &mt('Nothing to set here, as there are no other institutions');
                                  '</div><div><table>';                          $skip = 1;
                     my $rem;                      }
                     for (my $i=0; $i<@locations; $i++) {                  }
                         my ($showloc,$value,$checkedtype);                  unless ($skip) {
                         if (ref($by_location{$locations[$i]}) eq 'ARRAY') {                      $checked{'yes'} = ' checked="checked"'; 
                             my $ip = $by_location{$locations[$i]}->[0];                      if (ref($settings) eq 'HASH') {
                             if (ref($by_ip{$ip}) eq 'ARRAY') {                          if (ref($settings->{$position}) eq 'HASH') {
                                  $value = join(':',@{$by_ip{$ip}});                              if ($settings->{$position}->{$type} =~ /^(no|req)$/) {
                                 $showloc = join(', ',@{$by_ip{$ip}});                                  $checked{$1} = $checked{'yes'};
                                 if (ref($current{$type}) eq 'ARRAY') {                                  delete($checked{'yes'}); 
                                     foreach my $loc (@{$by_ip{$ip}}) {    
                                         if (grep(/^\Q$loc\E$/,@{$current{$type}})) {  
                                             $checkedtype = ' checked="checked"';  
                                             last;  
                                         }  
                                     }  
                                 }  
                             }                              }
                         }                          }
                         $rem = $i%($numinrow);                      } else {
                         if ($rem == 0) {                          if ($legacy == 0) {
                             if ($i > 0) {                              $checked{'req'} = $checked{'yes'};
                                 $datatable .= '</tr>';                              delete($checked{'yes'});    
                             }                          }
                             $datatable .= '<tr>';  
                         }  
                         $datatable .= '<td class="LC_left_item">'.  
                                       '<span class="LC_nobreak"><label>'.  
                                       '<input type="checkbox" name="'.$prefix.'_'.$type.  
                                       '" value="'.$value.'"'.$checkedtype.' />'.$showloc.  
                                       '</label></span></td>';  
                     }                      }
                     $rem = @locations%($numinrow);                      foreach my $option ('no','yes','req') {
                     my $colsleft = $numinrow - $rem;                          $datatable .= '<span class="LC_nobreak"><label>'.
                     if ($colsleft > 1 ) {                                        '<input type="radio" name="'.$position.'_'.$type.'" '.
                         $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.                                        'value="'.$option.'"'.$checked{$option}.' />'.$titles{$option}.
                                       '&nbsp;</td>';                                        '</label></span>'.('&nbsp;'x2);
                     } elsif ($colsleft == 1) {  
                         $datatable .= '<td class="LC_left_item">&nbsp;</td>';  
                     }                      }
                     $datatable .= '</tr></table>';  
                 }                  }
                 $datatable .= '</td></tr>';                  $datatable .= '</td></tr>';
                   $itemcount ++; 
               }
           } else {
               my $prefix = 'replication';
               my @types = ('certreq','nocertreq');
               if (keys(%by_location) == 0) {
                   $datatable .= '<tr'.$css_class.'><td>'.
                                 &mt('Nothing to set here, as there are no other institutions').
                                 '</td></tr>';
                 $itemcount ++;                  $itemcount ++;
               } else {
                   ($datatable,$itemcount) = 
                       &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles);
             }              }
         }          }
     }      }
Line 4781  sub print_usersessions { Line 6049  sub print_usersessions {
     return $datatable;      return $datatable;
 }  }
   
   sub ssl_titles {
       return &Apache::lonlocal::texthash (
                  dom           => 'LON-CAPA servers/VMs from same domain',
                  intdom        => 'LON-CAPA servers/VMs from same "internet" domain',
                  other         => 'External LON-CAPA servers/VMs',
                  connto        => 'Connections to other servers',
                  connfrom      => 'Connections from other servers',
                  replication   => 'Replicating content to other institutions',
                  certreq       => 'Client certificate required, but specific domains exempt',
                  nocertreq     => 'No client certificate required, except for specific domains',
                  no            => 'SSL not used',
                  yes           => 'SSL Optional (used if available)',
                  req           => 'SSL Required',
       );
   }
   
   sub print_trust {
       my ($prefix,$dom,$settings,$rowtotal) = @_;
       my ($css_class,$datatable,%checked,%choices);
       my (%by_ip,%by_location,@intdoms,@instdoms);
       &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
       my $itemcount = 1;
       my %titles = &trust_titles();
       my @types = ('exc','inc');
       if ($prefix eq 'top') {
           $prefix = 'content';
       } elsif ($prefix eq 'bottom') {
           $prefix = 'msg';
       }
       ($datatable,$itemcount) = &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles);
       $$rowtotal += $itemcount;
       return $datatable;
   }
   
   sub trust_titles {
       return &Apache::lonlocal::texthash(
                  content  => "Access to this domain's content by others",
                  shared   => "Access to other domain's content by this domain",
                  enroll   => "Enrollment in this domain's courses by others", 
                  othcoau  => "Co-author roles in this domain for others",
                  coaurem  => "Co-author roles for this domain's users elsewhere", 
                  domroles => "Domain roles in this domain assignable to others",
                  catalog  => "Course Catalog for this domain displayed elsewhere",
                  reqcrs   => "Requests for creation of courses in this domain by others",
                  msg      => "Users in other domains can send messages to this domain",
                  exc      => "Allow all, but exclude specific domains",
                  inc      => "Deny all, but include specific domains",
              );
   } 
   
 sub build_location_hashes {  sub build_location_hashes {
     my ($intdoms,$by_ip,$by_location) = @_;      my ($intdoms,$by_ip,$by_location,$instdoms) = @_;
     return unless((ref($intdoms) eq 'ARRAY') && (ref($by_ip) eq 'HASH') &&      return unless((ref($intdoms) eq 'ARRAY') && (ref($by_ip) eq 'HASH') &&
                   (ref($by_location) eq 'HASH'));                     (ref($by_location) eq 'HASH') && (ref($instdoms) eq 'ARRAY'));
     my %iphost = &Apache::lonnet::get_iphost();      my %iphost = &Apache::lonnet::get_iphost();
     my $primary_id = &Apache::lonnet::domain($env{'request.role.domain'},'primary');      my $primary_id = &Apache::lonnet::domain($env{'request.role.domain'},'primary');
     my $primary_ip = &Apache::lonnet::get_host_ip($primary_id);      my $primary_ip = &Apache::lonnet::get_host_ip($primary_id);
Line 4801  sub build_location_hashes { Line 6119  sub build_location_hashes {
             foreach my $id (@{$iphost{$ip}}) {              foreach my $id (@{$iphost{$ip}}) {
                 my $location = &Apache::lonnet::internet_dom($id);                  my $location = &Apache::lonnet::internet_dom($id);
                 if ($location) {                  if ($location) {
                     next if (grep(/^\Q$location\E$/,@{$intdoms}));                      if (grep(/^\Q$location\E$/,@{$intdoms})) {
                           my $dom = &Apache::lonnet::host_domain($id);
                           unless (grep(/^\Q$dom\E/,@{$instdoms})) {
                               push(@{$instdoms},$dom);
                           }
                           next;
                       }
                     if (ref($by_ip->{$ip}) eq 'ARRAY') {                      if (ref($by_ip->{$ip}) eq 'ARRAY') {
                         unless(grep(/^\Q$location\E$/,@{$by_ip->{$ip}})) {                          unless(grep(/^\Q$location\E$/,@{$by_ip->{$ip}})) {
                             push(@{$by_ip->{$ip}},$location);                              push(@{$by_ip->{$ip}},$location);
Line 5108  sub print_loadbalancing { Line 6432  sub print_loadbalancing {
         my $disabled_div_style = 'display: block';          my $disabled_div_style = 'display: block';
         my $homedom_div_style = 'display: none';          my $homedom_div_style = 'display: none';
         $datatable .= '<tr class="'.$css_class[$cssidx].'">'.          $datatable .= '<tr class="'.$css_class[$cssidx].'">'.
                       '<td rowspan="'.$rownum.'" valign="top">'.                        '<td rowspan="'.$rownum.'" style="vertical-align: top">'.
                       '<p>';                        '<p>';
         if ($lonhost eq '') {          if ($lonhost eq '') {
             $datatable .= '<span class="LC_nobreak">';              $datatable .= '<span class="LC_nobreak">';
Line 5141  sub print_loadbalancing { Line 6465  sub print_loadbalancing {
                 $homedom_div_style = 'display: block';                  $homedom_div_style = 'display: block';
             }              }
         }          }
         $datatable .= '</p></td><td rowspan="'.$rownum.'" valign="top">'.          $datatable .= '</p></td><td rowspan="'.$rownum.'" style="vertical-align: top">'.
                   '<div id="loadbalancing_disabled_'.$balnum.'" style="'.                    '<div id="loadbalancing_disabled_'.$balnum.'" style="'.
                   $disabled_div_style.'">'.$disabledtext.'</div>'."\n".                    $disabled_div_style.'">'.$disabledtext.'</div>'."\n".
                   '<div id="loadbalancing_targets_'.$balnum.'" style="'.$targets_div_style.'">'.&mt('Offloads to:').'<br />';                    '<div id="loadbalancing_targets_'.$balnum.'" style="'.$targets_div_style.'">'.&mt('Offloads to:').'<br />';
Line 5152  sub print_loadbalancing { Line 6476  sub print_loadbalancing {
                                   no => ' checked="checked"',                                    no => ' checked="checked"',
                               );                                );
         my %balcookiechecked = (          my %balcookiechecked = (
                                   no => ' checked="checked"',                                    no => ' checked="checked"', 
                                );                                 );
         foreach my $sparetype (@sparestypes) {          foreach my $sparetype (@sparestypes) {
             my $targettable;              my $targettable;
Line 5370  sub loadbalance_rule_row { Line 6694  sub loadbalance_rule_row {
     }      }
     my $space;      my $space;
     if ($islast && $num == 1) {      if ($islast && $num == 1) {
         $space = '<div display="inline-block">&nbsp;</div>';          $space = '<div style="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 style="vertical-align: top">'.$space.
         '<div id="balanceruletitle_'.$balnum.'_'.$type.'" style="'.$style.'">'.$title.'</div></td>'."\n".          '<div id="balanceruletitle_'.$balnum.'_'.$type.'" style="'.$style.'">'.$title.'</div></td>'."\n".
         '<td valaign="top">'.$space.          '<td valaign="top">'.$space.
         '<div id="balancerule_'.$balnum.'_'.$type.'" style="'.$style.'">'."\n";          '<div id="balancerule_'.$balnum.'_'.$type.'" style="'.$style.'">'."\n";
Line 5462  sub contact_titles { Line 6786  sub contact_titles {
                    'requestsmail'    => 'E-mail from course requests requiring approval',                     'requestsmail'    => 'E-mail from course requests requiring approval',
                    'updatesmail'     => 'E-mail from nightly check of LON-CAPA module integrity/updates',                     'updatesmail'     => 'E-mail from nightly check of LON-CAPA module integrity/updates',
                    'idconflictsmail' => 'E-mail from bi-nightly check for multiple users sharing same student/employee ID',                     'idconflictsmail' => 'E-mail from bi-nightly check for multiple users sharing same student/employee ID',
                    'hostipmail'      => 'E-mail from nightly check of hostname/IP network changes',                     'errorthreshold'  => 'Error/warning threshold for status e-mail',
                      'errorsysmail'    => 'Error threshold for e-mail to core group',
                      'errorweights'    => 'Weights used to compute error count',
                      'errorexcluded'   => 'Servers with unsent updates excluded from count',
                  );                   );
     my %short_titles = &Apache::lonlocal::texthash (      my %short_titles = &Apache::lonlocal::texthash (
                            adminemail   => 'Admin E-mail address',                             adminemail   => 'Admin E-mail address',
Line 5509  sub tool_titles { Line 6836  sub tool_titles {
                      unofficial => 'Unofficial courses',                       unofficial => 'Unofficial courses',
                      community  => 'Communities',                       community  => 'Communities',
                      textbook   => 'Textbook courses',                       textbook   => 'Textbook courses',
                        placement  => 'Placement tests',
                  );                   );
     return %titles;      return %titles;
 }  }
Line 5519  sub courserequest_titles { Line 6847  sub courserequest_titles {
                                    unofficial => 'Unofficial',                                     unofficial => 'Unofficial',
                                    community  => 'Communities',                                     community  => 'Communities',
                                    textbook   => 'Textbook',                                     textbook   => 'Textbook',
                                      placement  => 'Placement tests',
                                      lti        => 'LTI Provider',
                                    norequest  => 'Not allowed',                                     norequest  => 'Not allowed',
                                    approval   => 'Approval by Dom. Coord.',                                     approval   => 'Approval by DC',
                                    validate   => 'With validation',                                     validate   => 'With validation',
                                    autolimit  => 'Numerical limit',                                     autolimit  => 'Numerical limit',
                                    unlimited  => '(blank for unlimited)',                                     unlimited  => '(blank for unlimited)',
Line 5609  sub print_usercreation { Line 6939  sub print_usercreation {
             }              }
             $datatable .= '<tr'.$css_class.'>'.              $datatable .= '<tr'.$css_class.'>'.
                          '<td><span class="LC_nobreak">'.$lt{$item}.                           '<td><span class="LC_nobreak">'.$lt{$item}.
                          '</span></td><td align="right">';                           '</span></td><td style="text-align: right">';
             my @options = ('any');              my @options = ('any');
             if (ref($rules) eq 'HASH') {              if (ref($rules) eq 'HASH') {
                 if (keys(%{$rules}) > 0) {                  if (keys(%{$rules}) > 0) {
Line 5632  sub print_usercreation { Line 6962  sub print_usercreation {
         }          }
     } else {      } else {
         my @contexts = ('author','course','domain');          my @contexts = ('author','course','domain');
         my @authtypes = ('int','krb4','krb5','loc');          my @authtypes = ('int','krb4','krb5','loc','lti');
         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 5731  sub print_selfcreation { Line 7061  sub print_selfcreation {
         ($datatable,$itemcount) = &radiobutton_prefs(\%radiohash,\@toggles,\%defaultchecked,          ($datatable,$itemcount) = &radiobutton_prefs(\%radiohash,\@toggles,\%defaultchecked,
                                                      \%choices,$itemcount,$onclick);                                                       \%choices,$itemcount,$onclick);
         $$rowtotal += $itemcount;          $$rowtotal += $itemcount;
           
         if (ref($usertypes) eq 'HASH') {          if (ref($usertypes) eq 'HASH') {
             if (keys(%{$usertypes}) > 0) {              if (keys(%{$usertypes}) > 0) {
                 $datatable .= &insttypes_row($createsettings,$types,$usertypes,                  $datatable .= &insttypes_row($createsettings,$types,$usertypes,
Line 5868  sub print_selfcreation { Line 7198  sub print_selfcreation {
                 my $currstyle = 'display:none';                  my $currstyle = 'display:none';
                 if (grep(/^\Q$status\E$/,@ordered)) {                  if (grep(/^\Q$status\E$/,@ordered)) {
                     $currstyle = $rowstyle;                      $currstyle = $rowstyle;
                     $hidden = 0;                      $hidden = 0; 
                 }                  }
                 $datatable .= &noninst_users($processing,$emailverified,$emailoptions,$emaildomain,                  $datatable .= &noninst_users($processing,$emailverified,$emailoptions,$emaildomain,
                                              $emailrules,$emailruleorder,$settings,$status,$rowid,                                               $emailrules,$emailruleorder,$settings,$status,$rowid,
Line 5895  sub print_selfcreation { Line 7225  sub print_selfcreation {
             foreach my $status (@posstypes) {              foreach my $status (@posstypes) {
                 my $rowid = $classprefix.$status;                  my $rowid = $classprefix.$status;
                 my $datarowstyle = 'display:none';                  my $datarowstyle = 'display:none';
                 if (grep(/^\Q$status\E$/,@ordered)) {                  if (grep(/^\Q$status\E$/,@ordered)) { 
                     $datarowstyle = $rowstyle;                      $datarowstyle = $rowstyle; 
                 }                  }
                 $datatable .= &modifiable_userdata_row('cancreate','emailusername_'.$status,$settings,                  $datatable .= &modifiable_userdata_row('cancreate','emailusername_'.$status,$settings,
                                                        $numinrow,$$rowtotal,\%usertypeshash,$infofields,                                                         $numinrow,$$rowtotal,\%usertypeshash,$infofields,
Line 5998  function toggleEmailOptions(form,radio,p Line 7328  function toggleEmailOptions(form,radio,p
                     document.getElementById(altprefix+'_inst_'+status).style.display = 'none';                      document.getElementById(altprefix+'_inst_'+status).style.display = 'none';
                     document.getElementById(altprefix+'_noninst_'+status).style.display = 'none';                      document.getElementById(altprefix+'_noninst_'+status).style.display = 'none';
                     if (curr == 'custom') {                      if (curr == 'custom') {
                         if (prefix) {                          if (prefix) { 
                             document.getElementById(prefix+'_'+status).style.display = 'inline';                              document.getElementById(prefix+'_'+status).style.display = 'inline';
                         }                          }
                     } else if (curr == 'inst') {                      } else if (curr == 'inst') {
Line 6021  ENDSCRIPT Line 7351  ENDSCRIPT
   
 sub noninst_users {  sub noninst_users {
     my ($processing,$emailverified,$emailoptions,$emaildomain,$emailrules,      my ($processing,$emailverified,$emailoptions,$emaildomain,$emailrules,
         $emailruleorder,$settings,$type,$rowid,$typetitle,$css_class,$rowstyle,$intdom) = @_;          $emailruleorder,$settings,$type,$rowid,$typetitle,$css_class,$rowstyle,$intdom) = @_; 
     my $class = 'LC_left_item';      my $class = 'LC_left_item';
     if ($css_class) {      if ($css_class) {
         $css_class = ' class="'.$css_class.'"';          $css_class = ' class="'.$css_class.'"'; 
     }      }
     if ($rowid) {      if ($rowid) {
         $rowid = ' id="'.$rowid.'"';          $rowid = ' id="'.$rowid.'"';
Line 6039  sub noninst_users { Line 7369  sub noninst_users {
         $description = &mt('Requests for: [_1] (status self-reported)',$typetitle);          $description = &mt('Requests for: [_1] (status self-reported)',$typetitle);
     }      }
     $output = '<tr'.$css_class.$rowid.$rowstyle.'>'.      $output = '<tr'.$css_class.$rowid.$rowstyle.'>'.
               "<td>$description</td>\n".                "<td>$description</td>\n".           
               '<td class="'.$class.'" colspan="2">'.                '<td class="'.$class.'" colspan="2">'.
               '<table><tr>';                '<table><tr>';
     my %headers = &Apache::lonlocal::texthash(      my %headers = &Apache::lonlocal::texthash( 
               approve  => 'Processing',                approve  => 'Processing',
               email    => 'E-mail',                email    => 'E-mail',
               username => 'Username',                username => 'Username',
Line 6052  sub noninst_users { Line 7382  sub noninst_users {
     }      }
     $output .= '</tr><tr>';      $output .= '</tr><tr>';
     foreach my $item ('approve','email','username') {      foreach my $item ('approve','email','username') {
         $output .= '<td valign="top">';          $output .= '<td style="vertical-align: top">';
         my (%choices,@options,$hashref,$defoption,$name,$onclick,$hascustom);          my (%choices,@options,$hashref,$defoption,$name,$onclick,$hascustom);
         if ($item eq 'approve') {          if ($item eq 'approve') {
             %choices = &Apache::lonlocal::texthash (              %choices = &Apache::lonlocal::texthash (
Line 6167  sub noninst_users { Line 7497  sub noninst_users {
                     my $value;                      my $value;
                     if (ref($emaildomain) eq 'HASH') {                      if (ref($emaildomain) eq 'HASH') {
                         if (ref($emaildomain->{$type}) eq 'HASH') {                          if (ref($emaildomain->{$type}) eq 'HASH') {
                             $value = $emaildomain->{$type}->{$option};                              $value = $emaildomain->{$type}->{$option}; 
                         }                          }
                     }                      }
                     if ($value eq '') {                      if ($value eq '') {
Line 6194  sub noninst_users { Line 7524  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;  
     if ($context eq 'cancreate') {      if ($context eq 'cancreate') {
         $rowname = &mt('CAPTCHA validation');          $rowname = &mt('CAPTCHA validation');
     } elsif ($context eq 'login') {      } elsif ($context eq 'login') {
         $rowname =  &mt('"Contact helpdesk" CAPTCHA validation');          $rowname =  &mt('"Contact helpdesk" CAPTCHA validation');
     } elsif ($context eq 'passwords') {  
         $rowname = &mt('"Forgot Password" CAPTCHA validation');  
         $colspan=1;  
     }      }
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if ($settings->{'captcha'}) {          if ($settings->{'captcha'}) {
Line 6244  sub captcha_choice { Line 7570  sub captcha_choice {
         $css_class .= ' style="'.$rowstyle.'"';          $css_class .= ' style="'.$rowstyle.'"';
     }      }
     my $output = '<tr'.$css_class.'>'.      my $output = '<tr'.$css_class.'>'.
                  '<td class="LC_left_item">'.$rowname.'</td><td class="LC_left_item" colspan="'.$colspan.'">'."\n".                   '<td class="LC_left_item">'.$rowname.'</td><td class="LC_left_item" colspan="2">'."\n".
                  '<table><tr><td>'."\n";                   '<table><tr><td>'."\n";
     foreach my $option ('original','recaptcha','notused') {      foreach my $option ('original','recaptcha','notused') {
         $output .= '<span class="LC_nobreak"><label><input type="radio" name="'.$context.'_captcha" value="'.          $output .= '<span class="LC_nobreak"><label><input type="radio" name="'.$context.'_captcha" value="'.
Line 6376  sub authtype_names { Line 7702  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 6444  sub print_defaults { Line 7771  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');                  my @authtypes = ('internal','krb4','krb5','localauth','lti');
                 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 6481  sub print_defaults { Line 7809  sub print_defaults {
             $datatable .= '</td></tr>';              $datatable .= '</td></tr>';
             $rownum ++;              $rownum ++;
         }          }
       } elsif ($position eq 'middle') {
           my @items = ('intauth_cost','intauth_check','intauth_switch');
           my %defaults;
           if (ref($settings) eq 'HASH') {
               %defaults = %{$settings};
               if ($defaults{'intauth_cost'} !~ /^\d+$/) {
                   $defaults{'intauth_cost'} = 10;
               }
               if ($defaults{'intauth_check'} !~ /^(0|1|2)$/) {
                   $defaults{'intauth_check'} = 0;
               }
               if ($defaults{'intauth_switch'} !~ /^(0|1|2)$/) {
                   $defaults{'intauth_switch'} = 0;
               }
           } else {
               %defaults = (
                             'intauth_cost'   => 10,
                             'intauth_check'  => 0,
                             'intauth_switch' => 0,
                           );
           }
           foreach my $item (@items) {
               if ($rownum%2) {
                   $css_class = '';
               } else {
                   $css_class = ' class="LC_odd_row" ';
               }
               $datatable .= '<tr'.$css_class.'>'.
                             '<td><span class="LC_nobreak">'.$titles->{$item}.
                             '</span></td><td class="LC_left_item" colspan="3">';
               if ($item eq 'intauth_switch') {
                   my @options = (0,1,2);
                   my %optiondesc = &Apache::lonlocal::texthash (
                                      0 => 'No',
                                      1 => 'Yes',
                                      2 => 'Yes, and copy existing passwd file to passwd.bak file',
                                    );
                   $datatable .= '<table width="100%">';
                   foreach my $option (@options) {
                       my $checked = ' ';
                       if ($defaults{$item} eq $option) {
                           $checked = ' checked="checked"';
                       }
                       $datatable .= '<tr><td class="LC_left_item"><span class="LC_nobreak">'.
                                     '<label><input type="radio" name="'.$item.
                                     '" value="'.$option.'"'.$checked.' />'.
                                     $optiondesc{$option}.'</label></span></td></tr>';
                   }
                   $datatable .= '</table>';
               } elsif ($item eq 'intauth_check') {
                   my @options = (0,1,2);
                   my %optiondesc = &Apache::lonlocal::texthash (
                                      0 => 'No',
                                      1 => 'Yes, allow login then update passwd file using default cost (if higher)',
                                      2 => 'Yes, disallow login if stored cost is less than domain default',
                                    );
                   $datatable .= '<table width="100%">';
                   foreach my $option (@options) {
                       my $checked = ' ';
                       my $onclick;
                       if ($defaults{$item} eq $option) {
                           $checked = ' checked="checked"';
                       }
                       if ($option == 2) {
                           $onclick = ' onclick="javascript:warnIntAuth(this);"';
                       }
                       $datatable .= '<tr><td class="LC_left_item"><span class="LC_nobreak">'.
                                     '<label><input type="radio" name="'.$item.
                                     '" value="'.$option.'"'.$checked.$onclick.' />'.
                                     $optiondesc{$option}.'</label></span></td></tr>';
                   }
                   $datatable .= '</table>';
               } else {
                   $datatable .= '<input type="text" name="'.$item.'" value="'.
                                 $defaults{$item}.'" size="3" onblur="javascript:warnIntAuth(this);" />'; 
               }
               $datatable .= '</td></tr>';
               $rownum ++;
           }
     } else {      } else {
         my %defaults;          my %defaults;
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
Line 6505  sub print_defaults { Line 7912  sub print_defaults {
                     $datatable .= '</select>&nbsp;'.&mt('Internal ID:').'&nbsp;<b>'.$item.'</b>&nbsp;'.                      $datatable .= '</select>&nbsp;'.&mt('Internal ID:').'&nbsp;<b>'.$item.'</b>&nbsp;'.
                                   '<input type="checkbox" name="inststatus_delete" value="'.$item.'" />'.                                    '<input type="checkbox" name="inststatus_delete" value="'.$item.'" />'.
                                   &mt('delete').'</span></td>'.                                    &mt('delete').'</span></td>'.
                                   '<td class="LC_left_item"><span class="LC_nobreak">'.&mt('Name displayed:').                                    '<td class="LC_left_item" colspan="2"><span class="LC_nobreak">'.&mt('Name displayed:').
                                   '<input type="text" size="20" name="inststatus_title_'.$item.'" value="'.$title.'" />'.                                    '<input type="text" size="20" name="inststatus_title_'.$item.'" value="'.$title.'" />'.
                                   '</span></td></tr>';                                    '</span></td></tr>';
                 }                  }
Line 6524  sub print_defaults { Line 7931  sub print_defaults {
                 $datatable .= '</select>&nbsp;'.&mt('Internal ID:').                  $datatable .= '</select>&nbsp;'.&mt('Internal ID:').
                               '<input type="text" size="10" name="addinststatus" value="" />'.                                '<input type="text" size="10" name="addinststatus" value="" />'.
                               '&nbsp;'.&mt('(new)').                                '&nbsp;'.&mt('(new)').
                               '</span></td><td class="LC_left_item"><span class="LC_nobreak">'.                                '</span></td><td class="LC_left_item" colspan="2"><span class="LC_nobreak">'.
                               &mt('Name displayed:').                                &mt('Name displayed:').
                               '<input type="text" size="20" name="addinststatus_title" value="" /></span></td>'.                                '<input type="text" size="20" name="addinststatus_title" value="" /></span></td>'.
                               '</tr>'."\n";                                '</tr>'."\n";
Line 6741  sub print_scantronformat { Line 8148  sub print_scantronformat {
         }          }
         $datatable .= '</span></td>';          $datatable .= '</span></td>';
         if (keys(%error) == 0) {           if (keys(%error) == 0) { 
             $datatable .= '<td valign="bottom">';              $datatable .= '<td style="vertical-align: bottom">';
             if (!$switchserver) {              if (!$switchserver) {
                 $datatable .= &mt('Upload:').'<br />';                  $datatable .= &mt('Upload:').'<br />';
             }              }
Line 6906  sub scantronconfig_titles { Line 8313  sub scantronconfig_titles {
                                           csv => 'Comma separated values (.csv)',                                            csv => 'Comma separated values (.csv)',
                                           hdr => 'Remove first line in file (contains column titles)',                                            hdr => 'Remove first line in file (contains column titles)',
                                           pad => 'Prepend 0s to PaperID',                                            pad => 'Prepend 0s to PaperID',
                                           rem => 'Remove leading spaces (except Question Response columns)',                                            rem => 'Remove leading spaces (except Q columns)',
                                           CODE => 'CODE',                                            CODE => 'CODE',
                                           ID   => 'Student ID',                                            ID   => 'Student ID',
                                           PaperID => 'Paper ID',                                            PaperID => 'Paper ID',
Line 6976  sub print_coursecategories { Line 8383  sub print_coursecategories {
         my $toggle_catscomm_dom = ' checked="checked" ';          my $toggle_catscomm_dom = ' checked="checked" ';
         my $can_catcomm_comm = ' ';          my $can_catcomm_comm = ' ';
         my $can_catcomm_dom = ' checked="checked" ';          my $can_catcomm_dom = ' checked="checked" ';
           my $toggle_catsplace_place = ' ';
           my $toggle_catsplace_dom = ' checked="checked" ';
           my $can_catplace_place = ' ';
           my $can_catplace_dom = ' checked="checked" ';
   
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if ($settings->{'togglecats'} eq 'crs') {              if ($settings->{'togglecats'} eq 'crs') {
Line 6994  sub print_coursecategories { Line 8405  sub print_coursecategories {
                 $can_catcomm_comm = $can_catcomm_dom;                  $can_catcomm_comm = $can_catcomm_dom;
                 $can_catcomm_dom = ' ';                  $can_catcomm_dom = ' ';
             }              }
               if ($settings->{'togglecatsplace'} eq 'place') {
                   $toggle_catsplace_place = $toggle_catsplace_dom;
                   $toggle_catsplace_dom = ' ';
               }
               if ($settings->{'categorizeplace'} eq 'place') {
                   $can_catplace_place = $can_catplace_dom;
                   $can_catplace_dom = ' ';
               }
         }          }
         my %title = &Apache::lonlocal::texthash (          my %title = &Apache::lonlocal::texthash (
                      togglecats     => 'Show/Hide a course in catalog',                       togglecats      => 'Show/Hide a course in catalog',
                      togglecatscomm => 'Show/Hide a community in catalog',                       togglecatscomm  => 'Show/Hide a community in catalog',
                      categorize     => 'Assign a category to a course',                       togglecatsplace => 'Show/Hide a placement test in catalog',
                      categorizecomm => 'Assign a category to a community',                       categorize      => 'Assign a category to a course',
                        categorizecomm  => 'Assign a category to a community',
                        categorizeplace => 'Assign a category to a placement test',
                     );                      );
         my %level = &Apache::lonlocal::texthash (          my %level = &Apache::lonlocal::texthash (
                      dom  => 'Set in Domain',                       dom   => 'Set in Domain',
                      crs  => 'Set in Course',                       crs   => 'Set in Course',
                      comm => 'Set in Community',                       comm  => 'Set in Community',
                        place => 'Set in Placement Test',
                     );                      );
         $datatable = '<tr class="LC_odd_row">'.          $datatable = '<tr class="LC_odd_row">'.
                   '<td>'.$title{'togglecats'}.'</td>'.                    '<td>'.$title{'togglecats'}.'</td>'.
Line 7034  sub print_coursecategories { Line 8456  sub print_coursecategories {
                   $can_catcomm_dom.' value="dom" />'.$level{'dom'}.'</label>&nbsp;'.                    $can_catcomm_dom.' value="dom" />'.$level{'dom'}.'</label>&nbsp;'.
                   '<label><input type="radio" name="categorizecomm"'.                    '<label><input type="radio" name="categorizecomm"'.
                   $can_catcomm_comm.'value="comm" />'.$level{'comm'}.'</label></span></td>'.                    $can_catcomm_comm.'value="comm" />'.$level{'comm'}.'</label></span></td>'.
                     '</tr><tr class="LC_odd_row">'.
                     '<td>'.$title{'togglecatsplace'}.'</td>'.
                     '<td class="LC_right_item"><span class="LC_nobreak"><label>'.
                     '<input type="radio" name="togglecatsplace"'.
                     $toggle_catsplace_dom.' value="dom" />'.$level{'dom'}.'</label>&nbsp;'.
                     '<label><input type="radio" name="togglecatscomm"'.
                     $toggle_catsplace_place.' value="comm" />'.$level{'place'}.'</label></span></td>'.
                     '</tr><tr>'.
                     '<td>'.$title{'categorizeplace'}.'</td>'.
                     '<td class="LC_right_item"><span class="LC_nobreak">'.
                     '<label><input type="radio" name="categorizeplace"'.
                     $can_catplace_dom.' value="dom" />'.$level{'dom'}.'</label>&nbsp;'.
                     '<label><input type="radio" name="categorizeplace"'.
                     $can_catplace_place.'value="place" />'.$level{'place'}.'</label></span></td>'.
                   '</tr>';                    '</tr>';
         $$rowtotal += 4;          $$rowtotal += 6;
     } else {      } else {
         my $css_class;          my $css_class;
         my $itemcount = 1;          my $itemcount = 1;
Line 7060  sub print_coursecategories { Line 8496  sub print_coursecategories {
                     my %default_names = (                      my %default_names = (
                           instcode    => &mt('Official courses'),                            instcode    => &mt('Official courses'),
                           communities => &mt('Communities'),                            communities => &mt('Communities'),
                             placement   => &mt('Placement Tests'),
                     );                      );
   
                     if ((!grep(/^instcode$/,@{$cats[0]})) ||                       if ((!grep(/^instcode$/,@{$cats[0]})) || 
                         ($cathash->{'instcode::0'} eq '') ||                          ($cathash->{'instcode::0'} eq '') ||
                         (!grep(/^communities$/,@{$cats[0]})) ||                           (!grep(/^communities$/,@{$cats[0]})) || 
                         ($cathash->{'communities::0'} eq '')) {                          ($cathash->{'communities::0'} eq '') ||
                           (!grep(/^placement$/,@{$cats[0]})) ||
                           ($cathash->{'placement::0'} eq '')) {
                         $maxnum ++;                          $maxnum ++;
                     }                      }
                     my $lastidx;                      my $lastidx;
Line 7086  sub print_coursecategories { Line 8525  sub print_coursecategories {
                             $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';                              $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
                         }                          }
                         $datatable .= '</select></span></td><td>';                          $datatable .= '</select></span></td><td>';
                         if ($parent eq 'instcode' || $parent eq 'communities') {                          if ($parent eq 'instcode' || $parent eq 'communities' || $parent eq 'placement') {
                             $datatable .=  '<span class="LC_nobreak">'                              $datatable .=  '<span class="LC_nobreak">'
                                            .$default_names{$parent}.'</span>';                                             .$default_names{$parent}.'</span>';
                             if ($parent eq 'instcode') {                              if ($parent eq 'instcode') {
Line 7109  sub print_coursecategories { Line 8548  sub print_coursecategories {
                             $datatable .= '<label><input type="radio" name="'                              $datatable .= '<label><input type="radio" name="'
                                           .$parent.'" value="0" />'                                            .$parent.'" value="0" />'
                                           .&mt('Do not display').'</label></span>';                                            .&mt('Do not display').'</label></span>';
                             if ($parent eq 'communities') {                              if (($parent eq 'communities') || ($parent eq 'placement')) {
                                 $datatable .= '</td></tr></table>';                                  $datatable .= '</td></tr></table>';
                             }                              }
                             $datatable .= '</td>';                              $datatable .= '</td>';
Line 7141  sub print_coursecategories { Line 8580  sub print_coursecategories {
                                   .'<input type="text" size="20" name="addcategory_name" value="" /></td>'                                    .'<input type="text" size="20" name="addcategory_name" value="" /></td>'
                                   .'</tr>'."\n";                                    .'</tr>'."\n";
                     $itemcount ++;                      $itemcount ++;
                     foreach my $default ('instcode','communities') {                      foreach my $default ('instcode','communities','placement') {
                         if ((!grep(/^\Q$default\E$/,@{$cats[0]})) || ($cathash->{$default.'::0'} eq '')) {                          if ((!grep(/^\Q$default\E$/,@{$cats[0]})) || ($cathash->{$default.'::0'} eq '')) {
                             $css_class = $itemcount%2?' class="LC_odd_row"':'';                              $css_class = $itemcount%2?' class="LC_odd_row"':'';
                             my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','$lastidx'".');"';                              my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','$lastidx'".');"';
Line 7230  sub print_serverstatuses { Line 8669  sub print_serverstatuses {
   
 sub serverstatus_pages {  sub serverstatus_pages {
     return ('userstatus','lonstatus','loncron','server-status','codeversions',      return ('userstatus','lonstatus','loncron','server-status','codeversions',
             'checksums','clusterstatus','metadata_keywords','metadata_harvest',              'checksums','clusterstatus','certstatus','metadata_keywords',
             'takeoffline','takeonline','showenv','toggledebug','ping','domconf',              'metadata_harvest','takeoffline','takeonline','showenv','toggledebug',
             'uniquecodes','diskusage','coursecatalog');              'ping','domconf','uniquecodes','diskusage','coursecatalog');
 }  }
   
 sub defaults_javascript {  sub defaults_javascript {
     my ($settings) = @_;      my ($settings) = @_;
     return unless (ref($settings) eq 'HASH');      my $intauthcheck = &mt('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.');
       my $intauthcost = &mt('Warning: bcrypt encryption cost for internal authentication must be an integer.');
       &js_escape(\$intauthcheck);
       &js_escape(\$intauthcost);
       my $intauthjs = <<"ENDSCRIPT";
   
   function warnIntAuth(field) {
       if (field.name == 'intauth_check') {
           if (field.value == '2') {
               alert('$intauthcheck');
           }
       }
       if (field.name == 'intauth_cost') {
           field.value.replace(/\s/g,'');
           if (field.value != '') {
               var regexdigit=/^\\d+\$/;
               if (!regexdigit.test(field.value)) {
                   alert('$intauthcost');
               }
           }
       }
       return;
   }
   
   ENDSCRIPT
   
       if (ref($settings) ne 'HASH') {
           return &Apache::lonhtmlcommon::scripttag($intauthjs);
       }
     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 7291  $jstext Line 8758  $jstext
     return;      return;
 }  }
   
   $intauthjs
   
 // ]]>  // ]]>
 </script>  </script>
   
 ENDSCRIPT  ENDSCRIPT
     }  
 }  
   
 sub passwords_javascript {  
     my %intalert = &Apache::lonlocal::texthash (  
         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.',  
         authcost => 'Warning: bcrypt encryption cost for internal authentication must be an integer.',  
         passmin => 'Warning: minimum password length must be a positive integer greater than 6.',  
         passmax => 'Warning: maximum password length must be a positive integer (or blank).',  
         passexp => 'Warning: days before password expiration must be a positive integer (or blank).',  
         passnum => 'Warning: number of previous passwords to save must be a positive integer (or blank).',  
     );  
     &js_escape(\%intalert);  
     my $defmin = $Apache::lonnet::passwdmin;  
     my $intauthjs = <<"ENDSCRIPT";  
   
 function warnIntAuth(field) {  
     if (field.name == 'intauth_check') {  
         if (field.value == '2') {  
             alert('$intalert{authcheck}');  
         }  
     }  
     if (field.name == 'intauth_cost') {  
         field.value.replace(/\s/g,'');  
         if (field.value != '') {  
             var regexdigit=/^\\d+\$/;  
             if (!regexdigit.test(field.value)) {  
                 alert('$intalert{authcost}');  
             }  
         }  
     }  
     return;  
 }  
   
 function warnIntPass(field) {  
     field.value.replace(/^\s+/,'');  
     field.value.replace(/\s+\$/,'');  
     var regexdigit=/^\\d+\$/;  
     if (field.name == 'passwords_min') {  
         if (field.value == '') {  
             alert('$intalert{passmin}');  
             field.value = '$defmin';  
         } else {  
             if (!regexdigit.test(field.value)) {  
                 alert('$intalert{passmin}');  
                 field.value = '$defmin';  
             }  
             var minval = parseInt(field.value,10);  
             if (minval < $defmin) {  
                 alert('$intalert{passmin}');  
                 field.value = '$defmin';  
             }  
         }  
     } else {      } else {
         if (field.value == '0') {          return &Apache::lonhtmlcommon::scripttag($intauthjs);
             field.value = '';  
         }  
         if (field.value != '') {  
             if (field.name == 'passwords_expire') {  
                 var regexpposnum=/^\\d+(|\\.\\d*)\$/;  
                 if (!regexpposnum.test(field.value)) {  
                     alert('$intalert{passexp}');  
                     field.value = '';  
                 } else {  
                     var expval = parseFloat(field.value);  
                     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 = '';  
                 }  
             }  
         }  
     }      }
     return;  
 }  
   
 ENDSCRIPT  
     return &Apache::lonhtmlcommon::scripttag($intauthjs);  
 }  }
   
 sub coursecategories_javascript {  sub coursecategories_javascript {
Line 7410  sub coursecategories_javascript { Line 8793  sub coursecategories_javascript {
     }      }
     my $instcode_reserved = &mt('The name: [_1] is a reserved category.','"instcode"');      my $instcode_reserved = &mt('The name: [_1] is a reserved category.','"instcode"');
     my $communities_reserved = &mt('The name: [_1] is a reserved category.','"communities"');      my $communities_reserved = &mt('The name: [_1] is a reserved category.','"communities"');
       my $placement_reserved = &mt('The name: [_1] is a reserved category.','"placement"');
     my $choose_again = "\n".&mt('Please use a different name for the new top level category.');       my $choose_again = "\n".&mt('Please use a different name for the new top level category.'); 
     &js_escape(\$instcode_reserved);      &js_escape(\$instcode_reserved);
     &js_escape(\$communities_reserved);      &js_escape(\$communities_reserved);
       &js_escape(\$placement_reserved);
     &js_escape(\$choose_again);      &js_escape(\$choose_again);
     $output = <<"ENDSCRIPT";      $output = <<"ENDSCRIPT";
 <script type="text/javascript">  <script type="text/javascript">
Line 7482  function categoryCheck(form) { Line 8867  function categoryCheck(form) {
         alert('$communities_reserved\\n$choose_again');          alert('$communities_reserved\\n$choose_again');
         return false;          return false;
     }      }
       if (form.elements['addcategory_name'].value == 'placement') {
           alert('$placement_reserved\\n$choose_again');
           return false;
       }
     return true;      return true;
 }  }
   
Line 7498  sub initialize_categories { Line 8887  sub initialize_categories {
     my %default_names = (      my %default_names = (
                       instcode    => 'Official courses (with institutional codes)',                        instcode    => 'Official courses (with institutional codes)',
                       communities => 'Communities',                        communities => 'Communities',
                         placement   => 'Placement Tests',
                         );                          );
     my $select0 = ' selected="selected"';      my %selnum = (
     my $select1 = '';                     instcode    => '0',
     foreach my $default ('instcode','communities') {                     communities => '1',
                      placement   => '2',
                    );
       my %selected;
       foreach my $default ('instcode','communities','placement') {
         $css_class = $itemcount%2?' class="LC_odd_row"':'';          $css_class = $itemcount%2?' class="LC_odd_row"':'';
         $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','0'".');"';          $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','0'".');"';
         if ($default eq 'communities') {          map { $selected{$selnum{$_}} = '' } keys(%selnum);
             $select1 = $select0;          $selected{$selnum{$default}} = ' selected="selected"';
             $select0 = '';  
         }  
         $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'          $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
                      .'<select name="'.$default.'_pos">'                       .'<select name="'.$default.'_pos"'.$chgstr.'>'
                      .'<option value="0"'.$select0.'>1</option>'                       .'<option value="0"'.$selected{'0'}.'>1</option>'
                      .'<option value="1"'.$select1.'>2</option>'                       .'<option value="1"'.$selected{'1'}.'>2</option>'
                      .'<option value="2">3</option></select>&nbsp;'                       .'<option value="2"'.$selected{'2'}.'>3</option>'
                        .'<option value="3">4</option></select>&nbsp;'
                      .$default_names{$default}                       .$default_names{$default}
                      .'</span></td><td><span class="LC_nobreak">'                       .'</span></td><td><span class="LC_nobreak">'
                      .'<label><input type="radio" name="'.$default.'" value="1" checked="checked" />'                       .'<label><input type="radio" name="'.$default.'" value="1" checked="checked" />'
Line 7527  sub initialize_categories { Line 8920  sub initialize_categories {
                   .'<select name="addcategory_pos"'.$chgstr.'>'                    .'<select name="addcategory_pos"'.$chgstr.'>'
                   .'<option value="0">1</option>'                    .'<option value="0">1</option>'
                   .'<option value="1">2</option>'                    .'<option value="1">2</option>'
                   .'<option value="2" selected="selected">3</option></select>&nbsp;'                    .'<option value="2">3</option>'
                     .'<option value="3" selected="selected">4</option></select>&nbsp;'
                   .&mt('Add category').'</span></td><td><span class="LC_nobreak">'.&mt('Name:')                    .&mt('Add category').'</span></td><td><span class="LC_nobreak">'.&mt('Name:')
                   .'&nbsp;<input type="text" size="20" name="addcategory_name" value="" /></span>'                    .'&nbsp;<input type="text" size="20" name="addcategory_name" value="" /></span>'
                   .'</td></tr>';                    .'</td></tr>';
Line 7639  sub modifiable_userdata_row { Line 9033  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 7676  sub modifiable_userdata_row { Line 9072  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;
       my %current;
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if (ref($settings->{$context}) eq 'HASH') {          my $hashref;
           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') {
                 my $hashref = $settings->{$context}->{$role};                  $hashref = $settings->{'lti_instdata'};
                 if ($role eq 'emailusername') {              }
                     if ($statustype) {              if ($role eq 'emailusername') {
                         if (ref($settings->{$context}->{$role}->{$statustype}) eq 'HASH') {                  if ($statustype) {
                             $hashref = $settings->{$context}->{$role}->{$statustype};                      if (ref($settings->{$context}->{$role}->{$statustype}) eq 'HASH') {
                             if (ref($hashref) eq 'HASH') {                           $hashref = $settings->{$context}->{$role}->{$statustype};
                                 foreach my $field (@fields) {  
                                     if ($hashref->{$field}) {  
                                         $checks{$field} = $hashref->{$field};  
                                     }  
                                 }  
                             }  
                         }  
                     }                      }
                 } else {                  }
                     if (ref($hashref) eq 'HASH') {              }
                         foreach my $field (@fields) {          }
                             if ($hashref->{$field}) {          if (ref($hashref) eq 'HASH') { 
                                 $checks{$field} = ' checked="checked" ';              foreach my $field (@fields) {
                             }                  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 7724  sub modifiable_userdata_row { Line 9121  sub modifiable_userdata_row {
         my $check = ' ';          my $check = ' ';
         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]}
             } else {              } elsif ($context ne 'lti') {
                 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 7735  sub modifiable_userdata_row { Line 9132  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 7745  sub modifiable_userdata_row { Line 9143  sub modifiable_userdata_row {
                     $checked='checked="checked" ';                      $checked='checked="checked" ';
                 }                  }
                 $output .= '<label>'.                  $output .= '<label>'.
                            '<input type="radio" name="canmodify_'.$item.'_'.$fields[$i].'" value="'.$option.'" '.$checked.'/>'.                             '<input type="radio" name="'.$prefix.'_'.$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="canmodify_'.$role.'" '.                         '<input type="checkbox" name="'.$prefix.'_'.$role.'" '.
                        'value="'.$fields[$i].'"'.$check.'/>'.$fieldtitles{$fields[$i]}.                         'value="'.$fields[$i].'"'.$check.'/>'.$fieldtitles{$fields[$i]}.
                        '</label>';                         '</label>';
         }          }
Line 7838  sub insttypes_row { Line 9239  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 7851  sub insttypes_row { Line 9252  sub insttypes_row {
         } else {          } else {
             $output .= '<td class="LC_left_item">';              $output .= '<td class="LC_left_item">';
         }          }
         $output .= '&nbsp;';          $output .= '&nbsp;';  
     } else {      } else {
         if ($rem == 0) {          if ($rem == 0) {
             $output .= '<tr>';              $output .= '<tr>';
Line 8783  sub display_colorchgs { Line 10184  sub display_colorchgs {
                         } else {                          } else {
                             my $newitem = $confhash->{$role}{$item};                              my $newitem = $confhash->{$role}{$item};
                             if ($key eq 'images') {                              if ($key eq 'images') {
                                 $newitem = '<img src="'.$confhash->{$role}{$item}.'" alt="'.$choices{$item}.'" valign="bottom" />';                                  $newitem = '<img src="'.$confhash->{$role}{$item}.'" alt="'.$choices{$item}.'" style="vertical-align: bottom" />';
                             }                              }
                             $resulttext .= '<li>'.&mt("$choices{$item} set to [_1]",$newitem).'</li>';                              $resulttext .= '<li>'.&mt("$choices{$item} set to [_1]",$newitem).'</li>';
                         }                          }
Line 8836  sub check_configuser { Line 10237  sub check_configuser {
     my ($configuserok,%currroles);      my ($configuserok,%currroles);
     if ($uhome eq 'no_host') {      if ($uhome eq 'no_host') {
         srand( time() ^ ($$ + ($$ << 15))  ); # Seed rand.          srand( time() ^ ($$ + ($$ << 15))  ); # Seed rand.
         my $configpass = &LONCAPA::Enrollment::create_password($dom);          my $configpass = &LONCAPA::Enrollment::create_password();
         $configuserok =           $configuserok = 
             &Apache::lonnet::modifyuser($dom,$confname,'','internal',              &Apache::lonnet::modifyuser($dom,$confname,'','internal',
                              $configpass,'','','','','',undef,$servadm);                               $configpass,'','','','','',undef,$servadm);
Line 8865  sub check_authorstatus { Line 10266  sub check_authorstatus {
   
 sub publishlogo {  sub publishlogo {
     my ($r,$action,$formname,$dom,$confname,$subdir,$thumbwidth,$thumbheight,$savefileas) = @_;      my ($r,$action,$formname,$dom,$confname,$subdir,$thumbwidth,$thumbheight,$savefileas) = @_;
     my ($output,$fname,$logourl);      my ($output,$fname,$logourl,$madethumb);
     if ($action eq 'upload') {      if ($action eq 'upload') {
         $fname=$env{'form.'.$formname.'.filename'};          $fname=$env{'form.'.$formname.'.filename'};
         chop($env{'form.'.$formname});          chop($env{'form.'.$formname});
Line 8994  $env{'user.name'}.':'.$env{'user.domain' Line 10395  $env{'user.name'}.':'.$env{'user.domain'
                                     $r->set_handlers('PerlCleanupHandler' => [\&notifysubscribed,@{$handlers}]);                                      $r->set_handlers('PerlCleanupHandler' => [\&notifysubscribed,@{$handlers}]);
                                     $registered_cleanup=1;                                      $registered_cleanup=1;
                                 }                                  }
                                   $madethumb = 1;
                             } else {                              } else {
                                 print $logfile "\nUnable to write ".$copyfile.                                  print $logfile "\nUnable to write ".$copyfile.
                                                ':'.$!."\n";                                                 ':'.$!."\n";
Line 9006  $env{'user.name'}.':'.$env{'user.domain' Line 10408  $env{'user.name'}.':'.$env{'user.domain'
             $output = $versionresult;              $output = $versionresult;
         }          }
     }      }
     return ($output,$logourl);      return ($output,$logourl,$madethumb);
 }  }
   
 sub logo_versioning {  sub logo_versioning {
Line 9160  sub modify_quotas { Line 10562  sub modify_quotas {
         $context = $action;          $context = $action;
     }      }
     if ($context eq 'requestcourses') {      if ($context eq 'requestcourses') {
         @usertools = ('official','unofficial','community','textbook');          @usertools = ('official','unofficial','community','textbook','placement','lti');
         @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 9209  sub modify_quotas { Line 10611  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');          my @crstypes = ('official','unofficial','community','textbook','placement','lti');
         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 9331  sub modify_quotas { Line 10733  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 9883  sub process_textbook_image { Line 11285  sub process_textbook_image {
     return ($url,$error);      return ($url,$error);
 }  }
   
   sub modify_ltitools {
       my ($r,$dom,$action,$lastactref,%domconfig) = @_;
       my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
       my ($newid,@allpos,%changes,%confhash,%encconfig,$errors,$resulttext);
       my $confname = $dom.'-domainconfig';
       my $servadm = $r->dir_config('lonAdmEMail');
       my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);
       my (%posslti,%possfield);
       my @courseroles = ('cc','in','ta','ep','st');
       my @ltiroles = qw(Instructor ContentDeveloper TeachingAssistant Learner);
       map { $posslti{$_} = 1; } @ltiroles;
       my @allfields = ('fullname','firstname','lastname','email','user','roles');
       map { $possfield{$_} = 1; } @allfields;
       my %lt = &ltitools_names(); 
       if ($env{'form.ltitools_add'}) {
           my $title = $env{'form.ltitools_add_title'};
           $title =~ s/(`)/'/g;
           ($newid,my $error) = &get_ltitools_id($dom,$title);
           if ($newid) {
               my $position = $env{'form.ltitools_add_pos'};
               $position =~ s/\D+//g;
               if ($position ne '') {
                   $allpos[$position] = $newid;
               }
               $changes{$newid} = 1;
               foreach my $item ('title','url','key','secret','lifetime') {
                   $env{'form.ltitools_add_'.$item} =~ s/(`)/'/g;
                   if ($item eq 'lifetime') {
                       $env{'form.ltitools_add_'.$item} =~ s/[^\d.]//g;
                   }
                   if ($env{'form.ltitools_add_'.$item}) {
                       if (($item eq 'key') || ($item eq 'secret')) {
                           $encconfig{$newid}{$item} = $env{'form.ltitools_add_'.$item};
                       } else {
                           $confhash{$newid}{$item} = $env{'form.ltitools_add_'.$item};
                       }
                   }
               }
               if ($env{'form.ltitools_add_version'} eq 'LTI-1p0') {
                   $confhash{$newid}{'version'} = $env{'form.ltitools_add_version'};
               }
               if ($env{'form.ltitools_add_msgtype'} eq 'basic-lti-launch-request') {
                   $confhash{$newid}{'msgtype'} = $env{'form.ltitools_add_msgtype'};
               }
               if ($env{'form.ltitools_add_sigmethod'} eq 'HMAC-SHA256') {
                   $confhash{$newid}{'sigmethod'} = $env{'form.ltitools_add_sigmethod'};
               } else {
                   $confhash{$newid}{'sigmethod'} = 'HMAC-SHA1';
               }
               foreach my $item ('width','height','linktext','explanation') {
                   $env{'form.ltitools_add_'.$item} =~ s/^\s+//;
                   $env{'form.ltitools_add_'.$item} =~ s/\s+$//;
                   if (($item eq 'width') || ($item eq 'height')) {
                       if ($env{'form.ltitools_add_'.$item} =~ /^\d+$/) {
                           $confhash{$newid}{'display'}{$item} = $env{'form.ltitools_add_'.$item};
                       }
                   } else {
                       if ($env{'form.ltitools_add_'.$item} ne '') {
                           $confhash{$newid}{'display'}{$item} = $env{'form.ltitools_add_'.$item}; 
                       }
                   }
               }
               if ($env{'form.ltitools_add_target'} eq 'window') {
                   $confhash{$newid}{'display'}{'target'} = $env{'form.ltitools_add_target'};
               } elsif ($env{'form.ltitools_add_target'} eq 'tab') {
                   $confhash{$newid}{'display'}{'target'} = $env{'form.ltitools_add_target'};
               } else {
                   $confhash{$newid}{'display'}{'target'} = 'iframe';
               }
               foreach my $item ('passback','roster') {
                   if ($env{'form.ltitools_'.$item.'_add'}) {
                       $confhash{$newid}{$item} = 1;
                       if ($env{'form.ltitools_'.$item.'valid_add'} ne '') {
                           my $lifetime = $env{'form.ltitools_'.$item.'valid_add'};
                           $lifetime =~ s/^\s+|\s+$//g;
                           if ($lifetime =~ /^\d+\.?\d*$/) {
                               $confhash{$newid}{$item.'valid'} = $lifetime;
                           }
                       }
                   }
               }
               if ($env{'form.ltitools_add_image.filename'} ne '') {
                   my ($imageurl,$error) =
                       &process_ltitools_image($r,$dom,$confname,'ltitools_add_image',$newid,
                                               $configuserok,$switchserver,$author_ok);
                   if ($imageurl) {
                       $confhash{$newid}{'image'} = $imageurl;
                   }
                   if ($error) {
                       &Apache::lonnet::logthis($error);
                       $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
                   }
               }
               my @fields = &Apache::loncommon::get_env_multiple('form.ltitools_add_fields');
               foreach my $field (@fields) {
                   if ($possfield{$field}) {
                       if ($field eq 'roles') {
                           foreach my $role (@courseroles) {
                               my $choice = $env{'form.ltitools_add_roles_'.$role};
                               if (($choice ne '') && ($posslti{$choice})) {
                                   $confhash{$newid}{'roles'}{$role} = $choice;
                                   if ($role eq 'cc') {
                                       $confhash{$newid}{'roles'}{'co'} = $choice; 
                                   }
                               }
                           }
                       } else {
                           $confhash{$newid}{'fields'}{$field} = 1;
                       }
                   }
               }
               if (ref($confhash{$newid}{'fields'}) eq 'HASH') {
                   if ($confhash{$newid}{'fields'}{'user'}) {
                       if ($env{'form.ltitools_userincdom_add'}) {
                           $confhash{$newid}{'incdom'} = 1;
                       }
                   }
               }
               my @courseconfig = &Apache::loncommon::get_env_multiple('form.ltitools_courseconfig');
               foreach my $item (@courseconfig) {
                   $confhash{$newid}{'crsconf'}{$item} = 1;
               }
               if ($env{'form.ltitools_add_custom'}) {
                   my $name = $env{'form.ltitools_add_custom_name'};
                   my $value = $env{'form.ltitools_add_custom_value'};
                   $value =~ s/(`)/'/g;
                   $name =~ s/(`)/'/g;
                   $confhash{$newid}{'custom'}{$name} = $value;
               }
           } else {
               my $error = &mt('Failed to acquire unique ID for new external tool');   
               $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
           }
       }
       if (ref($domconfig{$action}) eq 'HASH') {
           my %deletions;
           my @todelete = &Apache::loncommon::get_env_multiple('form.ltitools_del');
           if (@todelete) {
               map { $deletions{$_} = 1; } @todelete;
           }
           my %customadds;
           my @newcustom = &Apache::loncommon::get_env_multiple('form.ltitools_customadd');
           if (@newcustom) {
               map { $customadds{$_} = 1; } @newcustom;
           } 
           my %imgdeletions;
           my @todeleteimages = &Apache::loncommon::get_env_multiple('form.ltitools_image_del');
           if (@todeleteimages) {
               map { $imgdeletions{$_} = 1; } @todeleteimages;
           }
           my $maxnum = $env{'form.ltitools_maxnum'};
           for (my $i=0; $i<=$maxnum; $i++) {
               my $itemid = $env{'form.ltitools_id_'.$i};
               $itemid =~ s/\D+//g;
               if (ref($domconfig{$action}{$itemid}) eq 'HASH') {
                   if ($deletions{$itemid}) {
                       if ($domconfig{$action}{$itemid}{'image'}) {
                           #FIXME need to obsolete item in RES space
                       }
                       $changes{$itemid} = $domconfig{$action}{$itemid}{'title'};
                       next;
                   } else {
                       my $newpos = $env{'form.ltitools_'.$itemid};
                       $newpos =~ s/\D+//g;
                       foreach my $item ('title','url','lifetime') {
                           $confhash{$itemid}{$item} = $env{'form.ltitools_'.$item.'_'.$i};
                           if ($domconfig{$action}{$itemid}{$item} ne $confhash{$itemid}{$item}) {
                               $changes{$itemid} = 1;
                           }
                       }
                       foreach my $item ('key','secret') {
                           $encconfig{$itemid}{$item} = $env{'form.ltitools_'.$item.'_'.$i};
                           if ($domconfig{$action}{$itemid}{$item} ne $encconfig{$itemid}{$item}) {
                               $changes{$itemid} = 1;
                           }
                       }
                       if ($env{'form.ltitools_version_'.$i} eq 'LTI-1p0') {
                           $confhash{$itemid}{'version'} = $env{'form.ltitools_version_'.$i};
                       }
                       if ($env{'form.ltitools_msgtype_'.$i} eq 'basic-lti-launch-request') {
                           $confhash{$itemid}{'msgtype'} = $env{'form.ltitools_msgtype_'.$i};
                       }
                       if ($env{'form.ltitools_sigmethod_'.$i} eq 'HMAC-SHA256') {
                           $confhash{$itemid}{'sigmethod'} = $env{'form.ltitools_sigmethod_'.$i};
                       } else {
                           $confhash{$itemid}{'sigmethod'} = 'HMAC-SHA1'; 
                       }
                       if ($domconfig{$action}{$itemid}{'sigmethod'} eq '') {
                           if ($confhash{$itemid}{'sigmethod'} ne 'HMAC-SHA1') {
                               $changes{$itemid} = 1;
                           }
                       } elsif ($domconfig{$action}{$itemid}{'sigmethod'} ne $confhash{$itemid}{'sigmethod'}) {
                           $changes{$itemid} = 1;
                       }
                       foreach my $size ('width','height') {
                           $env{'form.ltitools_'.$size.'_'.$i} =~ s/^\s+//;
                           $env{'form.ltitools_'.$size.'_'.$i} =~ s/\s+$//;
                           if ($env{'form.ltitools_'.$size.'_'.$i} =~ /^\d+$/) {
                               $confhash{$itemid}{'display'}{$size} = $env{'form.ltitools_'.$size.'_'.$i};
                               if (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') {
                                   if ($domconfig{$action}{$itemid}{'display'}{$size} ne $confhash{$itemid}{'display'}{$size}) {
                                       $changes{$itemid} = 1;
                                   }
                               } else {
                                   $changes{$itemid} = 1;
                               }
                           } elsif (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') {
                               if ($domconfig{$action}{$itemid}{'display'}{$size} ne '') {
                                   $changes{$itemid} = 1;
                               }
                           }
                       }
                       foreach my $item ('linktext','explanation') {
                           $env{'form.ltitools_'.$item.'_'.$i} =~ s/^\s+//;
                           $env{'form.ltitools_'.$item.'_'.$i} =~ s/\s+$//;
                           if ($env{'form.ltitools_'.$item.'_'.$i} ne '') {
                               $confhash{$itemid}{'display'}{$item} = $env{'form.ltitools_'.$item.'_'.$i};
                               if (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') {
                                   if ($domconfig{$action}{$itemid}{'display'}{$item} ne $confhash{$itemid}{'display'}{$item}) {
                                       $changes{$itemid} = 1;
                                   }
                               } else {
                                   $changes{$itemid} = 1;
                               }
                           } elsif (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') {
                               if ($domconfig{$action}{$itemid}{'display'}{$item} ne '') {
                                   $changes{$itemid} = 1;
                               }
                           }
                       }
                       if ($env{'form.ltitools_target_'.$i} eq 'window') {
                           $confhash{$itemid}{'display'}{'target'} = $env{'form.ltitools_target_'.$i};
                       } elsif ($env{'form.ltitools_target_'.$i} eq 'tab') {
                           $confhash{$itemid}{'display'}{'target'} = $env{'form.ltitools_target_'.$i};
                       } else {
                           $confhash{$itemid}{'display'}{'target'} = 'iframe';
                       }
                       if (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') {
                           if ($domconfig{$action}{$itemid}{'display'}{'target'} ne $confhash{$itemid}{'display'}{'target'}) {
                               $changes{$itemid} = 1;
                           }
                       } else {
                           $changes{$itemid} = 1;
                       }
                       foreach my $extra ('passback','roster') {
                           if ($env{'form.ltitools_'.$extra.'_'.$i}) {
                               $confhash{$itemid}{$extra} = 1;
                               if ($env{'form.ltitools_'.$extra.'valid_'.$i} ne '') {
                                   my $lifetime = $env{'form.ltitools_'.$extra.'valid_'.$i};
                                   $lifetime =~ s/^\s+|\s+$//g;
                                   if ($lifetime =~ /^\d+\.?\d*$/) {
                                       $confhash{$itemid}{$extra.'valid'} = $lifetime;
                                   }
                               }
                           }
                           if ($domconfig{$action}{$itemid}{$extra} ne $confhash{$itemid}{$extra}) {
                               $changes{$itemid} = 1;
                           }
                           if ($domconfig{$action}{$itemid}{$extra.'valid'} ne $confhash{$itemid}{$extra.'valid'}) {
                               $changes{$itemid} = 1;
                           }
                       }
                       my @courseconfig = &Apache::loncommon::get_env_multiple('form.ltitools_courseconfig_'.$i);
                       foreach my $item ('label','title','target','linktext','explanation','append') {
                           if (grep(/^\Q$item\E$/,@courseconfig)) {
                               $confhash{$itemid}{'crsconf'}{$item} = 1;
                               if (ref($domconfig{$action}{$itemid}{'crsconf'}) eq 'HASH') {
                                   if ($domconfig{$action}{$itemid}{'crsconf'}{$item} ne $confhash{$itemid}{'crsconf'}{$item}) {
                                       $changes{$itemid} = 1;
                                   }
                               } else {
                                   $changes{$itemid} = 1;
                               }
                           }
                       }
                       my @fields = &Apache::loncommon::get_env_multiple('form.ltitools_fields_'.$i);
                       foreach my $field (@fields) {
                           if ($possfield{$field}) {
                               if ($field eq 'roles') {
                                   foreach my $role (@courseroles) {
                                       my $choice = $env{'form.ltitools_roles_'.$role.'_'.$i};
                                       if (($choice ne '') && ($posslti{$choice})) {
                                           $confhash{$itemid}{'roles'}{$role} = $choice;
                                           if ($role eq 'cc') {
                                               $confhash{$itemid}{'roles'}{'co'} = $choice;
                                           }
                                       }
                                       if (ref($domconfig{$action}{$itemid}{'roles'}) eq 'HASH') {
                                           if ($domconfig{$action}{$itemid}{'roles'}{$role} ne $confhash{$itemid}{'roles'}{$role}) {
                                               $changes{$itemid} = 1;
                                           }
                                       } elsif ($confhash{$itemid}{'roles'}{$role}) {
                                           $changes{$itemid} = 1;
                                       }
                                   }
                               } else {
                                   $confhash{$itemid}{'fields'}{$field} = 1;
                                   if (ref($domconfig{$action}{$itemid}{'fields'}) eq 'HASH') {
                                       if ($domconfig{$action}{$itemid}{'fields'}{$field} ne $confhash{$itemid}{'fields'}{$field}) {
                                           $changes{$itemid} = 1;
                                       }
                                   } else {
                                       $changes{$itemid} = 1;
                                   }
                               }
                           }
                       }
                       if (ref($confhash{$itemid}{'fields'}) eq 'HASH') {
                           if ($confhash{$itemid}{'fields'}{'user'}) {
                               if ($env{'form.ltitools_userincdom_'.$i}) {
                                   $confhash{$itemid}{'incdom'} = 1;
                               }
                               if ($domconfig{$action}{$itemid}{'incdom'} ne $confhash{$itemid}{'incdom'}) {
                                   $changes{$itemid} = 1;
                               }
                           }
                       }
                       $allpos[$newpos] = $itemid;
                   }
                   if ($imgdeletions{$itemid}) {
                       $changes{$itemid} = 1;
                       #FIXME need to obsolete item in RES space
                   } elsif ($env{'form.ltitools_image_'.$i.'.filename'}) {
                       my ($imgurl,$error) = &process_ltitools_image($r,$dom,$confname,'ltitools_image_'.$i,
                                                                    $itemid,$configuserok,$switchserver,
                                                                    $author_ok);
                       if ($imgurl) {
                           $confhash{$itemid}{'image'} = $imgurl;
                           $changes{$itemid} = 1;
                       }
                       if ($error) {
                           &Apache::lonnet::logthis($error);
                           $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
                       }
                   } elsif ($domconfig{$action}{$itemid}{'image'}) {
                       $confhash{$itemid}{'image'} =
                          $domconfig{$action}{$itemid}{'image'};
                   }
                   if ($customadds{$i}) {
                       my $name = $env{'form.ltitools_custom_name_'.$i};
                       $name =~ s/(`)/'/g;
                       $name =~ s/^\s+//;
                       $name =~ s/\s+$//;
                       my $value = $env{'form.ltitools_custom_value_'.$i};
                       $value =~ s/(`)/'/g;
                       $value =~ s/^\s+//;
                       $value =~ s/\s+$//;
                       if ($name ne '') {
                           $confhash{$itemid}{'custom'}{$name} = $value;
                           $changes{$itemid} = 1;
                       }
                   }
                   my %customdels;
                   my @customdeletions = &Apache::loncommon::get_env_multiple('form.ltitools_customdel_'.$i); 
                   if (@customdeletions) {
                       $changes{$itemid} = 1;
                   }
                   map { $customdels{$_} = 1; } @customdeletions;
                   if (ref($domconfig{$action}{$itemid}{'custom'}) eq 'HASH') {
                       foreach my $key (keys(%{$domconfig{$action}{$itemid}{'custom'}})) {
                           unless ($customdels{$key}) {
                               if ($env{'form.ltitools_customval_'.$key.'_'.$i} ne '') {
                                   $confhash{$itemid}{'custom'}{$key} = $env{'form.ltitools_customval_'.$key.'_'.$i}; 
                               }
                               if ($domconfig{$action}{$itemid}{'custom'}{$key} ne $env{'form.ltitools_customval_'.$key.'_'.$i}) {
                                   $changes{$itemid} = 1;
                               }
                           }
                       }
                   }
                   unless ($changes{$itemid}) {
                       foreach my $key (keys(%{$domconfig{$action}{$itemid}})) {
                           if (ref($domconfig{$action}{$itemid}{$key}) eq 'HASH') {
                               if (ref($confhash{$itemid}{$key}) eq 'HASH') {
                                   foreach my $innerkey (keys(%{$domconfig{$action}{$itemid}{$key}})) {
                                       unless (exists($confhash{$itemid}{$key}{$innerkey})) {
                                           $changes{$itemid} = 1;
                                           last;
                                       }
                                   }
                               } elsif (keys(%{$domconfig{$action}{$itemid}{$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 ++;
               }
           }
       }
       my %ltitoolshash = (
                             $action => { %confhash }
                          );
       my $putresult = &Apache::lonnet::put_dom('configuration',\%ltitoolshash,
                                                $dom);
       if ($putresult eq 'ok') {
           my %ltienchash = (
                                $action => { %encconfig }
                            );
           &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom);
           if (keys(%changes) > 0) {
               my $cachetime = 24*60*60;
               my %ltiall = %confhash;
               foreach my $id (keys(%ltiall)) {
                   if (ref($encconfig{$id}) eq 'HASH') {
                       foreach my $item ('key','secret') {
                           $ltiall{$id}{$item} = $encconfig{$id}{$item};
                       }
                   }
               }
               &Apache::lonnet::do_cache_new('ltitools',$dom,\%ltiall,$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'ltitools'} = 1;
               }
               $resulttext = &mt('Changes made:').'<ul>';
               my %bynum;
               foreach my $itemid (sort(keys(%changes))) {
                   my $position = $confhash{$itemid}{'order'};
                   $bynum{$position} = $itemid;
               }
               foreach my $pos (sort { $a <=> $b } keys(%bynum)) {
                   my $itemid = $bynum{$pos}; 
                   if (ref($confhash{$itemid}) ne 'HASH') {
                       $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';
                   } else {
                       $resulttext .= '<li><b>'.$confhash{$itemid}{'title'}.'</b>';
                       if ($confhash{$itemid}{'image'}) {
                           $resulttext .= '&nbsp;'.
                                          '<img src="'.$confhash{$itemid}{'image'}.'"'.
                                          ' alt="'.&mt('Tool Provider icon').'" />';
                       }
                       $resulttext .= '</li><ul>';
                       my $position = $pos + 1;
                       $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';
                       foreach my $item ('version','msgtype','sigmethod','url','lifetime') {
                           if ($confhash{$itemid}{$item} ne '') {
                               $resulttext .= '<li>'.$lt{$item}.':&nbsp;'.$confhash{$itemid}{$item}.'</li>';
                           }
                       }
                       if ($encconfig{$itemid}{'key'} ne '') {
                           $resulttext .= '<li>'.$lt{'key'}.':&nbsp;'.$encconfig{$itemid}{'key'}.'</li>';
                       }
                       if ($encconfig{$itemid}{'secret'} ne '') {
                           $resulttext .= '<li>'.$lt{'secret'}.':&nbsp;';
                           my $num = length($encconfig{$itemid}{'secret'});
                           $resulttext .= ('*'x$num).'</li>';
                       }
                       $resulttext .= '<li>'.&mt('Configurable in course:');
                       my @possconfig = ('label','title','target','linktext','explanation','append');
                       my $numconfig = 0; 
                       if (ref($confhash{$itemid}{'crsconf'}) eq 'HASH') { 
                           foreach my $item (@possconfig) {
                               if ($confhash{$itemid}{'crsconf'}{$item}) {
                                   $numconfig ++;
                                   $resulttext .= ' "'.$lt{'crs'.$item}.'"';
                               }
                           }
                       }
                       if (!$numconfig) {
                           $resulttext .= &mt('None');
                       }
                       $resulttext .= '</li>';
                       foreach my $item ('passback','roster') {
                           $resulttext .= '<li>'.$lt{$item}.'&nbsp;';
                           if ($confhash{$itemid}{$item}) {
                               $resulttext .= &mt('Yes');
                               if ($confhash{$itemid}{$item.'valid'}) {
                                   if ($item eq 'passback') {
                                       $resulttext .= ' '.&mt('valid for at least [quant,_1,day] after launch',
                                                              $confhash{$itemid}{$item.'valid'});
                                   } else {
                                       $resulttext .= ' '.&mt('valid for at least [quant,_1,second] after launch',
                                                              $confhash{$itemid}{$item.'valid'});
                                   }
                               }
                           } else {
                               $resulttext .= &mt('No');
                           }
                           $resulttext .= '</li>';
                       }
                       if (ref($confhash{$itemid}{'display'}) eq 'HASH') {
                           my $displaylist;
                           if ($confhash{$itemid}{'display'}{'target'}) {
                               $displaylist = &mt('Display target').':&nbsp;'.
                                              $confhash{$itemid}{'display'}{'target'}.',';
                           }
                           foreach my $size ('width','height') { 
                               if ($confhash{$itemid}{'display'}{$size}) {
                                   $displaylist .= ('&nbsp;'x2).$lt{$size}.':&nbsp;'.
                                                   $confhash{$itemid}{'display'}{$size}.',';
                               }
                           }
                           if ($displaylist) {
                               $displaylist =~ s/,$//;
                               $resulttext .= '<li>'.$displaylist.'</li>';
                           }
                           foreach my $item ('linktext','explanation') {
                               if ($confhash{$itemid}{'display'}{$item}) {
                                   $resulttext .= '<li>'.$lt{$item}.':&nbsp;'.$confhash{$itemid}{'display'}{$item}.'</li>';
                               }
                           }
                       }
                       if (ref($confhash{$itemid}{'fields'}) eq 'HASH') {
                           my $fieldlist;
                           foreach my $field (@allfields) {
                               if ($confhash{$itemid}{'fields'}{$field}) {
                                   $fieldlist .= ('&nbsp;'x2).$lt{$field}.',';
                               }
                           }
                           if ($fieldlist) {
                               $fieldlist =~ s/,$//;
                               if ($confhash{$itemid}{'fields'}{'user'}) {
                                   if ($confhash{$itemid}{'incdom'}) {
                                       $fieldlist .= ' ('.&mt('username:domain').')';
                                   } else {
                                       $fieldlist .= ' ('.&mt('username').')';
                                   }
                               }
                               $resulttext .= '<li>'.&mt('Data sent').':'.$fieldlist.'</li>';
                           }
                       }
                       if (ref($confhash{$itemid}{'roles'}) eq 'HASH') {
                           my $rolemaps;
                           foreach my $role (@courseroles) {
                               if ($confhash{$itemid}{'roles'}{$role}) {
                                   $rolemaps .= ('&nbsp;'x2).&Apache::lonnet::plaintext($role,'Course').'='.
                                                $confhash{$itemid}{'roles'}{$role}.',';
                               }
                           }
                           if ($rolemaps) {
                               $rolemaps =~ s/,$//; 
                               $resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>';
                           }
                       }
                       if (ref($confhash{$itemid}{'custom'}) eq 'HASH') {
                           my $customlist;
                           if (keys(%{$confhash{$itemid}{'custom'}})) {
                               foreach my $key (sort(keys(%{$confhash{$itemid}{'custom'}}))) {
                                   $customlist .= $key.':'.$confhash{$itemid}{'custom'}{$key}.('&nbsp;'x2);
                               } 
                           }
                           if ($customlist) {
                               $resulttext .= '<li>'.&mt('Custom items').': '.$customlist.'</li>';
                           }
                       } 
                       $resulttext .= '</ul></li>';
                   }
               }
               $resulttext .= '</ul>';
           } else {
               $resulttext = &mt('No changes made.');
           }
       } 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 process_ltitools_image {
       my ($r,$dom,$confname,$caller,$itemid,$configuserok,$switchserver,$author_ok) = @_;
       my $filename = $env{'form.'.$caller.'.filename'};
       my ($error,$url);
       my ($width,$height) = (21,21);
       if ($configuserok eq 'ok') {
           if ($switchserver) {
               $error = &mt('Upload of Tool Provider (LTI) icon is not permitted to this server: [_1]',
                            $switchserver);
           } elsif ($author_ok eq 'ok') {
               my ($result,$imageurl,$madethumb) =
                   &publishlogo($r,'upload',$caller,$dom,$confname,
                                "ltitools/$itemid/icon",$width,$height);
               if ($result eq 'ok') {
                   if ($madethumb) {
                       my ($path,$imagefile) = ($imageurl =~ m{^(.+)/([^/]+)$});
                       my $imagethumb = "$path/tn-".$imagefile;
                       $url = $imagethumb;
                   } else {
                       $url = $imageurl;
                   }
               } else {
                   $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result);
               }
           } else {
               $error = &mt("Upload of [_1] failed because an author role could not be assigned to a Domain Configuration user ([_2]) in domain: [_3].  Error was: [_4].",$filename,$confname,$dom,$author_ok);
           }
       } else {
           $error = &mt("Upload of [_1] failed because a Domain Configuration user ([_2]) could not be created in domain: [_3].  Error was: [_4].",$filename,$confname,$dom,$configuserok);
       }
       return ($url,$error);
   }
   
   sub get_ltitools_id {
       my ($cdom,$title) = @_;
       # get lock on ltitools db
       my $lockhash = {
                         lock => $env{'user.name'}.
                                 ':'.$env{'user.domain'},
                      };
       my $tries = 0;
       my $gotlock = &Apache::lonnet::newput_dom('ltitools',$lockhash,$cdom);
       my ($id,$error);
    
       while (($gotlock ne 'ok') && ($tries<10)) {
           $tries ++;
           sleep (0.1);
           $gotlock = &Apache::lonnet::newput_dom('ltitools',$lockhash,$cdom);
       }
       if ($gotlock eq 'ok') {
           my %currids = &Apache::lonnet::dump_dom('ltitools',$cdom);
           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('ltitools',{ $id => $title },$cdom) eq 'ok') {
                       $error = 'nostore';
                   }
               } else {
                   $error = 'nonumber';
               }
           }
           my $dellockoutcome = &Apache::lonnet::del_dom('ltitools',['lock'],$cdom);
       } else {
           $error = 'nolock';
       }
       return ($id,$error);
   }
   
   sub modify_lti {
       my ($r,$dom,$action,$lastactref,%domconfig) = @_;
       my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
       my ($newid,@allpos,%changes,%confhash,%encconfig,$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');
       my %coursetypetitles = &Apache::lonlocal::texthash (
                                  official   => 'Official',
                                  unofficial => 'Unofficial',
                                  community  => 'Community',
                                  textbook   => 'Textbook',
                                  placement  => 'Placement Test',
       );
       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 (@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;
                   }
               }
           }
       }
       foreach my $idx (@items) {
           my $itemid = $itemids{$idx};
           next unless ($itemid);
           my $position = $env{'form.lti_pos_'.$idx};
           $position =~ s/\D+//g;
           if ($position ne '') {
               $allpos[$position] = $itemid;
           }
           foreach my $item ('consumer','key','secret','lifetime','requser') {
               my $formitem = 'form.lti_'.$item.'_'.$idx;
               $env{$formitem} =~ s/(`)/'/g;
               if ($item eq 'lifetime') {
                   $env{$formitem} =~ s/[^\d.]//g;
               }
               if ($env{$formitem} ne '') {
                   if (($item eq 'key') || ($item eq 'secret')) {
                       $encconfig{$itemid}{$item} = $env{$formitem};
                   } else {
                       $confhash{$itemid}{$item} = $env{$formitem};
                       unless (($idx eq 'add') || ($changes{$itemid})) {
                           if ($domconfig{$action}{$itemid}{$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; 
               }
               foreach my $ltirole (@lticourseroles) {
                   my $possrole = $env{'form.lti_maprole_'.$ltirole.'_'.$idx};
                   if (grep(/^\Q$possrole\E$/,@courseroles)) {
                       $confhash{$itemid}{'maproles'}{$ltirole} = $possrole;
                   }
               }
               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_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_makecrs_'.$idx}) {
                   $confhash{$itemid}{'makecrs'} = 1;
               }
               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','topmenu','inlinemenu') {
                   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';
                   }
               }
               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);
                       }
                   }
               }
               unless (($idx eq 'add') || ($changes{$itemid})) {
                   foreach my $field ('mapuser','mapcrs','makecrs','section','passback','roster','lcauth','lcauthparm','topmenu','inlinemenu') {
                       if ($domconfig{$action}{$itemid}{$field} ne $confhash{$itemid}{$field}) {
                           $changes{$itemid} = 1;
                       }
                   }
                   unless ($changes{$itemid}) {
                       if ($domconfig{$action}{$itemid}{'passback'} eq $confhash{$itemid}{'passback'}) {
                           if ($domconfig{$action}{$itemid}{'passbackformat'} ne $confhash{$itemid}{'passbackformat'}) {
                               $changes{$itemid} = 1;
                           }
                       }
                   }
                   foreach my $field ('makeuser','mapcrstype','selfenroll','instdata','lcmenu') {
                       unless ($changes{$itemid}) {
                           if (ref($domconfig{$action}{$itemid}{$field}) eq 'ARRAY') {
                               if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
                                   my @diffs = &Apache::loncommon::compare_arrays($domconfig{$action}{$itemid}{$field},
                                                                                  $confhash{$itemid}{$field});
                                   if (@diffs) {
                                       $changes{$itemid} = 1;
                                   }
                               } elsif (@{$domconfig{$action}{$itemid}{$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($domconfig{$action}{$itemid}{'maproles'}) eq 'HASH') {
                           if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
                               foreach my $ltirole (keys(%{$domconfig{$action}{$itemid}{'maproles'}})) {
                                   if ($domconfig{$action}{$itemid}{'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 
                                           $domconfig{$action}{$itemid}{'maproles'}{$ltirole}) {
                                           $changes{$itemid} = 1;
                                           last;
                                       }
                                   }
                               }
                           } elsif (keys(%{$domconfig{$action}{$itemid}{'maproles'}}) > 0) {
                               $changes{$itemid} = 1;
                           }
                       } elsif (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
                           unless ($changes{$itemid}) {
                               if (keys(%{$confhash{$itemid}{'maproles'}}) > 0) {
                                   $changes{$itemid} = 1;
                               }
                           }
                       }
                   }
               }
           }
       }
       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 ++;
               }
           }
       }
       my %ltihash = (
                             $action => { %confhash }
                          );
       my $putresult = &Apache::lonnet::put_dom('configuration',\%ltihash,
                                                $dom);
       if ($putresult eq 'ok') {
           my %ltienchash = (
                                $action => { %encconfig }
                            );
           &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom);
           if (keys(%changes) > 0) {
               my $cachetime = 24*60*60;
               my %ltiall = %confhash;
               foreach my $id (keys(%ltiall)) {
                   if (ref($encconfig{$id}) eq 'HASH') {
                       foreach my $item ('key','secret') {
                           $ltiall{$id}{$item} = $encconfig{$id}{$item};
                       }
                   }
               }
               &Apache::lonnet::do_cache_new('lti',$dom,\%ltiall,$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'lti'} = 1;
               }
               $resulttext = &mt('Changes made:').'<ul>';
               my %bynum;
               foreach my $itemid (sort(keys(%changes))) {
                   my $position = $confhash{$itemid}{'order'};
                   $bynum{$position} = $itemid;
               }
               foreach my $pos (sort { $a <=> $b } keys(%bynum)) {
                   my $itemid = $bynum{$pos};
                   if (ref($confhash{$itemid}) ne 'HASH') {
                       $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';
                   } else {
                       $resulttext .= '<li><b>'.$confhash{$itemid}{'consumer'}.'</b></li><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 ($encconfig{$itemid}{'key'} ne '') {
                           $resulttext .= '<li>'.$lt{'key'}.':&nbsp;'.$encconfig{$itemid}{'key'}.'</li>';
                       }
                       if ($encconfig{$itemid}{'secret'} ne '') {
                           $resulttext .= '<li>'.$lt{'secret'}.':&nbsp;';
                           my $num = length($encconfig{$itemid}{'secret'});
                           $resulttext .= ('*'x$num).'</li>';
                       }
                       if ($confhash{$itemid}{'requser'}) {
                           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}{'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 (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>';
                               }
                           }
                           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}{'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>';
                   }
               }
               $resulttext .= '</ul>';
           } else {
               $resulttext = &mt('No changes made.');
           }
       } 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_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 10468  sub modify_contacts { Line 13036  sub modify_contacts {
     my (%others,%to,%bcc,%includestr,%includeloc);      my (%others,%to,%bcc,%includestr,%includeloc);
     my @contacts = ('supportemail','adminemail');      my @contacts = ('supportemail','adminemail');
     my @mailings = ('errormail','packagesmail','helpdeskmail','otherdomsmail',      my @mailings = ('errormail','packagesmail','helpdeskmail','otherdomsmail',
                     'lonstatusmail','requestsmail','updatesmail','idconflictsmail','hostipmail');                      'lonstatusmail','requestsmail','updatesmail','idconflictsmail');
     my @toggles = ('reporterrors','reportupdates');      my @toggles = ('reporterrors','reportupdates','reportstatus');
       my @lonstatus = ('threshold','sysmail','weights','excluded');
     my ($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields();      my ($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields();
     foreach my $type (@mailings) {      foreach my $type (@mailings) {
         @{$newsetting{$type}} =           @{$newsetting{$type}} = 
Line 10502  sub modify_contacts { Line 13071  sub modify_contacts {
             $contacts_hash{'contacts'}{$item} = $env{'form.'.$item};              $contacts_hash{'contacts'}{$item} = $env{'form.'.$item};
         }          }
     }      }
       my ($lonstatus_defs,$lonstatus_names) = &Apache::loncommon::lon_status_items();
       foreach my $item (@lonstatus) {
           if ($item eq 'excluded') {
               my (%serverhomes,@excluded);
               map { $serverhomes{$_} = 1; } values(%Apache::lonnet::serverhomeIDs);
               my @possexcluded = &Apache::loncommon::get_env_multiple('form.errorexcluded');
               if (@possexcluded) {
                   foreach my $id (sort(@possexcluded)) {
                       if ($serverhomes{$id}) {
                           push(@excluded,$id);
                       }
                   }
               }
               if (@excluded) {
                   $contacts_hash{'contacts'}{'lonstatus'}{$item} = \@excluded;
               }
           } elsif ($item eq 'weights') {
               foreach my $type ('E','W','N') {
                   $env{'form.error'.$item.'_'.$type} =~ s/^\s+|\s+$//g;
                   if ($env{'form.error'.$item.'_'.$type} =~ /^\d+$/) {
                       unless ($env{'form.error'.$item.'_'.$type} == $lonstatus_defs->{$type}) {
                           $contacts_hash{'contacts'}{'lonstatus'}{$item}{$type} =
                               $env{'form.error'.$item.'_'.$type};
                       }
                   }
               }
           } elsif (($item eq 'threshold') || ($item eq 'sysmail')) {
               $env{'form.error'.$item} =~ s/^\s+|\s+$//g;
               if ($env{'form.error'.$item} =~ /^\d+$/) {
                   unless ($env{'form.error'.$item} == $lonstatus_defs->{$item}) {
                       $contacts_hash{'contacts'}{'lonstatus'}{$item} = $env{'form.error'.$item};
                   }
               }
           }
       }
     if ((ref($fields) eq 'ARRAY') && (ref($possoptions) eq 'HASH')) {      if ((ref($fields) eq 'ARRAY') && (ref($possoptions) eq 'HASH')) {
         foreach my $field (@{$fields}) {          foreach my $field (@{$fields}) {
             if (ref($possoptions->{$field}) eq 'ARRAY') {              if (ref($possoptions->{$field}) eq 'ARRAY') {
Line 10556  sub modify_contacts { Line 13160  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 10614  sub modify_contacts { Line 13218  sub modify_contacts {
             }              }
         }          }
         if (@statuses) {          if (@statuses) {
             if (ref($currsetting{'overrides'}) eq 'HASH') {              if (ref($currsetting{'overrides'}) eq 'HASH') { 
                 foreach my $key (keys(%{$currsetting{'overrides'}})) {                  foreach my $key (keys(%{$currsetting{'overrides'}})) {
                     if (ref($currsetting{'overrides'}{$key}) eq 'HASH') {                      if (ref($currsetting{'overrides'}{$key}) eq 'HASH') {
                         if (ref($newsetting{'override_'.$key}) eq 'HASH') {                          if (ref($newsetting{'override_'.$key}) eq 'HASH') {
                             foreach my $item (@contacts,'bcc','others','include') {                              foreach my $item (@contacts,'bcc','others','include') {
                                 if ($currsetting{'overrides'}{$key}{$item} ne $newsetting{'override_'.$key}{$item}) {                                  if ($currsetting{'overrides'}{$key}{$item} ne $newsetting{'override_'.$key}{$item}) { 
                                     push(@{$changes{'overrides'}},$key);                                      push(@{$changes{'overrides'}},$key);
                                     last;                                      last;
                                 }                                  }
Line 10636  sub modify_contacts { Line 13240  sub modify_contacts {
                 }                  }
             } else {              } else {
                 foreach my $key (@overrides) {                  foreach my $key (@overrides) {
                     push(@{$changes{'overrides'}},$key);                      push(@{$changes{'overrides'}},$key); 
                   }
               }
           }
           if (ref($currsetting{'lonstatus'}) eq 'HASH') {
               foreach my $key ('excluded','weights','threshold','sysmail') {
                   if ($key eq 'excluded') {
                       if ((ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') &&
                           (ref($contacts_hash{contacts}{lonstatus}{excluded}) eq 'ARRAY')) {
                           if ((ref($currsetting{'lonstatus'}{$key}) eq 'ARRAY') &&
                               (@{$currsetting{'lonstatus'}{$key}})) {
                               my @diffs =
                                   &Apache::loncommon::compare_arrays($contacts_hash{contacts}{lonstatus}{excluded},
                                                                      $currsetting{'lonstatus'}{$key});
                               if (@diffs) {
                                   push(@{$changes{'lonstatus'}},$key);
                               }
                           } elsif (@{$contacts_hash{contacts}{lonstatus}{excluded}}) {
                               push(@{$changes{'lonstatus'}},$key);
                           }
                       } elsif ((ref($currsetting{'lonstatus'}{$key}) eq 'ARRAY') &&
                                (@{$currsetting{'lonstatus'}{$key}})) {
                           push(@{$changes{'lonstatus'}},$key);
                       }
                   } elsif ($key eq 'weights') {
                       if ((ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') &&
                           (ref($contacts_hash{contacts}{lonstatus}{$key}) eq 'HASH')) {
                           if (ref($currsetting{'lonstatus'}{$key}) eq 'HASH') {
                               foreach my $type ('E','W','N','U') {
                                   unless ($contacts_hash{contacts}{lonstatus}{$key}{$type} eq
                                           $currsetting{'lonstatus'}{$key}{$type}) {
                                       push(@{$changes{'lonstatus'}},$key);
                                       last;
                                   }
                               }
                           } else {
                               foreach my $type ('E','W','N','U') {
                                   if ($contacts_hash{contacts}{lonstatus}{$key}{$type} ne '') {
                                       push(@{$changes{'lonstatus'}},$key);
                                       last;
                                   }
                               }
                           }
                       } elsif (ref($currsetting{'lonstatus'}{$key}) eq 'HASH') {
                           foreach my $type ('E','W','N','U') {
                               if ($currsetting{'lonstatus'}{$key}{$type} ne '') {
                                   push(@{$changes{'lonstatus'}},$key);
                                   last;
                               }
                           }
                       }
                   } elsif (($key eq 'threshold') || ($key eq 'sysmail')) {
                       if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') {
                           if ($currsetting{'lonstatus'}{$key} =~ /^\d+$/) {
                               if ($currsetting{'lonstatus'}{$key} != $contacts_hash{contacts}{lonstatus}{$key}) {
                                   push(@{$changes{'lonstatus'}},$key);
                               }
                           } elsif ($contacts_hash{contacts}{lonstatus}{$key} =~ /^\d+$/) {
                               push(@{$changes{'lonstatus'}},$key);
                           }
                       } elsif ($currsetting{'lonstatus'}{$key} =~ /^\d+$/) {
                           push(@{$changes{'lonstatus'}},$key);
                       }
                   }
               }
           } else {
               if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') {
                   foreach my $key ('excluded','weights','threshold','sysmail') {
                       if (exists($contacts_hash{contacts}{lonstatus}{$key})) {
                           push(@{$changes{'lonstatus'}},$key);
                       }
                 }                  }
             }              }
         }          }
Line 10651  sub modify_contacts { Line 13325  sub modify_contacts {
         $default{'lonstatusmail'} = 'adminemail';          $default{'lonstatusmail'} = 'adminemail';
         $default{'requestsmail'} = 'adminemail';          $default{'requestsmail'} = 'adminemail';
         $default{'updatesmail'} = 'adminemail';          $default{'updatesmail'} = 'adminemail';
         $default{'hostipmail'} = 'adminemail';  
         foreach my $item (@contacts) {          foreach my $item (@contacts) {
            if ($to{$item} ne $default{$item}) {             if ($to{$item} ne $default{$item}) {
                $changes{$item} = 1;                 $changes{$item} = 1;
Line 10685  sub modify_contacts { Line 13358  sub modify_contacts {
                 }                  }
             }              }
         }          }
           if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') {
               foreach my $key ('excluded','weights','threshold','sysmail') {
                   if (exists($contacts_hash{contacts}{lonstatus}{$key})) {
                       push(@{$changes{'lonstatus'}},$key);
                   }
               }
           }
     }      }
     foreach my $item (@toggles) {      foreach my $item (@toggles) {
         if (($env{'form.'.$item} == 1) && ($currsetting{$item} == 0)) {          if (($env{'form.'.$item} == 1) && ($currsetting{$item} == 0)) {
Line 10741  sub modify_contacts { Line 13421  sub modify_contacts {
                             $resulttext .= $bcctext.': <span class="LC_cusr_emph">'.$bcc{$type}.'</span>';                              $resulttext .= $bcctext.': <span class="LC_cusr_emph">'.$bcc{$type}.'</span>';
                         } elsif (!@text) {                          } elsif (!@text) {
                             $resulttext .= &mt('No one');                              $resulttext .= &mt('No one');
                         }                          }   
                         if ($includestr{$type} ne '') {                          if ($includestr{$type} ne '') {
                             if ($includeloc{$type} eq 'b') {                              if ($includeloc{$type} eq 'b') {
                                 $resulttext .= '<br />'.&mt('Text automatically added to e-mail body:').' '.$includestr{$type};                                  $resulttext .= '<br />'.&mt('Text automatically added to e-mail body:').' '.$includestr{$type};
Line 10765  sub modify_contacts { Line 13445  sub modify_contacts {
                             if (ref($newsetting{'override_'.$type}) eq 'HASH') {                              if (ref($newsetting{'override_'.$type}) eq 'HASH') {
                                 my @text;                                  my @text;
                                 foreach my $item (@contacts) {                                  foreach my $item (@contacts) {
                                     if ($newsetting{'override_'.$type}{$item}) {                                      if ($newsetting{'override_'.$type}{$item}) { 
                                         push(@text,$short_titles->{$item});                                          push(@text,$short_titles->{$item});
                                     }                                      }
                                 }                                  }
                                 if ($newsetting{'override_'.$type}{'others'} ne '') {                                  if ($newsetting{'override_'.$type}{'others'} ne '') {
                                     push(@text,$newsetting{'override_'.$type}{'others'});                                      push(@text,$newsetting{'override_'.$type}{'others'});
                                 }                                  }
     
                                 if (@text) {                                  if (@text) {
                                     $resulttext .= &mt('Helpdesk e-mail sent to: [_1]',                                      $resulttext .= &mt('Helpdesk e-mail sent to: [_1]',
                                                        '<span class="LC_cusr_emph">'.join(', ',@text).'</span>');                                                         '<span class="LC_cusr_emph">'.join(', ',@text).'</span>');
Line 10810  sub modify_contacts { Line 13490  sub modify_contacts {
                 }                  }
             }              }
             my @offon = ('off','on');              my @offon = ('off','on');
               my $corelink = &core_link_msu();
             if ($changes{'reporterrors'}) {              if ($changes{'reporterrors'}) {
                 $resulttext .= '<li>'.                  $resulttext .= '<li>'.
                                &mt('E-mail error reports to [_1] set to "'.                                 &mt('E-mail error reports to [_1] set to "'.
                                    $offon[$env{'form.reporterrors'}].'".',                                     $offon[$env{'form.reporterrors'}].'".',
                                    &Apache::loncommon::modal_link('http://loncapa.org/core.html',                                     $corelink).
                                        &mt('LON-CAPA core group - MSU'),600,500)).  
                                '</li>';                                 '</li>';
             }              }
             if ($changes{'reportupdates'}) {              if ($changes{'reportupdates'}) {
                 $resulttext .= '<li>'.                  $resulttext .= '<li>'.
                                 &mt('E-mail record of completed LON-CAPA updates to [_1] set to "'.                                  &mt('E-mail record of completed LON-CAPA updates to [_1] set to "'.
                                     $offon[$env{'form.reportupdates'}].'".',                                      $offon[$env{'form.reportupdates'}].'".',
                                     &Apache::loncommon::modal_link('http://loncapa.org/core.html',                                      $corelink).
                                         &mt('LON-CAPA core group - MSU'),600,500)).  
                                 '</li>';                                  '</li>';
             }              }
               if ($changes{'reportstatus'}) {
                   $resulttext .= '<li>'.
                                   &mt('E-mail status if errors above threshold to [_1] set to "'.
                                       $offon[$env{'form.reportstatus'}].'".',
                                       $corelink).
                                   '</li>';
               }
               if (ref($changes{'lonstatus'}) eq 'ARRAY') {
                   $resulttext .= '<li>'.
                                  &mt('Nightly status check e-mail settings').':<ul>';
                   my (%defval,%use_def,%shown);
                   $defval{'threshold'} = $lonstatus_defs->{'threshold'};
                   $defval{'sysmail'} = $lonstatus_defs->{'sysmail'};
                   $defval{'weights'} =
                       join(', ',map { $lonstatus_names->{$_}.'='.$lonstatus_defs->{$_}; } ('E','W','N','U'));
                   $defval{'excluded'} = &mt('None');
                   if (ref($contacts_hash{'contacts'}{'lonstatus'}) eq 'HASH') {
                       foreach my $item ('threshold','sysmail','weights','excluded') {
                           if (exists($contacts_hash{'contacts'}{'lonstatus'}{$item})) {
                               if (($item eq 'threshold') || ($item eq 'sysmail')) {
                                   $shown{$item} = $contacts_hash{'contacts'}{'lonstatus'}{$item};
                               } elsif ($item eq 'weights') {
                                   if (ref($contacts_hash{'contacts'}{'lonstatus'}{$item}) eq 'HASH') {
                                       foreach my $type ('E','W','N','U') {
                                           $shown{$item} .= $lonstatus_names->{$type}.'=';
                                           if (exists($contacts_hash{'contacts'}{'lonstatus'}{$item}{$type})) {
                                               $shown{$item} .= $contacts_hash{'contacts'}{'lonstatus'}{$item}{$type};
                                           } else {
                                               $shown{$item} .= $lonstatus_defs->{$type};
                                           }
                                           $shown{$item} .= ', ';
                                       }
                                       $shown{$item} =~ s/, $//;
                                   } else {
                                       $shown{$item} = $defval{$item};
                                   }
                               } elsif ($item eq 'excluded') {
                                   if (ref($contacts_hash{'contacts'}{'lonstatus'}{$item}) eq 'ARRAY') {
                                       $shown{$item} = join(', ',@{$contacts_hash{'contacts'}{'lonstatus'}{$item}});
                                   } else {
                                       $shown{$item} = $defval{$item};
                                   }
                               }
                           } else {
                               $shown{$item} = $defval{$item};
                           }
                       }
                   } else {
                       foreach my $item ('threshold','weights','excluded','sysmail') {
                           $shown{$item} = $defval{$item};
                       }
                   }
                   foreach my $item ('threshold','weights','excluded','sysmail') {
                       $resulttext .= '<li>'.&mt($titles->{'error'.$item}.' -- [_1]',
                                             $shown{$item}).'</li>';
                   }
                   $resulttext .= '</ul></li>';
               }
             if ((ref($changes{'helpform'}) eq 'ARRAY') && (ref($fields) eq 'ARRAY')) {              if ((ref($changes{'helpform'}) eq 'ARRAY') && (ref($fields) eq 'ARRAY')) {
                 my (@optional,@required,@unused,$maxsizechg);                  my (@optional,@required,@unused,$maxsizechg);
                 foreach my $field (@{$changes{'helpform'}}) {                  foreach my $field (@{$changes{'helpform'}}) {
Line 10877  sub modify_contacts { Line 13614  sub modify_contacts {
     return $resulttext;      return $resulttext;
 }  }
   
 sub modify_passwords {  
     my ($r,$dom,$confname,$lastactref,%domconfig) = @_;  
     my ($resulttext,%current,%changes,%newvalues,@oktypes,$errors,  
         $updatedefaults,$updateconf);  
     my $customfn = 'resetpw.html';  
     if (ref($domconfig{'passwords'}) eq 'HASH') {  
         %current = %{$domconfig{'passwords'}};  
     }  
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);  
     my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);  
     if (ref($types) eq 'ARRAY') {  
         @oktypes = @{$types};  
     }  
     push(@oktypes,'default');  
   
     my %titles = &Apache::lonlocal::texthash (  
         intauth_cost   => 'Encryption cost for bcrypt (positive integer)',  
         intauth_check  => 'Check bcrypt cost if authenticated',  
         intauth_switch => 'Existing crypt-based switched to bcrypt on authentication',  
         permanent      => 'Permanent e-mail address',  
         critical       => 'Critical notification address',  
         notify         => 'Notification address',  
         min            => 'Minimum password length',  
         max            => 'Maximum password length',  
         chars          => 'Required characters',  
         numsaved       => 'Number of previous passwords to save',  
         reset          => 'Resetting Forgotten Password',  
         intauth        => 'Encryption of Stored Passwords (Internal Auth)',  
         rules          => 'Rules for LON-CAPA Passwords',  
         crsownerchg    => 'Course Owner Changing Student Passwords',  
         username       => 'Username',  
         email          => 'E-mail address',  
     );  
   
 #  
 # Retrieve current domain configuration for internal authentication from $domconfig{'defaults'}.  
 #  
     my (%curr_defaults,%save_defaults);  
     if (ref($domconfig{'defaults'}) eq 'HASH') {  
         foreach my $key (keys(%{$domconfig{'defaults'}})) {  
             if ($key =~ /^intauth_(cost|check|switch)$/) {  
                 $curr_defaults{$key} = $domconfig{'defaults'}{$key};  
             } else {  
                 $save_defaults{$key} = $domconfig{'defaults'}{$key};  
             }  
         }  
     }  
     my %staticdefaults = (  
         'resetlink'      => 2,  
         'resetcase'      => \@oktypes,  
         'resetprelink'   => 'both',  
         'resetemail'     => ['critical','notify','permanent'],  
         'intauth_cost'   => 10,  
         'intauth_check'  => 0,  
         'intauth_switch' => 0,  
     );  
     $staticdefaults{'min'} = $Apache::lonnet::passwdmin;  
     foreach my $type (@oktypes) {  
         $staticdefaults{'resetpostlink'}{$type} = ['email','username'];  
     }  
     my $linklife = $env{'form.passwords_link'};  
     $linklife =~ s/^\s+|\s+$//g;  
     if (($linklife =~ /^\d+(|\.\d*)$/) && ($linklife > 0)) {  
         $newvalues{'resetlink'} = $linklife;  
         if ($current{'resetlink'}) {  
             if ($current{'resetlink'} ne $linklife) {  
                 $changes{'reset'} = 1;  
             }  
         } elsif (!ref($domconfig{passwords}) eq 'HASH') {  
             if ($staticdefaults{'resetlink'} ne $linklife) {  
                 $changes{'reset'} = 1;  
             }  
         }  
     } elsif ($current{'resetlink'}) {  
         $changes{'reset'} = 1;  
     }  
     my @casesens;  
     my @posscase = &Apache::loncommon::get_env_multiple('form.passwords_case_sensitive');  
     foreach my $case (sort(@posscase)) {  
         if (grep(/^\Q$case\E$/,@oktypes)) {  
             push(@casesens,$case);  
         }  
     }  
     $newvalues{'resetcase'} = \@casesens;  
     if (ref($current{'resetcase'}) eq 'ARRAY') {  
         my @diffs = &Apache::loncommon::compare_arrays($current{'resetcase'},\@casesens);  
         if (@diffs > 0) {  
             $changes{'reset'} = 1;  
         }  
     } elsif (!ref($domconfig{passwords}) eq 'HASH') {  
         my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetcase'},\@casesens);  
         if (@diffs > 0) {  
             $changes{'reset'} = 1;  
         }  
     }  
     if ($env{'form.passwords_prelink'} =~ /^(both|either)$/) {  
         $newvalues{'resetprelink'} = $env{'form.passwords_prelink'};  
         if (exists($current{'resetprelink'})) {  
             if ($current{'resetprelink'} ne $newvalues{'resetprelink'}) {  
                 $changes{'reset'} = 1;  
             }  
         } elsif (!ref($domconfig{passwords}) eq 'HASH') {  
             if ($staticdefaults{'resetprelink'} ne $newvalues{'resetprelink'}) {  
                 $changes{'reset'} = 1;  
             }  
         }  
     } elsif ($current{'resetprelink'}) {  
         $changes{'reset'} = 1;  
     }  
     foreach my $type (@oktypes) {  
         my @possplink = &Apache::loncommon::get_env_multiple('form.passwords_postlink_'.$type);  
         my @postlink;  
         foreach my $item (sort(@possplink)) {  
             if ($item =~ /^(email|username)$/) {  
                 push(@postlink,$item);  
             }  
         }  
         $newvalues{'resetpostlink'}{$type} = \@postlink;  
         unless ($changes{'reset'}) {  
             if (ref($current{'resetpostlink'}) eq 'HASH') {  
                 if (ref($current{'resetpostlink'}{$type}) eq 'ARRAY') {  
                     my @diffs = &Apache::loncommon::compare_arrays($current{'resetpostlink'}{$type},\@postlink);  
                     if (@diffs > 0) {  
                         $changes{'reset'} = 1;  
                     }  
                 } else {  
                     $changes{'reset'} = 1;  
                 }  
             } elsif (!ref($domconfig{passwords}) eq 'HASH') {  
                 my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetpostlink'}{$type},\@postlink);  
                 if (@diffs > 0) {  
                     $changes{'reset'} = 1;  
                 }  
             }  
         }  
     }  
     my @possemailsrc = &Apache::loncommon::get_env_multiple('form.passwords_emailsrc');  
     my @resetemail;  
     foreach my $item (sort(@possemailsrc)) {  
         if ($item =~ /^(permanent|critical|notify)$/) {  
             push(@resetemail,$item);  
         }  
     }  
     $newvalues{'resetemail'} = \@resetemail;  
     unless ($changes{'reset'}) {  
         if (ref($current{'resetemail'}) eq 'ARRAY') {  
             my @diffs = &Apache::loncommon::compare_arrays($current{'resetemail'},\@resetemail);  
             if (@diffs > 0) {  
                 $changes{'reset'} = 1;  
             }  
         } elsif (!ref($domconfig{passwords}) eq 'HASH') {  
             my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetemail'},\@resetemail);  
             if (@diffs > 0) {  
                 $changes{'reset'} = 1;  
             }  
         }  
     }  
     if ($env{'form.passwords_stdtext'} == 0) {  
         $newvalues{'resetremove'} = 1;  
         unless ($current{'resetremove'}) {  
             $changes{'reset'} = 1;  
         }  
     } elsif ($current{'resetremove'}) {  
         $changes{'reset'} = 1;  
     }  
     if ($env{'form.passwords_customfile.filename'} ne '') {  
         my $servadm = $r->dir_config('lonAdmEMail');  
         my $servadm = $r->dir_config('lonAdmEMail');  
         my ($configuserok,$author_ok,$switchserver) =  
             &config_check($dom,$confname,$servadm);  
         my $error;  
         if ($configuserok eq 'ok') {  
             if ($switchserver) {  
                 $error = &mt("Upload of file containing domain-specific text is not permitted to this server: [_1]",$switchserver);  
             } else {  
                 if ($author_ok eq 'ok') {  
                     my ($result,$customurl) =  
                         &publishlogo($r,'upload','passwords_customfile',$dom,  
                                      $confname,'customtext/resetpw','','',$customfn);  
                     if ($result eq 'ok') {  
                         $newvalues{'resetcustom'} = $customurl;  
                         $changes{'reset'} = 1;  
                     } else {  
                         $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$customfn,$result);  
                     }  
                 } else {  
                     $error = &mt("Upload of [_1] failed because an author role could not be assigned to a Domain Configuration user ([_2]) in domain: [_3].  Error was: [_4].",$customfn,$confname,$dom,$author_ok);  
                 }  
             }  
         } else {  
             $error = &mt("Upload of [_1] failed because a Domain Configuration user ([_2]) could not be created in domain: [_3].  Error was: [_4].",$customfn,$confname,$dom,$configuserok);  
         }  
         if ($error) {  
             &Apache::lonnet::logthis($error);  
             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';  
         }  
     } elsif ($current{'resetcustom'}) {  
         if ($env{'form.passwords_custom_del'}) {  
             $changes{'reset'} = 1;  
         } else {  
             $newvalues{'resetcustom'} = $current{'resetcustom'};  
         }  
     }  
     $env{'form.intauth_cost'} =~ s/^\s+|\s+$//g;  
     if (($env{'form.intauth_cost'} ne '') && ($env{'form.intauth_cost'} =~ /^\d+$/)) {  
         $save_defaults{'intauth_cost'} = $env{'form.intauth_cost'};  
         if ($save_defaults{'intauth_cost'} ne $curr_defaults{'intauth_cost'}) {  
             $changes{'intauth'} = 1;  
         }  
     } else {  
         $save_defaults{'intauth_cost'} = $curr_defaults{'intauth_cost'};  
     }  
     if ($env{'form.intauth_check'} =~ /^(0|1|2)$/) {  
         $save_defaults{'intauth_check'} = $env{'form.intauth_check'};  
         if ($save_defaults{'intauth_check'} ne $curr_defaults{'intauth_check'}) {  
             $changes{'intauth'} = 1;  
         }  
     } else {  
         $save_defaults{'intauth_check'} = $curr_defaults{'intauth_check'};  
     }  
     if ($env{'form.intauth_switch'} =~ /^(0|1|2)$/) {  
         $save_defaults{'intauth_switch'} = $env{'form.intauth_switch'};  
         if ($save_defaults{'intauth_switch'} ne $curr_defaults{'intauth_switch'}) {  
             $changes{'intauth'} = 1;  
         }  
     } else {  
         $save_defaults{'intauth_check'} = $curr_defaults{'intauth_check'};  
     }  
     foreach my $item ('cost','check','switch') {  
         if ($save_defaults{'intauth_'.$item} ne $domdefaults{'intauth_'.$item}) {  
             $domdefaults{'intauth_'.$item} = $save_defaults{'intauth_'.$item};  
             $updatedefaults = 1;  
         }  
     }  
     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 = (  
                         by => [],  
                         for => [],  
                       );  
     foreach my $item ('by','for') {  
         my @posstypes = &Apache::loncommon::get_env_multiple('form.passwords_crsowner_'.$item);  
         foreach my $type (sort(@posstypes)) {  
             if (grep(/^\Q$type\E$/,@oktypes)) {  
                 push(@{$crsownerchg{$item}},$type);  
             }  
         }  
     }  
     $newvalues{'crsownerchg'} = \%crsownerchg;  
     if (ref($current{'crsownerchg'}) eq 'HASH') {  
         foreach my $item ('by','for') {  
             if (ref($current{'crsownerchg'}{$item}) eq 'ARRAY') {  
                 my @diffs = &Apache::loncommon::compare_arrays($current{'crsownerchg'}{$item},$crsownerchg{$item});  
                 if (@diffs > 0) {  
                     $changes{'crsownerchg'} = 1;  
                     last;  
                 }  
             }  
         }  
     } elsif (!(ref($domconfig{passwords}) eq 'HASH')) {  
         foreach my $item ('by','for') {  
             if (@{$crsownerchg{$item}} > 0) {  
                 $changes{'crsownerchg'} = 1;  
                 last;  
             }  
         }  
     }  
   
     my %confighash = (  
                         defaults  => \%save_defaults,  
                         passwords => \%newvalues,  
                      );  
     &process_captcha('passwords',\%changes,$confighash{'passwords'},$domconfig{'passwords'});  
   
     my $putresult = &Apache::lonnet::put_dom('configuration',\%confighash,$dom);  
     if ($putresult eq 'ok') {  
         if (keys(%changes) > 0) {  
             $resulttext = &mt('Changes made: ').'<ul>';  
             foreach my $key ('reset','intauth','rules','crsownerchg') {  
                 if ($changes{$key}) {  
                     unless ($key eq 'intauth') {  
                         $updateconf = 1;  
                     }  
                     $resulttext .= '<li>'.$titles{$key}.':<ul>';  
                     if ($key eq 'reset') {  
                         if ($confighash{'passwords'}{'captcha'} eq 'original') {  
                             $resulttext .= '<li>'.&mt('CAPTCHA validation set to use: original CAPTCHA').'</li>';  
                         } elsif ($confighash{'passwords'}{'captcha'} eq 'recaptcha') {  
                             $resulttext .= '<li>'.&mt('CAPTCHA validation set to use: reCAPTCHA').' '.  
                                            &mt('version: [_1]',$confighash{'passwords'}{'recaptchaversion'}).'<br />';  
                             if (ref($confighash{'passwords'}{'recaptchakeys'}) eq 'HASH') {  
                                 $resulttext .= &mt('Public key: [_1]',$confighash{'passwords'}{'recaptchakeys'}{'public'}).'</br>'.  
                                                &mt('Private key: [_1]',$confighash{'passwords'}{'recaptchakeys'}{'private'}).'</li>';  
                             }  
                         } else {  
                             $resulttext .= '<li>'.&mt('No CAPTCHA validation').'</li>';  
                         }  
                         if ($confighash{'passwords'}{'resetlink'}) {  
                             $resulttext .= '<li>'.&mt('Reset link expiration set to [quant,_1,hour]',$confighash{'passwords'}{'resetlink'}).'</li>';  
                         } else {  
                             $resulttext .= '<li>'.&mt('No reset link expiration set.').' '.  
                                                   &mt('Will default to 2 hours').'</li>';  
                         }  
                         if (ref($confighash{'passwords'}{'resetcase'}) eq 'ARRAY') {  
                             if (@{$confighash{'passwords'}{'resetcase'}} == 0) {  
                                 $resulttext .= '<li>'.&mt('User input for username and/or e-mail address not case sensitive for "Forgot Password" web form').'</li>';  
                             } else {  
                                 my $casesens;  
                                 foreach my $type (@{$confighash{'passwords'}{'resetcase'}}) {  
                                     if ($type eq 'default') {  
                                         $casesens .= $othertitle.', ';  
                                     } elsif ($usertypes->{$type} ne '') {  
                                         $casesens .= $usertypes->{$type}.', ';  
                                     }  
                                 }  
                                 $casesens =~ s/\Q, \E$//;  
                                 $resulttext .= '<li>'.&mt('"Forgot Password" web form input for username and/or e-mail address is case-sensitive for: [_1]',$casesens).'</li>';  
                             }  
                         } else {  
                             $resulttext .= '<li>'.&mt('Case-sensitivity not set for "Forgot Password" web form').' '.&mt('Will default to case-sensitive for username and/or e-mail address for all').'</li>';  
                         }  
                         if ($confighash{'passwords'}{'resetprelink'} eq 'either') {  
                             $resulttext .= '<li>'.&mt('Users can enter either a username or an e-mail address in "Forgot Password" web form').'</li>';  
                         } else {  
                             $resulttext .= '<li>'.&mt('Users can enter both a username and an e-mail address in "Forgot Password" web form').'</li>';  
                         }  
                         if (ref($confighash{'passwords'}{'resetpostlink'}) eq 'HASH') {  
                             my $output;  
                             if (ref($types) eq 'ARRAY') {  
                                 foreach my $type (@{$types}) {  
                                     if (ref($confighash{'passwords'}{'resetpostlink'}{$type}) eq 'ARRAY') {  
                                         if (@{$confighash{'passwords'}{'resetpostlink'}{$type}} == 0) {  
                                             $output .= $usertypes->{$type}.' -- '.&mt('none');  
                                         } else {  
                                             $output .= $usertypes->{$type}.' -- '.  
                                                        join(', ',map { $titles{$_}; } (@{$confighash{'passwords'}{'resetpostlink'}{$type}})).'; ';  
                                         }  
                                     }  
                                 }  
                             }  
                             if (ref($confighash{'passwords'}{'resetpostlink'}{'default'}) eq 'ARRAY') {  
                                 if (@{$confighash{'passwords'}{'resetpostlink'}{'default'}} == 0) {  
                                     $output .= $othertitle.' -- '.&mt('none');  
                                 } else {  
                                     $output .= $othertitle.' -- '.  
                                                join(', ',map { $titles{$_}; } (@{$confighash{'passwords'}{'resetpostlink'}{'default'}}));  
                                 }  
                             }  
                             if ($output) {  
                                 $resulttext .= '<li>'.&mt('Information required for new password form (by user type) set to: [_1]',$output).'</li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt('Information required for new password form not set.').' '.&mt('Will default to requiring both the username and an e-mail address').'</li>';  
                             }  
                         } else {  
                             $resulttext .= '<li>'.&mt('Information required for new password form not set.').' '.&mt('Will default to requiring both the username and an e-mail address').'</li>';  
                         }  
                         if (ref($confighash{'passwords'}{'resetemail'}) eq 'ARRAY') {  
                             if (@{$confighash{'passwords'}{'resetemail'}} > 0) {  
                                 $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$confighash{'passwords'}{'resetemail'}})).'</li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$staticdefaults{'resetemail'}})).'</li>';  
                             }  
                         } else {  
                             $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA usedfor verification will include: [_1]',join(', ',map { $titles{$_}; } @{$staticdefaults{'resetemail'}})).'</li>';  
                         }  
                         if ($confighash{'passwords'}{'resetremove'}) {  
                             $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" web form not shown').'</li>';  
                         } else {  
                             $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" web form is shown').'</li>';  
                         }  
                         if ($confighash{'passwords'}{'resetcustom'}) {  
                             my $customlink = &Apache::loncommon::modal_link($confighash{'passwords'}{'resetcustom'},  
                                                                             &mt('custom text'),600,500,undef,undef,  
                                                                             undef,undef,'background-color:#ffffff');  
                             $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" form includes: [_1]',$customlink).'</li>';  
                         } else {  
                             $resulttext .= '<li>'.&mt('No custom text included in preamble to "Forgot Password" form').'</li>';  
                         }  
                     } elsif ($key eq 'intauth') {  
                         foreach my $item ('cost','switch','check') {  
                             my $value = $save_defaults{$key.'_'.$item};  
                             if ($item eq 'switch') {  
                                 my %optiondesc = &Apache::lonlocal::texthash (  
                                                      0 => 'No',  
                                                      1 => 'Yes',  
                                                      2 => 'Yes, and copy existing passwd file to passwd.bak file',  
                                                  );  
                                 if ($value =~ /^(0|1|2)$/) {  
                                     $value = $optiondesc{$value};  
                                 } else {  
                                     $value = &mt('none -- defaults to No');  
                                 }  
                             } elsif ($item eq 'check') {  
                                 my %optiondesc = &Apache::lonlocal::texthash (  
                                                      0 => 'No',  
                                                      1 => 'Yes, allow login then update passwd file using default cost (if higher)',  
                                                      2 => 'Yes, disallow login if stored cost is less than domain default',  
                                                  );  
                                 if ($value =~ /^(0|1|2)$/) {  
                                     $value = $optiondesc{$value};  
                                 } else {  
                                     $value = &mt('none -- defaults to No');  
                                 }  
                             }  
                             $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$titles{$key.'_'.$item},$value).'</li>';  
                         }  
                     } elsif ($key eq 'rules') {  
                         foreach my $rule ('min','max','numsaved') {  
                             if ($confighash{'passwords'}{$rule} eq '') {  
                                 if ($rule eq 'min') {  
                                     $resulttext .= '<li>'.&mt('[_1] not set.',$titles{$rule});  
                                                    ' '.&mt('Default of [_1] will be used',  
                                                            $Apache::lonnet::passwdmin).'</li>';  
                                 } else {  
                                     $resulttext .= '<li>'.&mt('[_1] set to none',$titles{$rule}).'</li>';  
                                 }  
                             } else {  
                                 $resulttext .= '<li>'.&mt('[_1] set to [_2]',$titles{$rule},$confighash{'passwords'}{$rule}).'</li>';  
                             }  
                         }  
                         if (ref($confighash{'passwords'}{'chars'}) eq 'ARRAY') {  
                             if (@{$confighash{'passwords'}{'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{$_} } @{$confighash{'passwords'}{'chars'}}).  
                                              '</li></ul>';  
                                 $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{'chars'},$needed).'</li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';  
                             }  
                         } else {  
                             $resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';  
                         }  
                     } elsif ($key eq 'crsownerchg') {  
                         if (ref($confighash{'passwords'}{'crsownerchg'}) eq 'HASH') {  
                             if ((@{$confighash{'passwords'}{'crsownerchg'}{'by'}} == 0) ||  
                                 (@{$confighash{'passwords'}{'crsownerchg'}{'for'}} == 0)) {  
                                 $resulttext .= '<li>'.&mt('Course owner may not change student passwords.').'</li>';  
                             } else {  
                                 my %crsownerstr;  
                                 foreach my $item ('by','for') {  
                                     if (ref($confighash{'passwords'}{'crsownerchg'}{$item}) eq 'ARRAY') {  
                                         foreach my $type (@{$confighash{'passwords'}{'crsownerchg'}{$item}}) {  
                                             if ($type eq 'default') {  
                                                 $crsownerstr{$item} .= $othertitle.', ';  
                                             } elsif ($usertypes->{$type} ne '') {  
                                                 $crsownerstr{$item} .= $usertypes->{$type}.', ';  
                                             }  
                                         }  
                                         $crsownerstr{$item} =~ s/\Q, \E$//;  
                                     }  
                                 }  
                                 $resulttext .= '<li>'.&mt('Course owner (with status: [_1]) may change passwords for students (with status: [_2]).',  
                                            $crsownerstr{'by'},$crsownerstr{'for'}).'</li>';  
                             }  
                         } else {  
                             $resulttext .= '<li>'.&mt('Course owner may not change student passwords.').'</li>';  
                         }  
                     }  
                     $resulttext .= '</ul></li>';  
                 }  
             }  
             $resulttext .= '</ul>';  
         } else {  
             $resulttext = &mt('No changes made to password settings');  
         }  
         my $cachetime = 24*60*60;  
         if ($updatedefaults) {  
             &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);  
             if (ref($lastactref) eq 'HASH') {  
                 $lastactref->{'domdefaults'} = 1;  
             }  
         }  
         if ($updateconf) {  
             &Apache::lonnet::do_cache_new('passwdconf',$dom,$confighash{'passwords'},$cachetime);  
             if (ref($lastactref) eq 'HASH') {  
                 $lastactref->{'passwdconf'} = 1;  
             }  
         }  
     } else {  
         $resulttext = '<span class="LC_error">'.  
             &mt('An error occurred: [_1]',$putresult).'</span>';  
     }  
     if ($errors) {  
         $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.  
                        $errors.'</ul></p>';  
     }  
     return $resulttext;  
 }  
   
 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 11504  sub modify_usercreation { Line 13698  sub modify_usercreation {
     }      }
   
     my @authen_contexts = ('author','course','domain');      my @authen_contexts = ('author','course','domain');
     my @authtypes = ('int','krb4','krb5','loc');      my @authtypes = ('int','krb4','krb5','loc','lti');
     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 11719  sub modify_selfcreation { Line 13913  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 11769  sub modify_selfcreation { Line 13962  sub modify_selfcreation {
                             if (($chosen eq 'inst') || ($chosen eq 'noninst')) {                              if (($chosen eq 'inst') || ($chosen eq 'noninst')) {
                                 my $emaildom;                                  my $emaildom;
                                 if ($env{'form.cancreate_emaildomain_'.$chosen.'_'.$type} =~ /^\@[^\@]+$/) {                                  if ($env{'form.cancreate_emaildomain_'.$chosen.'_'.$type} =~ /^\@[^\@]+$/) {
                                     $emaildom = $env{'form.cancreate_emaildomain_'.$chosen.'_'.$type};                                      $emaildom = $env{'form.cancreate_emaildomain_'.$chosen.'_'.$type}; 
                                     $cancreate{'emaildomain'}{$type}{$chosen} = $emaildom;                                      $cancreate{'emaildomain'}{$type}{$chosen} = $emaildom;
                                     if (ref($curremaildom{$type}) eq 'HASH') {                                      if (ref($curremaildom{$type}) eq 'HASH') {
                                         if (exists($curremaildom{$type}{$chosen})) {                                          if (exists($curremaildom{$type}{$chosen})) {
Line 11781  sub modify_selfcreation { Line 13974  sub modify_selfcreation {
                                         }                                          }
                                     } elsif ($emaildom ne '') {                                      } elsif ($emaildom ne '') {
                                         push(@{$changes{'cancreate'}},'emaildomain');                                          push(@{$changes{'cancreate'}},'emaildomain');
                                     }                                      } 
                                 }                                  }
                                 $cancreate{'emailoptions'}{$type} = $env{'form.cancreate_emailoptions_'.$type};                                  $cancreate{'emailoptions'}{$type} = $env{'form.cancreate_emailoptions_'.$type};
                             } elsif ($chosen eq 'custom') {                              } elsif ($chosen eq 'custom') {
Line 12208  sub modify_selfcreation { Line 14401  sub modify_selfcreation {
                                                                   );                                                                    );
                         if (@types) {                          if (@types) {
                             if (@statuses) {                              if (@statuses) {
                                 $chgtext .= &mt('Processing of requests to create account with e-mail verification set as follows:').                                  $chgtext .= &mt('Processing of requests to create account with e-mail verification set as follows:'). 
                                             '<ul>';                                              '<ul>';
                                 foreach my $status (@statuses) {                                  foreach my $status (@statuses) {
                                     if ($status eq 'default') {                                      if ($status eq 'default') {
Line 12234  sub modify_selfcreation { Line 14427  sub modify_selfcreation {
                                 $chgtext .= &mt('For self-created accounts verified by e-mail address, username is set as follows:').                                  $chgtext .= &mt('For self-created accounts verified by e-mail address, username is set as follows:').
                                             '<ul>';                                              '<ul>';
                                 foreach my $status (@statuses) {                                  foreach my $status (@statuses) {
                                     if ($status eq 'default') {                                      if ($type eq 'default') {
                                         $chgtext .= '<li>'.$othertitle.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>';                                          $chgtext .= '<li>'.$othertitle.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>';
                                     } else {                                      } else {
                                         $chgtext .= '<li>'.$usertypes{$status}.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>';                                          $chgtext .= '<li>'.$usertypes{$status}.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>';
Line 12294  sub modify_selfcreation { Line 14487  sub modify_selfcreation {
                                                 $output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>';                                                  $output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>';
                                             } else {                                              } else {
                                                 $output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address needs to end: [_1]",                                                  $output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address needs to end: [_1]",
                                                                                               $cancreate{'emaildomain'}{$type}{'inst'}).'</li>';                                                                                                $cancreate{'emaildomain'}{$type}{'inst'}).'</li>'; 
                                             }                                              }
                                         }                                          }
                                     } elsif ($cancreate{'emailoptions'}{$type} eq 'noninst') {                                      } elsif ($cancreate{'emailoptions'}{$type} eq 'noninst') {
Line 12312  sub modify_selfcreation { Line 14505  sub modify_selfcreation {
                                                 $output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>';                                                  $output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>';
                                             } else {                                              } else {
                                                 $output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address must not end: [_1]",                                                  $output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address must not end: [_1]",
                                                                                                 $cancreate{'emaildomain'}{$type}{'noninst'}).'</li>';                                                                                                  $cancreate{'emaildomain'}{$type}{'noninst'}).'</li>';   
                                             }                                              }
                                         }                                          }
                                     }                                      }
Line 12416  sub modify_selfcreation { Line 14609  sub modify_selfcreation {
                                 $typename = $othertitle;                                  $typename = $othertitle;
                             } else {                              } else {
                                 $typename = $usertypes{$type};                                  $typename = $usertypes{$type};
                             }                              } 
                             $chgtext .= &mt('(Affiliation: [_1])',$typename);                              $chgtext .= &mt('(Affiliation: [_1])',$typename);
                         }                          }
                         if (@{$email_rule{$type}} > 0) {                          if (@{$email_rule{$type}} > 0) {
Line 12503  sub modify_selfcreation { Line 14696  sub modify_selfcreation {
 }  }
   
 sub process_captcha {  sub process_captcha {
     my ($container,$changes,$newsettings,$currsettings) = @_;      my ($container,$changes,$newsettings,$current) = @_;
     return unless ((ref($changes) eq 'HASH') && (ref($newsettings) eq 'HASH'));      return unless ((ref($changes) eq 'HASH') && (ref($newsettings) eq 'HASH') || (ref($current) eq 'HASH'));
     $newsettings->{'captcha'} = $env{'form.'.$container.'_captcha'};      $newsettings->{'captcha'} = $env{'form.'.$container.'_captcha'};
     unless ($newsettings->{'captcha'} eq 'recaptcha' || $newsettings->{'captcha'} eq 'notused') {      unless ($newsettings->{'captcha'} eq 'recaptcha' || $newsettings->{'captcha'} eq 'notused') {
         $newsettings->{'captcha'} = 'original';          $newsettings->{'captcha'} = 'original';
     }      }
     my %current;      if ($current->{'captcha'} ne $newsettings->{'captcha'}) {
     if (ref($currsettings) eq 'HASH') {  
         %current = %{$currsettings};  
     }  
     if ($current{'captcha'} ne $newsettings->{'captcha'}) {  
         if ($container eq 'cancreate') {          if ($container eq 'cancreate') {
             if (ref($changes->{'cancreate'}) eq 'ARRAY') {              if (ref($changes->{'cancreate'}) eq 'ARRAY') {
                 push(@{$changes->{'cancreate'}},'captcha');                  push(@{$changes->{'cancreate'}},'captcha');
             } elsif (!defined($changes->{'cancreate'})) {              } elsif (!defined($changes->{'cancreate'})) {
                 $changes->{'cancreate'} = ['captcha'];                  $changes->{'cancreate'} = ['captcha'];
             }              }
         } elsif ($container eq 'passwords') {  
             $changes->{'reset'} = 1;  
         } else {          } else {
             $changes->{'captcha'} = 1;              $changes->{'captcha'} = 1;
         }          }
Line 12543  sub process_captcha { Line 14730  sub process_captcha {
         }          }
         $newsettings->{'recaptchaversion'} = $newversion;          $newsettings->{'recaptchaversion'} = $newversion;
     }      }
     if (ref($current{'recaptchakeys'}) eq 'HASH') {      if (ref($current->{'recaptchakeys'}) eq 'HASH') {
         $currpub = $current{'recaptchakeys'}{'public'};          $currpub = $current->{'recaptchakeys'}{'public'};
         $currpriv = $current{'recaptchakeys'}{'private'};          $currpriv = $current->{'recaptchakeys'}{'private'};
         unless ($newsettings->{'captcha'} eq 'recaptcha') {          unless ($newsettings->{'captcha'} eq 'recaptcha') {
             $newsettings->{'recaptchakeys'} = {              $newsettings->{'recaptchakeys'} = {
                                                  public  => '',                                                   public  => '',
Line 12553  sub process_captcha { Line 14740  sub process_captcha {
                                               }                                                }
         }          }
     }      }
     if ($current{'captcha'} eq 'recaptcha') {      if ($current->{'captcha'} eq 'recaptcha') {
         $currversion = $current{'recaptchaversion'};          $currversion = $current->{'recaptchaversion'};
         if ($currversion ne '2') {          if ($currversion ne '2') {
             $currversion = 1;              $currversion = 1;
         }          }
Line 12566  sub process_captcha { Line 14753  sub process_captcha {
             } elsif (!defined($changes->{'cancreate'})) {              } elsif (!defined($changes->{'cancreate'})) {
                 $changes->{'cancreate'} = ['recaptchaversion'];                  $changes->{'cancreate'} = ['recaptchaversion'];
             }              }
         } elsif ($container eq 'passwords') {  
             $changes->{'reset'} = 1;  
         } else {          } else {
             $changes->{'recaptchaversion'} = 1;              $changes->{'recaptchaversion'} = 1;
         }          }
Line 12579  sub process_captcha { Line 14764  sub process_captcha {
             } elsif (!defined($changes->{'cancreate'})) {              } elsif (!defined($changes->{'cancreate'})) {
                 $changes->{'cancreate'} = ['recaptchakeys'];                  $changes->{'cancreate'} = ['recaptchakeys'];
             }              }
         } elsif ($container eq 'passwords') {  
             $changes->{'reset'} = 1;  
         } else {          } else {
             $changes->{'recaptchakeys'} = 1;              $changes->{'recaptchakeys'} = 1;
         }          }
Line 12696  sub modify_defaults { Line 14879  sub modify_defaults {
     my ($resulttext,$mailmsgtxt,%newvalues,%changes,@errors);      my ($resulttext,$mailmsgtxt,%newvalues,%changes,@errors);
     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','intauth_cost','intauth_check','intauth_switch');
     my @authtypes = ('internal','krb4','krb5','localauth');      my @authtypes = ('internal','krb4','krb5','localauth','lti');
     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 12738  sub modify_defaults { Line 14921  sub modify_defaults {
                     push(@errors,$item);                      push(@errors,$item);
                 }                  }
             }              }
           } elsif ($item eq 'intauth_cost') {
               if ($newvalues{$item} ne '') {
                   if ($newvalues{$item} =~ /\D/) {
                       push(@errors,$item);
                   }
               }
           } elsif ($item eq 'intauth_check') {
               if ($newvalues{$item} ne '') {
                   unless ($newvalues{$item} =~ /^(0|1|2)$/) {
                       push(@errors,$item);
                   }
               }
           } elsif ($item eq 'intauth_switch') {
               if ($newvalues{$item} ne '') {
                   unless ($newvalues{$item} =~ /^(0|1|2)$/) {
                       push(@errors,$item);
                   }
               }
         }          }
         if (grep(/^\Q$item\E$/,@errors)) {          if (grep(/^\Q$item\E$/,@errors)) {
             $newvalues{$item} = $domdefaults{$item};              $newvalues{$item} = $domdefaults{$item};
Line 12746  sub modify_defaults { Line 14947  sub modify_defaults {
         }          }
         $domdefaults{$item} = $newvalues{$item};          $domdefaults{$item} = $newvalues{$item};
     }      }
     my %staticdefaults = (  
                            'intauth_cost'   => 10,  
                            'intauth_check'  => 0,  
                            'intauth_switch' => 0,  
                          );  
     foreach my $item ('intauth_cost','intauth_check','intauth_switch') {  
         if (exists($domdefaults{$item})) {  
             $newvalues{$item} = $domdefaults{$item};  
         } else {  
             $newvalues{$item} = $staticdefaults{$item};  
         }  
     }  
     my %defaults_hash = (      my %defaults_hash = (
                          defaults => \%newvalues,                           defaults => \%newvalues,
                         );                          );
Line 12778  sub modify_defaults { Line 14967  sub modify_defaults {
     my @allpos;      my @allpos;
     my %alltypes;      my %alltypes;
     my @inststatusguest;      my @inststatusguest;
     if (ref($currinststatus) eq 'HASH') {      if (ref($currinststatus->{'inststatusguest'}) eq 'ARRAY') {
         if (ref($currinststatus->{'inststatusguest'}) eq 'ARRAY') {          foreach my $type (@{$currinststatus->{'inststatusguest'}}) {
             foreach my $type (@{$currinststatus->{'inststatusguest'}}) {              unless (grep(/^\Q$type\E$/,@todelete)) {
                 unless (grep(/^\Q$type\E$/,@todelete)) {                  push(@inststatusguest,$type);
                     push(@inststatusguest,$type);  
                 }  
             }              }
         }          }
     }      }
Line 12871  sub modify_defaults { Line 15058  sub modify_defaults {
                             $resulttext =~ s/, $//;                              $resulttext =~ s/, $//;
                             $resulttext .= '</li>';                              $resulttext .= '</li>';
                         } else {                          } else {
                             $resulttext .= '<li>'.&mt('Institutional user status types deleted').'</li>';                              $resulttext .= '<li>'.&mt('Institutional user status types deleted').'</li>'; 
                         }                          }
                     }                      }
                 } else {                  } else {
Line 12885  sub modify_defaults { Line 15072  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}};
                       } elsif ($item eq 'intauth_switch') {
                           my %optiondesc = &Apache::lonlocal::texthash (
                                               0 => 'No',
                                               1 => 'Yes',
                                               2 => 'Yes, and copy existing passwd file to passwd.bak file',
                                            );
                           if ($value =~ /^(0|1|2)$/) {
                               $value = $optiondesc{$value};
                           } else {
                               $value = &mt('none -- defaults to No');
                           }
                       } elsif ($item eq 'intauth_check') {
                           my %optiondesc = &Apache::lonlocal::texthash (
                                                0 => 'No',
                                                1 => 'Yes, allow login then update passwd file using default cost (if higher)',
                                                2 => 'Yes, disallow login if stored cost is less than domain default',
                                            );
                           if ($value =~ /^(0|1|2)$/) {
                               $value = $optiondesc{$value};
                           } else {
                               $value = &mt('none -- defaults to No');
                           }
                     }                      }
                     $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";  
Line 13098  sub modify_scantron { Line 15308  sub modify_scantron {
                 &mt('An error occurred: [_1]',$putresult).'</span>';                  &mt('An error occurred: [_1]',$putresult).'</span>';
         }          }
     } else {      } else {
         $resulttext = &mt('No changes made to bubblesheet format settings');          $resulttext = &mt('No changes made to bubblesheet format file'); 
     }      }
     if ($errors) {      if ($errors) {
         $resulttext .= &mt('The following errors occurred: ').'<ul>'.          $resulttext .= &mt('The following errors occurred: ').'<ul>'.
Line 13131  sub modify_coursecategories { Line 15341  sub modify_coursecategories {
         if ($domconfig{'coursecategories'}{'categorizecomm'} ne $env{'form.categorizecomm'}) {          if ($domconfig{'coursecategories'}{'categorizecomm'} ne $env{'form.categorizecomm'}) {
             $changes{'categorizecomm'} = 1;              $changes{'categorizecomm'} = 1;
             $domconfig{'coursecategories'}{'categorizecomm'} = $env{'form.categorizecomm'};              $domconfig{'coursecategories'}{'categorizecomm'} = $env{'form.categorizecomm'};
   
           }
           if ($domconfig{'coursecategories'}{'togglecatsplace'} ne $env{'form.togglecatsplace'}) {
               $changes{'togglecatsplace'} = 1;
               $domconfig{'coursecategories'}{'togglecatsplace'} = $env{'form.togglecatsplace'};
           }
           if ($domconfig{'coursecategories'}{'categorizeplace'} ne $env{'form.categorizeplace'}) {
               $changes{'categorizeplace'} = 1;
               $domconfig{'coursecategories'}{'categorizeplace'} = $env{'form.categorizeplace'};
         }          }
         foreach my $item (@catitems) {          foreach my $item (@catitems) {
             if (grep(/^\Q$env{'form.coursecat_'.$item}\E$/,@cattypes)) {              if (grep(/^\Q$env{'form.coursecat_'.$item}\E$/,@cattypes)) {
Line 13145  sub modify_coursecategories { Line 15364  sub modify_coursecategories {
         $changes{'categorize'} = 1;          $changes{'categorize'} = 1;
         $changes{'togglecatscomm'} = 1;          $changes{'togglecatscomm'} = 1;
         $changes{'categorizecomm'} = 1;          $changes{'categorizecomm'} = 1;
           $changes{'togglecatsplace'} = 1;
           $changes{'categorizeplace'} = 1;
         $domconfig{'coursecategories'} = {          $domconfig{'coursecategories'} = {
                                              togglecats => $env{'form.togglecats'},                                               togglecats => $env{'form.togglecats'},
                                              categorize => $env{'form.categorize'},                                               categorize => $env{'form.categorize'},
                                              togglecatscomm => $env{'form.togglecatscomm'},                                               togglecatscomm => $env{'form.togglecatscomm'},
                                              categorizecomm => $env{'form.categorizecomm'},                                               categorizecomm => $env{'form.categorizecomm'},
                                                togglecatsplace => $env{'form.togglecatsplace'},
                                                categorizeplace => $env{'form.categorizeplace'},
                                          };                                           };
         foreach my $item (@catitems) {          foreach my $item (@catitems) {
             if ($env{'form.coursecat_'.$item} ne 'std') {              if ($env{'form.coursecat_'.$item} ne 'std') {
Line 13167  sub modify_coursecategories { Line 15390  sub modify_coursecategories {
         if (($domconfig{'coursecategories'}{'cats'}{'communities::0'} ne '')  && ($env{'form.communities'} == 0)) {          if (($domconfig{'coursecategories'}{'cats'}{'communities::0'} ne '')  && ($env{'form.communities'} == 0)) {
             push(@deletecategory,'communities::0');              push(@deletecategory,'communities::0');
         }          }
           if (($domconfig{'coursecategories'}{'cats'}{'placement::0'} ne '')  && ($env{'form.placement'} == 0)) {
               push(@deletecategory,'placement::0');
           }
     }      }
     my (@predelcats,@predeltrails,%predelallitems,%sort_by_deltrail);      my (@predelcats,@predeltrails,%predelallitems,%sort_by_deltrail);
     if (ref($cathash) eq 'HASH') {      if (ref($cathash) eq 'HASH') {
Line 13229  sub modify_coursecategories { Line 15455  sub modify_coursecategories {
             $adds{$newitem} = 1;              $adds{$newitem} = 1;
         }          }
     }      }
       if ($env{'form.placement'} eq '1') {
           if (ref($cathash) eq 'HASH') {
               my $newitem = 'placement::0';
               if ($cathash->{$newitem} eq '') {
                   $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.placement_pos'};
                   $adds{$newitem} = 1;
               }
           } else {
               my $newitem = 'placement::0';
               $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.placement_pos'};
               $adds{$newitem} = 1;
           }
       }
     if ($env{'form.addcategory_name'} ne '') {      if ($env{'form.addcategory_name'} ne '') {
         if (($env{'form.addcategory_name'} ne 'instcode') &&          if (($env{'form.addcategory_name'} ne 'instcode') &&
             ($env{'form.addcategory_name'} ne 'communities')) {              ($env{'form.addcategory_name'} ne 'communities') &&
               ($env{'form.addcategory_name'} ne 'placement')) {
             my $newitem = &escape($env{'form.addcategory_name'}).'::0';              my $newitem = &escape($env{'form.addcategory_name'}).'::0';
             $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.addcategory_pos'};              $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.addcategory_pos'};
             $adds{$newitem} = 1;              $adds{$newitem} = 1;
Line 13347  sub modify_coursecategories { Line 15587  sub modify_coursecategories {
                     }                      }
                     $resulttext .= '</ul></li>';                      $resulttext .= '</ul></li>';
                 }                  }
                 &Apache::lonnet::do_cache_new('cats',$dom,$cathash,3600);  
                 if (ref($lastactref) eq 'HASH') {  
                     $lastactref->{'cats'} = 1;  
                 }  
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
             if ($changes{'unauth'} || $changes{'auth'}) {              if ($changes{'unauth'} || $changes{'auth'}) {
Line 13830  sub modify_coursedefaults { Line 16066  sub modify_coursedefaults {
     my ($dom,$lastactref,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,$errors,%changes,%defaultshash);      my ($resulttext,$errors,%changes,%defaultshash);
     my %defaultchecked = (      my %defaultchecked = (
                              'canuse_pdfforms' => 'off',
                            'uselcmath'       => 'on',                             'uselcmath'       => 'on',
                            'usejsme'         => 'on'                             'usejsme'         => 'on'
                          );                           );
     my @toggles = ('uselcmath','usejsme');      my @toggles = ('canuse_pdfforms','uselcmath','usejsme');
     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','uploadquota_placement',
                    'mysqltables_unofficial','mysqltables_community','mysqltables_textbook');                     'mysqltables_official','mysqltables_unofficial','mysqltables_community',
     my @types = ('official','unofficial','community','textbook');                     'mysqltables_textbook','mysqltables_placement');
       my @types = ('official','unofficial','community','textbook','placement');
     my %staticdefaults = (      my %staticdefaults = (
                            anonsurvey_threshold => 10,                             anonsurvey_threshold => 10,
                            uploadquota          => 500,                             uploadquota          => 500,
Line 13895  sub modify_coursedefaults { Line 16133  sub modify_coursedefaults {
                 $defaultshash{'coursedefaults'}{$setting}{$type} = $newdef;                  $defaultshash{'coursedefaults'}{$setting}{$type} = $newdef;
             }              }
             if ($currdef ne $newdef) {              if ($currdef ne $newdef) {
                   my $staticdef;
                 if ($item eq 'anonsurvey_threshold') {                  if ($item eq 'anonsurvey_threshold') {
                     unless (($currdef eq '') && ($newdef == $staticdefaults{$item})) {                      unless (($currdef eq '') && ($newdef == $staticdefaults{$item})) {
                         $changes{$item} = 1;                          $changes{$item} = 1;
Line 13910  sub modify_coursedefaults { Line 16149  sub modify_coursedefaults {
         my $texengine;          my $texengine;
         if ($env{'form.texengine'} =~ /^(MathJax|mimetex|tth)$/) {          if ($env{'form.texengine'} =~ /^(MathJax|mimetex|tth)$/) {
             $texengine = $env{'form.texengine'};              $texengine = $env{'form.texengine'};
             my $currdef = $domconfig{'coursedefaults'}{'texengine'};              if ($defaultshash{'coursedefaults'}{'texengine'} eq '') {
             if ($currdef eq '') {                  unless ($texengine eq 'MathJax') {
                 unless ($texengine eq $Apache::lonnet::deftex) {  
                     $changes{'texengine'} = 1;                      $changes{'texengine'} = 1;
                 }                  }
             } elsif ($currdef ne $texengine) {              } elsif ($defaultshash{'coursedefaults'}{'texengine'} ne $texengine) {
                 $changes{'texengine'} = 1;                  $changes{'texengine'} = 1;
             }              }
         }          }
Line 14040  sub modify_coursedefaults { Line 16278  sub modify_coursedefaults {
     if ($putresult eq 'ok') {      if ($putresult eq 'ok') {
         if (keys(%changes) > 0) {          if (keys(%changes) > 0) {
             my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);              my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
             if (($changes{'uploadquota'}) || ($changes{'postsubmit'}) ||              if (($changes{'canuse_pdfforms'}) || ($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'})) {
                 foreach my $item ('uselcmath','usejsme','texengine') {                  foreach my $item ('canuse_pdfforms','uselcmath','usejsme','texengine') {
                     if ($changes{$item}) {                      if ($changes{$item}) {
                         $domdefaults{$item}=$defaultshash{'coursedefaults'}{$item};                          $domdefaults{$item}=$defaultshash{'coursedefaults'}{$item};
                     }                      }
Line 14094  sub modify_coursedefaults { Line 16332  sub modify_coursedefaults {
             }              }
             $resulttext = &mt('Changes made:').'<ul>';              $resulttext = &mt('Changes made:').'<ul>';
             foreach my $item (sort(keys(%changes))) {              foreach my $item (sort(keys(%changes))) {
                 if ($item eq 'uselcmath') {                  if ($item eq 'canuse_pdfforms') {
                       if ($env{'form.'.$item} eq '1') {
                           $resulttext .= '<li>'.&mt("Course/Community users can create/upload PDF forms set to 'on'").'</li>';
                       } else {
                           $resulttext .= '<li>'.&mt('Course/Community users can create/upload PDF forms set to "off"').'</li>';
                       }
                   } elsif ($item eq 'uselcmath') {
                     if ($env{'form.'.$item} eq '1') {                      if ($env{'form.'.$item} eq '1') {
                         $resulttext .= '<li>'.&mt('Math preview uses LON-CAPA previewer (javascript), if supported by browser.').'</li>';                          $resulttext .= '<li>'.&mt('Math preview uses LON-CAPA previewer (javascript), if supported by browser.').'</li>';
                     } else {                      } else {
Line 14119  sub modify_coursedefaults { Line 16363  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('Placement tests: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'placement'}.'</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 14132  sub modify_coursedefaults { Line 16376  sub modify_coursedefaults {
                                        '<li>'.&mt('Official courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'official'}.'</b>').'</li>'.                                         '<li>'.&mt('Official courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'official'}.'</b>').'</li>'.
                                        '<li>'.&mt('Unofficial courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'unofficial'}.'</b>').'</li>'.                                         '<li>'.&mt('Unofficial courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'unofficial'}.'</b>').'</li>'.
                                        '<li>'.&mt('Textbook courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'textbook'}.'</b>').'</li>'.                                         '<li>'.&mt('Textbook courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'textbook'}.'</b>').'</li>'.
                                          '<li>'.&mt('Placement tests: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'placement'}.'</b>').'</li>'.
                                        '<li>'.&mt('Communities: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'community'}.'</b>').'</li>'.                                         '<li>'.&mt('Communities: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'community'}.'</b>').'</li>'.
                                        '</ul>'.                                         '</ul>'.
                                        '</li>';                                         '</li>';
Line 14167  sub modify_coursedefaults { Line 16412  sub modify_coursedefaults {
                                     $resulttext .= &mt('Unofficial courses');                                      $resulttext .= &mt('Unofficial courses');
                                 } elsif ($type eq 'textbook') {                                  } elsif ($type eq 'textbook') {
                                     $resulttext .= &mt('Textbook courses');                                      $resulttext .= &mt('Textbook courses');
                                   } elsif ($type eq 'placement') {
                                       $resulttext .= &mt('Placement tests');
                                 }                                  }
                                 $resulttext .= ' -- '.$display.'</li>';                                  $resulttext .= ' -- '.$display.'</li>';
                             }                              }
Line 14218  sub modify_coursedefaults { Line 16465  sub modify_coursedefaults {
 sub modify_selfenrollment {  sub modify_selfenrollment {
     my ($dom,$lastactref,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,$errors,%changes,%selfenrollhash,%ordered);      my ($resulttext,$errors,%changes,%selfenrollhash,%ordered);
     my @types = ('official','unofficial','community','textbook');      my @types = ('official','unofficial','community','textbook','placement');
     my %titles = &tool_titles();      my %titles = &tool_titles();
     my %descs = &Apache::lonuserutils::selfenroll_default_descs();      my %descs = &Apache::lonuserutils::selfenroll_default_descs();
     ($ordered{'admin'},my $titlesref) = &Apache::lonuserutils::get_selfenroll_titles();      ($ordered{'admin'},my $titlesref) = &Apache::lonuserutils::get_selfenroll_titles();
Line 14465  sub modify_usersessions { Line 16712  sub modify_usersessions {
                 );                  );
     my @prefixes = ('remote','hosted','spares');      my @prefixes = ('remote','hosted','spares');
     my @lcversions = &Apache::lonnet::all_loncaparevs();      my @lcversions = &Apache::lonnet::all_loncaparevs();
     my (%by_ip,%by_location,@intdoms);      my (%by_ip,%by_location,@intdoms,@instdoms);
     &build_location_hashes(\@intdoms,\%by_ip,\%by_location);      &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
     my @locations = sort(keys(%by_location));      my @locations = sort(keys(%by_location));
     my (%defaultshash,%changes);      my (%defaultshash,%changes);
     foreach my $prefix (@prefixes) {      foreach my $prefix (@prefixes) {
Line 14723  sub modify_usersessions { Line 16970  sub modify_usersessions {
                         } else {                          } else {
                             foreach my $type (@{$types{$prefix}}) {                              foreach my $type (@{$types{$prefix}}) {
                                 if (defined($changes{$prefix}{$type})) {                                  if (defined($changes{$prefix}{$type})) {
                                     my $newvalue;                                      my ($newvalue,$notinuse);
                                     if (ref($defaultshash{'usersessions'}) eq 'HASH') {                                      if (ref($defaultshash{'usersessions'}) eq 'HASH') {
                                         if (ref($defaultshash{'usersessions'}{$prefix})) {                                          if (ref($defaultshash{'usersessions'}{$prefix})) {
                                             if ($type eq 'version') {                                              if ($type eq 'version') {
                                                 $newvalue = $defaultshash{'usersessions'}{$prefix}{$type};                                                  $newvalue = $defaultshash{'usersessions'}{$prefix}{$type};
                                             } elsif (ref($defaultshash{'usersessions'}{$prefix}{$type}) eq 'ARRAY') {                                              } else {
                                                 if (@{$defaultshash{'usersessions'}{$prefix}{$type}} > 0) {                                                  if (ref($defaultshash{'usersessions'}{$prefix}{$type}) eq 'ARRAY') {
                                                     $newvalue = join(', ',@{$defaultshash{'usersessions'}{$prefix}{$type}});                                                      if (@{$defaultshash{'usersessions'}{$prefix}{$type}} > 0) {
                                                           $newvalue = join(', ',@{$defaultshash{'usersessions'}{$prefix}{$type}});
                                                       }
                                                   } else {
                                                       $notinuse = 1;
                                                 }                                                  }
                                             }                                              }
                                         }                                          }
Line 14738  sub modify_usersessions { Line 16989  sub modify_usersessions {
                                     if ($newvalue eq '') {                                      if ($newvalue eq '') {
                                         if ($type eq 'version') {                                          if ($type eq 'version') {
                                             $resulttext .= '<li>'.&mt('[_1] set to: off',$lt{$type}).'</li>';                                              $resulttext .= '<li>'.&mt('[_1] set to: off',$lt{$type}).'</li>';
                                           } elsif ($notinuse) {
                                               $resulttext .= '<li>'.&mt('[_1] set to: not in use',$lt{$type}).'</li>';
                                         } else {                                          } else {
                                             $resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>';                                              $resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>';
                                         }                                          }
                                     } 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 14782  sub modify_usersessions { Line 17035  sub modify_usersessions {
     return $resulttext;      return $resulttext;
 }  }
   
   sub modify_ssl {
       my ($dom,$lastactref,%domconfig) = @_;
       my (%by_ip,%by_location,@intdoms,@instdoms);
       &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
       my @locations = sort(keys(%by_location));
       my %servers = &Apache::lonnet::internet_dom_servers($dom);
       my (%defaultshash,%changes);
       my $action = 'ssl';
       my @prefixes = ('connto','connfrom','replication');
       foreach my $prefix (@prefixes) {
           $defaultshash{$action}{$prefix} = {};
       }
       my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
       my $resulttext;
       my %iphost = &Apache::lonnet::get_iphost();
       my @reptypes = ('certreq','nocertreq');
       my @connecttypes = ('dom','intdom','other');
       my %types = (
                     connto      => \@connecttypes,
                     connfrom    => \@connecttypes,
                     replication => \@reptypes,
                   );
       foreach my $prefix (sort(keys(%types))) {
           foreach my $type (@{$types{$prefix}}) {
               if (($prefix eq 'connto') || ($prefix eq 'connfrom')) {
                   my $value = 'yes';
                   if ($env{'form.'.$prefix.'_'.$type} =~ /^(no|req)$/) {
                       $value = $env{'form.'.$prefix.'_'.$type};
                   }
                   if (ref($domconfig{$action}) eq 'HASH') {
                       if (ref($domconfig{$action}{$prefix}) eq 'HASH') {
                           if ($domconfig{$action}{$prefix}{$type} ne '') {
                               if ($value ne $domconfig{$action}{$prefix}{$type}) {
                                   $changes{$prefix}{$type} = 1;
                               }
                               $defaultshash{$action}{$prefix}{$type} = $value;
                           } else {
                               $defaultshash{$action}{$prefix}{$type} = $value;
                               $changes{$prefix}{$type} = 1;
                           }
                       } else {
                           $defaultshash{$action}{$prefix}{$type} = $value;
                           $changes{$prefix}{$type} = 1;
                       }
                   } else {
                       $defaultshash{$action}{$prefix}{$type} = $value;
                       $changes{$prefix}{$type} = 1;
                   }
                   if (($type eq 'dom') && (keys(%servers) == 1)) {
                       delete($changes{$prefix}{$type});
                   } elsif (($type eq 'intdom') && (@instdoms == 1)) {
                       delete($changes{$prefix}{$type});
                   } elsif (($type eq 'other') && (keys(%by_location) == 0)) { 
                       delete($changes{$prefix}{$type});
                   }
               } elsif ($prefix eq 'replication') {
                   if (@locations > 0) {
                       my $inuse = $env{'form.'.$prefix.'_'.$type.'_inuse'};
                       my @vals = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$type);
                       my @okvals;
                       foreach my $val (@vals) {
                           if ($val =~ /:/) {
                               my @items = split(/:/,$val);
                               foreach my $item (@items) {
                                   if (ref($by_location{$item}) eq 'ARRAY') {
                                       push(@okvals,$item);
                                   }
                               }
                           } else {
                               if (ref($by_location{$val}) eq 'ARRAY') {
                                   push(@okvals,$val);
                               }
                           }
                       }
                       @okvals = sort(@okvals);
                       if (ref($domconfig{$action}) eq 'HASH') {
                           if (ref($domconfig{$action}{$prefix}) eq 'HASH') {
                               if (ref($domconfig{$action}{$prefix}{$type}) eq 'ARRAY') {
                                   if ($inuse == 0) {
                                       $changes{$prefix}{$type} = 1;
                                   } else {
                                       $defaultshash{$action}{$prefix}{$type} = \@okvals;
                                       my @changed = &Apache::loncommon::compare_arrays($domconfig{$action}{$prefix}{$type},$defaultshash{$action}{$prefix}{$type});
                                       if (@changed > 0) {
                                           $changes{$prefix}{$type} = 1;
                                       }
                                   }
                               } else {
                                   if ($inuse == 1) {
                                       $defaultshash{$action}{$prefix}{$type} = \@okvals;
                                       $changes{$prefix}{$type} = 1;
                                   }
                               }
                           } else {
                               if ($inuse == 1) {
                                   $defaultshash{$action}{$prefix}{$type} = \@okvals;
                                   $changes{$prefix}{$type} = 1;
                               }
                           }
                       } else {
                           if ($inuse == 1) {
                               $defaultshash{$action}{$prefix}{$type} = \@okvals;
                               $changes{$prefix}{$type} = 1;
                           }
                       }
                   }
               }
           }
       }
       if (keys(%changes)) {
           foreach my $prefix (keys(%changes)) {
               if (ref($changes{$prefix}) eq 'HASH') {
                   if (scalar(keys(%{$changes{$prefix}})) == 0) {
                       delete($changes{$prefix});
                   }
               } else {
                   delete($changes{$prefix});
               }
           }
       }
       my $nochgmsg = &mt('No changes made to LON-CAPA SSL settings');
       if (keys(%changes) > 0) {
           my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
                                                    $dom);
           if ($putresult eq 'ok') {
               if (ref($defaultshash{$action}) eq 'HASH') {
                   if (ref($defaultshash{$action}{'replication'}) eq 'HASH') {
                       $domdefaults{'replication'} = $defaultshash{$action}{'replication'};
                   }
                   if (ref($defaultshash{$action}{'connto'}) eq 'HASH') {
                       $domdefaults{'connto'} = $defaultshash{$action}{'connto'};
                   }
                   if (ref($defaultshash{$action}{'connfrom'}) eq 'HASH') {
                       $domdefaults{'connfrom'} = $defaultshash{$action}{'connfrom'};
                   }
               }
               my $cachetime = 24*60*60;
               &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'domdefaults'} = 1;
               }
               if (keys(%changes) > 0) {
                   my %titles = &ssl_titles();
                   $resulttext = &mt('Changes made:').'<ul>';
                   foreach my $prefix (@prefixes) {
                       if (ref($changes{$prefix}) eq 'HASH') {
                           $resulttext .= '<li>'.$titles{$prefix}.'<ul>';
                           foreach my $type (@{$types{$prefix}}) {
                               if (defined($changes{$prefix}{$type})) {
                                   my ($newvalue,$notinuse);
                                   if (ref($defaultshash{$action}) eq 'HASH') {
                                       if (ref($defaultshash{$action}{$prefix})) {
                                           if (($prefix eq 'connto') || ($prefix eq 'connfrom')) {
                                               $newvalue = $titles{$defaultshash{$action}{$prefix}{$type}};
                                           } else {
                                               if (ref($defaultshash{$action}{$prefix}{$type}) eq 'ARRAY') {
                                                   if (@{$defaultshash{$action}{$prefix}{$type}} > 0) {
                                                       $newvalue = join(', ',@{$defaultshash{$action}{$prefix}{$type}});
                                                   }
                                               } else {
                                                   $notinuse = 1;
                                               }
                                           }
                                       }
                                       if ($notinuse) {
                                           $resulttext .= '<li>'.&mt('[_1] set to: not in use',$titles{$type}).'</li>';
                                       } elsif ($newvalue eq '') {
                                           $resulttext .= '<li>'.&mt('[_1] set to: none',$titles{$type}).'</li>';
                                       } else {
                                           $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$titles{$type},$newvalue).'</li>';
                                       }
                                   }
                               }
                           }
                           $resulttext .= '</ul>';
                       }
                   }
               } else {
                   $resulttext = $nochgmsg;
               }
           } else {
               $resulttext = '<span class="LC_error">'.
                             &mt('An error occurred: [_1]',$putresult).'</span>';
           }
       } else {
           $resulttext = $nochgmsg;
       }
       return $resulttext;
   }
   
   sub modify_trust {
       my ($dom,$lastactref,%domconfig) = @_;
       my (%by_ip,%by_location,@intdoms,@instdoms);
       &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
       my @locations = sort(keys(%by_location));
       my @prefixes = qw(content shared enroll othcoau coaurem domroles catalog reqcrs msg);
       my @types = ('exc','inc');
       my (%defaultshash,%changes);
       foreach my $prefix (@prefixes) {
           $defaultshash{'trust'}{$prefix} = {};
       }
       my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
       my $resulttext;
       foreach my $prefix (@prefixes) {
           foreach my $type (@types) {
               my $inuse = $env{'form.'.$prefix.'_'.$type.'_inuse'};
               my @vals = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$type);
               my @okvals;
               foreach my $val (@vals) {
                   if ($val =~ /:/) {
                       my @items = split(/:/,$val);
                       foreach my $item (@items) {
                           if (ref($by_location{$item}) eq 'ARRAY') {
                               push(@okvals,$item);
                           }
                       }
                   } else {
                       if (ref($by_location{$val}) eq 'ARRAY') {
                           push(@okvals,$val);
                       }
                   }
               }
               @okvals = sort(@okvals);
               if (ref($domconfig{'trust'}) eq 'HASH') {
                   if (ref($domconfig{'trust'}{$prefix}) eq 'HASH') {
                       if (ref($domconfig{'trust'}{$prefix}{$type}) eq 'ARRAY') {
                           if ($inuse == 0) {
                               $changes{$prefix}{$type} = 1;
                           } else {
                               $defaultshash{'trust'}{$prefix}{$type} = \@okvals;
                               my @changed = &Apache::loncommon::compare_arrays($domconfig{'trust'}{$prefix}{$type},$defaultshash{'trust'}{$prefix}{$type});
                               if (@changed > 0) {
                                   $changes{$prefix}{$type} = 1;
                               }
                           }
                       } else {
                           if ($inuse == 1) {
                               $defaultshash{'trust'}{$prefix}{$type} = \@okvals;
                               $changes{$prefix}{$type} = 1;
                           }
                       }
                   } else {
                       if ($inuse == 1) {
                           $defaultshash{'trust'}{$prefix}{$type} = \@okvals;
                           $changes{$prefix}{$type} = 1;
                       }
                   }
               } else {
                   if ($inuse == 1) {
                       $defaultshash{'trust'}{$prefix}{$type} = \@okvals;
                       $changes{$prefix}{$type} = 1;
                   }
               }
           }
       }
       my $nochgmsg = &mt('No changes made to trust settings.');
       if (keys(%changes) > 0) {
           my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
                                                    $dom);
           if ($putresult eq 'ok') {
               if (ref($defaultshash{'trust'}) eq 'HASH') {
                   foreach my $prefix (@prefixes) {
                       if (ref($defaultshash{'trust'}{$prefix}) eq 'HASH') {
                           $domdefaults{'trust'.$prefix} = $defaultshash{'trust'}{$prefix};
                       }
                   }
               }
               my $cachetime = 24*60*60;
               &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'domdefaults'} = 1;
               }
               if (keys(%changes) > 0) {
                   my %lt = &trust_titles();
                   $resulttext = &mt('Changes made:').'<ul>';
                   foreach my $prefix (@prefixes) {
                       if (ref($changes{$prefix}) eq 'HASH') {
                           $resulttext .= '<li>'.$lt{$prefix}.'<ul>';
                           foreach my $type (@types) {
                               if (defined($changes{$prefix}{$type})) {
                                   my ($newvalue,$notinuse);
                                   if (ref($defaultshash{'trust'}) eq 'HASH') {
                                       if (ref($defaultshash{'trust'}{$prefix})) {
                                           if (ref($defaultshash{'trust'}{$prefix}{$type}) eq 'ARRAY') {
                                               if (@{$defaultshash{'trust'}{$prefix}{$type}} > 0) {
                                                   $newvalue = join(', ',@{$defaultshash{'trust'}{$prefix}{$type}});
                                               }
                                           } else {
                                               $notinuse = 1;
                                           }
                                       }
                                   }
                                   if ($notinuse) {
                                       $resulttext .= '<li>'.&mt('[_1] set to: not in use',$lt{$type}).'</li>';
                                   } elsif ($newvalue eq '') {
                                       $resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>';
                                   } else {
                                       $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>';
                                   }
                               }
                           }
                           $resulttext .= '</ul>';
                       }
                   }
                   $resulttext .= '</ul>';
               } else {
                   $resulttext = $nochgmsg;
               }
           } else {
               $resulttext = '<span class="LC_error">'.
                             &mt('An error occurred: [_1]',$putresult).'</span>';
           }
       } else {
           $resulttext = $nochgmsg;
       }
       return $resulttext;
   }
   
 sub modify_loadbalancing {  sub modify_loadbalancing {
     my ($dom,%domconfig) = @_;      my ($dom,%domconfig) = @_;
     my $primary_id = &Apache::lonnet::domain($dom,'primary');      my $primary_id = &Apache::lonnet::domain($dom,'primary');
Line 14852  sub modify_loadbalancing { Line 17423  sub modify_loadbalancing {
         }          }
         if ($env{'form.loadbalancing_cookie_'.$i}) {          if ($env{'form.loadbalancing_cookie_'.$i}) {
             $defaultshash{'loadbalancing'}{$balancer}{'cookie'} = 1;              $defaultshash{'loadbalancing'}{$balancer}{'cookie'} = 1;
             if (exists($currbalancer{$balancer})) {              if (exists($currbalancer{$balancer})) { 
                 unless ($currcookies{$balancer}) {                  unless ($currcookies{$balancer}) {
                     $changes{'curr'}{$balancer}{'cookie'} = 1;                      $changes{'curr'}{$balancer}{'cookie'} = 1;
                 }                  }
Line 15017  sub modify_loadbalancing { Line 17588  sub modify_loadbalancing {
                         }                          }
                         if ($changes{'curr'}{$balancer}{'cookie'}) {                          if ($changes{'curr'}{$balancer}{'cookie'}) {
                             $resulttext .= '<li>'.&mt('Load Balancer: [_1] -- cookie use enabled',                              $resulttext .= '<li>'.&mt('Load Balancer: [_1] -- cookie use enabled',
                                                       $balancer).'</li>';                                                        $balancer).'</li>'; 
                         }                          }
                         if (keys(%toupdate)) {                          if (keys(%toupdate)) {
                             my %thismachine;                              my %thismachine;
Line 15795  sub devalidate_remote_domconfs { Line 18366  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','usersessions',      my @posscached = ('domainconfig','domdefaults','ltitools','usersessions','directorysrch');
                       'directorysrch','passwdconf','cats');  
     if (keys(%servers)) {      if (keys(%servers)) {
         foreach my $server (keys(%servers)) {          foreach my $server (keys(%servers)) {
             next if ($thismachine{$server});              next if ($thismachine{$server});

Removed from v.1.160.6.104  
changed lines
  Added in v.1.347


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