module external_handling implicit none contains function generate_players_gemini() result(res) use captain_db implicit none character(len=:), pointer::res character(len=PLAYER_NAME_LENGTH), dimension(:), pointer::players integer::n, i, nsize character(len=3*PLAYER_NAME_LENGTH)::one_player n = get_player_count() if(n == 0) then allocate(character(len=1024) :: res) res = "None Yet" else players => get_player_names() nsize = 1024 do i = 1, size(players) nsize = nsize + 16 + 2*len_trim(players(i)) end do allocate(character(len=nsize) :: res) res = "## Existing Players" do i = 1, n one_player = "=> /players/"//trim(players(i))//".gmi "//trim(players(i)) if(i == 1) then res = trim(res)//new_line(res(1:1))//new_line(res(1:1))//trim(one_player) else res = trim(res)//new_line(res(1:1))//trim(one_player) end if end do deallocate(players) end if res = trim(res)//new_line(res(1:1))//new_line(res(1:1))//"## Management"// & new_line(res(1:1))//"=> /players/add.gmi Add Player" end function generate_players_gemini function generate_instructions_gemini() result(res) use captain_db implicit none character(len=:), pointer::res character(len=PLAYER_NAME_LENGTH), dimension(:), pointer::instruction_names integer::n, i, nsize character(len=3*PLAYER_NAME_LENGTH)::one_player n = get_instuctions_count() if(n == 0) then allocate(character(len=1024) :: res) res = "None Yet" else instruction_names => get_instruction_names() nsize = 1024 do i = 1, size(instruction_names) nsize = nsize + 16 + 2*len_trim(instruction_names(i)) end do allocate(character(len=nsize) :: res) res = "## Instructions" do i = 1, n one_player = "=> /instructions/"//trim(instruction_names(i))//".json "//trim(instruction_names(i)) if(i == 1) then res = trim(res)//new_line(res(1:1))//new_line(res(1:1))//trim(one_player) else res = trim(res)//new_line(res(1:1))//trim(one_player) end if end do deallocate(instruction_names) end if res = trim(res)//new_line(res(1:1))//new_line(res(1:1))//"## Management"// & new_line(res(1:1))//"=> /instructions/scan.gmi Scan for Instructions" end function generate_instructions_gemini pure function is_input_provided_request(req) use server_response, only: request implicit none class(request), intent(in)::req logical::is_input_provided_request is_input_provided_request = associated(req%query_string) end function is_input_provided_request pure function is_input_required_request(req) use server_response, only: request implicit none class(request), intent(in)::req logical::is_input_required_request is_input_required_request = .false. if(req%location == "/players/add.gmi") then is_input_required_request = .true. end if end function is_input_required_request function external_input_required_gemini(req) result(resp) use server_response implicit none class(request), intent(in)::req type(response)::resp resp%code = GEMINI_CODE_INPUT if(req%location == "/players/add.gmi") then call resp%set_message("Enter name of new player to add") end if end function external_input_required_gemini function external_input_request_gemini(req) result(resp) use server_response use captain_db implicit none class(request), intent(in)::req type(response)::resp if(req%location == "/players/add.gmi") then call add_player_db(req%query_string) resp%code = GEMINI_CODE_REDIRECT call resp%set_url("/players.gmi") end if end function external_input_request_gemini function is_request_static(req) use server_response use logging implicit none class(request), intent(in)::req logical::is_request_static character(64)::first call req%path_component(1, first) call write_log("Static check: "//trim(first)) is_request_static = ((trim(first) == "releases") .or. & (trim(first) == "uploads") .or. & (trim(first) == "results") .or. & (trim(first) == "static") .or. & (trim(first) == "favicon.txt") .or. & (trim(first) == "instructions")) end function is_request_static function is_redirect_action(req) use server_response implicit none class(request), intent(in)::req logical::is_redirect_action is_redirect_action = .false. if(req%location == "/instructions/scan.gmi") then is_redirect_action = .true. end if end function is_redirect_action function external_redirect_action_request_gemini(req) result(resp) use captain_db use server_response use logging implicit none class(request), intent(in)::req type(response)::resp resp%code = GEMINI_CODE_REDIRECT if(req%location == "/instructions/scan.gmi") then call scan_instructions_for_db() call resp%set_url("/instructions.gmi") end if end function external_redirect_action_request_gemini function external_request_static(req) result(resp) use logging, only: write_log use config use utilities use server_response implicit none class(request), intent(in)::req type(response)::resp character(64)::category character(256)::filename logical::exists resp%temporary_file = .false. call req%path_component(1, category) call req%last_component(filename) call write_log("Catgeory: "//trim(category)//" File: "//trim(filename)) if(category == "releases") then allocate(character(len=(len_trim(release_dir)+len_trim(filename)+1)) :: resp%body_filename) call combine_paths(release_dir, filename, resp%body_filename) else if(category == "uploads") then allocate(character(len=(len_trim(release_dir)+len_trim(filename)+1)) :: resp%body_filename) call combine_paths(release_dir, filename, resp%body_filename) else if(category == "results") then allocate(character(len=(len_trim(results_dir)+len_trim(filename)+1)) :: resp%body_filename) call combine_paths(results_dir, filename, resp%body_filename) else if(category == "static") then allocate(character(len=(len_trim(static_dir)+len_trim(filename)+1)) :: resp%body_filename) call combine_paths(static_dir, filename, resp%body_filename) else if(category == "favicon.txt") then allocate(character(len=(len_trim(static_dir)+len_trim(filename)+1)) :: resp%body_filename) call combine_paths(static_dir, filename, resp%body_filename) end if inquire(file=resp%body_filename, exist=exists) if(.not. exists) then resp%code = GEMINI_CODE_PERMFAIL call write_log("File did not exist: "//resp%body_filename) else resp%code = GEMINI_CODE_SUCCESS if(index(filename, ".gmi") /= 0) then resp%body_mimetype = "text/gemini" else if(index(filename, ".txt") /= 0) then resp%body_mimetype = "text/plain" else if(index(filename, ".json") /= 0) then resp%body_mimetype = "text/plain" ! Just a catch-all, whatever... else resp%body_mimetype = "application/octet-stream" end if end if end function external_request_static function external_request_templated(req) result(resp) use page_template use config, only: template_filepath, project use logging, only: write_log use server_response implicit none class(request), intent(in)::req type(response)::resp character(1024)::template_file type(template)::page character(len=:), pointer::contents ! Open the base template call template_filepath("index.gmi", template_file) call page%init(trim(template_file)) call write_log("Processing request") if(trim(req%location) == "/" .or. trim(req%location) == "/index.gmi") then call write_log("Assign") call page%assign('title', 'Home') call write_log("Assign done") else if(trim(req%location) == "/releases.gmi") then call page%assign('title', 'Releases') else if(trim(req%location) == "/jobs.gmi") then call page%assign('title', 'Jobs') else if(trim(req%location) == "/players.gmi") then call page%assign('title', 'Players') contents => generate_players_gemini() call page%assign('contents', contents) else if(req%location(1:9) == '/players/') then else if(trim(req%location) == "/about.gmi") then call page%assign('title', 'About') else if(trim(req%location) == "/instructions.gmi") then call page%assign('title', 'Build Instructions') contents => generate_instructions_gemini() call page%assign('contents', contents) else call page%assign('title', 'Not Found') end if call page%assign('project', project) call write_log("Rendering page for "//req%location) call page%render() call write_log("Finalizing response") resp%temporary_file = .true. resp%body_filename => page%output_filename resp%body_mimetype = "text/gemini" resp%code = GEMINI_CODE_SUCCESS end function external_request_templated function external_request_gemini(req) result(resp) use server_response use logging implicit none class(request), intent(in)::req type(response)::resp if(is_redirect_action(req)) then call write_log("Action request") resp = external_redirect_action_request_gemini(req) else if(is_input_provided_request(req)) then call write_log("Input request") resp = external_input_request_gemini(req) else if(is_input_required_request(req)) then call write_log("Input required") resp = external_input_required_gemini(req) else if(is_request_static(req)) then call write_log("Req static") resp = external_request_static(req) else call write_log("Req template") resp = external_request_templated(req) end if end function external_request_gemini end module external_handling