--- loncom/interface/lonuserutils.pm	2024/08/24 23:49:48	1.184.4.10.2.8
+++ loncom/interface/lonuserutils.pm	2025/01/13 01:00:58	1.225
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Utility functions for managing LON-CAPA user accounts
 #
-# $Id: lonuserutils.pm,v 1.184.4.10.2.8 2024/08/24 23:49:48 raeburn Exp $
+# $Id: lonuserutils.pm,v 1.225 2025/01/13 01:00:58 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -50,6 +50,7 @@ use strict;
 use Apache::lonnet;
 use Apache::loncommon();
 use Apache::lonhtmlcommon;
+use Apache::loncoursequeueadmin;
 use Apache::lonlocal;
 use Apache::longroup;
 use HTML::Entities;
@@ -176,6 +177,560 @@ sub modifyuserrole {
     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(/:/,$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 {
     my ($uname,$udom,$user) = @_;
     my (@types,@roles);
@@ -575,6 +1130,7 @@ END
             case 'loc':
                 alertmsg = '';
                 break;
+            case 'lti':
             default:
                 alertmsg = '';
         }
@@ -932,6 +1488,7 @@ sub print_upload_manager_footer {
     my $krbform = &Apache::loncommon::authform_kerberos(%param);
     my $intform = &Apache::loncommon::authform_internal(%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,
                                          $formname,$permission,$crstype);
 
@@ -960,7 +1517,7 @@ sub print_upload_manager_footer {
             &Apache::loncommon::help_open_topic('Auth_Options').
             "</p>\n";
     }
-    $Str .= &set_login($defdom,$krbform,$intform,$locform);
+    $Str .= &set_login($defdom,$krbform,$intform,$locform,$ltiform);
 
     my ($home_server_pick,$numlib) =
         &Apache::loncommon::home_server_form_item($defdom,'lcserver',
@@ -977,8 +1534,14 @@ sub print_upload_manager_footer {
                 &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'))
-           .&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();
 
     $Str .= &Apache::lonhtmlcommon::row_title(&mt('Starting and Ending Dates'))
@@ -1603,10 +2166,11 @@ sub my_custom_roles {
     my %rolehash=&Apache::lonnet::dump('roles',$udom,$uname);
     foreach my $key (keys(%rolehash)) {
         if ($key=~/^rolesdef\_(\w+)$/) {
+            my $role = $1;
             if ($crstype eq 'Community') {
                 next if ($rolehash{$key} =~ /bre\&S/); 
             }
-            $returnhash{$1}=$1;
+            $returnhash{$role}=$role;
         }
     }
     return %returnhash;
@@ -2280,6 +2844,7 @@ sub gather_userinfo {
             ($userdata{'username'},$userdata{'domain'},$userdata{'role'}) =
                 split(/:/,$item);
             ($userdata{'start'},$userdata{'end'})=split(/:/,$rolehash->{$item});
+            next if (($userdata{'username'} eq '') && ($userdata{'domain'} eq ''));
             &build_user_record($context,\%userdata,$userinfo,$indexhash,
                                $item,$userlist);
         } elsif ($context eq 'course') {
@@ -2953,15 +3518,28 @@ END
                                                 Future  => 'Future',
                                                 Expired => 'Expired',
                                                );
-    my (%crslogins,%camanagers);
+    my (%crslogins,%camanagers,%othdoms);
     if ($context eq 'course') {
         # If this is for a single course get last course "log-in".
         %crslogins=&Apache::lonnet::dump('nohist_crslastlogin',$cdom,$cnum);
     } elsif ($context eq 'author') {
-        map { $camanagers{$_.':ca'} = 1; } split(/,/,$env{'environment.authormanagers'});
+        my $authormanagers;
+        if ($env{'request.role'} =~ m{^(?:ca|aa)\./($match_domain)/($match_username)$}) {
+            my %envhash = &Apache::lonnet::userenvironment($1,$2,'authormanagers');
+            $authormanagers = $envhash{'authormanagers'};
+        } else {
+            $authormanagers = $env{'environment.authormanagers'};
+        }
+        if ($authormanagers ne '') {
+            map { $camanagers{$_.':ca'} = 1; } split(/,/,$authormanagers);
+        }
     }
     # Get groups, role, permanent e-mail so we can sort on them if
     # necessary.
+    # Compare user's domain with $env{'request.role.dom'}, and if
+    # different add to the domains for which to retrieve data on
+    # viewable user information, by institutional status, for users
+    # from "other" domains.
     foreach my $user (keys(%{$userlist})) {
         if ($user eq '' ) {
             delete($userlist->{$user});
@@ -3092,6 +3670,9 @@ END
                 $userlist->{$user}->[$index{'authorquota'}] = sprintf("%.2f",$disk_quota);
             }
         }
+        unless ($env{'request.role.domain'} eq $udom) {
+            $othdoms{$udom} = 1;
+        }
         $usercount ++;
     }
     my $autocount = 0;
@@ -3133,16 +3714,83 @@ END
             $disabled = ' disabled="disabled"';
         }
     }
+    my (%shownfields_by_dom,%checkshown);
+    if (keys(%othdoms)) {
+        my @userinfo = ('firstname','middlename','lastname','generation',
+                        'permanentemail','id');
+        foreach my $dom (keys(%othdoms)) {
+            my %shownfields = &get_othdom_shownfields($dom,\@userinfo);
+            $shownfields_by_dom{$dom} = \%shownfields;
+        }
+        foreach my $item (@userinfo) {
+            if ($item eq 'id') {
+                if (grep(/^\Q$item\E$/,@cols)) {
+                    $checkshown{$item} = 1;
+                }
+            } elsif ($item eq 'permamentemail') {
+                if (grep(/^email$/,@cols)) {
+                    $checkshown{$item} = 1;
+                }
+            } elsif (grep(/^fullname$/,@cols)) {
+                $checkshown{$item} = 1;
+            }
+        }
+    }
     foreach my $user (@sorted_users) {
         my %in;
         my $sdata = $userlist->{$user};
-        $rowcount ++; 
+        $rowcount ++;
         foreach my $item (@{$keylist}) {
             $in{$item} = $sdata->[$index{$item}];
         }
-        my $clickers = (&Apache::lonnet::userenvironment($in{'domain'},$in{'username'},'clickers'))[1];
-        if ($clickers!~/\w/) { $clickers='-'; }
-        $in{'clicker'} = $clickers;
+        if ((grep(/^clicker$/,@cols)) || (keys(%checkshown) && (exists($othdoms{$in{'domain'}})))) {
+            my %info = &Apache::lonnet::userenvironment($in{'domain'},$in{'username'},'clickers','inststatus',
+                                                        'firstname','middlename','lastname','generation');
+            if (grep(/^clicker$/,@cols)) {
+                if ($info{'clickers'} !~/\w/) { $info{'clickers'} = '-'; }
+                $in{'clicker'} = $info{'clickers'};
+            }
+            if (keys(%checkshown) && exists($othdoms{$in{'domain'}})) {
+                my @statuses;
+                if ($info{'inststatus'} ne '') {
+                    @statuses = split(/:/,$info{'inststatus'});
+                } else {
+                    @statuses = ('default');
+                }
+                if (ref($shownfields_by_dom{$in{'domain'}}) eq 'HASH') {
+                    my (%shown,$rebuildname,%names);
+                    foreach my $type (@statuses) {
+                        if (ref($shownfields_by_dom{$in{'domain'}}{$type}) eq 'HASH') {
+                            foreach my $key (keys(%{$shownfields_by_dom{$in{'domain'}}{$type}})) {
+                                $shown{$key} = 1;
+                            }
+                        }
+                    }
+                    foreach my $item ('id','permanentemail') {
+                        if ($checkshown{$item} && !$shown{$item}) {
+                            if ($item eq 'permanentemail') {
+                                $in{'email'} = &mt('not shown');
+                            } else {
+                                $in{$item} = &mt('not shown');
+                            }
+                        }
+                    }
+                    foreach my $item ('firstname','middlename','lastname','generation') {
+                        if ($checkshown{$item} && !$shown{$item}) {
+                            $rebuildname = 1;
+                        } else {
+                            $names{$item} = $info{$item};
+                        }
+                    }
+                    if ($rebuildname) {
+                        $in{'fullname'} = &Apache::lonnet::format_name($names{'firstname'},
+                                                                       $names{'middlename'},
+                                                                       $names{'lastname'},
+                                                                       $names{'generation'},'lastname');
+                    }
+                }
+            }
+        }
 	my $role = $in{'role'};
         $in{'role'}=&Apache::lonnet::plaintext($sdata->[$index{'role'}],$crstype);
         unless ($mode eq 'excel') {
@@ -3264,13 +3912,10 @@ END
                 } elsif ($item eq 'clicker') {
                     if (($context eq 'course') && ($mode ne 'autoenroll')) {
                         if ($env{'form.showrole'} eq 'st' || $env{'form.showrole'} eq 'Any') {
-                            my $clickers =
-                   (&Apache::lonnet::userenvironment($in{'domain'},$in{'username'},'clickers'))[1];
-                            if ($clickers!~/\w/) { $clickers='-'; }
-                            $r->print('<td>'.$clickers.'</td>');
+                            $r->print('<td>'.$in{'clicker'}.'</td>');
                         } else {
-                             $r->print('<td>&nbsp;</td>'."\n");
-                        } 
+                            $r->print('<td>&nbsp;</td>'."\n");
+                        }
                     }
                 } elsif (($item eq 'authorquota') || ($item eq 'authorusage')) {
                     $r->print('<td align="right">'.$in{$item}.'</td>'."\n");
@@ -3886,10 +4531,16 @@ sub results_header_row {
             $description .= ' ('.$constraint.')';
         } 
     } elsif ($context eq 'author') {
+        my ($auname,$audom);
+        if ($env{'request.role'} =~ m{^(?:ca|aa)\./($match_domain)/($match_username)$}) {
+            ($audom,$auname) = ($1,$2);
+        } else {
+            ($audom,$auname) = ($env{'user.domain'},$env{'user.name'});
+        }
         $description = 
             &mt('Author space for [_1]'
                 ,'<span class="LC_cusr_emph">'
-                .&Apache::loncommon::plainname($env{'user.name'},$env{'user.domain'})
+                .&Apache::loncommon::plainname($auname,$audom)
                 .'</span>')
             .':&nbsp;&nbsp;';
         if ($statusmode eq 'Expired') {
@@ -4309,7 +4960,47 @@ sub upfile_drop_add {
     my $defdom=$env{'request.role.domain'};
     my $domain;
     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 {
         $domain = $defdom;
     }
@@ -4321,7 +5012,6 @@ sub upfile_drop_add {
         if (! exists($home_servers{$desiredhost})) {
             $r->print('<p class="LC_error">'.&mt('Error').': '.
                       &mt('Invalid home server specified').'</p>');
-            $r->print(&Apache::loncommon::end_page());
             return 'invalidhome';
         }
     }
@@ -4349,6 +5039,8 @@ sub upfile_drop_add {
         if ((defined($env{'form.locarg'})) && ($env{'form.locarg'})) {
             $genpwd=$env{'form.locarg'};
         }
+    } elsif ($env{'form.login'} eq 'lti') {
+        $amode='lti';
     }
     if ($amode =~ /^krb/) {
         if (! defined($genpwd) || $genpwd eq '') {
@@ -4442,6 +5134,8 @@ sub upfile_drop_add {
             $r->print('<h3>'.&mt('Adding/Modifying Users')."</h3>\n<p>\n");
         }
         $r->rflush;
+        my (%got_role_approvals,%got_instdoms,%process_by,%instdoms,
+            %pending,%reject,%notifydc,%status,%unauthorized,%currqueued);
 
         my %counts = (
                        user => 0,
@@ -4501,6 +5195,7 @@ sub upfile_drop_add {
         my (%existinguser,%userinfo,%disallow,%rulematch,%inst_results,%alerts,%checkuname,
             %showpasswdrules,$haspasswdmap);
         my $counter = -1;
+        my (%willtrust,%trustchecked);
         foreach my $line (@userdata) {
             $counter ++;
             my @secs;
@@ -4548,6 +5243,28 @@ sub upfile_drop_add {
                                 '"<b>'.$entries{$fields{'domain'}}.'</b>"',
                                 $fname,$mname,$lname,$gen);
                         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 $userdomain = $entries{$fields{'domain'}};
@@ -4732,7 +5449,7 @@ sub upfile_drop_add {
                                 &mt('The user does not already exist, and you may not create a new user in a different domain.');
                             next;
                         } else {
-                            unless ($password || $env{'form.login'} eq 'loc') {
+                            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>');
@@ -4951,6 +5668,17 @@ sub upfile_drop_add {
                                 $sec = $secs[0];
                             }
                         }
+                        if ($userdomain ne $env{'request.role.domain'}) {
+                            my $item = "/$crsdom/$crsnum" ;
+                            if ($sec ne '') {
+                                $item .= "/$sec";
+                            }
+                            $item .= '_st';
+                            next if (&restricted_dom($context,$item,$userdomain,$username,$role,$startdate,
+                                                     $enddate,$crsdom,$crsnum,$sec,$credits,\%process_by,
+                                                     \%instdoms,\%got_role_approvals,\%got_instdoms,\%reject,
+                                                     \%pending,\%notifydc,\%status,\%unauthorized,\%currqueued));
+                        }
                         &modifystudent($userdomain,$username,$cid,$sec,
                                        $desiredhost,$context);
                         $roleresult =
@@ -4962,16 +5690,34 @@ sub upfile_drop_add {
                                  '',$context,$inststatus,$credits);
                         $userresult = $roleresult;
                     } else {
-                        if ($role ne '') { 
+                        my $possrole;
+                        if ($role ne '') {
                             if ($context eq 'course' || $setting eq 'course') {
                                 if ($customroles{$role}) {
                                     $role = 'cr_'.$env{'user.domain'}.'_'.
                                             $env{'user.name'}.'_'.$role;
                                 }
-                                if (($role ne 'cc') && ($role ne 'co')) { 
+                                $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));
+                                            }
                                             ($userres{$sec},$authres{$sec},$roleres{$sec},$idres{$sec}) =
                                             &modifyuserrole($context,$setting,
                                                 $changeauth,$cid,$userdomain,$username,
@@ -4985,9 +5731,22 @@ sub upfile_drop_add {
                                         $singlesec = $secs[0];
                                     }
                                 }
+                            } else {
+                                $possrole = $role;
                             }
                         }
                         if (!$multiple) {
+                            if (($userdomain ne $env{'request.role.domain'}) && ($role ne '')) {
+                                my $item = "/$crsdom/$crsnum";
+                                if ($singlesec ne '') {
+                                    $item .= "/$singlesec";
+                                }
+                                $item .= '_'.$possrole;
+                                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, 
@@ -5044,6 +5803,12 @@ sub upfile_drop_add {
         }
         $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  #
         #####################################
@@ -5237,7 +6002,8 @@ sub update_user_list {
     if ($context eq 'course') {
         $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') {
         @changelist = &Apache::loncommon::get_env_multiple('form.droplist');
     } else {
@@ -5267,7 +6033,7 @@ sub update_user_list {
     foreach my $item (@changelist) {
         my ($role,$uname,$udom,$cid,$sec,$scope,$result,$type,$locktype,
             @sections,$scopestem,$singlesec,$showsecs,$warn_singlesec,
-            $nothingtodo,$keepnosection,$credits,$instsec);
+            $nothingtodo,$keepnosection,$credits,$instsec,$cdom,$cnum);
         if ($choice eq 'drop') {
             ($uname,$udom,$sec) = split(/:/,$item,-1);
             $role = 'st';
@@ -5284,6 +6050,8 @@ sub update_user_list {
                 split(/\:/,$item,8);
             $instsec = &unescape($instsec);
             $cid = $env{'request.course.id'};
+            $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+            $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
             $scopestem = '/'.$cid;
             $scopestem =~s/\_/\//g;
             if ($sec eq '') {
@@ -5294,15 +6062,20 @@ sub update_user_list {
         } elsif ($context eq 'author') {
             ($uname,$udom,$role) = split(/\:/,$item,-1);
             $scope = '/'.$env{'user.domain'}.'/'.$env{'user.name'};
+            $cdom = $env{'user.domain'};
+            $cnum = $env{'user.name'};
         } elsif ($context eq 'domain') {
             if ($setting eq 'domain') {
                 ($role,$uname,$udom) = split(/\:/,$item,-1);
                 $scope = '/'.$env{'request.role.domain'}.'/';
+                $cdom = $env{'request.role.domain'};
             } elsif ($setting eq 'author') { 
                 ($uname,$udom,$role,$scope) = split(/\:/,$item);
+                (undef,$cdom,$cnum) = split(/\//,$scope);
             } elsif ($setting eq 'course') {
                 ($uname,$udom,$role,$cid,$sec,$type,$locktype,$credits,$instsec) = 
                     split(/\:/,$item,9);
+                ($cdom,$cnum) = split('_',$cid);
                 $instsec = &unescape($instsec);
                 $scope = '/'.$cid;
                 $scope =~s/\_/\//g;
@@ -5344,7 +6117,12 @@ sub update_user_list {
                 $start = $startdate; 
                 $end = $enddate;
             }
+            my $id = $scope.'_'.$role;
             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') {
                     $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
                 } else {
@@ -5353,6 +6131,10 @@ sub update_user_list {
                                                     $now,'','',$context);
                 }
             } 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') {
                     $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
                 } else {
@@ -5360,6 +6142,10 @@ sub update_user_list {
                                             $now,'','',$context);
                 }
             } 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') {
                     $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
                 } else {
@@ -5569,6 +6355,12 @@ sub update_user_list {
             $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');
     if ($choice eq 'drop') {
         $linktext = &mt('Display current class roster');
@@ -5652,7 +6444,7 @@ END
 }
 
 sub set_login {
-    my ($dom,$authformkrb,$authformint,$authformloc) = @_;
+    my ($dom,$authformkrb,$authformint,$authformloc,$authformlti) = @_;
     my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom);
     my $response;
     my ($authnum,%can_assign) =
@@ -5674,6 +6466,11 @@ sub set_login {
                          '<td>'.$authformloc.'</td>'.
                          &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();
     }
     return $response;
@@ -5964,12 +6761,20 @@ sub can_modify_userinfo {
     my %domconfig =
        &Apache::lonnet::get_dom('configuration',['usermodification'],
                                 $dom);
+    if (($context eq 'author') &&
+        ($env{'request.role'} =~ m{^(ca|aa)\./$match_domain/$match_username$})) {
+        $context = 'coauthor';
+    }
     my %canmodify;
     if (ref($fields) eq 'ARRAY') {
         foreach my $field (@{$fields}) {
             $canmodify{$field}  = 0;
             if (&Apache::lonnet::allowed('mau',$dom)) {
                 $canmodify{$field} = 1;
+            } elsif (($context ne 'selfcreate') &&
+                     ($env{'request.role.dom'} ne $dom) &&
+                     ($env{'user.domain'} ne $dom)) {
+                $canmodify{$field} = 0;
             } else {
                 if (ref($domconfig{'usermodification'}) eq 'HASH') {
                     if (ref($domconfig{'usermodification'}{$context}) eq 'HASH') {
@@ -7163,6 +7968,27 @@ sub adhoc_staff {
     return $output;
 }
 
+sub get_othdom_shownfields {
+    my ($dom,$userinfo) = @_;
+    return unless (ref($userinfo) eq 'ARRAY');
+    my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
+    my @insttypes;
+    if (ref($domdefaults{'inststatustypes'}) eq 'HASH') {
+        @insttypes = keys(%{$domdefaults{'inststatustypes'}});
+    }
+    push(@insttypes,'default');
+    my %shownfields;
+    if (ref($domdefaults{'privacyothdom'}) eq 'HASH') {
+        %shownfields = %{$domdefaults{'privacyothdom'}};
+    } else {
+        foreach my $type (@insttypes) {
+            foreach my $field (@{$userinfo}) {
+                $shownfields{$type}{$field} = 1;
+            }
+        }
+    }
+    return %shownfields;
+}
 
 1;