author | Olivier Brunel
<jjk@jjacky.com> 2015-02-12 21:48:20 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2015-04-04 12:47:33 UTC |
parent | e7deaccf7dc628a54cfbdbfe8a8e249bdd78f030 |
src/anopa/start-stop.c | +225 | -3 |
src/anopa/start-stop.h | +18 | -4 |
diff --git a/src/anopa/start-stop.c b/src/anopa/start-stop.c index 6190b36..491fe75 100644 --- a/src/anopa/start-stop.c +++ b/src/anopa/start-stop.c @@ -34,6 +34,7 @@ genalloc ga_failed = GENALLOC_ZERO; int cols = 80; int is_utf8 = 0; int ioloop = 1; +int si_password = -1; /* aa-start.c */ void check_essential (int si); @@ -47,6 +48,9 @@ free_progress (struct progress *pg) void clear_draw () { + if (draw & DRAW_CUR_PASSWORD) + aa_is_flush (AA_OUT, ANSI_CLEAR_BEFORE ANSI_START_LINE); + if (draw & DRAW_CUR_WAITING) { aa_is_flush (AA_OUT, ANSI_CLEAR_BEFORE ANSI_START_LINE); @@ -61,7 +65,7 @@ clear_draw () { struct progress *pg = &genalloc_s (struct progress, &ga_progress)[i]; - if (pg->is_drawn) + if (pg->is_drawn > 0) { aa_is_flush (AA_OUT, ANSI_PREV_LINE ANSI_CLEAR_AFTER); pg->is_drawn = 0; @@ -83,6 +87,23 @@ draw_progress_for (int si) draw |= DRAW_CUR_PROGRESS; } +void +draw_password () +{ + aa_service *s = aa_service (si_password); + struct progress *pg = &genalloc_s (struct progress, &ga_progress)[s->pi]; + + if (pg->is_drawn == DRAWN_PASSWORD_READY) + aa_is_noflush (AA_OUT, ANSI_HIGHLIGHT_ON); + aa_is_noflush (AA_OUT, aa_service_name (s)); + if (pg->is_drawn == DRAWN_PASSWORD_READY) + aa_is_noflush (AA_OUT, ANSI_HIGHLIGHT_OFF); + aa_is_noflush (AA_OUT, ": "); + aa_is_noflush (AA_OUT, pg->aa_pg.sa.s); + aa_is_flush (AA_OUT, " : "); + draw |= DRAW_CUR_PASSWORD; +} + void draw_waiting (int already_drawn) { @@ -109,19 +130,80 @@ draw_waiting (int already_drawn) draw |= DRAW_CUR_WAITING; } +static int +term_set_echo (int on) +{ + struct termios termios; + int r; + + r = tcgetattr (0, &termios); + if (r < 0) + return r; + + if (on) + { + if (termios.c_lflag & ECHO) + return 0; + termios.c_lflag |= ECHO; + } + else + { + if (!(termios.c_lflag & ECHO)) + return 0; + termios.c_lflag &= ~ECHO; + } + + return tcsetattr (0, TCSANOW, &termios); +} + void refresh_draw () { unsigned int old_draw = draw; if ((!(draw & DRAW_NEED_WAITING) && (draw & DRAW_CUR_WAITING)) - || (draw & DRAW_CUR_PROGRESS)) + || (draw & (DRAW_CUR_PROGRESS | DRAW_CUR_PASSWORD))) { clear_draw (); if (old_draw & DRAW_NEED_WAITING) draw |= DRAW_NEED_WAITING; } + if ((draw & DRAW_NEED_PASSWORD) && si_password < 0) + { + int i; + + for (i = 0; i < genalloc_len (struct progress, &ga_progress); ++i) + { + struct progress *pg = &genalloc_s (struct progress, &ga_progress)[i]; + + if (pg->si >= 0 && pg->is_drawn == DRAWN_PASSWORD_READY) + { + iopause_fd iop; + int r; + + r = term_set_echo (0); + if (r < 0) + { + strerr_warnwu2sys ("set terminal attributes; " + "can't ask for password for service ", + aa_service_name (aa_service (pg->si))); + break; + } + + iop.fd = 0; + iop.events = IOPAUSE_READ; + genalloc_append (iopause_fd, &ga_iop, &iop); + + si_password = pg->si; + break; + } + } + + if (si_password < 0) + draw &= ~DRAW_NEED_PASSWORD; + } + if (draw & DRAW_NEED_PROGRESS) { int i; @@ -130,7 +212,7 @@ refresh_draw () { struct progress *pg = &genalloc_s (struct progress, &ga_progress)[i]; - if (pg->si >= 0) + if (pg->si >= 0 && pg->is_drawn >= 0) draw_progress_for (pg->si); } @@ -138,6 +220,12 @@ refresh_draw () draw &= ~DRAW_NEED_PROGRESS; } + if (draw & DRAW_NEED_PASSWORD) + { + draw_password (); + draw &= ~DRAW_NEED_WAITING; + } + if (draw & DRAW_NEED_WAITING) draw_waiting ((old_draw & DRAW_CUR_WAITING) && !(draw & DRAW_CUR_PROGRESS)); @@ -308,6 +396,46 @@ handle_fd_progress (int si) close_fd_for (s->fd_progress, si); return 0; } + + /* PASSWORD */ + if ((r > 3 && buf[1] == '<' && buf[2] == ' ') || pg->is_drawn == DRAWN_PASSWORD_WAITMSG) + { + int rr; + + if (pg->is_drawn != DRAWN_PASSWORD_WAITMSG) + { + pg->aa_pg.sa.len = 0; + i = 3; + } + else + i = 1; + + rr = byte_rchr (buf + i, r, '\n'); + if (rr == r) + { + if (!stralloc_catb (&pg->aa_pg.sa, buf + i, rr)) + return -1; + pg->is_drawn = DRAWN_PASSWORD_WAITMSG; + return 0; + } + + buf[i + rr] = '\0'; + if (!stralloc_catb (&pg->aa_pg.sa, buf + i, rr + 1)) + return -1; + + pg->is_drawn = DRAWN_PASSWORD_READY; + draw |= DRAW_NEED_PASSWORD; + /* clear in order to "reset" any WAITING */ + clear_draw (); + return 0; + } + else if (pg->is_drawn < 0) + /* no progress during a password prompt */ + return -1; + + + /* PROGRESS */ + /* if sa is empty (i.e. we just created pg) we need to keep it consistent * with our expectations: it starts with the msg before the * buffered/unprocessed data. So we'll add a NUL (i.e. no msg) */ @@ -331,12 +459,44 @@ handle_fd_progress (int si) return 0; } +int +handle_fd_in (void) +{ + aa_service *s = aa_service (si_password); + struct progress *pg = &genalloc_s (struct progress, &ga_progress)[s->pi]; + char buf[256]; + iopause_fd iop; + int r; + + r = fd_read (0, buf, 256); + if (r < 0) + return r; + else if (r == 0) + goto done; + + if (!stralloc_catb (&pg->aa_pg.sa, buf, r)) + return -1; + + iop.fd = s->fd_in; + iop.events = IOPAUSE_WRITE; + genalloc_append (iopause_fd, &ga_iop, &iop); + pg->is_drawn = DRAWN_PASSWORD_WRITING; + r = 0; + +done: + remove_fd_from_iop (0); + return r; +} + int handle_fd (int fd) { int si; int i; + if (fd == 0 && si_password >= 0) + return handle_fd_in (); + for (i = 0; i < genalloc_len (int, &aa_tmp_list); ++i) { si = list_get (&aa_tmp_list, i); @@ -350,6 +510,62 @@ handle_fd (int fd) return -1; } +int +handle_fdw (int fd) +{ + aa_service *s; + struct progress *pg; + int offset; + int len; + int r; + + if (si_password < 0 || aa_service (si_password)->fd_in != fd) + return (errno = ENOENT, -1); + + s = aa_service (si_password); + pg = &genalloc_s (struct progress, &ga_progress)[s->pi]; + + offset = byte_chr (pg->aa_pg.sa.s, pg->aa_pg.sa.len, '\0') + 1; + len = pg->aa_pg.sa.len - offset; + + r = fd_write (fd, pg->aa_pg.sa.s + offset, len); + if (r < 0) + { + strerr_warnwu2sys ("write to fd_in of service ", aa_service_name (s)); + return r; + } + else if (r < len) + { + memmove (pg->aa_pg.sa.s + offset, pg->aa_pg.sa.s + offset + r, len - r); + pg->aa_pg.sa.len -= r; + } + else + { + clear_draw (); + /* we put the message into the service output */ + aa_bs_noflush (AA_OUT, aa_service_name (s)); + aa_bs_noflush (AA_OUT, ": "); + aa_bs_noflush (AA_OUT, pg->aa_pg.sa.s); + aa_bs_flush (AA_OUT, "\n"); + + remove_fd_from_iop (fd); + pg->si = -1; + pg->is_drawn = 0; + pg->aa_pg.sa.len = 0; + s->pi = -1; + si_password = -1; + + r = term_set_echo (1); + if (r < 0) + strerr_warnwu1sys ("reset terminal attributes"); + + /* to get to the next one, if any */ + draw |= DRAW_NEED_PASSWORD; + } + + return 0; +} + static int handle_oneshot (int is_start) { @@ -703,6 +919,12 @@ mainloop (aa_mode mode, aa_scan_cb scan_cb) if (r < 0) strerr_warnwu1sys ("handle fd"); } + else if (iofd->revents & IOPAUSE_WRITE) + { + r = handle_fdw (iofd->fd); + if (r < 0) + strerr_warnwu1sys ("handle fdw"); + } else if (iofd->revents & IOPAUSE_EXCEPT) close_fd_for (iofd->fd, -1); } diff --git a/src/anopa/start-stop.h b/src/anopa/start-stop.h index 1c8ec61..ebd73bd 100644 --- a/src/anopa/start-stop.h +++ b/src/anopa/start-stop.h @@ -28,16 +28,29 @@ extern genalloc ga_failed; extern int cols; extern int is_utf8; extern int ioloop; +extern int si_password; enum { DRAW_CUR_WAITING = (1 << 0), DRAW_CUR_PROGRESS = (1 << 1), - DRAW_HAS_CUR = (1 << 2) - 1, + DRAW_CUR_PASSWORD = (1 << 2), + DRAW_HAS_CUR = (1 << 3) - 1, - DRAW_NEED_WAITING = (1 << 2), - DRAW_NEED_PROGRESS = (1 << 3), - DRAW_HAS_NEED = (1 << 4) - DRAW_HAS_CUR - 1 + DRAW_NEED_WAITING = (1 << 3), + DRAW_NEED_PROGRESS = (1 << 4), + DRAW_NEED_PASSWORD = (1 << 5), + DRAW_HAS_NEED = (1 << 6) - DRAW_HAS_CUR - 1 +}; + +enum +{ + DRAWN_NOT = 0, + DRAWN = 1, + + DRAWN_PASSWORD_WAITMSG = -1, + DRAWN_PASSWORD_READY = -2, + DRAWN_PASSWORD_WRITING = -3 }; struct progress @@ -58,6 +71,7 @@ void remove_fd_from_iop (int fd); void close_fd_for (int fd, int si); int handle_fd_out (int si); int handle_fd_progress (int si); +int handle_fd_in (void); int handle_fd (int fd); int handle_longrun (aa_mode mode, uint16 id, char event); int is_locale_utf8 (void);