AmendHub

Download:

jcs

/

subtext

/

amendments

/

17

session: Support view templates

Properly close sessions in telnet+console

jcs made amendment 17 over 2 years ago
--- console.c Sun Dec 5 21:43:35 2021 +++ console.c Tue Dec 7 15:02:14 2021 @@ -29,13 +29,14 @@ struct node_funcs console_node_funcs = { console_input, console_output, + console_close }; void console_redraw(struct console *console, short numhints, short *hints); void console_parse_csi(struct console *console); struct console * -console_init(void) +console_init(struct console **cur_console) { char title[64] = { 0 }; struct console *console; @@ -44,6 +45,7 @@ console_init(void) short width, height; console = xmalloczero(sizeof(struct console)); + console->cur_console = cur_console; memset(console->chars, ' ', sizeof(console->chars)); console->ncolumns = 80; console->nlines = 24; @@ -80,76 +82,31 @@ console_init(void) console->session = session_create("console", &console_node_funcs); console->session->cookie = (void *)console; + *cur_console = console; + return console; } void -console_idle(struct console *console) +console_close(struct session *session) { - console_output(console->session); -} + struct console *console = (struct console *)session->cookie; -void -console_suspend(struct console *console) -{ + DisposeWindow(console->win); + *(console->cur_console) = NULL; + free(console); } void -console_resume(struct console *console) +console_idle(struct console *console) { -} - -void -console_update(struct console *console, EventRecord *event) -{ - Rect r; - short what = -1; - - if (event != NULL) - what = event->what; - - switch (what) { - case -1: - case updateEvt: - console_redraw(console, -1, NULL); - //browser_update_menu(browser); - UpdtControl(console->win, console->win->visRgn); - - break; - case activateEvt: - break; - } -} - -void -console_mouse_down(struct console *console, EventRecord *event) -{ -} - -void -console_key_down(struct console *console, EventRecord *event) -{ - char k; - - if (console->session->ibuflen >= sizeof(console->session->ibuf)) - return; - - k = (event->message & charCodeMask); - console->session->ibuf[console->session->ibuflen++] = k; - if (k == '\r') - console->session->ibuf[console->session->ibuflen++] = '\n'; -} - -short -console_output(struct session *session) -{ - struct console *console = (struct console *)session->cookie; + struct session *session = console->session; short n, len, cursor, iac = 0; short hints[100]; short nhints = 0; if (session->obuflen == 0) - return 0; + return; cursor = (console->cursor_line * console->ncolumns) + console->cursor_column; @@ -166,7 +123,7 @@ console_output(struct session *session) if (console->in_csi) { if (session->obuf[n] == '\e' || - console->csilen >= sizeof(console->csi) - 1) { + console->csilen >= nitems(console->csi) - 1) { console_parse_csi(console); console->in_csi = 0; console->csi[0] = '\0'; @@ -206,7 +163,7 @@ console_output(struct session *session) console->chars[cursor] = session->obuf[n]; console->attrs[cursor] |= ATTR_DIRTY; console->cursor_column++; - if (nhints != -1 && nhints < sizeof(hints) - 1) + if (nhints != -1 && nhints < nitems(hints) - 1) hints[nhints++] = cursor; else nhints = -1; @@ -214,7 +171,6 @@ console_output(struct session *session) } } - len = session->obuflen; session->obuflen = 0; @@ -222,29 +178,85 @@ output_done: cursor = (console->cursor_line * console->ncolumns) + console->cursor_column; console->attrs[cursor] |= (ATTR_DIRTY | ATTR_CURSOR); - if (nhints != -1 && nhints < sizeof(hints) - 1) + if (nhints != -1 && nhints < nitems(hints) - 1) hints[nhints++] = cursor; else if (nhints == -1) nhints = 0; console_redraw(console, nhints, hints); +} + +void +console_suspend(struct console *console) +{ +} + +void +console_resume(struct console *console) +{ +} + +void +console_update(struct console *console, EventRecord *event) +{ + Rect r; + short what = -1; - return len; + if (event != NULL) + what = event->what; + + switch (what) { + case -1: + case updateEvt: + console_redraw(console, -1, NULL); + //browser_update_menu(browser); + UpdtControl(console->win, console->win->visRgn); + + break; + case activateEvt: + break; + } } +void +console_mouse_down(struct console *console, EventRecord *event) +{ +} + +void +console_key_down(struct console *console, EventRecord *event) +{ + char k; + + if (console->session->ibuflen >= nitems(console->session->ibuf)) + return; + + k = (event->message & charCodeMask); + console->session->ibuf[console->session->ibuflen++] = k; + if (k == '\r') + console->session->ibuf[console->session->ibuflen++] = '\n'; +} + short +console_output(struct session *session) +{ + /* nothing to do here, output is printed from console_idle */ + uthread_yield(); + return 0; +} + +short console_input(struct session *session) { - /* nothing to do, input is fed from main loop */ + /* nothing to do here, input is fed from main loop */ uthread_yield(); return 0; } void -console_redraw(struct console *console, short nhints, short hints[]) +console_redraw(struct console *console, short nhints, short *hints) { Rect cursor; - short n, cell, line = 0, column = 0; - short nsize; + short n, nsize, cell, line = 0, column = 0; TextFont(monaco); TextSize(9); @@ -252,7 +264,7 @@ console_redraw(struct console *console, short nhints, if (nhints > 0) nsize = nhints; else { - nsize = sizeof(console->chars); + nsize = nitems(console->chars); SetCursor(*(GetCursor(watchCursor))); } @@ -343,7 +355,7 @@ console_parse_csi(struct console *console) param1 = 1; if (console->csilen > 1) { - for (x = 0; x < console->csilen - 1, x < sizeof(parambuf); x++) { + for (x = 0; x < console->csilen - 1, x < nitems(parambuf); x++) { parambuf[x] = console->csi[x]; parambuf[x + 1] = '\0'; } @@ -619,24 +631,8 @@ console_parse_csi(struct console *console) session_output(console->session, "\e[0n"); break; case 6: /* CPR - report cursor position */ - session_output(console->session, "\e["); - - sprintf(parambuf, "%d", console->cursor_line + 1); - for (x = 0; x < sizeof(parambuf); x++) { - if (parambuf[x] == '\0') - break; - session_output_char(console->session, parambuf[x]); - } - session_output_char(console->session, ';'); - - sprintf(parambuf, "%d", console->cursor_column + 1); - for (x = 0; x < sizeof(parambuf); x++) { - if (parambuf[x] == '\0') - break; - session_output_char(console->session, parambuf[x]); - } - - session_output_char(console->session, 'R'); + session_output(console->session, "\e[%d;%dR", + console->cursor_line + 1, console->cursor_column + 1); break; } break; --- console.h Sun Nov 28 13:22:53 2021 +++ console.h Mon Dec 6 17:32:18 2021 @@ -21,6 +21,7 @@ struct console { short state; + struct console **cur_console; WindowPtr win; ControlHandle scroller; char chars[80 * 24]; @@ -41,7 +42,7 @@ struct console { struct session *session; }; -struct console *console_init(void); +struct console *console_init(struct console **cur_console); void console_idle(struct console *console); void console_suspend(struct console *console); void console_resume(struct console *console); @@ -49,6 +50,7 @@ void console_update(struct console *console, EventReco void console_mouse_down(struct console *console, EventRecord *event); void console_key_down(struct console *console, EventRecord *event); +void console_close(struct session *session); short console_output(struct session *session); short console_input(struct session *session); short console_read(struct session *session); --- db.c Mon Dec 6 09:26:36 2021 +++ db.c Mon Dec 6 14:25:11 2021 @@ -168,7 +168,7 @@ db_init(char *path, short is_new) tdb = xmalloczero(sizeof(struct db)); tdb->fh = fh; - memcpy(tdb->filename, path, strlen(path) + 1); + strlcpy(tdb->filename, path, sizeof(tdb->filename)); if (db_migrate(tdb, is_new) != 0) { free(tdb); --- db.h Sun Dec 5 22:59:33 2021 +++ db.h Mon Dec 6 10:35:10 2021 @@ -25,16 +25,21 @@ #define DB_TYPE 'STDB' +#define DB_CUR_VERS 1 + +#define DB_TRUE 0x100 +#define DB_FALSE 0x000 + #define DB_CONFIG_RTYPE 'STCF' #define DB_USER_RTYPE 'STUS' #define DB_BOARD_RTYPE 'STBD' #define DB_FILEAREA_RTYPE 'STFL' #define DB_VERS_RTYPE 'STVR' -#define DB_CUR_VERS 1 - -#define DB_TRUE 0x100 -#define DB_FALSE 0x000 +#define DB_TEXT_TYPE 'TEXT' +#define DB_TEXT_MENU_ID 1 +#define DB_TEXT_SHORTMENU_ID 2 +#define DB_TEXT_ISSUE_ID 3 struct config { char name[32]; --- main.c Mon Dec 6 09:45:14 2021 +++ main.c Tue Dec 7 15:08:48 2021 @@ -45,12 +45,10 @@ main(void) AppFile finder_file; short event_in, n, finder_action, finder_count; char *dbpath; - char key; + char key, iters; uthread_init(); - mainResFile = CurMap; - InitGraf(&thePort); InitFonts(); FlushEvents(everyEvent, 0); @@ -61,6 +59,7 @@ main(void) InitCursor(); MaxApplZone(); + mainResFile = CurMap; err_init(); load_db_tmpls(); @@ -87,18 +86,23 @@ main(void) if (!db) ExitToShell(); - cur_console = console_init(); + console_init(&cur_console); if (db->config.telnet_port) telnet_init(); + iters = 0; while (!quitting) { if (db->config.telnet_port) telnet_idle(); uthread_coordinate(); - WaitNextEvent(everyEvent, &event, 1, 0); - + if (++iters % 10 == 0) { + WaitNextEvent(everyEvent, &event, 1, 0); + iters = 0; + } else if (!GetNextEvent(everyEvent, &event)) + continue; + switch (event.what) { case nullEvent: if (cur_console) --- session.c Mon Dec 6 10:01:19 2021 +++ session.c Tue Dec 7 13:20:38 2021 @@ -46,7 +46,7 @@ session_create(char *node, struct node_funcs *node_fun session->state = SESSION_STATE_INIT; session->node_funcs = node_funcs; - memcpy(session->node, node, sizeof(session->node)); + strlcpy(session->node, node, sizeof(session->node)); nsessions++; sessions = xreallocarray(sessions, nsessions, sizeof(struct session)); @@ -59,26 +59,68 @@ void session_run(struct uthread *uthread, void *arg) { struct session *s = (struct session *)arg; + Handle h; + char *view; + size_t len; - session_output(s, "\r\n" - "Welcome to %s (%s)\r\n" - "\r\n", db->config.name, s->node); + len = session_load_view(s, DB_TEXT_ISSUE_ID, &view); + if (len) { + session_output_formatted(s, view, len); + free(view); + } else { + session_output(s, "\r\n" + "Welcome to %s (%s)\r\n" + "\r\n", db->config.name, s->node); + } if (session_login(s) == AUTH_USER_OK) session_output(s, "Welcome, %s\r\n", s->user->username); else session_output(s, "Thanks for playing\r\n"); - for (;;) { + session_close(&s); +} + +void +session_close(struct session **session) +{ + struct session **newsessions = NULL; + unsigned long now; + short onsessions, n; + + /* try to flush output */ + now = Ticks; + while ((*session)->obuflen && (Ticks - now) < 60) { + (*session)->node_funcs->output(*session); uthread_yield(); } + + /* close the node */ + (*session)->node_funcs->close(*session); + + /* remove session from sessions */ + onsessions = nsessions - 1; + if (onsessions) { + newsessions = xmallocarray(onsessions, sizeof(struct session)); + nsessions = 0; + for (n = 0; n < onsessions; n++) { + if (sessions[n] == *session) + continue; + newsessions[nsessions++] = sessions[n]; + } + } + free(sessions); + sessions = newsessions; + + free(*session); + *session = NULL; } -short +size_t session_output(struct session *session, const char *format, ...) { va_list ap; - short len; + size_t len; va_start(ap, format); len = vsprintf(session_tbuf, format, ap); @@ -86,25 +128,36 @@ session_output(struct session *session, const char *fo if (len >= sizeof(session_tbuf)) err(1, "sprintf overflow in session_output!"); - if (len > (sizeof(session->obuf) - session->obuflen)) { - warn("session_output is out of room!"); - len = sizeof(session->obuf) - session->obuflen; - } - - memcpy(session->obuf + session->obuflen, session_tbuf, len); - session->obuflen += len; - session->node_funcs->output(session); - - return len; + return session_output_formatted(session, session_tbuf, len); } -short -session_output_char(struct session *session, const char c) +size_t +session_output_formatted(struct session *session, const char *str, + size_t len) { - session->obuf[session->obuflen++] = c; - session->node_funcs->output(session); + size_t chunk, olen = len, stroff = 0; - return 1; + while (len) { + chunk = (sizeof(session->obuf) - session->obuflen); + if (chunk == 0) { + /* wait until output buffer clears */ + uthread_yield(); + continue; + } + if (chunk > len) + chunk = len; + + memcpy(session->obuf + session->obuflen, str + stroff, chunk); + session->obuflen += chunk; + stroff += chunk; + len -= chunk; + session->node_funcs->output(session); + + if (len) + uthread_yield(); + } + + return olen; } char @@ -177,7 +230,7 @@ session_field_input(struct session *session, unsigned ipos++; ilen++; field[ipos] = '\0'; - session_output_char(session, mask ? mask : c); + session_output_formatted(session, mask ? &mask : &c, 1); } } @@ -231,9 +284,69 @@ session_login(struct session *s) if (s->user) return AUTH_USER_OK; - uthread_sleep(60); + uthread_msleep(60); session_output(s, "Login incorrect\r\n"); } return AUTH_USER_FAILED; +} + +#define EXPAND_TO_FIT(var, size, pos, len) { \ + if ((pos) >= ((size) - (len))) { \ + (size) += 1024; \ + (var) = xrealloc((var), (size)); \ + } \ +} + +size_t +session_load_view(struct session *session, short id, char **ret) +{ + char curvar[64]; + size_t retsize = 1024, retpos = 0; + size_t hsize, len; + Handle h; + short n, invar = 0, varlen = 0; + char c; + + h = Get1Resource(DB_TEXT_TYPE, id); + if (!h) + return 0; + hsize = GetHandleSize(h); + + *ret = xmalloc(retsize); + retpos = 0; + HLock(h); + + for (n = 0; n < hsize; n++) { + c = (*h)[n]; + + if (c == '%' && (*h)[n + 1] == '%') { + n++; + if (invar) { + invar = 0; + curvar[varlen] = '\0'; + if (strcmp(curvar, "NODE") == 0) { + len = strlcpy(curvar, session->node, sizeof(curvar)); + EXPAND_TO_FIT(*ret, retsize, retpos, len); + memcpy(*ret + retpos, curvar, len); + retpos += len; + } + } else { + invar = 1; + varlen = 0; + } + } else if (invar) { + if (varlen < sizeof(curvar) - 2) + curvar[varlen++] = c; + } else if (c == '\r' && (*h)[n + 1] != '\n') { + EXPAND_TO_FIT(*ret, retsize, retpos, 2); + (*ret)[retpos++] = '\r'; + (*ret)[retpos++] = '\n'; + } else { + EXPAND_TO_FIT(*ret, retsize, retpos, 1); + (*ret)[retpos++] = c; + } + } + + return retpos; } --- session.h Sun Dec 5 16:50:30 2021 +++ session.h Tue Dec 7 08:40:19 2021 @@ -34,11 +34,12 @@ enum session_input_state { struct node_funcs { short (*input)(struct session *session); short (*output)(struct session *session); + void (*close)(struct session *session); }; struct session { - char node[32]; - char obuf[64]; + char node[10]; + char obuf[512]; char ibuf[64]; enum session_state state; enum session_input_state input_state; @@ -54,11 +55,14 @@ extern struct session **sessions; extern short nsessions; struct session *session_create(char *node, struct node_funcs *node_funcs); +void session_close(struct session **session); void session_idle(struct session *session); char session_input_char(struct session *session); -short session_output(struct session *session, const char *format, ...); -short session_output_char(struct session *session, const char c); +size_t session_output(struct session *session, const char *format, ...); +size_t session_output_formatted(struct session *session, const char *str, + size_t len); char *session_field_input(struct session *session, unsigned short len, char mask); +size_t session_load_view(struct session *session, short id, char **ret); #endif /* __SESSION_H__ */ --- telnet.c Mon Dec 6 09:44:44 2021 +++ telnet.c Tue Dec 7 15:41:49 2021 @@ -47,12 +47,11 @@ TCPiopb telnet_exit_pb; TCPStatusPB telnet_status_pb; void telnet_atexit(void); -short telnet_output(struct session *session); -short telnet_input(struct session *session); struct node_funcs telnet_node_funcs = { telnet_input, telnet_output, + telnet_close }; void @@ -60,9 +59,8 @@ telnet_init(void) { struct telnet_node *node; short error, i; - ip_port port = db->config.telnet_port; - if (!port) + if (!db->config.telnet_port) return; if (_TCPInit() != 0) @@ -80,17 +78,7 @@ telnet_init(void) node->tcp_buf_len = (4 * 1500) + 1024; node->tcp_buf = xmalloc(node->tcp_buf_len); - error = _TCPCreate(&node->pb, &node->stream, (Ptr)node->tcp_buf, - node->tcp_buf_len, nil, nil, nil, false); - if (error) - err(1, "TCPCreate[%d] failed: %d", i, error); - - error = _TCPPassiveOpen(&node->listen_pb, node->stream, nil, nil, - nil, &port, nil, nil, true); - if (error) - err(1, "TCPPassiveOpen[%d] on port %d failed: %d", i, port, - error); - node->state = TELNET_PB_STATE_LISTENING; + /* delay actual listening until telnet_idle */ } } @@ -104,15 +92,14 @@ telnet_atexit(void) node = &telnet_nodes[i]; if (node->state > TELNET_PB_STATE_UNUSED) { - error = _TCPClose(&telnet_exit_pb, node->stream, nil, nil, + error = _TCPAbort(&telnet_exit_pb, node->stream, nil, nil, false); - if (error == noErr) - error = _TCPRelease(&telnet_exit_pb, node->stream, nil, - nil, false); + error = _TCPRelease(&telnet_exit_pb, node->stream, nil, + nil, false); } if (node->tcp_buf) - ;//free(node->tcp_buf); + free(node->tcp_buf); } } @@ -121,13 +108,27 @@ telnet_idle(void) { struct telnet_node *node; short i, error; + ip_port port = db->config.telnet_port; + + if (!port) + return; for (i = 0; i < TELNET_SLOTS; i++) { node = &telnet_nodes[i]; - if (node->state == TELNET_PB_STATE_UNUSED) - continue; - switch (node->state) { + case TELNET_PB_STATE_UNUSED: + error = _TCPCreate(&node->pb, &node->stream, + (Ptr)node->tcp_buf, node->tcp_buf_len, nil, nil, nil, false); + if (error) + err(1, "TCPCreate[%d] failed: %d", i, error); + + error = _TCPPassiveOpen(&node->listen_pb, node->stream, nil, + nil, nil, &port, nil, nil, true); + if (error) + err(1, "TCPPassiveOpen[%d] on port %d failed: %d", i, port, + error); + node->state = TELNET_PB_STATE_LISTENING; + break; case TELNET_PB_STATE_LISTENING: if (node->listen_pb.ioResult > 0) continue; @@ -148,11 +149,35 @@ telnet_idle(void) } break; case TELNET_PB_STATE_CONNECTED: + if (node->session) { + telnet_output(node->session); + telnet_input(node->session); + } break; } } } +void +telnet_close(struct session *session) +{ + struct telnet_node *node = (struct telnet_node *)session->cookie; + short error; + + error = _TCPClose(&telnet_exit_pb, node->stream, nil, nil, false); + /* TODO: allow some time to fully close? */ + error = _TCPRelease(&telnet_exit_pb, node->stream, nil, nil, false); + + if (error) { + warn("error shutting down telnet session: %d", error); + return; + } + + session->cookie = NULL; + node->session = NULL; + node->state = TELNET_PB_STATE_UNUSED; +} + short telnet_output(struct session *session) { @@ -168,12 +193,17 @@ telnet_output(struct session *session) if (node->tcp_wds[0].length) { /* previous _TCPSend completed, shift out those bytes */ - BlockMove(session->obuf + node->tcp_wds[0].length, - session->obuf, session->obuflen - node->tcp_wds[0].length); session->obuflen -= node->tcp_wds[0].length; + if (session->obuflen < 0) + warn("bogus obuflen %d", session->obuflen); + if (session->obuflen > 0) + BlockMove(session->obuf + node->tcp_wds[0].length, + session->obuf, session->obuflen); + node->tcp_wds[0].length = 0; + if (session->obuflen == 0) - return 0; + return node->tcp_wds[0].length; } /* @@ -191,8 +221,8 @@ telnet_output(struct session *session) if (error) /* TODO: make this not fatal */ err(1, "TCPSend[%d] failed: %d", node->id, error); - - return session->obuflen; + + return 0; } short @@ -211,10 +241,12 @@ telnet_input(struct session *session) error = _TCPStatus(&node->pb, node->stream, &telnet_status_pb, nil, nil, false); - if (error) - /* TODO: make this not fatal */ - err(1, "TCPRecv[%d] failed: %d", node->id, error); - + if (error || + telnet_status_pb.connectionState != ConnectionStateEstablished) { + telnet_close(session); + return 0; + } + if (telnet_status_pb.amtUnreadData == 0) return 0; --- telnet.h Mon Nov 29 15:26:06 2021 +++ telnet.h Mon Dec 6 17:33:07 2021 @@ -14,5 +14,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "session.h" + void telnet_init(void); -void telnet_idle(void); +void telnet_idle(void); + +void telnet_close(struct session *session); +short telnet_output(struct session *session); +short telnet_input(struct session *session);