From 14441b7f0d6dd0a101b38a4500fe1f662ae00215 Mon Sep 17 00:00:00 2001 From: Jeffrey Armstrong Date: Tue, 13 Apr 2021 09:56:28 -0400 Subject: Releases page and file/dir listing works great on Linux. Should work on BSD hosts as well. --- captain/external.f90 | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++-- common/utilities.F90 | 26 +++++++++++---- 2 files changed, 109 insertions(+), 9 deletions(-) diff --git a/captain/external.f90 b/captain/external.f90 index c4dcb5a..3ffa819 100644 --- a/captain/external.f90 +++ b/captain/external.f90 @@ -248,6 +248,92 @@ contains end subroutine get_job_page_title + function generate_releases_gemini(req) result(res) + use utilities + use server_response + use config + implicit none + + type(request), intent(in)::req + character(len=:), pointer::res + character(len=DIR_LIST_STRING_LENGTH), dimension(:), pointer::directories + character(len=DIR_LIST_STRING_LENGTH), dimension(:), pointer::files + + character(1024)::public_path, local_path, subpath + integer::allocation_size, i + character(1)::nl = new_line(' ') + character(4)::folder_icon = char(240)//char(159)//char(147)//char(129) + + if(.not. associated(req%query_string)) then + public_path = "/releases" + local_path = release_dir + else + call combine_paths("/releases", req%query_string, public_path) + call combine_paths(release_dir, req%query_string, local_path) + end if + + res => null() + + ! Easy safety check - no relative paths + if(index(local_path, '..') > 0) then + allocate(character(len=64)::res) + res = "None Found" + return + end if + + directories => get_directories_in_directory(local_path) + files => get_files_in_directory(local_path) + + allocation_size = 1024 + if(associated(directories)) then + allocation_size = allocation_size + size(directories) * DIR_LIST_STRING_LENGTH + end if + if(associated(files)) then + allocation_size = allocation_size + size(files) * DIR_LIST_STRING_LENGTH + end if + allocate(character(len=allocation_size) :: res) + res = "## Listing for "//trim(public_path) + + ! Add an "Up" link + if(trim(public_path) /= "/releases") then + i = index(req%query_string, "/", back=.true.) + if(i > 0) then + res = trim(res)//nl//"=> /releases.gmi?"//req%query_string(1:(i-1))//" Up a directory" + else + res = trim(res)//nl//"=> /releases.gmi Up a directory" + end if + end if + + if(associated(directories)) then + + do i = 1, size(directories) + + if(associated(req%query_string)) then + call combine_paths(req%query_string, trim(directories(i)), subpath) + else + subpath = trim(directories(i)) + end if + + res = trim(res)//nl//"=> /releases.gmi?"//trim(subpath)//" "//folder_icon//" "//trim(directories(i)) + end do + + deallocate(directories) + + end if + + if(associated(files)) then + + do i = 1, size(files) + call combine_paths(public_path, trim(files(i)), subpath) + res = trim(res)//nl//"=> "//trim(subpath)//" "//trim(files(i)) + end do + + deallocate(files) + + end if + + end function generate_releases_gemini + function generate_players_gemini() result(res) use captain_db implicit none @@ -544,8 +630,8 @@ contains resp%code = GEMINI_CODE_REDIRECT call resp%set_url("/players.gmi") - else if(req%location == "/jobs.gmi") then - ! Used for paging - send it back + else if(req%location == "/jobs.gmi" .or. req%location == "/releases.gmi") then + ! Used for paging (jobs) or subdirs (releases) - send it back resp = external_request_templated(req) else if(trim(first) == "instructions") then @@ -701,6 +787,8 @@ contains else if(trim(req%location) == "/releases.gmi") then call page%assign('title', 'Releases') + contents => generate_releases_gemini(req) + call page%assign('contents', contents) else if(trim(req%location) == "/jobs.gmi") then diff --git a/common/utilities.F90 b/common/utilities.F90 index 961a349..ddc0c79 100644 --- a/common/utilities.F90 +++ b/common/utilities.F90 @@ -6,6 +6,8 @@ module utilities character, parameter::dir_sep = '/' #endif + integer, parameter::DIR_LIST_STRING_LENGTH = 128 + interface replace_field module procedure replace_field_text module procedure replace_field_int @@ -276,7 +278,7 @@ contains implicit none character(*), intent(in)::directory - character(1024), dimension(:), pointer::res + character(DIR_LIST_STRING_LENGTH), dimension(:), pointer::res character(80)::line character(len=:), pointer::tempfile integer::dcount, unum, ierr, i @@ -288,6 +290,10 @@ contains wait=.true.) open(newunit=unum, file=tempfile, action='read') + + ! First line is "total ###" + read(unum, '(A)', iostat=ierr) line + dcount = 0 read(unum, '(A)', iostat=ierr) line do while(ierr == 0) @@ -303,14 +309,14 @@ contains allocate(res(dcount)) ! Now call ls, but group directories first - call execute_command_line("ls -g "//trim(directory)//" > "//trim(tempfile), & + call execute_command_line("ls --group-directories-first "//trim(directory)//" > "//trim(tempfile), & wait=.true.) open(newunit=unum, file=tempfile, action='read') i = 0 read(unum, '(A)', iostat=ierr) line do while(ierr == 0 .and. i < dcount) i = i + 1 - call combine_paths(trim(directory), trim(line), res(i)) + res(i) = trim(line) read(unum, '(A)', iostat=ierr) line end do @@ -325,7 +331,7 @@ contains implicit none character(*), intent(in)::directory - character(1024), dimension(:), pointer::res + character(DIR_LIST_STRING_LENGTH), dimension(:), pointer::res character(80)::line character(len=:), pointer::tempfile integer::dcount, total_count, unum, ierr, i @@ -337,6 +343,10 @@ contains wait=.true.) open(newunit=unum, file=tempfile, action='read') + + ! First line is "total ###" + read(unum, '(A)', iostat=ierr) line + dcount = 0 total_count = 0 read(unum, '(A)', iostat=ierr) line @@ -354,16 +364,18 @@ contains allocate(res(total_count - dcount)) ! Now call ls, but group directories first - call execute_command_line("ls -g "//trim(directory)//" > "//trim(tempfile), & + call execute_command_line("ls --group-directories-first "//trim(directory)//" > "//trim(tempfile), & wait=.true.) open(newunit=unum, file=tempfile, action='read') + i = 0 read(unum, '(A)', iostat=ierr) line - do while(ierr == 0 .and. i < dcount) + do while(ierr == 0 .and. i <= total_count) i = i + 1 if(i > dcount) then - call combine_paths(trim(directory), trim(line), res(i-dcount)) + res(i-dcount) = trim(line) end if + read(unum, '(A)', iostat=ierr) line end do -- cgit v1.2.3