AmendHub

Download:

jcs

/

detritus

/

amendments

/

25

*: Split handler process into fetch and process, for downloading


jcs made amendment 25 about 1 year ago
--- browser.c Mon Nov 4 14:36:26 2024 +++ browser.c Wed Nov 6 12:52:48 2024 @@ -34,14 +34,14 @@ static Rect zerorect = { 0, 0, 0, 0 }; static Pattern fill_pattern; +extern struct uri_handler finger_handler; extern struct uri_handler gemini_handler; extern struct uri_handler gopher_handler; -extern struct uri_handler finger_handler; struct uri_handler * uri_handlers[] = { + &finger_handler, &gemini_handler, &gopher_handler, - &finger_handler, }; bool browser_close(struct focusable *focusable); @@ -68,17 +68,35 @@ browser_idle(struct focusable *focusable, EventRecord { struct browser *browser = (struct browser *)focusable->cookie; struct uri_handler *handler; + struct page *page; + bool ret; TEIdle(browser->uri_te); - if (browser->loading_page) { - HLock(browser->loading_page); - handler = (*(browser->loading_page))->handler; - HUnlock(browser->loading_page); + if (!browser->loading_page) + return; - if (!handler->process(browser->loading_page)) - browser_finished_loading(browser); + HLock(browser->loading_page); + page = *(browser->loading_page); + handler = page->handler; + + ret = true; + if (page->fetch_cookie != NULL || page->download_frefnum) { + ret = handler->fetch(page); + + /* handle may have grown during fetch */ + HLock(browser->loading_page); + page = *(browser->loading_page); + handler = page->handler; } + + if (!page->download_frefnum) + ret &= handler->process(page); + + if (!ret) + browser_finished_loading(browser); + + HUnlock(browser->loading_page); } struct browser * @@ -234,27 +252,22 @@ browser_close(struct focusable *focusable) browser_stop_loading_page(browser); if (browser->current_page) { - pageh = browser->current_page; - HLock(pageh); - fpage = (*pageh)->fwd_page; - HUnlock(pageh); + fpage = (*(browser->current_page))->fwd_page; while (fpage) { HLock(fpage); tpage = (*fpage)->fwd_page; - (*fpage)->handler->cleanup(fpage); + (*fpage)->handler->cleanup(*fpage); HLock(fpage); xfree(&(*fpage)->uri); DisposeHandle(fpage); fpage = tpage; } - HLock(pageh); bpage = (*pageh)->back_page; - HUnlock(pageh); while (bpage) { HLock(bpage); tpage = (*bpage)->back_page; - (*bpage)->handler->cleanup(bpage); + (*bpage)->handler->cleanup(*bpage); HLock(bpage); xfree(&(*bpage)->uri); DisposeHandle(bpage); @@ -262,7 +275,7 @@ browser_close(struct focusable *focusable) } HLock(pageh); - (*pageh)->handler->cleanup(pageh); + (*pageh)->handler->cleanup(*pageh); HLock(pageh); xfree(&(*pageh)->uri); DisposeHandle(pageh); @@ -285,36 +298,37 @@ void browser_finished_loading(struct browser *browser) { struct URI *redir; - struct page *page; size_t size; + bool download = false; - HLock(browser->loading_page); - if ((*(browser->loading_page))->redir_to) { browser_follow_redir(browser); - HUnlock(browser->loading_page); return; } + if ((*(browser->loading_page))->download_frefnum) { + FSClose((*(browser->loading_page))->download_frefnum); + browser_statusf(browser, "Finished downloading %ld bytes", + (*(browser->loading_page))->download_len); + download = true; + } + browser_stop_loading_page(browser); browser->redirs = 0; + if (download) + return; + /* release some memory if we can */ - HLock(browser->current_page); - page = *(browser->current_page); - if (page->content_size > page->content_len) { - size = page->content_len; - page->content_size = size; + if ((*(browser->current_page))->content_size > + (*(browser->current_page))->content_len) { + size = (*(browser->current_page))->content_len; + (*(browser->current_page))->content_size = size; HUnlock(browser->current_page); SetHandleSize(browser->current_page, sizeof(struct page) + size); - HLock(browser->current_page); - page = *(browser->current_page); } - - browser_statusf(page->browser, "Finished loading %ld bytes", - page->content_len); - - HUnlock(browser->current_page); + browser_statusf(browser, "Finished loading %ld bytes", + (*(browser->current_page))->content_len); } void @@ -328,12 +342,14 @@ browser_stop_loading_page(struct browser *browser) HLock(browser->loading_page); page = *(browser->loading_page); - page->handler->cleanup(browser->loading_page); - HLock(browser->loading_page); + page->handler->cleanup(page); + HUnlock(browser->loading_page); + if ((*(browser->loading_page))->download_frefnum) + FSClose((*(browser->loading_page))->download_frefnum); + /* only dispose if uncommitted */ if (browser->current_page != browser->loading_page) { - HLock(browser->loading_page); xfree(&(*(browser->loading_page))->uri); DisposeHandle(browser->loading_page); } @@ -403,16 +419,12 @@ void browser_update_menu(struct browser *browser) { size_t vlines; - TERec *te; Cell cell = { 0, 0 }; TextFont(systemFont); TextSize(12); - HLock(browser->uri_te); - te = *(browser->uri_te); - - if (te->selStart == te->selEnd) { + if ((*(browser->uri_te))->selStart == (*(browser->uri_te))->selEnd) { DisableItem(edit_menu, EDIT_MENU_CUT_ID); DisableItem(edit_menu, EDIT_MENU_COPY_ID); } else { @@ -422,19 +434,12 @@ browser_update_menu(struct browser *browser) EnableItem(edit_menu, EDIT_MENU_PASTE_ID); EnableItem(edit_menu, EDIT_MENU_SELECT_ALL_ID); - - HUnlock(browser->uri_te); } void browser_update_buttons(struct browser *browser) { - TERec *te; - bool is_go; - if (browser->current_page) { - HLock(browser->current_page); - if ((*(browser->current_page))->back_page) HiliteControl(browser->back, 0); else @@ -444,8 +449,6 @@ browser_update_buttons(struct browser *browser) HiliteControl(browser->fwd, 0); else HiliteControl(browser->fwd, 255); - - HUnlock(browser->current_page); } else { HiliteControl(browser->back, 255); HiliteControl(browser->fwd, 255); @@ -453,24 +456,15 @@ browser_update_buttons(struct browser *browser) if (browser->loading_page) { HiliteControl(browser->go_stop, 0); - HLock(browser->go_stop); - is_go = ((*(browser->go_stop))->contrlTitle[1] == 'G'); - HUnlock(browser->go_stop); - if (is_go) + if ((*(browser->go_stop))->contrlTitle[1] == 'G') SetCTitle(browser->go_stop, "\pStop"); } else { - HLock(browser->uri_te); - te = *(browser->uri_te); - if (te->teLength) + if ((*(browser->uri_te))->teLength) HiliteControl(browser->go_stop, 0); else HiliteControl(browser->go_stop, 255); - HUnlock(browser->uri_te); - HLock(browser->go_stop); - is_go = ((*(browser->go_stop))->contrlTitle[1] == 'G'); - HUnlock(browser->go_stop); - if (!is_go) + if ((*(browser->go_stop))->contrlTitle[1] != 'G') SetCTitle(browser->go_stop, "\pGo"); } } @@ -494,18 +488,14 @@ browser_update(struct focusable *focusable, EventRecor DrawGrowIconOnly(browser->win); browser_draw_status(browser); - HLock(browser->uri_te); r = (*(browser->uri_te))->viewRect; InsetRect(&r, -1, -1); FrameRect(&r); TEUpdate(&r, browser->uri_te); - HUnlock(browser->uri_te); - HLock(browser->output_tv); r = (*(browser->output_tv))->view; InsetRect(&r, -1, -1); FrameRect(&r); - HUnlock(browser->output_tv); TVUpdate(browser->output_tv); ValidRect(&browser->win->portRect); @@ -531,18 +521,14 @@ browser_mouse_down(struct focusable *focusable, EventR p = event->where; GlobalToLocal(&p); - HLock(browser->uri_te); r = (*(browser->uri_te))->viewRect; - HUnlock(browser->uri_te); if (PtInRect(p, &r)) { TEClick(p, ((event->modifiers & shiftKey) != 0), browser->uri_te); browser_update_menu(browser); return; } - HLock(browser->output_tv); r = (*(browser->output_tv))->view; - HUnlock(browser->output_tv); if (PtInRect(p, &r)) { TVClick(browser->output_tv, p, ((event->modifiers & shiftKey) != 0)); @@ -572,7 +558,7 @@ browser_mouse_down(struct focusable *focusable, EventR if (TrackControl(control, p, 0L) && control == browser->go_stop) { if (browser->loading_page) { browser_stop_loading_page(browser); - browser_statusf(browser, "Stopped loading"); + browser_statusf(browser, "Stopped"); } else browser_go(browser, 0); } else if (TrackControl(control, p, 0L) && control == browser->back) @@ -645,6 +631,7 @@ browser_handle_menu(struct focusable *focusable, short TESetSelect(0, 1024 * 32, browser->uri_te); return true; } + browser_update_buttons(browser); break; } @@ -654,15 +641,12 @@ browser_handle_menu(struct focusable *focusable, short void browser_go_uri(struct browser *browser, char *uristr) { - TERec *te; Rect r; TESetText(uristr, strlen(uristr), browser->uri_te); TESetSelect(SHRT_MAX, SHRT_MAX, browser->uri_te); - HLock(browser->uri_te); r = (*(browser->uri_te))->viewRect; - HUnlock(browser->uri_te); TEUpdate(&r, browser->uri_te); browser_go(browser, 0); @@ -680,19 +664,14 @@ browser_go(struct browser *browser, short dir) browser_statusf(browser, ""); if (dir == 0) { - HLock(browser->uri_te); - te = *(browser->uri_te); - len = te->teLength; + len = (*(browser->uri_te))->teLength; uristr = xmalloc(len + 1); if (uristr == NULL) { warn("Out of memory"); return; } - HLock(te->hText); - memcpy(uristr, *(te->hText), len); - HUnlock(te->hText); + memcpy(uristr, *((*(browser->uri_te))->hText), len); uristr[len] = '\0'; - HUnlock(browser->uri_te); browser_create_page(browser, uristr); xfree(&uristr); @@ -703,23 +682,23 @@ browser_go(struct browser *browser, short dir) if (!pageh) return; - HLock(pageh); - page = *pageh; - if (dir == -1) - opage = page->back_page; - else - opage = page->fwd_page; - HUnlock(pageh); + opage = (dir == -1) ? (*pageh)->back_page : (*pageh)->fwd_page; if (!opage) return; HLock(opage); - if ((*opage)->handler->init(opage) && (*opage)->content_len == 0) - /* page didn't load before, try again */ - browser->loading_page = opage; - HLock(opage); - (*opage)->handler->process(opage); - HUnlock(opage); + browser->loading_page = opage; + browser_update_buttons(browser); + + if ((*opage)->handler->init(*opage)) { + HUnlock(opage); + browser_commit_to_loading_page(browser); + } else { + (*opage)->handler->cleanup(*opage); + HUnlock(opage); + browser->loading_page = NULL; + browser_update_buttons(browser); + } } } @@ -757,17 +736,19 @@ browser_create_page(struct browser *browser, char *uri browser->loading_page = pageh; browser_update_buttons(browser); - if (handler->init(pageh)) - return pageh; - - /* handler failed, no point in keeping page */ - browser->loading_page = NULL; - browser_update_buttons(browser); HLock(pageh); - page = *pageh; - xfree(&page->uri); - DisposeHandle(pageh); - return NULL; + if (!handler->init(*pageh)) { + /* handler failed, no point in keeping page */ + (*pageh)->handler->cleanup(*pageh); + browser->loading_page = NULL; + browser_update_buttons(browser); + xfree(&(*pageh)->uri); + DisposeHandle(pageh); + return NULL; + } + + HUnlock(pageh); + return pageh; } warn("Could not parse URI \"%s\"", uristr); @@ -865,10 +846,8 @@ browser_print_link(struct browser *browser, const char return 0; } - HLock(browser->output_tv); link->pos = (*(browser->output_tv))->text_length; link->len = title_len ? title_len : uri_len; - HUnlock(browser->output_tv); link->uri = (char *)link + sizeof(struct browser_link); memcpy(link->uri, uri, uri_len); @@ -897,26 +876,21 @@ browser_print_link(struct browser *browser, const char } void -browser_commit_to_page(struct browser *browser, page_handle pageh) +browser_commit_to_loading_page(struct browser *browser) { - struct page *page; page_handle tpage, fpage, bpage; Rect r; browser_free_links(browser); - HLock(pageh); - page = *pageh; - - if (browser->current_page == pageh) + if (browser->current_page == browser->loading_page) Debugger(); - TESetText(page->uri->str, strlen(page->uri->str), browser->uri_te); + TESetText((*(browser->loading_page))->uri->str, + strlen((*(browser->loading_page))->uri->str), browser->uri_te); TESetSelect(SHRT_MAX, SHRT_MAX, browser->uri_te); - HLock(browser->uri_te); r = (*(browser->uri_te))->viewRect; - HUnlock(browser->uri_te); TEUpdate(&r, browser->uri_te); TVAutoCalc(browser->output_tv, true); @@ -924,43 +898,85 @@ browser_commit_to_page(struct browser *browser, page_h TVUpdateScrollbar(browser->output_tv, browser->output_tv_scroller); if (browser->current_page) { - HLock(browser->current_page); fpage = (*(browser->current_page))->fwd_page; bpage = (*(browser->current_page))->back_page; - HUnlock(browser->current_page); - if (pageh == bpage) { + if (browser->loading_page == bpage) { /* we're going backwards in history */ - } else if (pageh == fpage) { + } else if (browser->loading_page == fpage) { /* we're going fowards in history */ } else { /* purge any forward pages because we're forking history now */ while (fpage) { - HLock(fpage); tpage = (*fpage)->fwd_page; DisposeHandle(fpage); fpage = tpage; } - HLock(browser->current_page); - (*(browser->current_page))->fwd_page = pageh; - HUnlock(browser->current_page); - - page->back_page = browser->current_page; + (*(browser->current_page))->fwd_page = browser->loading_page; + (*(browser->loading_page))->back_page = browser->current_page; } } - browser->current_page = pageh; - HUnlock(pageh); - + browser->current_page = browser->loading_page; browser_update_buttons(browser); } -size_t -browser_grow_page_content(page_handle pageh, size_t len) +bool +browser_start_download(struct browser *browser, char *filename) { + char buf[256], pfilename[32]; + SFReply reply; + short error, frefnum; + + if (filename) { + snprintf(buf, sizeof(buf), "Save %s:", filename); + strlcpy(pfilename, filename, sizeof(pfilename)); + CtoPstr(pfilename); + } else { + snprintf(buf, sizeof(buf), "Save file:"); + pfilename[0] = '0'; + } + CtoPstr(buf); + + SFPutFile(centered_sfput_dialog(), buf, pfilename, NULL, &reply); + if (!reply.good) + return false; + + error = Create(reply.fName, reply.vRefNum, '????', '????'); + if (error && error != dupFNErr) { + warn("Failed to create file %s: %d", PtoCstr(reply.fName), error); + return false; + } + + error = FSOpen(reply.fName, reply.vRefNum, &frefnum); + if (error) { + warn("Failed to open new file %s: %d", PtoCstr(reply.fName), error); + return false; + } + + error = SetEOF(frefnum, 0); + if (error) { + warn("Failed to truncate file %s: %d", PtoCstr(reply.fName), error); + return false; + } + + (*(browser->loading_page))->download_frefnum = frefnum; + return true; +} + +struct page * +browser_grow_page_content(struct page *page, size_t len) +{ unsigned long size, gsize; + page_handle pageh; + pageh = (page_handle)RecoverHandle(page); + if (pageh == NULL) { + Debugger(); + return NULL; + } + HLock(pageh); size = (*pageh)->content_size + MAX(len, PAGE_CONTENT_CHUNK_SIZE); HUnlock(pageh); @@ -969,12 +985,12 @@ browser_grow_page_content(page_handle pageh, size_t le SetHandleSize(pageh, gsize); if (MemError() != 0) { warn("Out of memory growing page to %ld bytes", gsize); - return 0; + return NULL; } HLock(pageh); (*pageh)->content_size = size; - HUnlock(pageh); - return size; + /* keep locked */ + return *pageh; } --- browser.h Sun Nov 3 11:22:13 2024 +++ browser.h Tue Nov 5 21:28:05 2024 @@ -23,6 +23,9 @@ #include "tcp.h" #include "util.h" +//#define BROWSER_DEBUGF(x) browser_statusf +#define BROWSER_DEBUGF(x) + #define STYLE_NONE 0 #define STYLE_BOLD (1UL << 0) #define STYLE_ITALIC (1UL << 1) @@ -70,10 +73,9 @@ size_t browser_statusf(struct browser *browser, const size_t browser_print_link(struct browser *browser, const char *url, size_t url_len, const char *title, size_t title_len); size_t browser_print(struct browser *browser, const char *str, size_t len); -//#define BROWSER_DEBUGF(x) browser_statusf -#define BROWSER_DEBUGF(x) -void browser_commit_to_page(struct browser *browser, page_handle pageh); -size_t browser_grow_page_content(page_handle pageh, size_t len); +struct page * browser_grow_page_content(struct page *page, size_t len); void browser_go_uri(struct browser *browser, char *uristr); +void browser_commit_to_loading_page(struct browser *browser); +bool browser_start_download(struct browser *browser, char *filename); #endif \ No newline at end of file --- detritus.h Mon Nov 4 11:11:36 2024 +++ detritus.h Wed Nov 6 09:45:19 2024 @@ -72,21 +72,31 @@ struct page { size_t content_len; size_t content_pos; struct uri_handler *handler; - void *handler_cookie; + void *fetch_cookie; char type[32]; + short state; short parse_state; struct URI *redir_to; + short download_frefnum; + size_t download_len; char content[]; }; struct uri_handler { + /* return a URI if this handler can process this string */ struct URI * (*parse_uri)(char *uristr); + /* do any post-init on a new page, like doing a request if no content */ - bool (*init)(page_handle pageh); - /* process any request or parse existing content */ - bool (*process)(page_handle pageh); + bool (*init)(struct page *page); + + /* continue fetching content */ + bool (*fetch)(struct page *page); + + /* parse existing content */ + bool (*process)(struct page *page); + /* cleanup when done loading, such as freeing request */ - void (*cleanup)(page_handle pageh); + void (*cleanup)(struct page *page); }; extern MenuHandle file_menu, edit_menu, bookmarks_menu; --- finger.c Mon Nov 4 14:28:05 2024 +++ finger.c Wed Nov 6 12:57:34 2024 @@ -36,15 +36,15 @@ struct finger_request { }; struct URI * finger_parse_uri(char *uristr); -bool finger_init_request(page_handle pageh); -bool finger_process(page_handle pageh); -void finger_cleanup(page_handle pageh); +bool finger_init_request(struct page *page); +bool finger_fetch(struct page *page); +bool finger_process(struct page *page); +void finger_cleanup(struct page *page); -static bool parse_content(struct page *page); - struct uri_handler finger_handler = { finger_parse_uri, finger_init_request, + finger_fetch, finger_process, finger_cleanup, }; @@ -56,9 +56,8 @@ finger_parse_uri(char *uristr) } bool -finger_init_request(page_handle pageh) +finger_init_request(struct page *page) { - struct page *page; struct finger_request *req = NULL; size_t len; char ip_s[12 + 3 + 1]; @@ -66,18 +65,16 @@ finger_init_request(page_handle pageh) ip_addr ip, local_ip; tcp_port port, local_port; - HLock(pageh); - page = *pageh; if (page->content_len) { /* already fetched, nothing to do here but reset */ page->content_pos = 0; - goto done; + return true; } req = xmalloczero(sizeof(struct finger_request)); if (req == NULL) { warn("Out of memory"); - goto fail; + return false; } if (page->uri->port == 0) @@ -89,7 +86,7 @@ finger_init_request(page_handle pageh) err = DNSResolveName(page->uri->hostname, &ip, NULL); if (err) { browser_statusf(page->browser, "Error: Failed resolving: %d", err); - goto fail; + return false; } long2ip(ip, (char *)&ip_s); @@ -100,7 +97,7 @@ finger_init_request(page_handle pageh) sizeof(req->tcp_buf), NULL, NULL, NULL, false); if (err) { browser_statusf(page->browser, "Error: TCPCreate failed: %d", err); - goto fail; + return false; } err = _TCPActiveOpen(&req->tcp_iopb, req->tcp_stream, ip, @@ -109,7 +106,7 @@ finger_init_request(page_handle pageh) browser_statusf(page->browser, "Error: Failed connecting to %s (%s) port %d: %d", page->uri->hostname, ip_s, page->uri->port, err); - goto fail; + return false; } err = _TCPStatus(&req->tcp_iopb, req->tcp_stream, &req->tcp_status_pb, @@ -118,7 +115,7 @@ finger_init_request(page_handle pageh) browser_statusf(page->browser, "Error: Failed TCPStatus on connection to %s (%s) port %d: %d", page->uri->hostname, ip_s, page->uri->port, err); - goto fail; + return false; } if (page->uri->path[0] == '\0' || @@ -140,154 +137,95 @@ finger_init_request(page_handle pageh) NULL, false); if (err) { browser_statusf(page->browser, "Error: TCPSend failed: %d", err); - goto fail; + return false; } - page->handler_cookie = req; - -done: - HUnlock(pageh); - browser_commit_to_page(page->browser, pageh); - + page->fetch_cookie = req; return true; - -fail: - if (req) { - if (req->tcp_stream) { - _TCPAbort(&req->tcp_iopb, req->tcp_stream, NULL, NULL, false); - _TCPRelease(&req->tcp_iopb, req->tcp_stream, NULL, NULL, false); - } - - xfree(&req); - page->handler_cookie = NULL; - } - - HUnlock(pageh); - return false; } void -finger_cleanup(page_handle pageh) +finger_cleanup(struct page *page) { struct finger_request *req; - struct page *page; - HLock(pageh); - page = *pageh; - req = (struct finger_request *)(page->handler_cookie); - - if (req) { - if (req->tcp_stream) { - _TCPAbort(&req->tcp_iopb, req->tcp_stream, NULL, NULL, false); - _TCPRelease(&req->tcp_iopb, req->tcp_stream, NULL, NULL, false); - } - - xfree(&page->handler_cookie); - } - - HUnlock(pageh); + if (page->fetch_cookie == NULL) + return; + + req = (struct finger_request *)(page->fetch_cookie); + + if (req->tcp_stream) + _TCPRelease(&req->tcp_iopb, req->tcp_stream, NULL, NULL, false); + + xfree(&page->fetch_cookie); } bool -finger_process(page_handle pageh) +finger_fetch(struct page *page) { struct finger_request *req; - struct page *page; - size_t size, len, n; short err; unsigned short slen; - bool ret; - HLock(pageh); - page = *pageh; - - if (page->handler_cookie == NULL) - goto parse; + if (page->fetch_cookie == NULL) + return false; - req = (struct finger_request *)(page->handler_cookie); + req = (struct finger_request *)(page->fetch_cookie); if (req->tcp_iopb.ioResult > 0 || CommandPeriodPressed()) { BROWSER_DEBUGF((page->browser, "TCP I/O Result %d, disconnecting", req->tcp_iopb.ioResult)); - goto finish_request; + return false; } err = _TCPStatus(&req->tcp_iopb, req->tcp_stream, &req->tcp_status_pb, NULL, NULL, false); if (err) { browser_statusf(page->browser, "Error: Bad TCPStatus: %d", err); - goto finish_request; + return false; } if (req->tcp_status_pb.connectionState != ConnectionStateEstablished) { - BROWSER_DEBUGF((page->browser, "TCP connection closed (state %d)", + BROWSER_DEBUGF((page->browser, "TCP connection closed (state %d)", req->tcp_status_pb.connectionState)); - goto finish_request; + return false; } - if (req->tcp_status_pb.amtUnreadData == 0) - goto parse; + + slen = req->tcp_status_pb.amtUnreadData; + if (slen == 0) + return true; - if (page->content_len + req->tcp_status_pb.amtUnreadData >= - page->content_size) { - if (!browser_grow_page_content(pageh, - req->tcp_status_pb.amtUnreadData)) + if (page->content_len + slen >= page->content_size) { + page = browser_grow_page_content(page, slen); + if (page == NULL) return false; - HLock(pageh); - page = *pageh; - req = (struct finger_request *)(page->handler_cookie); + req = (struct finger_request *)(page->fetch_cookie); } - slen = req->tcp_status_pb.amtUnreadData; err = _TCPRcv(&req->tcp_iopb, req->tcp_stream, (Ptr)(page->content + page->content_len), &slen, NULL, NULL, false); if (err) { browser_statusf(page->browser, "Error: Failed TCPRcv: %d", err); - goto finish_request; + return false; } + page->content_len += slen; browser_statusf(page->browser, "Read %ld bytes", page->content_len); - goto parse; - -finish_request: - finger_cleanup(pageh); - -parse: - HLock(pageh); - page = *pageh; - - if (page->content_pos == page->content_len) { - if (!page->handler_cookie) { - /* nothing left to do */ - return false; - } - HUnlock(pageh); - return true; - } - - TVAutoCalc(page->browser->output_tv, false); - ret = parse_content(page); - TVCalcLines(page->browser->output_tv); - TVUpdate(page->browser->output_tv); - TVUpdateScrollbar(page->browser->output_tv, - page->browser->output_tv_scroller); - - if (ret) { - HUnlock(pageh); - return true; - } - -request_fail: - HUnlock(pageh); - return false; + return true; } -static bool -parse_content(struct page *page) +bool +finger_process(struct page *page) { long n, plines = 0; - + bool ret = true; + + if (page->content_pos == page->content_len) + return (page->fetch_cookie != NULL); + + TVAutoCalc(page->browser->output_tv, false); page->browser->style = STYLE_PRE; /* text file, convert newlines and display */ @@ -322,16 +260,19 @@ parse_content(struct page *page) } } - if (!page->handler_cookie && + if (page->fetch_cookie == NULL && page->content_pos < page->content_len) { + /* no request to fetch more content, finish */ browser_print(page->browser, page->content + page->content_pos, page->content_len - page->content_pos); page->content_pos = page->content_len; - return false; + ret = false; } - if (page->handler_cookie) - return true; + TVCalcLines(page->browser->output_tv); + TVUpdate(page->browser->output_tv); + TVUpdateScrollbar(page->browser->output_tv, + page->browser->output_tv_scroller); - return false; + return ret; } --- gemini.c Mon Nov 4 14:28:38 2024 +++ gemini.c Wed Nov 6 13:06:39 2024 @@ -54,20 +54,21 @@ struct gemini_request { }; struct URI * gemini_parse_uri(char *uristr); -bool gemini_init_request(page_handle pageh); -bool gemini_process(page_handle pageh); -void gemini_cleanup(page_handle pageh); +bool gemini_init_request(struct page *page); +bool gemini_fetch(struct page *page); +bool gemini_process(struct page *page); +void gemini_cleanup(struct page *page); static bool shuffle_read_tls_ciphertext(struct page *page); static bool shuffle_read_tcp_ciphertext(struct page *page, short space); static bool shuffle_tls_send_plaintext(struct page *page, short space); static bool shuffle_tls_read_plaintext(struct page *page); static bool parse_header(struct page *page, char *str, size_t len); -static bool parse_content(struct page *page); struct uri_handler gemini_handler = { gemini_parse_uri, gemini_init_request, + gemini_fetch, gemini_process, gemini_cleanup, }; @@ -79,9 +80,8 @@ gemini_parse_uri(char *uristr) } bool -gemini_init_request(page_handle pageh) +gemini_init_request(struct page *page) { - struct page *page; struct gemini_request *req = NULL; struct tls_init_request tls_req; char ip_s[12 + 3 + 1]; @@ -90,24 +90,22 @@ gemini_init_request(page_handle pageh) ip_addr ip, local_ip; tcp_port port, local_port; - HLock(pageh); - page = *pageh; if (page->content_len) { /* already fetched, nothing to do here but reset */ page->content_pos = 0; page->parse_state = PARSE_STATE_HEADER; - goto done; + return true; } if (!scsi_can_do_tls()) { warn("No TLS accelerator found, cannot make Gemini requests"); - goto fail; + return false; } req = xmalloczero(sizeof(struct gemini_request)); if (req == NULL) { warn("Out of memory"); - goto fail; + return false; } if (page->uri->port == 0) @@ -177,84 +175,67 @@ gemini_init_request(page_handle pageh) goto fail; } - page->handler_cookie = req; - -done: - HUnlock(pageh); + page->fetch_cookie = req; return true; fail: if (req) { - if (req->tcp_stream) { - _TCPAbort(&req->tcp_iopb, req->tcp_stream, NULL, NULL, false); + if (req->tcp_stream) _TCPRelease(&req->tcp_iopb, req->tcp_stream, NULL, NULL, false); - } xfree(&req); - page->handler_cookie = NULL; + page->fetch_cookie = NULL; } - HUnlock(pageh); return false; } void -gemini_cleanup(page_handle pageh) +gemini_cleanup(struct page *page) { struct gemini_request *req; - struct page *page; - HLock(pageh); - page = *pageh; - - if (page->handler_cookie) { - req = (struct gemini_request *)(page->handler_cookie); - - if (req->tcp_stream) { - _TCPAbort(&req->tcp_iopb, req->tcp_stream, NULL, NULL, false); - _TCPRelease(&req->tcp_iopb, req->tcp_stream, NULL, NULL, false); - } - - if (req->tls_id) - scsi_tls_close(req->tls_id); + if (page->fetch_cookie == NULL) + return; - xfree(&page->handler_cookie); - } + req = (struct gemini_request *)(page->fetch_cookie); - HUnlock(pageh); + if (req->tcp_stream) + _TCPRelease(&req->tcp_iopb, req->tcp_stream, NULL, NULL, false); + + if (req->tls_id) + scsi_tls_close(req->tls_id); + + xfree(&page->fetch_cookie); } bool -gemini_process(page_handle pageh) +gemini_fetch(struct page *page) { + page_handle pageh; struct gemini_request *req; - struct page *page; size_t len; unsigned short slen; short err, status; short cipherspace, plainspace, error; bool ret; - HLock(pageh); - page = *pageh; - - if (page->handler_cookie == NULL) { - ret = parse_content(page); - HUnlock(pageh); - return ret; - } + if (page->fetch_cookie == NULL) + return false; - req = (struct gemini_request *)(page->handler_cookie); + req = (struct gemini_request *)(page->fetch_cookie); if (req->tcp_iopb.ioResult > 0 || CommandPeriodPressed()) { BROWSER_DEBUGF((page->browser, "TCP I/O Result %d, disconnecting", req->tcp_iopb.ioResult)); - goto finish_request; + return false; } status = scsi_tls_status(req->tls_id, &cipherspace, &plainspace, &error); + pageh = (page_handle)RecoverHandle(page); + while (status != 0) { if ((status & 0x1) && page->content_pos == page->content_len) { /* closed */ @@ -262,22 +243,21 @@ gemini_process(page_handle pageh) browser_statusf(page->browser, "Error: TLS handshake failed: %d (TLS status 0x%x)", error, status); - goto finish_request; + return false; } if (status & 0x2) { /* tls has ciphertext for tcp */ if (!shuffle_read_tls_ciphertext(page)) - goto finish_request; - HLock(pageh); - page = *pageh; + return false; status &= ~0x2; } if ((status & 0x10) || page->content_pos < page->content_len) { /* tls has plaintext data for us */ if (!shuffle_tls_read_plaintext(page)) - goto finish_request; + return false; + /* handle may have grown */ HLock(pageh); page = *pageh; status &= ~0x10; @@ -286,34 +266,24 @@ gemini_process(page_handle pageh) if (status & 0x8) { /* tls can read plaintext from us */ if (!shuffle_tls_send_plaintext(page, plainspace)) - goto finish_request; - HLock(pageh); - page = *pageh; + return false; status &= ~0x8; } if (status & 0x4) { /* tls can read ciphertext from tcp */ if (!shuffle_read_tcp_ciphertext(page, cipherspace)) - goto finish_request; - HLock(pageh); - page = *pageh; + return false; status &= ~0x4; } if (status) { browser_statusf(page->browser, "TLS status is 0x%x?", status); - goto finish_request; + return false; } } - HUnlock(pageh); return true; - -finish_request: - HUnlock(pageh); - gemini_cleanup(pageh); - return false; } static bool @@ -326,7 +296,7 @@ shuffle_read_tls_ciphertext(struct page *page) /* read ciphertext from TLS and send it out TCP */ - req = (struct gemini_request *)(page->handler_cookie); + req = (struct gemini_request *)(page->fetch_cookie); len = scsi_tls_read(req->tls_id, &buf, 0, true); if (len == 0 || buf == NULL) { @@ -365,7 +335,7 @@ shuffle_read_tcp_ciphertext(struct page *page, short s /* read ciphertext from TCP and send it to TLS */ - req = (struct gemini_request *)(page->handler_cookie); + req = (struct gemini_request *)(page->fetch_cookie); if (req->tcp_input_len == sizeof(req->tcp_input) || req->tcp_done_reading) @@ -445,7 +415,7 @@ shuffle_tls_send_plaintext(struct page *page, short sp /* send any plaintext from us to TLS */ - req = (struct gemini_request *)(page->handler_cookie); + req = (struct gemini_request *)(page->fetch_cookie); if (req->message_len == 0) return true; @@ -492,19 +462,17 @@ shuffle_tls_read_plaintext(struct page *page) /* read as much plaintext from TLS as we can buffer */ - req = (struct gemini_request *)(page->handler_cookie); + req = (struct gemini_request *)(page->fetch_cookie); len = scsi_tls_read(req->tls_id, &buf, PAGE_CONTENT_CHUNK_SIZE, false); if (len == 0) return true; if (page->content_len + len >= page->content_size) { - pageh = (page_handle)RecoverHandle(page); - if (!browser_grow_page_content(pageh, len)) + page = browser_grow_page_content(page, len); + if (page == NULL) return false; - HLock(pageh); - page = *pageh; - req = (struct gemini_request *)(page->handler_cookie); + req = (struct gemini_request *)(page->fetch_cookie); } memcpy(page->content + page->content_len, buf, len); @@ -512,16 +480,19 @@ shuffle_tls_read_plaintext(struct page *page) browser_statusf(page->browser, "Read %ld bytes", page->content_len); - return parse_content(page); + return true; } static bool -parse_content(struct page *page) +gemini_process(struct page *page) { + page_handle pageh; size_t n, trail, skip, len; char c; bool newline; + pageh = (page_handle)RecoverHandle(page); + handle_state: switch (page->parse_state) { case PARSE_STATE_HEADER: { @@ -540,10 +511,11 @@ handle_state: return false; } - if (strcmp(page->type, "text/gemini") == 0) { + if (strncmp(page->type, "text/gemini", 10) == 0) { page->parse_state = PARSE_STATE_GEMTEXT; - browser_commit_to_page(page->browser, - (page_handle)RecoverHandle(page)); + browser_commit_to_loading_page(page->browser); + HLock(pageh); + page = *pageh; } else page->parse_state = PARSE_STATE_DOWNLOAD; @@ -553,7 +525,7 @@ handle_state: goto handle_state; } - if (page->handler_cookie == NULL) + if (page->fetch_cookie == NULL) /* no more data will be coming */ return false; @@ -583,7 +555,7 @@ handle_state: len--; trail++; } - } else if (page->handler_cookie != NULL) { + } else if (page->fetch_cookie != NULL) { /* * No newline found at the end of the buffer, but the * buffer isn't full so wait for more data. --- gopher.c Mon Nov 4 14:29:11 2024 +++ gopher.c Wed Nov 6 12:57:26 2024 @@ -23,6 +23,8 @@ #define GOPHER_PORT 70 +static const char showable_types[] = "013i"; + struct gopher_request { unsigned char tcp_buf[(4 * 1500) + 2048]; /* 4*MTU + tcp_input */ @@ -36,16 +38,17 @@ struct gopher_request { }; struct URI * gopher_parse_uri(char *uristr); -bool gopher_init_request(page_handle pageh); -bool gopher_process(page_handle pageh); -void gopher_cleanup(page_handle pageh); +bool gopher_init_request(struct page *page); +bool gopher_fetch(struct page *page); +bool gopher_process(struct page *page); +void gopher_cleanup(struct page *page); -static bool parse_content(struct page *page); static void gopher_print_menu(struct page *page, char *line, size_t len); struct uri_handler gopher_handler = { gopher_parse_uri, gopher_init_request, + gopher_fetch, gopher_process, gopher_cleanup, }; @@ -57,28 +60,25 @@ gopher_parse_uri(char *uristr) } bool -gopher_init_request(page_handle pageh) +gopher_init_request(struct page *page) { - struct page *page; struct gopher_request *req = NULL; size_t len; - char ip_s[12 + 3 + 1]; + char ip_s[12 + 3 + 1], *filename; short err; ip_addr ip, local_ip; tcp_port port, local_port; - HLock(pageh); - page = *pageh; if (page->content_len) { /* already fetched, nothing to do here but reset */ page->content_pos = 0; - goto done; + return true; } req = xmalloczero(sizeof(struct gopher_request)); if (req == NULL) { warn("Out of memory"); - goto fail; + return false; } if (page->uri->port == 0) @@ -90,7 +90,7 @@ gopher_init_request(page_handle pageh) err = DNSResolveName(page->uri->hostname, &ip, NULL); if (err) { browser_statusf(page->browser, "Error: Failed resolving: %d", err); - goto fail; + return false; } long2ip(ip, (char *)&ip_s); @@ -101,7 +101,7 @@ gopher_init_request(page_handle pageh) sizeof(req->tcp_buf), NULL, NULL, NULL, false); if (err) { browser_statusf(page->browser, "Error: TCPCreate failed: %d", err); - goto fail; + return false; } err = _TCPActiveOpen(&req->tcp_iopb, req->tcp_stream, ip, @@ -110,7 +110,7 @@ gopher_init_request(page_handle pageh) browser_statusf(page->browser, "Error: Failed connecting to %s (%s) port %d: %d", page->uri->hostname, ip_s, page->uri->port, err); - goto fail; + return false; } err = _TCPStatus(&req->tcp_iopb, req->tcp_stream, &req->tcp_status_pb, @@ -119,7 +119,7 @@ gopher_init_request(page_handle pageh) browser_statusf(page->browser, "Error: Failed TCPStatus on connection to %s (%s) port %d: %d", page->uri->hostname, ip_s, page->uri->port, err); - goto fail; + return false; } /* @@ -137,7 +137,7 @@ gopher_init_request(page_handle pageh) req->selector_len = snprintf(req->selector, sizeof(req->selector), "%s\r\n", page->uri->path + 2); } - + browser_statusf(page->browser, "Connected to %s, sending request...", page->uri->hostname); @@ -149,166 +149,144 @@ gopher_init_request(page_handle pageh) NULL, false); if (err) { browser_statusf(page->browser, "Error: TCPSend failed: %d", err); - goto fail; + return false; } - page->handler_cookie = req; - -done: - HUnlock(pageh); - browser_commit_to_page(page->browser, pageh); + page->fetch_cookie = req; - return true; - -fail: - if (req) { - if (req->tcp_stream) { - _TCPAbort(&req->tcp_iopb, req->tcp_stream, NULL, NULL, false); - _TCPRelease(&req->tcp_iopb, req->tcp_stream, NULL, NULL, false); + if (strchr(showable_types, page->type[0]) == NULL) { + if (req->selector_len == 2) + filename = NULL; + else { + filename = strrchr(page->uri->path + 2, '/'); + if (filename && filename[0] == '/') + filename++; + if (!browser_start_download(page->browser, filename)) + return false; } + } else + browser_commit_to_loading_page(page->browser); - xfree(&req); - page->handler_cookie = NULL; - } - - HUnlock(pageh); - return false; + return true; } void -gopher_cleanup(page_handle pageh) +gopher_cleanup(struct page *page) { struct gopher_request *req; - struct page *page; - HLock(pageh); - page = *pageh; - req = (struct gopher_request *)(page->handler_cookie); - - if (req) { - if (req->tcp_stream) { - _TCPAbort(&req->tcp_iopb, req->tcp_stream, NULL, NULL, false); - _TCPRelease(&req->tcp_iopb, req->tcp_stream, NULL, NULL, false); - } - - xfree(&page->handler_cookie); - } - - HUnlock(pageh); + if (page->fetch_cookie == NULL) + return; + + req = (struct gopher_request *)(page->fetch_cookie); + + if (req->tcp_stream) + _TCPRelease(&req->tcp_iopb, req->tcp_stream, NULL, NULL, false); + + xfree(&page->fetch_cookie); } bool -gopher_process(page_handle pageh) +gopher_fetch(struct page *page) { struct gopher_request *req; - struct page *page; - size_t size, len, n; short err; unsigned short slen; - bool ret; + unsigned long llen, ollen; + Ptr rcvptr; - HLock(pageh); - page = *pageh; - - if (page->handler_cookie == NULL) - goto parse; + if (page->fetch_cookie == NULL) + return false; - req = (struct gopher_request *)(page->handler_cookie); + req = (struct gopher_request *)(page->fetch_cookie); if (req->tcp_iopb.ioResult > 0 || CommandPeriodPressed()) { BROWSER_DEBUGF((page->browser, "TCP I/O Result %d, disconnecting", req->tcp_iopb.ioResult)); - goto finish_request; + return false; } err = _TCPStatus(&req->tcp_iopb, req->tcp_stream, &req->tcp_status_pb, NULL, NULL, false); if (err) { browser_statusf(page->browser, "Error: Bad TCPStatus: %d", err); - goto finish_request; + return false; } if (req->tcp_status_pb.connectionState != ConnectionStateEstablished) { - BROWSER_DEBUGF((page->browser, "TCP connection closed (state %d)", + BROWSER_DEBUGF((page->browser, "TCP connection closed (state %d)", req->tcp_status_pb.connectionState)); - goto finish_request; + return false; } - if (req->tcp_status_pb.amtUnreadData == 0) - goto parse; + + slen = req->tcp_status_pb.amtUnreadData; + if (slen == 0) + return true; - if (page->content_len + req->tcp_status_pb.amtUnreadData >= - page->content_size) { - if (!browser_grow_page_content(pageh, - req->tcp_status_pb.amtUnreadData)) - return false; - HLock(pageh); - page = *pageh; - req = (struct gopher_request *)(page->handler_cookie); + if (page->download_frefnum) { + rcvptr = (Ptr)(page->content); + if (slen > page->content_size) + slen = page->content_size; + } else { + if (page->content_len + slen >= page->content_size) { + page = browser_grow_page_content(page, slen); + if (page == NULL) + return false; + req = (struct gopher_request *)(page->fetch_cookie); + } + rcvptr = (Ptr)(page->content + page->content_len); } - - slen = req->tcp_status_pb.amtUnreadData; - err = _TCPRcv(&req->tcp_iopb, req->tcp_stream, - (Ptr)(page->content + page->content_len), &slen, NULL, NULL, false); + + err = _TCPRcv(&req->tcp_iopb, req->tcp_stream, rcvptr, &slen, NULL, + NULL, false); if (err) { browser_statusf(page->browser, "Error: Failed TCPRcv: %d", err); - goto finish_request; + return false; } - page->content_len += slen; - browser_statusf(page->browser, "Read %ld bytes", page->content_len); - if ((page->type[0] == '0' || page->type[0] == '1' || - page->type[0] == 3) && page->content_len >= 3 && - (page->content_len == 3 || - page->content[page->content_len - 4] == '\n') && - page->content[page->content_len - 3] == '.' && - page->content[page->content_len - 2] == '\r' && - page->content[page->content_len - 1] == '\n') { - /* ".\r\n" is end of transfer */ - page->content_len -= 3; - goto finish_request; - } - - goto parse; - -finish_request: - gopher_cleanup(pageh); - -parse: - HLock(pageh); - page = *pageh; + if (page->download_frefnum) { + ollen = llen = slen; + err = FSWrite(page->download_frefnum, &llen, page->content); + if (err || ollen != llen) { + warn("Failed to write: %d", err); + return false; + } + + page->download_len += llen; + browser_statusf(page->browser, "Wrote %ld bytes", + page->download_len); + } else { + page->content_len += slen; + browser_statusf(page->browser, "Read %ld bytes", page->content_len); - if (page->content_pos == page->content_len) { - if (!page->handler_cookie) { - /* nothing left to do */ + if (strchr(showable_types, page->type[0]) && + page->content_len >= 3 && + (page->content_len == 3 || + page->content[page->content_len - 4] == '\n') && + page->content[page->content_len - 3] == '.' && + page->content[page->content_len - 2] == '\r' && + page->content[page->content_len - 1] == '\n') { + /* ".\r\n" is end of transfer */ + page->content_len -= 3; return false; } - HUnlock(pageh); - return true; } - TVAutoCalc(page->browser->output_tv, false); - ret = parse_content(page); - TVCalcLines(page->browser->output_tv); - TVUpdate(page->browser->output_tv); - TVUpdateScrollbar(page->browser->output_tv, - page->browser->output_tv_scroller); - - if (ret) { - HUnlock(pageh); - return true; - } - -request_fail: - HUnlock(pageh); - return false; + return true; } -static bool -parse_content(struct page *page) +bool +gopher_process(struct page *page) { long n, plines = 0; + bool ret = true; + if (page->content_pos == page->content_len) + return (page->fetch_cookie != NULL); + + TVAutoCalc(page->browser->output_tv, false); + if (page->type[0] == '1') { /* gopher menu */ for (n = page->content_pos; n < page->content_len; n++) { @@ -330,12 +308,12 @@ parse_content(struct page *page) } } - if (!page->handler_cookie && + if (page->fetch_cookie == NULL && page->content_pos < page->content_len) { gopher_print_menu(page, page->content + page->content_pos, page->content_len - page->content_pos); page->content_pos = page->content_len; - return false; + ret = false; } } else if (page->type[0] == '0') { /* text file, convert newlines and display */ @@ -370,24 +348,27 @@ parse_content(struct page *page) } } - if (!page->handler_cookie && + if (page->fetch_cookie == NULL && page->content_pos < page->content_len) { browser_print(page->browser, page->content + page->content_pos, page->content_len - page->content_pos); page->content_pos = page->content_len; - return false; + ret = false; } } else { /* anything else, just download it */ browser_print(page->browser, page->content + page->content_pos, page->content_len - page->content_pos); page->content_pos = page->content_len; + ret = false; } - if (page->handler_cookie) - return true; + TVCalcLines(page->browser->output_tv); + TVUpdate(page->browser->output_tv); + TVUpdateScrollbar(page->browser->output_tv, + page->browser->output_tv_scroller); - return false; + return ret; } static void @@ -435,7 +416,9 @@ gopher_print_menu(struct page *page, char *line, size_ tlen = snprintf(uri, sizeof(uri), "gopher://%s/%c%s", hostname, type, selector); + page->browser->style |= STYLE_BOLD; browser_print_link(page->browser, uri, tlen, label, strlen(label)); + page->browser->style &= ~(STYLE_BOLD); browser_print(page->browser, "\r", 1); break; } --- main.c Mon Nov 4 11:15:12 2024 +++ main.c Tue Nov 5 20:47:53 2024 @@ -261,7 +261,7 @@ parse_uri(char *uristr, char *restrict_protocol) if (count = 0, sscanf(uristr, "%" STR(URI_MAX_PROTOCOL_LEN) "[^:]://%" STR(URI_MAX_HOSTNAME_LEN) "[^/]%" - STR(URI_MAX_PATH_LEN) "s%n", + STR(URI_MAX_PATH_LEN) "[ -~]%n", /* %s stops at whitespace, use all vis */ &protocol, &hostname, &path, &count) == 3 && count > 10) goto parse_ok; @@ -318,6 +318,7 @@ parse_ok: uri->hostname[hostname_len] = '\0'; data += hostname_len + 1; + /* TODO: cut at ? and put that in query */ uri->path = data; memcpy(uri->path, path, path_len); uri->path[path_len] = '\0';