Diff for /loncom/interface/lonuserutils.pm between versions 1.169 and 1.213

version 1.169, 2014/12/15 01:11:49 version 1.213, 2022/12/01 01:28:26
Line 30 Line 30
   
 package Apache::lonuserutils;  package Apache::lonuserutils;
   
   =pod
   
   =head1 NAME
   
   Apache::lonuserutils.pm
   
   =head1 SYNOPSIS
   
       Utilities for management of users and custom roles
   
       Provides subroutines called by loncreateuser.pm
   
   =head1 OVERVIEW
   
   =cut
   
 use strict;  use strict;
 use Apache::lonnet;  use Apache::lonnet;
 use Apache::loncommon();  use Apache::loncommon();
 use Apache::lonhtmlcommon;  use Apache::lonhtmlcommon;
   use Apache::loncoursequeueadmin;
 use Apache::lonlocal;  use Apache::lonlocal;
 use Apache::longroup;  use Apache::longroup;
   use HTML::Entities;
 use LONCAPA qw(:DEFAULT :match);  use LONCAPA qw(:DEFAULT :match);
   
 ###############################################################  ###############################################################
Line 136  sub modifyuserrole { Line 154  sub modifyuserrole {
     return ($userresult,$authresult,$roleresult,$idresult);      return ($userresult,$authresult,$roleresult,$idresult);
 }  }
   
   sub role_approval {
       my ($dom,$context,$process_by,$notifydc) = @_;
       if (ref($process_by) eq 'HASH') {
           my %domconfig = &Apache::lonnet::get_dom('configuration',['privacy'],$dom);
           if (ref($domconfig{'privacy'}) eq 'HASH') {
               if (ref($notifydc) eq 'ARRAY') {
                   if ($domconfig{'privacy'}{'notify'} ne '') {
                       @{$notifydc} = split(/,/,$domconfig{'privacy'}{'notify'});
                   }
               }
               if (ref($domconfig{'privacy'}{'approval'}) eq 'HASH') {
                   my %approvalconf = %{$domconfig{'privacy'}{'approval'}};
                   foreach my $key ('instdom','extdom') {
                       if (ref($approvalconf{$key}) eq 'HASH') {
                           if (keys(%{$approvalconf{$key}})) {
                               $process_by->{$key} = $approvalconf{$key}{$context};
                           }
                       }
                   }
               }
           }
       }
       return;
   }
   
   sub get_instdoms {
       my ($udom,$instdoms) = @_;
       return unless (ref($instdoms) eq 'ARRAY');
       my @intdoms;
       my %iphost = &Apache::lonnet::get_iphost();
       my $primary_id = &Apache::lonnet::domain($udom,'primary');
       my $primary_ip = &Apache::lonnet::get_host_ip($primary_id);
       if (ref($iphost{$primary_ip}) eq 'ARRAY') {
           foreach my $id (@{$iphost{$primary_ip}}) {
               my $intdom = &Apache::lonnet::internet_dom($id);
               unless(grep(/^\Q$intdom\E$/,@intdoms)) {
                   push(@intdoms,$intdom);
               }
           }
       }
       foreach my $ip (keys(%iphost)) {
           if (ref($iphost{$ip}) eq 'ARRAY') {
               foreach my $id (@{$iphost{$ip}}) {
                   my $location = &Apache::lonnet::internet_dom($id);
                   if ($location) {
                       if (grep(/^\Q$location\E$/,@intdoms)) {
                           my $dom = &Apache::lonnet::host_domain($id);
                           unless (grep(/^\Q$dom\E/,@{$instdoms})) {
                               push(@{$instdoms},$dom);
                           }
                       }
                   }
               }
           }
       }
       return;
   }
   
   sub restricted_dom {
       my ($context,$key,$udom,$uname,$role,$start,$end,$cdom,$cnum,$csec,$credits,
           $process_by,$instdoms,$got_role_approvals,$got_instdoms,$reject,$pending,
           $notifydc,$status,$unauthorized,$currqueued) = @_;
       return if ($udom eq $cdom);
       return unless ((ref($process_by) eq 'HASH') && (ref($instdoms) eq 'HASH') &&
                      (ref($got_role_approvals) eq 'HASH') && (ref($got_instdoms) eq 'HASH') &&
                      (ref($reject) eq 'HASH') && (ref($pending) eq 'HASH') &&
                      (ref($notifydc) eq 'HASH') && (ref($status) eq 'HASH') &&
                      (ref($unauthorized) eq 'HASH') && (ref($currqueued) eq 'HASH'));
       my (%approval,@notify,$gotdata,$skip);
       if (ref($got_role_approvals->{$context}) eq 'HASH') {
           if ($got_role_approvals->{$context}{$udom}) {
               $gotdata = 1;
               if (ref($process_by->{$context}{$udom}) eq 'HASH') {
                   %approval = %{$process_by->{$context}{$udom}};
               }
           }
       }
       unless ($gotdata) {
           &role_approval($udom,$context,\%approval,\@notify);
           $process_by->{$context} = {
                                       $udom => \%approval,
                                     };
           $got_role_approvals->{$context} = {
                                               $udom => 1,
                                             };
           $notifydc->{$udom} = \@notify;
       }
       if (ref($process_by->{$context}) eq 'HASH') {
           if (ref($process_by->{$context}{$udom}) eq 'HASH') {
               my @inst;
               if ($got_instdoms->{$udom}) {
                   if (ref($instdoms->{$udom}) eq 'ARRAY') {
                       @inst = @{$instdoms->{$udom}};
                   }
               } else {
                   &get_instdoms(\@inst);
                   $instdoms->{$udom} = \@inst;
                   $got_instdoms->{$udom} = 1;
               }
               if (grep(/^\Q$cdom\E$/,@inst)) {
                   if (exists($approval{'instdom'})) {
                       my $rule = $approval{'instdom'};
                       if (($rule eq 'none') || ($rule eq 'user') || ($rule eq 'domain')) {
                           my ($id,$currstatus,$curradj) = &get_othdomreq_status($key,$uname,$udom,$role,$cdom,$cnum,$csec);
                           if (($currstatus ne '') && ($curradj eq $rule)) {
                               $status->{$key}->{$uname.':'.$udom} = $currstatus;
                           }
                           if ($rule eq 'none') {
                                $reject->{$key}->{$uname.':'.$udom} = {
                                                                        cdom  => $cdom,
                                                                        cnum  => $cnum,
                                                                        csec  => $csec,
                                                                        udom  => $udom,
                                                                        uname => $uname,
                                                                        role  => $role,
                                                                      };
                               $skip = 1;
                           } elsif (($rule eq 'user') || ($rule eq 'domain')) {
                               if ($curradj eq $rule) {
                                   unless ($currstatus eq 'approved') {
                                       if ($currstatus eq 'rejected') {
                                           $unauthorized->{$key}->{$uname.':'.$udom} = {
                                                                                         cdom  => $cdom,
                                                                                         cnum  => $cnum,
                                                                                         csec  => $csec,
                                                                                         udom  => $udom,
                                                                                         uname => $uname,
                                                                                         role  => $role,
                                                                                       };
                                       } elsif ($currstatus eq 'pending') {
                                           $currqueued->{$key}->{$uname.':'.$udom} = {
                                                                                       cdom  => $cdom,
                                                                                       cnum  => $cnum,
                                                                                       csec  => $csec,
                                                                                       udom  => $udom,
                                                                                       uname => $uname,
                                                                                       role  => $role,
                                                                                       adj   => $rule,
                                                                          };
                                       }
                                       $skip = 1;
                                   }
                               } else {
                                   $pending->{$key}->{$uname.':'.$udom} = {
                                                                            cdom  => $cdom,
                                                                            cnum  => $cnum,
                                                                            csec  => $csec,
                                                                            udom  => $udom,
                                                                            uname => $uname,
                                                                            role  => $role,
                                                                            start => $start,
                                                                            end   => $end,
                                                                            adj   => $rule,
                                                                          };
                                   if (($role eq 'st') && ($credits ne '')) {
                                       $pending->{$key}->{$uname.':'.$udom}->{'credits'} = $credits;
                                   }
                                   $skip = 1;
                               }
                           }
                       }
                   }
               } elsif (exists($approval{'extdom'})) {
                   my $rule = $approval{'extdom'};
                   if (($rule eq 'none') || ($rule eq 'user') || ($rule eq 'domain')) {
                       my ($id,$currstatus,$curradj) = &get_othdomreq_status($key,$uname,$udom,$role,$cdom,$cnum,$csec);
                       if (($currstatus ne '') && ($curradj eq $rule)) {
                           $status->{$key}->{$uname.':'.$udom} = $currstatus;
                       }
                       if ($rule eq 'none') {
                           $reject->{$key}->{$uname.':'.$udom} = {
                                                                   cdom  => $cdom,
                                                                   cnum  => $cnum,
                                                                   csec  => $csec,
                                                                   udom  => $udom,
                                                                   uname => $uname,
                                                                   role  => $role,
                                                                 };
                           $skip = 1;
                       } elsif (($rule eq 'user') || ($rule eq 'domain')) {
                           if ($curradj eq $rule) {
                               unless ($currstatus eq 'approved') {
                                   if ($currstatus eq 'rejected') {
                                       $unauthorized->{$key}->{$uname.':'.$udom} = {
                                                                                     cdom  => $cdom,
                                                                                     cnum  => $cnum,
                                                                                     csec  => $csec,
                                                                                     udom  => $udom,
                                                                                     uname => $uname,
                                                                                     role  => $role,
                                                                                   };
                                   } elsif ($currstatus eq 'pending') {
                                       $currqueued->{$key}->{$uname.':'.$udom} = {
                                                                                   cdom  => $cdom,
                                                                                   cnum  => $cnum,
                                                                                   csec  => $csec,
                                                                                   udom  => $udom,
                                                                                   uname => $uname,
                                                                                   role  => $role,
                                                                                   adj   => $rule,
                                                                          };
                                   }
                                   $skip = 1;
                               }
                           } else {
                               $pending->{$key}->{$uname.':'.$udom} = {
                                                                        cdom  => $cdom,
                                                                        cnum  => $cnum,
                                                                        csec  => $csec,
                                                                        udom  => $udom,
                                                                        uname => $uname,
                                                                        role  => $role,
                                                                        start => $start,
                                                                        end   => $end,
                                                                        adj   => $rule,
                                                                      };
                               if (($role eq 'st') && ($credits ne '')) {
                                   $pending->{$key}->{$uname.':'.$udom}->{'credits'} = $credits;
                               }
                               $skip = 1;
                           }
                       }
                   }
               }
           }
       }
       return $skip;
   }
   
   sub get_othdomreq_status {
       my ($key,$uname,$udom,$role,$cdom,$cnum,$csec) = @_;
       my $id = $uname.':'.$udom.':'.$role; 
       my ($dbnum,$currstatus,$curradj);
       if (($role eq 'ca') || ($role eq 'aa')) {
           $dbnum = $cnum;
       } elsif ($key eq $cdom.'_'.$role) {
           $dbnum = &Apache::lonnet::get_domainconfiguser($cdom);
       } else {
           $id .= ':'.$csec;
           $dbnum = $cnum;
       }
       my $statusid = 'status&'.$id;
       my %curr = &Apache::lonnet::get('nohist_othdomqueued',[$id,$statusid],$cdom,$dbnum);
       if (ref($curr{$id}) eq 'HASH') {
           $curradj = $curr{$id}{'adj'};
       }
       $currstatus = $curr{$statusid};
       return ($id,$currstatus,$curradj);
   }
   
   sub print_roles_rejected {
       my ($context,$reject,$unauthorized) = @_;
       return unless ((ref($reject) eq 'HASH') || (ref($unauthorized) eq 'HASH'));
       my $output;
       if (keys(%{$reject}) > 0) {
           $output = '<p class="LC_warning">'.
                     &mt("The following roles could not be assigned because the user is from another domain, and that domain's policies disallow it").'<ul>';
           foreach my $key (sort(keys(%{$reject}))) {
               if (ref($reject->{$key}) eq 'HASH') {
                   foreach my $user (sort(keys(%{$reject->{$key}}))) {
                       if (ref($reject->{$key}->{$user}) eq 'HASH') {
                           my ($crstype,$role,$cdom,$cnum,$csec,$title,$plainrole);
                           $role = $reject->{$key}->{$user}{'role'};
                           $cdom = $reject->{$key}->{$user}{'cdom'};
                           $cnum = $reject->{$key}->{$user}{'cnum'};
                           $csec = $reject->{$key}->{$user}{'csec'};
                           if (($context eq 'domain') && ($cnum ne '')) {
                               if (($role eq 'ca') || ($role eq 'aa')) {
                                   $title = &Apache::loncommon::plainname($cnum,$cdom);
                               } else {
                                   if (&Apache::lonnet::is_course($cdom,$cnum)) {
                                       my %coursedata = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
                                       $crstype = $coursedata{'type'};
                                       $title = $coursedata{'description'};
                                   }
                               }
                           } elsif ($context eq 'course') {
                               $crstype = &Apache::loncommon::course_type();
                           }
                           my $plainrole = &Apache::lonnet::plaintext($role,$crstype);
                           $output .= '<li>'.&mt('User: [_1]',$reject->{$key}->{$user}{'uname'}).' | '.
                                             &mt('Domain: [_1]',$reject->{$key}->{$user}{'udom'}).' | '.
                                             &mt('Role: [_1]',$plainrole);
                           if ($crstype) {
                               if ($csec ne'') {
                                   $output .= ' | '.&mt('Section: [_1]',$csec);
                               }
                           } elsif (($context eq 'domain') && (($role eq 'ca') || ($role eq 'aa'))) {
                               $output .= ' | '.&mt('Authoring Space belonging to: [_1]',$title);
                                                   
                           }
                           if (($context eq 'domain') && ($crstype)) {
                               $output .= ' | '.&mt("$crstype: [_1]",$title);
                           }
                           $output .= '</li>';
                       }
                   }
               }
           }
           $output .= '</ul></p>';
       }
       if (keys(%{$unauthorized}) > 0) {
           $output = '<p class="LC_warning">'.
                     &mt("The following roles could not be assigned because the user is from another domain, and that domain's policies require approval by the user themselves or by a domain coordinator in that domain, and approval has been withheld.").'<ul>';
           foreach my $key (sort(keys(%{$unauthorized}))) {
               if (ref($unauthorized->{$key}) eq 'HASH') {
                   foreach my $user (sort(keys(%{$unauthorized->{$key}}))) {
                       if (ref($unauthorized->{$key}->{$user}) eq 'HASH') {
                           my ($crstype,$role,$cdom,$cnum,$csec,$title,$plainrole);
                           $role = $unauthorized->{$key}->{$user}{'role'};
                           $cdom = $unauthorized->{$key}->{$user}{'cdom'};
                           $cnum = $unauthorized->{$key}->{$user}{'cnum'};
                           $csec = $unauthorized->{$key}->{$user}{'csec'};
                           if (($context eq 'domain') && ($cnum ne '')) {
                               if (($role eq 'ca') || ($role eq 'aa')) {
                                   $title = &mt('Authoring Space belonging to: [_1]',
                                                &Apache::loncommon::plainname($cnum,$cdom));
                               } else {
                                   if (&Apache::lonnet::is_course($cdom,$cnum)) {
                                       my %coursedata = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
                                       $crstype = $coursedata{'type'};
                                       $title = &mt("$crstype: [_1]",$coursedata{'description'});
                                   }
                               }
                           } elsif ($context eq 'course') {
                               $crstype = &Apache::loncommon::course_type();
                           }
                           $plainrole = &Apache::lonnet::plaintext($role,$crstype);
                           $output .= '<li>'.&mt('User: [_1]',$unauthorized->{$key}->{$user}{'uname'}).' | '.
                                             &mt('Domain: [_1]',$unauthorized->{$key}->{$user}{'udom'}).' | '.
                                             &mt('Role: [_1]',$plainrole);
                           if ($crstype) {
                               if ($csec ne'') {
                                   $output .= ' | '.&mt('Section: [_1]',$csec);
                               }
                           }
                           if ($title ne '') {
                               $output .= ' | '.$title;
                           }
                           $output .= '</li>';
                       }
                   }
               }
           }
           $output .= '</ul></p>'; 
       }
       return $output;
   }
   
   sub print_roles_queued {
       my ($context,$pending,$notifydc,$currqueued) = @_;
       return unless ((ref($pending) eq 'HASH') && (ref($notifydc) eq 'HASH') &&
                      (ref($currqueued) eq 'HASH'));
       my $output;
       if (keys(%{$pending}) > 0) {
           my $now = time;
           $output = '<p class="LC_warning">'.
                     &mt("The following role assignments have been queued because the user is from another domain, and that domain's policies require approval by the user themselves or by a domain coordinator in that domain").'<ul>';
           my (%todom,%touser,%crsqueue,%caqueue,%domqueue);
           my $requester = $env{'user.name'}.':'.$env{'user.domain'};
           foreach my $key (sort(keys(%{$pending}))) {
               if (ref($pending->{$key}) eq 'HASH') {
                   foreach my $user (sort(keys(%{$pending->{$key}}))) {
                       if (ref($pending->{$key}->{$user}) eq 'HASH') {
                           my $role = $pending->{$key}->{$user}{'role'};
                           my $uname = $pending->{$key}->{$user}{'uname'};
                           my $udom = $pending->{$key}->{$user}{'udom'};
                           my $csec = $pending->{$key}->{$user}{'csec'};
                           my $cdom = $pending->{$key}->{$user}{'cdom'};
                           my $cnum = $pending->{$key}->{$user}{'cnum'};
                           my $adj = $pending->{$key}->{$user}{'adj'};
                           my $start = $pending->{$key}->{$user}{'start'};
                           my $end = $pending->{$key}->{$user}{'end'};
                           my $credits = $pending->{$key}->{$user}{'credits'};
                           my $now = time;
                           my ($crstype,$title,$plainrole,$extent,$id,$status);
                           if ($context eq 'course') {
                               $crstype = &Apache::loncommon::course_type();
                               $title = $env{'course.'.$env{'request.course.id'}.'.description'};
                           } elsif ($context eq 'domain') {
                               if (&Apache::lonnet::is_course($cdom,$cnum)) {
                                   my %coursedata = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
                                   $crstype = $coursedata{'type'};
                                   $title = $coursedata{'description'};
                               } elsif (($role eq 'ca') || ($role eq 'aa')) {
                                   $title = &Apache::loncommon::plainname($cnum,$cdom);
                               }
                           }
                           $plainrole = &Apache::lonnet::plaintext($role,$crstype);
                           $extent = "/$cdom/$cnum";
                           $id = $uname.':'.$udom.':'.$role;
                           if (($context eq 'course') || ($crstype)) {
                               $id .= ':'.$csec;
                           }
                           $output .= '<li>'.&mt('User: [_1]',$uname).' | '.
                                             &mt('Domain: [_1]',$udom).' | '.
                                             &mt('Role: [_1]',$plainrole);
                           if ($crstype) {
                               if ($csec ne'') {
                                   $output .= ' | '.&mt('Section: [_1]',$csec);
                               }
                           } elsif (($context eq 'domain') && (($role eq 'ca') || ($role eq 'aa'))) {
                               $output .= ' | '.&mt('Authoring Space belonging to: [_1]',$title);
                           }
                           if (($context eq 'domain') && ($crstype)) {
                               $output .= ' | '.&mt("$crstype: [_1]",$title);
                           }
                           if (($crstype) && ($csec ne '')) {
                               $extent .= "/$csec";
                           }
                           if ($adj eq 'user') {
                               $output .= '<br />'.&mt('Message sent to user for approval');
                               $touser{$uname.':'.$udom}{'pending:'.$extent.':'.$role} = {
                                                                                           timestamp => $now,
                                                                                           requester => $requester,
                                                                                           start     => $start,
                                                                                           end       => $end,
                                                                                           credits   => $credits,
                                                                                           context   => $context,
                                                                                         };
                           } elsif ($adj eq 'domain') {
                               $output .= '<br />'.&mt("Message sent to user's domain coordinator for approval");
                               $todom{$udom}{'pending:'.$uname.':'.$extent.':'.$role} = {
                                                                                          timestamp => $now,
                                                                                          requester => $requester,
                                                                                          start     => $start,
                                                                                          end       => $end,
                                                                                          credits   => $credits,
                                                                                          context   => $context,
                                                                                        };
                           }
                           $output .= '</li>';
                           if (($context eq 'course') || ($crstype)) {
                               $crsqueue{$cdom.'_'.$cnum}{$id} = {
                                                                   timestamp => $now,
                                                                   requester => $requester,
                                                                   adj       => $adj,
                                                                 };
                               $crsqueue{$cdom.'_'.$cnum}{'status&'.$id} = 'pending';
                           } elsif (($context eq 'author') ||
                                    (($context eq 'domain') && (($role eq 'ca') || ($role eq 'aa')))) {
                               $caqueue{$cnum.':'.$cdom}{$id} = {
                                                                  timestamp => $now,
                                                                  requester => $requester,
                                                                  adj       => $adj,
                                                                };
                               $caqueue{$cnum.':'.$cdom}{'status&'.$id} = 'pending';
                           } elsif ($context eq 'domain') {
                               $domqueue{$id} = {
                                                  timestamp => $now,
                                                  requester => $requester,
                                                  adj       => $adj,
                                                };
                               $domqueue{'status&'.$id} = 'pending';
                           }
                       }
                   }
               }
           }
           $output .= '</ul></p>';
           if (keys(%touser)) {
               foreach my $key (keys(%touser)) {
                   my ($uname,$udom) = split(/:/,$touser{$key});
                   if (&Apache::lonnet::put('nohist_queuedrolereqs',$touser{$key},$udom,$uname) eq 'ok') {
                       my $owndomdesc = &Apache::lonnet::domain($udom);
                       &Apache::loncoursequeueadmin::send_selfserve_notification($uname.':'.$udom,
                           '','',$owndomdesc,$now,'othdomroleuser',$requester);
                   }
               }
           }
           if (keys(%todom)) {
               foreach my $dom (keys(%todom)) {
                   if (ref($todom{$dom}) eq 'HASH') {
                       my $confname = &Apache::lonnet::get_domainconfiguser($dom);
                       if (&Apache::lonnet::put('nohist_queuedrolereqs',$todom{$dom},$dom,$confname) eq 'ok') {
                           if (ref($notifydc->{$dom}) eq 'ARRAY') {
                               if (@{$notifydc->{$dom}} > 0) {
                                   my $notifylist = join(',',@{$notifydc->{$dom}});
                                   &Apache::loncoursequeueadmin::send_selfserve_notification($notifylist,
                                       '','','',$now,'othdomroledc',$requester);
                               }
                           }
                       }
                   }
               }
           }
           if (keys(%crsqueue)) {
               foreach my $key (keys(%crsqueue)) {
                   my ($cdom,$cnum) = split(/_/,$key);
                   if (ref($crsqueue{$key}) eq 'HASH') {
                       &Apache::lonnet::put('nohist_othdomqueued',$crsqueue{$key},$cdom,$cnum);
                   }
               }
           }
           if (keys(%caqueue)) {
               foreach my $key (keys(%caqueue)) {
                   my ($auname,$audom) = split(/:/,$key);
                   if (ref($caqueue{$key}) eq 'HASH') {
                       &Apache::lonnet::put('nohist_othdomqueued',$caqueue{$key},$audom,$auname);
                   }
               }
           }
           if (keys(%domqueue)) {
               my $confname = &Apache::lonnet::get_domainconfiguser($env{'request.role.domain'});
               &Apache::lonnet::put('nohist_othdomqueued',\%domqueue,$env{'request.role.domain'},$confname);
           }
       }
       if (keys(%{$currqueued}) > 0) {
           $output = '<p class="LC_warning">'.
                     &mt("The following role assignments were already queued because the user is from another domain, and that domain's policies require approval by the user themselves or by a domain coordinator in that domain").'<ul>';
           my $requester = $env{'user.name'}.':'.$env{'user.domain'};
           foreach my $key (sort(keys(%{$currqueued}))) {
               if (ref($currqueued->{$key}) eq 'HASH') {
                   foreach my $user (sort(keys(%{$currqueued->{$key}}))) {
                       if (ref($currqueued->{$key}->{$user}) eq 'HASH') {
                           my $role = $currqueued->{$key}->{$user}{'role'};
                           my $csec = $currqueued->{$key}->{$user}{'csec'};
                           my $cdom = $currqueued->{$key}->{$user}{'cdom'};
                           my $cnum = $currqueued->{$key}->{$user}{'cnum'};
                           my ($crstype,$title,$plainrole);
                           if ($context eq 'course') {
                               $crstype = &Apache::loncommon::course_type();
                           } elsif (($context eq 'domain') && ($cnum ne '')) {
                               if (($role eq 'ca') || ($role eq 'aa')) {
                                   $title = &mt('Authoring Space belonging to: [_1]',
                                                &Apache::loncommon::plainname($cnum,$cdom));
                               } elsif (&Apache::lonnet::is_course($cdom,$cnum)) {
                                   my %coursedata = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
                                   $crstype = $coursedata{'type'};
                                   $title = &mt("$crstype: [_1]",$coursedata{'description'});
                               }
                           }
                           $plainrole = &Apache::lonnet::plaintext($role,$crstype);
                           $output .= '<li>'.&mt('User: [_1]',$currqueued->{$key}->{$user}{'uname'}).' | '.
                                             &mt('Domain: [_1]',$currqueued->{$key}->{$user}{'udom'}).' | '.
                                             &mt('Role: [_1]',$plainrole);
                           if ($title ne '') {
                               $output .= ' | '.$title;
                           }
                           if ($crstype) {
                               if ($csec ne '') {
                                   $output .= ' | '.&mt('Section: [_1]',$csec);
                               }
                           }
                           $output .= '</li>';
                       }
                   }
               }
           }
           $output .= '</ul></p>';
       }
       return $output;
   }
   
 sub propagate_id_change {  sub propagate_id_change {
     my ($uname,$udom,$user) = @_;      my ($uname,$udom,$user) = @_;
     my (@types,@roles);      my (@types,@roles);
Line 421  sub javascript_validations { Line 993  sub javascript_validations {
             } elsif ($context eq 'domain') {              } elsif ($context eq 'domain') {
                 $setsection_call = 'setCourse()';                  $setsection_call = 'setCourse()';
                 $setsections_js = &dc_setcourse_js($param{'formname'},$mode,                  $setsections_js = &dc_setcourse_js($param{'formname'},$mode,
                                                    $context,$showcredits);                                                     $context,$showcredits,$domain);
             }              }
             $finish = "  var checkSec = $setsection_call\n".              $finish = "  var checkSec = $setsection_call\n".
                       "  if (checkSec == 'ok') {\n".                        "  if (checkSec == 'ok') {\n".
Line 450  sub javascript_validations { Line 1022  sub javascript_validations {
     if (($mode eq 'upload') && ($context eq 'domain')) {      if (($mode eq 'upload') && ($context eq 'domain')) {
         $alert{'inststatus'} = &mt('The optional affiliation field was not specified');           $alert{'inststatus'} = &mt('The optional affiliation field was not specified'); 
     }      }
       &js_escape(\%alert);
     my $function_name = <<"END";      my $function_name = <<"END";
 $setsections_js  $setsections_js
   
Line 513  END Line 1086  END
 /* regexp here to check for non \d \. in credits */  /* regexp here to check for non \d \. in credits */
 END  END
     } else {      } else {
           my ($numrules,$intargjs) =
               &Apache::loncommon::passwd_validation_js('vf.elements[current.argfield].value',$domain);
         $auth_checks .= (<<END);          $auth_checks .= (<<END);
     foundatype=1;      foundatype=1;
     if (current.argfield == null || current.argfield == '') {      if (current.argfield == null || current.argfield == '') {
           // The login radiobutton checked does not have an associated textbox
       } else if (vf.elements[current.argfield].value == '') {
         var alertmsg = '';          var alertmsg = '';
         switch (current.radiovalue) {          switch (current.radiovalue) {
             case 'krb':              case 'krb':
                 alertmsg = '$alert{'krb'}';                  alertmsg = '$alert{'krb'}';
                 break;                  break;
             case 'loc':              case 'int':
             case 'fsys':  
                 alertmsg = '$alert{'ipass'}';                  alertmsg = '$alert{'ipass'}';
                 break;                  break;
             case 'fsys':              case 'fsys':
                   alertmsg = '$alert{'ipass'}';
                   break;
               case 'loc':
                 alertmsg = '';                  alertmsg = '';
                 break;                  break;
               case 'lti':
             default:              default:
                 alertmsg = '';                  alertmsg = '';
         }          }
Line 535  END Line 1115  END
             alert(alertmsg);              alert(alertmsg);
             return;              return;
         }          }
       } else if (current.radiovalue == 'int') {
           if ($numrules > 0) {
   $intargjs
           }
     }      }
 END  END
     }      }
