Blob Blame History Raw
From 45a5ca011bd0a402cd55bbca950634280e152dea Mon Sep 17 00:00:00 2001
From: Martin Kutlak <mkutlak@redhat.com>
Date: Fri, 7 Apr 2017 10:49:51 +0200
Subject: [PATCH 04/14] lib: fix newline issue with ask_password

The newline wasn't printed out because printing characters in terminal was
disabled (ECHO flag unset). After 'ask_password' function call, there would
have to be print function to create newline, otherwise the next message
would show up in the same line.

ECHONL flag allows to print newline character even if the ECHO flag is disabled.

Logic for the changes of the flags follows:
Change ECHO flag only when:
  - ECHO is set (0) and there was no change (0) previously.
  OR
  - ECHO is unset (1) and there was a change (1) previously.

Change ECHONL flag only when:
  - ECHONL is unset (1) and there was no change (0) previously.
  OR
  - ECHONL is set (0) and there was a change (1) previously.

Also ECHONL needs ICANON flag to be set (It is set by default).

Signed-off-by: Martin Kutlak <mkutlak@redhat.com>
---
 configure.ac                    |   4 ++
 src/cli/cli-report.c            |   3 -
 src/lib/client.c                |  18 ++++-
 src/plugins/reporter-mantisbt.c |   2 -
 tests/Makefile.am               |   3 +-
 tests/client.at                 | 152 ++++++++++++++++++++++++++++++++++++++++
 tests/testsuite.at              |   1 +
 7 files changed, 174 insertions(+), 9 deletions(-)
 create mode 100644 tests/client.at

diff --git a/configure.ac b/configure.ac
index ccefe50..c8745f8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -239,6 +239,10 @@ PKG_CHECK_MODULES([AUGEAS], [augeas])
 #PKG_CHECK_MODULES([LZ4], [liblz4])
 
 
+AC_SEARCH_LIBS([forkpty], [util])
+AC_REPLACE_FUNCS([forkpty])
+
+
 AC_ARG_WITH(newt,
 AS_HELP_STRING([--with-newt],[use newt (default is YES)]),
 LIBREPORT_PARSE_WITH([newt]))
diff --git a/src/cli/cli-report.c b/src/cli/cli-report.c
index c83dc20..537b194 100644
--- a/src/cli/cli-report.c
+++ b/src/cli/cli-report.c
@@ -442,9 +442,6 @@ static void ask_for_missing_settings(const char *event_name)
             case OPTION_TYPE_PASSWORD:
             {
                 opt->eo_value = ask_password(question);
-                /* Newline was not added by pressing Enter because ECHO was
-                   disabled, so add it now. */
-                puts("");
                 break;
             }
             case OPTION_TYPE_BOOL:
