From 7b79a6edcda94d4224bc4cbbe47cb6dcf2ea42db Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Tue, 14 Sep 2010 14:59:17 +0300 Subject: Rename mailbox/ to libmailutils/. This change has been waiting since 2005-08-16 (aaab88142c8193f1), when libmailbox had been renamed to libmailutils. Back then MU was still under CVS, which didn't like renames. --- libmailutils/.gitignore | 16 + libmailutils/Makefile.am | 186 +++ libmailutils/acl.c | 784 ++++++++++ libmailutils/address.c | 595 ++++++++ libmailutils/alloc.c | 116 ++ libmailutils/amd.c | 1925 +++++++++++++++++++++++ libmailutils/argcv.c | 549 +++++++ libmailutils/asnprintf.c | 40 + libmailutils/asprintf.c | 42 + libmailutils/assoc.c | 529 +++++++ libmailutils/attachment.c | 467 ++++++ libmailutils/attribute.c | 470 ++++++ libmailutils/auth.c | 164 ++ libmailutils/base64.c | 273 ++++ libmailutils/binflt.c | 113 ++ libmailutils/body.c | 419 +++++ libmailutils/cfg_driver.c | 755 +++++++++ libmailutils/cfg_format.c | 395 +++++ libmailutils/cfg_lexer.l | 405 +++++ libmailutils/cfg_parser.y | 1817 ++++++++++++++++++++++ libmailutils/crlfdot.c | 336 ++++ libmailutils/crlfflt.c | 182 +++ libmailutils/cstrcasecmp.c | 58 + libmailutils/cstrlower.c | 31 + libmailutils/cstrupper.c | 31 + libmailutils/daemon.c | 189 +++ libmailutils/date.c | 245 +++ libmailutils/dbgstderr.c | 36 + libmailutils/dbgstream.c | 86 ++ libmailutils/dbgsyslog.c | 34 + libmailutils/debug.c | 298 ++++ libmailutils/diag.c | 179 +++ libmailutils/dot.c | 268 ++++ libmailutils/envelope.c | 181 +++ libmailutils/errors | 87 ++ libmailutils/fgetpwent.c | 163 ++ libmailutils/file_stream.c | 312 ++++ libmailutils/filter.c | 193 +++ libmailutils/filter_iconv.c | 474 ++++++ libmailutils/fltstream.c | 533 +++++++ libmailutils/folder.c | 511 +++++++ libmailutils/freeitem.c | 29 + libmailutils/gdebug.c | 263 ++++ libmailutils/gocs.c | 397 +++++ libmailutils/hdritr.c | 162 ++ libmailutils/header.c | 1228 +++++++++++++++ libmailutils/iostream.c | 261 ++++ libmailutils/ipsrv.c | 580 +++++++ libmailutils/iterator.c | 284 ++++ libmailutils/kwd.c | 94 ++ libmailutils/linelenflt.c | 110 ++ libmailutils/list.c | 685 +++++++++ libmailutils/listlist.c | 139 ++ libmailutils/locale.c | 242 +++ libmailutils/locker.c | 1025 +++++++++++++ libmailutils/mailbox.c | 786 ++++++++++ libmailutils/mailcap.c | 744 +++++++++ libmailutils/mailer.c | 698 +++++++++ libmailutils/mapfile_stream.c | 378 +++++ libmailutils/mbx_default.c | 454 ++++++ libmailutils/mbxitr.c | 160 ++ libmailutils/md5.c | 454 ++++++ libmailutils/memory_stream.c | 224 +++ libmailutils/message.c | 1292 ++++++++++++++++ libmailutils/message_stream.c | 438 ++++++ libmailutils/mime.c | 1071 +++++++++++++ libmailutils/mimehdr.c | 695 +++++++++ libmailutils/mkfilename.c | 46 + libmailutils/monitor.c | 282 ++++ libmailutils/msgscan.c | 106 ++ libmailutils/msrv.c | 1091 +++++++++++++ libmailutils/mu_auth.c | 539 +++++++ libmailutils/muctype.c | 152 ++ libmailutils/muerrno.cin | 65 + libmailutils/muerror.c | 117 ++ libmailutils/munre.c | 93 ++ libmailutils/mutil.c | 1491 ++++++++++++++++++ libmailutils/nls.c | 62 + libmailutils/nullrec.c | 49 + libmailutils/observer.c | 239 +++ libmailutils/opool.c | 446 ++++++ libmailutils/parse822.c | 2040 +++++++++++++++++++++++++ libmailutils/parsedate.y | 1206 +++++++++++++++ libmailutils/permstr.c | 128 ++ libmailutils/prog_stream.c | 462 ++++++ libmailutils/progmailer.c | 314 ++++ libmailutils/property.c | 192 +++ libmailutils/qpflt.c | 262 ++++ libmailutils/rdcache_stream.c | 213 +++ libmailutils/refcount.c | 107 ++ libmailutils/registrar.c | 443 ++++++ libmailutils/rfc2047.c | 314 ++++ libmailutils/secret.c | 135 ++ libmailutils/server.c | 293 ++++ libmailutils/sha1.c | 418 +++++ libmailutils/size_max.h | 31 + libmailutils/socket_stream.c | 122 ++ libmailutils/stdio_stream.c | 83 + libmailutils/stream.c | 1140 ++++++++++++++ libmailutils/stream_printf.c | 32 + libmailutils/stream_vprintf.c | 42 + libmailutils/streamcpy.c | 128 ++ libmailutils/streamref.c | 312 ++++ libmailutils/stripws.c | 33 + libmailutils/strltrim.c | 63 + libmailutils/strrtrim.c | 51 + libmailutils/strskip.c | 50 + libmailutils/syslog.c | 145 ++ libmailutils/system.c | 160 ++ libmailutils/tcp.c | 356 +++++ libmailutils/temp_file_stream.c | 65 + libmailutils/testsuite/.gitignore | 7 + libmailutils/testsuite/Addrs | 644 ++++++++ libmailutils/testsuite/Argcv | 52 + libmailutils/testsuite/Decode | 5 + libmailutils/testsuite/Decode2047 | 36 + libmailutils/testsuite/Encode | Bin 0 -> 256 bytes libmailutils/testsuite/Encode2047 | 27 + libmailutils/testsuite/Mailcap | 195 +++ libmailutils/testsuite/Makefile.am | 92 ++ libmailutils/testsuite/Mime | 212 +++ libmailutils/testsuite/Urls | 629 ++++++++ libmailutils/testsuite/lib/DISTFILES | 1 + libmailutils/testsuite/lib/mailbox.exp | 243 +++ libmailutils/testsuite/mailbox/DISTFILES | 9 + libmailutils/testsuite/mailbox/address.exp | 48 + libmailutils/testsuite/mailbox/argcv.exp | 55 + libmailutils/testsuite/mailbox/base64.exp | 37 + libmailutils/testsuite/mailbox/decode2047.exp | 50 + libmailutils/testsuite/mailbox/encode2047.exp | 62 + libmailutils/testsuite/mailbox/list.exp | 330 ++++ libmailutils/testsuite/mailbox/mailcap.exp | 71 + libmailutils/testsuite/mailbox/mime.exp | 39 + libmailutils/testsuite/mailbox/url.exp | 48 + libmailutils/ticket.c | 243 +++ libmailutils/url.c | 1135 ++++++++++++++ libmailutils/vartab.c | 347 +++++ libmailutils/vasnprintf.c | 87 ++ libmailutils/version.c | 189 +++ libmailutils/wicket.c | 360 +++++ libmailutils/xscript-stream.c | 437 ++++++ 141 files changed, 47188 insertions(+) create mode 100644 libmailutils/.gitignore create mode 100644 libmailutils/Makefile.am create mode 100644 libmailutils/acl.c create mode 100644 libmailutils/address.c create mode 100644 libmailutils/alloc.c create mode 100644 libmailutils/amd.c create mode 100644 libmailutils/argcv.c create mode 100644 libmailutils/asnprintf.c create mode 100644 libmailutils/asprintf.c create mode 100644 libmailutils/assoc.c create mode 100644 libmailutils/attachment.c create mode 100644 libmailutils/attribute.c create mode 100644 libmailutils/auth.c create mode 100644 libmailutils/base64.c create mode 100644 libmailutils/binflt.c create mode 100644 libmailutils/body.c create mode 100644 libmailutils/cfg_driver.c create mode 100644 libmailutils/cfg_format.c create mode 100644 libmailutils/cfg_lexer.l create mode 100644 libmailutils/cfg_parser.y create mode 100644 libmailutils/crlfdot.c create mode 100644 libmailutils/crlfflt.c create mode 100644 libmailutils/cstrcasecmp.c create mode 100644 libmailutils/cstrlower.c create mode 100644 libmailutils/cstrupper.c create mode 100644 libmailutils/daemon.c create mode 100644 libmailutils/date.c create mode 100644 libmailutils/dbgstderr.c create mode 100644 libmailutils/dbgstream.c create mode 100644 libmailutils/dbgsyslog.c create mode 100644 libmailutils/debug.c create mode 100644 libmailutils/diag.c create mode 100644 libmailutils/dot.c create mode 100644 libmailutils/envelope.c create mode 100644 libmailutils/errors create mode 100644 libmailutils/fgetpwent.c create mode 100644 libmailutils/file_stream.c create mode 100644 libmailutils/filter.c create mode 100644 libmailutils/filter_iconv.c create mode 100644 libmailutils/fltstream.c create mode 100644 libmailutils/folder.c create mode 100644 libmailutils/freeitem.c create mode 100644 libmailutils/gdebug.c create mode 100644 libmailutils/gocs.c create mode 100644 libmailutils/hdritr.c create mode 100644 libmailutils/header.c create mode 100644 libmailutils/iostream.c create mode 100644 libmailutils/ipsrv.c create mode 100644 libmailutils/iterator.c create mode 100644 libmailutils/kwd.c create mode 100644 libmailutils/linelenflt.c create mode 100644 libmailutils/list.c create mode 100644 libmailutils/listlist.c create mode 100644 libmailutils/locale.c create mode 100644 libmailutils/locker.c create mode 100644 libmailutils/mailbox.c create mode 100644 libmailutils/mailcap.c create mode 100644 libmailutils/mailer.c create mode 100644 libmailutils/mapfile_stream.c create mode 100644 libmailutils/mbx_default.c create mode 100644 libmailutils/mbxitr.c create mode 100644 libmailutils/md5.c create mode 100644 libmailutils/memory_stream.c create mode 100644 libmailutils/message.c create mode 100644 libmailutils/message_stream.c create mode 100644 libmailutils/mime.c create mode 100644 libmailutils/mimehdr.c create mode 100644 libmailutils/mkfilename.c create mode 100644 libmailutils/monitor.c create mode 100644 libmailutils/msgscan.c create mode 100644 libmailutils/msrv.c create mode 100644 libmailutils/mu_auth.c create mode 100644 libmailutils/muctype.c create mode 100644 libmailutils/muerrno.cin create mode 100644 libmailutils/muerror.c create mode 100644 libmailutils/munre.c create mode 100644 libmailutils/mutil.c create mode 100644 libmailutils/nls.c create mode 100644 libmailutils/nullrec.c create mode 100644 libmailutils/observer.c create mode 100644 libmailutils/opool.c create mode 100644 libmailutils/parse822.c create mode 100644 libmailutils/parsedate.y create mode 100644 libmailutils/permstr.c create mode 100644 libmailutils/prog_stream.c create mode 100644 libmailutils/progmailer.c create mode 100644 libmailutils/property.c create mode 100644 libmailutils/qpflt.c create mode 100644 libmailutils/rdcache_stream.c create mode 100644 libmailutils/refcount.c create mode 100644 libmailutils/registrar.c create mode 100644 libmailutils/rfc2047.c create mode 100644 libmailutils/secret.c create mode 100644 libmailutils/server.c create mode 100644 libmailutils/sha1.c create mode 100644 libmailutils/size_max.h create mode 100644 libmailutils/socket_stream.c create mode 100644 libmailutils/stdio_stream.c create mode 100644 libmailutils/stream.c create mode 100644 libmailutils/stream_printf.c create mode 100644 libmailutils/stream_vprintf.c create mode 100644 libmailutils/streamcpy.c create mode 100644 libmailutils/streamref.c create mode 100644 libmailutils/stripws.c create mode 100644 libmailutils/strltrim.c create mode 100644 libmailutils/strrtrim.c create mode 100644 libmailutils/strskip.c create mode 100644 libmailutils/syslog.c create mode 100644 libmailutils/system.c create mode 100644 libmailutils/tcp.c create mode 100644 libmailutils/temp_file_stream.c create mode 100644 libmailutils/testsuite/.gitignore create mode 100644 libmailutils/testsuite/Addrs create mode 100644 libmailutils/testsuite/Argcv create mode 100644 libmailutils/testsuite/Decode create mode 100644 libmailutils/testsuite/Decode2047 create mode 100644 libmailutils/testsuite/Encode create mode 100644 libmailutils/testsuite/Encode2047 create mode 100644 libmailutils/testsuite/Mailcap create mode 100644 libmailutils/testsuite/Makefile.am create mode 100644 libmailutils/testsuite/Mime create mode 100644 libmailutils/testsuite/Urls create mode 100644 libmailutils/testsuite/lib/DISTFILES create mode 100644 libmailutils/testsuite/lib/mailbox.exp create mode 100644 libmailutils/testsuite/mailbox/DISTFILES create mode 100644 libmailutils/testsuite/mailbox/address.exp create mode 100644 libmailutils/testsuite/mailbox/argcv.exp create mode 100644 libmailutils/testsuite/mailbox/base64.exp create mode 100644 libmailutils/testsuite/mailbox/decode2047.exp create mode 100644 libmailutils/testsuite/mailbox/encode2047.exp create mode 100644 libmailutils/testsuite/mailbox/list.exp create mode 100644 libmailutils/testsuite/mailbox/mailcap.exp create mode 100644 libmailutils/testsuite/mailbox/mime.exp create mode 100644 libmailutils/testsuite/mailbox/url.exp create mode 100644 libmailutils/ticket.c create mode 100644 libmailutils/url.c create mode 100644 libmailutils/vartab.c create mode 100644 libmailutils/vasnprintf.c create mode 100644 libmailutils/version.c create mode 100644 libmailutils/wicket.c create mode 100644 libmailutils/xscript-stream.c (limited to 'libmailutils') diff --git a/libmailutils/.gitignore b/libmailutils/.gitignore new file mode 100644 index 000000000..8ce64ea2d --- /dev/null +++ b/libmailutils/.gitignore @@ -0,0 +1,16 @@ +*.la +*.lo +.deps +.libs +Makefile +Makefile.in +T +_* +.gdbinit +mailutils-config +parsedate.c +*y.output +muerrno.c +cfg_lexer.c +cfg_parser.c +cfg_parser.h diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am new file mode 100644 index 000000000..f28b1bdbc --- /dev/null +++ b/libmailutils/Makefile.am @@ -0,0 +1,186 @@ +## Process this file with GNU Automake to create Makefile.in + +## Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009, +## 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. +## +## This program 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 this program; if not, write to the Free Software +## Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA +## 02110-1301 USA + +INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I${top_srcdir}/libmailutils + +YLWRAP = $(SHELL) $(mu_aux_dir)/gylwrap +AM_YFLAGS=-vt +AM_LFLAGS=-dvp + +SUBDIRS = testsuite + +lib_LTLIBRARIES = libmailutils.la + +localedir = $(datadir)/locale +AM_CPPFLAGS = \ + -DSYSCONFDIR=\"$(sysconfdir)\"\ + -DSITE_VIRTUAL_PWDDIR=\"@SITE_VIRTUAL_PWDDIR@\"\ + -DLOCALEDIR=\"$(localedir)\" + +EXTRA_DIST = \ + errors\ + muerrno.cin\ + parsedate.y\ + fgetpwent.c\ + cfg_lexer.l\ + cfg_parser.y\ + cfg_parser.h + +libmailutils_la_SOURCES = \ + acl.c\ + address.c\ + alloc.c\ + amd.c\ + argcv.c\ + asnprintf.c\ + asprintf.c\ + assoc.c\ + attachment.c\ + attribute.c\ + auth.c\ + base64.c\ + binflt.c\ + body.c\ + cstrcasecmp.c\ + cfg_driver.c\ + cfg_format.c\ + cfg_lexer.c\ + cfg_parser.c\ + crlfdot.c\ + crlfflt.c\ + cstrlower.c\ + cstrupper.c\ + daemon.c\ + date.c\ + dbgstderr.c\ + dbgstream.c\ + dbgsyslog.c\ + debug.c\ + diag.c\ + dot.c\ + envelope.c\ + fgetpwent.c\ + file_stream.c\ + filter.c\ + filter_iconv.c\ + fltstream.c\ + folder.c\ + freeitem.c\ + gdebug.c\ + gocs.c\ + hdritr.c\ + header.c\ + iostream.c\ + iterator.c\ + ipsrv.c\ + kwd.c\ + linelenflt.c\ + list.c\ + listlist.c\ + locale.c\ + locker.c\ + mailbox.c\ + mailcap.c\ + mailer.c\ + mapfile_stream.c\ + mbx_default.c\ + mbxitr.c\ + md5.c\ + message.c\ + memory_stream.c\ + message_stream.c\ + mime.c\ + mimehdr.c\ + mkfilename.c\ + monitor.c\ + msgscan.c\ + msrv.c\ + mu_auth.c\ + muctype.c\ + munre.c\ + mutil.c\ + muerror.c\ + muerrno.c\ + nls.c\ + nullrec.c\ + observer.c\ + opool.c\ + parse822.c\ + parsedate.c\ + permstr.c\ + progmailer.c\ + prog_stream.c\ + property.c\ + qpflt.c\ + rdcache_stream.c\ + registrar.c\ + refcount.c\ + rfc2047.c\ + sha1.c\ + secret.c\ + server.c\ + socket_stream.c\ + stdio_stream.c\ + stream.c\ + stream_printf.c\ + stream_vprintf.c\ + streamcpy.c\ + streamref.c\ + strltrim.c\ + strskip.c\ + stripws.c\ + strrtrim.c\ + syslog.c\ + system.c\ + temp_file_stream.c\ + ticket.c\ + tcp.c\ + url.c\ + vartab.c\ + vasnprintf.c\ + version.c\ + wicket.c\ + xscript-stream.c + +BUILT_SOURCES = parsedate.c muerrno.c cfg_parser.c cfg_parser.h cfg_lexer.c +MOSTLYCLEANFILES= + +parsedate.c: $(srcdir)/parsedate.y + $(YLWRAP) "$(YACC) $(AM_YFLAGS)" $< \ + y.tab.c parsedate.c y.output parsedate.y.output \ + -- -yy pd_yy + +cfg_parser.c cfg_parser.h: $(srcdir)/cfg_parser.y + $(YLWRAP) "$(YACC) $(AM_YFLAGS) -d" $< \ + y.tab.c cfg_parser.c y.tab.h cfg_parser.h \ + y.output cfg_parser.y.output \ + -- -yy mu_cfg_yy + +cfg_lexer.c: $(srcdir)/cfg_lexer.l cfg_parser.h + $(YLWRAP) "$(LEX) $(AM_LFLAGS) $(LFLAGS)" \ + $(srcdir)/cfg_lexer.l lex.yy.c cfg_lexer.c \ + -- -yy mu_cfg_yy + +muerrno.c: errors muerrno.cin + $(AWK) -f $(mu_aux_dir)/generr.awk $^ > $@ + +libmailutils_la_LIBADD = @MU_COMMON_LIBRARIES@ +libmailutils_la_LDFLAGS = -version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@ + diff --git a/libmailutils/acl.c b/libmailutils/acl.c new file mode 100644 index 000000000..a3e3764f2 --- /dev/null +++ b/libmailutils/acl.c @@ -0,0 +1,784 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2007, 2008, 2009, 2010 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct _mu_acl_entry +{ + mu_acl_action_t action; + void *arg; + unsigned netmask; + int salen; + struct sockaddr sa[1]; +}; + +struct _mu_acl +{ + mu_debug_t debug; + mu_list_t aclist; +}; + + +static void +_destroy_acl_entry (void *item) +{ + struct _mu_acl_entry *p = item; + free (p); + /* FIXME: free arg? */ +} + +static size_t +mu_acl_entry_size (int salen) +{ + return sizeof (struct _mu_acl_entry) + salen - sizeof (struct sockaddr); +} + +static int +prepare_sa (struct sockaddr *sa) +{ + switch (sa->sa_family) + { + case AF_INET: + { + struct sockaddr_in *s_in = (struct sockaddr_in *)sa; + s_in->sin_addr.s_addr = ntohl (s_in->sin_addr.s_addr); + break; + } + + case AF_UNIX: + break; + + default: + return 1; + } + return 0; +} + +int +mu_acl_entry_create (struct _mu_acl_entry **pent, + mu_acl_action_t action, void *data, + struct sockaddr *sa, int salen, unsigned long netmask) +{ + struct _mu_acl_entry *p = malloc (mu_acl_entry_size (salen)); + if (!p) + return EINVAL; + + p->action = action; + p->arg = data; + p->netmask = ntohl (netmask); + p->salen = salen; + memcpy (p->sa, sa, salen); + if (prepare_sa (p->sa)) + { + free (p); + return EINVAL; + } + *pent = p; + return 0; +} + + +int +mu_acl_create (mu_acl_t *pacl) +{ + int rc; + mu_acl_t acl; + mu_log_level_t level; + + acl = calloc (1, sizeof (*acl)); + if (!acl) + return errno; + rc = mu_list_create (&acl->aclist); + if (rc) + free (acl); + else + *pacl = acl; + mu_list_set_destroy_item (acl->aclist, _destroy_acl_entry); + + level = mu_global_debug_level ("acl"); + if (level) + { + int status = mu_debug_create (&acl->debug, NULL); + if (status == 0) + mu_debug_set_level (acl->debug, level); + } + + return rc; +} + +int +mu_acl_count (mu_acl_t acl, size_t *pcount) +{ + if (!acl) + return EINVAL; + return mu_list_count (acl->aclist, pcount); +} + +int +mu_acl_destroy (mu_acl_t *pacl) +{ + mu_acl_t acl; + if (!pacl || !*pacl) + return EINVAL; + acl = *pacl; + mu_list_destroy (&acl->aclist); + mu_debug_destroy (&acl->debug, NULL); + free (acl); + *pacl = acl; + return 0; +} + +int +mu_acl_get_debug (mu_acl_t acl, mu_debug_t *pdebug) +{ + if (!acl) + return EINVAL; + if (!pdebug) + return MU_ERR_OUT_NULL; + *pdebug = acl->debug; + return 0; +} + +int +mu_acl_set_debug (mu_acl_t acl, mu_debug_t debug) +{ + if (!acl) + return EINVAL; + acl->debug = debug; + return 0; +} + +int +mu_acl_get_iterator (mu_acl_t acl, mu_iterator_t *pitr) +{ + if (!acl) + return EINVAL; + return mu_list_get_iterator (acl->aclist, pitr); +} + +int +mu_acl_append (mu_acl_t acl, mu_acl_action_t act, + void *data, struct sockaddr *sa, int salen, + unsigned long netmask) +{ + int rc; + struct _mu_acl_entry *ent; + + if (!acl) + return EINVAL; + rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask); + if (rc) + { + MU_DEBUG1 (acl->debug, MU_DEBUG_ERROR, "Cannot allocate ACL entry: %s", + mu_strerror (rc)); + return ENOMEM; + } + + rc = mu_list_append (acl->aclist, ent); + if (rc) + { + MU_DEBUG1 (acl->debug, MU_DEBUG_ERROR, "Cannot append ACL entry: %s", + mu_strerror (rc)); + free (ent); + } + return rc; +} + +int +mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data, + struct sockaddr *sa, int salen, unsigned long netmask) +{ + int rc; + struct _mu_acl_entry *ent; + + if (!acl) + return EINVAL; + rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask); + if (rc) + { + MU_DEBUG1 (acl->debug, MU_DEBUG_ERROR, "Cannot allocate ACL entry: %s", + mu_strerror (rc)); + return ENOMEM; + } + rc = mu_list_prepend (acl->aclist, ent); + if (rc) + { + MU_DEBUG1 (acl->debug, MU_DEBUG_ERROR, "Cannot prepend ACL entry: %s", + mu_strerror (rc)); + free (ent); + } + return rc; +} + +int +mu_acl_insert (mu_acl_t acl, size_t pos, int before, + mu_acl_action_t act, void *data, + struct sockaddr *sa, int salen, unsigned long netmask) +{ + int rc; + void *ptr; + struct _mu_acl_entry *ent; + + if (!acl) + return EINVAL; + + rc = mu_list_get (acl->aclist, pos, &ptr); + if (rc) + { + MU_DEBUG1 (acl->debug, MU_DEBUG_ERROR, "No such entry %lu", + (unsigned long) pos); + return rc; + } + rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask); + if (!ent) + { + MU_DEBUG1 (acl->debug, MU_DEBUG_ERROR, "Cannot allocate ACL entry: %s", + mu_strerror (rc)); + return ENOMEM; + } + rc = mu_list_insert (acl->aclist, ptr, ent, before); + if (rc) + { + MU_DEBUG1 (acl->debug, MU_DEBUG_ERROR, "Cannot insert ACL entry: %s", + mu_strerror (rc)); + free (ent); + } + return rc; +} + + +static mu_kwd_t action_tab[] = { + { "accept", mu_acl_accept }, + { "deny", mu_acl_deny }, + { "log", mu_acl_log }, + { "exec", mu_acl_exec }, + { "ifexec", mu_acl_ifexec }, + { NULL } +}; + +int +mu_acl_action_to_string (mu_acl_action_t act, const char **pstr) +{ + return mu_kwd_xlat_tok (action_tab, act, pstr); +} + +int +mu_acl_string_to_action (const char *str, mu_acl_action_t *pres) +{ + int x; + int rc = mu_kwd_xlat_name (action_tab, str, &x); + if (rc == 0) + *pres = x; + return rc; +} + +#define MU_S_UN_NAME(sa, salen) \ + ((salen < mu_offsetof (struct sockaddr_un,sun_path)) ? "" : (sa)->sun_path) + +static void +debug_sockaddr (mu_debug_t dbg, mu_log_level_t lvl, struct sockaddr *sa, + int salen) +{ + switch (sa->sa_family) + { + case AF_INET: + { + struct sockaddr_in s_in = *(struct sockaddr_in *)sa; + s_in.sin_addr.s_addr = htonl (s_in.sin_addr.s_addr); + mu_debug_printf (dbg, lvl, "{AF_INET %s:%d}", + inet_ntoa (s_in.sin_addr), ntohs (s_in.sin_port)); + break; + } + + case AF_UNIX: + { + struct sockaddr_un *s_un = (struct sockaddr_un *)sa; + if (MU_S_UN_NAME(s_un, salen)[0] == 0) + mu_debug_printf (dbg, lvl, "{AF_UNIX}"); + else + mu_debug_printf (dbg, lvl, "{AF_UNIX %s}", s_un->sun_path); + break; + } + + default: + mu_debug_printf (dbg, lvl, "{Unsupported family: %d}", sa->sa_family); + } +} + +size_t +mu_stpcpy (char **pbuf, size_t *psize, const char *src) +{ + size_t slen = strlen (src); + if (pbuf == NULL || *pbuf == NULL) + return slen; + else + { + char *buf = *pbuf; + size_t size = *psize; + if (size > slen) + size = slen; + memcpy (buf, src, size); + *psize -= size; + *pbuf += size; + if (*psize) + **pbuf = 0; + else + (*pbuf)[-1] = 0; + return size; + } +} + +void +mu_sockaddr_to_str (const struct sockaddr *sa, int salen, + char *bufptr, size_t buflen, + size_t *plen) +{ + char *nbuf; + size_t len = 0; + switch (sa->sa_family) + { + case AF_INET: + { + struct sockaddr_in s_in = *(struct sockaddr_in *)sa; + len += mu_stpcpy (&bufptr, &buflen, inet_ntoa (s_in.sin_addr)); + len += mu_stpcpy (&bufptr, &buflen, ":"); + if (mu_asprintf (&nbuf, "%hu", ntohs (s_in.sin_port)) == 0) + { + len += mu_stpcpy (&bufptr, &buflen, nbuf); + free (nbuf); + } + break; + } + + case AF_UNIX: + { + struct sockaddr_un *s_un = (struct sockaddr_un *)sa; + if (MU_S_UN_NAME(s_un, salen)[0] == 0) + len += mu_stpcpy (&bufptr, &buflen, "anonymous socket"); + else + { + len += mu_stpcpy (&bufptr, &buflen, "socket "); + len += mu_stpcpy (&bufptr, &buflen, s_un->sun_path); + } + break; + } + + default: + len += mu_stpcpy (&bufptr, &buflen, "{Unsupported family"); + if (mu_asprintf (&nbuf, ": %d", sa->sa_family) == 0) + { + len += mu_stpcpy (&bufptr, &buflen, nbuf); + free (nbuf); + } + len += mu_stpcpy (&bufptr, &buflen, "}"); + } + if (plen) + *plen = len + 1; +} + +char * +mu_sockaddr_to_astr (const struct sockaddr *sa, int salen) +{ + size_t size; + char *p; + + mu_sockaddr_to_str (sa, salen, NULL, 0, &size); + p = malloc (size); + if (p) + mu_sockaddr_to_str (sa, salen, p, size, NULL); + return p; +} + +int +_acl_match (mu_debug_t debug, struct _mu_acl_entry *ent, struct sockaddr *sa, + int salen) +{ +#define RESMATCH(word) \ + if (mu_debug_check_level (debug, MU_DEBUG_TRACE0)) \ + mu_debug_printf (debug, MU_DEBUG_TRACE0, "%s; ", word); + + if (mu_debug_check_level (debug, MU_DEBUG_TRACE0)) + { + struct in_addr a; + + __MU_DEBUG1 (debug, MU_DEBUG_TRACE0, "%s", "Does "); + debug_sockaddr (debug, MU_DEBUG_TRACE0, sa, salen); + mu_debug_printf (debug, MU_DEBUG_TRACE0, " match "); + debug_sockaddr (debug, MU_DEBUG_TRACE0, ent->sa, salen); + a.s_addr = ent->netmask; + a.s_addr = htonl (a.s_addr); + mu_debug_printf (debug, MU_DEBUG_TRACE0, " netmask %s? ", inet_ntoa (a)); + } + + if (ent->sa->sa_family != sa->sa_family) + { + RESMATCH ("no"); + return 1; + } + + switch (ent->sa->sa_family) + { + case AF_INET: + { + struct sockaddr_in *sin_ent = (struct sockaddr_in *)ent->sa; + struct sockaddr_in *sin_item = (struct sockaddr_in *)sa; + + if (sin_ent->sin_addr.s_addr != + (sin_item->sin_addr.s_addr & ent->netmask)) + { + RESMATCH ("no (address differs)"); + return 1; + } + + if (sin_ent->sin_port && sin_item->sin_port + && sin_ent->sin_port != sin_item->sin_port) + { + RESMATCH ("no (port differs)"); + return 1; + } + break; + } + + case AF_UNIX: + { + struct sockaddr_un *sun_ent = (struct sockaddr_un *)ent->sa; + struct sockaddr_un *sun_item = (struct sockaddr_un *)sa; + + if (MU_S_UN_NAME (sun_ent, ent->salen)[0] + && MU_S_UN_NAME (sun_item, salen)[0] + && strcmp (sun_ent->sun_path, sun_item->sun_path)) + { + RESMATCH ("no"); + return 1; + } + break; + } + } + + RESMATCH ("yes"); + return 0; +} + +struct run_closure +{ + unsigned idx; + mu_debug_t debug; + struct sockaddr *sa; + int salen; + mu_acl_result_t *result; +}; + +static int +_expand_aclno (const char *name, void *data, char **p) +{ + struct run_closure *rp = data; + /*FIXME: memory leak*/ + return mu_asprintf (p, "%u", rp->idx); +} + +#if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX) +# define getmaxfd() sysconf (_SC_OPEN_MAX) +#elif defined (HAVE_GETDTABLESIZE) +# define getmaxfd() getdtablesize () +#else +# define getmaxfd() 64 +#endif + +static int +expand_arg (const char *cmdline, struct run_closure *rp, char **s) +{ + int rc; + mu_vartab_t vtab; + + MU_DEBUG1 (rp->debug, MU_DEBUG_TRACE0, "Expanding \"%s\" => ", cmdline); + + mu_vartab_create (&vtab); + mu_vartab_define_exp (vtab, "aclno", _expand_aclno, NULL, rp); + switch (rp->sa->sa_family) + { + case AF_INET: + { + struct sockaddr_in *s_in = (struct sockaddr_in *)rp->sa; + struct in_addr addr = s_in->sin_addr; + char *p; + + mu_vartab_define (vtab, "family", "AF_INET", 1); + addr.s_addr = htonl (addr.s_addr); + mu_vartab_define (vtab, "address", inet_ntoa (addr), 0); + if (mu_asprintf (&p, "%hu", ntohs (s_in->sin_port)) == 0) + { + mu_vartab_define (vtab, "port", p, 0); + free (p); + } + } + break; + + case AF_UNIX: + { + struct sockaddr_un *s_un = (struct sockaddr_un *)rp->sa; + + mu_vartab_define (vtab, "family", "AF_UNIX", 1); + mu_vartab_define (vtab, "address", s_un->sun_path, 1); + } + break; + } + + rc = mu_vartab_expand (vtab, cmdline, s); + mu_vartab_destroy (&vtab); + + if (rc == 0) + MU_DEBUG1 (rp->debug, MU_DEBUG_TRACE0, "\"%s\". ", *s); + else + MU_DEBUG (rp->debug, MU_DEBUG_TRACE0, "failed. "); + return rc; +} + +static int +spawn_prog (const char *cmdline, int *pstatus, struct run_closure *rp) +{ + char *s; + pid_t pid; + + if (expand_arg (cmdline, rp, &s)) + s = strdup (cmdline); + + pid = fork (); + if (pid == 0) + { + int i; + int argc; + char **argv; + + mu_argcv_get (s, " \t", NULL, &argc, &argv); + for (i = getmaxfd (); i > 2; i--) + close (i); + execvp (argv[0], argv); + exit (127); + } + + free (s); + + if (pid == (pid_t)-1) + { + MU_DEBUG1 (rp->debug, MU_DEBUG_ERROR, "cannot fork: %s", + mu_strerror (errno)); + return errno; + } + + if (pstatus) + { + int status; + waitpid (pid, &status, 0); + if (WIFEXITED (status)) + { + status = WEXITSTATUS (status); + MU_DEBUG1 (rp->debug, MU_DEBUG_TRACE0, + "Program finished with code %d.", status); + *pstatus = status; + } + else if (WIFSIGNALED (status)) + { + MU_DEBUG1 (rp->debug, MU_DEBUG_ERROR, + "Program terminated on signal %d.", + WTERMSIG (status)); + return MU_ERR_PROCESS_SIGNALED; + } + else + return MU_ERR_PROCESS_UNKNOWN_FAILURE; + } + + return 0; +} + + +int +_run_entry (void *item, void *data) +{ + int status = 0; + struct _mu_acl_entry *ent = item; + struct run_closure *rp = data; + + rp->idx++; + + if (mu_debug_check_level (rp->debug, MU_DEBUG_TRACE0)) + { + const char *s = "undefined"; + mu_acl_action_to_string (ent->action, &s); + __MU_DEBUG2 (rp->debug, MU_DEBUG_TRACE0, "%d:%s: ", rp->idx, s); + } + + if (_acl_match (rp->debug, ent, rp->sa, rp->salen) == 0) + { + switch (ent->action) + { + case mu_acl_accept: + *rp->result = mu_acl_result_accept; + status = 1; + break; + + case mu_acl_deny: + *rp->result = mu_acl_result_deny; + status = 1; + break; + + case mu_acl_log: + { + char *s; + mu_debug_t dbg = NULL; + mu_diag_get_debug (&dbg); + if (ent->arg && expand_arg (ent->arg, rp, &s) == 0) + { + mu_debug_printf (dbg, MU_DIAG_INFO, "%s\n", s); + free (s); + } + else + { + debug_sockaddr (dbg, MU_DIAG_INFO, rp->sa, rp->salen); + mu_debug_printf (dbg, MU_DIAG_INFO, "\n"); + } + } + break; + + case mu_acl_exec: + spawn_prog (ent->arg, NULL, rp); + break; + + case mu_acl_ifexec: + { + int prog_status; + int rc = spawn_prog (ent->arg, &prog_status, rp); + if (rc == 0) + { + switch (prog_status) + { + case 0: + *rp->result = mu_acl_result_accept; + status = 1; + break; + + case 1: + *rp->result = mu_acl_result_deny; + status = 1; + } + } + } + break; + } + } + + if (mu_debug_check_level (rp->debug, MU_DEBUG_TRACE0)) + mu_debug_printf (rp->debug, MU_DEBUG_TRACE0, "\n"); + + return status; +} + +int +mu_acl_check_sockaddr (mu_acl_t acl, const struct sockaddr *sa, int salen, + mu_acl_result_t *pres) +{ + struct run_closure r; + + if (!acl) + return EINVAL; + + r.sa = malloc (salen); + if (!r.sa) + return ENOMEM; + memcpy (r.sa, sa, salen); + if (prepare_sa (r.sa)) + { + free (r.sa); + return EINVAL; + } + r.salen = salen; + + if (mu_debug_check_level (acl->debug, MU_DEBUG_TRACE0)) + { + __MU_DEBUG1 (acl->debug, MU_DEBUG_TRACE0, "%s", "Checking sockaddr "); + debug_sockaddr (acl->debug, MU_DEBUG_TRACE0, r.sa, r.salen); + mu_debug_printf (acl->debug, MU_DEBUG_TRACE0, "\n"); + } + + r.idx = 0; + r.debug = acl->debug; + r.result = pres; + *r.result = mu_acl_result_undefined; + mu_list_do (acl->aclist, _run_entry, &r); + free (r.sa); + return 0; +} + +int +mu_acl_check_inaddr (mu_acl_t acl, const struct in_addr *inp, + mu_acl_result_t *pres) +{ + struct sockaddr_in cs; + int len = sizeof cs; + + cs.sin_family = AF_INET; + cs.sin_addr = *inp; + cs.sin_addr.s_addr = ntohl (cs.sin_addr.s_addr); + return mu_acl_check_sockaddr (acl, (struct sockaddr *) &cs, len, pres); +} + +int +mu_acl_check_ipv4 (mu_acl_t acl, unsigned int addr, mu_acl_result_t *pres) +{ + struct in_addr in; + + in.s_addr = addr; + return mu_acl_check_inaddr (acl, &in, pres); +} + +int +mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t *pres) +{ + struct sockaddr_in cs; + socklen_t len = sizeof cs; + + if (getpeername (fd, (struct sockaddr *) &cs, &len) < 0) + { + MU_DEBUG1 (acl->debug, MU_DEBUG_ERROR, + "Cannot obtain IP address of client: %s", + mu_strerror (errno)); + return MU_ERR_FAILURE; + } + + return mu_acl_check_sockaddr (acl, (struct sockaddr *) &cs, len, pres); +} + diff --git a/libmailutils/address.c b/libmailutils/address.c new file mode 100644 index 000000000..cd151c141 --- /dev/null +++ b/libmailutils/address.c @@ -0,0 +1,595 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2005, 2006, 2007, 2009, 2010 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, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301 USA */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +/* Get email addresses from rfc822 address. */ +int +mu_address_create_hint (mu_address_t *a, const char *s, mu_address_t hint, + int hflags) +{ + /* 'a' must exist, and can't already have been initialized + */ + int status; + + if (!a) + return MU_ERR_OUT_PTR_NULL; + + if (!s) + return EINVAL; + + *a = NULL; + status = mu_parse822_address_list (a, s, hint, hflags); + if (status == 0) + { + /* And address-list may contain 0 addresses but parse correctly. + */ + if (!*a) + return MU_ERR_EMPTY_ADDRESS; + + (*a)->addr = strdup (s); + if (!(*a)->addr) + { + mu_address_destroy (a); + return ENOMEM; + } + } + return status; +} + +int +mu_address_create (mu_address_t *a, const char *s) +{ + struct mu_address hint; + const char *d; + mu_get_user_email_domain (&d); + hint.domain = (char*) d; + return mu_address_create_hint (a, s, &hint, MU_ADDR_HINT_DOMAIN); +} + +/* Get email addresses from array of rfc822 addresses. + FIXME: No hints? */ +int +mu_address_createv (mu_address_t *a, const char *sv[], size_t len) +{ + int status = 0; + size_t buflen = 0; + char *buf = 0; + size_t i; + + if (!a) + return MU_ERR_OUT_PTR_NULL; + + if (!sv) + return EINVAL; + + if (len == (size_t) - 1) + { + const char **vp = sv; + + len = 0; + + for (len = 0; *vp; vp++, len++) + ; + } + + if (len == 0) + return EINVAL; + + for (i = 0; i < len; i++) + { + /* NULL strings are allowed */ + if (sv[i]) + buflen += strlen (sv[i]); + } + + buflen += (len - 1) * strlen (", "); + buflen += 1; /* Termination null. */ + + buf = malloc (buflen); + + if (!buf) + return ENOMEM; + + for (i = 0, buf[0] = '\0'; i < len; i++) + { + if (i != 0) + strcat (buf, ", "); + + if (sv[i]) + strcat (buf, sv[i]); + } + + status = mu_address_create (a, buf); + + free (buf); + + return status; +} + +void +mu_address_destroy (mu_address_t *paddress) +{ + if (paddress && *paddress) + { + mu_address_t address = *paddress; + mu_address_t current; + for (; address; address = current) + { + if (address->addr) + free (address->addr); + if (address->comments) + free (address->comments); + if (address->personal) + free (address->personal); + if (address->email) + free (address->email); + if (address->local_part) + free (address->local_part); + if (address->domain) + free (address->domain); + if (address->route) + free (address->route); + current = address->next; + free (address); + } + *paddress = NULL; + } +} + +int +mu_address_concatenate (mu_address_t to, mu_address_t *from) +{ + if (!to || !from || !*from) + return EINVAL; + + while (to->next) + to = to->next; + + assert (to && !to->next); + + to->next = *from; + *from = NULL; + + /* discard the current string cache as it is now inaccurate */ + if (to->addr) + { + free (to->addr); + to->addr = NULL; + } + + to = to->next; + + /* only the first address must have a cache */ + if (to->addr) + { + free (to->addr); + to->addr = NULL; + } + + return 0; +} + +mu_address_t +_address_get_nth (mu_address_t addr, size_t no) +{ + int i; + + for (i = 1; addr; addr = addr->next, i++) + if (i == no) + break; + return addr; +} + +int +mu_address_get_nth (mu_address_t addr, size_t no, mu_address_t *pret) +{ + mu_address_t subaddr = _address_get_nth (addr, no); + if (!subaddr) + return MU_ERR_NOENT; + *pret = mu_address_dup (subaddr); + return 0; +} + + +/* General accessors: */ +#define AC4(a,b,c,d) a ## b ## c ## d +#define ACCESSOR(action,field) AC4(mu_address_,action,_,field) + +#define DECL_SET(field) \ +int \ +ACCESSOR(set, field) (mu_address_t addr, size_t no, const char *buf) \ +{ \ + char *s; \ + mu_address_t subaddr; \ + \ + if (addr == NULL) \ + return EINVAL; \ + \ + subaddr = _address_get_nth (addr, no); \ + if (!subaddr) \ + return MU_ERR_NOENT; \ + \ + s = strdup (buf); \ + if (!s) \ + return errno; \ + \ + free (subaddr->field); \ + subaddr->field = s; \ + \ + return 0; \ +} + +#define DECL_SGET(field) \ +int \ +ACCESSOR(sget,field) (mu_address_t addr, size_t no, char const **sptr) \ +{ \ + mu_address_t subaddr; \ + \ + if (addr == NULL) \ + return EINVAL; \ + \ + subaddr = _address_get_nth (addr, no); \ + if (!subaddr) \ + return MU_ERR_NOENT; \ + *sptr = subaddr->field; \ + return 0; \ +} + +#define DECL_GET(field) \ +int \ +ACCESSOR(get,field) (mu_address_t addr, size_t no, char *buf, size_t len, \ + size_t *n) \ +{ \ + size_t i; \ + const char *str; \ + int status = ACCESSOR(sget, field) (addr, no, &str); \ + \ + if (status) \ + return status; \ + \ + i = mu_cpystr (buf, str, len); \ + if (n) \ + *n = i; \ + return 0; \ +} + +#define DECL_AGET(field) \ +int \ +ACCESSOR(aget, field) (mu_address_t addr, size_t no, char **buf) \ +{ \ + const char *str; \ + int status = ACCESSOR(sget, field) (addr, no, &str); \ + \ + if (status) \ + return status; \ + \ + if (str) \ + { \ + *buf = strdup (str); \ + if (!*buf) \ + status = ENOMEM; \ + } \ + else \ + *buf = NULL; \ + return status; \ +} + +#define DECL_ACCESSORS(field) \ +DECL_SET(field) \ +DECL_SGET(field) \ +DECL_GET(field) \ +DECL_AGET(field) + + + +/* Personal part */ +DECL_ACCESSORS(personal) +/* Comments */ +DECL_ACCESSORS(comments) +/* Email */ +DECL_ACCESSORS(email) +/* Local part */ +DECL_ACCESSORS(local_part) +/* Domain */ +DECL_ACCESSORS(domain) +/* Route */ +DECL_ACCESSORS(route) + + + +#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) + { + if (addr->email) + { + 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++; + } + } + format_char (0); + return rc; +} + +static int +_address_is_group (mu_address_t addr) +{ + if (addr->personal && !addr->local_part && !addr->domain) + return 1; + return 0; +} + +static int +_address_is_email (mu_address_t addr) +{ + if (addr->email) + return 1; + return 0; +} + +static int +_address_is_unix_mailbox (mu_address_t addr) +{ + if (addr->local_part && !addr->email) + return 1; + return 0; +} + +int +mu_address_is_group (mu_address_t addr, size_t no, int *yes) +{ + mu_address_t subaddr; + + if (addr == NULL) + return EINVAL; + + subaddr = _address_get_nth (addr, no); + if (!subaddr) + return MU_ERR_NOENT; + + if (yes) + *yes = _address_is_group (subaddr); + return 0; +} + +int +mu_address_to_string (mu_address_t addr, char *buf, size_t len, size_t *n) +{ + size_t i; + if (addr == NULL) + return EINVAL; + if (buf) + *buf = '\0'; + + if (!addr->addr) + { + 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); + } + + i = mu_cpystr (buf, addr->addr, len); + if (n) + *n = i; + return 0; +} + +int +mu_address_get_count (mu_address_t addr, size_t *pcount) +{ + size_t j; + for (j = 0; addr; addr = addr->next, j++) + ; + if (pcount) + *pcount = j; + return 0; +} + +int +mu_address_get_group_count (mu_address_t addr, size_t *pcount) +{ + size_t j; + for (j = 0; addr; addr = addr->next) + { + if (_address_is_group (addr)) + j++; + } + if (pcount) + *pcount = j; + return 0; +} + +int +mu_address_get_email_count (mu_address_t addr, size_t *pcount) +{ + size_t j; + for (j = 0; addr; addr = addr->next) + { + if (_address_is_email (addr)) + j++; + } + if (pcount) + *pcount = j; + return 0; +} + +int +mu_address_get_unix_mailbox_count (mu_address_t addr, size_t *pcount) +{ + size_t j; + for (j = 0; addr; addr = addr->next) + { + if (_address_is_unix_mailbox (addr)) + j++; + } + if (pcount) + *pcount = j; + return 0; +} + +int +mu_address_contains_email (mu_address_t addr, const char *email) +{ + for (; addr; addr = addr->next) + if (mu_c_strcasecmp (addr->email, email) == 0) + return 1; + return 0; +} + +mu_address_t +mu_address_dup (mu_address_t src) +{ + mu_address_t dst = calloc (1, sizeof (*dst)); + + if (!dst) + return NULL; + + /* FIXME: How about: + if (src->addr) + dst->addr = strdup (src->addr); + ? + */ + if (src->comments) + dst->comments = strdup (src->comments); + if (src->personal) + dst->personal = strdup (src->personal); + if (src->email) + dst->email = strdup (src->email); + if (src->local_part) + dst->local_part = strdup (src->local_part); + if (src->domain) + dst->domain = strdup (src->domain); + if (src->route) + dst->route = strdup (src->route); + + return dst; +} + +int +mu_address_union (mu_address_t *a, mu_address_t b) +{ + mu_address_t last = NULL; + + if (!a || !b) + return EINVAL; + + if (!*a) + { + *a = mu_address_dup (b); + if (!*a) + return ENOMEM; + last = *a; + b = b->next; + } + else + { + if ((*a)->addr) + { + free ((*a)->addr); + (*a)->addr = NULL; + } + for (last = *a; last->next; last = last->next) + ; + } + + for (; b; b = b->next) + if (!mu_address_contains_email (*a, b->email)) + { + mu_address_t next = mu_address_dup (b); + if (!next) + return ENOMEM; + last->next = next; + last = next; + } + return 0; +} + diff --git a/libmailutils/alloc.c b/libmailutils/alloc.c new file mode 100644 index 000000000..05801bb1a --- /dev/null +++ b/libmailutils/alloc.c @@ -0,0 +1,116 @@ +/* Error-proof memory allocation functions. + Copyright (C) 2008, 2010 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, 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 GNU Mailutils. If not, see . */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include +#include +#include +#include + +void (*mu_alloc_die_hook) (void) = NULL; + +void +mu_alloc_die () +{ + if (mu_alloc_die_hook) + mu_alloc_die_hook (); + mu_error (_("Not enough memory")); + abort (); +} + +void * +mu_alloc (size_t size) +{ + void *p = malloc (size); + if (!p) + mu_alloc_die (); + return p; +} + +void * +mu_calloc (size_t nmemb, size_t size) +{ + void *p = calloc (nmemb, size); + if (!p) + mu_alloc_die (); + return p; +} + +void * +mu_zalloc (size_t size) +{ + void *p = mu_alloc (size); + memset (p, 0, size); + return p; +} + +void * +mu_realloc (void *p, size_t size) +{ + void *newp = realloc (p, size); + if (!newp) + mu_alloc_die (); + return newp; +} + +char * +mu_strdup (const char *s) +{ + char *news = strdup (s); + if (!news) + mu_alloc_die (); + return news; +} + +/* Copied from gnulib */ +void * +mu_2nrealloc (void *p, size_t *pn, size_t s) +{ + size_t n = *pn; + + if (!p) + { + if (!n) + { + /* The approximate size to use for initial small allocation + requests, when the invoking code specifies an old size of + zero. 64 bytes is the largest "small" request for the + GNU C library malloc. */ + enum { DEFAULT_MXFAST = 64 }; + + n = DEFAULT_MXFAST / s; + n += !n; + } + } + else + { + /* Set N = ceil (1.5 * N) so that progress is made if N == 1. + Check for overflow, so that N * S stays in size_t range. + The check is slightly conservative, but an exact check isn't + worth the trouble. */ + if ((size_t) -1 / 3 * 2 / s <= n) + mu_alloc_die (); + n += (n + 1) / 2; + } + + *pn = n; + return mu_realloc (p, n * s); +} + diff --git a/libmailutils/amd.c b/libmailutils/amd.c new file mode 100644 index 000000000..3cf3dde6c --- /dev/null +++ b/libmailutils/amd.c @@ -0,0 +1,1925 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, + 2008, 2009, 2010 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, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301 USA */ + +/* Mailutils Abstract Mail Directory Layer + First draft by Sergey Poznyakoff. + Thanks Tang Yong Ping for initial + patch (although not used here). + + This module provides basic support for "MH" and "Maildir" formats. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WITH_PTHREAD +# ifdef HAVE_PTHREAD_H +# ifndef _XOPEN_SOURCE +# define _XOPEN_SOURCE 500 +# endif +# include +# endif +#endif + +#include +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void amd_destroy (mu_mailbox_t mailbox); +static int amd_open (mu_mailbox_t, int); +static int amd_close (mu_mailbox_t); +static int amd_get_message (mu_mailbox_t, size_t, mu_message_t *); +static int amd_quick_get_message (mu_mailbox_t mailbox, mu_message_qid_t qid, + mu_message_t *pmsg); +static int amd_append_message (mu_mailbox_t, mu_message_t); +static int amd_messages_count (mu_mailbox_t, size_t *); +static int amd_messages_recent (mu_mailbox_t, size_t *); +static int amd_message_unseen (mu_mailbox_t, size_t *); +static int amd_expunge (mu_mailbox_t); +static int amd_sync (mu_mailbox_t); +static int amd_uidnext (mu_mailbox_t mailbox, size_t *puidnext); +static int amd_uidvalidity (mu_mailbox_t, unsigned long *); +static int amd_scan (mu_mailbox_t, size_t, size_t *); +static int amd_is_updated (mu_mailbox_t); +static int amd_get_size (mu_mailbox_t, mu_off_t *); + +static int amd_body_size (mu_body_t body, size_t *psize); +static int amd_body_lines (mu_body_t body, size_t *plines); + +static int amd_header_fill (void *data, char **pbuf, size_t *plen); + +static int amd_get_attr_flags (mu_attribute_t attr, int *pflags); +static int amd_set_attr_flags (mu_attribute_t attr, int flags); +static int amd_unset_attr_flags (mu_attribute_t attr, int flags); + +static void _amd_message_delete (struct _amd_data *amd, + struct _amd_message *msg); +static int amd_pool_open (struct _amd_message *mhm); +static int amd_pool_open_count (struct _amd_data *amd); +static void amd_pool_flush (struct _amd_data *amd); +static struct _amd_message **amd_pool_lookup (struct _amd_message *mhm); + +static int amd_envelope_date (mu_envelope_t envelope, char *buf, size_t len, + size_t *psize); +static int amd_envelope_sender (mu_envelope_t envelope, char *buf, size_t len, + size_t *psize); + + +static int amd_body_stream_read (mu_stream_t str, char *buffer, + size_t buflen, + size_t *pnread); +static int amd_body_stream_readdelim (mu_stream_t is, + char *buffer, size_t buflen, + int delim, + size_t *pnread); +static int amd_body_stream_size (mu_stream_t str, mu_off_t *psize); +static int amd_body_stream_seek (mu_stream_t str, mu_off_t off, + mu_off_t *presult); + +struct _amd_body_stream +{ + struct _mu_stream stream; + mu_body_t body; + mu_off_t off; +}; + + +/* Operations on message array */ + +/* Perform binary search for message MSG on a segment of message array + of AMD between the indexes FIRST and LAST inclusively. + If found, return 0 and store index of the located entry in the + variable PRET. Otherwise, return 1 and place into PRET index of + the nearest array element that is less than MSG (in the sense of + amd->msg_cmp) + Indexes are zero-based. */ + +static int +amd_msg_bsearch (struct _amd_data *amd, mu_off_t first, mu_off_t last, + struct _amd_message *msg, + mu_off_t *pret) +{ + mu_off_t mid; + int rc; + + if (last < first) + return 1; + + mid = (first + last) / 2; + rc = amd->msg_cmp (amd->msg_array[mid], msg); + if (rc > 0) + return amd_msg_bsearch (amd, first, mid-1, msg, pret); + *pret = mid; + if (rc < 0) + return amd_msg_bsearch (amd, mid+1, last, msg, pret); + /* else */ + return 0; +} + +/* Search for message MSG in the message array of AMD. + If found, return 0 and store index of the located entry in the + variable PRET. Otherwise, return 1 and place into PRET index of + the array element that is less than MSG (in the sense of + amd->msg_cmp) + Index returned in PRET is 1-based, so *PRET == 0 means that MSG + is less than the very first element of the message array. + + In other words, when amd_msg_lookup() returns 1, the value in *PRET + can be regarded as a 0-based index of the array slot where MSG can + be inserted */ + +int +amd_msg_lookup (struct _amd_data *amd, struct _amd_message *msg, + size_t *pret) +{ + int rc; + mu_off_t i; + + if (amd->msg_count == 0) + { + *pret = 0; + return 1; + } + + rc = amd->msg_cmp (msg, amd->msg_array[0]); + if (rc < 0) + { + *pret = 0; + return 1; + } + else if (rc == 0) + { + *pret = 1; + return 0; + } + + rc = amd->msg_cmp (msg, amd->msg_array[amd->msg_count - 1]); + if (rc > 0) + { + *pret = amd->msg_count; + return 1; + } + else if (rc == 0) + { + *pret = amd->msg_count; + return 0; + } + + rc = amd_msg_bsearch (amd, 0, amd->msg_count - 1, msg, &i); + *pret = i + 1; + return rc; +} + +#define AMD_MSG_INC 64 + +/* Prepare the message array for insertion of a new message + at position INDEX (zero based), by moving its contents + one slot to the right. If necessary, expand the array by + AMD_MSG_INC */ +int +amd_array_expand (struct _amd_data *amd, size_t index) +{ + if (amd->msg_count == amd->msg_max) + { + struct _amd_message **p; + + amd->msg_max += AMD_MSG_INC; /* FIXME: configurable? */ + p = realloc (amd->msg_array, amd->msg_max * amd->msg_size); + if (!p) + { + amd->msg_max -= AMD_MSG_INC; + return ENOMEM; + } + amd->msg_array = p; + } + memmove (&amd->msg_array[index+1], &amd->msg_array[index], + (amd->msg_count-index) * amd->msg_size); + amd->msg_count++; + return 0; +} + +/* Shrink the message array by removing element at INDEX-1 and + shifting left by one position all the elements on the right of + it. */ +int +amd_array_shrink (struct _amd_data *amd, size_t index) +{ + memmove (&amd->msg_array[index-1], &amd->msg_array[index], + (amd->msg_count-index) * amd->msg_size); + amd->msg_count--; + return 0; +} + + +int +amd_init_mailbox (mu_mailbox_t mailbox, size_t amd_size, + struct _amd_data **pamd) +{ + int status; + struct _amd_data *amd; + + if (mailbox == NULL) + return MU_ERR_MBX_NULL; + if (amd_size < sizeof (*amd)) + return EINVAL; + + amd = mailbox->data = calloc (1, amd_size); + if (mailbox->data == NULL) + return ENOMEM; + + /* Back pointer. */ + amd->mailbox = mailbox; + + status = mu_url_aget_path (mailbox->url, &amd->name); + if (status) + { + free (amd); + mailbox->data = NULL; + return status; + } + + /* Overloading the defaults. */ + mailbox->_destroy = amd_destroy; + + mailbox->_open = amd_open; + mailbox->_close = amd_close; + + /* Overloading of the entire mailbox object methods. */ + mailbox->_get_message = amd_get_message; + mailbox->_quick_get_message = amd_quick_get_message; + mailbox->_append_message = amd_append_message; + mailbox->_messages_count = amd_messages_count; + mailbox->_messages_recent = amd_messages_recent; + mailbox->_message_unseen = amd_message_unseen; + mailbox->_expunge = amd_expunge; + mailbox->_sync = amd_sync; + mailbox->_uidvalidity = amd_uidvalidity; + mailbox->_uidnext = amd_uidnext; + + mailbox->_scan = amd_scan; + mailbox->_is_updated = amd_is_updated; + + mailbox->_get_size = amd_get_size; + + MU_DEBUG1 (mailbox->debug, MU_DEBUG_TRACE1, "amd_init(%s)\n", amd->name); + *pamd = amd; + return 0; +} + +static void +amd_destroy (mu_mailbox_t mailbox) +{ + struct _amd_data *amd = mailbox->data; + size_t i; + + if (!amd) + return; + + amd_pool_flush (amd); + mu_monitor_wrlock (mailbox->monitor); + for (i = 0; i < amd->msg_count; i++) + { + mu_message_destroy (&amd->msg_array[i]->message, amd->msg_array[i]); + free (amd->msg_array[i]); + } + free (amd->msg_array); + + if (amd->name) + free (amd->name); + + free (amd); + mailbox->data = NULL; + mu_monitor_unlock (mailbox->monitor); +} + +static int +amd_open (mu_mailbox_t mailbox, int flags) +{ + struct _amd_data *amd = mailbox->data; + struct stat st; + + mailbox->flags = flags; + if (stat (amd->name, &st) < 0) + { + if ((flags & MU_STREAM_CREAT) && errno == ENOENT) + { + int rc; + int perms = mu_stream_flags_to_mode (flags, 1); + if (mkdir (amd->name, S_IRUSR|S_IWUSR|S_IXUSR|perms)) + return errno; + if (stat (amd->name, &st) < 0) + return errno; + if (amd->create && (rc = amd->create (amd, flags))) + return rc; + } + else + return errno; + } + + if (!S_ISDIR (st.st_mode)) + return EINVAL; + + if (mailbox->locker == NULL) + mu_locker_create (&mailbox->locker, "/dev/null", 0); + + return 0; +} + +static int +amd_close (mu_mailbox_t mailbox) +{ + struct _amd_data *amd; + int i; + + if (!mailbox) + return MU_ERR_MBX_NULL; + + amd = mailbox->data; + + /* Destroy all cached data */ + amd_pool_flush (amd); + mu_monitor_wrlock (mailbox->monitor); + for (i = 0; i < amd->msg_count; i++) + { + mu_message_destroy (&amd->msg_array[i]->message, amd->msg_array[i]); + free (amd->msg_array[i]); + } + free (amd->msg_array); + amd->msg_array = NULL; + + amd->msg_count = 0; /* number of messages in the list */ + amd->msg_max = 0; /* maximum message buffer capacity */ + + amd->uidvalidity = 0; + mu_monitor_unlock (mailbox->monitor); + + return 0; +} + +static int +amd_message_qid (mu_message_t msg, mu_message_qid_t *pqid) +{ + struct _amd_message *mhm = mu_message_get_owner (msg); + + return mhm->amd->cur_msg_file_name (mhm, pqid); +} + +struct _amd_message * +_amd_get_message (struct _amd_data *amd, size_t msgno) +{ + msgno--; + if (msgno >= amd->msg_count) + return NULL; + return amd->msg_array[msgno]; +} + +static int +_amd_attach_message (mu_mailbox_t mailbox, struct _amd_message *mhm, + mu_message_t *pmsg) +{ + int status; + mu_message_t msg; + + /* Check if we already have it. */ + if (mhm->message) + { + if (pmsg) + *pmsg = mhm->message; + return 0; + } + + /* Get an empty message struct. */ + status = mu_message_create (&msg, mhm); + if (status != 0) + return status; + + /* Set the header. */ + { + mu_header_t header = NULL; + status = mu_header_create (&header, NULL, 0); + if (status != 0) + { + mu_message_destroy (&msg, mhm); + return status; + } + mu_header_set_fill (header, amd_h