From 723324ae71f8209e4b1757a3f84bd0e66b6c6319 Mon Sep 17 00:00:00 2001 From: Jeffrey Armstrong Date: Tue, 5 May 2020 07:54:53 -0400 Subject: Actual client can now load and display a page using dumb_renderer --- dumb_render.f90 | 12 +++++ files.f90 | 32 ++++++++++--- gemini-windows.prj | 7 ++- main.F90 | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++++ protocol.f90 | 43 +++++++++++++++-- render.f90 | 2 + request.f90 | 4 +- 7 files changed, 224 insertions(+), 13 deletions(-) create mode 100644 main.F90 diff --git a/dumb_render.f90 b/dumb_render.f90 index 21d6c34..3980245 100644 --- a/dumb_render.f90 +++ b/dumb_render.f90 @@ -36,6 +36,8 @@ implicit none procedure :: request_input => dumb_request_input procedure :: draw_error => dumb_draw_error + + procedure :: report_status => dumb_draw_status end type dumb_renderer @@ -224,4 +226,14 @@ contains end subroutine dumb_draw_error + subroutine dumb_draw_status(self, text) + implicit none + + class(dumb_renderer)::self + character(*), intent(in)::text + + Print *, "*** "//trim(text)//" ***" + + end subroutine dumb_draw_status + end module dumb_render \ No newline at end of file diff --git a/files.f90 b/files.f90 index 45bc116..cbdb44d 100644 --- a/files.f90 +++ b/files.f90 @@ -3,8 +3,29 @@ module file_handling integer, parameter::file_type_plain_text = 1 integer, parameter::file_type_gemini = 2 + character(17), parameter::end_indicator = "** END OF FILE **" + contains + subroutine mark_file_end(unit_number) + implicit none + + integer, intent(in)::unit_number + + Write(unit_number, '(A17)') end_indicator + + end subroutine mark_file_end + + function is_file_end_marker(text) + implicit none + + character(*), intent(in)::text + logical::is_file_end_marker + + is_file_end_marker = (index(text, end_indicator) > 0) + + end function is_file_end_marker + function read_line_text(unit_number, iostatus) result(res) implicit none @@ -24,7 +45,7 @@ contains end do length = (endpos - startpos + 1) - print '(A10, I8)', "allocated", length + !print '(A10, I8)', "allocated", length allocate(character(len=length) :: res) res = repeat(' ', length) @@ -97,7 +118,6 @@ contains type(line), pointer::first_line type(line), pointer::walker, next_line - character::c integer::iostatus logical::preformatted_on @@ -110,9 +130,9 @@ contains walker=>first_line - call process_line(walker, file_type, preformatted_on) - - do while(iostatus /= -1) ! -1 should be end of file + do while(iostatus /= -1 .and. .not. is_file_end_marker(walker%text)) ! -1 should be end of file + + call process_line(walker, file_type, preformatted_on) allocate(next_line) next_line%next => null() @@ -122,8 +142,6 @@ contains walker => walker%next walker%text = read_line_text(unit_number, iostatus) - print *, walker%text - call process_line(walker, file_type, preformatted_on) end do diff --git a/gemini-windows.prj b/gemini-windows.prj index ba68877..d70f6cd 100644 --- a/gemini-windows.prj +++ b/gemini-windows.prj @@ -37,6 +37,9 @@ },{ "filename":".\\layout.f90", "enabled":"1" + },{ + "filename":".\\main.F90", + "enabled":"1" },{ "filename":".\\protocol.f90", "enabled":"1" @@ -87,8 +90,8 @@ "Working Directory":"", "Launch Using MPI":"false", "Keep Console":"true", - "External Console":"false", - "Command Line Arguments":"-g samples\\sample1.gmi", + "External Console":"true", + "Command Line Arguments":"gemini://pon.ix.tc", "Build Before Launch":"true" }, "Build Options":{ diff --git a/main.F90 b/main.F90 new file mode 100644 index 0000000..cb9e8b1 --- /dev/null +++ b/main.F90 @@ -0,0 +1,137 @@ +program gemini +use request +use dumb_render +use gemini_protocol +use layout +use file_handling + +#ifdef WINDOWS +use wsa_network, only: windows_network_startup => startup +#endif + +implicit none + + character(256)::initial_site + character(1024)::current_url + type(connection)::conn + type(dumb_renderer)::r + + logical::running + logical::loaded + + integer::return_code + + integer, parameter::io = 100 + + type(line), pointer::first_line + +#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/" ! gemini://pon.ix.tc/ + + end if + + running = .true. + loaded = .false. + call r%initialize() + + current_url = initial_site + + open(unit=io, form="formatted", status="scratch", access='stream') + + do while(running) + + if(.not. loaded) then + + call r%report_status("Requesting "//trim(current_url)) + + return_code = request_url(trim(current_url), io) + + call update_status(r, current_url, return_code) + + loaded = .true. + + end if + + if(return_code == STATUS_REDIRECT) then + + call get_redirect_url(io, current_url) + loaded = .false. + + else + + first_line => load_unit(io, file_type_gemini) + + call r%report_status("Performing Layout") + call layout_lines(first_line, r) + + end if + + + running = .not. loaded + + + + 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)) + + case (STATUS_INPUT) + call r%report_status("Ok (input)") + + case (STATUS_SUCCESS) + call r%report_status("Ok") + + case (STATUS_REDIRECT) + call r%report_status("Ok (redirect)") + + case (STATUS_TEMPFAIL) + call r%report_status("Server reports temporary failure") + + case (STATUS_PERMFAIL) + call r%report_status("Server reports permanent failure") + + case (STATUS_CERTREQ) + call r%report_status("Server requesting certificate (unsupported)") + + end select + + end subroutine update_status + +end program gemini diff --git a/protocol.f90 b/protocol.f90 index bd109c1..52b6430 100644 --- a/protocol.f90 +++ b/protocol.f90 @@ -16,6 +16,7 @@ contains function request_url(url, unit_number, server_name) result(returncode) use request use iso_c_binding + use file_handling, only: mark_file_end implicit none character(*), intent(in)::url @@ -47,7 +48,7 @@ contains if(send_string(conn%ssl, url//c_carriage_return//c_new_line, trimming=.false.)) then bytes_received = retrieve_characters(conn%ssl, buffer) - + Print *, bytes_received do while(bytes_received > 0) do i=1, bytes_received @@ -57,6 +58,8 @@ contains bytes_received = retrieve_characters(conn%ssl, buffer) end do + call mark_file_end(unit_number) + rewind(unit_number) read(unit_number, '(I1)') returncode @@ -64,18 +67,52 @@ contains returncode = -1 write(unit_number, *) "Send Error: Could Not Send Request" - + write(*, *) "Send Error: Could Not Send Request" end if else returncode = -1 write(unit_number, *) "Connection Error: "//trim(translate_connection_code(conn%code)) - + write(*, *) "Connection Error: "//trim(translate_connection_code(conn%code)) end if call close_connection(conn) end function request_url + subroutine get_redirect_url(unit_number, url) + implicit none + + integer, intent(in)::unit_number + character(*), intent(inout)::url + + character::search + integer::i, istat + + rewind(unit_number) + + ! Status code + read(unit_number, '(A1)', advance='no') search + read(unit_number, '(A1)', advance='no') search + + ! Clear the url + url = repeat(" ", len(url)) + + ! At least one whitespace, but whatever... + read(unit_number, '(A1)', advance='no') search + do while(search == " " .or. search == CHAR(9)) + read(unit_number, '(A1)', advance='no', iostat=istat) search + end do + + ! Now search contains our first url component + i = 0 + do while(search /= CHAR(13) .and. i < len(url) .and. istat == 0) + i = i + 1 + url(i:i) = search + read(unit_number, '(A1)', advance='no', iostat=istat) search + end do + + end subroutine get_redirect_url + end module gemini_protocol \ No newline at end of file diff --git a/render.f90 b/render.f90 index 684197c..6f285f7 100644 --- a/render.f90 +++ b/render.f90 @@ -31,6 +31,8 @@ implicit none procedure(request_input), deferred::request_input procedure(draw_text), deferred::draw_error + + procedure(draw_text), deferred::report_status end type renderer diff --git a/request.f90 b/request.f90 index 67cc4f7..8a4e4e5 100644 --- a/request.f90 +++ b/request.f90 @@ -158,12 +158,14 @@ contains if(end_server <= 0) then end_server = len_trim(url) else - end_server = end_server + start_server - 1 + ! Get rid of trailing slash + end_server = end_server + start_server - 2 end if length = end_server - start_server + 1 allocate(character(len=length) :: server) server = url(start_server:end_server) + Print *, "server is: "//trim(server) end if end function get_server_from_url -- cgit v1.2.3