diff --git a/src/lib/client.c b/src/lib/client.c
index 811f33e..8a4e2ad 100644
--- a/src/lib/client.c
+++ b/src/lib/client.c
@@ -34,14 +34,26 @@ static int is_noninteractive_mode()
 int set_echo(int enable)
 {
     struct termios t;
+    int chvalue = 0;
     if (tcgetattr(STDIN_FILENO, &t) < 0)
         return 0;
 
-    /* No change needed? */
-    if (!(t.c_lflag & ECHO) == !enable)
+    /* ECHO flag change if needed */
+    if ((!(t.c_lflag & ECHO)) == enable)
+    {
+        t.c_lflag ^= ECHO;
+        chvalue = 1;
+    }
+    /* ECHONL flag change if needed */
+    if ((!(t.c_lflag & ECHONL)) != enable)
+    {
+        t.c_lflag ^= ECHONL;
+        chvalue = 1;
+    }
+
+    if (!chvalue)
         return 0;
 
-    t.c_lflag ^= ECHO;
     if (tcsetattr(STDIN_FILENO, TCSANOW, &t) < 0)
         perror_msg_and_die("tcsetattr");
 
diff --git a/src/plugins/reporter-mantisbt.c b/src/plugins/reporter-mantisbt.c
index 5062d32..622af87 100644
--- a/src/plugins/reporter-mantisbt.c
+++ b/src/plugins/reporter-mantisbt.c
@@ -62,8 +62,6 @@ static char *
 ask_mantisbt_password(const char *message)
 {
     char *password = ask_password(message);
-    /* TODO: this should be fixed in ask_password() as other tools have the same problem */
-    putchar('\n');
     if (password == NULL || password[0] == '\0')
     {
         set_xfunc_error_retval(EXIT_CANCEL_BY_USER);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index df19403..2b8972d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -59,7 +59,8 @@ TESTSUITE_AT = \
   event_config.at \
   proc_helpers.at \
   compress.at \
-  forbidden_words.at
+  forbidden_words.at \
+  client.at
 
 TESTSUITE_AT_IN = \
   bugzilla_plugin.at
diff --git a/tests/client.at b/tests/client.at
new file mode 100644
index 0000000..b643789
--- /dev/null
+++ b/tests/client.at
@@ -0,0 +1,152 @@
+# -*- Autotest -*-
+
+AT_BANNER([Client])
+
+## ---------------- ##
+##     set_echo     ##
+## ---------------- ##
+
+AT_TESTFUN([set_echo],
+[[
+#include <assert.h>
+#include "client.h"
+#include "internal_libreport.h"
+#include <pty.h>
+
+#define ECHO_TEST (!(new_mode.c_lflag & ECHO))
+#define ECHONL_TEST (!(new_mode.c_lflag & ECHONL))
+
+int main (void)
+{
+    int master_pty;
+
+    pid_t pid = forkpty(&master_pty, NULL, NULL, NULL);
+    if (pid < 0) {
+        perror_msg_and_die("forkpty failed.");
+    }
+
+    if (pid == 0) {
+        int check, result, changed;
+        struct termios old_mode, new_mode;
+        assert(isatty(STDIN_FILENO) == 1);
+
+        check = tcgetattr(STDIN_FILENO, &new_mode);
+        assert(check == 0);
+        old_mode = new_mode;
+
+        new_mode.c_lflag |= ECHO;
+        new_mode.c_lflag &= ~(ECHONL);
+        check = tcsetattr(STDIN_FILENO, TCSANOW, &new_mode);
+        assert(check == 0);
+
+        changed = 0;
+        result = set_echo(changed);
+        check = tcgetattr(STDIN_FILENO, &new_mode);
+        assert(check == 0);
+        assert(result != changed);
+        assert(ECHO_TEST == 1);
+        assert(ECHONL_TEST == 0);
+
+        changed = 1;
+        result = set_echo(changed);
+        check = tcgetattr(STDIN_FILENO, &new_mode);
+        assert(check == 0);
+        assert(result == changed);
+        assert(ECHO_TEST == 0);
+        assert(ECHONL_TEST == 1);
+
+        new_mode.c_lflag &= ~(ECHO);
+        new_mode.c_lflag |= ECHONL;
+        check = tcsetattr(STDIN_FILENO, TCSANOW, &new_mode);
+        assert(check == 0);
+
+        changed = 0;
+        result = set_echo(changed);
+        check = tcgetattr(STDIN_FILENO, &new_mode);
+        assert(result == changed);
+        assert(ECHO_TEST == 1);
+        assert(ECHONL_TEST == 0);
+
+        new_mode.c_lflag |= ECHO;
+        new_mode.c_lflag &= ~(ECHONL);
+        check = tcsetattr(STDIN_FILENO, TCSANOW, &new_mode);
+        assert(check == 0);
+
+        changed = 1;
+        result = set_echo(changed);
+        check = tcgetattr(STDIN_FILENO, &new_mode);
+        assert(result != changed);
+        assert(ECHO_TEST == 0);
+        assert(ECHONL_TEST == 1);
+
+        new_mode.c_lflag &= ~(ECHO | ECHONL);
+        check = tcsetattr(STDIN_FILENO, TCSANOW, &new_mode);
+        assert(check == 0);
+
+        changed = 0;
+        result = set_echo(changed);
+        check = tcgetattr(STDIN_FILENO, &new_mode);
+        assert(result != changed);
+        assert(ECHO_TEST == 1);
+        assert(ECHONL_TEST == 0);
+
+        new_mode.c_lflag &= ~(ECHO | ECHONL);
+        check = tcsetattr(STDIN_FILENO, TCSANOW, &new_mode);
+        assert(check == 0);
+
+        changed = 1;
+        result = set_echo(changed);
+        check = tcgetattr(STDIN_FILENO, &new_mode);
+        assert(check == 0);
+        assert(result == changed);
+        assert(ECHO_TEST == 0);
+        assert(ECHONL_TEST == 1);
+
+        new_mode.c_lflag |= (ECHO | ECHONL);
+        check = tcsetattr(STDIN_FILENO, TCSANOW, &new_mode);
+        assert(check == 0);
+
+        changed = 0;
+        result = set_echo(changed);
+        check = tcgetattr(STDIN_FILENO, &new_mode);
+        assert(check == 0);
+        assert(result != changed);
+        assert(ECHO_TEST == 1);
+        assert(ECHONL_TEST == 0);
+
+        new_mode.c_lflag |= (ECHO | ECHONL);
+        check = tcsetattr(STDIN_FILENO, TCSANOW, &new_mode);
+        assert(check == 0);
+
+        changed = 1;
+        result = set_echo(changed);
+        check = tcgetattr(STDIN_FILENO, &new_mode);
+        assert(check == 0);
+        assert(result == changed);
+        assert(ECHO_TEST == 0);
+        assert(ECHONL_TEST == 1);
+
+        check = tcsetattr(STDIN_FILENO, TCSANOW, &old_mode);
+        assert(check == 0);
+
+        return 0;
+    }
+
+    int status;
+    if (safe_waitpid(pid, &status, 0) < 0) {
+        perror_msg_and_die("waitpid failed.");
+    }
+
+    if (WIFEXITED(status)) {
+        return WEXITSTATUS(status);
+    }
+    else if (WIFSIGNALED(status)) {
+        error_msg_and_die("Killed by signal %d.", WTERMSIG(status));
+    }
+    else {
+        error_msg_and_die("Test unexpectedly stopped/continued.");
+    }
+
+    return 0;
+}
+]])
diff --git a/tests/testsuite.at b/tests/testsuite.at
index a0865b2..45ff6da 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -30,3 +30,4 @@ m4_include([bugzilla_plugin.at])
 m4_include([proc_helpers.at])
 m4_include([compress.at])
 m4_include([forbidden_words.at])
+m4_include([client.at])
-- 
2.9.5