* the implementations of event command request handlers were moved in to
  separate functions
* the request handlers are called through run_event_state callbacks

Signed-off-by: Jakub Filak <[email protected]>
---
 src/include/run_event.h |   88 +++++++++++++++++++++++++++++++++++++++++++
 src/lib/run_event.c     |   96 ++++++++++++++++++++++++++++++++---------------
 2 files changed, 154 insertions(+), 30 deletions(-)

diff --git a/src/include/run_event.h b/src/include/run_event.h
index 43730ce..4577444 100644
--- a/src/include/run_event.h
+++ b/src/include/run_event.h
@@ -40,6 +40,57 @@ struct run_event_state {
     char* (*logging_callback)(char *log_line, void *param);
     void *logging_param;
 
+    /*
+     * An optional argument for the following callbacks
+     */
+    void *interaction_param;
+
+    /*
+     * Called when child command produced an alert.
+     *
+     * The default value is run_event_stdio_alert()
+     *
+     * @param msg An alert message produced byt child command
+     * @param args An interaction param
+     */
+    void (*alert_callback)(const char *msg, void *interaction_param);
+
+    /*
+     * Called when child command ask for some input. A callee
+     * should return a text whithout any new line character.
+     *
+     * The default value is run_event_stdio_ask()
+     *
+     * @param msg An ask message produced by child command
+     * @param args An interaction param
+     * @return Must allways return string without new lines, an empty string
+     *         if response was not get.
+     */
+    char *(*ask_callback)(const char *msg, void *interaction_param);
+
+    /*
+     * Called when child command wants to know 'yes/no' decision.
+     *
+     * The default value is run_event_stdio_ask_yes_no()
+     *
+     * @param msg An ask message produced by child command
+     * @param args An implementor args
+     * @return Return 0 if an answer is NO, otherwise return nonzero value.
+     */
+    int (*ask_yes_no_callback)(const char *msg, void *interaction_param);
+
+    /*
+     * Called when child wants to know a password.
+     *
+     * The default value is run_event_stdio_ask_password()
+     *
+     * @param msg An ask message produced by child command
+     * @param args An interaction param
+     * @return Must allways return string without new lines, an empty string
+     *         if password was not get.
+     */
+    char *(*ask_password_callback)(const char *msg, void *interaction_param);
+
     /* Internal data for async command execution */
     GList *rule_list;
     pid_t command_pid;
@@ -76,6 +127,43 @@ int run_event_on_problem_data(struct run_event_state 
*state, problem_data_t *dat
  */
 char *list_possible_events(struct dump_dir *dd, const char *dump_dir_name, 
const char *pfx);
 
+/* Command line run event callback implemenetation */
+
+/*
+ * Prints the msg param on stdout
+ *
+ * @param msg a printed message
+ * @param param UNUSED
+ */
+void run_event_stdio_alert(const char *msg, void *param);
+
+/*
+ * Prints the msg param on stdout and reads a response from stdin
+ *
+ * @param msg a printed message
+ * @param param UNUSED
+ * @return a malloced string with response, an empty string on error or no 
response
+ */
+char *run_event_stdio_ask(const char *msg, void *param);
+
+/*
+ * Prints the msg param on stdout and reads a response from stdin
+ *
+ * @param msg a printed message
+ * @param param UNUSED
+ * @return 0 if user's answer is 'no', otherwise non 0 value
+ */
+int run_event_stdio_ask_yes_no(const char *msg, void *param);
+
+/*
+ * Prints the msg param on stdout and reads a response from stdin
+ *
+ * @param msg a printed message
+ * @param param UNUSED
+ * @return a malloced string with response, an empty string on error or no 
response
+ */
+char *run_event_stdio_ask_password(const char *msg, void *param);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/lib/run_event.c b/src/lib/run_event.c
index 105cef5..ab6d79c 100644
--- a/src/lib/run_event.c
+++ b/src/lib/run_event.c
@@ -23,7 +23,14 @@
 
 struct run_event_state *new_run_event_state()
 {
-    return xzalloc(sizeof(struct run_event_state));
+    struct run_event_state *state = xzalloc(sizeof(struct 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_password_callback = run_event_stdio_ask_password;
+
+    return state;
 }
 
 void free_run_event_state(struct run_event_state *state)
@@ -451,60 +458,48 @@ static int run_event_command_on_dir_name(struct 
run_event_state *state, const ch
     {
         msg = buf;
 
+        char *response = NULL;
         /* just cut off prefix, no waiting */
         if (strncmp(REPORT_PREFIX_ALERT, msg, alert_prefix_len) == 0)
         {
             msg += alert_prefix_len;
-            printf("%s\n", msg);
-            fflush(stdout);
+            state->alert_callback(msg, state->interaction_param);
         }
         /* wait for y/N response on the same line */
         else if (strncmp(REPORT_PREFIX_ASK_YES_NO, msg, ask_yes_no_prefix_len) 
== 0)
         {
             msg += ask_yes_no_prefix_len;
-            printf("%s [%s/%s] ", msg, _("y"), _("N"));
-            fflush(stdout);
-            char buf[16];
-            if (!fgets(buf, sizeof(buf), stdin))
-                buf[0] = '\0';
-
-            if (write(state->command_in_fd, buf, strlen(buf)) < 0)
-                perror_msg_and_die("write");
+            const bool ans = state->ask_yes_no_callback(msg, 
state->interaction_param);
+            response = xstrdup(ans ? "yes" : "no");
         }
         /* wait for the string on the same line */
         else if (strncmp(REPORT_PREFIX_ASK, msg, ask_prefix_len) == 0)
         {
             msg += ask_prefix_len;
-            printf("%s ", msg);
-            fflush(stdout);
-            char buf[256];
-            if (!fgets(buf, sizeof(buf), stdin))
-                buf[0] = '\0';
-
-            if (write(state->command_in_fd, buf, strlen(buf)) < 0)
-                perror_msg_and_die("write");
+            response = state->ask_callback(msg, state->interaction_param);
         }
         /* set echo off and wait for password on the same line */
         else if (strncmp(REPORT_PREFIX_ASK_PASSWORD, msg, 
ask_password_prefix_len) == 0)
         {
             msg += ask_password_prefix_len;
-            printf("%s ", msg);
-            fflush(stdout);
-            char buf[256];
-            bool changed = set_echo(false);
-            if (!fgets(buf, sizeof(buf), stdin))
-                buf[0] = '\0';
-            if (changed)
-                set_echo(true);
-
-            if (write(state->command_in_fd, buf, strlen(buf)) < 0)
-                perror_msg_and_die("write");
+            response = state->ask_password_callback(msg, 
state->interaction_param);
         }
         /* no special prefix -> forward to log if applicable
          * note that callback may take ownership of buf by returning NULL */
         else if (state->logging_callback)
             buf = state->logging_callback(buf, state->logging_param);
 
+        if (response)
+        {
+            size_t len = strlen(response);
+            response[len++] = '\n';
+
+            if (full_write(state->command_in_fd, response, len) != len)
+                perror_msg_and_die("Can't write %lu bytes to child's stdin", 
len);
+
+            free(response);
+        }
+
         free(buf);
     }
     fclose(fp); /* Got EOF, close. This also closes state->command_out_fd */
@@ -612,3 +607,44 @@ char *list_possible_events(struct dump_dir *dd, const char 
*dump_dir_name, const
 
     return strbuf_free_nobuf(result);
 }
+
+void run_event_stdio_alert(const char *msg, void *param)
+{
+    printf("%s\n", msg);
+    fflush(stdout);
+}
+
+char *run_event_stdio_ask(const char *msg, void *param)
+{
+    printf("%s ", msg);
+    fflush(stdout);
+    char buf[256];
+    if (!safe_read(STDIN_FILENO, buf, sizeof(buf)))
+        buf[0] = '\0';
+    else
+        strtrimch(buf, '\n');
+
+    return xstrdup(buf);
+}
+
+int run_event_stdio_ask_yes_no(const char *msg, void *param)
+{
+    printf("%s [%s/%s] ", msg, _("y"), _("N"));
+    fflush(stdout);
+    char buf[16];
+    if (!safe_read(STDIN_FILENO, buf, sizeof(buf)))
+        return false;
+
+    return buf[0] == 'y' && (buf[1] == '\n' || buf[1] == '\0');
+}
+
+char *run_event_stdio_ask_password(const char *msg, void *param)
+{
+    const bool changed = set_echo(false);
+    char *const password = run_event_stdio_ask(msg, param);
+
+    if (changed)
+        set_echo(true);
+
+    return password;
+}
-- 
1.7.10.4

Reply via email to