--- loncom/lonnet/perl/lonnet.pm	2023/11/17 17:02:22	1.1518
+++ loncom/lonnet/perl/lonnet.pm	2024/03/29 17:32:03	1.1524
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.1518 2023/11/17 17:02:22 raeburn Exp $
+# $Id: lonnet.pm,v 1.1524 2024/03/29 17:32:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -2757,8 +2757,7 @@ sub get_domain_defaults {
                                   'selfenrollment','coursecategories',
                                   'ssl','autoenroll','trust',
                                   'helpsettings','wafproxy',
-                                  'ltisec','toolsec','domexttool',
-                                  'exttool','privacy'],$domain);
+                                  'ltisec','toolsec','privacy'],$domain);
     my @coursetypes = ('official','unofficial','community','textbook','placement');
     if (ref($domconfig{'defaults'}) eq 'HASH') {
         $domdefaults{'lang_def'} = $domconfig{'defaults'}{'lang_def'}; 
@@ -2784,7 +2783,7 @@ sub get_domain_defaults {
         } else {
             $domdefaults{'defaultquota'} = $domconfig{'quotas'};
         }
-        my @usertools = ('aboutme','blog','webdav','portfolio');
+        my @usertools = ('aboutme','blog','webdav','portfolio','portaccess');
         foreach my $item (@usertools) {
             if (ref($domconfig{'quotas'}{$item}) eq 'HASH') {
                 $domdefaults{$item} = $domconfig{'quotas'}{$item};
@@ -2854,6 +2853,11 @@ sub get_domain_defaults {
             } else {
                 $domdefaults{$type.'exttool'} = 0;
             }
+            if (ref($domconfig{'coursedefaults'}{'crsauthor'}) eq 'HASH') {
+                $domdefaults{$type.'crsauthor'} = $domconfig{'coursedefaults'}{'crsauthor'}{$type};
+            } else {
+                $domdefaults{$type.'crsauthor'} = 1;
+            }
         }
         if (ref($domconfig{'coursedefaults'}{'canclone'}) eq 'HASH') {
             if (ref($domconfig{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') {
@@ -2971,6 +2975,17 @@ sub get_domain_defaults {
                 $domdefaults{'ltiprivhosts'} = $domconfig{'ltisec'}{'private'}{'keys'};
             }
         }
+        if (ref($domconfig{'ltisec'}{'suggested'}) eq 'HASH') {
+            my %suggestions = %{$domconfig{'ltisec'}{'suggested'}};
+            foreach my $item (keys(%{$domconfig{'ltisec'}{'suggested'}})) {
+                unless (ref($domconfig{'ltisec'}{'suggested'}{$item}) eq 'HASH') {
+                    delete($suggestions{$item});
+                }
+            }
+            if (keys(%suggestions)) {
+                $domdefaults{'linkprotsuggested'} = \%suggestions;
+            }
+        }
     }
     if (ref($domconfig{'toolsec'}) eq 'HASH') {
         if (ref($domconfig{'toolsec'}{'encrypt'}) eq 'HASH') {
@@ -6994,6 +7009,7 @@ sub rolesinit {
     my %allroles=();
     my %allgroups=();
     my %gotcoauconfig=();
+    my %domdefaults=();
 
     for my $area (grep { ! /^rolesdef_/ } keys(%rolesdump)) {
         my $role = $rolesdump{$area};
@@ -7053,7 +7069,25 @@ sub rolesinit {
                     $gotcoauconfig{$area} = 1;
                     foreach my $item (@ca_settings) {
                         if (exists($info{$item})) {
-                            $coauthorenv{"environment.internal.$item.$area"} = $info{$item};
+                            my $name = $item;
+                            if ($item eq 'authoreditors') {
+                                $name = 'editors';
+                                unless ($info{'authoreditors'}) {
+                                    my %domdefs;
+                                    if (ref($domdefaults{$audom}) eq 'HASH') {
+                                        %domdefs = %{$domdefaults{$audom}};
+                                    } else {
+                                        %domdefs = &get_domain_defaults($audom);
+                                        $domdefaults{$audom} = \%domdefs;
+                                    }
+                                    if ($domdefs{$name} ne '') {
+                                        $info{'authoreditors'} = $domdefs{$name};
+                                    } else {
+                                        $info{'authoreditors'} = 'edit,xml';
+                                    }
+                                }
+                            }
+                            $coauthorenv{"environment.internal.$name.$area"} = $info{$item};
                         }
                     }
                 }
@@ -7980,7 +8014,7 @@ sub portfolio_access {
 }
 
 sub get_portfolio_access {
-    my ($udom,$unum,$file_name,$group,$clientip,$access_hash) = @_;
+    my ($udom,$unum,$file_name,$group,$clientip,$access_hash,$portaccessref) = @_;
 
     if (!ref($access_hash)) {
 	my $current_perms = &get_portfile_permissions($udom,$unum);
@@ -7989,11 +8023,19 @@ sub get_portfolio_access {
 	$access_hash = $access_controls{$file_name};
     }
 
-    my ($public,$guest,@domains,@users,@courses,@groups,@ips);
+    my $portaccess;
+    if (ref($portaccess) eq 'SCALAR') {
+        $portaccess = $$portaccessref;
+    } else {
+        $portaccess = &usertools_access($unum,$udom,'portaccess',undef,'tools');
+    }
+
+    my ($public,$guest,@domains,@users,@courses,@groups,@ips,@userips);
     my $now = time;
     if (ref($access_hash) eq 'HASH') {
         foreach my $key (keys(%{$access_hash})) {
             my ($num,$scope,$end,$start) = ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/);
+            next if (($scope ne 'ip') && ($portaccess == 0));
             if ($start > $now) {
                 next;
             }
@@ -8015,6 +8057,8 @@ sub get_portfolio_access {
                 push(@groups,$key);
             } elsif ($scope eq 'ip') {
                 push(@ips,$key);
+            } elsif ($scope eq 'userip') {
+                push(@userips,$key);
             }
         }
         if ($public) {
@@ -8032,6 +8076,19 @@ sub get_portfolio_access {
             if ($allowed) {
                 return 'ok';
             }
+        } elsif (@userips > 0) {
+            my $allowed;
+            foreach my $useripkey (@userips) {
+                if (ref($access_hash->{$useripkey}{'ip'}) eq 'ARRAY') {
+                    if (&Apache::loncommon::check_ip_acc(join(',',@{$access_hash->{$useripkey}{'ip'}}),$clientip)) {
+                        $allowed = 1;
+                        last;
+                    }
+                }
+            }
+            if ($allowed) {
+                return 'ok';
+            }
         }
         if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public') {
             if ($guest) {
@@ -9212,6 +9269,22 @@ sub constructaccess {
             if (($ownername eq $env{'course.'.$env{'request.course.id'}.'.num'}) &&
                 ($ownerdomain eq $env{'course.'.$env{'request.course.id'}.'.domain'})) {
                 if (&allowed('mdc',$env{'request.course.id'})) {
+                    return if ($env{'course.'.$env{'request.course.id'}.'.internal.crsauthor'} eq '0');
+                    unless ($env{'course.'.$env{'request.course.id'}.'.internal.crsauthor'}) {
+                        my %domdefs = &get_domain_defaults($ownerdomain);
+                        my $type = lc($env{'course.'.$env{'request.course.id'}.'.type'});
+                        unless (($type eq 'community') || ($type eq 'placement')) {
+                            $type = 'unofficial';
+                            if ($env{'course.'.$env{'request.course.id'}.'internal.coursecode'} ne '') {
+                                $type = 'official';
+                            } elsif ($env{'course.'.$env{'request.course.id'}.'internal.textbook'} ne '') {
+                                $type = 'textbook';
+                            } else {
+                                $type = 'unofficial';
+                            }
+                        }
+                        return if ($domdefs{$type.'crsauthor'} eq '0');
+                    }
                     $ownerhome = $env{'course.'.$env{'request.course.id'}.'.home'};
                     return ($ownername,$ownerdomain,$ownerhome);
                 }