/* $Id: skeleton.c-h,v 1.1 1999/06/16 22:54:23 levitte Exp $ */ #include #include "io.h" #include "io_buffer.h" #include "vms.h" struct ssh_ch_tt_st { struct ssh_ch_st ssh_ch_block; tty_s *old_tty; /* To save old tty parameters */ }; struct io_tt_in_st { struct io_st io_block; struct iosb iosb; /* For input */ int lock:1; /* If set, the AST shouldn't touch in[]. Instead, temporarly save in extra[]. */ int inbuf_i:1; /* Indicates which in[] element is currently in use by the AST*/ struct { char buf[8192]; /* That's serious lag... */ int read_pos; int buf_n; } in[2]; char extra_n; char extra[128]; }; struct io_methods tt_in_methods = { tt_create_input, tt_get_buffer, 0, 0, 0, tt_destroy }; struct io_tt_out_st { struct io_st io_block; struct iosb iosb; struct buf_pool *pool_buf; }; struct io_methods tt_out_methods = { tt_create_output, 0, tt_put_buffer, 0, 0, tt_destroy }; struct ssh_ch_st *tt_in_init(void) { struct ssh_ch_tt_in_st *v = (struct ssh_ch_tt_in_st *)xmalloc(sizeof(struct ssh_ch_tt_out_st)); ssh_ch_init(v, tt_in_methods); return (struct ssh_ch_st *)v; } struct ssh_ch_st *tt_out_init(void) { struct ssh_ch_tt_out_st *v = (struct ssh_ch_tt_out_st *)xmalloc(sizeof(struct ssh_ch_tt_out_st)); ssh_ch_init(v, tt_out_methods); return (struct ssh_ch_st *)v; } int tt_get_buffer(io_st *ctx, char *buf, size_t siz) { struct io_tt_st *v = (struct io_tt_st *)ctx; int c; /* Counter for some loops. There's no need to check more than two input buffers :-) */ int l = 0; int i; /* Index to the current buffer to look at */ int rp; /* The reader position in that buffer */ int bn; /* The number of bytes in total in that buffer */ int bl; /* bytes left to read. It is bn - rp */ v->lock = 1; /* If this is called more than once, were screwed. Perhaps I should protect better against that possibility... */ i = 1 - v->inbuf_i; /* We look in the one that is not being written to for the moment... */ rp = v->in[i].read_pos; bn = v->in[i].buf_n; bl = bn - rp; for (c = 2; c-- > 0 && siz - l > 0;) { if (siz - l < bl) { memcpy(buf + l, v->in[i].buf + rp, siz - l); v->in[i].read_pos += siz - l; l = siz; } else { memcpy(buf + l, v->in[i].buf + rp, bl); l += bl; /* * OK, we've emptied this buffer, so lets move to the next, * and tell the AST that this is the one to use next... */ v->in[i].buf_n = 0; v->in[i].read_pos = 0; v->inbuf_i = i; i = 1 - i; } } v->lock = 0; return l; } void tt_put_AST(struct io_tt_out_st *ctx) { int status; status = ctx->iosb.iosb_w_status; if (!$VMS_STATUS_SUCCESS(status)) lib$signal(status); status = buf_pool_free(ctx->pool_buf); if (!$VMS_STATUS_SUCCESS(status)) lib$signal(status); ctx->pool_buf = 0; status = io_pool_free(ctx); if (!$VMS_STATUS_SUCCESS(status)) lib$signal(status); return; } int tt_put_buffer(struct ssh_ch_st *ctx, char *buf, size_t len) { struct io_tt_out_st *v = (struct io_tt_out_st *)io_pool_get(sizeof(struct io_tt_out_st *)); v->io_block.ssh_ch_block = ctx; v->pool_buf = buf_pool_get(len); if (v->pool_buf == 0) lib$signal(SS$_INSFMEM); memcpy(v->pool_buf->buf, buf, len); v->pool_buf->flag = pool_busy; return sys$qio(v->io_block.ssh_ch_block->VMS_channel, IO$_WRITEVBLK, &v->iosb, tt_put_AST, v, v->pool_buf->buf, len, 0, 0, 0, 0); } static const unsigned int terminator_mask[2] = {0, 0}; void tt_get_AST(struct io_tt_in_st *ctx); void tt_get_start(struct io_tt_in_st *ctx) { int n = sizeof(ctx->extra) - ctx->extra_n; int status = sys$qio(0, ctx->ssh_ch_block->old_tty->channel, IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR, &ctx->iosb, tt_get_AST, ctx, ctx->extra + ctx->extra_n, n < 1 ? 0 : 1, 0, terminator_mask, 0, 0); if (!$VMS_STATUS_SUCCESS(status)) lib$signal(status); } void tt_get_AST(struct io_tt_in_st *ctx) { int status; static enum { NOTHING, CR_SEEN, TILDE_SEEN, SKIP } keystate = NOTHING; register unsigned int c = -1; register unsigned int i; if (ctx->iosb.iosb_w_count != 0) { if (!$VMS_STATUS_SUCCESS(ctx->iosb.iosb_w_status)) { ssh_debugf("Terminal_Read_AST(): Exiting on condition %%X%X", ctx->iosb.iosb_w_status); lib$signal(ctx->iosb.iosb_w_status); } } if (!v->lock) { for (i = 0; i < ctx->iosb.iosb_w_count; i++) { c = ctx->buf[i]; if (c >= 0) { switch (keystate) { case NOTHING: if (c == '\r' || c == '\n') keystate = CR_SEEN; break; case CR_SEEN: if (c == '~') keystate = TILDE_SEEN; else keystate = NOTHING; break; case TILDE_SEEN: keystate = SKIP; switch (c) { case '?': { fprintf(stderr, "%c?\r\n" "Supported escape sequences:\r\n" "~. - terminate connection\r\n" "~# - list forwarded connections (not yet implemented)\r\n" "~? - this message\r\n" "~~ - send the escape character by typing it twice\r\n" "(Note that escapes are only recognized immediately after newline.)\r\n", '~'); break; } case '.': lib$signal(FISH_M_CLOSED); break; case '~': keystate = NOTHING; break; case '#': default: v->in.buf[v->in.buf_n++] = '~'; keystate = NOTHING; break; } break; default: keystate = NOTHING; break; } if (keystate == NOTHING || keystate == CR_SEEN) v->in.buf[v->in.buf_n++] = c; if (keystate == SKIP) keystate = NOTHING; } } } tt_get_start(ctx); } int tt_create_input(struct ssh_ch_st *ctx, ...) { char *device; int status; tty_s *ttyi; struct io_tt_in_st *v = (struct io_tt_in_st *)io_pool_get(sizeof(struct io_tt_in_st *)); struct ssh_ch_tt_st *w = (struct ssh_ch_tt_st *)ctx va_list args; va_start(args, ctx); v->io_block.ssh_ch_block = ctx; v->lock = 0; v->inbuf_i = 0; v->in[0].buf_n = 0; v->in[0].read_pos = 0; v->in[1].buf_n = 0; v->in[1].read_pos = 0; v->extra_n = 0; device = va_arg(args, char *); ttyi = va_arg(args, tty_s *); if (!ttyi) { ttyi = tty_open(device, &status); if (!tty_sensemode(ttyi, &status)) lib$signal(status); w->old_tty = tty_dup(ttyi); if (ttyi) { tty_setflags(ttyi, TT$M_NOECHO|TT$M_HOSTSYNC, TT2$M_PASTHRU, &status); tty_clearflags(ttyi, 0 ,TT2$M_LOCALECHO, &status); if (!tty_setmode(ttyi,&status)) lib$signal(status); tty_release(ttyi,&status); } } tt_get_start(v); va_end(args); } int tt_create_output(struct ssh_ch_st *ctx, ...) { char *device; int status; tty_s *ttyo; struct ssh_ch_tt_st *w = (struct ssh_ch_tt_st *)ctx va_list args; va_start(args, ctx); device = (char *) va_arg(args, char *); ttyo = (tty_s *) va_arg(args, tty_s *); if (!ttyo) { ttyo = tty_open(device, &status); if (!tty_sensemode(ttyo, &status)) lib$signal(status); w->tty = tty_dup(ttyo); if (ttyo) { tty_setflags(ttyo, TT$M_NOECHO|TT$M_HOSTSYNC, TT2$M_PASTHRU, &status); tty_clearflags(ttyo, 0 ,TT2$M_LOCALECHO, &status); if (!tty_setmode(ttyo,&status)) lib$signal(status); tty_release(ttyo,&status); } } va_end(args); } void tt_destroy(struct ssh_ch_st *ctx) { int status; tty_io_cancel(ctx->tty, &status); tty_setmode(ctx->tty, &status); tty_close(ctx->tty, &status); ctx->tty = 0; free(ctx); return; } /* Emacs local variables Local variables: eval: (set-c-style "BSD") end: */