From 18e23d6e98bc5942269e385dbb9ea9f0886909ef Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Sat, 2 Feb 2019 09:04:42 +0200 Subject: Rewrite the mailcap support * configure.ac: Build libmailutils/mailcap/Makefile * include/mailutils/mailcap.h: Rewrite * include/mailutils/sys/Makefile.am: Add mailcap.h * include/mailutils/sys/mailcap.h: New file. * include/mailutils/util.h: Add missing include. * lib/mailcap.c: Rewrite using new API. * libmailutils/Makefile.am: Build in mailcap * libmailutils/base/Makefile.am: Remove mailcap.c * libmailutils/base/mailcap.c: Remove. * libmailutils/mailcap/Makefile.am: New file. * libmailutils/mailcap/ctmatch.c: New file. * libmailutils/mailcap/deferrclos.c: New file. * libmailutils/mailcap/mcp_creat.c: New file. * libmailutils/mailcap/mcp_destr.c: New file. * libmailutils/mailcap/mcp_err.c: New file. * libmailutils/mailcap/mcp_flags.c: New file. * libmailutils/mailcap/mcp_get.c: New file. * libmailutils/mailcap/mcp_sel.c: New file. * libmailutils/mailcap/mcp_count.c: New file. * libmailutils/mailcap/mcp_find.c: New file. * libmailutils/mailcap/ent_cmd.c: New file. * libmailutils/mailcap/ent_creat.c: New file. * libmailutils/mailcap/ent_destr.c: New file. * libmailutils/mailcap/ent_locus.c: New file. * libmailutils/mailcap/ent_type.c: New file. * libmailutils/mailcap/fieldacc.c: New file. * libmailutils/mailcap/fields.c: New file. * libmailutils/mailcap/finder.c: New file. * libmailutils/mailcap/parse.c: New file. * libmailutils/mailcap/parsefile.c: New file. * libmailutils/tests/mailcap.c: Rewrite using new API. Improve cli * libmailutils/tests/mcf.c: New file. * libmailutils/tests/ctm.c: New file. * libmailutils/tests/ctm.at: New file. * libmu_cpp/mailcap.cc: Rewrite using new API. * python/2/libmu_py/mailcap.c: Rewrite using new API. * python/3/libmu_py/mailcap.c: Rewrite using new API. * examples/python/2/mailcap.py: Minor change. This example is broken with the new API. Should be fixed. * include/mailutils/cpp/mailcap.h: Update * include/mailutils/cpp/pop3.h: Update --- configure.ac | 1 + examples/python/2/mailcap.py | 3 +- include/mailutils/cpp/mailcap.h | 12 +- include/mailutils/cpp/pop3.h | 2 +- include/mailutils/mailcap.h | 202 ++++++----- include/mailutils/sys/Makefile.am | 1 + include/mailutils/sys/mailcap.h | 58 +++ include/mailutils/util.h | 1 + lib/mailcap.c | 426 ++++++++-------------- libmailutils/Makefile.am | 32 +- libmailutils/base/Makefile.am | 1 - libmailutils/base/mailcap.c | 738 -------------------------------------- libmailutils/mailcap/Makefile.am | 42 +++ libmailutils/mailcap/ctmatch.c | 166 +++++++++ libmailutils/mailcap/deferrclos.c | 32 ++ libmailutils/mailcap/ent_cmd.c | 66 ++++ libmailutils/mailcap/ent_creat.c | 51 +++ libmailutils/mailcap/ent_destr.c | 47 +++ libmailutils/mailcap/ent_locus.c | 33 ++ libmailutils/mailcap/ent_type.c | 66 ++++ libmailutils/mailcap/fieldacc.c | 108 ++++++ libmailutils/mailcap/fields.c | 163 +++++++++ libmailutils/mailcap/finder.c | 131 +++++++ libmailutils/mailcap/mcp_count.c | 51 +++ libmailutils/mailcap/mcp_creat.c | 56 +++ libmailutils/mailcap/mcp_destr.c | 36 ++ libmailutils/mailcap/mcp_err.c | 44 +++ libmailutils/mailcap/mcp_find.c | 32 ++ libmailutils/mailcap/mcp_flags.c | 39 ++ libmailutils/mailcap/mcp_get.c | 31 ++ libmailutils/mailcap/mcp_sel.c | 44 +++ libmailutils/mailcap/parse.c | 239 ++++++++++++ libmailutils/mailcap/parsefile.c | 41 +++ libmailutils/tests/.gitignore | 2 + libmailutils/tests/Makefile.am | 3 + libmailutils/tests/ctm.at | 95 +++++ libmailutils/tests/ctm.c | 106 ++++++ libmailutils/tests/mailcap.at | 262 +++++++++++++- libmailutils/tests/mailcap.c | 221 +++++++++--- libmailutils/tests/mcf.c | 148 ++++++++ libmailutils/tests/testsuite.at | 23 +- libmu_cpp/mailcap.cc | 38 +- python/2/libmu_py/mailcap.c | 61 +++- python/3/libmu_py/mailcap.c | 63 ++-- 44 files changed, 2789 insertions(+), 1228 deletions(-) create mode 100644 include/mailutils/sys/mailcap.h delete mode 100644 libmailutils/base/mailcap.c create mode 100644 libmailutils/mailcap/Makefile.am create mode 100644 libmailutils/mailcap/ctmatch.c create mode 100644 libmailutils/mailcap/deferrclos.c create mode 100644 libmailutils/mailcap/ent_cmd.c create mode 100644 libmailutils/mailcap/ent_creat.c create mode 100644 libmailutils/mailcap/ent_destr.c create mode 100644 libmailutils/mailcap/ent_locus.c create mode 100644 libmailutils/mailcap/ent_type.c create mode 100644 libmailutils/mailcap/fieldacc.c create mode 100644 libmailutils/mailcap/fields.c create mode 100644 libmailutils/mailcap/finder.c create mode 100644 libmailutils/mailcap/mcp_count.c create mode 100644 libmailutils/mailcap/mcp_creat.c create mode 100644 libmailutils/mailcap/mcp_destr.c create mode 100644 libmailutils/mailcap/mcp_err.c create mode 100644 libmailutils/mailcap/mcp_find.c create mode 100644 libmailutils/mailcap/mcp_flags.c create mode 100644 libmailutils/mailcap/mcp_get.c create mode 100644 libmailutils/mailcap/mcp_sel.c create mode 100644 libmailutils/mailcap/parse.c create mode 100644 libmailutils/mailcap/parsefile.c create mode 100644 libmailutils/tests/ctm.at create mode 100644 libmailutils/tests/ctm.c create mode 100644 libmailutils/tests/mcf.c diff --git a/configure.ac b/configure.ac index 4efd44198..be5ee11d6 100644 --- a/configure.ac +++ b/configure.ac @@ -1550,6 +1550,7 @@ AC_CONFIG_FILES([ libmailutils/list/Makefile libmailutils/locus/Makefile libmailutils/mailbox/Makefile + libmailutils/mailcap/Makefile libmailutils/mailer/Makefile libmailutils/mime/Makefile libmailutils/msgset/Makefile diff --git a/examples/python/2/mailcap.py b/examples/python/2/mailcap.py index 24e86e880..d88bf9073 100644 --- a/examples/python/2/mailcap.py +++ b/examples/python/2/mailcap.py @@ -15,8 +15,9 @@ # along with GNU Mailutils. If not, see . from mailutils import stream, mailcap +from os import environ -stm = stream.FileStream ("/etc/mailcap") +stm = stream.FileStream (environ['MAILCAP'] if 'MAILCAP' in environ else "/etc/mailcap") mc = mailcap.Mailcap (stm) for i, entry in enumerate (mc): diff --git a/include/mailutils/cpp/mailcap.h b/include/mailutils/cpp/mailcap.h index 2b259238f..d5847794c 100644 --- a/include/mailutils/cpp/mailcap.h +++ b/include/mailutils/cpp/mailcap.h @@ -40,10 +40,10 @@ class MailcapEntry size_t fields_count (); std::string get_typefield (); std::string get_viewcommand (); - std::string get_field (size_t i); + std::string get_field (const std::string& name); - inline std::string operator [] (size_t i) { - return this->get_field (i); + inline std::string operator [] (const std::string& name) { + return this->get_field (name); } }; @@ -58,10 +58,10 @@ class Mailcap ~Mailcap (); size_t entries_count (); - MailcapEntry& get_entry (size_t i); + MailcapEntry& find_entry (const std::string& name); - inline MailcapEntry& operator [] (size_t i) { - return this->get_entry (i); + inline MailcapEntry& operator [] (const std::string& name) { + return this->find_entry (name); } }; diff --git a/include/mailutils/cpp/pop3.h b/include/mailutils/cpp/pop3.h index abf8d35aa..192ec6f24 100644 --- a/include/mailutils/cpp/pop3.h +++ b/include/mailutils/cpp/pop3.h @@ -56,7 +56,7 @@ class Pop3 void quit (); Stream& retr (unsigned int msgno); void rset (); - void stat (unsigned int* count, mu_off_t* octets); + void stat (size_t* count, mu_off_t* octets); Stream& top (unsigned int msgno, unsigned int lines); std::string uidl (unsigned int msgno); Iterator& uidl_all (); diff --git a/include/mailutils/mailcap.h b/include/mailutils/mailcap.h index 85abf5715..8cb7372d8 100644 --- a/include/mailutils/mailcap.h +++ b/include/mailutils/mailcap.h @@ -20,101 +20,133 @@ #include #include +#include +#include /* See RFC1524 (A User Agent Configuration Mechanism). */ #ifdef __cplusplus extern "C" { #endif +#if 0 +} +#endif -/* Create a mailcap from stream. */ -int mu_mailcap_create (mu_mailcap_t * mailcap, mu_stream_t stream); - -/* Destroy mailcap object. */ -void mu_mailcap_destroy (mu_mailcap_t * mailcap); - -/* Return the number of entries in the mailcap file. */ -int mu_mailcap_entries_count (mu_mailcap_t mailcap, size_t *pno); - -/* Return the mailcap record number, no, of the mailcap file . */ -int mu_mailcap_get_entry (mu_mailcap_t mailcap, size_t no, +struct mu_mailcap_selector_closure +{ + int (*selector) (mu_mailcap_entry_t, void *); + void *data; + void (*data_free) (void *); +}; + +struct mu_mailcap_error_closure +{ + void (*error) (void *, struct mu_locus_range const *, char const *); + void *data; + void (*data_free) (void *); +}; + +extern struct mu_mailcap_error_closure mu_mailcap_default_error_closure; + +#define MU_MAILCAP_FLAG_DEFAULT 0 +#define MU_MAILCAP_FLAG_LOCUS 0x1 + +int mu_mailcap_create (mu_mailcap_t *pmailcap); +void mu_mailcap_destroy (mu_mailcap_t *pmailcap); + +int mu_mailcap_set_flags (mu_mailcap_t mailcap, int flags); +int mu_mailcap_get_flags (mu_mailcap_t mailcap, int *flags); + +int mu_mailcap_set_error (mu_mailcap_t mailcap, + struct mu_mailcap_error_closure const *err); +int mu_mailcap_get_error (mu_mailcap_t mailcap, + struct mu_mailcap_error_closure *err); +int mu_mailcap_set_selector (mu_mailcap_t mailcap, + struct mu_mailcap_selector_closure const *sel); +int mu_mailcap_get_selector (mu_mailcap_t mailcap, + struct mu_mailcap_selector_closure *sel); + +int mu_mailcap_get_count (mu_mailcap_t mailcap, size_t *pcount); +int mu_mailcap_get_iterator (mu_mailcap_t mailcap, mu_iterator_t *pitr); +int mu_mailcap_foreach (mu_mailcap_t mailcap, + int (*action) (mu_mailcap_entry_t, void *), + void *data); +int mu_mailcap_get_entry (mu_mailcap_t mailcap, size_t n, mu_mailcap_entry_t *entry); - -/* Return the number of fields in a mailcap entry */ -int mu_mailcap_entry_fields_count (mu_mailcap_entry_t entry, - size_t *pcount); - -/* Save in buffer[] the content-type of the record. */ -int mu_mailcap_entry_get_typefield (mu_mailcap_entry_t entry, - char *buffer, size_t buflen, - size_t *pn); - -/* Save in buffer[] the view command of the record. */ -int mu_mailcap_entry_get_viewcommand (mu_mailcap_entry_t entry, - char *buffer, size_t buflen, - size_t *pn); - -/* Save in buffer[] the field number no the record . */ -int mu_mailcap_entry_get_field (mu_mailcap_entry_t entry, size_t no, - char *buffer, size_t buflen, size_t *pn); - -/* Save in buffer the value of a key: - * mu_mailcap_entry_get_value (entry, "compose", buffer, buflen, pn); - * i.e compose="lynx %s" --> "lynx %s" will be saved in the buffer without - * the quotes. */ -int mu_mailcap_entry_get_value (mu_mailcap_entry_t entry, const char *key, - char *buffer, size_t buflen, size_t *pn); - -/* Helper function saving in buffer, the argument of "compose" field. */ -int mu_mailcap_entry_get_compose (mu_mailcap_entry_t entry, char *buffer, - size_t buflen, size_t *pn); - -/* Helper function saving in buffer, the argument of "composetyped" field. */ -int mu_mailcap_entry_get_composetyped (mu_mailcap_entry_t entry, - char *buffer, size_t buflen, - size_t *pn); - -/* Helper function saving in buffer, the argument of "edit" field. */ -int mu_mailcap_entry_get_edit (mu_mailcap_entry_t entry, char *buffer, - size_t buflen, size_t *pn); - -/* Helper function saving in buffer, the argument of "textualnewlines" field. */ -int mu_mailcap_entry_get_textualnewlines (mu_mailcap_entry_t entry, - char *buffer, size_t buflen, - size_t *pn); - -/* Helper function saving in buffer, the argument of "test" field. */ -int mu_mailcap_entry_get_test (mu_mailcap_entry_t entry, - char *buffer, size_t buflen, size_t *pn); - -/* Helper function saving in buffer, the argument of "x11-bitmap" field. */ -int mu_mailcap_entry_get_x11bitmap (mu_mailcap_entry_t entry, - char *buffer, size_t buflen, size_t *pn); - -/* Helper function saving in buffer, the argument of "description" field. */ -int mu_mailcap_entry_get_description (mu_mailcap_entry_t entry, - char *buffer, size_t buflen, - size_t *pn); - -/* Helper function saving in buffer, the argument of "nametemplate" field. */ -int mu_mailcap_entry_get_nametemplate (mu_mailcap_entry_t entry, - char *buffer, size_t buflen, - size_t *pn); - -/* Helper function saving in buffer, the argument of "notes" field. */ -int mu_mailcap_entry_get_notes (mu_mailcap_entry_t entry, char *buffer, - size_t buflen, size_t *pn); - -/* Helper function. Returns *on != 0 if the flag "needsterminal" is in the - record. */ -int mu_mailcap_entry_needsterminal (mu_mailcap_entry_t entry, int *on); - -/* Helper function. Returns *on != 0 if the flag "copiousoutput" is in the - record. */ -int mu_mailcap_entry_copiousoutput (mu_mailcap_entry_t entry, int *on); +int mu_mailcap_find_entry (mu_mailcap_t mailcap, char const *type, + mu_mailcap_entry_t *entry); + +int mu_mailcap_parse (mu_mailcap_t mailcap, mu_stream_t input, + struct mu_locus_point const *pt); +int mu_mailcap_parse_file (mu_mailcap_t mailcap, char const *file_name); + +int mu_mailcap_entry_create (mu_mailcap_entry_t *ret_entry, + char *type, char *command); +void mu_mailcap_entry_destroy (mu_mailcap_entry_t *pent); +void mu_mailcap_entry_destroy_item (void *ptr); + +int mu_mailcap_entry_sget_type (mu_mailcap_entry_t ent, char const **ptype); +int mu_mailcap_entry_aget_type (mu_mailcap_entry_t ent, char **ptype); +int mu_mailcap_entry_get_type (mu_mailcap_entry_t ent, + char *buffer, size_t buflen, + size_t *pn); + +int mu_mailcap_entry_sget_command (mu_mailcap_entry_t ent, char const **pcommand); +int mu_mailcap_entry_aget_command (mu_mailcap_entry_t ent, char **pcommand); +int mu_mailcap_entry_get_command (mu_mailcap_entry_t ent, + char *buffer, size_t buflen, + size_t *pn); + +int mu_mailcap_entry_get_locus (mu_mailcap_entry_t ent, + struct mu_locus_range *loc); + +void mu_mailcap_entry_field_deallocate (void *ptr); +int mu_mailcap_entry_set_bool (mu_mailcap_entry_t ent, char const *name); +int mu_mailcap_entry_set_string (mu_mailcap_entry_t ent, char const *name, + char const *value); +int mu_mailcap_entry_field_unset (mu_mailcap_entry_t ent, char const *name); +int mu_mailcap_entry_fields_count (mu_mailcap_entry_t ent, size_t *pcount); +int mu_mailcap_entry_fields_foreach (mu_mailcap_entry_t ent, + int (*action) (char const *, char const *, void *), + void *data); +int mu_mailcap_entry_fields_get_iterator (mu_mailcap_entry_t ent, + mu_iterator_t *pitr); + +int mu_mailcap_entry_sget_field (mu_mailcap_entry_t ent, char const *name, + char const **pval); +int mu_mailcap_entry_aget_field (mu_mailcap_entry_t ent, char const *name, + char **pval); +int mu_mailcap_entry_get_field (mu_mailcap_entry_t ent, + char const *name, + char *buffer, size_t buflen, + size_t *pn); + +#define MU_MAILCAP_NEEDSTERMINAL "needsterminal" +#define MU_MAILCAP_COPIOUSOUTPUT "copiousoutput" +#define MU_MAILCAP_COMPOSE "compose" +#define MU_MAILCAP_COMPOSETYPED "composetyped" +#define MU_MAILCAP_PRINT "print" +#define MU_MAILCAP_EDIT "edit" +#define MU_MAILCAP_TEST "test" +#define MU_MAILCAP_X11_BITMAP "x11-bitmap" +#define MU_MAILCAP_TEXTUALNEWLINES "textualnewlines" +#define MU_MAILCAP_DESCRIPTION "description" + +int mu_mailcap_string_match (char const *pattern, int delim, char const *type); +int mu_mailcap_content_type_match (const char *pattern, int delim, + mu_content_type_t ct); + +typedef struct _mu_mailcap_finder *mu_mailcap_finder_t; + +int mu_mailcap_finder_create (mu_mailcap_finder_t *, int, + struct mu_mailcap_selector_closure *, + struct mu_mailcap_error_closure *, + char **file_names); +int mu_mailcap_finder_next_match (mu_mailcap_finder_t, mu_mailcap_entry_t *); +void mu_mailcap_finder_destroy (mu_mailcap_finder_t *); #ifdef __cplusplus } #endif - + #endif diff --git a/include/mailutils/sys/Makefile.am b/include/mailutils/sys/Makefile.am index 11cf643fc..08d87560b 100644 --- a/include/mailutils/sys/Makefile.am +++ b/include/mailutils/sys/Makefile.am @@ -36,6 +36,7 @@ sysinclude_HEADERS = \ list.h\ logstream.h\ mailbox.h\ + mailcap.h\ mailer.h\ mapfile_stream.h\ memory_stream.h\ diff --git a/include/mailutils/sys/mailcap.h b/include/mailutils/sys/mailcap.h new file mode 100644 index 000000000..bc8140f0c --- /dev/null +++ b/include/mailutils/sys/mailcap.h @@ -0,0 +1,58 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999-2019 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + . */ + +#ifndef _MAILUTILS_SYS_MAILCAP_H +# define _MAILUTILS_SYS_MAILCAP_H +# include +# include + +struct _mu_mailcap_entry +{ + char *type; + char *command; + mu_assoc_t fields; + struct mu_locus_range *lrp; +}; + +enum fld_type + { + fld_bool, + fld_string + }; + +struct mailcap_field +{ + enum fld_type type; + char *strval; +}; + +struct _mu_mailcap +{ + int flags; + mu_list_t elist; + struct mu_mailcap_selector_closure selector; + struct mu_mailcap_error_closure error; + struct mu_locus_range locus; +}; + +struct _mu_mailcap_finder +{ + struct _mu_mailcap *mcp; + mu_iterator_t itr; +}; + +#endif diff --git a/include/mailutils/util.h b/include/mailutils/util.h index ec902d280..26c9bb359 100644 --- a/include/mailutils/util.h +++ b/include/mailutils/util.h @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/lib/mailcap.c b/lib/mailcap.c index dd84e081e..ba819ae97 100644 --- a/lib/mailcap.c +++ b/lib/mailcap.c @@ -18,15 +18,7 @@ # include #endif #include -#include #include -#include - -/* FNM_CASEFOLD is a GNU extension. Provide a replacement for systems - lacking it. */ -#ifndef FNM_CASEFOLD -# define FNM_CASEFOLD 0 -#endif /* Default mailcap path, the $HOME/.mailcap: entry is prepended to it */ #define DEFAULT_MAILCAP \ @@ -41,15 +33,14 @@ struct mime_context { - mu_stream_t input; + mu_stream_t input; mu_header_t hdr; - char *content_type_buffer; - char *content_type; - mu_list_t values; + mu_content_type_t content_type; + char *temp_file; int unlink_temp_file; - mu_list_t no_ask_types; + char *no_ask_types; int dh; int flags; }; @@ -59,29 +50,22 @@ mime_context_fill (struct mime_context *ctx, const char *file, mu_stream_t input, mu_header_t hdr, const char *no_ask, int interactive, int dry_run, mu_debug_handle_t dh) { - struct mu_wordsplit ws; - size_t i; - + int rc; + char *buffer; + memset (ctx, 0, sizeof *ctx); ctx->input = input; ctx->hdr = hdr; - if (mu_header_aget_value (hdr, MU_HEADER_CONTENT_TYPE, - &ctx->content_type_buffer)) + + rc = mu_header_aget_value_unfold (hdr, MU_HEADER_CONTENT_TYPE, &buffer); + if (rc) + return 1; + rc = mu_content_type_parse (buffer, NULL, &ctx->content_type); + free (buffer); + if (rc) return 1; - ws.ws_delim = ";"; - if (mu_wordsplit (ctx->content_type_buffer, &ws, - MU_WRDSF_DELIM|MU_WRDSF_SQUEEZE_DELIMS|MU_WRDSF_WS| - MU_WRDSF_NOVAR|MU_WRDSF_NOCMD)) - { - mu_error (_("cannot split line `%s': %s"), - ctx->content_type_buffer, - mu_wordsplit_strerror (&ws)); - return 1; - } - ctx->content_type = ws.ws_wordv[0]; - ws.ws_wordv[0] = NULL; - ctx->temp_file = file ? mu_strdup (file) : NULL; + ctx->temp_file = file ? mu_strdup (file) : NULL; ctx->unlink_temp_file = 0; if (interactive) @@ -89,56 +73,20 @@ mime_context_fill (struct mime_context *ctx, const char *file, if (dry_run) ctx->flags |= FLAGS_DRY_RUN; ctx->dh = dh; - - mu_list_create (&ctx->values); - for (i = 1; i < ws.ws_wordc; i++) - { - mu_list_append (ctx->values, ws.ws_wordv[i]); - ws.ws_wordv[i] = NULL; - } - mu_wordsplit_free (&ws); - - if (no_ask) - { - mu_list_create (&ctx->no_ask_types); - mu_list_set_destroy_item (ctx->no_ask_types, mu_list_free_item); - if (mu_string_split (no_ask, ",", ctx->no_ask_types)) - return 1; - } + ctx->no_ask_types = no_ask ? mu_strdup (no_ask) : NULL; + return 0; } static void mime_context_release (struct mime_context *ctx) { - free (ctx->content_type_buffer); + mu_content_type_destroy (&ctx->content_type); if (ctx->unlink_temp_file) unlink (ctx->temp_file); free (ctx->temp_file); - mu_list_destroy (&ctx->values); - mu_list_destroy (&ctx->no_ask_types); -} - -static int -mime_context_do_not_ask (struct mime_context *ctx) -{ - int rc = 0; - - if (ctx->no_ask_types) - { - mu_iterator_t itr; - mu_list_get_iterator (ctx->no_ask_types, &itr); - for (mu_iterator_first (itr); !rc && !mu_iterator_is_done (itr); - mu_iterator_next (itr)) - { - char *p; - mu_iterator_current (itr, (void**)&p); - rc = fnmatch (p, ctx->content_type, FNM_CASEFOLD) == 0; - } - mu_iterator_destroy (&itr); - } - return rc; + free (ctx->no_ask_types); } static int @@ -153,51 +101,12 @@ interactive_p (struct mime_context *ctx) return ctx->flags & FLAGS_INTERACTIVE; } -static void -mime_context_get_content_type (struct mime_context *ctx, char **ptr) -{ - *ptr = ctx->content_type; -} - static void mime_context_get_input (struct mime_context *ctx, mu_stream_t *pinput) { *pinput = ctx->input; } -static int -mime_context_get_content_type_value (struct mime_context *ctx, - char *name, size_t len, - char **ptr, size_t *plen) -{ - mu_iterator_t itr = NULL; - int rc = 1; - - mu_list_get_iterator (ctx->values, &itr); - for (mu_iterator_first (itr); - !mu_iterator_is_done (itr); mu_iterator_next (itr)) - { - char *item, *p; - - mu_iterator_current (itr, (void**) &item); - p = strchr (item, '='); - if (p - item == len && strncasecmp (item, name, len) == 0) - { - rc = 0; - *ptr = ++p; - *plen = strlen (*ptr); - if (**ptr == '"') - { - ++*ptr; - *plen -= 2; - } - break; - } - } - mu_iterator_destroy (&itr); - return rc; -} - /* FIXME: Rewrite via mu_stream_copy */ static void mime_context_write_input (struct mime_context *ctx, int fd) @@ -206,7 +115,7 @@ mime_context_write_input (struct mime_context *ctx, int fd) char buf[512]; size_t n; int status; - + mime_context_get_input (ctx, &input); status = mu_stream_seek (input, 0, SEEK_SET, NULL); if (status && status != ENOSYS) @@ -239,12 +148,13 @@ mime_context_get_temp_file (struct mime_context *ctx, char **ptr) static mu_opool_t expand_pool; static int -expand_string (struct mime_context *ct, char **pstr) +expand_string (struct mime_context *ct, char const *input, char **pstr) { - char *p, *s; + char const *p; + char *s; int rc = 0; - - for (p = *pstr; *p; ) + + for (p = input; *p; ) { switch (p[0]) { @@ -257,26 +167,34 @@ expand_string (struct mime_context *ct, char **pstr) rc = 1; p += 2; break; - + case 't': - mime_context_get_content_type (ct, &s); - mu_opool_appendz (expand_pool, s); + mu_opool_appendz (expand_pool, ct->content_type->type); + mu_opool_append_char (expand_pool, '/'); + mu_opool_appendz (expand_pool, ct->content_type->subtype); p += 2; break; - + case '{': { size_t n; - char *q; - + char const *q; + char *namebuf; + struct mu_mime_param *param; + p += 2; q = p; while (*p && *p != '}') p++; - if (mime_context_get_content_type_value (ct, - q, p-q, - &s, &n) == 0) - mu_opool_append (expand_pool, s, n); + n = p - q; + namebuf = mu_alloc (n + 1); + memcpy (namebuf, q, n); + namebuf[n] = 0; + param = mu_assoc_get (ct->content_type->param, namebuf); + if (param) + /* FIXME: cset? */ + mu_opool_appendz (expand_pool, param->value); + free (namebuf); if (*p) p++; break; @@ -286,7 +204,7 @@ expand_string (struct mime_context *ct, char **pstr) case 'n': p++; break; - + default: mu_opool_append_char (expand_pool, p[0]); } @@ -333,12 +251,12 @@ confirm_action (struct mime_context *ctx, const char *str) { char repl[128], *p; int len; - char *type; - mime_context_get_content_type (ctx, &type); - if (!interactive_p (ctx) || mime_context_do_not_ask (ctx)) + if (!interactive_p (ctx) + || mu_mailcap_content_type_match (ctx->no_ask_types, ',', + ctx->content_type) == 0) return 1; - + printf (_("Run `%s'?"), str); fflush (stdout); @@ -348,40 +266,44 @@ confirm_action (struct mime_context *ctx, const char *str) len = strlen (p); if (len > 0 && p[len-1] == '\n') p[len--] = 0; - + return mu_true_answer_p (p); } +struct list_closure +{ + unsigned long n; +}; + +static int +list_field (char const *name, char const *value, void *data) +{ + struct list_closure *fc = data; + printf ("\tfields[%lu]: ", fc->n++); + if (value) + printf ("%s=%s", name, value); + else + printf ("%s", name); + printf ("\n"); + return 0; +} + static void dump_mailcap_entry (mu_mailcap_entry_t entry) { - char buffer[256]; - size_t i, count; - - mu_mailcap_entry_get_typefield (entry, buffer, - sizeof (buffer), NULL); - printf ("typefield: %s\n", buffer); - + char const *value; + struct list_closure lc; + + mu_mailcap_entry_sget_type (entry, &value); + printf ("typefield: %s\n", value); + /* view-command. */ - mu_mailcap_entry_get_viewcommand (entry, buffer, - sizeof (buffer), NULL); - printf ("view-command: %s\n", buffer); + mu_mailcap_entry_sget_command (entry, &value); + printf ("view-command: %s\n", value); /* fields. */ - mu_mailcap_entry_fields_count (entry, &count); - for (i = 1; i <= count; i++) - { - int status = mu_mailcap_entry_get_field (entry, i, buffer, - sizeof (buffer), NULL); - if (status) - { - mu_error (_("cannot retrieve field %lu: %s"), - (unsigned long) i, - mu_strerror (status)); - break; - } - printf ("fields[%u]: %s\n", (unsigned) i, buffer); - } + lc.n = 1; + mu_mailcap_entry_fields_foreach (entry, list_field, &lc); printf ("\n"); } @@ -403,7 +325,7 @@ create_filter (char *cmd, int outfd, int *infd) if (infd) pipe (lp); - + pid = fork (); if (pid == -1) { @@ -421,7 +343,7 @@ create_filter (char *cmd, int outfd, int *infd) /* Child process */ struct mu_wordsplit ws; char **argv; - + if (need_shell_p (cmd)) { char *x_argv[4]; @@ -440,7 +362,7 @@ create_filter (char *cmd, int outfd, int *infd) _exit (127); } argv = ws.ws_wordv; - } + } /* Create input channel: */ if (infd) { @@ -448,11 +370,11 @@ create_filter (char *cmd, int outfd, int *infd) dup2 (lp[0], 0); close (lp[1]); } - + /* Create output channel */ if (outfd != -1 && outfd != 1) dup2 (outfd, 1); - + execvp (argv[0], argv); mu_error (_("cannot execute `%s': %s"), cmd, mu_strerror (errno)); _exit (127); @@ -470,9 +392,9 @@ create_filter (char *cmd, int outfd, int *infd) static void print_exit_status (int status) { - if (WIFEXITED (status)) + if (WIFEXITED (status)) printf (_("Command exited with status %d\n"), WEXITSTATUS(status)); - else if (WIFSIGNALED (status)) + else if (WIFSIGNALED (status)) printf(_("Command terminated on signal %d\n"), WTERMSIG(status)); else printf (_("Command terminated\n")); @@ -498,29 +420,17 @@ get_pager () static int run_test (mu_mailcap_entry_t entry, struct mime_context *ctx) { - size_t size; int status = 0; - - if (mu_mailcap_entry_get_test (entry, NULL, 0, &size) == 0) + char const *value; + + if (mu_mailcap_entry_sget_field (entry, MU_MAILCAP_TEST, &value) == 0) { - struct mu_wordsplit ws; char *str; - - mu_opool_alloc (expand_pool, size + 1); - str = mu_opool_finish (expand_pool, NULL); - mu_mailcap_entry_get_test (entry, str, size + 1, NULL); - - expand_string (ctx, &str); - if (mu_wordsplit (str, &ws, MU_WRDSF_DEFFLAGS)) - { - mu_error (_("%s failed: %s"), "mu_wordsplit", - mu_wordsplit_strerror (&ws)); - return 1; - } - - if (mu_spawnvp (ws.ws_wordv[0], ws.ws_wordv, &status)) + char *argv[] = { "/bin/sh", "-c", NULL, NULL }; + expand_string (ctx, value, &str); + argv[2] = str; + if (mu_spawnvp (argv[0], argv, &status)) status = 1; - mu_wordsplit_free (&ws); } return status; } @@ -528,59 +438,52 @@ run_test (mu_mailcap_entry_t entry, struct mime_context *ctx) static int run_mailcap (mu_mailcap_entry_t entry, struct mime_context *ctx) { - char *view_command; - size_t size; - int flag; - int status; - int fd; - int *pfd = NULL; - int outfd = -1; + char const *view_command; + char *command; + int status; + int fd; + int *pfd = NULL; + int outfd = -1; pid_t pid; - - if (mu_debug_level_p (ctx->dh, MU_DEBUG_TRACE3)) + struct mu_locus_range lr = MU_LOCUS_RANGE_INITIALIZER; + + if (mu_mailcap_entry_get_locus (entry, &lr) == 0) + { + mu_stream_lprintf (mu_strout, &lr, "trying entry\n"); + mu_locus_range_deinit (&lr); + } + if (mu_debug_level_p (ctx->dh, MU_DEBUG_TRACE2)) dump_mailcap_entry (entry); if (run_test (entry, ctx)) return -1; if (interactive_p (ctx)) - { - if (mu_mailcap_entry_get_viewcommand (entry, NULL, 0, &size)) - return 1; - size++; - mu_opool_alloc (expand_pool, size); - view_command = mu_opool_finish (expand_pool, NULL); - mu_mailcap_entry_get_viewcommand (entry, view_command, size, NULL); - } + status = mu_mailcap_entry_sget_command (entry, &view_command); else - { - if (mu_mailcap_entry_get_value (entry, "print", NULL, 0, &size)) - return 1; - size++; - mu_opool_alloc (expand_pool, size); - view_command = mu_opool_finish (expand_pool, NULL); - mu_mailcap_entry_get_value (entry, "print", view_command, size, NULL); - } + status = mu_mailcap_entry_sget_field (entry, MU_MAILCAP_PRINT, &view_command); + + if (status) + return 1; /* NOTE: We don't create temporary file for %s, we just use mimeview_file instead */ - if (expand_string (ctx, &view_command)) + if (expand_string (ctx, view_command, &command)) pfd = NULL; else pfd = &fd; - mu_debug (ctx->dh, MU_DEBUG_TRACE0, (_("executing %s...\n"), view_command)); + mu_debug (ctx->dh, MU_DEBUG_TRACE0, (_("executing %s...\n"), command)); - if (!confirm_action (ctx, view_command)) + if (!confirm_action (ctx, command)) return 1; if (dry_run_p (ctx)) return 0; - - flag = 0; + if (interactive_p (ctx) - && mu_mailcap_entry_copiousoutput (entry, &flag) == 0 && flag) + && mu_mailcap_entry_sget_field (entry, MU_MAILCAP_COPIOUSOUTPUT, NULL) == 0) create_filter (get_pager (), -1, &outfd); - - pid = create_filter (view_command, outfd, pfd); + + pid = create_filter (command, outfd, pfd); if (pid > 0) { if (pfd) @@ -588,7 +491,7 @@ run_mailcap (mu_mailcap_entry_t entry, struct mime_context *ctx) mime_context_write_input (ctx, fd); close (fd); } - + while (waitpid (pid, &status, 0) < 0) if (errno != EINTR) { @@ -602,62 +505,14 @@ run_mailcap (mu_mailcap_entry_t entry, struct mime_context *ctx) } static int -find_entry (const char *file, struct mime_context *ctx) +entry_selector (mu_mailcap_entry_t entry, void *data) { - mu_mailcap_t mailcap; - int status; - mu_stream_t stream; - int rc = 1; - - mu_debug (ctx->dh, MU_DEBUG_TRACE1, (_("trying %s...\n"), file)); - status = mu_file_stream_create (&stream, file, MU_STREAM_READ); - if (status) - { - if (status != ENOENT) - mu_error ("cannot open input stream %s: %s", - file, mu_strerror (status)); - return -1; - } + struct mime_context *ctx = data; + char const *pattern; - status = mu_mailcap_create (&mailcap, stream); - if (status == 0) - { - size_t i, count = 0; - char *type; - - mime_context_get_content_type (ctx, &type); - - mu_mailcap_entries_count (mailcap, &count); - for (i = 1; i <= count; i++) - { - mu_mailcap_entry_t entry; - char buffer[256]; - - if (mu_mailcap_get_entry (mailcap, i, &entry)) - continue; - - /* typefield. */ - mu_mailcap_entry_get_typefield (entry, - buffer, sizeof (buffer), NULL); - - if (fnmatch (buffer, type, FNM_CASEFOLD) == 0) - { - mu_debug (ctx->dh, MU_DEBUG_TRACE1, (_("found in %s\n"), file)); - if (run_mailcap (entry, ctx) == 0) - { - rc = 0; - break; - } - } - } - mu_mailcap_destroy (&mailcap); - } - else - { - mu_error ("cannot create mailcap for %s: %s", - file, mu_strerror (status)); - } - return rc; + if (mu_mailcap_entry_sget_type (entry, &pattern)) + return 1; + return mu_mailcap_content_type_match (pattern, 0, ctx->content_type); } int @@ -669,7 +524,7 @@ display_stream_mailcap (const char *ident, mu_stream_t stream, mu_header_t hdr, struct mu_wordsplit ws; struct mime_context ctx; int rc = 1; - + if (mime_context_fill (&ctx, ident, stream, hdr, no_ask, interactive, dry_run, dh)) return 1; @@ -681,10 +536,10 @@ display_stream_mailcap (const char *ident, mu_stream_t stream, mu_header_t hdr, DEFAULT_MAILCAP); free (home); if (!mailcap_path_tmp) - return 1; + return 1; mailcap_path = mailcap_path_tmp; } - + mu_opool_create (&expand_pool, MU_OPOOL_ENOMEMABRT); ws.ws_delim = ":"; @@ -697,14 +552,33 @@ display_stream_mailcap (const char *ident, mu_stream_t stream, mu_header_t hdr, } else { - size_t i; + mu_mailcap_finder_t finder; + int flags = MU_MAILCAP_FLAG_DEFAULT; + struct mu_mailcap_error_closure *errcp = NULL; + struct mu_mailcap_selector_closure selcl; + mu_mailcap_entry_t entry; + int rc; + + if (mu_debug_level_p (ctx.dh, MU_DEBUG_TRACE1) + || mu_debug_level_p (ctx.dh, MU_DEBUG_TRACE2)) + flags |= MU_MAILCAP_FLAG_LOCUS; + if (mu_debug_level_p (ctx.dh, MU_DEBUG_ERROR)) + errcp = &mu_mailcap_default_error_closure; + + memset (&selcl, 0, sizeof (selcl)); + selcl.selector = entry_selector; + selcl.data = &ctx; + + rc = mu_mailcap_finder_create (&finder, flags, + &selcl, errcp, ws.ws_wordv); + mu_wordsplit_free (&ws); - for (i = 0; i < ws.ws_wordc; i++) + while ((rc = mu_mailcap_finder_next_match (finder, &entry)) == 0) { - if ((rc = find_entry (ws.ws_wordv[i], &ctx)) == 0) + if (run_mailcap (entry, &ctx) == 0) break; } - mu_wordsplit_free (&ws); + mu_mailcap_finder_destroy (&finder); } mu_opool_destroy (&expand_pool); free (mailcap_path_tmp); diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am index 55b623892..422d2c154 100644 --- a/libmailutils/Makefile.am +++ b/libmailutils/Makefile.am @@ -16,9 +16,34 @@ # . SUBDIRS = \ - auth base address list sockaddr cidr cfg cli diag\ - filter locus mailbox mailer mime msgset opt server string stream stdstream\ - property url imapio datetime wicket . tests + auth\ + base\ + address\ + list\ + sockaddr\ + cidr\ + cfg\ + cli\ + diag\ + filter\ + locus\ + mailbox\ + mailcap\ + mailer\ + mime\ + msgset\ + opt\ + server\ + string\ + stream\ + stdstream\ + property\ + url\ + imapio\ + datetime\ + wicket\ + .\ + tests lib_LTLIBRARIES = libmailutils.la @@ -40,6 +65,7 @@ libmailutils_la_LIBADD = \ list/liblist.la\ locus/liblocus.la\ mailbox/libmailbox.la\ + mailcap/libmailcap.la\ mailer/libmailer.la\ mime/libmime.la\ msgset/libmsgset.la\ diff --git a/libmailutils/base/Makefile.am b/libmailutils/base/Makefile.am index e4ff1da57..e641f1dc0 100644 --- a/libmailutils/base/Makefile.am +++ b/libmailutils/base/Makefile.am @@ -43,7 +43,6 @@ libbase_la_SOURCES = \ lcall.c\ locale.c\ locker.c\ - mailcap.c\ md5.c\ monitor.c\ msgid.c\ diff --git a/libmailutils/base/mailcap.c b/libmailutils/base/mailcap.c deleted file mode 100644 index 4a4ba01ac..000000000 --- a/libmailutils/base/mailcap.c +++ /dev/null @@ -1,738 +0,0 @@ -/* GNU Mailutils -- a suite of utilities for electronic mail - Copyright (C) 1999-2019 Free Software Foundation, Inc. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General - Public License along with this library. If not, see - . */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include - -/* Definition of the structure, this should be in mailutils/sys/mailcap.h. */ -struct _mu_mailcap_entry -{ - char * typefield; - char * viewcommand; - char ** fields; - size_t fields_count; -}; - -/* Definition of the structure, this should be in mailutils/sys/mailcap.h. */ -struct _mu_mailcap -{ - mu_mailcap_entry_t *entries; - size_t entries_count; -}; - - -static int mu_mailcap_parse (mu_mailcap_t mailcap, mu_stream_t stream); -static int mu_mailcap_parse_entry (mu_mailcap_entry_t entry, char *buffer); -static char * tokenize (char *s, char **save_ptr); - -int -mu_mailcap_create (mu_mailcap_t * pmailcap, mu_stream_t stream) -{ - mu_mailcap_t mailcap; - int status = 0; - - if (stream == NULL) - return EINVAL; - if (pmailcap == NULL) - return MU_ERR_OUT_PTR_NULL; - - mailcap = calloc (1, sizeof (*mailcap)); - if (mailcap != NULL) - { - status = mu_mailcap_parse (mailcap, stream); - if (status != 0) - { - mu_mailcap_destroy (&mailcap); - } - else - { - *pmailcap = mailcap; - } - } - else - { - status = ENOMEM; - } - return status; -} - -void -mu_mailcap_destroy (mu_mailcap_t * pmailcap) -{ - if (pmailcap != NULL && *pmailcap != NULL) - { - int i; - mu_mailcap_t mailcap = *pmailcap; - - for (i = 0; i < mailcap->entries_count; i++) - { - int j; - mu_mailcap_entry_t entry = mailcap->entries[i]; - free (entry->typefield); - free (entry->viewcommand); - for (j = 0; j < entry->fields_count; j++) - { - free (entry->fields[j]); - } - } - } -} - -int -mu_mailcap_entries_count (mu_mailcap_t mailcap, size_t *pcount) -{ - int status = 0; - - if (mailcap == NULL) - status = EINVAL; - if (pcount != NULL) - { - *pcount = mailcap->entries_count; - } - return status; -} - -int -mu_mailcap_get_entry (mu_mailcap_t mailcap, size_t no, - mu_mailcap_entry_t *pentry) -{ - int status = 0; - if (mailcap == NULL) - status = EINVAL; - else if (pentry == NULL) - status = MU_ERR_OUT_PTR_NULL; - else if (no == 0 || no > mailcap->entries_count) - { - status = MU_ERR_NOENT; - } - else - { - *pentry = mailcap->entries[no - 1]; - } - return status; -} - -int -mu_mailcap_entry_get_typefield (mu_mailcap_entry_t entry, char *buffer, - size_t buflen, size_t *pn) -{ - int status = 0; - int len = 0; - - if (entry == NULL) - { - status = EINVAL; - } - else - { - len = strlen(entry->typefield); - if (buffer != NULL && buflen > 0) - { - buflen--; - len = (len < buflen) ? len : buflen; - memcpy (buffer, entry->typefield, len); - buffer[len] = '\0'; - } - } - if (pn) - { - *pn = len; - } - return status; -} - -int -mu_mailcap_entry_get_viewcommand (mu_mailcap_entry_t entry, char *buffer, - size_t buflen, size_t *pn) -{ - int status = 0; - int len = 0; - - if (entry == NULL) - { - status = EINVAL; - } - else - { - len = strlen(entry->viewcommand); - if (buffer != NULL && buflen > 0) - { - buflen--; - len = (len < buflen) ? len : buflen; - memcpy (buffer, entry->viewcommand, len); - buffer[len] = '\0'; - } - } - if (pn) - { - *pn = len; - } - return status; -} - -int -mu_mailcap_entry_fields_count (mu_mailcap_entry_t entry, size_t *pcount) -{ - int status = 0; - if (entry == NULL) - { - status = EINVAL; - } - if (pcount != NULL) - { - *pcount = entry->fields_count; - } - return status; -} - -int -mu_mailcap_entry_get_field (mu_mailcap_entry_t entry, size_t no, - char *buffer, size_t buflen, size_t *pn) -{ - int status = 0; - int len = 0; - - if (entry == NULL) - { - status = EINVAL; - } - else if ( no == 0 || no > entry->fields_count) - { - status = MU_ERR_NOENT; - } - else - { - len = strlen(entry->fields[no - 1]); - if (buffer != NULL && buflen > 0) - { - buflen--; - len = (len < buflen) ? len : buflen; - memcpy (buffer, entry->fields[no - 1], len); - buffer[len] = '\0'; - } - } - if (pn) - { - *pn = len; - } - return status; -} - -int -mu_mailcap_entry_get_compose (mu_mailcap_entry_t entry, - char *buffer, size_t buflen, size_t *pn) -{ - return mu_mailcap_entry_get_value (entry, "compose", buffer, buflen, pn); -} - -int -mu_mailcap_entry_get_composetyped (mu_mailcap_entry_t entry, char *buffer, - size_t buflen, size_t *pn) -{ - return mu_mailcap_entry_get_value (entry, "composetyped", buffer, buflen, pn); -} - -int -mu_mailcap_entry_get_edit (mu_mailcap_entry_t entry, char *buffer, - size_t buflen, size_t *pn) -{ - return mu_mailcap_entry_get_value (entry, "edit", buffer, buflen, pn); -} - -int -mu_mailcap_entry_get_test (mu_mailcap_entry_t entry, - char *buffer, size_t buflen, size_t *pn) -{ - return mu_mailcap_entry_get_value (entry, "test", buffer, buflen, pn); -} - -int -mu_mailcap_entry_get_x11bitmap (mu_mailcap_entry_t entry, - char *buffer, size_t buflen, size_t *pn) -{ - return mu_mailcap_entry_get_value (entry, "x11-bitmap", buffer, buflen, pn); -} - -int -mu_mailcap_entry_get_description (mu_mailcap_entry_t entry, - char *buffer, size_t buflen, size_t *pn) -{ - return mu_mailcap_entry_get_value (entry, "description", buffer, buflen, pn); -} - -int -mu_mailcap_entry_needsterminal (mu_mailcap_entry_t entry, int *on) -{ - int status = 0; - int found = 0; - if (entry == NULL) - { - status = EINVAL; - } - else - { - int i; - for (i = 0; i < entry->fields_count; i++) - { - int n = mu_c_strcasecmp (entry->fields[i], "needsterminal"); - if (n == 0) - { - found = 1; - break; - } - } - } - if (on) - *on = found; - return status; -} - -int -mu_mailcap_entry_copiousoutput (mu_mailcap_entry_t entry, int *on) -{ - int status = 0; - int found = 0; - if (entry == NULL) - { - status = EINVAL; - } - else - { - int i; - for (i = 0; i < entry->fields_count; i++) - { - int n = mu_c_strcasecmp (entry->fields[i], "copiousoutput"); - if (n == 0) - { - found = 1; - break; - } - } - } - if (on) - *on = found; - return status; -} - -int -mu_mailcap_entry_get_value (mu_mailcap_entry_t entry, const char *key, - char *buffer, size_t buflen, size_t *pn) -{ - int len = 0; - int status = ENOENT; - - if (!entry) - status = EINVAL; - else - { - int i; - int key_len = strlen (key); - for (i = 0; i < entry->fields_count; i++) - { - int n = mu_c_strncasecmp (entry->fields[i], key, key_len); - if (n == 0) - { - int field_len = strlen(entry->fields[i]); - status = 0; - if (field_len > key_len) - { - int c = entry->fields[i][key_len]; - if (mu_isspace (c) || c == '=') - { - char *value = strchr (entry->fields[i], '='); - if (value != NULL) - { - value++; /* Pass the equal. */ - /* Remove leading space. */ - for (; mu_isspace (*value); value++) - ; - len = strlen (value); - /* Strip surrounding double quotes */ - if (len > 1 && value[0] == '"' && value[len - 1] == '"') - { - value++; - len -= 2; - } - if (buffer != NULL && buflen > 0) - { - buflen--; - len = (len < buflen) ? len : buflen; - memcpy (buffer, value, len); - buffer[len] = '\0'; - } - break; - } - } - } - } - } - } - if (pn) - *pn = len; - return status; -} - -/* - * break the line on ';'. Same as strtok() but - * check for escaped "\;" - */ -static char * -tokenize (char *s, char **save_ptr) -{ - int c; - char *token; - - if (s == NULL) - { - s = *save_ptr; - } - - if (*s == '\0') - { - *save_ptr = s; - return NULL; - } - - for (token = s, c = 0; *s; s++) - { - if (*s == ';' && c != '\\') - { - break; - } - c = *s; - } - - if (*s == '\0') - { - *save_ptr = s; - } - else - { - *s = '\0'; - *save_ptr = s + 1; - } - return token; -} - -/** - * parse the mailcap line, fields are separated by ';' - */ -static int -mu_mailcap_parse_entry (mu_mailcap_entry_t entry, char *buffer) -{ - char *token = NULL; - char *s = NULL; - int i; - for (i = 0, token = tokenize (buffer, &s); - token != NULL; token = tokenize (NULL, &s), i++) - { - switch (i) - { - /* The first entry in a mailcap line is the typefield. */ - case 0: - entry->typefield = strdup (mu_str_stripws (token)); - break; - - /* The second entry in a mailcap line is the view-command. */ - case 1: - entry->viewcommand = strdup (mu_str_stripws (token)); - break; - - /* The rest are the optional fields. */ - default: - { - char **fields = realloc (entry->fields, - (entry->fields_count + 1) * - sizeof (*fields)); - if (fields != NULL) - { - entry->fields = fields; - entry->fields[entry->fields_count] = - strdup (mu_str_stripws (token)); - entry->fields_count++; - } - } - } - } - /* Make sure typefield and viewcommand are not null. */ - if (entry->typefield == NULL) - { - entry->typefield = strdup (""); - } - if (entry->viewcommand == NULL) - { - entry->viewcommand = strdup (""); - } - return 0; -} - -/* - * parse a mailcap file or stream, - * - ignore empty line. - * - ignore line starting with '#' - * - multiline is done with the '\' as continuation - * example: -# comment -application/pgp; gpg < %s | metamail; needsterminal; \ - test=test %{encapsulation}=entity ; copiousoutput - */ -static int -mu_mailcap_parse (mu_mailcap_t mailcap, mu_stream_t stream) -{ - int status; - size_t n; - char *previous; - char *buffer; - size_t buflen = 512; - - buffer = malloc (buflen); - if (buffer == NULL) - { - return ENOMEM; - } - - /* - * We are doing this a little more complex then expected, because we do not - * want to seek() back in the stream: - * - we have to take care of continuation line i.e. line ending with '\' - * - we have to take to account that the line may be bigger then the buffer - * and reallocate - * - check the return of malloc/realloc - * The old continuation line is saved in the "previous" pointer and - * prepended to the buffer. - */ - status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL); - if (status) - return status; - previous = NULL; - while ((status = mu_stream_readline (stream, buffer, buflen, &n)) == 0 - && n > 0) - { - int len; - - /* If there is no trailing newline, that means the buffer was too small, - * make room for the buffer and continue reading */ - if (buffer[n - 1] != '\n') - { - char *b = realloc (buffer, buflen * sizeof (*buffer)); - buflen *= 2; - if (b == NULL) - { - status = ENOMEM; - break; - } - buffer = b; - /* - * Fake this as a continuation line, for simplicity. - */ - strcat (buffer, "\\"); - } - else - { - /* Nuke the trailing newline. */ - buffer[n - 1] = '\0'; - } - - /* recalculate the len. */ - len = strlen (buffer); - - /* Ending with a '\' means continuation line. */ - if (len && buffer[len - 1] == '\\') - { - buffer[len - 1] = '\0'; - /* - * Check for any previous line: - * - if yes append the buffer to the previous line. - * - if not set the buffer as the previous line and continue. - */ - if (previous == NULL) - { - previous = strdup (buffer); - if (previous == NULL) - { - status = ENOMEM; - break; - } - } - else - { - char *b = realloc (previous, strlen (previous) + len + 1); - if (b == NULL) - { - status = ENOMEM; - break; - } - previous = b; - strcat(previous, buffer); - } - } - else - { - /* Did we have a previous incomplete line? - * if yes make one line from the previous and the buffer. - */ - if (previous != NULL) - { - int prev_len = strlen (previous); - int total = prev_len + len + 1; - if (total > buflen) - { - char *b = realloc (buffer, total * sizeof (*buffer)); - if (b == NULL) - { - status = ENOMEM; - break; - } - buffer = b; - buflen = total; - } - memmove (buffer + prev_len, buffer, len + 1); - memcpy (buffer, previous, prev_len); - free (previous); - previous = NULL; - } - } - - /* Parse the well-form mailcap line entry. */ - if (previous == NULL) { - /* Nuke the trailing/prepend spaces. */ - char *line = mu_str_stripws (buffer); - /* Ignore comments or empty lines */ - if (*line != '#' && *line != '\0') - { - mu_mailcap_entry_t *entries; - entries = realloc (mailcap->entries, - (mailcap->entries_count + 1) * - sizeof (*entries)); - if (entries != NULL) - { - mailcap->entries = entries; - mailcap->entries[mailcap->entries_count] = calloc (1, - sizeof(**entries)); - if (mailcap->entries[mailcap->entries_count] != NULL) - { - mu_mailcap_parse_entry (mailcap->entries[mailcap->entries_count], line); - } - mailcap->entries_count++; - } - else - { - status = ENOMEM; - break; - } - } - } - } - - if (buffer != NULL) - { - free (buffer); - } - if (previous != NULL) - { - free (previous); - } - return status; -} - -#ifdef STANDALONE_TEST -int main() -{ - mu_stream_t stream = NULL; - int status = 0; - - status = mu_file_stream_create (&stream, "/home/alain/mailcap", - MU_STREAM_READ); - if (status == 0) - { - mu_mailcap_t mailcap; - status = mu_mailcap_create (&mailcap, stream); - if (status == 0) - { - int i, n; - size_t count = 0; - char buffer[256]; - - mu_mailcap_entries_count (mailcap, &count); - for (i = 1; i <= count; i++) - { - int j; - mu_mailcap_entry_t entry = NULL; - int fields_count = 0; - - printf ("entry[%d]\n", i); -#if 1 - - mu_mailcap_get_entry (mailcap, i, &entry); - /* Print typefield. */ - mu_mailcap_entry_get_typefield (entry, buffer, - sizeof (buffer), NULL); - printf ("\ttypefield: %s\n", buffer); - - /* Print view-command. */ - mu_mailcap_entry_get_viewcommand (entry, buffer, - sizeof (buffer), NULL); - printf ("\tview-command: %s\n", buffer); - - /* Print fields. */ - mu_mailcap_entry_fields_count (entry, &fields_count); - for (j = 1; j <= fields_count; j++) - { - mu_mailcap_entry_get_field (entry, j, buffer, - sizeof (buffer), NULL); - printf("\tfields[%d]: %s\n", j, buffer); - } - n = 0; - mu_mailcap_entry_get_compose (entry, buffer, - sizeof (buffer), &n); - if (n > 0) - { - printf("\tcompose[%s]\n", buffer); - } - printf("\n"); - } -#else - for (i = 0; i < mailcap->entries_count; i++) - { - int j; - mu_mailcap_entry_t entry = mailcap->entries[i]; - printf("[%s];[%s]", entry->typefield, entry->viewcommand); - for (j = 0; j < entry->fields_count; j++) - { - printf(";[%s]", entry->fields[j]); - } - printf("\n"); - } -#endif - mu_mailcap_destroy (&mailcap); - } - } - return 0; -} - -#endif diff --git a/libmailutils/mailcap/Makefile.am b/libmailutils/mailcap/Makefile.am new file mode 100644 index 000000000..20e86682d --- /dev/null +++ b/libmailutils/mailcap/Makefile.am @@ -0,0 +1,42 @@ +# GNU Mailutils -- a suite of utilities for electronic mail +# Copyright (C) 2019 Free Software Foundation, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General +# Public License along with this library. If not, see +# . + +noinst_LTLIBRARIES = libmailcap.la + +libmailcap_la_SOURCES = \ + ctmatch.c\ + deferrclos.c\ + mcp_creat.c\ + mcp_destr.c\ + mcp_get.c\ + mcp_err.c\ + mcp_find.c\ + mcp_flags.c\ + mcp_sel.c\ + mcp_count.c\ + ent_cmd.c\ + ent_creat.c\ + ent_destr.c\ + ent_locus.c\ + ent_type.c\ + fields.c\ + fieldacc.c\ + finder.c\ + parse.c\ + parsefile.c + +AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils diff --git a/libmailutils/mailcap/ctmatch.c b/libmailutils/mailcap/ctmatch.c new file mode 100644 index 000000000..180ff594e --- /dev/null +++ b/libmailutils/mailcap/ctmatch.c @@ -0,0 +1,166 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999-2019 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + . */ + +#include +#include +#include + +enum + { + MATCH = 0, + NO_MATCH = 1 + }; + +/* Return MATCH (0) if content-type string TYPESTR matches one of + patterns from PATLIST, a list of patterns delimited with DELIM. + Whitespace is allowed at either side of patterns in PATLIST. + Empty patterns are ignored. + + A "pattern" is a type/subtype specification. Matching is case-insensitive. + If the subtype is '*', it matches any subtype from TYPESTR. +*/ +int +mu_mailcap_string_match (char const *patlist, int delim, char const *typestr) +{ + char const *type; + + if (!patlist) + return NO_MATCH; + + while (*patlist) + { + type = typestr; + + /* Skip whitespace and delimiters */ + while (*patlist && (*patlist == delim || mu_isspace (*patlist))) + patlist++; + + /* Match type */ + do + { + if (!*patlist || !*type + || mu_tolower (*patlist++) != mu_tolower (*type++)) + goto retry; + if (*patlist == delim) + goto retry; + } + while (*patlist != '/'); + + if (*type != '/') + goto retry; + patlist++; + type++; + + if (*patlist == '*') + return MATCH; + + /* Match subtype */ + while (*patlist && *patlist != delim && *type + && mu_tolower (*patlist) == mu_tolower (*type)) + { + patlist++; + type++; + } + + /* Skip optional whitespace */ + while (*patlist && mu_isspace (*patlist)) + patlist++; + + if (*patlist == 0 || *patlist == delim) + { + if (*type == 0) + return MATCH; + } + retry: + /* Skip to the next pattern */ + do + { + if (*patlist == 0) + return NO_MATCH; + patlist++; + } + while (*patlist != delim); + } + return NO_MATCH; +} + +/* Return 0 if parsed content-type CT matches PATTERN. */ +int +mu_mailcap_content_type_match (char const *patlist, int delim, + mu_content_type_t ct) +{ + char const *type; + + if (!patlist) + return NO_MATCH; + + while (*patlist) + { + type = ct->type; + + /* Skip whitespace and delimiters */ + while (*patlist && (*patlist == delim || mu_isspace (*patlist))) + patlist++; + + /* Match type */ + do + { + if (!*patlist || !*type + || mu_tolower (*patlist++) != mu_tolower (*type++)) + goto retry; + if (*patlist == delim) + goto retry; + } + while (*patlist != '/'); + + if (*type != 0) + goto retry; + patlist++; + + if (*patlist == '*') + return MATCH; + + /* Match subtype */ + type = ct->subtype; + while (*patlist && *patlist != delim && *type + && mu_tolower (*patlist) == mu_tolower (*type)) + { + patlist++; + type++; + } + + /* Skip optional whitespace */ + while (*patlist && mu_isspace (*patlist)) + patlist++; + + if (*patlist == 0 || *patlist == delim) + { + if (*type == 0) + return MATCH; + } + retry: + /* Skip to next pattern */ + do + { + if (*patlist == 0) + return NO_MATCH; + patlist++; + } + while (*patlist != delim); + } + return NO_MATCH; +} diff --git a/libmailutils/mailcap/deferrclos.c b/libmailutils/mailcap/deferrclos.c new file mode 100644 index 000000000..db260c6df --- /dev/null +++ b/libmailutils/mailcap/deferrclos.c @@ -0,0 +1,32 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999-2019 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + . */ + +#include +#include +#include + +static void +mailcap_error (void *closure, struct mu_locus_range const *loc, char const *msg) +{ + mu_diag_at_locus_range (MU_DIAG_ERR, loc, "%s", msg); +} + +struct mu_mailcap_error_closure mu_mailcap_default_error_closure = { + mailcap_error, + NULL, + NULL +}; diff --git a/libmailutils/mailcap/ent_cmd.c b/libmailutils/mailcap/ent_cmd.c new file mode 100644 index 000000000..ad741730c --- /dev/null +++ b/libmailutils/mailcap/ent_cmd.c @@ -0,0 +1,66 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999-2019 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + . */ + +#include +#include +#include + +int +mu_mailcap_entry_sget_command (mu_mailcap_entry_t ent, char const **pcommand) +{ + if (!ent) + return EINVAL; + if (!pcommand) + return MU_ERR_OUT_PTR_NULL; + *pcommand = ent->command; + return 0; +} + +int +mu_mailcap_entry_aget_command (mu_mailcap_entry_t ent, char **pcommand) +{ + if (!ent) + return EINVAL; + if (!pcommand) + return MU_ERR_OUT_PTR_NULL; + if (!(*pcommand = strdup (ent->command))) + return ENOMEM; + return 0; +} + +int +mu_mailcap_entry_get_command (mu_mailcap_entry_t ent, + char *buffer, size_t buflen, + size_t *pn) +{ + size_t len; + + if (!ent) + return EINVAL; + len = strlen (ent->command); + + if (buffer) + { + if (len > buflen) + len = buflen; + memcpy (buffer, ent->command, len); + buffer[len] = 0; + } + if (pn) + *pn = len; + return 0; +} diff --git a/libmailutils/mailcap/ent_creat.c b/libmailutils/mailcap/ent_creat.c new file mode 100644 index 000000000..30a139537 --- /dev/null +++ b/libmailutils/mailcap/ent_creat.c @@ -0,0 +1,51 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999-2019 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + . */ + +#include +#include +#include +#include + +int +mu_mailcap_entry_create (mu_mailcap_entry_t *ret_ent, + char *type, char *command) +{ + int rc; + mu_mailcap_entry_t ent = calloc (1, sizeof (*ent)); + + if (!ent) + return ENOMEM; + if (!ret_ent) + return MU_ERR_OUT_PTR_NULL; + + ent->type = strdup (type); + ent->command = strdup (command); + if (!ent->type || !ent->command) + { + mu_mailcap_entry_destroy (&ent); + return ENOMEM; + } + rc = mu_assoc_create (&ent->fields, MU_ASSOC_ICASE); + if (rc) + mu_mailcap_entry_destroy (&ent); + else + { + mu_assoc_set_destroy_item (ent->fields, mu_mailcap_entry_field_deallocate); + *ret_ent = ent; + } + return rc; +} diff --git a/libmailutils/mailcap/ent_destr.c b/libmailutils/mailcap/ent_destr.c new file mode 100644 index 000000000..1fa0769cf --- /dev/null +++ b/libmailutils/mailcap/ent_destr.c @@ -0,0 +1,47 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999-2019 Free Software Foundation, Inc. + + This libr