Commit 690b1bf8 690b1bf8506e50cb85d2634ba2db2fddbff99dfe by Sergey Poznyakoff

Fix API for obtaining full email address.

Old API relied on passing a pointer to the buffer string and its size,
which is defective.  The new API, in addtion to that, provides functions
for obtaining a pointer to the statically allocated original value, a
pointer to dynamically allocated copy, and a function for formatting the
address directly to a MU stream.

Two functions are marked as deprecated: mu_address_to_string and
mu_address_format_string.  Both assume a pointer to an allocated string
of a fixed size, which is far from being convenient nor reliable enough.

* include/mailutils/address.h (MU_ADDR_HINT_ADDR): Rename to
MU_ADDR_HINT_PRINTABLE
(mu_address)<addr>: Rename to printable.
(mu_address_sget_printable,mu_address_aget_printable)
(mu_address_get_printable): New protos.
(mu_stream_format_address): New proto.
(mu_address_to_string)
(mu_address_format_string): Mark as deprecated.
(mu_validate_email): New proto.
* examples/mta.c: Use mu_address_sget_printable instead
of (mu_address_to_string)
* libmailutils/address/addrstream.c: New file.
* libmailutils/address/Makefile.am (libaddress_la_SOURCES): Add
addrstream.c
* libmailutils/address/address.c (mu_address_format_string): Rewrite using
streams.
(mu_address_to_string): Rewrite as a wrapper over
mu_address_get_printable.
(mu_address_sget_printable,mu_address_aget_printable)
(mu_address_get_printable): New functions.
* libmailutils/mime/mimehdr.c (_mime_header_parse): Initialize rc.
* mail/util.c (util_merge_addresses): Use mu_address_aget_printable.
* mh/mh.h (mh_annotate): Both string args are const.
* mh/mh_init.c (mh_annotate): Likewise.
* mh/mh_format.c (builtin_formataddr): Use mu_address_sget_printable.
* mh/mh_whatnow.c (anno_data)<field,value>: Both are consts.
(annotate): Use mu_address_sget_printable.
* mh/send.c (set_address_header): Use mu_address_sget_printable.
* mu/imap.c (format_email): Use mu_stream_format_address.
* python/libmu_py/address.c (api_address_to_string): Likewise.
1 parent 924bc727
......@@ -112,8 +112,8 @@ addr_fieldptr_by_mask (mu_address_t addr, int mask)
{
switch (mask)
{
case MU_ADDR_HINT_ADDR:
return &addr->addr;
case MU_ADDR_HINT_PRINTABLE:
return &addr->printable;
case MU_ADDR_HINT_COMMENTS:
return &addr->comments;
......
......@@ -437,26 +437,17 @@ message_finalize (mu_message_t msg, int warn)
if (finalize_option && !have_to)
{
size_t n;
char const *sptr;
int c;
c = mu_address_to_string (recipients, NULL, 0, &n);
c = mu_address_sget_printable (recipients, &sptr);
if (c)
{
mu_error ("%s: mu_address_to_string failure: %s",
mu_error ("%s: mu_address_sget_printable failure: %s",
progname, mu_strerror (c));
return 1;
}
value = malloc (n + 1);
if (!value)
{
mu_error ("%s: not enough memory", progname);
return 1;
}
mu_address_to_string (recipients, value, n + 1, &n);
mu_header_set_value (header, MU_HEADER_TO, value, 1);
free (value);
mu_header_set_value (header, MU_HEADER_TO, sptr, 1);
}
return 0;
}
......
......@@ -25,7 +25,7 @@
extern "C" {
#endif
#define MU_ADDR_HINT_ADDR 0x0001 /* Not used yet */
#define MU_ADDR_HINT_PRINTABLE 0x0001 /* Not used yet */
#define MU_ADDR_HINT_COMMENTS 0x0002
#define MU_ADDR_HINT_PERSONAL 0x0004
#define MU_ADDR_HINT_EMAIL 0x0008
......@@ -42,9 +42,11 @@ extern "C" {
*/
struct mu_address
{
char *addr;
/* the original string that this list of addresses was created
* from, only present at the head of the list */
char *printable;
/* Printable representation of this address. Normally, it is
* the original string that this list of addresses was created
* from, only present at the head of the list
*/
char *comments;
/* the collection of comments stripped during parsing this MAILBOX */
......@@ -129,8 +131,12 @@ extern int mu_address_aget_route
extern int mu_address_is_group
(mu_address_t, size_t, int*);
extern int mu_address_to_string (mu_address_t, char *, size_t, size_t *);
extern int mu_address_sget_printable (mu_address_t addr, const char **sptr);
extern int mu_address_aget_printable (mu_address_t addr, char **presult);
extern int mu_address_get_printable (mu_address_t addr, char *buf, size_t len,
size_t *n);
extern int mu_address_get_count (mu_address_t, size_t *);
extern int mu_address_get_group_count (mu_address_t, size_t *);
extern int mu_address_get_email_count (mu_address_t, size_t *);
......@@ -139,8 +145,21 @@ extern int mu_address_get_unix_mailbox_count (mu_address_t, size_t *);
extern int mu_address_contains_email (mu_address_t addr, const char *email);
extern int mu_address_union (mu_address_t *a, mu_address_t b);
extern size_t mu_address_format_string (mu_address_t addr, char *buf, size_t buflen);
extern int mu_stream_format_address (mu_stream_t str, mu_address_t addr);
/* Deprecated calls */
extern int mu_address_to_string (mu_address_t, char *, size_t, size_t *)
MU_DEPRECATED; /* Use mu_address_get_printable, if you really have to */
extern size_t mu_address_format_string (mu_address_t addr, char *buf,
size_t buflen)
MU_DEPRECATED; /* Use mu_stream_format_address, or any of the
_get_printable functions */
extern int mu_validate_email (mu_address_t subaddr);
#ifdef __cplusplus
}
#endif
......
......@@ -19,6 +19,7 @@ noinst_LTLIBRARIES = libaddress.la
libaddress_la_SOURCES = \
address.c\
addrstream.c\
parse822.c
INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
......
......@@ -35,6 +35,7 @@
#include <mailutils/parse822.h>
#include <mailutils/address.h>
#include <mailutils/cstr.h>
#include <mailutils/stream.h>
int
mu_address_create_null (mu_address_t *pa)
......@@ -70,8 +71,8 @@ mu_address_create_hint (mu_address_t *a, const char *s, mu_address_t hint,
if (!*a)
return MU_ERR_EMPTY_ADDRESS;
(*a)->addr = strdup (s);
if (!(*a)->addr)
(*a)->printable = strdup (s);
if (!(*a)->printable)
{
mu_address_destroy (a);
return ENOMEM;
......@@ -159,8 +160,8 @@ mu_address_destroy (mu_address_t *paddress)
mu_address_t current;
for (; address; address = current)
{
if (address->addr)
free (address->addr);
if (address->printable)
free (address->printable);
if (address->comments)
free (address->comments);
if (address->personal)
......@@ -195,19 +196,19 @@ mu_address_concatenate (mu_address_t to, mu_address_t *from)
*from = NULL;
/* discard the current string cache as it is now inaccurate */
if (to->addr)
if (to->printable)
{
free (to->addr);
to->addr = NULL;
free (to->printable);
to->printable = NULL;
}
to = to->next;
/* only the first address must have a cache */
if (to->addr)
if (to->printable)
{
free (to->addr);
to->addr = NULL;
free (to->printable);
to->printable = NULL;
}
return 0;
......@@ -432,8 +433,8 @@ mu_address_set_email (mu_address_t addr, size_t no, const char *buf)
return 0;
}
static int
validate_email (mu_address_t subaddr)
int
mu_validate_email (mu_address_t subaddr)
{
if (!subaddr->email)
{
......@@ -473,82 +474,45 @@ mu_address_sget_email (mu_address_t addr, size_t no, char const **sptr)
if (!subaddr)
return MU_ERR_NOENT;
validate_email (subaddr);
mu_validate_email (subaddr);
*sptr = subaddr->email;
return 0;
}
DECL_GET(email)
DECL_AGET(email)
#define format_char(c) do {\
if (buflen) \
{\
*buf++ = c;\
buflen--;\
}\
else\
rc++;\
} while(0)
#define format_string(str) do {\
if (buflen) \
{\
int n = snprintf (buf, buflen, "%s", str);\
buf += n;\
buflen -= n;\
}\
else\
rc += strlen (str);\
} while (0)
size_t
mu_address_format_string (mu_address_t addr, char *buf, size_t buflen)
{
int rc = 0;
int comma = 0;
for (;addr; addr = addr->next)
mu_stream_t str;
int rc;
if (!buf)
rc = mu_nullstream_create (&str, MU_STREAM_WRITE);
else
rc = mu_fixed_memory_stream_create (&str, buf, buflen, MU_STREAM_WRITE);
if (rc == 0)
{
validate_email (addr);
if (addr->email)
size_t size;
mu_stream_stat_buffer statbuf;
mu_stream_set_stat (str, MU_STREAM_STAT_MASK (MU_STREAM_STAT_OUT),
statbuf);
rc = mu_stream_format_address (str, addr);
mu_stream_destroy (&str);
if (rc)
return 0;
size = statbuf[MU_STREAM_STAT_OUT];
if (buf)
{
int space = 0;
if (comma)
format_char (',');
if (addr->personal)
{
format_char ('"');
format_string (addr->personal);
format_char ('"');
space++;
}
if (addr->comments)
{
if (space)
format_char (' ');
format_char ('(');
format_string (addr->comments);
format_char (')');
space++;
}
if (space)
format_char (' ');
format_char ('<');
format_string (addr->email);
format_char ('>');
comma++;
if (size + 1 >= buflen)
size = buflen - 1;
buf[size] = 0;
}
return size;
}
format_char (0);
return rc;
return 0;
}
static int
......@@ -593,27 +557,86 @@ mu_address_is_group (mu_address_t addr, size_t no, int *yes)
}
int
mu_address_to_string (mu_address_t addr, char *buf, size_t len, size_t *n)
mu_address_sget_printable (mu_address_t addr, const char **sptr)
{
size_t i;
if (addr == NULL)
return EINVAL;
if (buf)
*buf = '\0';
if (!sptr)
return MU_ERR_OUT_PTR_NULL;
if (!addr->printable)
{
mu_stream_t str;
int rc;
rc = mu_memory_stream_create (&str, MU_STREAM_RDWR);
if (rc)
return rc;
rc = mu_stream_format_address (str, addr);
if (rc == 0)
{
mu_off_t size;
mu_stream_size (str, &size);
addr->printable = malloc (size + 1);
if (!addr->printable)
rc = ENOMEM;
else
{
mu_stream_seek (str, 0, MU_SEEK_SET, NULL);
rc = mu_stream_read (str, addr->printable, size, NULL);
addr->printable[size] = 0;
}
}
mu_stream_destroy (&str);
if (rc)
return rc;
}
*sptr = addr->printable;
return 0;
}
if (!addr->addr)
int
mu_address_aget_printable (mu_address_t addr, char **presult)
{
int rc;
const char *s;
if (addr == NULL)
return EINVAL;
if (!presult)
return MU_ERR_OUT_PTR_NULL;
rc = mu_address_sget_printable (addr, &s);
if (rc == 0)
{
i = mu_address_format_string (addr, NULL, 0);
addr->addr = malloc (i + 1);
if (!addr->addr)
return ENOMEM;
mu_address_format_string (addr, addr->addr, i+1);
char *result = strdup (s);
if (result)
*presult = result;
else
rc = ENOMEM;
}
return rc;
}
i = mu_cpystr (buf, addr->addr, len);
if (n)
*n = i;
return 0;
int
mu_address_get_printable (mu_address_t addr, char *buf, size_t len, size_t *n)
{
const char *s;
int rc;
rc = mu_address_sget_printable (addr, &s);
if (rc == 0)
{
size_t i;
i = mu_cpystr (buf, addr->printable, len);
if (n)
*n = i;
}
return rc;
}
int
mu_address_to_string (mu_address_t addr, char *buf, size_t len, size_t *n)
{
return mu_address_get_printable (addr, buf, len, n);
}
int
......@@ -687,8 +710,8 @@ mu_address_dup (mu_address_t src)
return NULL;
/* FIXME: How about:
if (src->addr)
dst->addr = strdup (src->addr);
if (src->printable)
dst->printable = strdup (src->printable);
?
*/
if (src->comments)
......@@ -725,10 +748,10 @@ mu_address_union (mu_address_t *a, mu_address_t b)
}
else
{
if ((*a)->addr)
if ((*a)->printable)
{
free ((*a)->addr);
(*a)->addr = NULL;
free ((*a)->printable);
(*a)->printable = NULL;
}
for (last = *a; last->next; last = last->next)
;
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2005, 2006, 2007, 2009, 2010, 2011
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
<http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <mailutils/address.h>
#include <mailutils/stream.h>
int
mu_stream_format_address (mu_stream_t str, mu_address_t addr)
{
int comma = 0;
for (;addr; addr = addr->next)
{
mu_validate_email (addr);
if (addr->email)
{
int space = 0;
if (comma)
mu_stream_write (str, ",", 1, NULL);
if (addr->personal)
{
mu_stream_printf (str, "\"%s\"", addr->personal);
space++;
}
if (addr->comments)
{
if (space)
mu_stream_write (str, " ", 1, NULL);
mu_stream_printf (str, "(%s)", addr->comments);
space++;
}
if (space)
mu_stream_write (str, " ", 1, NULL);
mu_stream_printf (str, "<%s>", addr->email);
comma++;
}
}
return mu_stream_err (str) ? mu_stream_last_error (str) : 0;
}
......@@ -713,8 +713,8 @@ addr_field_by_mask (mu_address_t addr, int mask)
{
switch (mask)
{
case MU_ADDR_HINT_ADDR:
return addr->addr;
case MU_ADDR_HINT_PRINTABLE:
return addr->printable;
case MU_ADDR_HINT_COMMENTS:
return addr->comments;
......@@ -758,7 +758,7 @@ addr_free_fields (mu_address_t a, int memflag)
{
char *p;
if ((p = addr_field_by_mask (a, memflag & MU_ADDR_HINT_ADDR)))
if ((p = addr_field_by_mask (a, memflag & MU_ADDR_HINT_PRINTABLE)))
free (p);
if ((p = addr_field_by_mask (a, memflag & MU_ADDR_HINT_COMMENTS)))
free (p);
......
......@@ -172,8 +172,8 @@ assoc_remove (mu_assoc_t assoc, struct _mu_assoc_elem *elem)
while ((j < r && r <= i) || (i < j && j < r) || (r <= i && i < j));
if (j != i)
memcpy (ASSOC_ELEM (assoc, j), ASSOC_ELEM (assoc, i),
assoc->elsize);
memcpy (ASSOC_ELEM (assoc, j), ASSOC_ELEM (assoc, i),
assoc->elsize);
}
return 0;
}
......
......@@ -287,7 +287,7 @@ static int
_mime_header_parse (const char *text, char **pvalue,
mu_assoc_t assoc, const char *outcharset, int subset)
{
int rc;
int rc = 0;
struct mu_wordsplit ws;
struct param_continuation cont;
size_t i;
......
......@@ -861,17 +861,13 @@ util_merge_addresses (char **addr_str, const char *value)
rc = mu_address_union (&addr, new_addr);
if (rc == 0)
{
size_t n;
rc = mu_address_to_string (addr, NULL, 0, &n);
char *val;
rc = mu_address_aget_printable (addr, &val);
if (rc == 0)
{
free (*addr_str);
*addr_str = malloc (n + 1);
if (!*addr_str)
rc = ENOMEM;
else
mu_address_to_string (addr, *addr_str, n + 1, &n);
*addr_str = val;
}
}
......@@ -972,15 +968,12 @@ util_header_expand (mu_header_t *phdr)
if (addr)
{
char *newvalue;
size_t n = 0;
const char *newvalue;
mu_address_to_string (addr, NULL, 0, &n);
newvalue = xmalloc (n + 1);
mu_address_to_string (addr, newvalue, n + 1, NULL);
rc = mu_address_sget_printable (addr, &newvalue);
if (rc == 0)
mu_header_set_value (hdr, name, newvalue, 1);
mu_address_destroy (&addr);
mu_header_set_value (hdr, name, newvalue, 1);
free (newvalue);
}
}
else
......
......@@ -358,7 +358,8 @@ typedef int (*mh_alias_enumerator_t) (char *alias, mu_list_t names, void *data);
void mh_alias_enumerate (mh_alias_enumerator_t fun, void *data);
void mh_annotate (mu_message_t msg, char *field, char *text, int date);
void mh_annotate (mu_message_t msg, const char *field, const char *text,
int date);
#define MHL_DECODE 1
#define MHL_CLEARSCREEN 2
......
......@@ -1801,7 +1801,6 @@ static void
builtin_formataddr (struct mh_machine *mach)
{
mu_address_t addr, dest;
size_t size;
int i;
size_t num;
const char *buf;
......@@ -1837,12 +1836,12 @@ builtin_formataddr (struct mh_machine *mach)
}
}
if (mu_address_to_string (dest, NULL, 0, &size) == 0)
if (mu_address_sget_printable (dest, &buf) == 0)
{
strobj_realloc (&mach->reg_str, size + 1);
mu_address_to_string (dest, strobj_ptr (&mach->reg_str), size + 1, NULL);
mu_address_destroy (&dest);
strobj_realloc (&mach->reg_str, strlen (buf) + 1);
strcpy (strobj_ptr (&mach->reg_str), buf);
}
mu_address_destroy (&dest);
}
/* putaddr literal print str address list with
......
......@@ -852,7 +852,7 @@ mh_install (char *name, int automode)
}
void
mh_annotate (mu_message_t msg, char *field, char *text, int date)
mh_annotate (mu_message_t msg, const char *field, const char *text, int date)
{
mu_header_t hdr;
mu_attribute_t attr;
......
......@@ -264,8 +264,8 @@ invoke (const char *compname, const char *defval, int argc, char **argv,
struct anno_data
{
char *field;
char *value;
const char *field;
const char *value;
int date;
};
......@@ -299,16 +299,12 @@ annotate (struct mh_whatnow_env *wh)
if (mu_address_get_nth (addr, i, &subaddr) == 0)
{
size_t size;
struct anno_data d;
mu_address_to_string (subaddr, NULL, 0, &size);
d.value = xmalloc (size + 1);
d.field = wh->anno_field;
d.date = i == 1;
mu_address_to_string (subaddr, d.value, size + 1, NULL);
mu_list_foreach (wh->anno_list, anno, &d);
free (d.value);
if (mu_address_sget_printable (subaddr, &d.value) == 0)
mu_list_foreach (wh->anno_list, anno, &d);
mu_address_destroy (&subaddr);
}
}
......
......@@ -475,11 +475,10 @@ get_sender_personal ()
static void
set_address_header (mu_header_t hdr, char *name, mu_address_t addr)
{
size_t s = mu_address_format_string (addr, NULL, 0);
char *value = xmalloc (s + 1);
mu_address_format_string (addr, value, s);
mu_header_set_value (hdr, name, value, 1);
free (value);
const char *value;
if (mu_address_sget_printable (addr, &value) == 0)
mu_header_set_value (hdr, name, value, 1);
/* FIXME: Error reporting */
}
void
......
......@@ -196,12 +196,7 @@ format_email (mu_stream_t str, const char *name, mu_address_t addr)
if (!addr)
mu_stream_printf (str, "NIL");
else
{
size_t sz = mu_address_format_string (addr, NULL, 0);
char *buf = xmalloc (sz + 1);
mu_address_format_string (addr, buf, sz);
mu_stream_write (str, buf, strlen (buf), NULL);
}
mu_stream_format_address (str, addr);
mu_stream_printf (str, "\n");
}
......
......@@ -267,17 +267,14 @@ static PyObject *
api_address_to_string (PyObject *self, PyObject *args)
{
int status;
size_t n;
char buf[256];
char const *sptr;
PyAddress *py_addr;
memset (buf, 0, sizeof (buf));
if (!PyArg_ParseTuple (args, "O!", &PyAddressType, &py_addr))
return NULL;
status = mu_address_to_string (py_addr->addr, buf, sizeof (buf), &n);
return status_object (status, PyString_FromString (buf));
status = mu_address_sget_printable (py_addr->addr, &sptr);
return status_object (status, PyString_FromString (sptr));
}
static PyMethodDef methods[] = {
......