/* * mish_priv.h * * Copyright (C) 2020 Michel Pollet * * SPDX-License-Identifier: Apache-2.0 */ #ifndef LIBMISH_SRC_MISH_PRIV_H_ #define LIBMISH_SRC_MISH_PRIV_H_ #include #include #include #include #include "bsd_queue.h" #include "mish_priv_vt.h" #include "mish_priv_line.h" struct mish_t; /* * The process_char callback of mish_input_t returns one of these. */ enum { MISH_IN_SKIP = 0, // skip current character (don't store) MISH_IN_STORE, // store current character in input buffer MISH_IN_SPLIT, // store current line, add it to backlog }; /* * This receives stuff from a file descriptor, 'processes' it, and split it * into lines to eventually store new lines into the 'backlog'. */ typedef struct mish_input_t { // lines read from fd are queued in here when \n has been received mish_line_queue_t backlog; uint32_t is_telnet : 1, flush_on_nl : 1; // return 1 for the character to be stored, 0 for it to be skipped int (*process_char)( struct mish_t *m, struct mish_input_t *i, uint8_t ch); void * refcon; // reference constant, for the callbacks int fd; mish_line_p line; } mish_input_t, *mish_input_p; /* various internal states for the client */ enum { MISH_CLIENT_INIT_SENT = (1 << 0), MISH_CLIENT_HAS_WINDOW_SIZE = (1 << 1), MISH_CLIENT_HAS_CURSOR_POS = (1 << 2), MISH_CLIENT_UPDATE_PROMPT = (1 << 3), MISH_CLIENT_UPDATE_WINDOW = (1 << 4), MISH_CLIENT_SCROLLING = (1 << 5), MISH_CLIENT_DELETE = (1 << 6), }; typedef struct mish_client_t { TAILQ_ENTRY(mish_client_t) self; struct mish_t * mish; uint32_t flags; // "coroutine" processing received lines from the stdout/err struct { void * state; // state for the prompt coroutine // _mish_client_interractive_cr() or _mish_client_dumb_cr() void (*process)( struct mish_t * m, struct mish_client_t* c); } cr; int footer_height; // # static lines at bottom of screen int current_vpos; mish_line_p bottom; // Line we are currently sending (or NULL) mish_line_p sending; /* * Output sent to the client is made of bits we want to send to move * the cursor and so on, and, the actual lines we captured from the program. * So a vector list is built as the output is built, and it's made of bits * we've copied in "sqb" as well as lines from the mish backlog. * Once we deem a good time to output stuff, we send that vector and wait * until it's all gone before starting again. */ struct { int fd; // index of fd we writev to struct iovec *v; // starts at NULL int count;// how many are filled in int size; // how many are allocated // temporary sequence buffer, for composite output. mish_line_p sqb; size_t total; // total bytes we sent } output; char prompt[64]; /* Since the prompt will contains more bytes than displayed glyphs, * we keep track of the number of glyphs so we can reposition the * cursor accurately. */ int prompt_gc; // prompt real glyph count /* * Unfiltered console input from the client. This get stored in there * until the input code notices any output has been sent. Then it is * passed down to 'vts' */ mish_input_t input; /* * this handles the vt sequences received at the command prompt, * like direction keys etc -also handles UTF8 sequences- (but doesn't do * anything with them). It is also subverted by the telnet decoder to * do it's own things, separately. * Sequences coming out are processed in mish_client_input. */ mish_vt_sequence_t vts; /* * Stuff received from 'input' side gets filtered via 'vts' and * stored in this. * Once a command has been validated, it is added back to the input * backlog to make this client 'history' */ mish_line_p cmd; struct { int w, h; } window_size; // valid if MISH_CLIENT_HAS_WINDOW_SIZE struct { int x, y; } cursor_pos; // valid if MISH_CLIENT_HAS_CURSOR_POS } mish_client_t, *mish_client_p; // supplement the public ones from mish.h enum { MISH_QUIT = (1 << 31), // the process console we started was a tty, so has terminal settings MISH_CONSOLE_TTY = (1 << 30), }; typedef struct mish_t { uint32_t flags; struct termios orig_termios; // original terminal settings int originals[2]; // backup the original 1,2 fds /* These are the ones we use to read the output from the main program. */ mish_input_t origin[2]; uint64_t stamp_start; TAILQ_HEAD(, mish_client_t) clients; mish_client_p console; // client that is also the original terminal. pthread_t capture; // libmish main thread pthread_t main; // todo: allow pause/stop/resume? struct { mish_line_queue_t log; unsigned int size; // number of lines in backlog size_t alloc; // number of bytes in the backlog } backlog; struct { int listen; // listen socket int port; // port we're listening on } telnet; // Used by the select thread in mish_capture_select.c struct { fd_set read, write; int max; } select; } mish_t, *mish_p; mish_client_p mish_client_new( mish_p m, int in, int out, int is_tty); void mish_client_delete( mish_p m, mish_client_p c); /* * Sequence buffer handling */ int _mish_send_flush( mish_p m, mish_client_p c); void _mish_send_queue( mish_client_p c, const char * b); void _mish_send_queue_fmt( mish_client_p c, const char *fmt, ...); void _mish_send_queue_line( mish_client_p c, mish_line_p line ); //! Parse current input buffer fro VT sequences, like keys. int _mish_client_vt_parse_input( struct mish_t *m, struct mish_input_t *in, uint8_t ich); /* * This is the main interactive client coroutine. This one is interesting. */ void _mish_client_interractive_cr( mish_p m, mish_client_p c); void _mish_client_dumb_cr( mish_p m, mish_client_p c); uint64_t _mish_stamp_ms(); /* * telnet handling */ int mish_telnet_prepare( mish_p m, uint16_t port); int mish_telnet_in_check( mish_p m, fd_set * r); void mish_telnet_send_init( mish_client_p c); int _mish_telnet_parse( mish_client_p c, uint8_t ch); /* * input handling */ void _mish_input_init( mish_p m, mish_input_p in, int fd); void _mish_input_clear( mish_p m, mish_input_p in); int _mish_input_read( mish_p m, fd_set * fds, mish_input_p in); /* * Capture thread function */ void * _mish_capture_select( void *param); /* * https://en.wikipedia.org/wiki/ANSI_escape_code#Terminal_output_sequences */ #define MISH_COLOR_RED "\033[38;5;125m" #define MISH_COLOR_GREEN "\033[38;5;28m" #define MISH_COLOR_RESET "\033[0m" #endif /* LIBMISH_SRC_MISH_PRIV_H_ */