From 6e391e2324f58f6d681aebe6754d4a7640aec291 Mon Sep 17 00:00:00 2001 From: ~keith Date: Thu, 19 May 2022 17:20:34 +0000 Subject: [PATCH] commit message --- .gitignore | 3 ++ README.md | 5 ++ hlogin.c | 22 ++++++-- ui.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++--- ui.h | 5 ++ 5 files changed, 179 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 62e76b7..a2dbe64 100644 --- a/.gitignore +++ b/.gitignore @@ -4,15 +4,18 @@ tmp/ .ccls-cache/ .deps/ +.directory autom4te.cache/ build/ +build-aux/ po/*.gmo po/Makefile po/Makefile.in po/POTFILES po/*.po~ +aclocal.m4 config.h config.in config.status diff --git a/README.md b/README.md index 9cb4cbf..33cdda6 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,8 @@ A replacement for `/bin/login` which provides a friendly TUI greeter. *DISCLAIMER:* While I'm reasonably sure this program is secure, I can't guarantee that for certain. Use it at your own risk. + +## TODO +- [ ] UTF-8 support +- [ ] Respect `/etc/login.defs` +- [ ] Appearance customization diff --git a/hlogin.c b/hlogin.c index 8652443..7aabfc2 100644 --- a/hlogin.c +++ b/hlogin.c @@ -19,7 +19,6 @@ */ #include "config.h" -#include #include #include #include @@ -28,8 +27,12 @@ #include "gettext.h" #include +#include +#include #include #include +#include +#include #include "ui.h" @@ -88,16 +91,27 @@ FAILURE: return PAM_CONV_ERR; } +/** number of seconds to hang after a login failure or error **/ +unsigned int fail_delay = 3; + int main(int argc, char* argv[]) { + int result; + setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); + openlog("hlogin", LOG_ODELAY, LOG_AUTHPRIV); + pam_handle_t *pam = NULL; struct pam_conv conv = { .conv = pam_conv_handler, .appdata_ptr = NULL }; - if (pam_start("login", NULL, &conv, &pam) != PAM_SUCCESS) { - // TODO log error & pause before exiting + + result = pam_start("login", NULL, &conv, &pam); + if (result != PAM_SUCCESS) { + syslog(LOG_ERR, _("Couldn't initialize PAM: %s"), pam_strerror(pam, result)); + fprintf(stderr, _("pam_start error: %s. Abort.\n"), pam_strerror(pam, result)); + sleep(fail_delay); return EXIT_FAILURE; } @@ -105,7 +119,7 @@ int main(int argc, char* argv[]) // prompt for username ui_setup_dialog(_("Login name:"), false); - int result = ui_run(); + result = ui_run(); char *login_name = ui_get_text(); if (result != 0) goto END; diff --git a/ui.c b/ui.c index 7a04a90..803d5a4 100644 --- a/ui.c +++ b/ui.c @@ -20,7 +20,6 @@ #include "config.h" #include "ui.h" -#include #include #include #include @@ -47,6 +46,12 @@ PANEL *login_p; WINDOW *login_shadow_w; PANEL *login_shadow_p; +WINDOW *error_w; +PANEL *error_p; + +WINDOW *error_shadow_w; +PANEL *error_shadow_p; + const int login_rows = 8; const int login_cols = 48; @@ -115,6 +120,7 @@ FAILURE: return unknown_str; } +/* char *xgetnisdomainname() { size_t len = HOST_NAME_MAX; @@ -136,6 +142,7 @@ char *xgetnisdomainname() buf[len] = '\0'; return buf; } +*/ char erase_ch; @@ -154,6 +161,16 @@ void ui_setup_dialog(char *prompt, bool password) paint_login(); } +void ui_setup_message(char *text) +{ + msg = text; + // TODO insert word wrap logic here + int msg_len = strlen(text); + + + +} + /** ui_init - initialize the UI subsystem */ void ui_init() @@ -250,9 +267,9 @@ void paint_login() wmove(login_w, 3, 3); whline(login_w, ' ', login_cols - 6); if (!hide_input) - waddnstr(login_w, input_buf, login_cols - 6); + waddnstr(login_w, input_buf + input_scroll, login_cols - 6); else { - int num_dots = strlen(input_buf); + int num_dots = strlen(input_buf) - input_scroll; if (num_dots > login_cols - 6) num_dots = login_cols - 6; whline(login_w, '*', num_dots); @@ -275,7 +292,7 @@ void paint_login() int ui_update() { paint_back(); - wmove(login_w, 3, 3 + input_pos); + wmove(login_w, 3, 3 + input_pos - input_scroll); update_panels(); doupdate(); @@ -290,11 +307,15 @@ int ui_update() input_backdel_char(); else if (ch == 0x7F || ch == KEY_DC) input_del_char(); - else if (ch == KEY_LEFT && input_pos > 0) + else if (ch == KEY_LEFT && input_pos > 0) { input_pos--; - else if (ch == KEY_RIGHT && input_pos < strlen(input_buf)) + if (input_pos < input_scroll) + input_scroll--; + } else if (ch == KEY_RIGHT && input_pos < strlen(input_buf)) { input_pos++; - else if (ch == '\t') + if (input_pos >= (input_scroll + login_cols - 6)) + input_scroll++; + } else if (ch == '\t') btn_focus = (btn_focus + 1) % btn_count; else if (ch == 0x1B) // escape return -2; @@ -336,6 +357,8 @@ void input_add_char(char ch) if (input_buf[i] == '\0') break; } + if (input_pos >= (input_scroll + login_cols - 6)) + input_scroll++; } void input_backdel_char() @@ -351,11 +374,13 @@ void input_del_char() if (input_buf[input_pos] == '\0') return; - for (int i = input_pos; i < (input_buflen - 1); i++) { + for (int i = input_pos; i < input_buflen - 1; i++) { input_buf[i] = input_buf[i + 1]; if (input_buf[i] == '\0') break; } + if ((input_scroll + login_cols - 6) > strlen(input_buf) && input_scroll > 0) + input_scroll--; } const attr_t light = A_BOLD | COLOR_PAIR(3); @@ -383,3 +408,118 @@ void draw_outline(WINDOW *win, int height, int width, int y, int x, bool inset) wattroff(win, A_ALTCHARSET); } + +/** output_word - used in word_wrap + */ +void output_word(char *word, size_t len, + char **out, size_t *out_size, int *out_pos, + int *line_pos, int *lines, int width) +{ + int i = 0; + while (i < len) { + int space = width - (*line_pos); + int remain = len - i; + if (space > remain) { // can fit on line + if ((*out_size) < (*out_pos) + remain) { + *out_size *= 2; + *out = realloc(*out, sizeof(char) * (*out_size)); + } + // copy word + memcpy((*out) + (*out_pos), word + i, sizeof(char) * remain); + i += remain; + *out_pos += remain; + *line_pos += remain; + } else { + if ((*out_size) < (*out_pos) + space + 1) { + *out_size *= 2; + *out = realloc(*out, sizeof(char) * (*out_size)); + } + // copy part of word + memcpy((*out) + (*out_pos), word + i, sizeof(char) * space); + i += space; + *out_pos += space; + // add newline + (*out)[(*out_pos)++] = '\n'; + *line_pos = 0; + (*lines)++; + } + } +} + +char *word_wrap(char *text, int width, int max_word, int *lines) +{ + // output buffer + size_t out_size = 256; + char *out = malloc(sizeof(char) * out_size); + int out_pos = 0; + // word buffer + char *word = malloc(sizeof(char) * max_word); + int word_len = 0; + + int line_pos = 0; + + char ch; + while ((ch = *text) != '\0') { + text++; + + switch (ch) { + case '\n': + case ' ': + if (word[0] == '\0') + word_len = 0; + // ensure buffer is large enough + if (out_size < out_pos + word_len + 2) { + out_size *= 2; + out = realloc(out, sizeof(char) * out_size); + } + if (word_len > 0) { + // do we have to wrap to a new line? + if (line_pos + word_len > width) { + out[out_pos++] = '\n'; + line_pos = 0; + (*lines)++; + } + memcpy(out + out_pos, word, sizeof(char) * word_len); + word_len = 0; + out_pos += word_len; + line_pos += word_len; + } + // output \n + if (ch == '\n' || line_pos >= width) { + out[out_pos++] = '\n'; + line_pos = 0; + (*lines)++; + } else { + out[out_pos++] = ' '; + line_pos++; + } + break; + default: + // word longer than word buffer + if (word_len >= max_word) { + if (word[0] != '\0') { + // write what we have + output_word(word, word_len, + &out, &out_size, &out_pos, + &line_pos, lines, width); + word[0] = '\0'; + } + // ensure buffer is large enough + if (out_size < out_pos + 2) { + out_size *= 2; + out = realloc(out, sizeof(char) * out_size); + } + // write char and maybe newline + out[out_pos++] = ch; + if ((++line_pos) >= width) { + out[out_pos++] = '\n'; + line_pos = 0; + (*lines)++; + } + } else + word[word_len++] = ch; + } + } + + free(word); +} diff --git a/ui.h b/ui.h index 283c19f..d76e8d4 100644 --- a/ui.h +++ b/ui.h @@ -17,6 +17,8 @@ * You should have received a copy of the GNU General Public License * along with hlogin. If not, see . */ +#define _XOPEN_SOURCE 600 + #ifndef __UI_H #define __UI_H @@ -31,6 +33,7 @@ void paint_back(); void paint_login(); void ui_setup_dialog(char *prompt, bool password); +void ui_setup_message(char *text); int ui_update(); int ui_run(); @@ -42,4 +45,6 @@ void input_del_char(); void draw_outline(WINDOW *win, int height, int width, int y, int x, bool inset); +char *word_wrap(char *text, int width, int max_word, int *lines); + #endif // __UI_H