From 639b440e0f08d68cff23ace9e6d33240954a93ce Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Tue, 11 Dec 2012 19:27:24 +0000 Subject: [PATCH] Demonstrated use of message sieve by piped frontend program --- test/frontend_pipes_xorriso.c | 512 ++++++++++++++++++++++++++-------- 1 file changed, 390 insertions(+), 122 deletions(-) diff --git a/test/frontend_pipes_xorriso.c b/test/frontend_pipes_xorriso.c index 55e3ad75..f73f957e 100644 --- a/test/frontend_pipes_xorriso.c +++ b/test/frontend_pipes_xorriso.c @@ -25,31 +25,86 @@ #include +static int usage() +{ + static char helptext[][80] = { +"usage: frontend_pipes_xorriso [path_to_xorriso|-h]", +"", +"Forks a process that runs xorriso and communicates with it via two pipes.", +"The command pipe sends payload commands and -mark commands. The reply pipe", +"receives -pkt_output lines which it dispatches to stdout and stderr.", +"The communication between both processes is made synchronous by the parent", +"awaiting the -mark message of the child.", +"Optionally the reply lines can be parsed into words. This is initiated by", +"meta command", +" @parse [prefix [separators [max_words [flag]]]]", +"which sets the four parameters for a function equivalent to", +"Xorriso_parse_line() (see xorriso.h). All reply will then be parsed and", +"non-empty word arrays are displayed. Meta command", +" @noparse", +"ends this mode.", +"Meta command", +" @drain_sieve", +"reports all recorded results of all installed message sieve filter rules.", +"@END@" + }; + int i; + + for (i = 0; strcmp(helptext[i], "@END@") != 0; i++) + fprintf(stderr, "%s\n", helptext[i]); + return(1); +} + + /* Local helpers of parent process */ -struct parse_rules { /* Parsing_parameters. See xorriso.h Xorriso_parse_line */ +struct boss_state { + /* What the parent needs to know about its connection to xorriso */ + + /* The ends of the dialog pipes */ + int command_fd; + int reply_fd; + + /* For synchronization between boss and xorriso */ + int mark_count; + char pending_mark[16]; + + /* Parsing_parameters. See xorriso.h Xorriso_parse_line */ int do_parse; char progname[1024]; - char prefix[1024]; char separators[256]; int max_words; int flag; + + /* A primitive catcher for result lines */ + int reply_lines_size; /* 0= catching disabled */ + char **reply_lines; + int reply_lines_count; }; +#define Frontend_xorriso_max_resulT 1000 + + +/* Some basic gestures of this program: */ + +static int prompt_for_command(struct boss_state *boss, + char *line, int line_size); + +static int transmit_command(struct boss_state *boss, char *line); + +static int await_all_replies(struct boss_state *boss); + +static int de_pkt_result(struct boss_state *boss); + +static int drain_sieve(struct boss_state *boss); + int parse_line(char *progname, char *line, char *prefix, char *separators, int max_words, int *argc, char ***argv, int flag); int dispose_parsed_words(int *argc, char ***argv); -static int await_all_replies(int fd, char *pending_mark, - struct parse_rules *parse); - -static int prompt_for_command(char *line, int line_size, - struct parse_rules *parse); - -static int usage(); /* Parent and child */ @@ -110,45 +165,37 @@ int main(int argc, char *argv[]) by watching for -mark reply pending_mark. */ - int mark_count = 0, ret; - char pending_mark[16], line[4096]; - struct parse_rules parse; + int ret; + char line[4096]; + struct boss_state boss; close(command_pipe[0]); /* Close unused read end */ close(reply_pipe[1]); /* Close unused write end */ - memset(&parse, 0, sizeof(parse)); /* Disable parsing as default */ - strcpy(parse.progname, argv[0]); + memset(&boss, 0, sizeof(boss)); + boss.command_fd = command_pipe[1]; + boss.reply_fd = reply_pipe[0]; + strcpy(boss.progname, argv[0]); + boss.reply_lines = NULL; /* Dialog loop */ - sprintf(pending_mark, "%d", mark_count); + sprintf(boss.pending_mark, "%d", boss.mark_count); while (1) { /* Wait for pending mark and print all replies */ - ret = await_all_replies(reply_pipe[0], pending_mark, &parse); + ret = await_all_replies(&boss); if (ret < 0) break; /* Prompt for command line */ - ret = prompt_for_command(line, sizeof(line), &parse); + ret = prompt_for_command(&boss, line, sizeof(line)); if (ret <= 0) break; /* Send line and -mark command */ - ret = write(command_pipe[1], line, strlen(line)); - if (ret == -1) { - perror("write"); + ret = transmit_command(&boss, line); + if (ret <= 0) break; - } - /* Produce new unique -mark text to watch for */ - mark_count++; - sprintf(pending_mark, "%d", mark_count); - sprintf(line, "-mark %s\n", pending_mark); - ret = write(command_pipe[1], line, strlen(line)); - if (ret == -1) { - perror("write"); - break; - } } @@ -166,64 +213,80 @@ int main(int argc, char *argv[]) /* ------------------- Local helpers of parent process -------------------- */ +static int show_parsed(struct boss_state *boss, char *line); +static int record_reply_line(struct boss_state *boss, char *line); +static int make_reply_lines(struct boss_state *boss); +static int input_interpreter(char *line, struct boss_state *boss); -static int usage() + +/* Ask the user for command input and trigger processing of meta commands. +*/ +static int prompt_for_command(struct boss_state *boss, + char *line, int line_size) { - static char helptext[][80] = { -"usage: frontend_pipes_xorriso [path_to_xorriso|-h]", -"", -"Forks a process that runs xorriso and communicates with it via two pipes.", -"The command pipe sends payload commands and -mark commands. The reply pipe", -"receives -pkt_output lines which it dispatches to stdout and stderr.", -"The communication between both processes is made synchronous by the parent", -"awaiting the -mark message of the child.", -"Optionally the reply lines can be parsed into words. This is initiated by", -"meta command", -" @parse [prefix [separators [max_words [flag]]]]", -"which sets the four parameters for a function equivalent to", -"Xorriso_parse_line() (see xorriso.h). All reply will then be parsed and", -"non-empty word arrays are displayed. Meta command", -" @noparse", -"ends this mode.", -"@END@" - }; - int i; + int l, ret; + char *line_res; - for (i = 0; strcmp(helptext[i], "@END@") != 0; i++) - fprintf(stderr, "%s\n", helptext[i]); + while (1) { + fprintf(stderr, "+++ Enter a command and its parameters :\n"); + line_res = fgets(line, line_size - 1, stdin); + if (line_res == NULL) + return(0); + l = strlen(line); + if (l == 0) { + line[0] = '\n'; + line[1] = 0; + } else if (line[l - 1] != '\n') { + line[l] = '\n'; + line[l + 1] = 0; + } + /* Interpret meta commands which begin by @ */ + ret = input_interpreter(line, boss); + if (ret == 0) + return(1); + if (ret < 0) + return(-1); + } +} + + +/* Transmit a command (which must end by white space, e.g. newline) + and its unique synchronization mark. +*/ +static int transmit_command(struct boss_state *boss, char *line) +{ + int ret; + char mark_line[32]; + + ret = write(boss->command_fd, line, strlen(line)); + if (ret == -1) { + perror("write"); + return(0); + } + /* Produce new unique -mark text to watch for */ + (boss->mark_count)++; + sprintf(boss->pending_mark, "%d", boss->mark_count); + sprintf(mark_line, "-mark %s\n", boss->pending_mark); + ret = write(boss->command_fd, mark_line, strlen(mark_line)); + if (ret == -1) { + perror("write"); + return(0); + } return(1); } -static int show_parsed(struct parse_rules *parse, char *line) +/* Read reply messages from xorriso and wait for the expected synchronization + mark. Messages can be printed or collected in boss->reply_lines. +*/ +static int await_all_replies(struct boss_state *boss) { - int argc, ret = 0, i; - char **argv = NULL; - - if (!parse->do_parse) - return(2); - ret = parse_line(parse->progname, line, parse->prefix, parse->separators, - parse->max_words, &argc, &argv, parse->flag); - if (ret <= 0 || argc <= 0) - return(0); - fprintf(stderr, "-----------------------------------------------------\n"); - fprintf(stderr, "parse_line returns %d, argc = %d\n", ret, argc); - for (i = 0; i < argc; i++) - fprintf(stderr, "%2d : %s\n", i, argv[i]); - fprintf(stderr, "-----------------------------------------------------\n"); - dispose_parsed_words(&argc, &argv); /* release memory */ - return(1); -} - - -static int await_all_replies(int fd, char *pending_mark, - struct parse_rules *parse) -{ - int count, remainder = 0; + int count, remainder = 0, ret; char buf[32769], *line, *npt; while (1) { - count = read(fd, buf + remainder, sizeof(buf) - 1 - remainder); + count = read(boss->reply_fd, buf + remainder, + sizeof(buf) - 1 - remainder); if (count == -1) { perror("read"); return(-1); @@ -267,7 +330,7 @@ static int await_all_replies(int fd, char *pending_mark, "+++ Protocol error : M-channel line shorter than 6 chars\n"); return(-1); } - if (strcmp(line + 5, pending_mark) == 0) { + if (strcmp(line + 5, boss->pending_mark) == 0) { if ((line - buf) + strlen(line) + 1 < count) { fprintf(stderr, "+++ Protocol error : Surplus reply data after M-match\n"); @@ -281,19 +344,29 @@ static int await_all_replies(int fd, char *pending_mark, They should be handled by specialized code which knows how to parse and interpret them. */ - printf("%s\n", line); + if (boss->reply_lines_count < boss->reply_lines_size) { + ret = record_reply_line(boss, line); + if (ret <= 0) + return(ret); + } else + printf("%s\n", line); } else { /* I-replies are pacifiers, notifications, warnings, or error messages. They should be handled by a general message interpreter which determines their severity and decides whether to bother the user. */ - fprintf(stderr, "%s\n", line); + if (boss->reply_lines_count < boss->reply_lines_size) { + ret = record_reply_line(boss, line); + if (ret <= 0) + return(ret); + } else + fprintf(stderr, "%s\n", line); } /* Parse line and show words */ if (strlen(line) >= 5) - show_parsed(parse, line + 5); + show_parsed(boss, line + 5); line = npt + 1; } @@ -302,32 +375,256 @@ static int await_all_replies(int fd, char *pending_mark, } -static int input_interpreter(char *line, struct parse_rules *parse) +/* Throw away I channel. + Unpack and reconstruct payload of R channel lines. +*/ +static int de_pkt_result(struct boss_state *boss) +{ + int i, l, w; + char *payload = NULL, *new_payload = NULL; + + w = 0; + for (i = 0; i < boss->reply_lines_count; i++) { + if (boss->reply_lines[i][0] != 'R' || + strlen(boss->reply_lines[i]) < 5) + continue; + + if (payload == NULL) { + payload = strdup(boss->reply_lines[i] + 5); + } else { + l = strlen(payload); + new_payload = calloc(l + strlen(boss->reply_lines[i] + 5) + 1, 1); + if (new_payload == NULL) + goto no_mem; + strcpy(new_payload, payload); + strcpy(new_payload + l, boss->reply_lines[i] + 5); + free(payload); + payload = new_payload; + } + if (payload == NULL) + goto no_mem; + l = strlen(payload); + if (l > 0) + if (payload[l - 1] == '\n') + payload[l - 1] = 0; + + if (boss->reply_lines[i][2] != '0') { + free(boss->reply_lines[w]); + boss->reply_lines[w] = payload; + w++; + payload = NULL; + } + } + for (i = w ; i < boss->reply_lines_count; i++) { + free(boss->reply_lines[i]); + boss->reply_lines[i] = NULL; + } + boss->reply_lines_count = w; + return(1); +no_mem:; + fprintf(stderr, "FATAL: Out of memory !\n"); + return(-1); +} + + +/* Inquire and print all recorded message sieve results. +*/ +static int drain_sieve(struct boss_state *boss) +{ + int ret, i, j, names_size = 0, names_count = 0, first_result; + int number_of_strings, available, xorriso_ret, number_of_lines, k, r; + char **names = NULL, line[1024]; + + /* Install catcher for reply_lines */ + ret = make_reply_lines(boss); + if (ret <= 0) + goto ex; + boss->reply_lines_size = Frontend_xorriso_max_resulT; + boss->reply_lines_count = 0; + + /* Get list of filter rule names from -msg_op show_sieve */ + ret = transmit_command(boss, "-msg_op show_sieve -\n"); + if (ret <= 0) + goto ex; + ret = await_all_replies(boss); + if (ret <= 0) + goto ex; + ret = de_pkt_result(boss); + if (ret <= 0) + goto ex; + + names = boss->reply_lines; + boss->reply_lines = NULL; + names_size = Frontend_xorriso_max_resulT; + names_count= boss->reply_lines_count; + ret = make_reply_lines(boss); + if (ret <= 0) + goto ex; + boss->reply_lines_size = Frontend_xorriso_max_resulT; + + /* Inquire caught results of each name by -msg_op read_sieve + until return value is <= 0 + */ + printf("--------------------------------------------------\n"); + for (i = 0; i < names_count; i++) { + available = 1; + first_result = 1; + while (available > 0) { + boss->reply_lines_count = 0; + sprintf(line, "-msg_op read_sieve '%s'\n", names[i]); + ret = transmit_command(boss, line); + if (ret <= 0) + goto ex; + ret = await_all_replies(boss); + if (ret <= 0) + goto ex; + ret = de_pkt_result(boss); + if (ret <= 0) + goto ex; + + if (boss->reply_lines_count < 2) { + fprintf(stderr, "drain_sieve: illegible result reply\n"); + {ret= 0; goto ex;} + } + xorriso_ret = -1; + sscanf(boss->reply_lines[0], "%d", &xorriso_ret); + if(xorriso_ret <= 0) + break; + number_of_strings = -1; + sscanf(boss->reply_lines[1], "%d", &number_of_strings); + if(xorriso_ret < 0) + break; + if (first_result) + printf(" '%s' |\n", names[i]); + first_result = 0; + for (j = 0; names[i][j] != 0; j++) + printf("-"); + printf("-----\n"); + r = 2; + for (j = 0; j < number_of_strings && r < boss->reply_lines_count; + j++) { + number_of_lines = -1; + sscanf(boss->reply_lines[r], "%d", &number_of_lines); + r++; + printf("|"); + for (k = 0; k < number_of_lines + && r < boss->reply_lines_count; k++) { + printf("%s%s", boss->reply_lines[r], + k < number_of_lines - 1 ? "\n" : ""); + r++; + } + printf("|\n"); + } + } + if (first_result == 0) + printf("--------------------------------------------------\n"); + } + + /* Dispose all recorded results */ + ret = transmit_command(boss, "-msg_op clear_sieve -\n"); + if (ret <= 0) + goto ex; + ret = await_all_replies(boss); + if (ret <= 0) + goto ex; + + ret = 1; +ex:; + /* Disable result catcher */ + boss->reply_lines_size = 0; + if (names != NULL) + dispose_parsed_words(&names_size, &names); + return(ret); +} + + +/* ------------------------- Helpers of local helpers ---------------------- */ + + +static int show_parsed(struct boss_state *boss, char *line) +{ + int argc, ret = 0, i; + char **argv = NULL; + + if (!boss->do_parse) + return(2); + ret = parse_line(boss->progname, line, boss->prefix, boss->separators, + boss->max_words, &argc, &argv, boss->flag); + if (ret <= 0 || argc <= 0) + return(0); + fprintf(stderr, "-----------------------------------------------------\n"); + fprintf(stderr, "parse_line returns %d, argc = %d\n", ret, argc); + for (i = 0; i < argc; i++) + fprintf(stderr, "%2d : %s\n", i, argv[i]); + fprintf(stderr, "-----------------------------------------------------\n"); + dispose_parsed_words(&argc, &argv); /* release memory */ + return(1); +} + + +static int make_reply_lines(struct boss_state *boss) +{ + int i; + + if (boss->reply_lines != NULL) + return(1); + + boss->reply_lines = calloc(Frontend_xorriso_max_resulT, + sizeof(char *)); + if (boss->reply_lines == 0) { + fprintf(stderr, "FATAL: Out of memory !\n"); + return(-1); + } + boss->reply_lines_count = 0; + boss->reply_lines_size = 0; + for (i = 0; i < Frontend_xorriso_max_resulT; i++) + boss->reply_lines[i] = NULL; + return(1); +} + + +static int record_reply_line(struct boss_state *boss, char *line) +{ + if (boss->reply_lines[boss->reply_lines_count] != NULL) + free(boss->reply_lines[boss->reply_lines_count]); + boss->reply_lines[boss->reply_lines_count] = strdup(line); + if (boss->reply_lines[boss->reply_lines_count] == NULL) { + fprintf(stderr, "FATAL: Out of memory !\n"); + return(-1); + } + boss->reply_lines_count++; + return(1); +} + + +static int input_interpreter(char *line, struct boss_state *boss) { int argc, ret = 0; char **argv = NULL; - ret = parse_line(parse->progname, line, "", "", 6, &argc, &argv, 0); + ret = parse_line(boss->progname, line, "", "", 6, &argc, &argv, 0); if (ret <= 0 || argc <= 0) return(0); if (strcmp(argv[0], "@parse") == 0) { - parse->do_parse = 1; - parse->prefix[0] = 0; + boss->do_parse = 1; + boss->prefix[0] = 0; if (argc > 1) - strcpy(parse->prefix, argv[1]); - parse->separators[0] = 0; + strcpy(boss->prefix, argv[1]); + boss->separators[0] = 0; if (argc > 2) - strcpy(parse->separators, argv[2]); - parse->max_words = 0; + strcpy(boss->separators, argv[2]); + boss->max_words = 0; if (argc > 3) - sscanf(argv[3], "%d", &(parse->max_words)); - parse->max_words = 0; + sscanf(argv[3], "%d", &(boss->max_words)); + boss->max_words = 0; if (argc > 4) - sscanf(argv[4], "%d", &(parse->flag)); + sscanf(argv[4], "%d", &(boss->flag)); ret = 1; } else if(strcmp(argv[0], "@noparse") == 0) { - parse->do_parse = 0; + boss->do_parse = 0; ret = 1; + } else if(strcmp(argv[0], "@drain_sieve") == 0) { + ret= drain_sieve(boss); } else { ret = 0; } @@ -336,35 +633,6 @@ static int input_interpreter(char *line, struct parse_rules *parse) } -static int prompt_for_command(char *line, int line_size, - struct parse_rules *parse) -{ - int l, ret; - char *line_res; - - while (1) { - fprintf(stderr, "+++ Enter a command and its parameters :\n"); - line_res = fgets(line, line_size - 1, stdin); - if (line_res == NULL) - return(0); - l = strlen(line); - if (l == 0) { - line[0] = '\n'; - line[1] = 0; - } else if (line[l - 1] != '\n') { - line[l] = '\n'; - line[l + 1] = 0; - } - /* Interpret meta commands which begin by @ */ - ret = input_interpreter(line, parse); - if (ret == 0) - return(1); - if (ret < 0) - return(-1); - } -} - - /* -------- Line-to-word parser equivalent to Xorriso_parse_line() -------- */