--- loncom/auth/switchserver.pm	2022/08/30 16:20:17	1.35.2.6.2.3
+++ loncom/auth/switchserver.pm	2023/06/02 01:20:26	1.65
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Switch Servers Handler
 #
-# $Id: switchserver.pm,v 1.35.2.6.2.3 2022/08/30 16:20:17 raeburn Exp $
+# $Id: switchserver.pm,v 1.65 2023/06/02 01:20:26 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -62,7 +62,7 @@ sub do_redirect {
     }
     my $start_page = 
 	&Apache::loncommon::start_page('Switching Server ...',undef,
-				       {'redirect'       => [$delay,$url,'',$write_to_opener],
+				       {'redirect'       => [$delay,$url,'',$write_to_opener,1],
 					'only_body'      => $only_body,});
     my $end_page   = &Apache::loncommon::end_page();
     $r->print($start_page.$extra_text.$end_page);
@@ -102,7 +102,7 @@ sub handler {
     if (!defined($handle)) { return FORBIDDEN; }
 
     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
-				['otherserver','role','origurl','symb','lcssowin']);
+				['otherserver','role','origurl','symb','lcssowin','edit']);
 
     my $switch_to=&Apache::lonnet::hostname($env{'form.otherserver'});
     if (! $env{'form.otherserver'}) {
@@ -155,34 +155,81 @@ sub handler {
                     $skip_canhost_check = 1;
                 }
             } elsif ($env{'form.role'} =~ m{^[ac]a\./($match_domain)/($match_username)$}) {
-                if (&Apache::lonnet::homeserver($2,$1) eq $env{'form.otherserver'}) {
-                    $skip_canhost_check = 1; 
+                my ($audom,$auname) = ($1,$2);
+                if (&Apache::lonnet::homeserver($auname,$audom) eq $env{'form.otherserver'}) {
+                    if ((&Apache::lonnet::will_trust('othcoau',$env{'user.domain'},$audom)) &&
+                        (&Apache::lonnet::will_trust('coaurem',$audom,$env{'user.domain'}))) {                             
+                        $skip_canhost_check = 1;
+                    }
                 }
             }
         }
     }
 
     unless ($skip_canhost_check) {
-        my $canhost = 1;
-        my $uprimary_id = &Apache::lonnet::domain($env{'user.domain'},'primary');
-        my $uint_dom = &Apache::lonnet::internet_dom($uprimary_id);
-        my @intdoms;
-        my $internet_names = &Apache::lonnet::get_internet_names($env{'form.otherserver'});
-        if (ref($internet_names) eq 'ARRAY') {
-            @intdoms = @{$internet_names};
-        }
-        unless ($uint_dom ne '' && grep(/^\Q$uint_dom\E$/,@intdoms)) {
-            my $serverhomeID = &Apache::lonnet::get_server_homeID($switch_to);
-            my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID);
-            my %defdomdefaults = &Apache::lonnet::get_domain_defaults($serverhomedom);
-            my %udomdefaults = &Apache::lonnet::get_domain_defaults($env{'user.domain'});
-            my $remoterev = &Apache::lonnet::get_server_loncaparev($env{'user.domain'},$env{'form.otherserver'});
-            $canhost = 
-                &Apache::lonnet::can_host_session($env{'user.domain'},
-                                                  $env{'form.otherserver'},
-                                                  $remoterev,
-                                                  $udomdefaults{'remotesessions'},
-                                                  $defdomdefaults{'hostedsessions'});
+        my $canhost = &Apache::lonnet::can_switchserver($env{'user.domain'},$env{'form.otherserver'});
+        unless ($canhost) {
+            if (($env{'request.course.id'}) && ($env{'form.symb'} ne '') &&
+                (&Apache::lonnet::allowed('mdc',$env{'request.course.id'}))) {
+                my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+                my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+                if (($cdom ne '') && ($cnum ne '') && ($env{'form.role'} =~ m{^([^.]+)\Q./$cdom/$cnum\E$})) {
+                    my $symb = &Apache::lonnet::symbclean($env{'form.symb'});
+                    my ($map,$idx,$url) = &Apache::lonnet::decode_symb($symb);
+                    if (&Apache::lonnet::symbverify($symb,$url)) {
+                        my $fileloc = &Apache::lonnet::declutter(&Apache::lonnet::filelocation("",$url));
+                        my $resurl = &Apache::lonnet::clutter($url);
+                        if ($resurl =~ m{^/res/($match_domain)/($match_username)/}) {
+                            my ($audom,$auname) = ($1,$2);
+                            if (&Apache::lonnet::homeserver($auname,$audom) eq $env{'form.otherserver'}) {
+                                my @possroles = ("user.role.au./$audom/","user.role.ca./$audom/$auname","user.role.aa./$audom/$auname");
+                                my $hasrole;
+                                foreach my $rolekey (@possroles) {
+                                    if (exists($env{$rolekey})) {
+                                        my ($start,$end) = split(/\./,$env{$rolekey});
+                                        unless (($start && $start > $now) || ($end && $end < $now)) {
+                                            if ($rolekey eq "user.role.au./$audom/") {
+                                                $hasrole = $rolekey;
+                                            } elsif ((&Apache::lonnet::will_trust('othcoau',$env{'user.domain'},$audom)) &&
+                                                     (&Apache::lonnet::will_trust('coaurem',$audom,$env{'user.domain'}))) {
+                                                $hasrole = $rolekey;
+                                            }
+                                        }
+                                        if ($hasrole) {
+                                            $hasrole =~ s/^\Quser.role.\E//;
+                                            last;
+                                        }
+                                    }
+                                }
+                                if ($hasrole) {
+                                    $env{'form.role'} = $hasrole;
+                                    $env{'form.origurl'} = &Apache::lonnet::deversion($resurl);
+                                    $env{'form.origurl'} =~ s{^/res/}{/priv/};
+                                    delete($env{'form.symb'});
+                                    $canhost = 1;
+                                    if ($env{'form.edit'}) {
+                                        my $ip = &Apache::lonnet::get_requestor_ip($r,REMOTE_NOLOOKUP);
+                                        my %info=('ip'            => $ip,
+                                                  'domain'        => $env{'user.domain'},
+                                                  'username'      => $env{'user.name'},
+                                                  'home'          => $env{'user.home'},
+                                                  'role'          => $env{'form.role'},
+                                                  'server'        => $r->dir_config('lonHostID'),
+                                                  'origurl'       => $env{'form.origurl'});
+                                        &Apache::loncommon::content_type($r,'text/html');
+                                        my $token = &Apache::lonnet::tmpput(\%info,$env{'form.otherserver'});
+                                        my $url = $protocol.'://'.$switch_to.'/adm/login?'.
+                                                                 'domain='.$env{'user.domain'}.
+                                                                 '&amp;username='.$env{'user.name'}.
+                                                                 '&amp;token='.$token;
+                                        return &do_redirect($r,$url,0);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
         }
         unless ($canhost) { return FORBIDDEN; }
     }
@@ -204,6 +251,10 @@ sub handler {
     my $logmsg = "Switch Server to $env{'form.otherserver'}";
     if ($env{'form.role'}) {
         $logmsg .= " with role: $env{'form.role'}";
+    } elsif (($env{'form.lti.reqcrs'}) && ($env{'form.lti.reqrole'} eq 'cc')) {
+        $logmsg .= " to create new LTI course";
+    } elsif ($env{'form.lti.selfenrollrole'}) {
+        $logmsg .= " to selfenroll with role: $env{'form.lti.selfenrollrole'}";
     } else {
         $logmsg .= " (no role)";
     }
@@ -231,9 +282,9 @@ sub handler {
 
 # ---------------------------------------------------------------- Get handover
 
-    my ($is_balancer,$setcookie,$newcookieid,$otherbalcookie);
+    my ($is_balancer,$setcookie,$newcookieid,$otherbalcookie,$offloadto,$dom_balancers);
     my $only_body = 0;
-    ($is_balancer,undef,$setcookie) =
+    ($is_balancer,undef,$setcookie,$offloadto,$dom_balancers) =
         &Apache::lonnet::check_loadbalancing($env{'user.name'},$env{'user.domain'},'switchserver');
     if ($is_balancer && $setcookie && $env{'form.otherserver'}) {
 
@@ -253,12 +304,25 @@ sub handler {
         $otherbalcookie = $env{'request.balancercookie'};
     }
 
-    my %info=('ip'       => $ip,
-	      'domain'   => $env{'user.domain'},
-	      'username' => $env{'user.name'},
-	      'role'     => $env{'form.role'},
-	      'server'   => $r->dir_config('lonHostID'),
-	      'balancer' => $is_balancer);
+    my %info=('ip'            => $ip,
+              'domain'        => $env{'user.domain'},
+              'username'      => $env{'user.name'},
+              'home'          => $env{'user.home'},
+              'role'          => $env{'form.role'},
+              'server'        => $r->dir_config('lonHostID'),
+              'balancer'      => $is_balancer,
+              'dom_balancers' => $dom_balancers,
+              'offloadto'     => '');
+    if (ref($offloadto) eq 'HASH') {
+        foreach my $key (keys(%{$offloadto})) {
+            if (ref($offloadto->{$key}) eq 'ARRAY') {
+                $info{'offloadto'} .= $key.'='.join(',',@{$offloadto->{$key}}).'&';
+            }
+        }
+        $info{'offloadto'} =~ s/\&$//;
+    } elsif (ref($offloadto) eq 'ARRAY') {
+        $info{'offloadto'} = join(',',@{$offloadto});
+    }
     if ($newcookieid) {
         $info{'balcookie'} = $newcookieid;
     } elsif ($otherbalcookie) {
@@ -266,6 +330,12 @@ sub handler {
     }
     if ($env{'form.origurl'}) {
         $info{'origurl'} = $env{'form.origurl'};
+        if ($env{'form.origurl'} eq '/adm/email') {
+            if ($env{'request.display'} && ($env{'request.mailrecip'} eq "$env{'user.name'}:$env{'user.domain'}")) {
+                $info{'display'} = &escape($env{'request.display'});
+                $info{'mailrecip'} = &escape($env{'request.mailrecip'});
+            }
+        }
     }
     if ($env{'form.symb'}) {
         $info{'symb'} = $env{'form.symb'};
@@ -277,7 +347,7 @@ sub handler {
         if (defined($r->dir_config("lonSSOUserLogoutScriptFile_$info{domain}"))) {
             if (open(my $fh,'<',$r->dir_config("lonSSOUserLogoutScriptFile_$info{domain}"))) {
                 $ssologoutscript .= join('',<$fh>);
-                close($fh);
+                close($fh); 
             }
         }
         if (defined($r->dir_config('lonSSOUserLogoutScriptFile'))) {
@@ -292,7 +362,7 @@ sub handler {
     }
     if ($env{'request.linkprot'}) {
         $info{'linkprot'} = $env{'request.linkprot'};
-        foreach my $item ('linkprotuser','linkprotexit') {
+        foreach my $item ('linkprotuser','linkprotexit','linkprotpbid','linkprotpburl') {
             if ($env{'request.'.$item}) {
                 $info{$item} = $env{'request.'.$item};
             }
@@ -303,6 +373,39 @@ sub handler {
     if ($env{'request.deeplink.login'}) {
         $info{'deeplink.login'} = $env{'request.deeplink.login'};
     }
+    if ($env{'request.lti.login'}) {
+        $info{'lti.login'} = $env{'request.lti.login'};
+    }
+    if ($env{'request.lti.uri'}) {
+        $info{'lti.uri'} = $env{'request.lti.uri'};
+    }
+    if ($env{'request.lti.reqcrs'}) {
+        $info{'lti.reqcrs'} = $env{'request.lti.reqcrs'};
+    }
+    if ($env{'request.lti.reqrole'}) {
+        $info{'lti.reqrole'} = $env{'request.lti.reqrole'};
+    }
+    if ($env{'request.lti.selfenrollrole'}) {
+        $info{'lti.selfenrollrole'} = $env{'request.lti.selfenrollrole'};
+    }
+    if ($env{'request.lti.sourcecrs'}) {
+        $info{'lti.sourcecrs'} = $env{'request.lti.sourcecrs'};
+    }
+    if ($env{'request.lti.passbackid'}) {
+        $info{'lti.passbackid'} = $env{'request.lti.passbackid'};
+    }
+    if ($env{'request.lti.passbackurl'}) {
+        $info{'lti.passbackurl'} = $env{'request.lti.passbackurl'};
+    }
+    if ($env{'request.lti.rosterid'}) {
+        $info{'lti.rosterid'} = $env{'request.lti.rosterid'};
+    }
+    if ($env{'request.lti.rosterurl'}) {
+        $info{'lti.rosterurl'} = $env{'request.lti.rosterurl'};
+    }
+    if ($env{'request.lti.target'}) {
+        $info{'lti.target'} = $env{'request.lti.target'};
+    }
     my $token = &Apache::lonnet::tmpput(\%info,$env{'form.otherserver'});
     my @args = ("domain=$env{'user.domain'}",
                 "username=$env{'user.name'}",