! Copyright (c) 2020 Jeffrey Armstrong ! ! Permission is hereby granted, free of charge, to any person obtaining a copy ! of this software and associated documentation files (the "Software"), to deal ! in the Software without restriction, including without limitation the rights ! to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! copies of the Software, and to permit persons to whom the Software is ! furnished to do so, subject to the following conditions: ! ! The above copyright notice and this permission notice shall be included in ! all copies or substantial portions of the Software. ! ! The Software shall be used for Good, not Evil. ! ! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ! AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ! SOFTWARE. program gemini use request #ifdef WINDOWS_GUI use ag_render, only: appgraphics_renderer use ag_binary, only: appgraphics_binary_handler #else use dumb_render use dumb_binary #endif use render use gemini_protocol use layout use file_handling use history #ifdef WINDOWS use wsa_network, only: windows_network_startup => startup #endif implicit none character(256)::initial_site character(1024)::current_url, input type(connection)::conn #ifdef WINDOWS_GUI type(appgraphics_renderer)::r type(appgraphics_binary_handler)::bh #else type(dumb_renderer)::r type(dumb_binary_handler)::bh #endif logical::running logical::loaded logical::populated integer::return_code character(256)::return_type integer, parameter::io = 100 type(line), pointer::first_line type(location), pointer::locations_visited #ifdef WINDOWS call windows_network_startup() #endif if(command_argument_count() > 0) then call get_command_argument(1, initial_site) if(index(initial_site, "//") > 0) then if(index(initial_site, "gemini://") /= 1) then Print *, "Please provide a gemini URL to start (or nothing at all)" stop end if else initial_site = "gemini://"//trim(initial_site) end if else initial_site = "gemini://gemini.circumlunar.space/" end if running = .true. loaded = .false. call r%initialize() locations_visited => null() current_url = initial_site open(unit=io, form="formatted", status="scratch", access='stream') do while(running) if(index(current_url, "gemini://") /= 1) then call r%report_unsupported_protocol(trim(current_url)) populated = .false. loaded = .true. return_code = STATUS_LOCALFAIL end if if(.not. loaded) then call r%report_status("Requesting "//trim(current_url)) return_code = request_url(current_url, io, return_type, bh) populated = .true. call update_status(r, current_url, return_code) end if if(return_code == STATUS_REDIRECT) then call get_redirect_url(io, current_url) loaded = .false. populated = .false. else if(return_code == STATUS_INPUT) then if(handle_input(r, current_url, io)) then ! Should force a new load loaded = .false. else loaded = .true. end if else if(populated) then locations_visited => add_location(locations_visited, current_url) if(r%type_supported(return_type)) then first_line => load_unit(io, file_type_gemini) loaded = .true. call r%new_page() call r%report_status("Performing Layout") call layout_lines(first_line, r) call r%status_ready() else call r%draw_error("Cannot display file of type "//return_type) call back_location(locations_visited, current_url) end if end if do while(loaded .and. running) select case(r%request_action(input)) case (render_action_quit) running = .false. case (render_action_back) call back_location(locations_visited, current_url) if(associated(first_line)) then call free_lines(first_line) end if loaded = .false. case (render_action_layout) if(associated(first_line)) then call r%report_status("Performing Layout") call layout_lines(first_line, r) call r%status_ready() end if case (render_action_goto) if(index(input, "://") > 0) then current_url = input else call handle_relative_url(current_url, input) end if if(associated(first_line)) then call free_lines(first_line) end if loaded = .false. end select end do end do close(io) contains subroutine update_status(r, url, code) use gemini_protocol implicit none class(renderer)::r character(*), intent(in)::url integer, intent(in)::code select case (code) case (STATUS_LOCALFAIL) call r%report_status("Network failure loading "//trim(url)) call r%report_displayed_page("...") case (STATUS_INPUT) call r%report_status("Ok (input)") call r%report_displayed_page(url) case (STATUS_SUCCESS) call r%report_status("Ok") call r%report_displayed_page(url) case (STATUS_REDIRECT) call r%report_status("Ok (redirect)") call r%report_displayed_page(url) case (STATUS_TEMPFAIL) call r%report_status("Server reports temporary failure") call r%report_displayed_page("...") case (STATUS_PERMFAIL) call r%report_status("Server reports permanent failure") call r%report_displayed_page("...") case (STATUS_CERTREQ) call r%report_status("Server requesting certificate (unsupported)") call r%report_displayed_page("...") case (STATUS_BADRESPONSE) call r%report_status("Bad response code from server") call r%report_displayed_page("...") end select end subroutine update_status end program gemini