This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GNU Mailutils".
http://git.savannah.gnu.org/cgit/mailutils.git/commit/?id=820568fbf17c86fd4e68fff5e056c1c6deb1a319 The branch, master has been updated via 820568fbf17c86fd4e68fff5e056c1c6deb1a319 (commit) from 110d13ec5187a06c59a53deb0f76b2e944c334ef (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 820568fbf17c86fd4e68fff5e056c1c6deb1a319 Author: Sergey Poznyakoff <g...@gnu.org.ua> Date: Thu Nov 18 10:36:46 2010 +0200 mh: implement prompter * configure.ac (MU_COND_READLINE): New cond. * mh/prompter.c: New file. * mh/prompter-rl.c: New file. * mh/prompter-tty.c: New file. * mh/prompter.h: New file. * mh/TODO: Update. * mh/Makefile.am: Build prompter. * doc/texinfo/mu-mh.texi: Document prompter * po/POTFILES.in: Update. ----------------------------------------------------------------------- Summary of changes: configure.ac | 6 +- doc/texinfo/mu-mh.texi | 63 +++++-- mh/Makefile.am | 16 ++ mh/TODO | 2 + testsuite/mbdel.c => mh/prompter-rl.c | 80 +++++---- mh/prompter-tty.c | 197 +++++++++++++++++++++ mh/prompter.c | 313 +++++++++++++++++++++++++++++++++ mail/list.c => mh/prompter.h | 23 +-- po/POTFILES.in | 2 + 9 files changed, 635 insertions(+), 67 deletions(-) copy testsuite/mbdel.c => mh/prompter-rl.c (53%) create mode 100644 mh/prompter-tty.c create mode 100644 mh/prompter.c copy mail/list.c => mh/prompter.h (67%) diff --git a/configure.ac b/configure.ac index 67ddf6b..7c9df0a 100644 --- a/configure.ac +++ b/configure.ac @@ -909,7 +909,7 @@ AC_SUBST(CURSES_LIBS) dnl Check for GNU Readline AC_SUBST(READLINE_LIBS) -if test x"$usereadline" = x"yes"; then +if test "$usereadline" = "yes"; then dnl FIXME This should only link in the curses libraries if it's dnl really needed! @@ -919,7 +919,7 @@ if test x"$usereadline" = x"yes"; then AC_CHECK_LIB(readline, readline, mu_have_readline=yes) LIBS=$saved_LIBS - if test x"$mu_have_readline" = x"yes"; then + if test "$mu_have_readline" = "yes"; then AC_CHECK_HEADERS(readline/readline.h, AC_DEFINE(WITH_READLINE,1,[Enable use of readline])) READLINE_LIBS="-lreadline $CURSES_LIBS" @@ -933,6 +933,8 @@ if test x"$usereadline" = x"yes"; then fi +AM_CONDITIONAL([MU_COND_READLINE], [test "$usereadline" = "yes"]) + AH_BOTTOM([ /* Newer versions of readline have rl_completion_matches */ #ifndef HAVE_RL_COMPLETION_MATCHES diff --git a/doc/texinfo/mu-mh.texi b/doc/texinfo/mu-mh.texi index b04a34c..99ebaeb 100644 --- a/doc/texinfo/mu-mh.texi +++ b/doc/texinfo/mu-mh.texi @@ -311,25 +311,6 @@ behaviour is disabled when @option{--quiet} option was given. The @option{--all} mode does not display commented out entries. -...@item repl - -Understands @option{--use} option. Disposition shell provides -...@code{use} command. - -...@item rmm - -...@enumerate 1 -...@item -Different behaviour if one of the messages in the list does not exist: - -Mailutils @command{rmm} does not delete any messages. Standard -...@command{rmm} in this case deletes all messages preceding the -non-existent one. - -...@item -The @code{rmmproc} profile component is not used. -...@end enumerate - @item pick The command line syntax @option...@var{component} @var{string}}) is @@ -388,6 +369,31 @@ pick --before '1 year ago' etc... @end smallexample +...@item prompter +...@enumerate +...@item +Prompter attempts to use GNU Readline library, if it is installed. +Consequently, arguments to @option{-erase} and @option{-kill} option +must follow GNU style key sequence notation (@pxref{Readline Init File +Syntax, keyseq,,readline,GNU Readline Library}). + +If @command{prompter} is built without @command{readline}, it accepts +the following character notations: + +...@table @asis +...@item \...@var{nnnn} +Here, @var{n} stands for a single octal digit. + +...@item ^...@var{chr} +This notation is translated to the ASCII code @sa...@var{chr} + 0100}. +...@end table + +...@item +Component continuation lines are not required to begin with a +whitespace. If leading whitespace is not present, @command{prompter} +will add it automatically. +...@end enumerate + @item refile @enumerate @@ -405,6 +411,25 @@ compatibility only. Message specs and folder names may be interspersed. @end enumerate +...@item repl + +Understands @option{--use} option. Disposition shell provides +...@code{use} command. + +...@item rmm + +...@enumerate 1 +...@item +Different behaviour if one of the messages in the list does not exist: + +Mailutils @command{rmm} does not delete any messages. Standard +...@command{rmm} in this case deletes all messages preceding the +non-existent one. + +...@item +The @code{rmmproc} profile component is not used. +...@end enumerate + @item sortm New option @option{--numfield} specifies numeric comparison for the diff --git a/mh/Makefile.am b/mh/Makefile.am index 2c52f55..08218b2 100644 --- a/mh/Makefile.am +++ b/mh/Makefile.am @@ -34,6 +34,7 @@ bin_PROGRAMS = \ mhparam\ mhpath\ pick\ + prompter\ refile\ repl\ rmf\ @@ -44,6 +45,21 @@ bin_PROGRAMS = \ whatnow\ whom +prompter_LDADD = $(mh_LIBS) + +if MU_COND_READLINE + PROMPTER_FUN=prompter-rl.c + prompter_LDADD += @READLINE_LIBS@ +else + PROMPTER_FUN=prompter-tty.c + prompter_LDADD += @CURSES_LIBS@ +endif + +prompter_SOURCES = \ + prompter.c\ + prompter.h\ + $(PROMPTER_FUN) + noinst_LIBRARIES = libmh.a libmh_a_SOURCES= \ diff --git a/mh/TODO b/mh/TODO index 8dfe2c6..ba6b410 100644 --- a/mh/TODO +++ b/mh/TODO @@ -40,6 +40,7 @@ State Nice Utility Comments + 10 mhpath + 10 whatnow + 20 sortm ++ 20 prompter Utilities In Alphabetical Order =============================== @@ -55,6 +56,7 @@ mhl mhn mhpath pick +prompter refile repl rmf diff --git a/testsuite/mbdel.c b/mh/prompter-rl.c similarity index 53% copy from testsuite/mbdel.c copy to mh/prompter-rl.c index e1c7339..731c9cb 100644 --- a/testsuite/mbdel.c +++ b/mh/prompter-rl.c @@ -14,41 +14,55 @@ You should have received a copy of the GNU General Public License along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <mailutils/mailutils.h> - -int -main (int argc, char **argv) +/* MH prompter - readline support */ + +#include <mh.h> +#include "prompter.h" +#include <readline/readline.h> + +void +prompter_init () { - int rc; - mu_mailbox_t mbox; - - if (argc != 2) - { - fprintf (stderr, "usage: %s URL\n", argv[0]); - return 1; - } +} + +void +prompter_done () +{ +} + +void +prompter_set_erase (const char *keyseq) +{ + rl_bind_keyseq (keyseq, rl_delete); +} - mu_register_all_mbox_formats (); - - MU_ASSERT (mu_mailbox_create (&mbox, argv[1])); - rc = mu_mailbox_remove (mbox); - if (rc) +void +prompter_set_kill (const char *keyseq) +{ + rl_bind_keyseq (keyseq, rl_kill_full_line); +} + +char * +prompter_get_value (const char *name) +{ + char *prompt = NULL; + char *val; + + if (name) { - if (rc == ENOTEMPTY) - { - printf ("mailbox removed, but has subfolders\n"); - rc = 0; - } - else - fprintf (stderr, "%s\n", mu_strerror (rc)); + prompt = xmalloc (strlen (name) + 3); + strcpy (prompt, name); + strcat (prompt, ": "); } - mu_mailbox_destroy (&mbox); - - return rc != 0; + val = readline (prompt); + free (prompt); + return val; } + +char * +prompter_get_line () +{ + return doteof_filter (readline (NULL)); +} + + diff --git a/mh/prompter-tty.c b/mh/prompter-tty.c new file mode 100644 index 0000000..92c3f3f --- /dev/null +++ b/mh/prompter-tty.c @@ -0,0 +1,197 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2010 Free Software Foundation, Inc. + + GNU Mailutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GNU Mailutils is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ + +/* MH prompter - traditional tty/termios support */ + +#include <mh.h> +#include "prompter.h" +#include "muaux.h" +#if HAVE_TERMIOS_H +# include <termios.h> +#endif + +mu_stream_t strin; +#if HAVE_TCGETATTR +struct termios tios; +#endif + +static int +decode_key (const char *keyseq) +{ + if (keyseq[0] == '^' && keyseq[1]) + { + if (keyseq[2]) + { + mu_error (_("invalid keysequence (%s near %d)"), + keyseq, 2); + exit (1); + } + return keyseq[1] + 0100; + } + else if (keyseq[0] == '\\') + { + int i; + int c = 0; + for (i = 1; i <= 3; i++) + { + int n; + switch (keyseq[i]) + { + case '0': + n = 0; + break; + case '1': + n = 1; + break; + case '2': + n = 2; + break; + case '3': + n = 3; + break; + case '4': + n = 4; + break; + case '5': + n = 5; + break; + case '6': + n = 6; + break; + case '7': + n = 7; + break; + default: + mu_error (_("invalid keysequence (%s near %d)"), + keyseq, i); + exit (1); + } + c = (c << 3) + n; + } + if (keyseq[i]) + { + mu_error (_("invalid keysequence (%s near %d)"), + keyseq, i); + exit (1); + } + return c; + } + else if (keyseq[1]) + { + mu_error (_("invalid keysequence (%s near %d)"), + keyseq, 2); + exit (1); + } + + return keyseq[0]; +} + +static RETSIGTYPE +sighan (int signo) +{ + prompter_done (); + exit (0); +} + +void +prompter_init () +{ + int rc; + if ((rc = mu_stdio_stream_create (&strin, MU_STDIN_FD, MU_STREAM_READ))) + { + mu_error (_("cannot open stdout: %s"), mu_strerror (rc)); + exit (1); + } +#if HAVE_TCGETATTR + rc = tcgetattr (MU_STDOUT_FD, &tios); + if (rc) + { + mu_error (_("tcgetattr failed: %s"), mu_strerror (rc)); + exit (1); + } + else + { + static int sigtab[] = { SIGPIPE, SIGABRT, SIGINT, SIGQUIT, SIGTERM }; + mu_set_signals (sighan, sigtab, MU_ARRAY_SIZE (sigtab)); + } +#endif +} + +void +prompter_done () +{ +#if HAVE_TCGETATTR + int rc = tcsetattr (MU_STDOUT_FD, TCSANOW, &tios); + if (rc) + mu_error (_("tcsetattr failed: %s"), mu_strerror (rc)); +#endif +} + +void +prompter_set_erase (const char *keyseq) +{ +#if HAVE_TCGETATTR + int rc; + struct termios t = tios; + + t.c_lflag |= ICANON; + t.c_cc[VERASE] = decode_key (keyseq); + rc = tcsetattr (MU_STDOUT_FD, TCSANOW, &t); + if (rc) + mu_error (_("tcsetattr failed: %s"), mu_strerror (rc)); +#endif +} + +void +prompter_set_kill (const char *keyseq) +{ +#if HAVE_TCGETATTR + int rc; + struct termios t = tios; + + t.c_lflag |= ICANON; + t.c_cc[VKILL] = decode_key (keyseq); + rc = tcsetattr (MU_STDOUT_FD, TCSANOW, &t); + if (rc) + mu_error (_("tcsetattr failed: %s"), mu_strerror (rc)); +#endif +} + +char * +prompter_get_value (const char *name) +{ + size_t size = 0, n; + char *buf = NULL; + + mu_stream_printf (strout, "%s: ", name); + mu_stream_flush (strout); + if (mu_stream_getline (strin, &buf, &size, &n) || n == 0) + return NULL; + mu_rtrim_cset (buf, "\n"); + return buf; +} + +char * +prompter_get_line () +{ + size_t size = 0, n; + char *buf = NULL; + + if (mu_stream_getline (strin, &buf, &size, &n) || n == 0) + return NULL; + mu_rtrim_cset (buf, "\n"); + return doteof_filter (buf); +} diff --git a/mh/prompter.c b/mh/prompter.c new file mode 100644 index 0000000..1131c4e --- /dev/null +++ b/mh/prompter.c @@ -0,0 +1,313 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2010 Free Software Foundation, Inc. + + GNU Mailutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GNU Mailutils is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ + +/* MH prompter command */ + +#include <mh.h> +#include "prompter.h" + +static char doc[] = N_("GNU MH prompter")"\v" +N_("Use -help to obtain the list of traditional MH options."); +static char args_doc[] = N_("FILE"); + +enum { + ARG_ERASE=256, + ARG_KILL, + ARG_PREPEND, + ARG_NOPREPEND, + ARG_RAPID, + ARG_NORAPID, + ARG_DOTEOF, + ARG_NODOTEOF +}; + +static struct argp_option options[] = { + { "erase", ARG_ERASE, N_("CHAR"), 0, + N_("set erase character") }, + { "kill", ARG_KILL, N_("CHAR"), 0, + N_("set kill character") }, + { "prepend", ARG_PREPEND, N_("BOOL"), 0, + N_("prepend user input to the message body") }, + { "noprepend", ARG_NOPREPEND, NULL, OPTION_HIDDEN, + NULL }, + { "rapid", ARG_RAPID, N_("BOOL"), 0, + N_("do not display message body") }, + { "norapid", ARG_NORAPID, NULL, OPTION_HIDDEN, + NULL }, + { "doteof", ARG_DOTEOF, N_("BOOL"), 0, + N_("a period on a line marks end-of-file") }, + { "nodoteof", ARG_NODOTEOF, NULL, OPTION_HIDDEN, + NULL }, + { NULL } +}; + +struct mh_option mh_option[] = { + { "erase", MH_OPT_ARG, "chr" }, + { "kill", MH_OPT_ARG, "chr" }, + { "prepend", MH_OPT_BOOL }, + { "rapid", MH_OPT_BOOL }, + { "doteof", MH_OPT_BOOL }, + { NULL } +}; + +char *erase_seq; +char *kill_seq; +int prepend_option; +int rapid_option; +int doteof_option; + +static error_t +opt_handler (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case ARG_ERASE: + erase_seq = arg; + break; + + case ARG_KILL: + kill_seq = arg; + break; + + case ARG_PREPEND: + prepend_option = is_true (arg); + break; + + case ARG_NOPREPEND: + prepend_option = 0; + break; + + case ARG_RAPID: + rapid_option = is_true (arg); + break; + + case ARG_NORAPID: + rapid_option = 0; + break; + + case ARG_DOTEOF: + doteof_option = is_true (arg); + break; + + case ARG_NODOTEOF: + doteof_option = 0; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static int +is_empty_string (const char *str) +{ + if (!str) + return 1; + return mu_str_skip_class (str, MU_CTYPE_BLANK)[0] == 0; +} + +char * +doteof_filter (char *val) +{ + if (!val) + return NULL; + if (doteof_option && val[0] == '.') + { + if (val[1] == 0) + { + free (val); + return NULL; + } + memmove (val, val + 1, strlen (val + 1) + 1); + } + return val; +} + +mu_stream_t strout; + +int +main (int argc, char **argv) +{ + int index; + int rc; + mu_stream_t in, tmp; + mu_message_t msg; + mu_header_t hdr; + mu_iterator_t itr; + const char *file; + char *newval; + mu_off_t size; + mu_body_t body; + mu_stream_t bstr; + + MU_APP_INIT_NLS (); + + mh_argp_init (); + mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc, + opt_handler, NULL, &index); + + if (index == argc) + { + mu_error (_("file name not given")); + exit (1); + } + file = argv[index]; + + prompter_init (); + if (erase_seq) + prompter_set_erase (erase_seq); + if (kill_seq) + prompter_set_erase (kill_seq); + + if ((rc = mu_stdio_stream_create (&strout, MU_STDOUT_FD, MU_STREAM_WRITE))) + { + mu_error (_("cannot open stdout: %s"), mu_strerror (rc)); + return 1; + } + + if ((rc = mu_file_stream_create (&in, file, MU_STREAM_RDWR))) + { + mu_error (_("cannot open input file `%s': %s"), + file, mu_strerror (rc)); + return 1; + } + rc = mu_stream_to_message (in, &msg); + if (rc) + { + mu_error (_("input stream %s is not a message (%s)"), + file, mu_strerror (rc)); + return 1; + } + + if ((rc = mu_temp_file_stream_create (&tmp, NULL))) + { + mu_error (_("Cannot open temporary file: %s"), + mu_strerror (rc)); + return 1; + } + + /* Copy headers */ + mu_message_get_header (msg, &hdr); + mu_header_get_iterator (hdr, &itr); + for (mu_iterator_first (itr); !mu_iterator_is_done (itr); + mu_iterator_next (itr)) + { + const char *name, *val; + + mu_iterator_current_kv (itr, (const void **)&name, (void**)&val); + if (!is_empty_string (val)) + { + mu_stream_printf (tmp, "%s: %s\n", name, val); + mu_stream_printf (strout, "%s: %s\n", name, val); + } + else + { + int cont = 0; + mu_opool_t opool; + const char *prompt = name; + + mu_opool_create (&opool, 1); + do + { + size_t len; + char *p; + p = prompter_get_value (prompt); + if (!p) + return 1; + prompt = NULL; + if (cont) + { + mu_opool_append_char (opool, '\n'); + if (!mu_isspace (p[0])) + mu_opool_append_char (opool, '\t'); + } + len = strlen (p); + if (len > 0 && p[len-1] == '\\') + { + len--; + cont = 1; + } + else + cont = 0; + mu_opool_append (opool, p, len); + free (p); + } + while (cont); + + newval = mu_opool_finish (opool, NULL); + if (!is_empty_string (newval)) + mu_stream_printf (tmp, "%s: %s\n", name, newval); + mu_opool_destroy (&opool); + } + } + mu_stream_printf (strout, "--------\n"); + mu_stream_write (tmp, "\n", 1, NULL); + + /* Copy body */ + + if (prepend_option) + { + mu_stream_printf (strout, "\n--------%s\n\n", _("Enter initial text")); + while (newval = prompter_get_line ()) + { + mu_stream_write (tmp, newval, strlen (newval), NULL); + free (newval); + mu_stream_write (tmp, "\n", 1, NULL); + } + } + + mu_message_get_body (msg, &body); + mu_body_get_streamref (body, &bstr); + + if (!prepend_option && !rapid_option) + { + mu_stream_copy (strout, bstr, 0, NULL); + mu_stream_seek (bstr, 0, MU_SEEK_SET, NULL); + } + + mu_stream_copy (tmp, bstr, 0, NULL); + mu_stream_unref (bstr); + + if (!prepend_option && !rapid_option) + { + printf ("\n--------%s\n\n", _("Enter additional text")); + while (newval = prompter_get_line ()) + { + mu_stream_write (tmp, newval, strlen (newval), NULL); + free (newval); + mu_stream_write (tmp, "\n", 1, NULL); + } + } + + /* Destroy the message */ + mu_message_destroy (&msg, mu_message_get_owner (msg)); + + /* Rewind the streams and copy data back to in. */ + mu_stream_seek (in, 0, MU_SEEK_SET, NULL); + mu_stream_seek (tmp, 0, MU_SEEK_SET, NULL); + mu_stream_copy (in, tmp, 0, &size); + mu_stream_truncate (in, size); + + mu_stream_destroy (&in); + mu_stream_destroy (&tmp); + mu_stream_destroy (&strout); + + prompter_done (); + + return 0; +} + diff --git a/mail/list.c b/mh/prompter.h similarity index 67% copy from mail/list.c copy to mh/prompter.h index a6eb18f..cdaf838 100644 --- a/mail/list.c +++ b/mh/prompter.h @@ -1,6 +1,5 @@ /* GNU Mailutils -- a suite of utilities for electronic mail - Copyright (C) 1999, 2001, 2005, 2007, 2010 Free Software Foundation, - Inc. + Copyright (C) 2010 Free Software Foundation, Inc. GNU Mailutils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,16 +14,14 @@ You should have received a copy of the GNU General Public License along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ -#include "mail.h" +void prompter_init (void); +void prompter_done (void); +void prompter_set_erase (const char *keyseq); +void prompter_set_kill (const char *keyseq); +char *prompter_get_value (const char *name); +char *prompter_get_line (void); +char *doteof_filter (char *val); + +extern mu_stream_t strout; -/* - * l[ist] - * * - */ -int -mail_list (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) -{ - mail_command_list (); - return 0; -} diff --git a/po/POTFILES.in b/po/POTFILES.in index 8d2e5e6..001f754 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -179,6 +179,8 @@ mh/mhl.c mh/mhn.c mh/mhpath.c mh/pick.c +mh/prompter.c +mh/prompter-tty.c mh/refile.c mh/repl.c mh/rmf.c hooks/post-receive -- GNU Mailutils _______________________________________________ Commit-mailutils mailing list Commit-mailutils@gnu.org http://lists.gnu.org/mailman/listinfo/commit-mailutils