Line 623  END Line 1207  END
                  $section_checks.$authheader;                   $section_checks.$authheader;
     return $result;      return $result;
 }  }
   
 ###############################################################  ###############################################################
 ###############################################################  ###############################################################
 sub upload_manager_javascript_forward_associate {  sub upload_manager_javascript_forward_associate {
Line 642  sub upload_manager_javascript_forward_as Line 1227  sub upload_manager_javascript_forward_as
             $numbuttons ++;              $numbuttons ++;
         }          }
         if (!$can_assign->{'int'}) {          if (!$can_assign->{'int'}) {
             my $warning = &mt('You may not specify an initial password for each user, as this is only available when new users use LON-CAPA internal authentication.').'\n'.              my $warning = &mt('You may not specify an initial password for each user, as this is only available when new users use LON-CAPA internal authentication.')."\n".
                           &mt('Your current role does not have rights to create users with that authentication type.');                            &mt('Your current role does not have rights to create users with that authentication type.');
               &js_escape(\$warning);
             $auth_update = <<"END";              $auth_update = <<"END";
    // Currently the initial password field is only supported for internal auth     // Currently the initial password field is only supported for internal auth
    // (see bug 6368).     // (see bug 6368).
Line 781  sub upload_manager_javascript_reverse_as Line 1367  sub upload_manager_javascript_reverse_as
         if (!$can_assign->{'int'}) {          if (!$can_assign->{'int'}) {
             my $warning = &mt('You may not specify an initial password, as this is only available when new users use LON-CAPA internal authentication.\n').              my $warning = &mt('You may not specify an initial password, as this is only available when new users use LON-CAPA internal authentication.\n').
                           &mt('Your current role does not have rights to create users with that authentication type.');                            &mt('Your current role does not have rights to create users with that authentication type.');
               &js_escape(\$warning);
             $auth_update = <<"END";              $auth_update = <<"END";
    // Currently the initial password field is only supported for internal auth     // Currently the initial password field is only supported for internal auth
    // (see bug 6368).     // (see bug 6368).
Line 878  sub print_upload_manager_footer { Line 1465  sub print_upload_manager_footer {
     my $krbform = &Apache::loncommon::authform_kerberos(%param);      my $krbform = &Apache::loncommon::authform_kerberos(%param);
     my $intform = &Apache::loncommon::authform_internal(%param);      my $intform = &Apache::loncommon::authform_internal(%param);
     my $locform = &Apache::loncommon::authform_local(%param);      my $locform = &Apache::loncommon::authform_local(%param);
       my $ltiform = &Apache::loncommon::authform_lti(%param);
     my $date_table = &date_setting_table(undef,undef,$context,undef,      my $date_table = &date_setting_table(undef,undef,$context,undef,
                                          $formname,$permission,$crstype);                                           $formname,$permission,$crstype);
   
Line 906  sub print_upload_manager_footer { Line 1494  sub print_upload_manager_footer {
             &Apache::loncommon::help_open_topic('Auth_Options').              &Apache::loncommon::help_open_topic('Auth_Options').
             "</p>\n";              "</p>\n";
     }      }
     $Str .= &set_login($defdom,$krbform,$intform,$locform);      $Str .= &set_login($defdom,$krbform,$intform,$locform,$ltiform);
   
     my ($home_server_pick,$numlib) =      my ($home_server_pick,$numlib) =
         &Apache::loncommon::home_server_form_item($defdom,'lcserver',          &Apache::loncommon::home_server_form_item($defdom,'lcserver',
Line 923  sub print_upload_manager_footer { Line 1511  sub print_upload_manager_footer {
                 &Apache::lonhtmlcommon::row_closure();                  &Apache::lonhtmlcommon::row_closure();
     }      }
   
       my ($trusted,$untrusted);
       if ($context eq 'course') {
           ($trusted,$untrusted) = &Apache::lonnet::trusted_domains('enroll',$defdom);
       } elsif ($context eq 'author') {
           ($trusted,$untrusted) = &Apache::lonnet::trusted_domains('othcoau',$defdom);
       }
     $Str .= &Apache::lonhtmlcommon::row_title(&mt('Default domain'))      $Str .= &Apache::lonhtmlcommon::row_title(&mt('Default domain'))
            .&Apache::loncommon::select_dom_form($defdom,'defaultdomain',undef,1)             .&Apache::loncommon::select_dom_form($defdom,'defaultdomain',undef,1,undef,$trusted,$untrusted)
            .&Apache::lonhtmlcommon::row_closure();             .&Apache::lonhtmlcommon::row_closure();
   
     $Str .= &Apache::lonhtmlcommon::row_title(&mt('Starting and Ending Dates'))      $Str .= &Apache::lonhtmlcommon::row_title(&mt('Starting and Ending Dates'))
Line 1101  sub print_upload_manager_form { Line 1695  sub print_upload_manager_form {
     if (!$env{'form.datatoken'}) {      if (!$env{'form.datatoken'}) {
         $datatoken=&Apache::loncommon::upfile_store($r);          $datatoken=&Apache::loncommon::upfile_store($r);
     } else {      } else {
         $datatoken=$env{'form.datatoken'};          $datatoken=&Apache::loncommon::valid_datatoken($env{'form.datatoken'});
         &Apache::loncommon::load_tmp_file($r);          if ($datatoken ne '') {
               &Apache::loncommon::load_tmp_file($r,$datatoken);
           }
       }
       if ($datatoken eq '') {
           $r->print('<p class="LC_error">'.&mt('Error').': '.
                     &mt('Invalid datatoken').'</p>');
           return 'missingdata';
     }      }
     my @records=&Apache::loncommon::upfile_record_sep();      my @records=&Apache::loncommon::upfile_record_sep();
     if($env{'form.noFirstLine'}){      if($env{'form.noFirstLine'}){
Line 1186  sub print_upload_manager_form { Line 1787  sub print_upload_manager_form {
     }      }
     &print_upload_manager_footer($r,$i,$keyfields,$defdom,$today,$halfyear,      &print_upload_manager_footer($r,$i,$keyfields,$defdom,$today,$halfyear,
                                  $context,$permission,$crstype,$showcredits);                                   $context,$permission,$crstype,$showcredits);
       return 'ok';
 }  }
   
 sub setup_date_selectors {  sub setup_date_selectors {
Line 1527  sub curr_role_permissions { Line 2129  sub curr_role_permissions {
 # ======================================================= Existing Custom Roles  # ======================================================= Existing Custom Roles
   
 sub my_custom_roles {  sub my_custom_roles {
     my ($crstype) = @_;      my ($crstype,$udom,$uname) = @_;
     my %returnhash=();      my %returnhash=();
     my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1});      my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1});
     my %rolehash=&Apache::lonnet::dump('roles');      my %rolehash=&Apache::lonnet::dump('roles',$udom,$uname);
     foreach my $key (keys(%rolehash)) {      foreach my $key (keys(%rolehash)) {
         if ($key=~/^rolesdef\_(\w+)$/) {          if ($key=~/^rolesdef\_(\w+)$/) {
               my $role = $1;
             if ($crstype eq 'Community') {              if ($crstype eq 'Community') {
                 next if ($rolehash{$key} =~ /bre\&S/);                   next if ($rolehash{$key} =~ /bre\&S/); 
             }              }
             $returnhash{$1}=$1;              $returnhash{$role}=$role;
         }          }
     }      }
     return %returnhash;      return %returnhash;
Line 2259  sub build_user_record { Line 2862  sub build_user_record {
   
 sub courses_selector {  sub courses_selector {
     my ($cdom,$formname) = @_;      my ($cdom,$formname) = @_;
     my %coursecodes = ();  
     my %codes = ();      my %codes = ();
     my @codetitles = ();      my @codetitles = ();
     my %cat_titles = ();      my %cat_titles = ();
Line 2272  sub courses_selector { Line 2874  sub courses_selector {
     my $jscript = '';      my $jscript = '';
   
     my $totcodes = 0;      my $totcodes = 0;
     $totcodes =      my $instcats = &Apache::lonnet::get_dom_instcats($cdom);
         &Apache::courseclassifier::retrieve_instcodes(\%coursecodes,      if (ref($instcats) eq 'HASH') {
                                                       $cdom,$totcodes);          if ((ref($instcats->{'codetitles'}) eq 'ARRAY') && (ref($instcats->{'codes'}) eq 'HASH') &&
     if ($totcodes > 0) {              (ref($instcats->{'cat_titles'}) eq 'HASH') && (ref($instcats->{'cat_order'}) eq 'HASH')) {
         $format_reply =              %codes = %{$instcats->{'codes'}};
              &Apache::lonnet::auto_instcode_format($caller,$cdom,\%coursecodes,              @codetitles = @{$instcats->{'codetitles'}};
                                 \%codes,\@codetitles,\%cat_titles,\%cat_order);              %cat_titles = %{$instcats->{'cat_titles'}};
         if ($format_reply eq 'ok') {              %cat_order = %{$instcats->{'cat_order'}};
               $totcodes = scalar(keys(%codes));
             my $numtypes = @codetitles;              my $numtypes = @codetitles;
             &Apache::courseclassifier::build_code_selections(\%codes,\@codetitles,\%cat_titles,\%cat_order,\%idlist,\%idnums,\%idlist_titles);              &Apache::courseclassifier::build_code_selections(\%codes,\@codetitles,\%cat_titles,\%cat_order,\%idlist,\%idnums,\%idlist_titles);
             my ($scripttext,$longtitles) = &Apache::courseclassifier::javascript_definitions(\@codetitles,\%idlist,\%idlist_titles,\%idnums,\%cat_titles);              my ($scripttext,$longtitles) = &Apache::courseclassifier::javascript_definitions(\@codetitles,\%idlist,\%idlist_titles,\%idnums,\%cat_titles);
Line 2287  sub courses_selector { Line 2890  sub courses_selector {
             my $allidlist = $idlist{$codetitles[0]};              my $allidlist = $idlist{$codetitles[0]};
             $jscript .= &Apache::courseclassifier::courseset_js_start($formname,$longtitles_str,$allidlist);              $jscript .= &Apache::courseclassifier::courseset_js_start($formname,$longtitles_str,$allidlist);
             $jscript .= $scripttext;              $jscript .= $scripttext;
             $jscript .= &Apache::courseclassifier::javascript_code_selections($formname,@codetitles);              $jscript .= &Apache::courseclassifier::javascript_code_selections($formname,\@codetitles);
         }          }
     }      }
     my $cb_jscript = &Apache::loncommon::coursebrowser_javascript($cdom);      my $cb_jscript = &Apache::loncommon::coursebrowser_javascript($cdom);
Line 2316  function setCourseCat(formname) { Line 2919  function setCourseCat(formname) {
     }      }
     courseSet('$codetitles[1]');      courseSet('$codetitles[1]');
     for (var j=0; j<formname.Department.length; j++) {      for (var j=0; j<formname.Department.length; j++) {
         if (formname.Department.options[j].value == "$env{'form.Department'}") {            formname.Department.options[j].selected = true;          if (formname.Department.options[j].value == "$env{'form.Department'}") {
               formname.Department.options[j].selected = true;
         }          }
     }      }
     if (formname.Department.options[formname.Department.selectedIndex].value == -1) {      if (formname.Department.options[formname.Department.selectedIndex].value == -1) {
Line 2410  sub make_keylist_array { Line 3014  sub make_keylist_array {
     $index->{'photo'} = &Apache::loncoursedata::CL_PHOTO();      $index->{'photo'} = &Apache::loncoursedata::CL_PHOTO();
     $index->{'thumbnail'} = &Apache::loncoursedata::CL_THUMBNAIL();      $index->{'thumbnail'} = &Apache::loncoursedata::CL_THUMBNAIL();
     $index->{'credits'} = &Apache::loncoursedata::CL_CREDITS();      $index->{'credits'} = &Apache::loncoursedata::CL_CREDITS();
       $index->{'instsec'} = &Apache::loncoursedata::CL_INSTSEC();
     $index->{'authorquota'} = &Apache::loncoursedata::CL_AUTHORQUOTA();      $index->{'authorquota'} = &Apache::loncoursedata::CL_AUTHORQUOTA();
     $index->{'authorusage'} = &Apache::loncoursedata::CL_AUTHORUSAGE();      $index->{'authorusage'} = &Apache::loncoursedata::CL_AUTHORUSAGE();
     foreach my $key (keys(%{$index})) {      foreach my $key (keys(%{$index})) {
Line 2542  $verify_action_js Line 3147  $verify_action_js
   
 function username_display_launch(username,domain) {  function username_display_launch(username,domain) {
     var target;      var target;
     for (var i=0; i<document.$formname.usernamelink.length; i++) {      if (!document.$formname.usernamelink.length) {
         if (document.$formname.usernamelink[i].checked) {          target = document.$formname.usernamelink.value;
             target = document.$formname.usernamelink[i].value;      } else {
           for (var i=0; i<document.$formname.usernamelink.length; i++) {
               if (document.$formname.usernamelink[i].checked) {
                  target = document.$formname.usernamelink[i].value;
               }
         }          }
     }      }
     if (target == 'modify') {      if ((target == 'modify') || (target == 'activity')) {
           var nextaction = 'singleuser';
           if (target == 'activity') {
               nextaction = 'accesslogs';
           }
         if (document.$formname.userwin.checked == true) {          if (document.$formname.userwin.checked == true) {
             var url = '/adm/createuser?srchterm='+username+'&srchdomain='+domain+'&phase=get_user_info&action=singleuser&srchin=dom&srchby=uname&srchtype=exact&popup=1';              var url = '/adm/createuser?srchterm='+username+'&srchdomain='+domain+'&phase=get_user_info&srchin=dom&srchby=uname&srchtype=exact&popup=1&action='+nextaction;
             var options = 'height=600,width=800,resizable=yes,scrollbars=yes,location=no,menubar=no,toolbar=no';              var options = 'height=600,width=800,resizable=yes,scrollbars=yes,location=no,menubar=no,toolbar=no';
             modifywin = window.open(url,'',options,1);              modifywin = window.open(url,'',options,1);
             modifywin.focus();              modifywin.focus();
Line 2558  function username_display_launch(usernam Line 3171  function username_display_launch(usernam
             document.$formname.srchterm.value=username;              document.$formname.srchterm.value=username;
             document.$formname.srchdomain.value=domain;              document.$formname.srchdomain.value=domain;
             document.$formname.phase.value='get_user_info';              document.$formname.phase.value='get_user_info';
             document.$formname.action.value = 'singleuser';              document.$formname.action.value = nextaction;
             document.$formname.submit();              document.$formname.submit();
         }          }
     }      }
Line 2604  END Line 3217  END
                        'owin'       => "Open in a new window",                         'owin'       => "Open in a new window",
                        'modify'     => "Modify a user's information",                         'modify'     => "Modify a user's information",
                        'track'      => "View a user's recent activity",                         'track'      => "View a user's recent activity",
                          'activity'   => "View a user's access log", 
                       );                        );
     my %lt = (%coltxt,%acttxt);      my %lt = (%coltxt,%acttxt);
     my $rolefilter = $env{'form.showrole'};      my $rolefilter = $env{'form.showrole'};
Line 2694  END Line 3308  END
             if ($permission->{'cusr'}) {              if ($permission->{'cusr'}) {
                 unshift (@linkdests,'modify');                  unshift (@linkdests,'modify');
             }              }
             if (&Apache::lonnet::allowed('vsa', $env{'request.course.id'}) ||              if ($context eq 'course') {
                 &Apache::lonnet::allowed('vsa', $env{'request.course.id'}.'/'.                  if (&Apache::lonnet::allowed('vsa', $env{'request.course.id'}) ||
                                          $env{'request.course.sec'})) {                      &Apache::lonnet::allowed('vsa', $env{'request.course.id'}.'/'.
                 push(@linkdests,'track');                                               $env{'request.course.sec'})) {
                       push(@linkdests,'track');
                   }
               } elsif ($context eq 'domain') {
                   if (&Apache::lonnet::allowed('vac',$env{'request.role.domain'})) {
                       push(@linkdests,'activity');
                   }
             }              }
   
             $output .= '<td>';              $output .= '<td>';
             my $usernamelink = $env{'form.usernamelink'};              my $usernamelink = $env{'form.usernamelink'};
             if ($usernamelink eq '') {              if ($usernamelink eq '') {
Line 2722  END Line 3341  END
                .'<input type="checkbox" name="userwin" value="1"'.$checkwin.' />'.$lt{'owin'}                 .'<input type="checkbox" name="userwin" value="1"'.$checkwin.' />'.$lt{'owin'}
                .'</label></span></td></tr></table></fieldset></div>';                 .'</label></span></td></tr></table></fieldset></div>';
         }          }
         $output .= "\n".'<br clear="all" />'."\n".          $output .= "\n".'<div style="padding:0;clear:both;margin:0;border:0"></div>'."\n".
                   &Apache::loncommon::start_data_table().                    &Apache::loncommon::start_data_table().
                   &Apache::loncommon::start_data_table_header_row();                    &Apache::loncommon::start_data_table_header_row();
         if ($mode eq 'autoenroll') {          if ($mode eq 'autoenroll') {
Line 2968  END Line 3587  END
             } (keys(%$userlist));              } (keys(%$userlist));
     }      }
     my $rowcount = 0;      my $rowcount = 0;
       my $disabled;
       if ($mode eq 'autoenroll') {
           unless ($permission->{'cusr'}) {
               $disabled = ' disabled="disabled"';
           }
       }
     foreach my $user (@sorted_users) {      foreach my $user (@sorted_users) {
         my %in;          my %in;
         my $sdata = $userlist->{$user};          my $sdata = $userlist->{$user};
Line 3004  END Line 3629  END
             if ($mode eq 'autoenroll') {              if ($mode eq 'autoenroll') {
                 my $cellentry;                  my $cellentry;
                 if ($in{'type'} eq 'auto') {                  if ($in{'type'} eq 'auto') {
                     $cellentry = '<b>'.&mt('auto').'</b>&nbsp;<label><input type="checkbox" name="chgauto" value="'.$in{'username'}.':'.$in{'domain'}.'" />&nbsp;'.&mt('Change').'</label>';                      $cellentry = '<b>'.&mt('auto').'</b>&nbsp;<label><input type="checkbox" name="chgauto" value="'.$in{'username'}.':'.$in{'domain'}.'"'.$disabled.' />&nbsp;'.&mt('Change').'</label>';
                     $autocount ++;                      $autocount ++;
                 } else {                  } else {
                     $cellentry = '<table border="0" cellspacing="0"><tr><td rowspan="2"><b>'.&mt('manual').'</b></td><td><span class="LC_nobreak"><label><input type="checkbox" name="chgmanual" value="'.$in{'username'}.':'.$in{'domain'}.'" />&nbsp;'.&mt('Change').'</label></span></td></tr><tr><td><span class="LC_nobreak">';                      $cellentry = '<table border="0" cellspacing="0"><tr><td rowspan="2"><b>'.&mt('manual').'</b></td><td><span class="LC_nobreak"><label><input type="checkbox" name="chgmanual" value="'.$in{'username'}.':'.$in{'domain'}.'"'.$disabled.' />&nbsp;'.&mt('Change').'</label></span></td></tr><tr><td><span class="LC_nobreak">';
                     $manualcount ++;                      $manualcount ++;
                     if ($in{'lockedtype'}) {                      if ($in{'lockedtype'}) {
                         $cellentry .= '<label><input type="checkbox" name="unlockchg" value="'.$in{'username'}.':'.$in{'domain'}.'" />&nbsp;'.&mt('Unlock').'</label>';                          $cellentry .= '<label><input type="checkbox" name="unlockchg" value="'.$in{'username'}.':'.$in{'domain'}.'"'.$disabled.' />&nbsp;'.&mt('Unlock').'</label>';
                         $unlockcount ++;                          $unlockcount ++;
                     } else {                      } else {
                         $cellentry .= '<label><input type="checkbox" name="lockchg" value="'.$in{'username'}.':'.$in{'domain'}.'" />&nbsp;'.&mt('Lock').'</label>';                          $cellentry .= '<label><input type="checkbox" name="lockchg" value="'.$in{'username'}.':'.$in{'domain'}.'"'.$disabled.' />&nbsp;'.&mt('Lock').'</label>';
                         $lockcount ++;                          $lockcount ++;
                     }                      }
                     $cellentry .= '</span></td></tr></table>';                      $cellentry .= '</span></td></tr></table>';
Line 3053  END Line 3678  END
                                 if ($role eq 'st') {                                  if ($role eq 'st') {
                                     $checkval .= ':'.$in{'type'}.':'.                                      $checkval .= ':'.$in{'type'}.':'.
                                                  $in{'lockedtype'}.':'.                                                   $in{'lockedtype'}.':'.
                                                  $in{'credits'};                                                   $in{'credits'}.':'.
                                                    &escape($in{'instsec'});
                                 }                                  }
                              }                               }
                         }                          }
                         if ($showcheckbox) {                          if ($showcheckbox) {
                             $r->print('<td><input type="checkbox" name="'.                              $r->print('<td><input type="checkbox" name="'.
                                       'actionlist" value="'.$checkval.'" /></td>');                                        'actionlist" value="'.
                                         &HTML::Entities::encode($checkval,'&<>"').'" />');
                               foreach my $item ('start','end') {
                                   $r->print('<input type="hidden" name="'.
                                             &HTML::Entities::encode($checkval.'_'.$item,'&<>"').'"'.
                                             ' value="'.$sdata->[$index{$item}].'" />');
                               }
                               $r->print('</td>');
                         } else {                          } else {
                             $r->print('<td>&nbsp;</td>');                              $r->print('<td>&nbsp;</td>');
                         }                          }
Line 3073  END Line 3706  END
             foreach my $item (@cols) {              foreach my $item (@cols) {
                 if ($item eq 'username') {                  if ($item eq 'username') {
                     $r->print('<td>'.&print_username_link($mode,\%in).'</td>');                      $r->print('<td>'.&print_username_link($mode,\%in).'</td>');
                 } elsif (($item eq 'start' || $item eq 'end') && ($actionselect)) {  
                     $r->print('<td>'.$in{$item}.'<input type="hidden" name="'.$checkval.'_'.$item.'" value="'.$sdata->[$index{$item}].'" /></td>'."\n");  
                 } elsif ($item eq 'status') {                  } elsif ($item eq 'status') {
                     my $showitem = $in{$item};                      my $showitem = $in{$item};
                     if (defined($ltstatus{$in{$item}})) {                      if (defined($ltstatus{$in{$item}})) {
Line 3173  sub bulkaction_javascript { Line 3804  sub bulkaction_javascript {
     my $noaction = &mt("You need to select an action to take for the user(s) you have selected");       my $noaction = &mt("You need to select an action to take for the user(s) you have selected"); 
     my $singconfirm = &mt(' for a single user?');      my $singconfirm = &mt(' for a single user?');
     my $multconfirm = &mt(' for multiple users?');      my $multconfirm = &mt(' for multiple users?');
       &js_escape(\$alert);
       &js_escape(\$noaction);
       &js_escape(\$singconfirm);
       &js_escape(\$multconfirm);
     my $output = <<"ENDJS";      my $output = <<"ENDJS";
 function verify_action (field) {  function verify_action (field) {
     var numchecked = 0;      var numchecked = 0;
Line 3461  END Line 4096  END
         setSections(formname,'$crstype');          setSections(formname,'$crstype');
         if (seccheck == 'ok') {          if (seccheck == 'ok') {
             opener.document.$callingform.newsecs.value = formname.sections.value;              opener.document.$callingform.newsecs.value = formname.sections.value;
           } else {
               return;
         }          }
 END  END
     } else {      } else {
Line 4045  sub print_first_users_upload_form { Line 4682  sub print_first_users_upload_form {
            .&Apache::lonhtmlcommon::end_pick_box();             .&Apache::lonhtmlcommon::end_pick_box();
   
     $str .= '<p>'      $str .= '<p>'
            .'<input type="submit" name="fileupload" value="'.&mt('Next').'"'             .'<input type="button" name="fileupload" value="'.&mt('Next').'"'
            .' onclick="javascript:checkUpload(this.form);" />'             .' onclick="javascript:checkUpload(this.form);" />'
            .'</p>';             .'</p>';
   
Line 4056  sub print_first_users_upload_form { Line 4693  sub print_first_users_upload_form {
 # ================================================= Drop/Add from uploaded file  # ================================================= Drop/Add from uploaded file
 sub upfile_drop_add {  sub upfile_drop_add {
     my ($r,$context,$permission,$showcredits) = @_;      my ($r,$context,$permission,$showcredits) = @_;
     &Apache::loncommon::load_tmp_file($r);      my $datatoken = &Apache::loncommon::valid_datatoken($env{'form.datatoken'});
       if ($datatoken ne '') {
           &Apache::loncommon::load_tmp_file($r,$datatoken);
       }
     my @userdata=&Apache::loncommon::upfile_record_sep();      my @userdata=&Apache::loncommon::upfile_record_sep();
     if($env{'form.noFirstLine'}){shift(@userdata);}      if($env{'form.noFirstLine'}){shift(@userdata);}
     my @keyfields = split(/\,/,$env{'form.keyfields'});      my @keyfields = split(/\,/,$env{'form.keyfields'});
Line 4070  sub upfile_drop_add { Line 4710  sub upfile_drop_add {
             $fields{$env{'form.f'.$i}}=$keyfields[$i];              $fields{$env{'form.f'.$i}}=$keyfields[$i];
         }          }
     }      }
     if ($env{'form.fullup'} ne 'yes') {  
         $r->print('<form name="studentform" method="post" action="/adm/createuser">'."\n".  
                   '<input type="hidden" name="action" value="'.$env{'form.action'}.'" />');  
     }  
     #      #
     # Store the field choices away      # Store the field choices away
     my @storefields = qw/username names fname mname lname gen id       my @storefields = qw/username names fname mname lname gen id 
Line 4087  sub upfile_drop_add { Line 4723  sub upfile_drop_add {
         $fieldstype{$field.'_choice'} = 'scalar';          $fieldstype{$field.'_choice'} = 'scalar';
     }      }
     &Apache::loncommon::store_course_settings('enrollment_upload',\%fieldstype);      &Apache::loncommon::store_course_settings('enrollment_upload',\%fieldstype);
     my ($cid,$crstype,$setting);      my ($cid,$crstype,$setting,$crsdom,$crsnum);
     if ($context eq 'domain') {      if ($context eq 'domain') {
         $setting = $env{'form.roleaction'};          $setting = $env{'form.roleaction'};
     }      }
     if ($env{'request.course.id'} ne '') {      if ($env{'request.course.id'} ne '') {
         $cid = $env{'request.course.id'};          $cid = $env{'request.course.id'};
         $crstype = &Apache::loncommon::course_type();          $crstype = &Apache::loncommon::course_type();
           $crsdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
           $crsnum = $env{'course.'.$env{'request.course.id'}.'.num'};
     } elsif ($setting eq 'course') {      } elsif ($setting eq 'course') {
         if (&Apache::lonnet::is_course($env{'form.dcdomain'},$env{'form.dccourse'})) {          if (&Apache::lonnet::is_course($env{'form.dcdomain'},$env{'form.dccourse'})) {
             $cid = $env{'form.dcdomain'}.'_'.$env{'form.dccourse'};              $cid = $env{'form.dcdomain'}.'_'.$env{'form.dccourse'};
             $crstype = &Apache::loncommon::course_type($cid);              $crstype = &Apache::loncommon::course_type($cid);
               $crsdom = $env{'form.dcdomain'};
               $crsnum = $env{'form.dccourse'};
         }          }
     }      }
     my ($startdate,$enddate) = &get_dates_from_form();      my ($startdate,$enddate) = &get_dates_from_form();
Line 4108  sub upfile_drop_add { Line 4748  sub upfile_drop_add {
     my $defdom=$env{'request.role.domain'};      my $defdom=$env{'request.role.domain'};
     my $domain;      my $domain;
     if ($env{'form.defaultdomain'} ne '') {      if ($env{'form.defaultdomain'} ne '') {
         $domain = $env{'form.defaultdomain'};          if (($context eq 'course') || ($setting eq 'course')) {
               if ($env{'form.defaultdomain'} eq $crsdom) {
                   $domain = $env{'form.defaultdomain'};
               } else {
                   if (&Apache::lonnet::will_trust('enroll',$crsdom,$env{'form.defaultdomain'})) {
                       $domain = $env{'form.defaultdomain'};
                   } else {
                       $r->print('<span class="LC_error">'.&mt('Error').': '.
                                 &mt('Enrollment of users not permitted for specified default domain: [_1].',
                                     &Apache::lonnet::domain($env{'form.defaultdomain'},'description')).'</span>');
                       return 'untrusted';
                   }
               }
           } elsif ($context eq 'author') {
               if ($env{'form.defaultdomain'} eq $defdom) {
                   $domain = $env{'form.defaultdomain'}; 
               } else {
                   if ((&Apache::lonnet::will_trust('othcoau',$defdom,$env{'form.defaultdomain'})) &&
                       (&Apache::lonnet::will_trust('coaurem',$env{'form.defaultdomain'},$defdom))) {
                       $domain = $env{'form.defaultdomain'};
                   } else {
                       $r->print('<span class="LC_error">'.&mt('Error').': '.
                                 &mt('Addition of users not permitted for specified default domain: [_1].',
                                     &Apache::lonnet::domain($env{'form.defaultdomain'},'description')).'</span>');
                       return 'untrusted';
                   }
               }
           } elsif (($context eq 'domain') && ($setting eq 'domain')) {
               if ($env{'form.defaultdomain'} eq $defdom) {
                   $domain = $env{'form.defaultdomain'};
               } else {
                   if (&Apache::lonnet::will_trust('domroles',$defdom,$env{'form.defaultdomain'})) {
                       $domain = $env{'form.defaultdomain'};
                   } else {
                       $r->print('<span class="LC_error">'.&mt('Error').': '.
                                 &mt('Addition of users not permitted for specified default domain: [_1].',
                                     &Apache::lonnet::domain($env{'form.defaultdomain'},'description')).'</span>');
                       return 'untrusted';
                   }
               }
           }
     } else {      } else {
         $domain = $defdom;          $domain = $defdom;
     }      }
Line 4118  sub upfile_drop_add { Line 4798  sub upfile_drop_add {
     } else {      } else {
         my %home_servers = &Apache::lonnet::get_servers($defdom,'library');          my %home_servers = &Apache::lonnet::get_servers($defdom,'library');
         if (! exists($home_servers{$desiredhost})) {          if (! exists($home_servers{$desiredhost})) {
             $r->print('<span class="LC_error">'.&mt('Error').              $r->print('<p class="LC_error">'.&mt('Error').': '.
                       &mt('Invalid home server specified').'</span>');                        &mt('Invalid home server specified').'</p>');
             $r->print(&Apache::loncommon::end_page());              return 'invalidhome';
             return;  
         }          }
     }      }
     # Determine authentication mechanism      # Determine authentication mechanism
Line 4131  sub upfile_drop_add { Line 4810  sub upfile_drop_add {
     }      }
     my $amode  = '';      my $amode  = '';
     my $genpwd = '';      my $genpwd = '';
       my @genpwdfail;
     if ($env{'form.login'} eq 'krb') {      if ($env{'form.login'} eq 'krb') {
         $amode='krb';          $amode='krb';
         $amode.=$env{'form.krbver'};          $amode.=$env{'form.krbver'};
Line 4139  sub upfile_drop_add { Line 4819  sub upfile_drop_add {
         $amode='internal';          $amode='internal';
         if ((defined($env{'form.intarg'})) && ($env{'form.intarg'})) {          if ((defined($env{'form.intarg'})) && ($env{'form.intarg'})) {
             $genpwd=$env{'form.intarg'};              $genpwd=$env{'form.intarg'};
               @genpwdfail =
                   &Apache::loncommon::check_passwd_rules($domain,$genpwd);
         }          }
     } elsif ($env{'form.login'} eq 'loc') {      } elsif ($env{'form.login'} eq 'loc') {
         $amode='localauth';          $amode='localauth';
         if ((defined($env{'form.locarg'})) && ($env{'form.locarg'})) {          if ((defined($env{'form.locarg'})) && ($env{'form.locarg'})) {
             $genpwd=$env{'form.locarg'};              $genpwd=$env{'form.locarg'};
         }          }
       } elsif ($env{'form.login'} eq 'lti') {
           $amode='lti';
     }      }
     if ($amode =~ /^krb/) {      if ($amode =~ /^krb/) {
         if (! defined($genpwd) || $genpwd eq '') {          if (! defined($genpwd) || $genpwd eq '') {
Line 4217  sub upfile_drop_add { Line 4901  sub upfile_drop_add {
                                                   \@statuses,\@poss_roles);                                                    \@statuses,\@poss_roles);
                 &gather_userinfo($context,'view',\%userlist,$indexhash,\%info,                  &gather_userinfo($context,'view',\%userlist,$indexhash,\%info,
                              \%cstr_roles,$permission);                               \%cstr_roles,$permission);
   
             }              }
         }          }
     }      }
       if ($datatoken eq '') {
           $r->print('<p class="LC_error">'.&mt('Error').': '.
                     &mt('Invalid datatoken').'</p>');
           return 'missingdata';
       }
     if ( $domain eq &LONCAPA::clean_domain($domain)      if ( $domain eq &LONCAPA::clean_domain($domain)
         && ($amode ne '')) {          && ($amode ne '')) {
         #######################################          #######################################
Line 4234  sub upfile_drop_add { Line 4922  sub upfile_drop_add {
             $r->print('<h3>'.&mt('Adding/Modifying Users')."</h3>\n<p>\n");              $r->print('<h3>'.&mt('Adding/Modifying Users')."</h3>\n<p>\n");
         }          }
         $r->rflush;          $r->rflush;
           my (%got_role_approvals,%got_instdoms,%process_by,%instdoms,
               %pending,%reject,%notifydc,%status,%unauthorized,%currqueued);
   
         my %counts = (          my %counts = (
                        user => 0,                         user => 0,
Line 4290  sub upfile_drop_add { Line 4980  sub upfile_drop_add {
         my $newuserdom = $env{'request.role.domain'};          my $newuserdom = $env{'request.role.domain'};
         map { $cancreate{$_} = &can_create_user($newuserdom,$context,$_); } keys(%longtypes);          map { $cancreate{$_} = &can_create_user($newuserdom,$context,$_); } keys(%longtypes);
         # Get new users list          # Get new users list
           my (%existinguser,%userinfo,%disallow,%rulematch,%inst_results,%alerts,%checkuname,
               %showpasswdrules,$haspasswdmap);
           my $counter = -1;
           my (%willtrust,%trustchecked);
         foreach my $line (@userdata) {          foreach my $line (@userdata) {
               $counter ++;
             my @secs;              my @secs;
             my %entries=&Apache::loncommon::record_sep($line);              my %entries=&Apache::loncommon::record_sep($line);
             # Determine user name              # Determine user name
Line 4322  sub upfile_drop_add { Line 5017  sub upfile_drop_add {
                     if ($entries{$fields{'username'}} =~ /\s/) {                      if ($entries{$fields{'username'}} =~ /\s/) {
                         $nowhitespace = ' - '.&mt('usernames may not contain spaces.');                          $nowhitespace = ' - '.&mt('usernames may not contain spaces.');
                     }                      }
                     $r->print(                      $disallow{$counter} =
                         '<br />'.  
                         &mt('Unacceptable username [_1] for user [_2] [_3] [_4] [_5]',                          &mt('Unacceptable username [_1] for user [_2] [_3] [_4] [_5]',
                                 '"<b>'.$entries{$fields{'username'}}.'</b>"',                              '"<b>'.$entries{$fields{'username'}}.'</b>"',
                                 $fname,$mname,$lname,$gen).                              $fname,$mname,$lname,$gen).$nowhitespace;
                         $nowhitespace);  
                     next;                      next;
                 } else {                  } else {
                     $entries{$fields{'domain'}} =~ s/^\s+|\s+$//g;                      $entries{$fields{'domain'}} =~ s/^\s+|\s+$//g;
                     if ($entries{$fields{'domain'}}                       if ($entries{$fields{'domain'}} 
                         ne &LONCAPA::clean_domain($entries{$fields{'domain'}})) {                          ne &LONCAPA::clean_domain($entries{$fields{'domain'}})) {
                         $r->print(                          $disallow{$counter} =
                             '<br />'.  
                             &mt('Unacceptable domain [_1] for user [_2] [_3] [_4] [_5]',                              &mt('Unacceptable domain [_1] for user [_2] [_3] [_4] [_5]',
                                    '"<b>'.$entries{$fields{'domain'}}.'</b>"',                                  '"<b>'.$entries{$fields{'domain'}}.'</b>"',
                                     $fname,$mname,$lname,$gen));                                  $fname,$mname,$lname,$gen);
                     next;                          next;
                       } elsif ($entries{$fields{'domain'}} ne $domain) {
                           my $possdom = $entries{$fields{'domain'}};
                           if ($context eq 'course' || $setting eq 'course') {
                               unless ($trustchecked{$possdom}) {
                                   $willtrust{$possdom} = &Apache::lonnet::will_trust('enroll',$domain,$possdom);
                                   $trustchecked{$possdom} = 1;
                               }
                           } elsif ($context eq 'author') {
                               unless ($trustchecked{$possdom}) {
                                   $willtrust{$possdom} = &Apache::lonnet::will_trust('othcoau',$domain,$possdom);
                               }
                               if ($willtrust{$possdom}) {
                                   $willtrust{$possdom} = &Apache::lonnet::will_trust('coaurem',$possdom,$domain); 
                               }
                           }
                           unless ($willtrust{$possdom}) {
                               $disallow{$counter} =
                                   &mt('Unacceptable domain [_1] for user [_2] [_3] [_4] [_5]',
                                       '"<b>'.$possdom.'</b>"',
                                       $fname,$mname,$lname,$gen);
                               next;
                           }
                     }                      }
                     my $username = $entries{$fields{'username'}};                      my $username = $entries{$fields{'username'}};
                     my $userdomain = $entries{$fields{'domain'}};                      my $userdomain = $entries{$fields{'domain'}};
Line 4350  sub upfile_drop_add { Line 5064  sub upfile_drop_add {
                             $entries{$fields{'sec'}} =~ s/\W//g;                              $entries{$fields{'sec'}} =~ s/\W//g;
                             my $item = $entries{$fields{'sec'}};                              my $item = $entries{$fields{'sec'}};
                             if ($item eq "none" || $item eq 'all') {                              if ($item eq "none" || $item eq 'all') {
                                 $r->print('<br />'.&mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a reserved word.','<b>'.$username.'</b>',$fname,$mname,$lname,$gen,$item));                                  $disallow{$counter} =
                                       &mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a reserved word.',
                                           '<b>'.$username.'</b>',$fname,$mname,$lname,$gen,$item);
                                 next;                                  next;
                             } elsif (exists($curr_groups{$item})) {                              } elsif (exists($curr_groups{$item})) {
                                 $r->print('<br />'.&mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a course group.','<b>'.$username.'</b>',$fname,$mname,$lname,$gen,$item).' '.&mt('Section names and group names must be distinct.'));                                  $disallow{$counter} =
                                       &mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a course group.',
                                           '<b>'.$username.'</b>',$fname,$mname,$lname,$gen,$item).' '.
                                       &mt('Section names and group names must be distinct.');
                                 next;                                  next;
                             } else {                              } else {
                                 push(@secs,$item);                                  push(@secs,$item);
Line 4365  sub upfile_drop_add { Line 5084  sub upfile_drop_add {
                         if (ref($userlist{$username.':'.$userdomain}) eq 'ARRAY') {                          if (ref($userlist{$username.':'.$userdomain}) eq 'ARRAY') {
                             my $currsec = $userlist{$username.':'.$userdomain}[$secidx];                              my $currsec = $userlist{$username.':'.$userdomain}[$secidx];
                             if ($currsec ne $env{'request.course.sec'}) {                              if ($currsec ne $env{'request.course.sec'}) {
                                 $r->print('<br />'.&mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]".','<b>'.$username.'</b>',$fname,$mname,$lname,$gen,$secs[0]).'<br />');                                  $disallow{$counter} =
                                       &mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]".',
                                           '<b>'.$username.'</b>',$fname,$mname,$lname,$gen,$secs[0]);
                                 if ($currsec eq '') {                                  if ($currsec eq '') {
                                     $r->print(&mt('This user already has an active/future student role in the course, unaffiliated to any section.'));                                      $disallow{$counter} .=
                                           &mt('This user already has an active/future student role in the course, unaffiliated to any section.');
   
                                 } else {                                  } else {
                                     $r->print(&mt('This user already has an active/future role in section "[_1]" of the course.',$currsec));                                      $disallow{$counter} .=
                                           &mt('This user already has an active/future role in section "[_1]" of the course.',$currsec);
                                 }                                  }
                                 $r->print('<br />'.&mt('Although your current role has privileges to add students to section "[_1]", you do not have privileges to modify existing enrollments in other sections.',$secs[0]).'<br />');                                  $disallow{$counter} .=
                                       '<br />'.
                                       &mt('Although your current role has privileges to add students to section "[_1]", you do not have privileges to modify existing enrollments in other sections.',
                                           $secs[0]);
                                 next;                                  next;
                             }                              }
                         }                          }
Line 4406  sub upfile_drop_add { Line 5132  sub upfile_drop_add {
                         }                          }
                     }                      }
                     # determine user password                      # determine user password
                     my $password = $genpwd;                      my $password;
                       my $passwdfromfile;
                     if (defined($fields{'ipwd'})) {                      if (defined($fields{'ipwd'})) {
                         if ($entries{$fields{'ipwd'}}) {                          if ($entries{$fields{'ipwd'}}) {
                             $password=$entries{$fields{'ipwd'}};                              $password=$entries{$fields{'ipwd'}};
                               $passwdfromfile = 1;
                               if ($env{'form.login'} eq 'int') {
                                   my $uhome=&Apache::lonnet::homeserver($username,$userdomain);
                                   if (($uhome eq 'no_host') || ($changeauth)) {
                                       my @brokepwdrules =
                                           &Apache::loncommon::check_passwd_rules($domain,$password);
                                       if (@brokepwdrules) {
                                           $disallow{$counter} = &mt('[_1]: Password included in file for this user did not meet requirements.',
                                                                     '<b>'.$username.'</b>');
                                           map { $showpasswdrules{$_} = 1; } @brokepwdrules;
                                           next;
                                       }
                                   }
                               }
                         }                          }
                     }                      }
                       unless ($passwdfromfile) {
                           if ($env{'form.login'} eq 'int') {
                               if (@genpwdfail) {
                                   my $uhome=&Apache::lonnet::homeserver($username,$userdomain);
                                   if (($uhome eq 'no_host') || ($changeauth)) {
                                       $disallow{$counter} = &mt('[_1]: No specific password in file for this user; default password did not meet requirements',
                                                                 '<b>'.$username.'</b>');
                                       unless ($haspasswdmap) {
                                           map { $showpasswdrules{$_} = 1; } @genpwdfail;
                                           $haspasswdmap = 1;
                                       }
                                   }
                                   next;
                               }
                           }
                           $password = $genpwd;
                       }
                     # determine user role                      # determine user role
                     my $role = '';                      my $role = '';
                     if (defined($fields{'role'})) {                      if (defined($fields{'role'})) {
Line 4424  sub upfile_drop_add { Line 5182  sub upfile_drop_add {
                             }                              }
                             if ($role eq '') {                              if ($role eq '') {
                                 my $rolestr = join(', ',@permitted_roles);                                  my $rolestr = join(', ',@permitted_roles);
                                 $r->print('<br />'                                  $disallow{$counter} =
                                          .&mt('[_1]: You do not have permission to add the requested role [_2] for the user.'                                      &mt('[_1]: You do not have permission to add the requested role [_2] for the user.'
                                              ,'<b>'.$entries{$fields{'username'}}.'</b>'                                          ,'<b>'.$entries{$fields{'username'}}.'</b>'
                                              ,$entries{$fields{'role'}})                                          ,$entries{$fields{'role'}})
                                          .'<br />'                                          .'<br />'
                                          .&mt('Allowable role(s) is/are: [_1].',$rolestr)."\n"                                          .&mt('Allowable role(s) is/are: [_1].',$rolestr);
                                 );  
                                 next;                                  next;
                             }                              }
                         }                          }
Line 4460  sub upfile_drop_add { Line 5217  sub upfile_drop_add {
                     # check against rules                      # check against rules
                     my $checkid = 0;                      my $checkid = 0;
                     my $newuser = 0;                      my $newuser = 0;
                     my (%rulematch,%inst_results,%idinst_results);  
                     my $uhome=&Apache::lonnet::homeserver($username,$userdomain);                      my $uhome=&Apache::lonnet::homeserver($username,$userdomain);
                     if ($uhome eq 'no_host') {                      if ($uhome eq 'no_host') {
                         if ($userdomain ne $newuserdom) {                          if ($userdomain ne $newuserdom) {
                             if ($context eq 'course') {                              if ($context eq 'course') {
                                 $r->print('<br />'.                                  $disallow{$counter} =
                                           &mt('[_1]: The domain specified ([_2]) is different to that of the course.',                                      &mt('[_1]: The domain specified ([_2]) is different to that of the course.',
                                           '<b>'.$username.'</b>',$userdomain).'<br />');                                         '<b>'.$username.'</b>',$userdomain);
                             } elsif ($context eq 'author') {                              } elsif ($context eq 'author') {
                                 $r->print(&mt('[_1]: The domain specified ([_2]) is different to that of the author.',                                  $disallow{$counter} =
                                         '<b>'.$username.'</b>',$userdomain).'<br />');                                       &mt('[_1]: The domain specified ([_2]) is different to that of the author.',
                                           '<b>'.$username.'</b>',$userdomain); 
                             } else {                              } else {
                                 $r->print(&mt('[_1]: The domain specified ([_2]) is different to that of your current role.',                                  $disallow{$counter} =
                                         '<b>'.$username.'</b>',$userdomain).'<br />');                                      &mt('[_1]: The domain specified ([_2]) is different to that of your current role.',
                                           '<b>'.$username.'</b>',$userdomain);
                             }                              }
                             $r->print(&mt('The user does not already exist, and you may not create a new user in a different domain.'));                              $disallow{$counter} .=
                                   &mt('The user does not already exist, and you may not create a new user in a different domain.');
                             next;                              next;
                           } else {
                               unless (($password ne '') || ($env{'form.login'} eq 'loc') || ($env{'form.login'} eq 'lti')) {
                                   $disallow{$counter} =
                                       &mt('[_1]: This is a new user but no default password was provided, and the authentication type requires one.',
                                           '<b>'.$username.'</b>');
                                   next;
                               }
                         }                          }
                         $checkid = 1;                          $checkid = 1;
                         $newuser = 1;                          $newuser = 1;
                         my $user = $username.':'.$newuserdom;                          $checkuname{$username.':'.$newuserdom} = { 'newuser' => $newuser, 'id' => $id };
                         my $checkhash;  
                         my $checks = { 'username' => 1 };  
                         $checkhash->{$username.':'.$newuserdom} = { 'newuser' => 1, };  
                         &Apache::loncommon::user_rule_check($checkhash,$checks,  
                             \%alerts,\%rulematch,\%inst_results,\%curr_rules,  
                             \%got_rules);  
                         if (ref($alerts{'username'}) eq 'HASH') {  
                             if (ref($alerts{'username'}{$newuserdom}) eq 'HASH') {  
                                 if ($alerts{'username'}{$newuserdom}{$username}) {  
                                     $r->print('<br />'.  
                                               &mt('[_1]: matches the username format at your institution, but is not known to your directory service.','<b>'.$username.'</b>').'<br />'.  
                                               &mt('Consequently, the user was not created.'));  
                                     next;  
                                 }  
                             }  
                         }  
                         my $usertype = 'unofficial';  
                         if (ref($rulematch{$user}) eq 'HASH') {  
                             if ($rulematch{$user}{'username'}) {  
                                 $usertype = 'official';  
                             }  
                         }  
                         unless ($cancreate{$usertype}) {  
                             my $showtype = $longtypes{$usertype};  
                             $r->print('<br />'.  
                                       &mt('[_1]: The user does not exist, and you are not permitted to create users of type: [_2].','<b>'.$username.'</b>',$showtype));  
                             next;  
                         }  
                     } else {                      } else {
                         if ($context eq 'course' || $context eq 'author') {                          if ($context eq 'course' || $context eq 'author') {
                             if ($userdomain eq $domain ) {                              if ($userdomain eq $domain ) {
Line 4541  sub upfile_drop_add { Line 5279  sub upfile_drop_add {
                                 }                                  }
                             }                              }
                         }                          }
                           if ($id) {
                               $existinguser{$userdomain}{$username} = $id;
                           }
                       }
                       $userinfo{$counter} = {
                                             username   => $username,
                                             domain     => $userdomain,
                                             fname      => $fname,
                                             mname      => $mname,
                                             lname      => $lname,
                                             gen        => $gen,
                                             email      => $email,
                                             id         => $id, 
                                             password   => $password,
                                             inststatus => $inststatus,
                                             role       => $role,
                                             sections   => \@secs,
                                             credits    => $credits,
                                             newuser    => $newuser,
                                             checkid    => $checkid,
                                           };
                   }
               }
           } # end of foreach (@userdata)
           if ($counter > -1) {
               my $total = $counter + 1;
               my %checkids;
               if ((keys(%existinguser)) || (keys(%checkuname))) {
                   $r->print(&mt('Please be patient -- checking for institutional data ...'));
                   $r->rflush();
                   if (keys(%existinguser)) {
                       foreach my $dom (keys(%existinguser)) {
                           if (ref($existinguser{$dom}) eq 'HASH') {
                               my %idhash = &Apache::lonnet::idrget($dom,keys(%{$existinguser{$dom}}));
                               foreach my $username (keys(%{$existinguser{$dom}})) {
                                   if ($idhash{$username} ne $existinguser{$dom}{$username}) {
                                       $checkids{$username.':'.$dom} = {
                                                                       'id' => $existinguser{$dom}{$username},
                                                                       };
                                   }
                               }
                               if (keys(%checkids)) {
                                   &Apache::loncommon::user_rule_check(\%checkids,{ 'id' => 1 },
                                                                       \%alerts,\%rulematch,
                                                                       \%inst_results,\%curr_rules,
                                                                       \%got_rules);
                               }
                           }
                     }                      }
                     if ($id ne '') {                  }
                         if (!$newuser) {                  if (keys(%checkuname)) {
                             my %idhash = &Apache::lonnet::idrget($userdomain,($username));                      &Apache::loncommon::user_rule_check(\%checkuname,{ 'username' => 1, 'id' => 1, },
                             if ($idhash{$username} ne $id) {                                                          \%alerts,\%rulematch,\%inst_results,
                                 $checkid = 1;                                                          \%curr_rules,\%got_rules);
                   }
                   $r->print(' '.&mt('done').'<br /><br />');
                   $r->rflush();
               }
               my %prog_state = &Apache::lonhtmlcommon::Create_PrgWin($r,$total);
               $r->print('<ul>');
               for (my $i=0; $i<=$counter; $i++) {
                   if ($disallow{$i}) {
                       $r->print('<li>'.$disallow{$i}.'</li>');
                   } elsif (ref($userinfo{$i}) eq 'HASH') {
                       my $password = $userinfo{$i}{'password'}; 
                       my $newuser = $userinfo{$i}{'newuser'};
                       my $checkid = $userinfo{$i}{'checkid'};
                       my $id = $userinfo{$i}{'id'};
                       my $role = $userinfo{$i}{'role'};
                       my @secs;
                       if (ref($userinfo{$i}{'sections'}) eq 'ARRAY') {
                           @secs = @{$userinfo{$i}{'sections'}};
                       }
                       my $fname = $userinfo{$i}{'fname'};
                       my $mname = $userinfo{$i}{'mname'}; 
                       my $lname = $userinfo{$i}{'lname'};
                       my $gen = $userinfo{$i}{'gen'};
                       my $email = $userinfo{$i}{'email'};
                       my $inststatus = $userinfo{$i}{'inststatus'};
                       my $credits = $userinfo{$i}{'credits'};
                       my $username = $userinfo{$i}{'username'};
                       my $userdomain = $userinfo{$i}{'domain'};
                       my $user = $username.':'.$userdomain;
                       if ($newuser) {
                           if (ref($alerts{'username'}) eq 'HASH') {
                               if (ref($alerts{'username'}{$userdomain}) eq 'HASH') {
                                   if ($alerts{'username'}{$userdomain}{$username}) {
                                       $r->print('<li>'.
                                                 &mt('[_1]: matches the username format at your institution, but is not known to your directory service.','<b>'.$username.'</b>').'<br />'.
                                                 &mt('Consequently, the user was not created.').'</li>');
                                       next;
                                   }
                               }
                           }
                           if (ref($inst_results{$user}) eq 'HASH') {
                               if ($inst_results{$user}{'firstname'} ne '') {
                                   $fname = $inst_results{$user}{'firstname'};
                               }
                               if ($inst_results{$user}{'middlename'} ne '') {
                                   $mname = $inst_results{$user}{'middlename'};
                               }
                               if ($inst_results{$user}{'lasttname'} ne '') {
                                   $lname = $inst_results{$user}{'lastname'};
                               }
                               if ($inst_results{$user}{'permanentemail'} ne '') {
                                   $email = $inst_results{$user}{'permanentemail'};
                               }
                               if ($inst_results{$user}{'id'} ne '') {
                                   $id = $inst_results{$user}{'id'};
                                   $checkid = 0;
                               }
                               if (ref($inst_results{$user}{'inststatus'}) eq 'ARRAY') {
                                   $inststatus = join(':',@{$inst_results{$user}{'inststatus'}});
                             }                              }
                         }                          }
                         if ($checkid) {                          if (($checkid) && ($id ne '')) {
                             my $checkhash;  
                             my $checks = { 'id' => 1 };  
                             $checkhash->{$username.':'.$userdomain} = { 'newuser' => $newuser,  
                                                                     'id'  => $id };  
                             &Apache::loncommon::user_rule_check($checkhash,$checks,  
                                 \%alerts,\%rulematch,\%idinst_results,\%curr_rules,  
                                 \%got_rules);  
                             if (ref($alerts{'id'}) eq 'HASH') {                              if (ref($alerts{'id'}) eq 'HASH') {
                                 if (ref($alerts{'id'}{$userdomain}) eq 'HASH') {                                  if (ref($alerts{'id'}{$userdomain}) eq 'HASH') {
                                     if ($alerts{'id'}{$userdomain}{$id}) {                                      if ($alerts{'id'}{$userdomain}{$username}) {
                                         $r->print(&mt('[_1]: has a student/employee ID matching the format at your institution, but the ID is found by your directory service.',                                          $r->print('<li>'.
                                                     &mt('[_1]: has a student/employee ID matching the format at your institution, but the ID is not found by your directory service.',
                                                   '<b>'.$username.'</b>').'<br />'.                                                    '<b>'.$username.'</b>').'<br />'.
                                                   &mt('Consequently, the user was not created.'));                                                    &mt('Consequently, the user was not created.').'</li>');
                                         next;                                          next;
                                     }                                      }
                                 }                                  }
                             }                              }
                         }                          }
                           my $usertype = 'unofficial';
                           if (ref($rulematch{$user}) eq 'HASH') {
                               if ($rulematch{$user}{'username'}) {
                                   $usertype = 'official';
                               }
                           }
                           unless ($cancreate{$usertype}) {
                               my $showtype = $longtypes{$usertype};
                               $r->print('<li>'.
                                         &mt('[_1]: The user does not exist, and you are not permitted to create users of type: [_2].','<b>'.$username.'</b>',$showtype).'</li>');
                               next;
                           }
                       } elsif ($id ne '') {
                           if (exists($checkids{$user})) {
                               $checkid = 1; 
                               if (ref($alerts{'id'}) eq 'HASH') {
                                   if (ref($alerts{'id'}{$userdomain}) eq 'HASH') {
                                       if ($alerts{'id'}{$userdomain}{$username}) {
                                           $r->print('<li>'.
                                                     &mt('[_1]: has a student/employee ID matching the format at your institution, but the ID is not found by your directory service.',
                                                     '<b>'.$username.'</b>').'<br />'.
                                                     &mt('Consequently, the ID was not changed.').'</li>');
                                           $id = '';
                                       }
                                   }
                               }
                           }
                     }                      }
                     if ($password || $env{'form.login'} eq 'loc') {                      my $multiple = 0;
                         my $multiple = 0;                      my ($userresult,$authresult,$roleresult,$idresult);
                         my ($userresult,$authresult,$roleresult,$idresult);                      my (%userres,%authres,%roleres,%idres);
                         my (%userres,%authres,%roleres,%idres);                      my $singlesec = '';
                         my $singlesec = '';                      if ($role eq 'st') {
                         if ($role eq 'st') {                          if (($context eq 'domain') && ($changeauth eq 'Yes') && (!$newuser)) {
                             my $sec;                              if ((&Apache::lonnet::allowed('mau',$userdomain)) &&
                                   (&Apache::lonnet::homeserver($username,$userdomain) ne 'no_host')) {
                                   if ((($amode =~ /^krb4|krb5|internal$/) && $password ne '') ||
                                        ($amode eq 'localauth')) {
                                       $authresult =
                                           &Apache::lonnet::modifyuserauth($userdomain,$username,$amode,$password);
                                   }
                               }
                           }
                           my $sec;
                           if (ref($userinfo{$i}{'sections'}) eq 'ARRAY') {
                             if (@secs > 0) {                              if (@secs > 0) {
                                 $sec = $secs[0];                                  $sec = $secs[0];
                             }                              }
                             &modifystudent($userdomain,$username,$cid,$sec,                          }
                                            $desiredhost,$context);                          if ($userdomain ne $env{'request.role.domain'}) {
                             $roleresult =                              my $item = "/$crsdom/$crsnum" ;
                                 &Apache::lonnet::modifystudent                              if ($sec ne '') {
                                     ($userdomain,$username,$id,$amode,$password,                                  $item .= "/$sec";
                                      $fname,$mname,$lname,$gen,$sec,$enddate,                              }
                                      $startdate,$env{'form.forceid'},                              $item .= '_st';
                                      $desiredhost,$email,'manual','',$cid,                              next if (&restricted_dom($context,$item,$userdomain,$username,$role,$startdate,
                                      '',$context,$inststatus,$credits);                                                       $enddate,$crsdom,$crsnum,$sec,$credits,\%process_by,
                             $userresult = $roleresult;                                                       \%instdoms,\%got_role_approvals,\%got_instdoms,\%reject,
                         } else {                                                       \%pending,\%notifydc,\%status,\%unauthorized,\%currqueued));
                             if ($role ne '') {                           }
                                 if ($context eq 'course' || $setting eq 'course') {                          &modifystudent($userdomain,$username,$cid,$sec,
                                     if ($customroles{$role}) {                                         $desiredhost,$context);
                                         $role = 'cr_'.$env{'user.domain'}.'_'.                          $roleresult =
                                                 $env{'user.name'}.'_'.$role;                              &Apache::lonnet::modifystudent
                                     }                                  ($userdomain,$username,$id,$amode,$password,
                                     if (($role ne 'cc') && ($role ne 'co')) {                                    $fname,$mname,$lname,$gen,$sec,$enddate,
                                         if (@secs > 1) {                                   $startdate,$env{'form.forceid'},
                                             $multiple = 1;                                   $desiredhost,$email,'manual','',$cid,
                                             foreach my $sec (@secs) {                                   '',$context,$inststatus,$credits);
                                                 ($userres{$sec},$authres{$sec},$roleres{$sec},$idres{$sec}) =                          $userresult = $roleresult;
                                                 &modifyuserrole($context,$setting,                      } else {
                                                     $changeauth,$cid,$userdomain,$username,                          my $possrole;
                                                     $id,$amode,$password,$fname,                          if ($role ne '') {
                                                     $mname,$lname,$gen,$sec,                              if ($context eq 'course' || $setting eq 'course') {
                                                     $env{'form.forceid'},$desiredhost,                                  if ($customroles{$role}) {
                                                     $email,$role,$enddate,                                      $role = 'cr_'.$env{'user.domain'}.'_'.
                                                     $startdate,$checkid,$inststatus);                                              $env{'user.name'}.'_'.$role;
                                   }
                                   $possrole = $role;
                                   if ($possrole =~ /^cr_/) {
                                       $possrole =~ s{_}{/}g;
                                   }
                                   if (($role ne 'cc') && ($role ne 'co')) {
                                      if (@secs > 1) {
                                           $multiple = 1;
                                           my $prefix = "/$crsdom/$crsnum";
                                           foreach my $sec (@secs) {
                                               if ($userdomain ne $env{'request.role.domain'}) {
                                                   my $item = $prefix;
                                                   if ($sec ne '') {
                                                       $item .= "/$sec";
                                                   }
                                                   $item .= '_'.$possrole;
                                                   next if (&restricted_dom($context,$item,$userdomain,$username,$possrole,
                                                                            $startdate,$enddate,$crsdom,$crsnum,$sec,
                                                                            $credits,\%process_by,\%instdoms,\%got_role_approvals,
                                                                            \%got_instdoms,\%reject,\%pending,\%notifydc,
                                                                            \%status,\%unauthorized,\%currqueued));
                                             }                                              }
                                         } elsif (@secs > 0) {                                              ($userres{$sec},$authres{$sec},$roleres{$sec},$idres{$sec}) =
                                             $singlesec = $secs[0];                                              &modifyuserrole($context,$setting,
                                                   $changeauth,$cid,$userdomain,$username,
                                                   $id,$amode,$password,$fname,
                                                   $mname,$lname,$gen,$sec,
                                                   $env{'form.forceid'},$desiredhost,
                                                   $email,$role,$enddate,
                                                   $startdate,$checkid,$inststatus);
                                         }                                          }
                                       } elsif (@secs > 0) {
                                           $singlesec = $secs[0];
                                     }                                      }
                                 }                                  }
                               } else {
                                   $possrole = $role;
                             }                              }
                             if (!$multiple) {                          }
                                 ($userresult,$authresult,$roleresult,$idresult) =                           if (!$multiple) {
                                     &modifyuserrole($context,$setting,                              if (($userdomain ne $env{'request.role.domain'}) && ($role ne '')) {
                                                     $changeauth,$cid,$userdomain,$username,                                   my $item = "/$crsdom/$crsnum";
                                                     $id,$amode,$password,$fname,                                  if ($singlesec ne '') {
                                                     $mname,$lname,$gen,$singlesec,                                      $item .= "/$singlesec";
                                                     $env{'form.forceid'},$desiredhost,                                  }
                                                     $email,$role,$enddate,$startdate,                                  $item .= '_'.$possrole;
                                                     $checkid,$inststatus);                                  next if (&restricted_dom($context,$item,$userdomain,$username,$possrole,$startdate,$enddate,
                                                            $crsdom,$crsnum,$singlesec,$credits,\%process_by,\%instdoms,
                                                            \%got_role_approvals,\%got_instdoms,\%reject,\%pending,\%notifydc,
                                                            \%status,\%unauthorized,\%currqueued));
                             }                              }
                               ($userresult,$authresult,$roleresult,$idresult) = 
                                   &modifyuserrole($context,$setting,
                                                   $changeauth,$cid,$userdomain,$username, 
                                                   $id,$amode,$password,$fname,
                                                   $mname,$lname,$gen,$singlesec,
                                                   $env{'form.forceid'},$desiredhost,
                                                   $email,$role,$enddate,$startdate,
                                                   $checkid,$inststatus);
                         }                          }
                         if ($multiple) {                      }
                             foreach my $sec (sort(keys(%userres))) {                      if ($multiple) {
                                 $flushc =                          foreach my $sec (sort(keys(%userres))) {
                               $flushc =
                                 &user_change_result($r,$userres{$sec},$authres{$sec},                                  &user_change_result($r,$userres{$sec},$authres{$sec},
                                                     $roleres{$sec},$idres{$sec},\%counts,$flushc,                                                      $roleres{$sec},$idres{$sec},\%counts,$flushc,
                                                     $username,$userdomain,\%userchg);                                                      $username,$userdomain,\%userchg);
   
                             }  
                         } else {  
                             $flushc =   
                                 &user_change_result($r,$userresult,$authresult,  
                                                     $roleresult,$idresult,\%counts,$flushc,  
                                                     $username,$userdomain,\%userchg);  
                         }                          }
                     } else {                      } else {
                         if ($context eq 'course') {                          $flushc = 
                             $r->print('<br />'.                               &user_change_result($r,$userresult,$authresult,
       &mt('[_1]: Unable to enroll. No password specified.','<b>'.$username.'</b>')                                                  $roleresult,$idresult,\%counts,$flushc,
                                      );                                                  $username,$userdomain,\%userchg);
                         } elsif ($context eq 'author') {  
                             $r->print('<br />'.  
       &mt('[_1]: Unable to add co-author. No password specified.','<b>'.$username.'</b>')  
                                      );  
                         } else {  
                             $r->print('<br />'.  
       &mt('[_1]: Unable to add user. No password specified.','<b>'.$username.'</b>')  
                                      );  
                         }  
                     }                      }
                 }                  }
             }                  &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,'last user');
         } # end of foreach (@userdata)              } # end of loop
               $r->print('</ul>');
               &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
           }
         # Flush the course logs so reverse user roles immediately updated          # Flush the course logs so reverse user roles immediately updated
         $r->register_cleanup(\&Apache::lonnet::flushcourselogs);          $r->register_cleanup(\&Apache::lonnet::flushcourselogs);
         $r->print("</p>\n<p>\n".&mt('Processed [quant,_1,user].',$counts{'user'}).          $r->print("</p>\n<p>\n".&mt('Processed [quant,_1,user].',$counts{'user'}).
                   "</p>\n");                    "</p>\n");
         if ($counts{'role'} > 0) {          if ($counts{'role'} > 0) {
             $r->print("<p>\n".              $r->print("<p>\n".
                       &mt('Roles added for [quant,_1,user].',$counts{'role'}).' '.&mt('If a user is currently logged-in to LON-CAPA, any new roles which are active will be available when the user next logs in.')."</p>\n");                        &mt('Roles added for [quant,_1,user].',$counts{'role'}).' '.
                         &mt('If a user is currently logged-in to LON-CAPA, any new roles which are active will be available when the user next logs in.').
                         "</p>\n");
         } else {          } else {
             $r->print('<p>'.&mt('No roles added').'</p>');              $r->print('<p>'.&mt('No roles added').'</p>');
         }          }
Line 4674  sub upfile_drop_add { Line 5583  sub upfile_drop_add {
                           $counts{'auth'})."</p>\n");                            $counts{'auth'})."</p>\n");
         }          }
         $r->print(&print_namespacing_alerts($domain,\%alerts,\%curr_rules));          $r->print(&print_namespacing_alerts($domain,\%alerts,\%curr_rules));
           $r->print(&passwdrule_alerts($domain,\%showpasswdrules));
           if ((keys(%reject)) || (keys(%unauthorized))) {
               $r->print(&print_roles_rejected($context,\%reject,\%unauthorized));
           }
           if ((keys(%pending)) || (keys(%currqueued))) {
               $r->print(&print_roles_queued($context,\%pending,\%notifydc,\%currqueued));
           }
         #####################################          #####################################
         # Display list of students to drop  #          # Display list of students to drop  #
         #####################################          #####################################
Line 4682  sub upfile_drop_add { Line 5598  sub upfile_drop_add {
             #  Get current classlist              #  Get current classlist
             my $classlist = &Apache::loncoursedata::get_classlist();              my $classlist = &Apache::loncoursedata::get_classlist();
             if (! defined($classlist)) {              if (! defined($classlist)) {
                 $r->print('<form name="studentform" method="post" action="/adm/createuser">'.                  $r->print('<p class="LC_info">'.
                           '<input type="hidden" name="action" value="'.$env{'form.action'}.'" />'.                            &mt('There are no students with current/future access to the course.').
                           '<p class="LC_info">'.&mt('There are no students with current/future access to the course.').'</p>'.                            '</p>'."\n");
                           '</form>'."\n");  
             } elsif (ref($classlist) eq 'HASH') {              } elsif (ref($classlist) eq 'HASH') {
                 # Remove the students we just added from the list of students.                  # Remove the students we just added from the list of students.
                 foreach my $line (@userdata) {                  foreach my $line (@userdata) {
Line 4701  sub upfile_drop_add { Line 5616  sub upfile_drop_add {
             }              }
         }          }
     } # end of unless      } # end of unless
     if ($env{'form.fullup'} ne 'yes') {      return 'ok';
         $r->print('</form>');  
     }  
 }  }
   
 sub print_namespacing_alerts {  sub print_namespacing_alerts {
Line 4746  sub print_namespacing_alerts { Line 5659  sub print_namespacing_alerts {
     }      }
 }  }
   
   sub passwdrule_alerts {
       my ($domain,$passwdrules) = @_;
       my $warning;
       if (ref($passwdrules) eq 'HASH') {
           my %showrules = %{$passwdrules};
           if (keys(%showrules)) {
               my %passwdconf = &Apache::lonnet::get_passwdconf($domain);
               $warning = '<b>'.&mt('Password requirement(s) unmet for one or more users:').'</b><ul>';
               if ($showrules{'min'}) {
                   my $min = $passwdconf{'min'};
                   if ($min eq '') {
                       $min = $Apache::lonnet::passwdmin;
                   }
                   $warning .= '<li>'.&mt('minimum [quant,_1,character]',$min).'</li>';
               }
               if ($showrules{'max'}) {
                   $warning .= '<li>'.&mt('maximum [quant,_1,character]',$passwdconf{'max'}).'</li>';
               }
               if ($showrules{'uc'}) {
                   $warning .= '<li>'.&mt('contain at least one upper case letter').'</li>';
               }
               if ($showrules{'lc'}) {
                   $warning .= '<li>'.&mt('contain at least one lower case letter').'</li>';
               }
               if ($showrules{'num'}) {
                   $warning .= '<li>'.&mt('contain at least one number').'</li>';
               }
               if ($showrules{'spec'}) {
                   $warning .= '<li>'.&mt('contain at least one non-alphanumeric').'</li>';
               }
               $warning .= '</ul>';
           }
       }
       return $warning;
   }
   
 sub user_change_result {  sub user_change_result {
     my ($r,$userresult,$authresult,$roleresult,$idresult,$counts,$flushc,      my ($r,$userresult,$authresult,$roleresult,$idresult,$counts,$flushc,
         $username,$userdomain,$userchg) = @_;          $username,$userdomain,$userchg) = @_;
     my $okresult = 0;      my $okresult = 0;
       my @status;
     if ($userresult ne 'ok') {      if ($userresult ne 'ok') {
         if ($userresult =~ /^error:(.+)$/) {          if ($userresult =~ /^error:(.+)$/) {
             my $error = $1;              my $error = $1;
             $r->print('<br />'.              push(@status,
                   &mt('[_1]: Unable to add/modify: [_2]','<b>'.$username.':'.$userdomain.'</b>',$error));                   &mt('[_1]: Unable to add/modify: [_2]','<b>'.$username.':'.$userdomain.'</b>',$error));
         }          }
     } else {      } else {
         $counts->{'user'} ++;          $counts->{'user'} ++;
Line 4763  sub user_change_result { Line 5713  sub user_change_result {
     if ($authresult ne 'ok') {      if ($authresult ne 'ok') {
         if ($authresult =~ /^error:(.+)$/) {          if ($authresult =~ /^error:(.+)$/) {
             my $error = $1;              my $error = $1;
             $r->print('<br />'.              push(@status, 
                   &mt('[_1]: Unable to modify authentication: [_2]','<b>'.$username.':'.$userdomain.'</b>',$error));                   &mt('[_1]: Unable to modify authentication: [_2]','<b>'.$username.':'.$userdomain.'</b>',$error));
         }           } 
     } else {      } else {
         $counts->{'auth'} ++;          $counts->{'auth'} ++;
Line 4773  sub user_change_result { Line 5723  sub user_change_result {
     if ($roleresult ne 'ok') {      if ($roleresult ne 'ok') {
         if ($roleresult =~ /^error:(.+)$/) {          if ($roleresult =~ /^error:(.+)$/) {
             my $error = $1;              my $error = $1;
             $r->print('<br />'.              push(@status,
                   &mt('[_1]: Unable to add role: [_2]','<b>'.$username.':'.$userdomain.'</b>',$error));                   &mt('[_1]: Unable to add role: [_2]','<b>'.$username.':'.$userdomain.'</b>',$error));
         }          }
     } else {      } else {
         $counts->{'role'} ++;          $counts->{'role'} ++;
Line 4783  sub user_change_result { Line 5733  sub user_change_result {
     if ($okresult) {      if ($okresult) {
         $flushc++;          $flushc++;
         $userchg->{$username.':'.$userdomain}=1;          $userchg->{$username.':'.$userdomain}=1;
         $r->print('. ');  
         if ($flushc>15) {          if ($flushc>15) {
             $r->rflush;              $r->rflush;
             $flushc=0;              $flushc=0;
         }          }
     }      }
     if ($idresult) {      if ($idresult) {
         $r->print($idresult);          push(@status,$idresult);
       }
       if (@status) {
           $r->print('<li>'.join('<br />',@status).'</li>');
     }      }
     return $flushc;      return $flushc;
 }  }
Line 4831  sub update_user_list { Line 5783  sub update_user_list {
     if ($context eq 'course') {      if ($context eq 'course') {
         $crstype = &Apache::loncommon::course_type();          $crstype = &Apache::loncommon::course_type();
     }      }
     my @changelist;      my (@changelist,%got_role_approvals,%got_instdoms,%process_by,%instdoms,
           %pending,%reject,%notifydc,%status,%unauthorized,%currqueued);
     if ($choice eq 'drop') {      if ($choice eq 'drop') {
         @changelist = &Apache::loncommon::get_env_multiple('form.droplist');          @changelist = &Apache::loncommon::get_env_multiple('form.droplist');
     } else {      } else {
Line 4861  sub update_user_list { Line 5814  sub update_user_list {
     foreach my $item (@changelist) {      foreach my $item (@changelist) {
         my ($role,$uname,$udom,$cid,$sec,$scope,$result,$type,$locktype,          my ($role,$uname,$udom,$cid,$sec,$scope,$result,$type,$locktype,
             @sections,$scopestem,$singlesec,$showsecs,$warn_singlesec,              @sections,$scopestem,$singlesec,$showsecs,$warn_singlesec,
             $nothingtodo,$keepnosection,$credits);              $nothingtodo,$keepnosection,$credits,$instsec,$cdom,$cnum);
         if ($choice eq 'drop') {          if ($choice eq 'drop') {
             ($uname,$udom,$sec) = split(/:/,$item,-1);              ($uname,$udom,$sec) = split(/:/,$item,-1);
             $role = 'st';              $role = 'st';
Line 4874  sub update_user_list { Line 5827  sub update_user_list {
                 $scope = $scopestem.'/'.$sec;                  $scope = $scopestem.'/'.$sec;
             }              }
         } elsif ($context eq 'course') {          } elsif ($context eq 'course') {
             ($uname,$udom,$role,$sec,$type,$locktype,$credits) =              ($uname,$udom,$role,$sec,$type,$locktype,$credits,$instsec) =
                 split(/\:/,$item);                  split(/\:/,$item,8);
               $instsec = &unescape($instsec);
             $cid = $env{'request.course.id'};              $cid = $env{'request.course.id'};
               $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
               $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
             $scopestem = '/'.$cid;              $scopestem = '/'.$cid;
             $scopestem =~s/\_/\//g;              $scopestem =~s/\_/\//g;
             if ($sec eq '') {              if ($sec eq '') {
Line 4887  sub update_user_list { Line 5843  sub update_user_list {
         } elsif ($context eq 'author') {          } elsif ($context eq 'author') {
             ($uname,$udom,$role) = split(/\:/,$item,-1);              ($uname,$udom,$role) = split(/\:/,$item,-1);
             $scope = '/'.$env{'user.domain'}.'/'.$env{'user.name'};              $scope = '/'.$env{'user.domain'}.'/'.$env{'user.name'};
               $cdom = $env{'user.domain'};
               $cnum = $env{'user.name'};
         } elsif ($context eq 'domain') {          } elsif ($context eq 'domain') {
             if ($setting eq 'domain') {              if ($setting eq 'domain') {
                 ($role,$uname,$udom) = split(/\:/,$item,-1);                  ($role,$uname,$udom) = split(/\:/,$item,-1);
                 $scope = '/'.$env{'request.role.domain'}.'/';                  $scope = '/'.$env{'request.role.domain'}.'/';
                   $cdom = $env{'request.role.domain'};
             } elsif ($setting eq 'author') {               } elsif ($setting eq 'author') { 
                 ($uname,$udom,$role,$scope) = split(/\:/,$item);                  ($uname,$udom,$role,$scope) = split(/\:/,$item);
                   (undef,$cdom,$cnum) = split(/\//,$scope);
             } elsif ($setting eq 'course') {              } elsif ($setting eq 'course') {
                 ($uname,$udom,$role,$cid,$sec,$type,$locktype,$credits) =                   ($uname,$udom,$role,$cid,$sec,$type,$locktype,$credits,$instsec) = 
                     split(/\:/,$item);                      split(/\:/,$item,9);
                   ($cdom,$cnum) = split('_',$cid);
                   $instsec = &unescape($instsec);
                 $scope = '/'.$cid;                  $scope = '/'.$cid;
                 $scope =~s/\_/\//g;                  $scope =~s/\_/\//g;
                 if ($sec ne '') {                  if ($sec ne '') {
Line 4917  sub update_user_list { Line 5879  sub update_user_list {
             $end = $now;               $end = $now; 
             if ($role eq 'st') {              if ($role eq 'st') {
                 $result =                   $result = 
                     &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits);                      &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
             } else {              } else {
                 $result =                   $result = 
                     &Apache::lonnet::revokerole($udom,$uname,$scope,$role,                      &Apache::lonnet::revokerole($udom,$uname,$scope,$role,
Line 4925  sub update_user_list { Line 5887  sub update_user_list {
             }              }
         } elsif ($choice eq 'delete') {          } elsif ($choice eq 'delete') {
             if ($role eq 'st') {              if ($role eq 'st') {
                 &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$now,$start,$type,$locktype,$cid,'',$context,$credits);                  &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$now,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
             }              }
             $result =              $result =
                 &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$now,                  &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$now,
Line 4936  sub update_user_list { Line 5898  sub update_user_list {
                 $start = $startdate;                   $start = $startdate; 
                 $end = $enddate;                  $end = $enddate;
             }              }
               my $id = $scope.'_'.$role;
             if ($choice eq 'reenable') {              if ($choice eq 'reenable') {
                   next if (&restricted_dom($context,$id,$udom,$uname,$role,$now,$end,$cdom,$cnum,
                                            $sec,$credits,\%process_by,\%instdoms,\%got_role_approvals,
                                            \%got_instdoms,\%reject,\%pending,\%notifydc,
                                            \%status,\%unauthorized,\%currqueued));
                 if ($role eq 'st') {                  if ($role eq 'st') {
                     $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits);                      $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
                 } else {                  } else {
                     $result =                       $result = 
                         &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,                          &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,
                                                     $now,'','',$context);                                                      $now,'','',$context);
                 }                  }
             } elsif ($choice eq 'activate') {              } elsif ($choice eq 'activate') {
                   next if (&restricted_dom($context,$id,$udom,$uname,$role,$now,$end,$cdom,$cnum,
                                            $sec,$credits,\%process_by,\%instdoms,\%got_role_approvals,
                                            \%got_instdoms,\%reject,\%pending,\%notifydc,
                                            \%status,\%unauthorized,\%currqueued));
                 if ($role eq 'st') {                  if ($role eq 'st') {
                     $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits);                      $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
                 } else {                  } else {
                     $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,                      $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,
                                             $now,'','',$context);                                              $now,'','',$context);
                 }                  }
             } elsif ($choice eq 'chgdates') {              } elsif ($choice eq 'chgdates') {
                   next if (&restricted_dom($context,$id,$udom,$uname,$role,$start,$end,$cdom,$cnum,
                                            $sec,$credits,\%process_by,\%instdoms,\%got_role_approvals,
                                            \%got_instdoms,\%reject,\%pending,\%notifydc,
                                            \%status,\%unauthorized,\%currqueued));
                 if ($role eq 'st') {                  if ($role eq 'st') {
                     $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits);                      $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
                 } else {                  } else {
                     $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,                      $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,
                                                 $start,'','',$context);                                                  $start,'','',$context);
Line 5023  sub update_user_list { Line 5998  sub update_user_list {
                     } else {                      } else {
                         if ($role eq 'st') {                          if ($role eq 'st') {
                             $result =                               $result = 
                                 &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,undef,$end,$start,$type,$locktype,$cid,'',$context,$credits);                                  &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,undef,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
                         } else {                          } else {
                             my $newscope = $scopestem;                              my $newscope = $scopestem;
                             $result = &Apache::lonnet::assignrole($udom,$uname,$newscope,$role,$end,$start,'','',$context);                              $result = &Apache::lonnet::assignrole($udom,$uname,$newscope,$role,$end,$start,'','',$context);
Line 5037  sub update_user_list { Line 6012  sub update_user_list {
                     foreach my $newsec (@newsecs) {                      foreach my $newsec (@newsecs) {
                         if (!grep(/^\Q$newsec\E$/,@retained)) {                          if (!grep(/^\Q$newsec\E$/,@retained)) {
                             if ($role eq 'st') {                              if ($role eq 'st') {
                                 $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$newsec,$end,$start,$type,$locktype,$cid,'',$context,$credits);                                  $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$newsec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
                                 if (@newsecs > 1) {                                  if (@newsecs > 1) {
                                     my $showsingle;                                       my $showsingle; 
                                     if ($newsec eq '') {                                      if ($newsec eq '') {
Line 5161  sub update_user_list { Line 6136  sub update_user_list {
             $r->print(&make_dates_default($startdate,$enddate,$context,$crstype));              $r->print(&make_dates_default($startdate,$enddate,$context,$crstype));
         }          }
     }      }
       if ((keys(%reject)) || (keys(%unauthorized))) {
           $r->print(&print_roles_rejected($context,\%reject,\%unauthorized));
       }
       if ((keys(%pending)) || (keys(%currqueued))) {
           $r->print(&print_roles_queued($context,\%pending,\%notifydc,\%currqueued));
       }
     my $linktext = &mt('Display User Lists');      my $linktext = &mt('Display User Lists');
     if ($choice eq 'drop') {      if ($choice eq 'drop') {
         $linktext = &mt('Display current class roster');          $linktext = &mt('Display current class roster');
Line 5215  sub active_student_roles { Line 6196  sub active_student_roles {
   
 sub section_check_js {  sub section_check_js {
     my $groupslist= &get_groupslist();      my $groupslist= &get_groupslist();
       my %js_lt = &Apache::lonlocal::texthash(
           mayn   => 'may not be used as the name for a section, as it is a reserved word.',
           plch   => 'Please choose a different section name.',
           mnot   => 'may not be used as a section name, as it is the name of a course group.',
           secn   => 'Section names and group names must be distinct. Please choose a different section name.',
       );
       &js_escape(\%js_lt);
     return <<"END";      return <<"END";
 function validate(caller) {  function validate(caller) {
     var groups = new Array($groupslist);      var groups = new Array($groupslist);
     var secname = caller.value;      var secname = caller.value;
     if ((secname == 'all') || (secname == 'none')) {      if ((secname == 'all') || (secname == 'none')) {
         alert("'"+secname+"' may not be used as the name for a section, as it is a reserved word.\\nPlease choose a different section name.");          alert("'"+secname+"' $js_lt{'mayn'}\\n$js_lt{'plch'}");
         return 'error';          return 'error';
     }      }
     if (secname != '') {      if (secname != '') {
         for (var k=0; k<groups.length; k++) {          for (var k=0; k<groups.length; k++) {
             if (secname == groups[k]) {              if (secname == groups[k]) {
                 alert("'"+secname+"' may not be used as the name for a section, as it is the name of a course group.\\nSection names and group names must be distinct. Please choose a different section name.");                  alert("'"+secname+"' $js_lt{'mnot'}\\n$js_lt{'secn'}");
                 return 'error';                  return 'error';
             }              }
         }          }
Line 5237  END Line 6225  END
 }  }
   
 sub set_login {  sub set_login {
     my ($dom,$authformkrb,$authformint,$authformloc) = @_;      my ($dom,$authformkrb,$authformint,$authformloc,$authformlti) = @_;
     my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom);      my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom);
     my $response;      my $response;
     my ($authnum,%can_assign) =      my ($authnum,%can_assign) =
Line 5259  sub set_login { Line 6247  sub set_login {
                          '<td>'.$authformloc.'</td>'.                           '<td>'.$authformloc.'</td>'.
                          &Apache::loncommon::end_data_table_row()."\n";                           &Apache::loncommon::end_data_table_row()."\n";
         }          }
           if ($can_assign{'lti'}) {
               $response .= &Apache::loncommon::start_data_table_row().
                            '<td>'.$authformlti.'</td>'.
                            &Apache::loncommon::end_data_table_row()."\n";
           }
         $response .= &Apache::loncommon::end_data_table();          $response .= &Apache::loncommon::end_data_table();
     }      }
     return $response;      return $response;
 }  }
   
 sub course_sections {  sub course_sections {
     my ($sections_count,$role,$current_sec) = @_;      my ($sections_count,$role,$current_sec,$disabled) = @_;
     my $output = '';      my $output = '';
     my @sections = (sort {$a <=> $b} keys(%{$sections_count}));      my @sections = (sort {$a <=> $b} keys(%{$sections_count}));
     my $numsec = scalar(@sections);      my $numsec = scalar(@sections);
     my $is_selected = ' selected="selected"';      my $is_selected = ' selected="selected"';
     if ($numsec <= 1) {      if ($numsec <= 1) {
         $output = '<select name="currsec_'.$role.'" >'."\n".          $output = '<select name="currsec_'.$role.'"'.$disabled.'>'."\n".
                   '  <option value="">'.&mt('Select').'</option>'."\n";                    '  <option value="">'.&mt('Select').'</option>'."\n";
         if ($current_sec eq 'none') {          if ($current_sec eq 'none') {
             $output .=                     $output .=       
Line 5294  sub course_sections { Line 6287  sub course_sections {
         my $multiple = 4;          my $multiple = 4;
         if (scalar(@sections) < 4) { $multiple = scalar(@sections); }          if (scalar(@sections) < 4) { $multiple = scalar(@sections); }
         if ($role eq 'st') {          if ($role eq 'st') {
             $output .= '>'."\n".              $output .= $disabled.'>'."\n".
                        '  <option value="">'.&mt('Select').'</option>'."\n";                         '  <option value="">'.&mt('Select').'</option>'."\n";
             if ($current_sec eq 'none') {              if ($current_sec eq 'none') {
                 $output .=                   $output .= 
Line 5304  sub course_sections { Line 6297  sub course_sections {
                        '  <option value="">'.&mt('No section')."</option>\n";                         '  <option value="">'.&mt('No section')."</option>\n";
             }              }
         } else {          } else {
             $output .= 'multiple="multiple" size="'.$multiple.'">'."\n";              $output .= 'multiple="multiple" size="'.$multiple.'"'.$disabled.'>'."\n";
         }          }
         foreach my $sec (@sections) {          foreach my $sec (@sections) {
             if ($current_sec eq $sec) {              if ($current_sec eq $sec) {
Line 5385  sub setsections_javascript { Line 6378  sub setsections_javascript {
                     mnot => 'may not be used as a section name, as it is the name of a course group.',                      mnot => 'may not be used as a section name, as it is the name of a course group.',
                     secn => 'Section names and group names must be distinct. Please choose a different section name.',                      secn => 'Section names and group names must be distinct. Please choose a different section name.',
                     nonw => 'Section names may only contain letters or numbers.',                      nonw => 'Section names may only contain letters or numbers.',
                  );                                   );
       &js_escape(\%alerts);
     $setsection_js .= <<"ENDSECCODE";      $setsection_js .= <<"ENDSECCODE";
   
 function setSections(formname,crstype) {  function setSections(formname,crstype) {
Line 5520  sub can_create_user { Line 6514  sub can_create_user {
     my $cancreate = 1;      my $cancreate = 1;
     if (&Apache::lonnet::allowed('mau',$dom)) {      if (&Apache::lonnet::allowed('mau',$dom)) {
         return $cancreate;          return $cancreate;
       } elsif ($context eq 'domain') {
           $cancreate = 0;
           return $cancreate;
     }      }
     if (ref($domconf{'usercreation'}) eq 'HASH') {      if (ref($domconf{'usercreation'}) eq 'HASH') {
         if (ref($domconf{'usercreation'}{'cancreate'}) eq 'HASH') {          if (ref($domconf{'usercreation'}{'cancreate'}) eq 'HASH') {
Line 5599  sub can_modify_userinfo { Line 6596  sub can_modify_userinfo {
     return %canmodify;      return %canmodify;
 }  }
   
   sub can_change_internalpass {
       my ($uname,$udom,$crstype,$permission) = @_;
       my $canchange;
       if (&Apache::lonnet::allowed('mau',$udom)) {
           $canchange = 1;
       } elsif ((ref($permission) eq 'HASH') && ($permission->{'mip'}) &&
                ($udom eq $env{'request.role.domain'})) {
           unless ($env{'course.'.$env{'request.course.id'}.'.internal.nopasswdchg'}) {
               my ($cnum,$cdom) = &get_course_identity();
               if ((&Apache::lonnet::is_course_owner($cdom,$cnum)) && ($udom eq $env{'user.domain'})) {
                   my @userstatuses = ('default');
                   my %userenv = &Apache::lonnet::userenvironment($udom,$uname,'inststatus');
                   if ($userenv{'inststatus'} ne '') {
                       @userstatuses =  split(/:/,$userenv{'inststatus'});
                   }
                   my $noupdate = 1;
                   my %passwdconf = &Apache::lonnet::get_passwdconf($cdom);
                   if (ref($passwdconf{'crsownerchg'}) eq 'HASH') {
                       if (ref($passwdconf{'crsownerchg'}{'for'}) eq 'ARRAY') {
                           foreach my $status (@userstatuses) {
                               if (grep(/^\Q$status\E$/,@{$passwdconf{'crsownerchg'}{'for'}})) {
                                   undef($noupdate);
                                   last;
                               }
                           }
                       }
                   }
                   if ($noupdate) {
                       return;
                   }
                   my %owned = &Apache::lonnet::courseiddump($cdom,'.',1,'.',
                                                             $env{'user.name'}.':'.$env{'user.domain'},
                                                             undef,undef,undef,'.');
                   my %roleshash = &Apache::lonnet::get_my_roles($uname,$udom,'userroles',
                                                                 ['active','future']);
                   foreach my $key (keys(%roleshash)) {
                       my ($name,$domain,$role) = split(/:/,$key);
                       if ($role eq 'st') {
                           next if (($name eq $cnum) && ($domain eq $cdom));
                           if ($owned{$domain.'_'.$name}) {
                               if (ref($owned{$domain.'_'.$name}) eq 'HASH') {
                                   if ($owned{$domain.'_'.$name}{'nopasswdchg'}) {
                                       $noupdate = 1;
                                       last;
                                   }
                               }
                           } else {
                               $noupdate = 1;
                               last;
                           }
                       } else {
                           $noupdate = 1;
                           last;
                       }
                   }
                   unless ($noupdate) {
                       $canchange = 1;
                   }
               }
           }
       }
       return $canchange;
   }
   
 sub check_usertype {  sub check_usertype {
     my ($dom,$uname,$rules,$curr_rules,$got_rules) = @_;      my ($dom,$uname,$rules,$curr_rules,$got_rules) = @_;
     my $usertype;      my $usertype;
Line 5662  sub roles_by_context { Line 6723  sub roles_by_context {
     } elsif ($context eq 'author') {      } elsif ($context eq 'author') {
         @allroles = ('ca','aa');          @allroles = ('ca','aa');
     } elsif ($context eq 'domain') {      } elsif ($context eq 'domain') {
         @allroles = ('li','ad','dg','sc','au','dc');          @allroles = ('li','ad','dg','dh','da','sc','au','dc');
     }      }
     return @allroles;      return @allroles;
 }  }
Line 5720  sub get_permission { Line 6781  sub get_permission {
                 }                  }
             }              }
         }          }
           if ($env{'request.course.id'}) {
               my $user;
               if (($env{'user.name'} ne '') && ($env{'user.domain'} ne '')) {
                   $user = $env{'user.name'}.':'.$env{'user.domain'};
               }
               if (($user ne '') && ($env{'course.'.$env{'request.course.id'}.'.internal.courseowner'} eq
                                     $user)) {
                   $permission{'owner'} = 1;
                   if (&Apache::lonnet::allowed('mip',$env{'request.course.id'})) {
                       $permission{'mip'} = 1;
                   }
               } elsif (($user ne '') && ($env{'course.'.$env{'request.course.id'}.'.internal.co-owners'} ne '')) {
                   if (grep(/^\Q$user\E$/,split(/,/,$env{'course.'.$env{'request.course.id'}.'.internal.co-owners'}))) {
                       $permission{'co-owner'} = 1;
                   }
               }
           }
     } elsif ($context eq 'author') {      } elsif ($context eq 'author') {
         $permission{'cusr'} = &authorpriv($env{'user.name'},$env{'request.role.domain'});          $permission{'cusr'} = &authorpriv($env{'user.name'},$env{'request.role.domain'});
         $permission{'view'} = $permission{'cusr'};          $permission{'view'} = $permission{'cusr'};
Line 5739  sub get_permission { Line 6817  sub get_permission {
         if (&Apache::lonnet::allowed('ccr',$env{'request.role.domain'})) {          if (&Apache::lonnet::allowed('ccr',$env{'request.role.domain'})) {
             $permission{'custom'} = 1;              $permission{'custom'} = 1;
         }          }
         $permission{'view'} = $permission{'cusr'};          if (&Apache::lonnet::allowed('vac',$env{'request.role.domain'})) {
               $permission{'activity'} = 1;
           }
           if (&Apache::lonnet::allowed('vur',$env{'request.role.domain'})) {
               $permission{'view'} = 1;
           }
           if (&Apache::lonnet::allowed('ccc',$env{'request.role.domain'})) {
               $permission{'owner'} = 1;
           }
     }      }
     my $allowed = 0;      my $allowed = 0;
     foreach my $perm (values(%permission)) {      foreach my $key (keys(%permission)) {
         if ($perm) { $allowed=1; last; }          next if (($key eq 'owner') || ($key eq 'co-owner'));
           if ($permission{$key}) { $allowed=1; last; }
     }      }
     return (\%permission,$allowed);      return (\%permission,$allowed);
 }  }
Line 5792  sub get_course_identity { Line 6879  sub get_course_identity {
 }  }
   
 sub dc_setcourse_js {  sub dc_setcourse_js {
     my ($formname,$mode,$context,$showcredits) = @_;      my ($formname,$mode,$context,$showcredits,$domain) = @_;
     my ($dc_setcourse_code,$authen_check);      my ($dc_setcourse_code,$authen_check);
     my $cctext = &Apache::lonnet::plaintext('cc');      my $cctext = &Apache::lonnet::plaintext('cc');
     my $cotext = &Apache::lonnet::plaintext('co');      my $cotext = &Apache::lonnet::plaintext('co');
Line 5801  sub dc_setcourse_js { Line 6888  sub dc_setcourse_js {
     if ($mode eq 'upload') {      if ($mode eq 'upload') {
         $role = 'courserole';          $role = 'courserole';
     } else {      } else {
         $authen_check = &verify_authen($formname,$context);          $authen_check = &verify_authen($formname,$context,$domain);
     }      }
     $dc_setcourse_code = (<<"SCRIPTTOP");      $dc_setcourse_code = (<<"SCRIPTTOP");
 $authen_check  $authen_check
Line 5945  ENDSCRIPT Line 7032  ENDSCRIPT
 }  }
   
 sub verify_authen {  sub verify_authen {
     my ($formname,$context) = @_;      my ($formname,$context,$domain) = @_;
     my %alerts = &authcheck_alerts();      my %alerts = &authcheck_alerts();
     my $finish = "return 'ok';";      my $finish = "return 'ok';";
     if ($context eq 'author') {      if ($context eq 'author') {
         $finish = "document.$formname.submit();";          $finish = "document.$formname.submit();";
     }      }
       my ($numrules,$intargjs) =
           &Apache::loncommon::passwd_validation_js('argpicked',$domain);
     my $outcome = <<"ENDSCRIPT";      my $outcome = <<"ENDSCRIPT";
   
 function auth_check() {  function auth_check() {
Line 5984  function auth_check() { Line 7073  function auth_check() {
                 break;                  break;
             case 'int':              case 'int':
                 alertmsg = '$alerts{'ipass'}';                  alertmsg = '$alerts{'ipass'}';
                   break;
             case 'fsys':              case 'fsys':
                 alertmsg = '$alerts{'ipass'}';                  alertmsg = '$alerts{'ipass'}';
                 break;                  break;
Line 5997  function auth_check() { Line 7087  function auth_check() {
             alert(alertmsg);              alert(alertmsg);
             return;              return;
         }          }
       } else if (logintype == 'int') {
           var numrules = $numrules;
           if (numrules > 0) {
   $intargjs
           }
     }      }
     $finish      $finish
 }  }
Line 6022  sub sectioncheck_alerts { Line 7117  sub sectioncheck_alerts {
                     thwa => 'There was a problem with your course selection',                      thwa => 'There was a problem with your course selection',
                     thwc => 'There was a problem with your community selection',                      thwc => 'There was a problem with your community selection',
                  );                   );
       &js_escape(\%alerts);
     return %alerts;      return %alerts;
 }  }
   
Line 6032  sub authcheck_alerts { Line 7128  sub authcheck_alerts {
                     krb    => 'You need to specify the Kerberos domain.',                      krb    => 'You need to specify the Kerberos domain.',
                     ipass  => 'You need to specify the initial password.',                      ipass  => 'You need to specify the initial password.',
         );          );
       &js_escape(\%alerts);
     return %alerts;      return %alerts;
 }  }
   
Line 6113  sub get_extended_type { Line 7210  sub get_extended_type {
     }      }
     if ($crstype eq 'Community') {      if ($crstype eq 'Community') {
         $type = 'community';          $type = 'community';
       } elsif ($crstype eq 'Placement') {
           $type = 'placement';
     } elsif ($settings{'internal.coursecode'}) {      } elsif ($settings{'internal.coursecode'}) {
         $type = 'official';          $type = 'official';
     } elsif ($settings{'internal.textbook'}) {      } elsif ($settings{'internal.textbook'}) {
Line 6171  sub selfenrollment_administration { Line 7270  sub selfenrollment_administration {
     return (\@in_course,\@in_domain);      return (\@in_course,\@in_domain);
 }  }
   
   sub custom_role_header {
       my ($context,$crstype,$templaterolerefs,$prefix) = @_;
       my %lt = &Apache::lonlocal::texthash(
                    sele => 'Select a Template',
       );
       my ($context_code,$button_code);
       if ($context eq 'domain') {
           $context_code = &custom_coursetype_switch($crstype,$prefix);
       }
       if (ref($templaterolerefs) eq 'ARRAY') {
           foreach my $role (@{$templaterolerefs}) {
               my $display = 'inline';
               if (($context eq 'domain') && ($role eq 'co')) {
                   $display = 'none';
               }
               $button_code .= &make_button_code($role,$crstype,$display,$prefix).' ';
           }
       }
       return <<"END";
   <div class="LC_left_float">
   <fieldset>
   <legend>$lt{'sele'}</legend>
   $button_code
   </fieldset></div>
   $context_code
   <br clear="all" />
   END
   }
   
   sub custom_coursetype_switch {
       my ($crstype,$prefix) = @_;
       my ($checkedcourse,$checkedcommunity);
       if ($crstype eq 'Community') {
           $checkedcommunity = ' checked="checked"';
       } else {
           $checkedcourse = ' checked="checked"';
       }
       my %lt = &Apache::lonlocal::texthash(
           cont => 'Context',
           cour => 'Course',
           comm => 'Community',
       );
       return <<"END";
   <div class="LC_left_float">
   <fieldset>
   <legend>$lt{'cont'}</legend>
   <label>
   <input type="radio" name="${prefix}_custrolecrstype" value="Course"$checkedcourse onclick="javascript:customSwitchType('$prefix');" />
   $lt{'cour'}
   </label>&nbsp;&nbsp;
   <label>
   <input type="radio" name="${prefix}_custrolecrstype" value="Community"$checkedcommunity onclick="javascript:customSwitchType('$prefix');" />
   $lt{'comm'}
   </label>
   </fieldset>
   </div>
   END
   }
   
   sub custom_role_table {
       my ($crstype,$full,$levels,$levelscurrent,$prefix,$add_class,$id) = @_;
       return unless ((ref($full) eq 'HASH') && (ref($levels) eq 'HASH') &&
                      (ref($levelscurrent) eq 'HASH'));
       my %lt=&Apache::lonlocal::texthash (
                       'prv'  => "Privilege",
                       'crl'  => "Course Level",
                       'dml'  => "Domain Level",
                       'ssl'  => "System Level");
       my %cr = (
                  course => '_c',
                  domain => '_d',
                  system => '_s',
                );
   
       my $output=&Apache::loncommon::start_data_table($add_class,$id).
                  &Apache::loncommon::start_data_table_header_row().
                  '<th>'.$lt{'prv'}.'</th><th>'.$lt{'crl'}.'</th><th>'.$lt{'dml'}.
                  '</th><th>'.$lt{'ssl'}.'</th>'.
                  &Apache::loncommon::end_data_table_header_row();
       foreach my $priv (sort(keys(%{$full}))) {
           my $privtext = &Apache::lonnet::plaintext($priv,$crstype);
           $output .= &Apache::loncommon::start_data_table_row().
                     '<td><span id="'.$prefix.$priv.'">'.$privtext.'</span></td>';
           foreach my $type ('course','domain','system') {
               if (($type eq 'system') && ($priv eq 'bre') && ($crstype eq 'Community')) {
                   $output .= '<td>&nbsp;</td>';
               } else {
                   $output .= '<td>'.
                     ($levels->{$type}{$priv}?'<input type="checkbox" id="'.$prefix.$priv.$cr{$type}.'"'.
                     ' name="'.$prefix.$priv.$cr{$type}.'"'.
                     ($levelscurrent->{$type}{$priv}?' checked="checked"':'').' />':'&nbsp;').
                     '</td>';
               }
           }
           $output .= &Apache::loncommon::end_data_table_row();
       }
       $output .= &Apache::loncommon::end_data_table();
       return $output;
   }
   
   sub custom_role_privs {
       my ($privs,$full,$levels,$levelscurrent)= @_;
       return unless ((ref($privs) eq 'HASH') && (ref($full) eq 'HASH') &&
                      (ref($levels) eq 'HASH') && (ref($levelscurrent) eq 'HASH'));
       my %cr = (
                  course => 'cr:c',
                  domain => 'cr:d',
                  system => 'cr:s',
                );
       foreach my $type ('course','domain','system') {
           foreach my $item (split(/\:/,$Apache::lonnet::pr{$cr{$type}})) {
               my ($priv,$restrict)=split(/\&/,$item);
               if (!$restrict) { $restrict='F'; }
               $levels->{$type}->{$priv}=$restrict;
               if ($privs->{$type}=~/\:$priv/) {
                   $levelscurrent->{$type}->{$priv}=1;
               }
               $full->{$priv}=1;
           }
       }
       return;
   }
   
   sub custom_template_roles {
       my ($context,$crstype) = @_;
       my @template_roles = ("in","ta","ep");
       if (($context eq 'domain') || ($context eq 'domprefs')) {
           push(@template_roles,"ad");
       }
       push(@template_roles,"st");
       if ($context eq 'domain') {
           unshift(@template_roles,('co','cc'));
       } else {
           if ($crstype eq 'Community') {
               unshift(@template_roles,'co');
           } else {
               unshift(@template_roles,'cc');
           }
       }
       return @template_roles;
   }
   
   sub custom_roledefs_js {
       my ($context,$crstype,$formname,$full,$templaterolesref,$jsback) = @_;
       my $button_code = "\n";
       my $head_script = "\n";
       my (%roletitlestr,$rolenamestr);
       my %role_titles = (
                           Course    => [],
                           Community => [],
                         );
       $head_script .= '<script type="text/javascript">'."\n"
                      .'// <![CDATA['."\n";
       if (ref($templaterolesref) eq 'ARRAY') {
           if ($context eq 'domain') {
               $rolenamestr = join("','",@{$templaterolesref});
           }
           foreach my $role (@{$templaterolesref}) {
               $head_script .= &make_script_template($role,$crstype,$formname);
               if ($context eq 'domain') {
                   foreach my $type ('Course','Community') {
                       push(@{$role_titles{$type}},&Apache::lonnet::plaintext($role,$type));
                   }
               }
           }
       }
       if ($context eq 'domain') {
           foreach my $type ('Course','Community') {
               $roletitlestr{$type} = join("','",@{$role_titles{$type}});
           }
           my %pt = (
               Community => {
                              cst => &mt('Grant/revoke role of Member'),
                              mdc => &mt('Edit community contents'),
                              pch => &mt('Post discussion on community resources'),
                              pfo => &mt('Print for other users and entire community'),
                            },
               Course    => {
                              cst => &mt('Grant/revoke role of Student'),
                              mdc => &mt('Edit course contents'),
                              pch => &mt('Post discussion on course resources'),
                              pfo => &mt('Print for other users and entire course'),
                            },
           );
           $head_script .= <<"ENDJS";
   function customSwitchType(prefix) {
       var privnames = new Array('cst','mdc','pch','pfo');
       var privtxtcrs = new Array('$pt{Course}{cst}','$pt{Course}{mdc}','$pt{Course}{pch}','$pt{Course}{pfo}');
       var privtxtcom = new Array('$pt{Community}{cst}','$pt{Community}{mdc}','$pt{Community}{pch}','$pt{Community}{pfo}');
       var rolenames = new Array('$rolenamestr');
       var rolescrs = new Array('$roletitlestr{Course}');
       var rolescom = new Array('$roletitlestr{Community}');
       var radio = prefix+'_custrolecrstype';
       if (document.$formname.elements[radio].length > 1) {
           for (var i=0; i<document.$formname.elements[radio].length; i++) {
               if (document.$formname.elements[radio][i].checked) {
                   if ((document.getElementById(prefix+'bre_s')) && (document.getElementById(prefix+'bro_s'))) {
                       if (document.$formname.elements[radio][i].value == 'Community') {
                           if (document.getElementById(prefix+'bre_s').checked) {
                               document.getElementById(prefix+'bro_s').checked = true;
                               document.getElementById(prefix+'bre_s').checked = false;
   
                           }
                           document.getElementById(prefix+'bre_s').style.visibility = 'hidden';
                       } else {
                           document.getElementById(prefix+'bre_s').style.visibility = 'visible';
                           if (document.getElementById(prefix+'bro_s').checked) {
                               document.getElementById(prefix+'bre_s').checked = true;
                               document.getElementById(prefix+'bro_s').checked = false;
                           }
                       }
                   }
                   for (var j=0; j<privnames.length; j++) {
                       if (document.getElementById(prefix+privnames[j])) {
                           if (document.getElementById(prefix+privnames[j])) {
                               if (document.$formname.elements[radio][i].value == 'Course') {
                                   document.getElementById(prefix+privnames[j]).innerHTML = privtxtcrs[j];
                               } else {
                                   document.getElementById(prefix+privnames[j]).innerHTML = privtxtcom[j];
                               }
                           }
                       }
                   }
                   for (var j=0; j<rolenames.length; j++) {
                       if (document.getElementById(prefix+rolenames[j])) {
                           if (document.getElementById(prefix+rolenames[j])) {
                               if (document.$formname.elements[radio][i].value == 'Course') {
                                   document.getElementById(prefix+rolenames[j]).value = rolescrs[j];
                                   if (rolenames[j] == 'cc') {
                                       document.getElementById(prefix+rolenames[j]).style.display = 'inline';
                                   }
                                   if (rolenames[j] == 'co') {
                                       document.getElementById(prefix+rolenames[j]).style.display = 'none';
                                   }
                               } else {
                                   document.getElementById(prefix+rolenames[j]).value = rolescom[j];
                                   if (rolenames[j] == 'cc') {
                                       document.getElementById(prefix+rolenames[j]).style.display = 'none';
                                   }
                                   if (rolenames[j] == 'co') {
                                       document.getElementById(prefix+rolenames[j]).style.display = 'inline';
                                   }
                               }
                           }
                       }
                   }
               }
           }
       }
       return;
   }
   ENDJS
       }
       $head_script .= "\n".$jsback."\n"
                      .'// ]]>'."\n"
                      .'</script>'."\n";
       return $head_script;
   }
   
   # --------------------------------------------------------
   sub make_script_template {
       my ($role,$crstype,$formname) = @_;
       my $return_script = 'function set_'.$role.'(prefix) {'."\n";
       my (%full_by_level,%role_priv);
       foreach my $level ('c','d','s') {
           foreach my $item (split(/\:/,$Apache::lonnet::pr{'cr:'.$level})) {
               next if (($level eq 's') && ($crstype eq 'Community') && ($item eq 'bre&S'));
               my ($priv,$restrict)=split(/\&/,$item);
               $full_by_level{$level}{$priv}=1;
           }
           $role_priv{$level} = {};
           my @temp = split(/:/,$Apache::lonnet::pr{$role.':'.$level});
           foreach my $priv (@temp) {
               my ($priv_item, $dummy) = split(/\&/,$priv);
               $role_priv{$level}{$priv_item} = 1;
           }
       }
       my %to_check = (
                         c => ['c','d','s'],
                         d => ['d','s'],
                         s => ['s'],
                      );
       foreach my $level ('c','d','s') {
           if (ref($full_by_level{$level}) eq 'HASH') {
               foreach my $priv (keys(%{$full_by_level{$level}})) {
                   my $value = 'false';
                   if (ref($to_check{$level}) eq 'ARRAY') {
                       foreach my $lett (@{$to_check{$level}}) {
                           if (exists($role_priv{$lett}{$priv})) {
                               $value = 'true';
                               last;
                           }
                       }
                       $return_script .= "document.$formname.elements[prefix+'".$priv."_".$level."'].checked = $value;\n";
                   }
               }
           }
       }
       $return_script .= '}'."\n";
       return ($return_script);
   }
   # ----------------------------------------------------------
   sub make_button_code {
       my ($role,$crstype,$display,$prefix) = @_;
       my $label = &Apache::lonnet::plaintext($role,$crstype);
       my $button_code = '<input type="button" onclick="set_'.$role."('$prefix'".')" '.
                         'id="'.$prefix.$role.'" value="'.$label.'" '.
                         'style="display:'.$display.'" />';
       return ($button_code);
   }
   
   sub custom_role_update {
       my ($rolename,$prefix) = @_;
   # ------------------------------------------------------- What can be assigned?
       my %privs = (
                         c => '',
                         d => '',
                         s => '',
                       );
       foreach my $level (keys(%privs)) {
           foreach my $item (split(/\:/,$Apache::lonnet::pr{'cr:'.$level})) {
               my ($priv,$restrict)=split(/\&/,$item);
               if (!$restrict) { $restrict=''; }
               if ($env{'form.'.$prefix.$priv.'_'.$level}) {
                   $privs{$level} .=':'.$item;
               }
           }
       }
       return %privs;
   }
   
   sub adhoc_status_types {
       my ($cdom,$context,$role,$selectedref,$othertitle,$usertypes,$types,$disabled) = @_;
       my $output = &Apache::loncommon::start_data_table();
       my $numinrow = 3;
       my $rem;
       if (ref($types) eq 'ARRAY') {
           for (my $i=0; $i<@{$types}; $i++) {
               if (defined($usertypes->{$types->[$i]})) {
                   my $rem = $i%($numinrow);
                   if ($rem == 0) {
                       if ($i > 0) {
                           $output .= &Apache::loncommon::end_data_table_row();
                       }
                       $output .= &Apache::loncommon::start_data_table_row();
                   }
                   my $check;
                   if (ref($selectedref) eq 'ARRAY') {
                       if (grep(/^\Q$types->[$i]\E$/,@{$selectedref})) {
                           $check = ' checked="checked"';
                       }
                   }
                   $output .= '<td>'.
                              '<span class="LC_nobreak"><label>'.
                              '<input type="checkbox" name="'.$context.$role.'_status" '.
                              'value="'.$types->[$i].'"'.$check.$disabled.' />'.
                              $usertypes->{$types->[$i]}.'</label></span></td>';
               }
           }
           $rem = @{$types}%($numinrow);
       }
       my $colsleft = $numinrow - $rem;
       if (($rem == 0) && (@{$types} > 0)) {
           $output .= &Apache::loncommon::start_data_table_row();
       }
       if ($colsleft > 1) {
           $output .= '<td colspan="'.$colsleft.'">';
       } else {
           $output .= '<td>';
       }
       my $defcheck;
       if (ref($selectedref) eq 'ARRAY') {
           if (grep(/^default$/,@{$selectedref})) {
               $defcheck = ' checked="checked"';
           }
       }
       $output .= '<span class="LC_nobreak"><label>'.
                  '<input type="checkbox" name="'.$context.$role.'_status"'.
                  'value="default"'.$defcheck.$disabled.' />'.
                  $othertitle.'</label></span></td>'.
                  &Apache::loncommon::end_data_table_row().
                  &Apache::loncommon::end_data_table();
       return $output;
   }
   
   sub adhoc_staff {
       my ($access,$context,$role,$selectedref,$adhocref,$disabled) = @_;
       my $output;
       if (ref($adhocref) eq 'HASH') {
           my %by_fullname;
           my $numinrow = 4;
           my $rem;
           my @personnel = keys(%{$adhocref});
           if (@personnel) {
               foreach my $person (@personnel) {
                   my ($uname,$udom) = split(/:/,$person);
                   my $fullname = &Apache::loncommon::plainname($uname,$udom,'lastname');
                   $by_fullname{$fullname} = $person;
               }
               my @sorted = sort(keys(%by_fullname));
               my $count = scalar(@sorted);
               $output = &Apache::loncommon::start_data_table();
               for (my $i=0; $i<$count; $i++) {
                   my $rem = $i%($numinrow);
                   if ($rem == 0) {
                       if ($i > 0) {
                           $output .= &Apache::loncommon::end_data_table_row();
                       }
                       $output .= &Apache::loncommon::start_data_table_row();
                   }
                   my $check;
                   my $user = $by_fullname{$sorted[$i]};
                   if (ref($selectedref) eq 'ARRAY') {
                       if (grep(/^\Q$user\E$/,@{$selectedref})) {
                           $check = ' checked="checked"';
                       }
                   }
                   if ($i == $count-1) {
                       my $colsleft = $numinrow - $rem;
                       if ($colsleft > 1) {
                           $output .= '<td colspan="'.$colsleft.'">';
                       } else {
                           $output .= '<td>';
                       }
                   } else {
                       $output .= '<td>';
                   }
                   $output .= '<span class="LC_nobreak"><label>'.
                              '<input type="checkbox" name="'.$context.$role.'_staff_'.$access.'" '.
                              'value="'.$user.'"'.$check.$disabled.' />'.$sorted[$i].
                              '</label></span></td>';
                   if ($i == $count-1) {
                       $output .= &Apache::loncommon::end_data_table_row();
                   }
               }
               $output .= &Apache::loncommon::end_data_table();
           }
       }
       return $output;
   }
   
   
 1;  1;
   

Removed from v.1.169  
changed lines
  Added in v.1.213


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