- a questions having this prefix have three posible answers:
    yes / no / yes and don't ask me again
- the prefix must be followed by ' ' and a single word as key for
  configuration, a question message follows the key
- somebody can be confused byt the logic but it was originally
  implemented in report-gtk ("Don't ask me again" check box)

Signed-off-by: Jakub Filak <[email protected]>
---
 src/cli/cli.c               | 19 +++++++++++----
 src/gui-wizard-gtk/wizard.c |  8 +++++++
 src/include/client.h        | 11 +++++++++
 src/include/run_event.h     | 29 +++++++++++++++++++++++
 src/lib/run_event.c         | 57 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 120 insertions(+), 4 deletions(-)

diff --git a/src/cli/cli.c b/src/cli/cli.c
index c82a783..bb73f70 100644
--- a/src/cli/cli.c
+++ b/src/cli/cli.c
@@ -134,6 +134,11 @@ int main(int argc, char** argv)
     /* Get settings */
     load_event_config_data();
 
+    /* At least, needed by ASK_YES_NO_YESFOREVER event command requests.
+     * Removing of the following statemen will get the yes forever stuff not
+     * working. */
+    load_user_settings("report-cli");
+
     /* Do the selected operation. */
     int exitcode = 0;
     switch (op)
@@ -182,7 +187,7 @@ int main(int argc, char** argv)
 
             /* Be consistent and return 1 when opening dd failed */
             if (exitcode == -1)
-                return 1;
+                exitcode = 1;
 
             break;
         }
@@ -194,9 +199,13 @@ int main(int argc, char** argv)
                     (always ? CLI_REPORT_BATCH : 0));
 
             if (exitcode == -1)
-                error_msg_and_die("Crash '%s' not found", dump_dir_name);
-
-            if (opts & OPT_delete)
+            {   /* Be consistent and return 1 */
+                exitcode = 1;
+                /* Can't use error_msg_and_die() function because we want to
+                 * store user's answers on yes/no/yes forever questions */
+                error_msg("Crash '%s' not found", dump_dir_name);
+            }
+            else if (opts & OPT_delete)
             {
                 int r = delete_dump_dir_possibly_using_abrtd(dump_dir_name);
                 if (exitcode == 0)
@@ -207,5 +216,7 @@ int main(int argc, char** argv)
         }
     }
 
+    /* At least, needed by ASK_YES_NO_YESFOREVER event command requests. */
+    save_user_settings();
     return exitcode;
 }
diff --git a/src/gui-wizard-gtk/wizard.c b/src/gui-wizard-gtk/wizard.c
index 1a48a8d..c2a7a72 100644
--- a/src/gui-wizard-gtk/wizard.c
+++ b/src/gui-wizard-gtk/wizard.c
@@ -1649,6 +1649,13 @@ static int run_event_gtk_ask_yes_no(const char *msg, 
void *args)
     return ret;
 }
 
