Demonstrated use of message sieve by piped frontend program

This commit is contained in:
Thomas Schmitt 2012-12-11 19:27:24 +00:00
parent a3ee936348
commit 639b440e0f

View File

@ -25,31 +25,86 @@
#include <ctype.h> #include <ctype.h>
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 */ /* 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; int do_parse;
char progname[1024]; char progname[1024];
char prefix[1024]; char prefix[1024];
char separators[256]; char separators[256];
int max_words; int max_words;
int flag; 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, int parse_line(char *progname, char *line,
char *prefix, char *separators, int max_words, char *prefix, char *separators, int max_words,
int *argc, char ***argv, int flag); int *argc, char ***argv, int flag);
int dispose_parsed_words(int *argc, char ***argv); 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 */ /* Parent and child */
@ -110,45 +165,37 @@ int main(int argc, char *argv[])
by watching for -mark reply pending_mark. by watching for -mark reply pending_mark.
*/ */
int mark_count = 0, ret; int ret;
char pending_mark[16], line[4096]; char line[4096];
struct parse_rules parse; struct boss_state boss;
close(command_pipe[0]); /* Close unused read end */ close(command_pipe[0]); /* Close unused read end */
close(reply_pipe[1]); /* Close unused write end */ close(reply_pipe[1]); /* Close unused write end */
memset(&parse, 0, sizeof(parse)); /* Disable parsing as default */ memset(&boss, 0, sizeof(boss));
strcpy(parse.progname, argv[0]); boss.command_fd = command_pipe[1];
boss.reply_fd = reply_pipe[0];
strcpy(boss.progname, argv[0]);
boss.reply_lines = NULL;
/* Dialog loop */ /* Dialog loop */
sprintf(pending_mark, "%d", mark_count); sprintf(boss.pending_mark, "%d", boss.mark_count);
while (1) { while (1) {
/* Wait for pending mark and print all replies */ /* 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) if (ret < 0)
break; break;
/* Prompt for command line */ /* Prompt for command line */
ret = prompt_for_command(line, sizeof(line), &parse); ret = prompt_for_command(&boss, line, sizeof(line));
if (ret <= 0) if (ret <= 0)
break; break;
/* Send line and -mark command */ /* Send line and -mark command */
ret = write(command_pipe[1], line, strlen(line)); ret = transmit_command(&boss, line);
if (ret == -1) { if (ret <= 0)
perror("write");
break; 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 -------------------- */ /* ------------------- 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] = { int l, ret;
"usage: frontend_pipes_xorriso [path_to_xorriso|-h]", char *line_res;
"",
"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;
for (i = 0; strcmp(helptext[i], "@END@") != 0; i++) while (1) {
fprintf(stderr, "%s\n", helptext[i]); 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); 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; int count, remainder = 0, ret;
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;
char buf[32769], *line, *npt; char buf[32769], *line, *npt;
while (1) { 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) { if (count == -1) {
perror("read"); perror("read");
return(-1); 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"); "+++ Protocol error : M-channel line shorter than 6 chars\n");
return(-1); return(-1);
} }
if (strcmp(line + 5, pending_mark) == 0) { if (strcmp(line + 5, boss->pending_mark) == 0) {
if ((line - buf) + strlen(line) + 1 < count) { if ((line - buf) + strlen(line) + 1 < count) {
fprintf(stderr, fprintf(stderr,
"+++ Protocol error : Surplus reply data after M-match\n"); "+++ 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 They should be handled by specialized code which knows
how to parse and interpret them. 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 { } else {
/* I-replies are pacifiers, notifications, warnings, or /* I-replies are pacifiers, notifications, warnings, or
error messages. They should be handled by a general error messages. They should be handled by a general
message interpreter which determines their severity message interpreter which determines their severity
and decides whether to bother the user. 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 */ /* Parse line and show words */
if (strlen(line) >= 5) if (strlen(line) >= 5)
show_parsed(parse, line + 5); show_parsed(boss, line + 5);
line = npt + 1; 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; int argc, ret = 0;
char **argv = NULL; 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) if (ret <= 0 || argc <= 0)
return(0); return(0);
if (strcmp(argv[0], "@parse") == 0) { if (strcmp(argv[0], "@parse") == 0) {
parse->do_parse = 1; boss->do_parse = 1;
parse->prefix[0] = 0; boss->prefix[0] = 0;
if (argc > 1) if (argc > 1)
strcpy(parse->prefix, argv[1]); strcpy(boss->prefix, argv[1]);
parse->separators[0] = 0; boss->separators[0] = 0;
if (argc > 2) if (argc > 2)
strcpy(parse->separators, argv[2]); strcpy(boss->separators, argv[2]);
parse->max_words = 0; boss->max_words = 0;
if (argc > 3) if (argc > 3)
sscanf(argv[3], "%d", &(parse->max_words)); sscanf(argv[3], "%d", &(boss->max_words));
parse->max_words = 0; boss->max_words = 0;
if (argc > 4) if (argc > 4)
sscanf(argv[4], "%d", &(parse->flag)); sscanf(argv[4], "%d", &(boss->flag));
ret = 1; ret = 1;
} else if(strcmp(argv[0], "@noparse") == 0) { } else if(strcmp(argv[0], "@noparse") == 0) {
parse->do_parse = 0; boss->do_parse = 0;
ret = 1; ret = 1;
} else if(strcmp(argv[0], "@drain_sieve") == 0) {
ret= drain_sieve(boss);
} else { } else {
ret = 0; 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() -------- */ /* -------- Line-to-word parser equivalent to Xorriso_parse_line() -------- */