+static int run_event_gtk_ask_yes_no_yesforever(const char *msg, const char 
*key, void *args)
+{
+    const int ret = ask_yes_no_save_result(msg, key);
+    log_request_response_communication(msg, ret ? "YES" : "NO", (struct 
analyze_event_data *)args);
+    return ret;
+}
+
 static char *run_event_gtk_ask_password(const char *msg, void *args)
 {
     return ask_helper(msg, args, true);
@@ -1802,6 +1809,7 @@ static void start_event_run(const char *event_name,
     state->alert_callback = run_event_gtk_alert;
     state->ask_callback = run_event_gtk_ask;
     state->ask_yes_no_callback = run_event_gtk_ask_yes_no;
+    state->ask_yes_no_yesforever_callback = 
run_event_gtk_ask_yes_no_yesforever;
     state->ask_password_callback = run_event_gtk_ask_password;
 
     if (prepare_commands(state, g_dump_dir_name, event_name) == 0)
diff --git a/src/include/client.h b/src/include/client.h
index a714ba8..8d7218c 100644
--- a/src/include/client.h
+++ b/src/include/client.h
@@ -21,6 +21,17 @@
 #define LIBREPORT_CLIENT_H_
 
 #define REPORT_PREFIX_ASK_YES_NO "ASK_YES_NO "
+/* The REPORT_PREFIX_ASK_YES_NO_YESFOREVER prefix must be followed by a single
+ * word used as key. If the prefix is followed only by the key the
+ * REPORT_PREFIX_ASK_YES_NO implementation is used instead.
+ *
+ * Example:
+ *   ASK_YES_NO_YESFOREVER ask_before_suicide Do you really want to kill 
yourself?
+ *
+ * Example of message handle as REPORT_PREFIX_ASK_YES_NO:
+ *   ASK_YES_NO_YESFOREVER Continue?
+ */
+#define REPORT_PREFIX_ASK_YES_NO_YESFOREVER "ASK_YES_NO_YESFOREVER "
 #define REPORT_PREFIX_ASK "ASK "
 #define REPORT_PREFIX_ASK_PASSWORD "ASK_PASSWORD "
 #define REPORT_PREFIX_ALERT "ALERT "
diff --git a/src/include/run_event.h b/src/include/run_event.h
index fdf3555..c5791f0 100644
--- a/src/include/run_event.h
+++ b/src/include/run_event.h
@@ -89,6 +89,21 @@ struct run_event_state {
     int (*ask_yes_no_callback)(const char *msg, void *interaction_param);
 
     /*
+     * Called when child command wants to know 'yes/no/yesforever' decision.
+     * The yes forever means that in next call the yes answer is returned
+     * immediately without asking. The yes forever answer is stored in
+     * configuration under a passed key.
+     *
+     * The default value is run_event_stdio_ask_yes_no_yesforever()
+     *
+     * @param msg An ask message produced by child command
+     * @param key An option name used as a key in configuration
+     * @param args An implementor args
+     * @return Return 0 if an answer is NO, otherwise return nonzero value.
+     */
+    int (*ask_yes_no_yesforever_callback)(const char *msg, const char *key, 
void *interaction_param);
+
+    /*
      * Called when child wants to know a password.
      *
      * The default value is run_event_stdio_ask_password()
@@ -179,6 +194,20 @@ char *run_event_stdio_ask(const char *msg, void *param);
 int run_event_stdio_ask_yes_no(const char *msg, void *param);
 
 /*
+ * Prints the msg param on stdout and reads a response from stdin. To store the
+ * yes forever answer uses libreport's user settings API. Therefore if you want
+ * to get the yes forever stuff working you have to call load_user_setting()
+ * function before this function call and call save_user_settings() function
+ * after this function call.
+ *
+ * @param msg a printed message
+ * @param key a key under which the yes forever answer is stored
+ * @param param UNUSED
+ * @return 0 if user's answer is 'no', otherwise non 0 value
+ */
+int run_event_stdio_ask_yes_no_yesforever(const char *msg, const char *key, 
void *param);
+
+/*
  * Prints the msg param on stdout and reads a response from stdin
  *
  * @param msg a printed message
diff --git a/src/lib/run_event.c b/src/lib/run_event.c
index 622833a..f04cb37 100644
--- a/src/lib/run_event.c
+++ b/src/lib/run_event.c
@@ -28,6 +28,7 @@ struct run_event_state *new_run_event_state()
     state->alert_callback = run_event_stdio_alert;
     state->ask_callback = run_event_stdio_ask;
     state->ask_yes_no_callback = run_event_stdio_ask_yes_no;
+    state->ask_yes_no_yesforever_callback= 
run_event_stdio_ask_yes_no_yesforever;
     state->ask_password_callback = run_event_stdio_ask_password;
 
     state->command_output = strbuf_new();
@@ -478,6 +479,37 @@ int consume_event_command_output(struct run_event_state 
*state, const char *dump
             {
                 state->alert_callback(msg + sizeof(REPORT_PREFIX_ALERT) - 1 , 
state->interaction_param);
             }
+            /* wait for y/N/f response on the same line */
+            else if (prefixcmp(msg, REPORT_PREFIX_ASK_YES_NO_YESFOREVER) == 0)
+            {
+                /* example:
+                 *   ASK_YES_NO_YESFOREVER ask_before_suicide Do you really 
want to kill yourself?
+                 */
+                char *key = msg + sizeof(REPORT_PREFIX_ASK_YES_NO_YESFOREVER) 
- 1;
+                char *key_end = strchr(key, ' ');
+
+                bool ans = false;
+
+                if (!key_end)
+                {   /* example:
+                     *  ASK_YES_NO_YESFOREVER Continue?
+                     *
+                     * Print a wraning only and do not scary users with error 
messages.
+                     */
+                    log("Warning: invalid input format (missing option name), 
using simple ask yes/no");
+
+                    /* can't simply use 'goto ask_yes_no' because of different 
lenght of prefixes */
+                    ans = state->ask_yes_no_callback(key, 
state->interaction_param);
+                }
+                else
+                {
+                    key_end[0] = '\0'; /* split 'key msg' to 'key' and 'msg' */
+                    ans = state->ask_yes_no_yesforever_callback(key + 
strlen(key) + 1, key, state->interaction_param);
+                    key_end[0] = ' '; /* restore original message, not sure if 
it is necessary */
+                }
+
+                response = xstrdup(ans ? "yes" : "no");
+            }
             /* wait for y/N response on the same line */
             else if (prefixcmp(msg, REPORT_PREFIX_ASK_YES_NO) == 0)
             {
@@ -671,6 +703,31 @@ int run_event_stdio_ask_yes_no(const char *msg, void 
*param)
     return buf[0] == 'y' && (buf[1] == '\n' || buf[1] == '\0');
 }
 
+int run_event_stdio_ask_yes_no_yesforever(const char *msg, const char *key, 
void *param)
+{
+    const char *ask_result = get_user_setting(key);
+
+    if (ask_result && string_to_bool(ask_result) == false)
+        /* Do you want to be asked? -> No, I don't */
+        return 1;
+
+    printf("%s [%s/%s/%s] ", msg, _("y"), _("N"), _("f"));
+    fflush(stdout);
+    char buf[16];
+    if (!fgets(buf, sizeof(buf), stdin))
+        buf[0] = '\0';
+
+    char *endln = strchr(buf, '\n');
+    if (endln)
+        endln[0] = '\0';
+
+    /* Do you want to be asked for next time? */
+    /* 'f' means 'yes forever' and it means 'no, dont' ask me again' */
+    set_user_setting(key, strcmp(_("f"), buf) == 0 ? "no" : "yes");
+
+    return strcmp(_("f"), buf) == 0 || strcmp(_("y"), buf) == 0;
+}
+
 char *run_event_stdio_ask_password(const char *msg, void *param)
 {
     const bool changed = set_echo(false);
-- 
1.7.11.4

Reply via email to