commit-mailutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU Mailutils branch, master, updated. release-2.2-361-gadca074


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-2.2-361-gadca074
Date: Wed, 30 Mar 2011 12:49:38 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Mailutils".

http://git.savannah.gnu.org/cgit/mailutils.git/commit/?id=adca074d616ac562095a92e01f2b181e6d3593c8

The branch, master has been updated
       via  adca074d616ac562095a92e01f2b181e6d3593c8 (commit)
       via  827cb66a4c639139c3f11c7af26aa5149f25a7e0 (commit)
      from  5acfb2a37b1bb49474d3bbb0137f22604b508310 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit adca074d616ac562095a92e01f2b181e6d3593c8
Author: Sergey Poznyakoff <address@hidden>
Date:   Wed Mar 30 00:49:43 2011 +0300

    Implement IPv6 support.
    
    * am/ipv6.m4: New file.
    * examples/sa.c: New file.
    * include/mailutils/cidr.h: New file.
    * include/mailutils/sockaddr.h: New file.
    * libmailutils/cidr/Makefile.am: New file.
    * libmailutils/cidr/fromsa.c: New file.
    * libmailutils/cidr/fromstr.c: New file.
    * libmailutils/cidr/match.c: New file.
    * libmailutils/cidr/tosa.c: New file.
    * libmailutils/cidr/tostr.c: New file.
    * libmailutils/sockaddr/Makefile.am: New file.
    * libmailutils/sockaddr/copy.c: New file.
    * libmailutils/sockaddr/create.c: New file.
    * libmailutils/sockaddr/free.c: New file.
    * libmailutils/sockaddr/fromnode.c: New file.
    * libmailutils/sockaddr/insert.c: New file.
    * libmailutils/sockaddr/ipaddr.c: New file.
    * libmailutils/sockaddr/str.c: New file.
    * libmailutils/sockaddr/unlink.c: New file.
    * libmailutils/sockaddr/url.c: New file.
    * libmailutils/tests/cidr.c: New file.
    
    * configure.ac: Call MU_ENABLE_IPV6.
    Build libmailutils/sockaddr and libmailutils/cidr.
    * examples/.gitignore: Add mblconv and sa
    * examples/Makefile.am: (noinst_PROGRAMS): Add sa.
    * examples/aclck.c: Use new ACL API.
    * examples/echosrv.c: Use new mserv API.
    * include/mailutils/Makefile.am (pkginclude_HEADERS): Add cidr.h
    and sockaddr.h
    
    * include/mailutils/acl.h (mu_acl_append, mu_acl_prepend)
    (mu_acl_insert): Change signatures.
    * include/mailutils/debug.h (mu_sockaddr_to_str): Remove proto.
    * include/mailutils/mailutils.h: Include cidr.h and sockaddr.h
    * include/mailutils/server.h (mu_ip_server_create): Change signature.
    (mu_ip_server_get_sockaddr): Likewise.
    (mu_m_server_set_default_address)
    (mu_m_server_get_default_address): Remove.
    * include/mailutils/stream.h (mu_tcp_stream_create_from_sa): New proto.
    * include/mailutils/types.hin (mu_cidr, mu_sockaddr): New structs.
    
    * include/mailutils/url.h (MU_URL_IPV6): New flag.
    (MU_URL_PARSE_DSLASH_OPTIONAL): New parse flag.
    
    * libmailutils/Makefile.am: Descend into cidr and sockaddr. Link in
    libcidr and libsockaddr.
    * libmailutils/diag/debug.c (mu_debug_log_begin): Flush mu_strerr.
    * libmailutils/diag/errors (MU_ERR_NONAME)
    (MU_ERR_BADFLAGS,MU_ERR_SOCKTYPE)
    (MU_ERR_FAMILY,MU_ERR_SERVICE): New errors.
    
    * libmailutils/server/acl.c: Rewrite API using mu_cidr.
    * libmailutils/server/ipsrv.c: Rewrite AI using mu_sockaddr.
    * libmailutils/server/msrv.c: Likewise.
    * libmailutils/stream/tcp.c: Likewise.
    
    * libmailutils/tests/.gitignore: Add cidr.
    * libmailutils/tests/Makefile.am (noinst_PROGRAMS): Add cidr.
    * libmailutils/tests/url-parse.c: Support command line options
    to tune the parsing.
    * libmailutils/tests/url.at: Pass options to url-parse.
    * libmailutils/url/create.c (getkn): Return meaningful error code.
    (_mu_url_ctx_parse_host): Accept IPv6 addresses. Set the MU_URL_IPV6
    flag if one is given.
    (_mu_url_ctx_parse): Unless MU_URL_PARSE_DSLASH_OPTIONAL flag is
    given, request :// after scheme part.
    (mu_url_create): Add MU_URL_PARSE_DSLASH_OPTIONAL flag.
    
    * libmu_cfg/acl.c: Use new ACL API.
    * mu/acl.c: Likewise.
    
    * libproto/mailer/smtp.c (smtp_open): Use mu_tcp_stream_create_from_sa
    * libproto/pop/mbox.c (pop_open): Likewise.
    * mu/imap.c (com_connect): Likewise.
    * mu/pop.c (com_connect): Likewise.
    * testsuite/smtpsend.c (main): Likewise.

commit 827cb66a4c639139c3f11c7af26aa5149f25a7e0
Author: Sergey Poznyakoff <address@hidden>
Date:   Wed Mar 30 09:40:41 2011 +0300

    Minor fix
    
    * mh/tests/comp.at: Remove trailing whitespace before comparisons

-----------------------------------------------------------------------

Summary of changes:
 am/ipv6.m4                                         |   56 +++
 configure.ac                                       |    9 +
 examples/.gitignore                                |    2 +
 examples/Makefile.am                               |    1 +
 examples/aclck.c                                   |   89 +----
 examples/echosrv.c                                 |   69 +++--
 examples/sa.c                                      |   93 +++++
 include/mailutils/Makefile.am                      |    2 +
 include/mailutils/acl.h                            |    8 +-
 include/mailutils/cidr.h                           |   61 ++++
 include/mailutils/debug.h                          |    3 -
 include/mailutils/mailutils.h                      |    2 +
 include/mailutils/server.h                         |   12 +-
 include/mailutils/sockaddr.h                       |   78 +++++
 include/mailutils/stream.h                         |    4 +
 include/mailutils/types.hin                        |    3 +
 include/mailutils/url.h                            |    9 +-
 libmailutils/Makefile.am                           |    4 +-
 libmailutils/{mailer => cidr}/Makefile.am          |   13 +-
 libmailutils/cidr/fromsa.c                         |  101 ++++++
 libmailutils/cidr/fromstr.c                        |  128 +++++++
 libmailutils/{base/getmaxfd.c => cidr/match.c}     |   30 +-
 libmailutils/cidr/tosa.c                           |   78 +++++
 libmailutils/cidr/tostr.c                          |  159 +++++++++
 libmailutils/diag/debug.c                          |    1 +
 libmailutils/diag/errors                           |    8 +
 libmailutils/server/acl.c                          |  366 +++++---------------
 libmailutils/server/ipsrv.c                        |   83 ++---
 libmailutils/server/msrv.c                         |  348 ++++++-------------
 libmailutils/{property => sockaddr}/Makefile.am    |   21 +-
 libmailutils/{url/urlstr.c => sockaddr/copy.c}     |   21 +-
 .../{base/getmaxfd.c => sockaddr/create.c}         |   35 ++-
 libmailutils/{base/getmaxfd.c => sockaddr/free.c}  |   40 ++-
 libmailutils/sockaddr/fromnode.c                   |  253 ++++++++++++++
 .../{base/getmaxfd.c => sockaddr/insert.c}         |   54 ++-
 libmailutils/sockaddr/ipaddr.c                     |   88 +++++
 libmailutils/sockaddr/str.c                        |  109 ++++++
 .../{base/getmaxfd.c => sockaddr/unlink.c}         |   35 +-
 libmailutils/sockaddr/url.c                        |  130 +++++++
 libmailutils/stream/tcp.c                          |  178 +++++-----
 libmailutils/tests/.gitignore                      |    1 +
 libmailutils/tests/Makefile.am                     |    1 +
 libmailutils/tests/cidr.c                          |   77 ++++
 libmailutils/tests/url-parse.c                     |   49 +++-
 libmailutils/tests/url.at                          |   14 +-
 libmailutils/url/create.c                          |   57 +++-
 libmu_cfg/acl.c                                    |  135 ++------
 libproto/mailer/smtp.c                             |   25 +-
 libproto/pop/mbox.c                                |   27 +-
 mh/tests/comp.at                                   |   26 +-
 mu/acl.c                                           |   40 +--
 mu/imap.c                                          |   25 +-
 mu/pop.c                                           |   47 ++-
 testsuite/smtpsend.c                               |   25 +-
 54 files changed, 2242 insertions(+), 1091 deletions(-)
 create mode 100644 am/ipv6.m4
 create mode 100644 examples/sa.c
 create mode 100644 include/mailutils/cidr.h
 create mode 100644 include/mailutils/sockaddr.h
 copy libmailutils/{mailer => cidr}/Makefile.am (83%)
 create mode 100644 libmailutils/cidr/fromsa.c
 create mode 100644 libmailutils/cidr/fromstr.c
 copy libmailutils/{base/getmaxfd.c => cidr/match.c} (70%)
 create mode 100644 libmailutils/cidr/tosa.c
 create mode 100644 libmailutils/cidr/tostr.c
 copy libmailutils/{property => sockaddr}/Makefile.am (79%)
 copy libmailutils/{url/urlstr.c => sockaddr/copy.c} (74%)
 copy libmailutils/{base/getmaxfd.c => sockaddr/create.c} (65%)
 copy libmailutils/{base/getmaxfd.c => sockaddr/free.c} (66%)
 create mode 100644 libmailutils/sockaddr/fromnode.c
 copy libmailutils/{base/getmaxfd.c => sockaddr/insert.c} (53%)
 create mode 100644 libmailutils/sockaddr/ipaddr.c
 create mode 100644 libmailutils/sockaddr/str.c
 copy libmailutils/{base/getmaxfd.c => sockaddr/unlink.c} (70%)
 create mode 100644 libmailutils/sockaddr/url.c
 create mode 100644 libmailutils/tests/cidr.c

diff --git a/am/ipv6.m4 b/am/ipv6.m4
new file mode 100644
index 0000000..2357314
--- /dev/null
+++ b/am/ipv6.m4
@@ -0,0 +1,56 @@
+dnl This file is part of GNU Mailutils.  -*- autoconf -*-
+dnl Copyright (C) 2011 Free Software Foundation, Inc.
+dnl
+dnl GNU Mailutils is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 3 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl GNU Mailutils is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>.
+
+AC_DEFUN([MU_ENABLE_IPV6],
+   [AC_ARG_ENABLE(ipv6,                     
+     [AC_HELP_STRING([--enable-ipv6], [enable IPv6 support])],
+     [status_ipv6=$enableval],
+     [status_ipv6=maybe])
+     
+    if test $status_ipv6 != no; then
+      working_ipv6=no
+      AC_EGREP_CPP(MAILUTILS_AF_INET6_DEFINED,[
+#include <sys/socket.h>
+#if defined(AF_INET6)
+MAILUTILS_AF_INET6_DEFINED
+#endif
+],[working_ipv6=yes])
+
+      AC_CHECK_TYPE([struct sockaddr_storage],
+                    [working_ipv6=yes], [working_ipv6=no],
+                   [#include <sys/socket.h>])
+      AC_CHECK_TYPE([struct sockaddr_in6],
+                    [working_ipv6=yes], [working_ipv6=no],
+                   [#include <sys/types.h>
+                     #include <netinet/in.h>])
+      AC_CHECK_TYPE([struct addrinfo],
+                    [working_ipv6=yes], [working_ipv6=no],
+                   [#include <netdb.h>])
+      AC_CHECK_FUNC([getnameinfo],
+                    [working_ipv6=yes], [working_ipv6=no],
+                   [#include <netdb.h>])
+
+      if test $working_ipv6 = no; then
+       if test $status_ipv6 = yes; then
+         AC_MSG_ERROR([IPv6 support is required but not available])
+       fi
+      fi
+      status_ipv6=$working_ipv6
+      if test $status_ipv6 = yes; then
+       AC_DEFINE_UNQUOTED([MAILUTILS_IPV6],1,
+                          [Define to 1 if IPv6 support is enabled])
+      fi
+    fi])
\ No newline at end of file
diff --git a/configure.ac b/configure.ac
index e03a4c3..2edb494 100644
--- a/configure.ac
+++ b/configure.ac
@@ -541,6 +541,10 @@ AH_BOTTOM([
 ])
 
 
+# IPv6 support
+MU_ENABLE_IPV6
+
+
 ## FriBidi support
 
 AC_CHECK_FUNCS(wcwidth)
@@ -1285,6 +1289,8 @@ LDAP support .................. $status_ldap
 Radius support ................ $status_radius
 Support for virtual domains ... $status_virtual_domains
 
+IPv6 support .................. $status_ipv6
+
 Interfaces:
 
 Guile ......................... $status_guile
@@ -1332,6 +1338,7 @@ status_mh=$mu_cv_enable_mh
 status_maildir=$mu_cv_enable_maildir
 status_smtp=$mu_cv_enable_smtp
 status_sendmail=$mu_cv_enable_sendmail
+status_ipv6=$status_ipv6
 ])
 
 dnl Output Makefiles
@@ -1382,6 +1389,8 @@ AC_CONFIG_FILES([
  libmailutils/auth/Makefile
  libmailutils/base/Makefile
  libmailutils/address/Makefile
+ libmailutils/sockaddr/Makefile
+ libmailutils/cidr/Makefile
  libmailutils/cfg/Makefile
  libmailutils/diag/Makefile
  libmailutils/filter/Makefile
diff --git a/examples/.gitignore b/examples/.gitignore
index af4156b..890812a 100644
--- a/examples/.gitignore
+++ b/examples/.gitignore
@@ -11,6 +11,7 @@ iconv
 listop
 lsf
 mailcap
+mblconv
 mimetest
 msg-send
 mta
@@ -20,5 +21,6 @@ muemail
 murun
 musocio
 nntpclient
+sa
 sfrom
 url-parse
diff --git a/examples/Makefile.am b/examples/Makefile.am
index e22a8d3..9df91ea 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -43,6 +43,7 @@ noinst_PROGRAMS = \
  murun\
  musocio\
  $(NNTPCLIENT)\
+ sa\
  sfrom
 
 EXTRA_PROGRAMS = nntpclient
diff --git a/examples/aclck.c b/examples/aclck.c
index 57f5c03..033c444 100644
--- a/examples/aclck.c
+++ b/examples/aclck.c
@@ -28,35 +28,9 @@
 #include <stdlib.h>
 #include <string.h>
 
-struct sockaddr *target_sa;
-int target_salen;
+struct mu_sockaddr *target_sa;
 mu_acl_t acl;
 
-struct sockaddr *
-parse_address (int *psalen, char *str)
-{
-  struct sockaddr_in in;
-  struct sockaddr *sa;
-  
-  in.sin_family = AF_INET;
-  if (inet_aton (str, &in.sin_addr) == 0)
-    {
-      mu_error ("Invalid IPv4: %s", str);
-      exit (1);
-    }
-  in.sin_port = 0;
-  *psalen = sizeof (in);
-  sa = malloc (*psalen);
-  if (!sa)
-    {
-      mu_error ("%s", mu_strerror (errno));
-      exit (1);
-    }
-  
-  memcpy (sa, &in, sizeof (in));
-  return sa;
-}
-
 void
 read_rules (FILE *fp)
 {
@@ -76,12 +50,9 @@ read_rules (FILE *fp)
   ws.ws_comment = "#";
   while (fgets (buf, sizeof buf, fp))
     {
-      unsigned long netmask;
-      int salen;
-      struct sockaddr *sa;
+      struct mu_cidr cidr;
       mu_acl_action_t action;
       void *data = NULL;
-      char *p;
       
       int len = strlen (buf);
       if (len == 0)
@@ -109,47 +80,19 @@ read_rules (FILE *fp)
          continue;
        }
 
-      p = strchr (ws.ws_wordv[1], '/');
-      if (p)
+      if (strcmp (ws.ws_wordv[1], "any") == 0)
+       memset (&cidr, 0, sizeof (cidr));
+      else
        {
-         char *q;
-         unsigned netlen;
-         
-         *p++ = 0;
-         netlen = strtoul (p, &q, 10);
-         if (*q == 0)
-           {
-             if (netlen == 0)
-               netmask = 0;
-             else
-               {
-                 netmask = 0xfffffffful >> (32 - netlen);
-                 netmask <<= (32 - netlen);
-                 netmask = htonl (netmask);
-               }
-           }
-         else if (*q == '.')
+         rc = mu_cidr_from_string (&cidr, ws.ws_wordv[1]);
+         if (rc)
            {
-             struct in_addr addr;
-             
-             if (inet_aton (p, &addr) == 0)
-               {
-                 mu_error ("%d: invalid netmask", line);
-                 continue;
-               }
-             netmask = addr.s_addr;
-           }
-         else
-           {
-             mu_error ("%d: invalid netmask", line);
+             mu_error ("%d: invalid source CIDR: %s",
+                       line, mu_strerror (rc));
              continue;
            }
        }
-      else
-       netmask = 0xfffffffful;
-      
-      sa = parse_address (&salen, ws.ws_wordv[1]);
-      
+
       /* accept addr
         deny addr
         log addr [rest ...]
@@ -174,7 +117,7 @@ read_rules (FILE *fp)
          data = strdup (ws.ws_wordv[2]);
        }
 
-      rc = mu_acl_append (acl, action, data, sa, salen, netmask);
+      rc = mu_acl_append (acl, action, data, &cidr);
       if (rc)
        mu_error ("%d: cannot append acl entry: %s", line,
                  mu_strerror (rc));
@@ -203,7 +146,12 @@ main (int argc, char **argv)
          break;
 
        case 'a':
-         target_sa = parse_address (&target_salen, optarg);
+         rc = mu_sockaddr_from_node (&target_sa, optarg, NULL, NULL);
+         if (rc)
+           {
+             mu_error ("mu_sockaddr_from_node: %s", mu_strerror (rc));
+             exit (1);
+           }
          break;
 
        case 'f':
@@ -225,7 +173,8 @@ main (int argc, char **argv)
   argc -= optind;
 
   read_rules (file ? file : stdin);
-  rc = mu_acl_check_sockaddr (acl, target_sa, target_salen, &result);
+  rc = mu_acl_check_sockaddr (acl, target_sa->addr, target_sa->addrlen,
+                             &result);
   if (rc)
     {
       mu_error ("mu_acl_check_sockaddr failed: %s", mu_strerror (rc));
diff --git a/examples/echosrv.c b/examples/echosrv.c
index fb68e7a..fffde73 100644
--- a/examples/echosrv.c
+++ b/examples/echosrv.c
@@ -39,13 +39,9 @@ echo_conn (int fd, struct sockaddr *s, int len,
           void *server_data, void *call_data,
           mu_ip_server_t srv)
 {
-  struct sockaddr_in srv_addr, *s_in = (struct sockaddr_in *)s;
-  int addrlen = sizeof srv_addr;
   pid_t pid;
   char buf[512];
   FILE *in, *out;
-  
-  mu_ip_server_get_sockaddr (srv, (struct sockaddr *)&srv_addr, &addrlen);
 
   pid = fork ();
   if (pid == -1)
@@ -56,10 +52,20 @@ echo_conn (int fd, struct sockaddr *s, int len,
 
   if (pid)
     {
-      mu_diag_output (MU_DIAG_INFO, "%lu: opened connection %s:%d => %s:%d",
+      struct mu_sockaddr *clt_addr;
+      int rc = mu_sockaddr_create (&clt_addr, s, len);
+      if (rc)
+       {
+         mu_error ("mu_sockaddr_create failed: %s", mu_strerror (rc));
+         return 0;
+       }
+  
+      mu_diag_output (MU_DIAG_INFO, "%lu: opened connection %s => %s",
                      (unsigned long) pid,
-                     inet_ntoa (srv_addr.sin_addr), ntohs (srv_addr.sin_port),
-                     inet_ntoa (s_in->sin_addr), ntohs (s_in->sin_port));
+                     mu_ip_server_addrstr (srv),
+                     mu_sockaddr_str (clt_addr));
+
+      mu_sockaddr_free (clt_addr);
       return 0;
     }
 
@@ -108,34 +114,45 @@ tcp_conn_free (void *conn_data, void *server_data)
 void
 create_server (char *arg)
 {
-  char *p, *q;
-  struct sockaddr_in s;
+  struct mu_sockaddr *s;
   mu_ip_server_t tcpsrv;
-  unsigned n;
-  
-  p = strchr (arg, ':');
-  if (!*p)
+  int rc;
+  mu_url_t url, url_hint;
+  struct mu_sockaddr_hints hints;
+
+  if (arg[0] == '/')
+    url_hint = NULL;
+  else
     {
-      mu_error ("invalid specification: %s\n", arg);
-      exit (1);
+      rc = mu_url_create (&url_hint, "inet://");
+      if (rc)
+       {
+         mu_error ("cannot create URL hints: %s", mu_strerror (rc));
+         exit (1);
+       }
     }
-  *p++ = 0;
-  s.sin_family = AF_INET;
-  if (inet_aton (arg, &s.sin_addr) == 0)
+  rc = mu_url_create_hint (&url, arg, MU_URL_PARSE_DEFAULT, url_hint);
+  mu_url_destroy (&url_hint);
+  if (rc)
     {
-      mu_error ("invalid IP address: %s\n", arg);
+      mu_error ("cannot parse URL `%s': %s", arg, mu_strerror (rc));
       exit (1);
     }
-  n = strtoul (p, &q, 0);
-  if (*q)
+
+  memset (&hints, sizeof(hints), 0);
+  hints.flags = MU_AH_PASSIVE;
+  hints.socktype = SOCK_STREAM;
+  hints.protocol = IPPROTO_TCP;
+  rc = mu_sockaddr_from_url (&s, url, &hints); 
+  mu_url_destroy (&url);
+
+  if (rc)
     {
-      mu_error ("invalid port number: %s\n", p);
+      mu_error ("cannot create sockaddr: %s", mu_strerror (rc));
       exit (1);
-    }      
-  s.sin_port = htons (n);
+    }
 
-  MU_ASSERT (mu_ip_server_create (&tcpsrv, (struct sockaddr*) &s, sizeof s,
-                                 MU_IP_TCP));
+  MU_ASSERT (mu_ip_server_create (&tcpsrv, s, MU_IP_TCP));
   MU_ASSERT (mu_ip_server_open (tcpsrv));
   MU_ASSERT (mu_ip_server_set_conn (tcpsrv, echo_conn));
   MU_ASSERT (mu_server_add_connection (server,
diff --git a/examples/sa.c b/examples/sa.c
new file mode 100644
index 0000000..7cc7e93
--- /dev/null
+++ b/examples/sa.c
@@ -0,0 +1,93 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2005, 2007, 2010, 2011 Free
+   Software Foundation, Inc.
+
+   GNU Mailutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GNU Mailutils is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <mailutils/mailutils.h>
+
+int
+main (int argc, char **argv)
+{
+  struct mu_sockaddr_hints hints;
+  struct mu_sockaddr *sa, *ap;
+  int rc, i;
+  char *node = NULL, *serv = NULL;
+  char *urlstr;
+  
+  mu_set_program_name (argv[0]);
+
+  memset (&hints, 0, sizeof (hints));
+  hints.family = AF_UNSPEC;
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], "passive") == 0)
+       hints.flags |= MU_AH_PASSIVE;
+      else if (strcmp (argv[i], "detect") == 0)
+       hints.flags |= MU_AH_DETECT_FAMILY;
+      else if (strncmp (argv[i], "node=", 5) == 0)
+       node = argv[i] + 5;
+      else if (strncmp (argv[i], "serv=", 5) == 0)
+       serv = argv[i] + 5;
+      else if (strncmp (argv[i], "url=", 4) == 0)
+       urlstr = argv[i] + 4;
+      else if (strncmp (argv[i], "proto=", 6) == 0)
+       hints.protocol = atoi(argv[i] + 6);
+      else if (strncmp (argv[i], "family=", 7) == 0)
+       hints.family = atoi (argv[i] + 7);
+      else if (strncmp (argv[i], "socktype=", 9) == 0)
+       hints.socktype = atoi (argv[i] + 9);
+      else
+       {
+         mu_error ("unknown argument: %s", argv[i]);
+         exit (1);
+       }
+    }
+
+  if (urlstr)
+    {
+      mu_url_t url;
+      
+      if (node || serv)
+       {
+         mu_error ("both url and host/serv are given");
+         exit (1);
+       }
+
+      rc = mu_url_create (&url, urlstr);
+      if (rc)
+       {
+         mu_error ("cannot create url: %s", mu_strerror (rc));
+         exit (2);
+       }
+      rc = mu_sockaddr_from_url (&sa, url, &hints);
+    }
+  else
+    rc = mu_sockaddr_from_node (&sa, node, serv, &hints);
+  if (rc)
+    {
+      mu_error ("cannot create sockaddr: %s", mu_strerror (rc));
+      exit (2);
+    }
+
+  for (ap = sa; ap; ap = ap->next)
+    printf ("%s\n", mu_sockaddr_str (ap));
+
+  mu_sockaddr_free (sa);
+  exit (0);
+}
+
diff --git a/include/mailutils/Makefile.am b/include/mailutils/Makefile.am
index daa46e9..1e21894 100644
--- a/include/mailutils/Makefile.am
+++ b/include/mailutils/Makefile.am
@@ -36,6 +36,7 @@ pkginclude_HEADERS = \
  body.h\
  cctype.h\
  cfg.h\
+ cidr.h\
  cstr.h\
  daemon.h\
  debug.h\
@@ -89,6 +90,7 @@ pkginclude_HEADERS = \
  server.h\
  sieve.h\
  smtp.h\
+ sockaddr.h\
  stdstream.h\
  stream.h\
  syslog.h\
diff --git a/include/mailutils/acl.h b/include/mailutils/acl.h
index b898463..167acc8 100644
--- a/include/mailutils/acl.h
+++ b/include/mailutils/acl.h
@@ -47,13 +47,11 @@ int mu_acl_destroy (mu_acl_t *acl);
 int mu_acl_count (mu_acl_t acl, size_t *pcount);
 int mu_acl_get_iterator (mu_acl_t acl, mu_iterator_t *pitr);
 int mu_acl_append (mu_acl_t acl, mu_acl_action_t act, void *data,
-                  struct sockaddr *sa, int salen,
-                  unsigned long netmask);
+                  struct mu_cidr *);
 int mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data,
-                   struct sockaddr *sa, int salen, unsigned long netmask);
+                   struct mu_cidr *);
 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);
+                  mu_acl_action_t act, void *data, struct mu_cidr *);
 
 int mu_acl_check_ipv4 (mu_acl_t acl, unsigned int addr, mu_acl_result_t *pres);
 int mu_acl_check_inaddr (mu_acl_t acl, const struct in_addr *inp,
diff --git a/include/mailutils/cidr.h b/include/mailutils/cidr.h
new file mode 100644
index 0000000..c54bf62
--- /dev/null
+++ b/include/mailutils/cidr.h
@@ -0,0 +1,61 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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/>. */
+
+#ifndef _MAILUTILS_CIDR_H
+#define _MAILUTILS_CIDR_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <mailutils/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MU_INADDR_BYTES 16
+
+struct mu_cidr
+{
+  int family;
+  int len;
+  unsigned char address[MU_INADDR_BYTES];
+  unsigned char netmask[MU_INADDR_BYTES];
+};
+
+#define MU_CIDR_MAXBUFSIZE 81
+  
+int mu_cidr_from_sockaddr (struct mu_cidr *cp, const struct sockaddr *sa);
+int mu_cidr_from_string (struct mu_cidr *cp, const char *str);
+
+#define MU_CIDR_FMT_ADDRONLY 0x01
+  
+int mu_cidr_to_string (struct mu_cidr *cidr, int flags, char *buf, size_t size,
+                      size_t *pret);
+int mu_cidr_format (struct mu_cidr *, int flags, char **pbuf);
+int mu_cidr_to_sockaddr (struct mu_cidr *, struct sockaddr **sa);
+
+int mu_cidr_match (struct mu_cidr *a, struct mu_cidr *b);
+
+int _mu_inaddr_to_bytes (int af, void *buf, unsigned char *bytes);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MAILUTILS_CIDR_H */
+       
+  
diff --git a/include/mailutils/debug.h b/include/mailutils/debug.h
index 5072d51..a619661 100644
--- a/include/mailutils/debug.h
+++ b/include/mailutils/debug.h
@@ -54,9 +54,6 @@ extern int mu_debug_line_info;
 
 
 struct sockaddr;
-void mu_sockaddr_to_str (const struct sockaddr *sa, int salen,
-                        char *bufptr, size_t buflen,
-                        size_t *plen);
 char *mu_sockaddr_to_astr (const struct sockaddr *sa, int salen);
 
 
diff --git a/include/mailutils/mailutils.h b/include/mailutils/mailutils.h
index 8d9e04b..08a2fc0 100644
--- a/include/mailutils/mailutils.h
+++ b/include/mailutils/mailutils.h
@@ -67,5 +67,7 @@
 #include <mailutils/log.h>
 #include <mailutils/stdstream.h>
 #include <mailutils/prog.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/cidr.h>
 
 /* EOF */
diff --git a/include/mailutils/server.h b/include/mailutils/server.h
index bf8d10e..c5da97e 100644
--- a/include/mailutils/server.h
+++ b/include/mailutils/server.h
@@ -54,8 +54,8 @@ typedef void (*mu_ip_server_free_fp) (void *data);
 #define MU_IP_TCP 0
 #define MU_IP_UDP 1
 
-int mu_ip_server_create (mu_ip_server_t *psrv, struct sockaddr *addr,
-                        int len, int type);
+int mu_ip_server_create (mu_ip_server_t *psrv, struct mu_sockaddr *addr,
+                        int type);
 int mu_ip_server_destroy (mu_ip_server_t *psrv);
 int mu_ip_server_get_type (mu_ip_server_t srv, int *ptype);
 int mu_ip_server_set_ident (mu_ip_server_t srv, const char *ident);
@@ -69,8 +69,8 @@ int mu_ip_server_shutdown (mu_ip_server_t srv);
 int mu_ip_server_accept (mu_ip_server_t srv, void *call_data);
 int mu_ip_server_loop (mu_ip_server_t srv, void *call_data);
 int mu_ip_server_get_fd (mu_ip_server_t srv);
-int mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct sockaddr *s,
-                              int *size);
+int mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct mu_sockaddr **psa);
+const char *mu_ip_server_addrstr (mu_ip_server_t srv);
 
 int mu_tcp_server_set_backlog (mu_ip_server_t srv, int backlog);
 int mu_udp_server_set_bufsize (mu_ip_server_t srv, size_t size);
@@ -99,8 +99,6 @@ void mu_m_server_set_max_children (mu_m_server_t srv, size_t 
num);
 int mu_m_server_set_pidfile (mu_m_server_t srv, const char *pidfile);
 int mu_m_server_set_foreground (mu_m_server_t srv, int enable);
 void mu_m_server_set_default_port (mu_m_server_t srv, int port);
-void mu_m_server_set_default_address (mu_m_server_t srv, struct sockaddr *sa,
-                                     int salen);
 void mu_m_server_set_timeout (mu_m_server_t srv, time_t t);
 void mu_m_server_set_mode (mu_m_server_t srv, int mode);
 void mu_m_server_set_sigset (mu_m_server_t srv, sigset_t *sigset);
@@ -112,8 +110,6 @@ time_t mu_m_server_timeout (mu_m_server_t srv);
 const char * mu_m_server_pidfile (mu_m_server_t srv);
 void mu_m_server_get_sigset (mu_m_server_t srv, sigset_t *sigset);
 int mu_m_server_get_srvlist (mu_m_server_t srv, mu_list_t *plist);
-int mu_m_server_get_default_address (mu_m_server_t srv, struct sockaddr *sa,
-                                    int *salen);
 
 void mu_m_server_configured_count (mu_m_server_t msrv, size_t count);
 
diff --git a/include/mailutils/sockaddr.h b/include/mailutils/sockaddr.h
new file mode 100644
index 0000000..5a98f7a
--- /dev/null
+++ b/include/mailutils/sockaddr.h
@@ -0,0 +1,78 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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/>. */
+
+#ifndef _MAILUTILS_SOCKADDR_H
+#define _MAILUTILS_SOCKADDR_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <mailutils/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct mu_sockaddr
+{
+  struct mu_sockaddr *prev, *next;
+  struct sockaddr *addr;            /* Address */
+  socklen_t        addrlen;         /* Size of addr */
+  char *str;                        /* string representation of addr,
+                                      filled up by mu_sockaddr_str */
+};
+
+#define MU_AH_PASSIVE       0x01
+#define MU_AH_DETECT_FAMILY 0x02
+  
+struct mu_sockaddr_hints
+{
+  int flags;
+  int family;
+  int socktype;
+  int protocol;
+  unsigned short port;
+};
+
+int mu_sockaddr_create (struct mu_sockaddr **res,
+                       struct sockaddr *addr, socklen_t len);
+int mu_sockaddr_copy (struct mu_sockaddr **pnew, struct mu_sockaddr *old);
+void mu_sockaddr_free (struct mu_sockaddr *addr);
+struct mu_sockaddr *mu_sockaddr_unlink (struct mu_sockaddr *addr);
+void mu_sockaddr_free_list (struct mu_sockaddr *addr);
+struct mu_sockaddr *mu_sockaddr_insert (struct mu_sockaddr *anchor,
+                                       struct mu_sockaddr *addr,
+                                       int before);
+const char *mu_sockaddr_str (struct mu_sockaddr *addr);
+
+int mu_sockaddr_format (char **pbuf, const struct sockaddr *sa,
+                       socklen_t salen);
+
+int mu_sockaddr_from_node (struct mu_sockaddr **retval, const char *node,
+                          const char *serv, struct mu_sockaddr_hints *hints); 
+int mu_sockaddr_from_url (struct mu_sockaddr **retval, mu_url_t url,
+                         struct mu_sockaddr_hints *hints);
+
+int mu_str_is_ipv4 (const char *addr);
+int mu_str_is_ipv6 (const char *addr);
+int mu_str_is_ipaddr (const char *addr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MAILUTILS_SOCKADDR_H */
+       
diff --git a/include/mailutils/stream.h b/include/mailutils/stream.h
index b253f4e..8bea907 100644
--- a/include/mailutils/stream.h
+++ b/include/mailutils/stream.h
@@ -315,6 +315,10 @@ int mu_streamref_create_abridged (mu_stream_t *pref, 
mu_stream_t str,
                                  mu_off_t start, mu_off_t end);
 int mu_streamref_create (mu_stream_t *pref, mu_stream_t str);
 
+int mu_tcp_stream_create_from_sa (mu_stream_t *pstream,
+                                 struct mu_sockaddr *remote_addr,
+                                 struct mu_sockaddr *source_addr, int flags);
+
 int mu_tcp_stream_create_with_source_ip (mu_stream_t *stream,
                                         const char *host, unsigned port,
                                         unsigned long source_ip,
diff --git a/include/mailutils/types.hin b/include/mailutils/types.hin
index e89b799..bf81756 100644
--- a/include/mailutils/types.hin
+++ b/include/mailutils/types.hin
@@ -75,6 +75,9 @@ struct _mu_assoc;
 struct _mu_acl;  
 struct _mu_server;
 struct _mu_tcp_server;
+
+struct mu_sockaddr; /* defined in mailutils/sockaddr.h */  
+struct mu_cidr;     /* defined in mailutils/cidr.h */  
   
 typedef _MU_OFF_TYPE_ mu_off_t;
 
diff --git a/include/mailutils/url.h b/include/mailutils/url.h
index 031e568..c33dadc 100644
--- a/include/mailutils/url.h
+++ b/include/mailutils/url.h
@@ -34,6 +34,7 @@ extern "C" {
 #define MU_URL_PATH   0x0040 /* Has path */
 #define MU_URL_PARAM  0x0080 /* Has parameters */
 #define MU_URL_QUERY  0x0100 /* Has query */
+#define MU_URL_IPV6   0x0200 /* Host part is bracketed (IPv6) */
   
 #define MU_URL_CRED (MU_URL_USER | MU_URL_SECRET | MU_URL_AUTH)  
   /* Has some of authentication credentials */
@@ -53,12 +54,14 @@ extern "C" {
 #define MU_URL_PARSE_PORTSRV      0x0004  /* Use getservbyname to determine
                                             port number */
 #define MU_URL_PARSE_PORTWC       0x0008  /* Allow wildcard (*) as a port
-                                           number (for tickets) */
+                                            number (for tickets) */
 #define MU_URL_PARSE_PIPE         0x0010  /* Translate "| ..." to
-                                           "prog://..." */
+                                            "prog://..." */
 #define MU_URL_PARSE_SLASH        0x0020  /* Translate "/..." to
                                             "file:///..." */
-
+#define MU_URL_PARSE_DSLASH_OPTIONAL 0x0040 /* Double-slash after scheme:
+                                              part is optional */
+  
 #define MU_URL_PARSE_DEFAULT \
   (MU_URL_PARSE_HEXCODE|MU_URL_PARSE_HIDEPASS|MU_URL_PARSE_PORTSRV|\
    MU_URL_PARSE_PIPE|MU_URL_PARSE_SLASH)
diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am
index ed1aeb0..5aef338 100644
--- a/libmailutils/Makefile.am
+++ b/libmailutils/Makefile.am
@@ -16,7 +16,7 @@
 # Public License along with this library.  If not, see
 # <http://www.gnu.org/licenses/>.
 
-SUBDIRS = auth base address cfg diag filter mailbox mailer mime\
+SUBDIRS = auth base address sockaddr cidr cfg diag filter mailbox mailer mime\
  server string stream stdstream property url . tests 
 
 lib_LTLIBRARIES = libmailutils.la
@@ -28,6 +28,8 @@ libmailutils_la_LIBADD = \
  auth/libauth.la\
  base/libbase.la\
  address/libaddress.la\
+ sockaddr/libsockaddr.la\
+ cidr/libcidr.la\
  cfg/libcfg.la\
  diag/libdiag.la\
  filter/libfilter.la\
diff --git a/libmailutils/mailer/Makefile.am b/libmailutils/cidr/Makefile.am
similarity index 83%
copy from libmailutils/mailer/Makefile.am
copy to libmailutils/cidr/Makefile.am
index 7a098cc..408806f 100644
--- a/libmailutils/mailer/Makefile.am
+++ b/libmailutils/cidr/Makefile.am
@@ -1,5 +1,5 @@
 # GNU Mailutils -- a suite of utilities for electronic mail
-# Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+# Copyright (C) 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
@@ -15,10 +15,13 @@
 # Public License along with this library.  If not, see
 # <http://www.gnu.org/licenses/>.
 
-noinst_LTLIBRARIES = libmailer.la
+noinst_LTLIBRARIES = libcidr.la
 
-libmailer_la_SOURCES = \
- mailer.c\
- progmailer.c
+libcidr_la_SOURCES = \
+ fromsa.c\
+ fromstr.c\
+ match.c\
+ tosa.c\
+ tostr.c
 
 INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
diff --git a/libmailutils/cidr/fromsa.c b/libmailutils/cidr/fromsa.c
new file mode 100644
index 0000000..a2fda66
--- /dev/null
+++ b/libmailutils/cidr/fromsa.c
@@ -0,0 +1,101 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <mailutils/cidr.h>
+#include <mailutils/errno.h>
+
+static void
+uint32_to_bytes (unsigned char *bytes, uint32_t u)
+{
+  int i;
+  
+  for (i = 0; i < 4; i++)
+    {
+      bytes[i] = u & 0xff;
+      u >>= 8;
+    }
+}
+
+int
+_mu_inaddr_to_bytes (int af, void *buf, unsigned char *bytes)
+{
+  uint32_t u;
+  
+  switch (af)
+    {
+    case AF_INET:
+      memcpy (&u, buf, sizeof u);
+      uint32_to_bytes (bytes, u);
+      return 4;
+
+#ifdef MAILUTILS_IPV6
+    case AF_INET6:
+      memcpy (bytes, buf, 16);
+      return 16;
+#endif
+    }
+  return 0;
+}
+
+int
+_mu_sockaddr_to_bytes (unsigned char *bytes, struct sockaddr const *sa)
+{
+  switch (sa->sa_family)
+    {
+    case AF_INET:
+      uint32_to_bytes (bytes, ((struct sockaddr_in*)sa)->sin_addr.s_addr);
+      return 4;
+
+#ifdef MAILUTILS_IPV6
+    case AF_INET6:
+      memcpy (bytes, &((struct sockaddr_in6*)sa)->sin6_addr, 16);
+      return 16;
+#endif
+    }
+  return 0;
+}
+
+int
+mu_cidr_from_sockaddr (struct mu_cidr *cidr, const struct sockaddr *sa)
+{
+  unsigned char address[MU_INADDR_BYTES];
+  int len;
+  int i;
+  
+  len = _mu_sockaddr_to_bytes (address, sa);
+  if (len == 0)
+    return MU_ERR_FAMILY;
+  cidr->family = sa->sa_family;
+  cidr->len = len;
+  memcpy (cidr->address, address, sizeof (cidr->address));
+  for (i = 0; i < MU_INADDR_BYTES; i++)
+    cidr->netmask[i] = 0xff;
+  return 0;
+}
+
+      
diff --git a/libmailutils/cidr/fromstr.c b/libmailutils/cidr/fromstr.c
new file mode 100644
index 0000000..4e7a56f
--- /dev/null
+++ b/libmailutils/cidr/fromstr.c
@@ -0,0 +1,128 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <string.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <mailutils/cidr.h>
+#include <mailutils/errno.h>
+#include <mailutils/sockaddr.h>
+
+static void
+masklen_to_netmask (unsigned char *buf, size_t len, size_t masklen)
+{
+  int i, cnt;
+
+  cnt = masklen / 8;
+  for (i = 0; i < cnt; i++)
+    buf[i] = 0xff;
+  if (i == MU_INADDR_BYTES)
+    return;
+  cnt = 8 - masklen % 8;
+  buf[i++] = (0xff >> cnt) << cnt;
+  for (; i < MU_INADDR_BYTES; i++)
+    buf[i] = 0;
+}
+
+int
+mu_cidr_from_string (struct mu_cidr *pcidr, const char *str)
+{
+  int rc;
+  char ipbuf[41];
+  struct mu_cidr cidr;
+  char *p;
+  size_t len;
+  union
+  {
+    struct in_addr in;
+#ifdef MAILUTILS_IPV6
+    struct in6_addr in6;
+#endif
+  } inaddr;
+  
+  p = strchr (str, '/');
+  if (p)
+    len = p - str;
+  else
+    len = strlen (str);
+
+  if (len > sizeof (ipbuf))
+    return MU_ERR_BUFSPACE;
+  
+  memcpy (ipbuf, str, len);
+  ipbuf[len] = 0;
+
+  if (mu_str_is_ipv4 (ipbuf))
+    cidr.family = AF_INET;
+#ifdef MAILUTILS_IPV6
+  else if (mu_str_is_ipv6 (ipbuf))
+    cidr.family = AF_INET6;
+#endif
+  else
+    return MU_ERR_FAMILY;
+
+  rc = inet_pton (cidr.family, ipbuf, &inaddr);
+  if (rc == -1)
+    return MU_ERR_FAMILY;
+  else if (rc == 0)
+    return MU_ERR_NONAME;
+  else if (rc != 1)
+    return MU_ERR_FAILURE;
+
+  cidr.len = _mu_inaddr_to_bytes (cidr.family, &inaddr, cidr.address);
+  if (cidr.len == 0)
+    return MU_ERR_FAMILY;
+
+  if (p)
+    {
+      char *end;
+      unsigned long masklen;
+      
+      p++;
+
+      masklen = strtoul (p, &end, 10);
+      if (*end == 0)
+       masklen_to_netmask (cidr.netmask, cidr.len, masklen);
+      else if ((cidr.family == AF_INET && mu_str_is_ipv4 (p))
+#ifdef MAILUTILS_IPV6
+              || (cidr.family == AF_INET6 && mu_str_is_ipv6 (ipbuf))
+#endif
+              )
+       {
+         rc = inet_pton (cidr.family, p, &inaddr);
+         if (rc == -1)
+           return MU_ERR_FAMILY;
+         else if (rc == 0)
+           return MU_ERR_NONAME;
+         else if (rc != 1)
+           return MU_ERR_FAILURE;
+
+         _mu_inaddr_to_bytes (cidr.family, &inaddr, cidr.netmask);
+       }
+      else
+       return MU_ERR_FAMILY;
+    }
+  else
+    masklen_to_netmask (cidr.netmask, cidr.len, cidr.len * 8);
+
+  memcpy (pcidr, &cidr, sizeof (*pcidr));
+  return 0;
+}
+
diff --git a/libmailutils/base/getmaxfd.c b/libmailutils/cidr/match.c
similarity index 70%
copy from libmailutils/base/getmaxfd.c
copy to libmailutils/cidr/match.c
index b905ac8..dff9194 100644
--- a/libmailutils/base/getmaxfd.c
+++ b/libmailutils/cidr/match.c
@@ -18,23 +18,21 @@
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
-
-#include <unistd.h>
-#include <limits.h>
-
-#if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX)
-# define __getmaxfd() sysconf (_SC_OPEN_MAX)
-#elif defined (HAVE_GETDTABLESIZE)
-# define __getmaxfd() getdtablesize ()
-#elif defined OPEN_MAX
-# define __getmaxfd() OPEN_MAX
-#else
-# define __getmaxfd() 256
-#endif
+#include <mailutils/cidr.h>
+#include <mailutils/errno.h>
 
 int
-mu_getmaxfd ()
+mu_cidr_match (struct mu_cidr *a, struct mu_cidr *b)
 {
-  return __getmaxfd ();
+  int i;
+
+  if (a->family != b->family)
+    return 1;
+  for (i = 0; i < a->len; i++)
+    {
+      if (a->address[i] != (b->address[i] & a->netmask[i]))
+       return 1;
+    }
+  return 0;
 }
-
+  
diff --git a/libmailutils/cidr/tosa.c b/libmailutils/cidr/tosa.c
new file mode 100644
index 0000000..c14a995
--- /dev/null
+++ b/libmailutils/cidr/tosa.c
@@ -0,0 +1,78 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <mailutils/cidr.h>
+#include <mailutils/errno.h>
+
+int
+mu_cidr_to_sockaddr (struct mu_cidr *cidr, struct sockaddr **psa)
+{
+  union
+  {
+    struct sockaddr sa;
+    struct sockaddr_in s_in;
+#ifdef MAILUTILS_IPV6
+    struct sockaddr_in6 s_in6;
+#endif
+  } addr;
+  struct sockaddr *sa;
+  int socklen;
+  int i;
+  
+  memset (&addr, 0, sizeof (addr));
+  addr.sa.sa_family = cidr->family;
+  switch (cidr->family)
+    {
+    case AF_INET:
+      socklen = sizeof (addr.s_in);
+      for (i = 0; i < cidr->len; i++)
+       {
+         addr.s_in.sin_addr.s_addr <<= 8;
+         addr.s_in.sin_addr.s_addr |= cidr->address[i];
+       }
+      break;
+
+#ifdef MAILUTILS_IPV6
+    case AF_INET6:
+      socklen = sizeof (addr.s_in6);
+      memcpy (&addr.s_in6.sin6_addr, cidr->address, 16);
+      break;
+#endif
+
+    default:
+      return MU_ERR_FAMILY;
+    }
+
+  sa = malloc (socklen);
+  if (!sa)
+    return ENOMEM;
+  memcpy (sa, &addr, socklen);
+  *psa = sa;
+  return 0;
+}
+
diff --git a/libmailutils/cidr/tostr.c b/libmailutils/cidr/tostr.c
new file mode 100644
index 0000000..3d1ee5f
--- /dev/null
+++ b/libmailutils/cidr/tostr.c
@@ -0,0 +1,159 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <string.h>
+#include <stdlib.h>
+#include <mailutils/cidr.h>
+#include <mailutils/errno.h>
+
+static int
+to_xdig (unsigned char b)
+{
+  if (b >= 0xa)
+    return 'A' + b - 0xa;
+  else
+    return '0' + b;
+}
+
+static size_t
+format_ipv6_bytes (const unsigned char *bytes, int len, 
+                  char *buf, size_t size)
+{
+  size_t total = 0;
+  int i;
+  
+  for (i = 0; i < len; i += 2)
+    {
+      if (i)
+       {
+         if (total++ < size)
+           *buf++ = ':';
+       }
+      if (total++ < size)
+       *buf++ = to_xdig (*bytes >> 4);
+      if (total++ < size)
+       *buf++ = to_xdig (*bytes & 0xf);
+      bytes++;
+      if (total++ < size)
+       *buf++ = to_xdig (*bytes >> 4);
+      if (total++ < size)
+       *buf++ = to_xdig (*bytes & 0xf);
+      bytes++;
+    }
+  return total;
+}
+
+static size_t
+format_ipv4_bytes (const unsigned char *bytes, int len, 
+                  char *buf, size_t size)
+{
+  int i;
+  size_t total = 0;
+  
+  for (i = 0; i < len; i++)
+    {
+      unsigned char b = *bytes++;
+      char nbuf[3];
+      int j;
+      
+      if (i)
+       {
+         if (total++ < size)
+           *buf++ = '.';
+       }
+
+      j = 0;
+      do
+       {
+         nbuf[j++] = b % 10 + '0';
+         b /= 10;
+       }
+      while (b);
+
+      for (; j; j--)
+       {
+         if (total++ < size)
+           *buf++ = nbuf[j - 1];
+       }
+    }
+  return total;
+}
+
+int
+mu_cidr_to_string (struct mu_cidr *cidr, int flags,
+                  char *buf, size_t size, size_t *pret)
+{
+  size_t (*fmt) (const unsigned char *bytes, int len, char *buf, size_t size);
+  size_t n, total = 0;
+  
+  if (size == 0)
+    return MU_ERR_BUFSPACE;
+  size--;
+  switch (cidr->family)
+    {
+    case AF_INET:
+      fmt = format_ipv4_bytes;
+      break;
+      
+#ifdef MAILUTILS_IPV6
+    case AF_INET6:
+      fmt = format_ipv6_bytes;
+      break;
+#endif
+
+    default:
+      return MU_ERR_FAMILY;
+    }
+
+  n = fmt (cidr->address, cidr->len, buf, size);
+  if (buf)
+    buf += n;
+  total += n;
+
+  if (!(flags & MU_CIDR_FMT_ADDRONLY))
+    {
+      if (total++ < size)
+       *buf++ = '/';
+      n = fmt (cidr->netmask, cidr->len, buf, size - total);
+      if (buf)
+       buf += n;
+      total += n;
+    }
+  
+  if (buf)
+    *buf++ = 0;
+  if (pret)
+    *pret = total;
+  return 0;
+}
+
+int
+mu_cidr_format (struct mu_cidr *cidr, int flags, char **pbuf)
+{
+  char buf[MU_CIDR_MAXBUFSIZE];
+  int rc = mu_cidr_to_string (cidr, flags, buf, sizeof (buf), NULL);
+  if (rc)
+    return rc;
+  *pbuf = strdup (buf);
+  if (!*buf)
+    return ENOMEM;
+  return 0;
+}
+
diff --git a/libmailutils/diag/debug.c b/libmailutils/diag/debug.c
index 124311b..aa10e41 100644
--- a/libmailutils/diag/debug.c
+++ b/libmailutils/diag/debug.c
@@ -689,6 +689,7 @@ mu_debug_log_begin (const char *fmt, ...)
   va_list ap;
 
   mu_diag_init ();
+  mu_stream_flush (mu_strerr);
   va_start (ap, fmt);
   mu_stream_printf (mu_strerr, "\033s<%d>", MU_LOG_DEBUG);
   mu_stream_vprintf (mu_strerr, fmt, ap);
diff --git a/libmailutils/diag/errors b/libmailutils/diag/errors
index 869e414..03f71b7 100644
--- a/libmailutils/diag/errors
+++ b/libmailutils/diag/errors
@@ -1,3 +1,4 @@
+
 # Error messages for GNU Mailutils
 # Copyright (C) 2005, 2006, 2007, 2010, 2011 Free Software Foundation,
 # Inc.
@@ -98,3 +99,10 @@ MU_ERR_URL_MISS_PARTS       _("URL missing required parts")
 MU_ERR_URL_EXTRA_PARTS      _("URL has parts not allowed by its scheme")
 
 MU_ERR_INFO_UNAVAILABLE            _("Information is not yet available")
+
+# The following are mapped to the corresponding EAI_ errors
+MU_ERR_NONAME              _("Name or service not known")
+MU_ERR_BADFLAGS                    _("Bad value for flags")
+MU_ERR_SOCKTYPE             _("Socket type not supported")
+MU_ERR_FAMILY               _("Address family not supported")
+MU_ERR_SERVICE              _("Requested service not supported")
diff --git a/libmailutils/server/acl.c b/libmailutils/server/acl.c
index 0b7a507..ba1a4b8 100644
--- a/libmailutils/server/acl.c
+++ b/libmailutils/server/acl.c
@@ -40,14 +40,20 @@
 #include <mailutils/kwd.h>
 #include <mailutils/io.h>
 #include <mailutils/util.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/cidr.h>
+#include <mailutils/stream.h>
+#include <mailutils/stdstream.h>
+
+#ifndef MU_INADDR_BYTES
+#define MU_INADDR_BYTES 16
+#endif
 
 struct _mu_acl_entry
 {
   mu_acl_action_t action;
   void *arg;
-  unsigned netmask;
-  int salen;
-  struct sockaddr sa[1];
+  struct mu_cidr cidr;
 };
 
 struct _mu_acl
@@ -64,52 +70,19 @@ _destroy_acl_entry (void *item)
   /* 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_cidr *cidr)
 {
-  struct _mu_acl_entry *p = malloc (mu_acl_entry_size (salen));
+  struct _mu_acl_entry *p = malloc (sizeof (*p));
   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;
-    }
+  memcpy (&p->cidr, cidr, sizeof (p->cidr));
+
   *pent = p;
   return 0;
 }
@@ -165,15 +138,14 @@ mu_acl_get_iterator (mu_acl_t acl, mu_iterator_t *pitr)
 
 int
 mu_acl_append (mu_acl_t acl, mu_acl_action_t act,
-              void *data, struct sockaddr *sa, int salen,
-              unsigned long netmask)
+              void *data, struct mu_cidr *cidr)
 {
   int rc;
   struct _mu_acl_entry *ent;
   
   if (!acl)
     return EINVAL;
-  rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask);
+  rc = mu_acl_entry_create (&ent, act, data, cidr);
   if (rc)
     {
       mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR, 
@@ -193,14 +165,14 @@ mu_acl_append (mu_acl_t acl, mu_acl_action_t act,
 
 int
 mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data,
-               struct sockaddr *sa, int salen, unsigned long netmask)
+               struct mu_cidr *cidr)
 {
   int rc;
   struct _mu_acl_entry *ent;
   
   if (!acl)
     return EINVAL;
-  rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask);
+  rc = mu_acl_entry_create (&ent, act, data, cidr);
   if (rc)
     {
       mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR,
@@ -219,8 +191,7 @@ mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void 
*data,
 
 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)
+              mu_acl_action_t act, void *data, struct mu_cidr *cidr)
 {
   int rc;
   void *ptr;
@@ -236,7 +207,7 @@ mu_acl_insert (mu_acl_t acl, size_t pos, int before,
                 ("No such entry %lu", (unsigned long) pos));
       return rc;
     }
-  rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask);
+  rc = mu_acl_entry_create (&ent, act, data, cidr);
   if (!ent)
     {
       mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR, 
@@ -279,124 +250,19 @@ mu_acl_string_to_action (const char *str, 
mu_acl_action_t *pres)
   return rc;
 }
 
-#define MU_S_UN_NAME(sa, salen) \
-  ((salen < mu_offsetof (struct sockaddr_un,sun_path)) ? "" : (sa)->sun_path)
-
-static void
-debug_sockaddr (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_log_cont ("{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_log_cont ("{AF_UNIX}");
-       else
-         mu_debug_log_cont ("{AF_UNIX %s}", s_un->sun_path);
-       break;
-      }
-
-    default:
-      mu_debug_log_cont ("{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)
+struct run_closure
 {
-  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;
-}
+  unsigned idx;
+  struct mu_cidr addr;
 
-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;
-}
+  char ipstr[40];
+  char *addrstr;
+  char *numbuf;
+  mu_acl_result_t *result;
+};
 
 int
-_acl_match (struct _mu_acl_entry *ent, struct sockaddr *sa, int salen)
+_acl_match (struct _mu_acl_entry *ent, struct run_closure *rp)
 {
 #define RESMATCH(word)                                   \
   if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9))     \
@@ -404,76 +270,26 @@ _acl_match (struct _mu_acl_entry *ent, struct sockaddr 
*sa, int salen)
                                                              
   if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9))
     {
-      struct in_addr a;
-      
-      mu_debug_log_begin ("Does ");
-      debug_sockaddr (sa, salen);
-      mu_debug_log_cont (" match ");
-      debug_sockaddr (ent->sa, salen);
-      a.s_addr = ent->netmask;
-      a.s_addr = htonl (a.s_addr);
-      mu_debug_log_cont (" netmask %s? ", inet_ntoa (a));
+      char *s;
+
+      if (ent->cidr.len == 0)
+       s = strdup ("any");
+      mu_cidr_format (&ent->cidr, 0, &s);
+      if (!rp->addrstr)
+       mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY, &rp->addrstr);
+      mu_debug_log_begin ("Does %s match %s? ", s, rp->addrstr);
+      free (s);
     }
 
-  if (ent->sa->sa_family != sa->sa_family)
+  if (ent->cidr.len > 0 && mu_cidr_match (&ent->cidr, &rp->addr))
     {
       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;
-  struct sockaddr *sa;
-  char *numbuf;
-  char *portbuf;
-  int salen;
-  mu_acl_result_t *result;
-};
-
 #define SEQ(s, n, l) \
   (((l) == (sizeof(s) - 1)) && memcmp (s, n, l) == 0)
 
@@ -489,40 +305,24 @@ acl_getvar (const char *name, size_t nlen, void *data)
       return rp->numbuf;
     }
   
-  switch (rp->sa->sa_family)
+  if (SEQ ("address", name, nlen))
     {
-    case AF_INET:
-      {
-       struct sockaddr_in *s_in = (struct sockaddr_in *)rp->sa;
-
-       if (SEQ ("address", name, nlen))
-         {
-           struct in_addr addr = s_in->sin_addr;
-           addr.s_addr = htonl (addr.s_addr);
-           return inet_ntoa (addr);
-         }
+      if (!rp->addrstr)
+       mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY, &rp->addrstr);
+      return rp->addrstr;
+    }
 
-       if (SEQ ("port", name, nlen))
-         {
-           if (!rp->portbuf &&
-               mu_asprintf (&rp->portbuf, "%hu", ntohs (s_in->sin_port)))
-             return NULL;
-           return rp->portbuf;
-         }
-       break;
-       
-      case AF_UNIX:
-       if (SEQ ("address", name, nlen))
-         {
-           struct sockaddr_un *s_un = (struct sockaddr_un *)rp->sa;
-           if (rp->salen == sizeof (s_un->sun_family))
-             return NULL;
-           else
-             return s_un->sun_path;
-         }
-      }
-      break;
+#if 0
+  /* FIXME?: */
+  if (SEQ ("port", name, nlen))
+    {
+      if (!rp->portbuf &&
+         mu_asprintf (&rp->portbuf, "%hu", ntohs (s_in->sin_port)))
+       return NULL;
+      return rp->portbuf;
     }
+#endif
+
   return NULL;
 }
 
@@ -535,12 +335,18 @@ expand_arg (const char *cmdline, struct run_closure *rp, 
char **s)
   
   mu_debug (MU_DEBCAT_ACL, MU_DEBUG_TRACE, ("Expanding \"%s\"", cmdline));
   env[0] = "family";
-  switch (rp->sa->sa_family)
+  switch (rp->addr.family)
     {
     case AF_INET:
       env[1] = "AF_INET";
       break;
 
+#ifdef MAILUTILS_IPV6
+    case AF_INET6:
+      env[1] = "AF_INET6";
+      break;
+#endif
+      
     case AF_UNIX:
       env[1] = "AF_UNIX";
       break;
@@ -654,7 +460,7 @@ _run_entry (void *item, void *data)
       mu_debug_log_begin ("%d:%s: ", rp->idx, s);
     }
   
-  if (_acl_match (ent, rp->sa, rp->salen) == 0)
+  if (_acl_match (ent, rp) == 0)
     {
       switch (ent->action)
        {
@@ -678,8 +484,10 @@ _run_entry (void *item, void *data)
              }
            else
              {
-               debug_sockaddr (rp->sa, rp->salen);
-               mu_debug_log_nl ();
+               if (!rp->addrstr)
+                 mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY,
+                                 &rp->addrstr);
+               mu_diag_output (MU_DIAG_INFO, "%s", rp->addrstr);
              }
          }
          break;
@@ -712,7 +520,7 @@ _run_entry (void *item, void *data)
     }
   
   if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9))
-     mu_debug_log_nl ();
+    mu_stream_flush (mu_strerr);
   
   return status;
 }
@@ -721,40 +529,39 @@ int
 mu_acl_check_sockaddr (mu_acl_t acl, const struct sockaddr *sa, int salen,
                       mu_acl_result_t *pres)
 {
+  int rc;
   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))
+  memset (&r, 0, sizeof (r));
+  if (sa->sa_family == AF_UNIX)
     {
-      free (r.sa);
-      return EINVAL;
+      *pres = mu_acl_result_accept;
+      return 0;
     }
-  r.salen = salen;
+  rc = mu_cidr_from_sockaddr (&r.addr, sa);
+  if (rc)
+    return rc;
   
   if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9))
     {
-      mu_debug_log_begin ("Checking sockaddr ");
-      debug_sockaddr (r.sa, r.salen);
+      mu_cidr_format (&r.addr, MU_CIDR_FMT_ADDRONLY, &r.addrstr);
+      mu_debug_log_begin ("Checking sockaddr %s", r.addrstr);
       mu_debug_log_nl ();
     }
 
   r.idx = 0;
   r.result = pres;
   *r.result = mu_acl_result_undefined;
-  r.numbuf = r.portbuf = NULL;
+  r.numbuf = NULL;
   mu_list_do (acl->aclist, _run_entry, &r);
   free (r.numbuf);
-  free (r.portbuf);
-  free (r.sa);
+  free (r.addrstr);
   return 0;
 }
-              
+
 int
 mu_acl_check_inaddr (mu_acl_t acl, const struct in_addr *inp,
                     mu_acl_result_t *pres)
@@ -780,10 +587,17 @@ mu_acl_check_ipv4 (mu_acl_t acl, unsigned int addr, 
mu_acl_result_t *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;
+  union
+  {
+    struct sockaddr sa;
+    struct sockaddr_in in;
+#ifdef MAILUTILS_IPV6
+    struct sockaddr_in6 in6;
+#endif
+  } addr;
+  socklen_t len = sizeof addr;
 
-  if (getpeername (fd, (struct sockaddr *) &cs, &len) < 0)
+  if (getpeername (fd, &addr.sa, &len) < 0)
     {
       mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR, 
                ("Cannot obtain IP address of client: %s",
@@ -791,6 +605,6 @@ mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t 
*pres)
       return MU_ERR_FAILURE;
     }
 
-  return mu_acl_check_sockaddr (acl, (struct sockaddr *) &cs, len, pres);
+  return mu_acl_check_sockaddr (acl, &addr.sa, len, pres);
 }
 
diff --git a/libmailutils/server/ipsrv.c b/libmailutils/server/ipsrv.c
index a802908..73b2e36 100644
--- a/libmailutils/server/ipsrv.c
+++ b/libmailutils/server/ipsrv.c
@@ -34,13 +34,13 @@
 #include <mailutils/diag.h>
 #include <mailutils/errno.h>
 #include <mailutils/nls.h>
+#include <mailutils/sockaddr.h>
 
 
 struct _mu_ip_server
 {
   char *ident;
-  struct sockaddr *addr;
-  int addrlen;
+  struct mu_sockaddr *addr;
   int fd;
   int type;
   mu_acl_t acl;
@@ -66,8 +66,7 @@ struct _mu_ip_server
 #define IDENTSTR(s) ((s)->ident ? (s)->ident : "default")
 
 int
-mu_ip_server_create (mu_ip_server_t *psrv, struct sockaddr *addr,
-                    int addrlen, int type)
+mu_ip_server_create (mu_ip_server_t *psrv, struct mu_sockaddr *addr, int type)
 {
   struct _mu_ip_server *srv;
 
@@ -84,14 +83,7 @@ mu_ip_server_create (mu_ip_server_t *psrv, struct sockaddr 
*addr,
   srv = calloc (1, sizeof *srv);
   if (!srv)
     return ENOMEM;
-  srv->addr = calloc (1, addrlen);
-  if (!srv->addr)
-    {
-      free (srv);
-      return ENOMEM;
-    }
-  memcpy (srv->addr, addr, addrlen);
-  srv->addrlen = addrlen;
+  srv->addr = addr;
   srv->type = type;
   srv->fd = -1;
   switch (type)
@@ -120,7 +112,7 @@ mu_ip_server_destroy (mu_ip_server_t *psrv)
   if (srv->f_free)
     srv->f_free (srv->data);
   close (srv->fd);
-  free (srv->addr);
+  mu_sockaddr_free (srv->addr);
   free (srv->ident);
   if (srv->type == MU_IP_UDP && srv->v.udp_data.buf)
     free (srv->v.udp_data.buf);
@@ -234,6 +226,11 @@ mu_address_family_to_domain (int family)
     case AF_INET:
       return PF_INET;
 
+#ifdef MAILUTILS_IPV6
+    case AF_INET6:
+      return PF_INET6;
+#endif
+      
     default:
       abort ();
     }
@@ -247,14 +244,11 @@ mu_ip_server_open (mu_ip_server_t srv)
   if (!srv || srv->fd != -1)
     return EINVAL;
 
-  if (mu_debug_level_p (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0))
-    {
-      char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
-      mu_debug_log ("opening server \"%s\" %s", IDENTSTR (srv), p);
-      free (p);
-    }
+  mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0,
+           ("opening server \"%s\" %s", IDENTSTR (srv),
+            mu_sockaddr_str (srv->addr)));
 
-  fd = socket (mu_address_family_to_domain (srv->addr->sa_family),
+  fd = socket (mu_address_family_to_domain (srv->addr->addr->sa_family),
               ((srv->type == MU_IP_UDP) ? SOCK_DGRAM : SOCK_STREAM), 0);
   if (fd == -1)
     {
@@ -263,7 +257,7 @@ mu_ip_server_open (mu_ip_server_t srv)
       return errno;
     }
   
-  switch (srv->addr->sa_family)
+  switch (srv->addr->addr->sa_family)
     {
     case AF_UNIX:
       {
@@ -299,7 +293,7 @@ mu_ip_server_open (mu_ip_server_t srv)
       }
       break;
 
-    case AF_INET:
+    default:
       {
        int t;
        
@@ -308,7 +302,7 @@ mu_ip_server_open (mu_ip_server_t srv)
       }
     }
   
-  if (bind (fd, srv->addr, srv->addrlen) == -1)
+  if (bind (fd, srv->addr->addr, srv->addr->addrlen) == -1)
     {
       mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR,
                ("%s: bind: %s", IDENTSTR (srv), mu_strerror (errno)));
@@ -336,12 +330,9 @@ mu_ip_server_shutdown (mu_ip_server_t srv)
 {
   if (!srv || srv->fd != -1)
     return EINVAL;
-  if (mu_debug_level_p (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0))
-    {
-      char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
-      mu_debug_log ("closing server \"%s\" %s", IDENTSTR (srv), p);
-      free (p);
-    }
+  mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0,
+           ("closing server \"%s\" %s", IDENTSTR (srv),
+            mu_sockaddr_str (srv->addr)));
   close (srv->fd);
   return 0;
 }
@@ -356,6 +347,9 @@ mu_ip_tcp_accept (mu_ip_server_t srv, void *call_data)
     struct sockaddr sa;
     struct sockaddr_in s_in;
     struct sockaddr_un s_un;
+#ifdef MAILUTILS_IPV6
+    struct sockaddr_in6 s_in6;
+#endif
   } client;
   
   socklen_t size = sizeof (client);
@@ -407,6 +401,9 @@ mu_ip_udp_accept (mu_ip_server_t srv, void *call_data)
     struct sockaddr sa;
     struct sockaddr_in s_in;
     struct sockaddr_un s_un;
+#ifdef MAILUTILS_IPV6
+    struct sockaddr_in6 s_in6;
+#endif
   } client;
   fd_set rdset;
   
@@ -463,7 +460,7 @@ mu_ip_udp_accept (mu_ip_server_t srv, void *call_data)
                   IDENTSTR (srv), strerror (rc)));
       if (res == mu_acl_result_deny)
        {
-         char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
+         char *p = mu_sockaddr_to_astr (&client.sa, salen);
          mu_diag_output (MU_DIAG_INFO, "Denying connection from %s", p);
          free (p);
          return 0;
@@ -528,22 +525,16 @@ mu_udp_server_get_rdata (mu_ip_server_t srv, char **pbuf, 
size_t *pbufsize)
 }
 
 int
-mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct sockaddr *s, int *size)
+mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct mu_sockaddr **psa)
 {
-  int len;
-  
-  if (!srv || !s)
+  if (!srv || !psa)
     return EINVAL;
-  if (s == 0)
-    len = srv->addrlen;
-  else
-    {
-      len = srv->addrlen;
-      if (*size < len)
-       return MU_ERR_BUFSPACE;
-      memcpy (s, srv->addr, len);
-    }
-  *size = len;
-  return 0;
+  return mu_sockaddr_copy (psa, srv->addr);
 }
-  
+
+const char *
+mu_ip_server_addrstr (mu_ip_server_t srv)
+{
+  return mu_sockaddr_str (srv->addr);
+}
+
diff --git a/libmailutils/server/msrv.c b/libmailutils/server/msrv.c
index 5c46e9d..d5ceb8a 100644
--- a/libmailutils/server/msrv.c
+++ b/libmailutils/server/msrv.c
@@ -41,6 +41,8 @@
 #include <mailutils/nls.h>
 #include <mailutils/daemon.h>
 #include <mailutils/acl.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/url.h>
 
 typedef RETSIGTYPE (*mu_sig_handler_t) (int);
 
@@ -65,19 +67,6 @@ set_signal (int sig, mu_sig_handler_t handler)
 # define NSIG 64
 #endif
 
-union m_sockaddr
-{
-  struct sockaddr s_sa;
-  struct sockaddr_in s_in;
-  struct sockaddr_un s_un;
-};
-
-struct m_default_address
-{
-  union m_sockaddr s;
-  int len;
-};
-
 struct _mu_m_server
 {
   char *ident;                   /* Server identifier, for logging purposes.*/
@@ -98,7 +87,7 @@ struct _mu_m_server
   size_t num_children;           /* Current number of running sub-processes. */
   pid_t *child_pid;
   char *pidfile;                 /* Name of a PID-file. */
-  struct m_default_address defaddr;  /* Default address. */
+  struct mu_sockaddr_hints hints; /* Default address hints. */
   time_t timeout;                /* Default idle timeout. */
   mu_acl_t acl;                  /* Global access control list. */
 
@@ -112,7 +101,7 @@ struct _mu_m_server
 struct m_srv_config        /* Configuration data for a single TCP server. */
 {
   mu_m_server_t msrv;      /* Parent m-server. */  
-  mu_ip_server_t tcpsrv;  /* TCP server these data are for. */
+  mu_ip_server_t tcpsrv;   /* TCP server these data are for. */
   mu_acl_t acl;            /* Access control list for this server. */ 
   int single_process;      /* Should it run as a single process? */
   int transcript;          /* Enable session transcript. */
@@ -395,33 +384,20 @@ mu_m_server_pidfile (mu_m_server_t srv)
 }
 
 void
-mu_m_server_set_default_address (mu_m_server_t srv, struct sockaddr *sa,
-                                int salen)
+mu_m_server_set_hints (mu_m_server_t srv, struct mu_sockaddr_hints *hints)
 {
-  if (salen > sizeof srv->defaddr.s)
-    {
-      mu_error (_("unhandled sockaddr size"));
-      abort ();
-    }
-  memcpy (&srv->defaddr.s.s_sa, sa, salen);
-  srv->defaddr.len = salen;
+  if (!hints)
+    memset (&srv->hints, 0, sizeof (srv->hints));
+  else
+    memcpy (&srv->hints, hints, sizeof (srv->hints));
 }
 
 int
-mu_m_server_get_default_address (mu_m_server_t srv, struct sockaddr *sa,
-                                int *salen)
+mu_m_server_get_hints (mu_m_server_t srv, struct mu_sockaddr_hints *hints)
 {
-  int len;
-  
-  if (!sa)
+  if (!hints)
     return EINVAL;
-  len = srv->defaddr.len;
-  if (sa)
-    {
-      if (*salen < len)
-       return MU_ERR_BUFSPACE;
-      memcpy (sa, &srv->defaddr.s.s_sa, len);
-    }
+  memcpy (hints, &srv->hints, sizeof (hints));
   return 0;
 }
 
@@ -429,11 +405,7 @@ mu_m_server_get_default_address (mu_m_server_t srv, struct 
sockaddr *sa,
 void
 mu_m_server_set_default_port (mu_m_server_t srv, int num)
 {
-  struct sockaddr_in s_in;
-  s_in.sin_family = AF_INET;
-  s_in.sin_addr.s_addr = htonl (INADDR_ANY);
-  s_in.sin_port = htons (num);
-  mu_m_server_set_default_address (srv, (struct sockaddr*) &s_in, sizeof s_in);
+  srv->hints.port = num;
 }
 
 void
@@ -473,12 +445,12 @@ static int m_srv_conn (int fd, struct sockaddr *sa, int 
salen,
                       mu_ip_server_t srv);
 
 static struct m_srv_config *
-add_server (mu_m_server_t msrv, struct sockaddr *s, int slen, int type)
+add_server (mu_m_server_t msrv, struct mu_sockaddr *s, int type)
 {
   mu_ip_server_t tcpsrv;
   struct m_srv_config *pconf;
 
-  MU_ASSERT (mu_ip_server_create (&tcpsrv, s, slen, type)); /* FIXME: type */
+  MU_ASSERT (mu_ip_server_create (&tcpsrv, s, type)); /* FIXME: type */
   MU_ASSERT (mu_ip_server_set_conn (tcpsrv, m_srv_conn));
   pconf = calloc (1, sizeof (*pconf));
   if (!pconf)
@@ -513,8 +485,21 @@ mu_m_server_begin (mu_m_server_t msrv)
     alloc_children (msrv);
 
   mu_list_count (msrv->srvlist, &count);
-  if (count == 0 && msrv->defaddr.len)
-    add_server (msrv, &msrv->defaddr.s.s_sa, msrv->defaddr.len, msrv->deftype);
+  if (count == 0)
+    {
+      struct mu_sockaddr *ta;
+
+      msrv->hints.flags = MU_AH_PASSIVE;
+      rc = mu_sockaddr_from_node (&ta, NULL, NULL, &msrv->hints);
+      if (rc == 0)
+       while (ta)
+         {
+           struct mu_sockaddr *next = ta->next;
+           ta->next = ta->prev = NULL;
+           add_server (msrv, ta, msrv->deftype);
+           ta = next;
+         }
+    }
   
   if (!msrv->foreground)
     {
@@ -599,23 +584,13 @@ tcp_conn_free (void *conn_data, void *server_data)
 static int
 _open_conn (void *item, void *data)
 {
-  union
-  {
-    struct sockaddr sa;
-    char pad[512];
-  }
-  addr;
-  int addrlen = sizeof addr;
-  char *p;
   mu_ip_server_t tcpsrv = item;
   mu_m_server_t msrv = data;
   int rc = mu_ip_server_open (tcpsrv);
   if (rc)
     {
-      mu_ip_server_get_sockaddr (tcpsrv, &addr.sa, &addrlen);
-      p = mu_sockaddr_to_astr (&addr.sa, addrlen);
-      mu_error (_("cannot open connection on %s: %s"), p, mu_strerror (rc));
-      free (p);
+      mu_error (_("cannot open connection on %s: %s"),
+               mu_ip_server_addrstr (tcpsrv), mu_strerror (rc));
       return 0;
     }
   rc = mu_server_add_connection (msrv->server,
@@ -624,10 +599,8 @@ _open_conn (void *item, void *data)
                                 tcp_conn_handler, tcp_conn_free);
   if (rc)
     {
-      mu_ip_server_get_sockaddr (tcpsrv, &addr.sa, &addrlen);
-      p = mu_sockaddr_to_astr (&addr.sa, addrlen);
-      mu_error (_("cannot add connection %s: %s"), p, mu_strerror (rc));
-      free (p);
+      mu_error (_("cannot add connection %s: %s"),
+               mu_ip_server_addrstr (tcpsrv), mu_strerror (rc));
       mu_ip_server_shutdown (tcpsrv);
       mu_ip_server_destroy (&tcpsrv);
     }
@@ -756,199 +729,55 @@ m_srv_conn (int fd, struct sockaddr *sa, int salen,
 }
 
 
-
-unsigned short
-get_port (const char *p)
-{
-  if (p)
-    {
-      char *q;
-      unsigned long n = strtoul (p, &q, 0);
-      if (*q == 0)
-       {
-         if (n > USHRT_MAX)
-           {
-             mu_error (_("invalid port number: %s"), p);
-             return 1;
-           }
-         
-         return htons (n);
-       }
-      else
-       {
-         struct servent *sp = getservbyname (p, "tcp");
-         if (!sp)
-           return 0;
-         return sp->s_port;
-       }
-    }
-  return 0;
-}
-
-static int
-get_family (const char **pstr, sa_family_t *pfamily)
-{
-  static struct family_tab
-  {
-    int len;
-    char *pfx;
-    int family;
-  } ftab[] = {
-#define S(s,f) { sizeof (#s":") - 1, #s":", f }
-    S (file, AF_UNIX),
-    S (unix, AF_UNIX),
-    S (local, AF_UNIX),
-    S (socket, AF_UNIX),
-    S (inet, AF_INET),
-    S (tcp, AF_INET),
-#undef S
-    { 0 }
-  };
-  struct family_tab *fp;
-  
-  const char *str = *pstr;
-  int len = strlen (str);
-  for (fp = ftab; fp->len; fp++)
-    {
-      if (len > fp->len && memcmp (str, fp->pfx, fp->len) == 0)
-       {
-         str += fp->len;
-         if (str[0] == '/' && str[1] == '/')
-           str += 2;
-         *pstr = str;
-         *pfamily = fp->family;
-         return 0;
-       }
-    }
-  return 1;
-}
-
-static int
-is_ip_addr (const char *arg)
-{
-  int     dot_count;
-  int     digit_count;
-
-  dot_count = 0;
-  digit_count = 0;
-  for (; *arg != 0 && *arg != ':'; arg++)
-    {
-      if (*arg == '.')
-       {
-         if (++dot_count > 3)
-           break;
-         digit_count = 0;
-       }
-      else if (!(mu_isdigit (*arg) && ++digit_count <= 3))
-       return 0;
-    }
-  return dot_count == 3;
-}  
-
 int
-_mu_m_server_parse_url (const char *arg, union m_sockaddr *s,
-                       int *psalen, struct sockaddr *defsa)
+mu_m_server_parse_url (mu_m_server_t msrv, const char *arg,
+                      struct mu_sockaddr **psa)
 {
-  char *p;
-  unsigned short n;
-  int len;
-      
-  if (is_ip_addr (arg))
-    s->s_sa.sa_family = AF_INET;
-  else if (get_family (&arg, &s->s_sa.sa_family))
+  int rc;
+  mu_url_t url, url_hint;
+
+  if (arg[0] == '/')
+    url_hint = NULL;
+  else
     {
-      mu_error (_("invalid family"));
-      return EINVAL;
+      rc = mu_url_create (&url_hint, "inet://");
+      if (rc)
+       return rc;
     }
-      
-  switch (s->s_sa.sa_family)
+  rc = mu_url_create_hint (&url, arg, MU_URL_PARSE_DEFAULT, url_hint);
+  mu_url_destroy (&url_hint);
+  if (rc)
     {
-    case AF_INET:
-      *psalen = sizeof (s->s_in);
-      if ((n = get_port (arg)))
-       {
-         s->s_in.sin_addr.s_addr = htonl (INADDR_ANY);
-         s->s_in.sin_port = htons (n);   
-       }
-      else
-       {
-         p = strchr (arg, ':');
-         if (p)
-           *p++ = 0;
-         if (inet_aton (arg, &s->s_in.sin_addr) == 0)
-           {
-             struct hostent *hp = gethostbyname (arg);
-             if (hp)
-               s->s_in.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
-             else
-               {
-                 mu_error (_("invalid IP address: %s"), arg);
-                 return EINVAL;
-               }
-           }
-         if (p)
-           {
-             n = get_port (p);
-             if (!n)
-               {
-                 mu_error (_("invalid port number: %s"), p);
-                 return EINVAL;
-               }
-             s->s_in.sin_port = n;
-           }
-         else if (defsa && defsa->sa_family == AF_INET)
-           s->s_in.sin_port = ((struct sockaddr_in*)defsa)->sin_port;
-         else
-           {
-             mu_error (_("missing port number"));
-             return EINVAL;
-           }
-       }
-      break;
-
-    case AF_UNIX:
-      *psalen = sizeof (s->s_un);
-      len = strlen (arg);
-      if (len > sizeof s->s_un.sun_path - 1)
-       {
-         mu_error (_("%s: file name too long"), arg);
-         return EINVAL;
-       }
-      strcpy (s->s_un.sun_path, arg);
-      break;
+      mu_error (_("cannot parse URL `%s': %s"), arg, mu_strerror (rc));
+      return rc;
     }
-  return 0;
-}
-
-int
-mu_m_server_parse_url (mu_m_server_t msrv, char *arg,
-                      struct sockaddr *sa, int *psalen)
-{
-  int rc;
-  union m_sockaddr s;
-  int salen;
 
-  rc = _mu_m_server_parse_url (arg, &s, &salen, &msrv->defaddr.s.s_sa);
+  msrv->hints.flags = MU_AH_PASSIVE;
+  rc = mu_sockaddr_from_url (psa, url, &msrv->hints);
   if (rc)
-    return rc;
-  if (sa)
-    {
-      if (*psalen < salen)
-       return MU_ERR_BUFSPACE;
-      memcpy (sa, &s.s_sa, salen);
-    }
-  *psalen = salen;
-  return 0;
+    mu_error (_("cannot create sockaddr for URL `%s': %s"), arg,
+             mu_strerror (rc));
+  mu_url_destroy (&url);
+  return rc;
 }
 
 static int
 server_block_begin (const char *arg, mu_m_server_t msrv, void **pdata)
 {
-  union m_sockaddr s;
-  int salen;
-  if (_mu_m_server_parse_url (arg, &s, &salen, &msrv->defaddr.s.s_sa))
+  struct mu_sockaddr *s;
+  if (mu_m_server_parse_url (msrv, arg, &s))
     return 1;
-  *pdata = add_server (msrv, &s.s_sa, salen, msrv->deftype);
+  if (s->next)
+    {
+      /* FIXME: (1) Find a way to handle all addresses.
+               (2) Print which address is being used.
+      */
+      mu_diag_output (MU_DIAG_WARNING,
+                     _("%s resolves to several addresses, "
+                       "only the first is used"), arg);
+      mu_sockaddr_free (s->next);
+    }
+  *pdata = add_server (msrv, s, msrv->deftype);
   return 0;
 }
 
@@ -1002,21 +831,46 @@ _cb_daemon_mode (void *data, mu_config_value_t *val)
   return 0;
 }
 
+unsigned short
+get_port (const char *p)
+{
+  if (p)
+    {
+      char *q;
+      unsigned long n = strtoul (p, &q, 0);
+      if (*q == 0)
+       {
+         if (n > USHRT_MAX)
+           {
+             mu_error (_("invalid port number: %s"), p);
+             return 1;
+           }
+         
+         return htons (n);
+       }
+      else
+       {
+         struct servent *sp = getservbyname (p, "tcp");
+         if (!sp)
+           return 0;
+         return sp->s_port;
+       }
+    }
+  return 0;
+}
+
 static int
 _cb_port (void *data, mu_config_value_t *val)
 {
-  struct m_default_address *ap = data;
+  struct mu_sockaddr_hints *hp = data;
   unsigned short num;
-
+  
   if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
     return 1;
   num = get_port (val->v.string);
   if (!num)
     return 1;
-  ap->s.s_in.sin_family = AF_INET;
-  ap->s.s_in.sin_addr.s_addr = htonl (INADDR_ANY);
-  ap->s.s_in.sin_port = num;
-  ap->len = sizeof ap->s.s_in;
+  hp->port = num;
   return 0;
 }
 
@@ -1036,7 +890,7 @@ static struct mu_cfg_param dot_server_cfg_param[] = {
     N_("Store PID of the master process in this file."),
     N_("file") },
   { "port", mu_cfg_callback,
-    NULL, mu_offsetof (struct _mu_m_server,defaddr), _cb_port,
+    NULL, mu_offsetof (struct _mu_m_server, hints), _cb_port,
     N_("Default port number.") },
   { "timeout", mu_cfg_time,
     NULL, mu_offsetof (struct _mu_m_server,timeout), NULL,
diff --git a/libmailutils/property/Makefile.am 
b/libmailutils/sockaddr/Makefile.am
similarity index 79%
copy from libmailutils/property/Makefile.am
copy to libmailutils/sockaddr/Makefile.am
index 60d10bc..dcfb184 100644
--- a/libmailutils/property/Makefile.am
+++ b/libmailutils/sockaddr/Makefile.am
@@ -1,5 +1,5 @@
 # GNU Mailutils -- a suite of utilities for electronic mail
-# Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+# Copyright (C) 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
@@ -15,16 +15,17 @@
 # Public License along with this library.  If not, see
 # <http://www.gnu.org/licenses/>.
 
-noinst_LTLIBRARIES = libproperty.la
+noinst_LTLIBRARIES = libsockaddr.la
 
-libproperty_la_SOURCES = \
- assocprop.c\
+libsockaddr_la_SOURCES = \
+ copy.c\
  create.c\
- mhprop.c\
- propclr.c\
- propget.c\
- propitr.c\
- propinv.c\
- propset.c
+ free.c\
+ fromnode.c\
+ insert.c\
+ ipaddr.c\
+ str.c\
+ unlink.c\
+ url.c
 
 INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
diff --git a/libmailutils/url/urlstr.c b/libmailutils/sockaddr/copy.c
similarity index 74%
copy from libmailutils/url/urlstr.c
copy to libmailutils/sockaddr/copy.c
index f2faa81..5e28e78 100644
--- a/libmailutils/url/urlstr.c
+++ b/libmailutils/sockaddr/copy.c
@@ -1,5 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 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
@@ -18,14 +18,19 @@
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
+
 #include <stdlib.h>
-#include <mailutils/types.h>
-#include <mailutils/sys/url.h>
+#include <mailutils/sockaddr.h>
 
-const char *
-mu_url_to_string (const mu_url_t url)
+int
+mu_sockaddr_copy (struct mu_sockaddr **pnew, struct mu_sockaddr *old)
 {
-  if (url == NULL || url->name == NULL)
-    return "";
-  return url->name;
+  if (!old)
+    {
+      *pnew = NULL;
+      return 0;
+    }
+  return mu_sockaddr_create (pnew, old->addr, old->addrlen);
 }
+
+
diff --git a/libmailutils/base/getmaxfd.c b/libmailutils/sockaddr/create.c
similarity index 65%
copy from libmailutils/base/getmaxfd.c
copy to libmailutils/sockaddr/create.c
index b905ac8..5b49471 100644
--- a/libmailutils/base/getmaxfd.c
+++ b/libmailutils/sockaddr/create.c
@@ -19,22 +19,29 @@
 # include <config.h>
 #endif
 
-#include <unistd.h>
-#include <limits.h>
-
-#if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX)
-# define __getmaxfd() sysconf (_SC_OPEN_MAX)
-#elif defined (HAVE_GETDTABLESIZE)
-# define __getmaxfd() getdtablesize ()
-#elif defined OPEN_MAX
-# define __getmaxfd() OPEN_MAX
-#else
-# define __getmaxfd() 256
-#endif
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <mailutils/sockaddr.h>
 
 int
-mu_getmaxfd ()
+mu_sockaddr_create (struct mu_sockaddr **res,
+                   struct sockaddr *addr, socklen_t len)
 {
-  return __getmaxfd ();
+  struct mu_sockaddr *sa;
+
+  sa = calloc (1, sizeof (*sa));
+  if (!sa)
+    return ENOMEM;
+  sa->addr = malloc (len);
+  if (!sa->addr)
+    {
+      free (sa);
+      return ENOMEM;
+    }
+  memcpy (sa->addr, addr, len);
+  sa->addrlen = len;
+  *res = sa;
+  return 0;
 }
 
diff --git a/libmailutils/base/getmaxfd.c b/libmailutils/sockaddr/free.c
similarity index 66%
copy from libmailutils/base/getmaxfd.c
copy to libmailutils/sockaddr/free.c
index b905ac8..2a31ec3 100644
--- a/libmailutils/base/getmaxfd.c
+++ b/libmailutils/sockaddr/free.c
@@ -19,22 +19,32 @@
 # include <config.h>
 #endif
 
-#include <unistd.h>
-#include <limits.h>
-
-#if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX)
-# define __getmaxfd() sysconf (_SC_OPEN_MAX)
-#elif defined (HAVE_GETDTABLESIZE)
-# define __getmaxfd() getdtablesize ()
-#elif defined OPEN_MAX
-# define __getmaxfd() OPEN_MAX
-#else
-# define __getmaxfd() 256
-#endif
+#include <stdlib.h>
+#include <mailutils/sockaddr.h>
 
-int
-mu_getmaxfd ()
+void
+mu_sockaddr_free (struct mu_sockaddr *addr)
 {
-  return __getmaxfd ();
+  if (!addr)
+    return;
+  free (addr->addr);
+  free (addr->str);
 }
 
+void
+mu_sockaddr_free_list (struct mu_sockaddr *addr)
+{
+  if (!addr)
+    return;
+  if (addr->prev)
+    addr->prev->next = NULL;
+  while (addr)
+    {
+      struct mu_sockaddr *next = addr->next;
+      mu_sockaddr_free (addr);
+      addr = next;
+    }
+}
+
+
+    
diff --git a/libmailutils/sockaddr/fromnode.c b/libmailutils/sockaddr/fromnode.c
new file mode 100644
index 0000000..d79b952
--- /dev/null
+++ b/libmailutils/sockaddr/fromnode.c
@@ -0,0 +1,253 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/url.h>
+#include <mailutils/io.h>
+#include <mailutils/errno.h>
+#include <mailutils/error.h>
+#include <mailutils/nls.h>
+
+static struct mu_sockaddr *
+match_sa (struct mu_sockaddr *list, struct sockaddr *sa, socklen_t len)
+{
+  for (; list; list = list->next)
+    if (len == list->addrlen && memcmp (list->addr, sa, len) == 0)
+      break;
+  return list;
+}
+
+int
+mu_sockaddr_from_node (struct mu_sockaddr **retval, const char *node,
+                      const char *serv, struct mu_sockaddr_hints *mh)
+{
+  int rc;
+
+  if (!mh)
+    {
+      static struct mu_sockaddr_hints nullhints = { 0, AF_UNSPEC };
+      mh = &nullhints;
+    }
+
+  if (mh->family == AF_UNIX)
+    {
+      size_t slen;
+      struct sockaddr_un s_un;
+
+      if (!node)
+       return MU_ERR_NONAME;
+      slen = strlen (node);
+      if (slen >= sizeof s_un.sun_path)
+       return MU_ERR_BUFSPACE;
+
+      s_un.sun_family = AF_UNIX;
+      strcpy(s_un.sun_path, node);
+      return mu_sockaddr_create (retval, (struct sockaddr*) &s_un,
+                                sizeof (s_un));
+    }
+  else 
+#ifdef MAILUTILS_IPV6
+    {
+      struct addrinfo hints;
+      struct addrinfo *res, *ap;
+      char portbuf[64];
+      struct mu_sockaddr *tail = NULL;
+      
+      memset (&hints, 0, sizeof (hints));
+      hints.ai_family = mh->family;
+      hints.ai_socktype = mh->socktype;
+      hints.ai_protocol = mh->protocol;
+
+      if (!node)
+       {
+         if (mh->flags & MU_AH_PASSIVE)
+           hints.ai_flags |= AI_PASSIVE;
+         else
+           return MU_ERR_NONAME;
+       }
+      if (!serv && mh->port)
+       {
+         snprintf (portbuf, sizeof portbuf, "%hu", mh->port);
+         serv = portbuf;
+       }
+       
+      rc = getaddrinfo (node, serv, &hints, &res);
+
+      switch (rc)
+       {
+       case 0:
+         break;
+
+       case EAI_FAIL:
+         return MU_ERR_GETHOSTBYNAME;
+         
+       case EAI_FAMILY:
+         return MU_ERR_FAMILY;
+
+       case EAI_NONAME:
+         return MU_ERR_NONAME;
+         
+       case EAI_SERVICE:
+         return MU_ERR_SERVICE;
+
+       case EAI_SYSTEM:
+         mu_error (_("%s:%s: cannot parse address: %s"),
+                   node, serv, mu_strerror (errno));
+         return errno;
+                       
+       case EAI_BADFLAGS:
+         return MU_ERR_BADFLAGS;
+         
+       case EAI_SOCKTYPE:
+         return MU_ERR_SOCKTYPE;
+                       
+       case EAI_MEMORY:
+         return ENOMEM;
+                       
+       default:
+         mu_error ("%s:%s: %s", node, serv, gai_strerror (rc));
+         return MU_ERR_FAILURE;
+       }
+
+      *retval = NULL;
+      for (ap = res; ap; ap = ap->ai_next)
+       if (mh->family == AF_UNSPEC || ap->ai_addr->sa_family == mh->family)
+         {
+           struct mu_sockaddr *sa;
+
+           if (match_sa (*retval, ap->ai_addr, ap->ai_addrlen))
+             continue;
+           rc = mu_sockaddr_create (&sa, ap->ai_addr, ap->ai_addrlen);
+           if (rc)
+             {
+               mu_sockaddr_free_list (*retval);
+               freeaddrinfo (res);
+               return rc;
+             }
+           if (tail)
+             mu_sockaddr_insert (tail, sa, 0);
+           else
+             *retval = sa;
+           tail = sa;
+         }
+      freeaddrinfo (res);
+    }
+#else
+  if (mh->family == AF_INET)
+    {
+      short port;
+      struct hostent *hp;
+      struct mu_sockaddr *tail = NULL;
+      char **p;
+
+      if (serv)
+       {
+         char *end;
+         unsigned long n = strtoul (serv, &end, 10);
+
+         if (*end)
+           {
+             struct servent *sp;
+             const char *proto;
+
+             if (mh->protocol)
+               {
+                 struct protoent *pp = getprotobynumber (mh->protocol);
+                 if (!pp)
+                   return EINVAL;
+                 proto = pp->p_name;
+               }
+             else
+               proto = NULL;
+             
+             sp = getservbyname (serv, proto);
+             if (!sp)
+               return MU_ERR_SERVICE;
+             port = sp->s_port;
+           }
+         else if (n == 0 || (port = n) != n)
+           return MU_ERR_PARSE; /* FIXME: need MU_ERR_RANGE? */
+       }
+      else if (mh->port)
+       port = htons (mh->port);
+      else
+       return MU_ERR_NONAME;
+
+      if (!node)
+       {
+         struct sockaddr_in s_in;
+
+         if (!(mh->flags & MU_AH_PASSIVE))
+           return MU_ERR_NONAME;
+
+         s_in.sin_family = AF_INET;
+         s_in.sin_addr.s_addr = INADDR_ANY;
+         s_in.sin_port = port;
+         return mu_sockaddr_create (retval, (struct sockaddr*)&s_in,
+                                    sizeof (s_in));
+       }
+      
+      hp = gethostbyname (node);
+      if (!hp)
+       return MU_ERR_GETHOSTBYNAME;
+
+      if (hp->h_addrtype != AF_INET || hp->h_length != 4)
+       return MU_ERR_FAMILY;
+
+      for (p = hp->h_addr_list; *p; p++)
+       {
+         struct mu_sockaddr *sa;
+         struct sockaddr_in s_in;
+
+         s_in.sin_family = AF_INET;
+         memcpy(&s_in.sin_addr, *p, 4);
+         s_in.sin_port = port;
+           
+         rc = mu_sockaddr_create (&sa, (struct sockaddr*)&s_in,
+                                  sizeof (s_in));
+         if (rc)
+           {
+             mu_sockaddr_free_list (*retval);
+             return rc;
+           }
+         if (tail)
+           mu_sockaddr_insert (tail, sa, 0);
+         else
+           *retval = sa;
+         tail = sa;
+       }
+    }
+  else
+    return MU_ERR_FAMILY;
+#endif
+  return 0;
+}
diff --git a/libmailutils/base/getmaxfd.c b/libmailutils/sockaddr/insert.c
similarity index 53%
copy from libmailutils/base/getmaxfd.c
copy to libmailutils/sockaddr/insert.c
index b905ac8..dbac151 100644
--- a/libmailutils/base/getmaxfd.c
+++ b/libmailutils/sockaddr/insert.c
@@ -19,22 +19,46 @@
 # include <config.h>
 #endif
 
-#include <unistd.h>
-#include <limits.h>
-
-#if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX)
-# define __getmaxfd() sysconf (_SC_OPEN_MAX)
-#elif defined (HAVE_GETDTABLESIZE)
-# define __getmaxfd() getdtablesize ()
-#elif defined OPEN_MAX
-# define __getmaxfd() OPEN_MAX
-#else
-# define __getmaxfd() 256
-#endif
+#include <stdlib.h>
+#include <mailutils/sockaddr.h>
 
-int
-mu_getmaxfd ()
+static void
+set_next (struct mu_sockaddr *sp, struct mu_sockaddr *tgt)
 {
-  return __getmaxfd ();
+  for (; sp->next; sp = sp->next)
+    ;
+  sp->next = tgt;
+  if (tgt)
+    tgt->prev = sp;
 }
 
+struct mu_sockaddr *
+mu_sockaddr_insert (struct mu_sockaddr *anchor, struct mu_sockaddr *addr,
+                   int before)
+{
+  struct mu_sockaddr *ret = anchor;
+
+  if (!anchor)
+    {
+      addr->prev = NULL;
+      set_next (addr, NULL);
+      return addr;
+    }
+  
+  if (before)
+    {
+      if (anchor->prev)
+       anchor = anchor->prev;
+      else
+       {
+         addr->prev = NULL;
+         set_next (addr, anchor);
+         return addr;
+       }
+    }
+
+  set_next (addr, anchor->next);
+  anchor->next = addr;
+  addr->prev = anchor;
+  return ret;
+}
diff --git a/libmailutils/sockaddr/ipaddr.c b/libmailutils/sockaddr/ipaddr.c
new file mode 100644
index 0000000..6b14b4c
--- /dev/null
+++ b/libmailutils/sockaddr/ipaddr.c
@@ -0,0 +1,88 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <string.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/cctype.h>
+
+int 
+mu_str_is_ipv4 (const char *addr)
+{
+  int dot_count = 0;
+  int digit_count = 0;
+
+  for (; *addr; addr++)
+    {
+      if (!mu_isascii (*addr))
+       return 0;
+      if (*addr == '.')
+       {
+         if (++dot_count > 3)
+           break;
+         digit_count = 0;
+       }
+      else if (!(mu_isdigit (*addr) && ++digit_count <= 3))
+       return 0;
+    }
+
+  return (dot_count == 3);
+}
+
+int 
+mu_str_is_ipv6 (const char *addr)
+{
+  int col_count = 0; /* Number of colons */
+  int dcol = 0;      /* Did we encounter a double-colon? */
+  int dig_count = 0; /* Number of digits in the last group */
+       
+  for (; *addr; addr++)
+    {
+      if (!mu_isascii (*addr))
+       return 0;
+      else if (mu_isxdigit (*addr))
+       {
+         if (++dig_count > 4)
+           return 0;
+       }
+      else if (*addr == ':')
+       {
+         if (col_count && dig_count == 0 && ++dcol > 1)
+           return 0;
+         if (++col_count > 7)
+           return 0;
+         dig_count = 0;
+       }
+      else
+       return 0;
+    }
+  
+  return (col_count == 7 || dcol);
+}
+
+int
+mu_str_is_ipaddr (const char *addr)
+{
+  if (strchr (addr, '.'))
+    return mu_str_is_ipv4(addr);
+  else if (strchr (addr, ':'))
+    return mu_str_is_ipv6(addr);
+  return 0;
+}
diff --git a/libmailutils/sockaddr/str.c b/libmailutils/sockaddr/str.c
new file mode 100644
index 0000000..949f21e
--- /dev/null
+++ b/libmailutils/sockaddr/str.c
@@ -0,0 +1,109 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <mailutils/sockaddr.h>
+#include <mailutils/errno.h>
+#include <mailutils/io.h>
+
+static char *default_sockaddr_text = "[not enogh memory]";
+
+#define S_UN_NAME(sa, salen) \
+       ((salen < mu_offsetof(struct sockaddr_un,sun_path)) ?   \
+         "" : (sa)->sun_path)
+
+int
+mu_sockaddr_format (char **pbuf, const struct sockaddr *sa, socklen_t salen)
+{
+  int rc = MU_ERR_FAILURE;
+  
+  switch (sa->sa_family)
+    {
+#ifdef MAILUTILS_IPV6
+    case AF_INET:
+    case AF_INET6:
+      {
+       char host[NI_MAXHOST];
+       char srv[NI_MAXSERV];
+       if (getnameinfo (sa, salen,
+                        host, sizeof (host), srv, sizeof (srv),
+                        NI_NUMERICHOST|NI_NUMERICSERV) == 0)
+         {
+           if (sa->sa_family == AF_INET6)
+             rc = mu_asprintf (pbuf, "inet6://[%s]:%s", host, srv);
+           else
+             rc = mu_asprintf (pbuf, "inet://%s:%s", host, srv);
+         }
+       else
+         rc = mu_asprintf (pbuf, "%s://[getnameinfo failed]",
+                           sa->sa_family == AF_INET ?
+                           "inet" : "inet6");
+       break;
+      }
+#else
+    case AF_INET:
+      {
+       struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
+       rc = mu_asprintf (pbuf, "inet://%s:%hu",
+                         inet_ntoa (s_in->sin_addr), s_in->sin_port);
+       break;
+      }
+#endif
+      
+    case AF_UNIX:
+      {
+       struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
+       if (S_UN_NAME (s_un, salen)[0] == 0)
+         rc = mu_asprintf (pbuf, "unix://[anonymous socket]");
+       else
+         rc = mu_asprintf (pbuf, "unix://%s", s_un->sun_path);
+       break;
+      }
+
+    default:
+      rc = mu_asprintf (pbuf, "family:%d", sa->sa_family);
+    }
+  return rc;
+}
+
+char *
+mu_sockaddr_to_astr (const struct sockaddr *sa, int salen)
+{
+  char *buf = NULL;
+  mu_sockaddr_format (&buf, sa, salen);
+  return buf;
+}
+
+const char *
+mu_sockaddr_str (struct mu_sockaddr *sa)
+{
+       if (!sa->str && mu_sockaddr_format (&sa->str, sa->addr, sa->addrlen))
+         return default_sockaddr_text;
+       return sa->str;
+}
+
+
diff --git a/libmailutils/base/getmaxfd.c b/libmailutils/sockaddr/unlink.c
similarity index 70%
copy from libmailutils/base/getmaxfd.c
copy to libmailutils/sockaddr/unlink.c
index b905ac8..65808f5 100644
--- a/libmailutils/base/getmaxfd.c
+++ b/libmailutils/sockaddr/unlink.c
@@ -19,22 +19,27 @@
 # include <config.h>
 #endif
 
-#include <unistd.h>
-#include <limits.h>
-
-#if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX)
-# define __getmaxfd() sysconf (_SC_OPEN_MAX)
-#elif defined (HAVE_GETDTABLESIZE)
-# define __getmaxfd() getdtablesize ()
-#elif defined OPEN_MAX
-# define __getmaxfd() OPEN_MAX
-#else
-# define __getmaxfd() 256
-#endif
+#include <stdlib.h>
+#include <mailutils/sockaddr.h>
 
-int
-mu_getmaxfd ()
+struct mu_sockaddr *
+mu_sockaddr_unlink (struct mu_sockaddr *addr)
 {
-  return __getmaxfd ();
+  struct mu_sockaddr *p;
+
+  if (!addr)
+    return NULL;
+
+  p = addr->prev;
+  if (p)
+    p->next = addr->next;
+  
+  p = addr->next;
+  if (p)
+    p->prev = addr->prev;
+
+  addr->prev = addr->next = NULL;
+  
+  return p;
 }
 
diff --git a/libmailutils/sockaddr/url.c b/libmailutils/sockaddr/url.c
new file mode 100644
index 0000000..0eaf870
--- /dev/null
+++ b/libmailutils/sockaddr/url.c
@@ -0,0 +1,130 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/url.h>
+#include <mailutils/io.h>
+#include <mailutils/errno.h>
+#include <mailutils/nls.h>
+#include <mailutils/kwd.h>
+
+static struct mu_kwd famtab[] = {
+  { "unix", AF_UNIX },
+  { "local", AF_UNIX },
+  { "inet4", AF_INET },
+#ifdef MAILUTILS_IPV6
+  { "inet6", AF_INET6 },
+  { "inet",  AF_UNSPEC },
+#else
+  { "inet",  AF_INET },
+#endif
+  { NULL }
+};
+
+int
+mu_sockaddr_from_url (struct mu_sockaddr **retval, mu_url_t url,
+                     struct mu_sockaddr_hints *mh)
+{
+  int rc;
+  const char *scheme;
+  const char *node = NULL, *serv = NULL;
+  struct mu_sockaddr_hints hints;
+  
+  if (mh)
+    memcpy (&hints, mh, sizeof (hints));
+  else
+    {
+      memset (&hints, sizeof(hints), 0);
+      hints.family = AF_UNSPEC;
+      hints.socktype = SOCK_STREAM;
+      hints.protocol = IPPROTO_TCP;
+    }
+
+  if (hints.family == AF_UNSPEC)
+    {
+      rc = mu_url_sget_scheme (url, &scheme);
+      if (rc)
+       return rc;
+
+      if (mu_kwd_xlat_name (famtab, scheme, &hints.family))
+       {
+         if (hints.flags & MU_AH_DETECT_FAMILY)
+           {
+             int flags = 0;
+             
+             mu_url_get_flags (url, &flags);
+#ifdef MAILUTILS_IPV6
+             if (flags & MU_URL_IPV6)
+               hints.family = AF_INET6;
+             else
+#endif
+               if (flags & (MU_URL_HOST|MU_URL_PORT))
+                 hints.family = AF_INET;
+             else if (flags & MU_URL_PATH)
+               hints.family = AF_UNIX;
+             else
+               return MU_ERR_FAMILY;
+           }
+         else
+           return MU_ERR_FAMILY;
+       }
+    }
+  
+  if (hints.family == AF_UNIX)
+    {
+      rc = mu_url_sget_path (url, &node);
+      if (rc)
+       {
+         if (rc == MU_ERR_NOENT)
+           {
+             rc = mu_url_sget_host (url, &node);
+             if (rc == MU_ERR_NOENT)
+               return MU_ERR_NONAME;
+           }
+         if (rc)
+           return rc;
+       }
+    }
+  else
+    {
+#ifdef MAILUTILS_IPV6
+      if (hints.family == AF_UNSPEC)
+       hints.family = mu_url_has_flag (url, MU_URL_IPV6) ? AF_INET6 : AF_INET;
+#endif
+      rc = mu_url_sget_host (url, &node);
+      if (rc && rc != MU_ERR_NOENT)
+       return MU_ERR_NONAME;
+      rc = mu_url_sget_portstr (url, &serv);
+      if (rc && rc != MU_ERR_NOENT)
+       return MU_ERR_NONAME;
+    }
+  return mu_sockaddr_from_node (retval, node, serv, &hints);
+}
diff --git a/libmailutils/stream/tcp.c b/libmailutils/stream/tcp.c
index 40b3712..f383f1b 100644
--- a/libmailutils/stream/tcp.c
+++ b/libmailutils/stream/tcp.c
@@ -39,7 +39,7 @@
 #include <mailutils/errno.h>
 #include <mailutils/stream.h>
 #include <mailutils/util.h>
-
+#include <mailutils/sockaddr.h>
 #include <mailutils/sys/stream.h>
 
 #define TCP_STATE_INIT                 1
@@ -52,18 +52,11 @@ struct _tcp_instance
 {
   struct _mu_stream stream;
   int          fd;
-  char                 *host;
-  unsigned short port;
   int          state;
-  unsigned long        address;
-  unsigned long source_addr;
+  struct mu_sockaddr *remote_addr;
+  struct mu_sockaddr *source_addr;
 };
 
-/* On solaris inet_addr() return -1.  */
-#ifndef INADDR_NONE
-# define INADDR_NONE (unsigned long)-1
-#endif
-
 static int
 _tcp_close (mu_stream_t stream)
 {
@@ -83,28 +76,12 @@ _tcp_close (mu_stream_t stream)
 }
 
 static int
-resolve_hostname (const char *host, unsigned long *ip)
-{
-  unsigned long address = inet_addr (host);
-  if (address == INADDR_NONE)
-    {
-      struct hostent *phe = gethostbyname (host);
-      if (!phe)
-       return MU_ERR_GETHOSTBYNAME;
-      address = *(((unsigned long **) phe->h_addr_list)[0]);
-    }
-  *ip = address;
-  return 0;
-}
-
-static int
 _tcp_open (mu_stream_t stream)
 {
   struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
   int flgs, ret;
   socklen_t namelen;
   struct sockaddr_in peer_addr;
-  struct sockaddr_in soc_addr;
   int flags;
 
   mu_stream_get_flags (stream, &flags);
@@ -114,7 +91,8 @@ _tcp_open (mu_stream_t stream)
     case TCP_STATE_INIT:
       if (tcp->fd == -1)
        {
-         if ((tcp->fd = socket (PF_INET, SOCK_STREAM, 0)) == -1)
+         tcp->fd = socket (tcp->remote_addr->addr->sa_family, SOCK_STREAM, 0);
+         if (tcp->fd == -1)
            return errno;
        }
       if (flags & MU_STREAM_NONBLOCK)
@@ -124,13 +102,10 @@ _tcp_open (mu_stream_t stream)
          fcntl (tcp->fd, F_SETFL, flgs);
          mu_stream_set_flags (stream, MU_STREAM_NONBLOCK);
        }
-      if (tcp->source_addr != INADDR_ANY)
+      if (tcp->source_addr)
        {
-         struct sockaddr_in s;
-         s.sin_family = AF_INET;
-         s.sin_addr.s_addr = tcp->source_addr;
-         s.sin_port = 0;
-         if (bind (tcp->fd, (struct sockaddr*) &s, sizeof(s)) < 0)
+         if (bind (tcp->fd, tcp->source_addr->addr,
+                   tcp->source_addr->addrlen) < 0)
            {
              int e = errno;
              close (tcp->fd);
@@ -142,27 +117,11 @@ _tcp_open (mu_stream_t stream)
       tcp->state = TCP_STATE_RESOLVING;
       
     case TCP_STATE_RESOLVING:
-      if (!(tcp->host != NULL && tcp->port > 0))
-       {
-         _tcp_close (stream);
-         return EINVAL;
-       }
-      
-      if ((ret = resolve_hostname (tcp->host, &tcp->address)))
-       {
-         _tcp_close (stream);
-         return ret;
-       }
       tcp->state = TCP_STATE_RESOLVE;
       
     case TCP_STATE_RESOLVE:
-      memset (&soc_addr, 0, sizeof (soc_addr));
-      soc_addr.sin_family = AF_INET;
-      soc_addr.sin_port = htons (tcp->port);
-      soc_addr.sin_addr.s_addr = tcp->address;
-
-      if ((connect (tcp->fd,
-                   (struct sockaddr *) &soc_addr, sizeof (soc_addr))) == -1)
+      if (connect (tcp->fd, tcp->remote_addr->addr,
+                  tcp->remote_addr->addrlen) == -1)
        {
          ret = errno;
          if (ret == EINPROGRESS || ret == EAGAIN)
@@ -254,10 +213,8 @@ _tcp_done (mu_stream_t stream)
 {
   struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
 
-  if (tcp->host)
-    free (tcp->host);
-  if (tcp->fd != -1)
-    close (tcp->fd);
+  mu_sockaddr_free (tcp->remote_addr);
+  mu_sockaddr_free (tcp->source_addr);
 }
 
 int
@@ -315,33 +272,21 @@ _create_tcp_stream (int flags)
 }
 
 int
-mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
-                                    const char *host, unsigned port,
-                                    unsigned long source_ip,
-                                    int flags)
+mu_tcp_stream_create_from_sa (mu_stream_t *pstream,
+                             struct mu_sockaddr *remote_addr,
+                             struct mu_sockaddr *source_addr, int flags)
 {
   int rc;
   mu_stream_t stream;
   struct _tcp_instance *tcp;
 
-  if (host == NULL)
-    return MU_ERR_TCP_NO_HOST;
-
-  if (port > USHRT_MAX)
-    return MU_ERR_TCP_NO_PORT;
-
   tcp = _create_tcp_stream (flags | MU_STREAM_RDWR);
   if (!tcp)
     return ENOMEM;
-  tcp->host = strdup (host);
-  if (!tcp->host)
-    {
-      free (tcp);
-      return ENOMEM;
-    }
-  tcp->port = port;
-  tcp->state = TCP_STATE_INIT;
-  tcp->source_addr = source_ip;
+
+  tcp->remote_addr = remote_addr;
+  tcp->source_addr = source_addr;
+  
   stream = (mu_stream_t) tcp;
   rc = mu_stream_open (stream);
   if (rc == 0 || rc == EAGAIN || rc == EINPROGRESS)
@@ -351,24 +296,93 @@ mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
   return rc;
 }
 
+
+int
+mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
+                                    const char *host, unsigned port,
+                                    unsigned long source_ip,
+                                    int flags)
+{
+  int rc;
+  struct mu_sockaddr *remote_addr, *source_addr = NULL;
+  struct mu_sockaddr_hints hints;
+  
+  memset (&hints, 0, sizeof hints);
+  hints.family = AF_INET;
+  hints.socktype = SOCK_STREAM;
+  hints.protocol = IPPROTO_TCP;
+  hints.port = port;
+  rc = mu_sockaddr_from_node (&remote_addr, host, NULL, &hints);
+  if (rc)
+    return rc;
+
+  if (source_ip)
+    {
+      struct sockaddr_in s;
+      s.sin_family = AF_INET;
+      s.sin_addr.s_addr = source_ip;
+      s.sin_port = 0;
+      rc = mu_sockaddr_create (&source_addr, (struct sockaddr*)&s,
+                              sizeof (s));
+      if (rc)
+       {
+         mu_sockaddr_free (remote_addr);
+         return 0;
+       }
+    }
+
+  rc = mu_tcp_stream_create_from_sa (pstream, remote_addr, source_addr, flags);
+  if (rc)
+    {
+      mu_sockaddr_free (remote_addr);
+      mu_sockaddr_free (source_addr);
+    }
+  return rc;
+}
+
 int
 mu_tcp_stream_create_with_source_host (mu_stream_t *stream,
                                       const char *host, unsigned port,
                                       const char *source_host,
                                       int flags)
 {
-  unsigned long source_addr;
-  int ret = resolve_hostname (source_host, &source_addr);
-  if (ret == 0)
-    ret = mu_tcp_stream_create_with_source_ip (stream, host, port,
-                                              source_addr, flags);
-  return ret;
+  int rc;
+  struct mu_sockaddr *remote_addr, *source_addr = NULL;
+  struct mu_sockaddr_hints hints;
+  
+  memset (&hints, 0, sizeof hints);
+  hints.family = AF_INET;
+  hints.socktype = SOCK_STREAM;
+  hints.port = port;
+  rc = mu_sockaddr_from_node (&remote_addr, host, NULL, &hints);
+  if (rc)
+    return rc;
+
+  if (source_host)
+    {
+      hints.flags = MU_AH_PASSIVE;
+      hints.port = 0;
+      rc = mu_sockaddr_from_node (&source_addr, source_host, NULL, &hints);
+      if (rc)
+       {
+         mu_sockaddr_free (remote_addr);
+         return 0;
+       }
+    }
+
+  rc = mu_tcp_stream_create_from_sa (stream, remote_addr, source_addr, flags);
+  if (rc)
+    {
+      mu_sockaddr_free (remote_addr);
+      mu_sockaddr_free (source_addr);
+    }
+  return rc;
 }
        
 int
 mu_tcp_stream_create (mu_stream_t *stream, const char *host, unsigned port,
                      int flags)
 {
-  return mu_tcp_stream_create_with_source_ip (stream, host, port,
-                                             INADDR_ANY, flags);
+  return mu_tcp_stream_create_with_source_host (stream, host, port,
+                                               NULL, flags);
 }
diff --git a/libmailutils/tests/.gitignore b/libmailutils/tests/.gitignore
index d205efe..d01d4ad 100644
--- a/libmailutils/tests/.gitignore
+++ b/libmailutils/tests/.gitignore
@@ -1,5 +1,6 @@
 atconfig
 atlocal
+cidr
 package.m4
 testsuite
 testsuite.dir
diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am
index 68618a1..5c00873 100644
--- a/libmailutils/tests/Makefile.am
+++ b/libmailutils/tests/Makefile.am
@@ -41,6 +41,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
 INCLUDES = @MU_LIB_COMMON_INCLUDES@ 
 noinst_PROGRAMS = \
  addr\
+ cidr\
  debugspec\
  decode2047\
  encode2047\
diff --git a/libmailutils/tests/cidr.c b/libmailutils/tests/cidr.c
new file mode 100644
index 0000000..797fb24
--- /dev/null
+++ b/libmailutils/tests/cidr.c
@@ -0,0 +1,77 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <stdio.h>
+#include <mailutils/mailutils.h>
+
+static void
+print_bytes (unsigned char *b, size_t l)
+{
+  for (; l; l--, b++)
+    printf (" %02x", *b);
+  printf ("\n");
+}
+
+int
+main (int argc, char **argv)
+{
+  mu_set_program_name (argv[0]);
+  if (argc < 2)
+    {
+      mu_error ("usage: %s CIDR [CIDR...]", argv[0]);
+      return 1;
+    }
+
+  while (--argc)
+    {
+      char *arg = *++argv;
+      struct mu_cidr cidr;
+      int rc;
+      char *str;
+      
+      rc = mu_cidr_from_string (&cidr, arg);
+      if (rc)
+       {
+         mu_error ("%s: %s", arg, mu_strerror (rc));
+         continue;
+       }
+
+      printf ("%s:\n", arg);
+      printf ("family = %d\n", cidr.family);
+      printf ("len = %d\n", cidr.len);
+      printf ("address =");
+      print_bytes (cidr.address, cidr.len);
+      printf ("netmask =");
+      print_bytes (cidr.netmask, cidr.len);
+      rc = mu_cidr_format (&cidr, 0, &str);
+      if (rc)
+       {
+         mu_error ("cannot covert to string: %s", mu_strerror (rc));
+         return 2;
+       }
+
+      printf ("string = %s\n", str);
+      free (str);
+    }
+  return 0;
+}
+       
+         
diff --git a/libmailutils/tests/url-parse.c b/libmailutils/tests/url-parse.c
index 86c9173..48dd40f 100644
--- a/libmailutils/tests/url-parse.c
+++ b/libmailutils/tests/url-parse.c
@@ -25,6 +25,7 @@
 #include <mailutils/errno.h>
 #include <mailutils/url.h>
 #include <mailutils/secret.h>
+#include <mailutils/kwd.h>
 
 #define CAT2(a,b) a ## b
 
@@ -73,12 +74,52 @@ print_query (mu_url_t url)
     printf ("query[%lu] <%s>\n", (unsigned long) i, qargv[i]);
 }
 
+struct mu_kwd parse_kwtab[] = {
+  { "hexcode", MU_URL_PARSE_HEXCODE },
+  { "hidepass", MU_URL_PARSE_HIDEPASS },
+  { "portsrv", MU_URL_PARSE_PORTSRV },
+  { "portwc", MU_URL_PARSE_PORTWC },
+  { "pipe",  MU_URL_PARSE_PIPE },
+  { "slash", MU_URL_PARSE_SLASH },
+  { "dslash_optional", MU_URL_PARSE_DSLASH_OPTIONAL },
+  { "default", MU_URL_PARSE_DEFAULT },
+  { "all", MU_URL_PARSE_ALL },
+  { NULL }
+};
+
+
 int
-main ()
+main (int argc, char **argv)
 {
   char str[1024];
   unsigned port = 0;
-  mu_url_t u = NULL;
+  mu_url_t u = NULL, uhint = NULL;
+  int i;
+  int parse_flags = 0;
+  int rc;
+  
+  mu_set_program_name (argv[0]);
+  for (i = 1; i < argc; i++)
+    {
+      int flag;
+
+      if (strncmp (argv[i], "hint=", 5) == 0)
+       {
+         rc = mu_url_create (&uhint, argv[i] + 5);
+         if (rc)
+           {
+             mu_error ("cannot create hints: %s", mu_strerror (rc));
+             exit (1);
+           }
+       }
+      else if (mu_kwd_xlat_name_ci (parse_kwtab, argv[i], &flag) == 0)
+       parse_flags |= flag;
+      else
+       {
+         mu_error ("%s: unknown flag %s", argv[0], argv[i]);
+         exit (1);
+       }
+    }
 
   while (fgets (str, sizeof (str), stdin) != NULL)
     {
@@ -89,9 +130,9 @@ main ()
       str[strlen (str) - 1] = '\0';     /* chop newline */
       if (strspn (str, " \t") == strlen (str))
         continue;               /* skip empty lines */
-      if ((rc = mu_url_create (&u, str)) != 0)
+      if ((rc = mu_url_create_hint (&u, str, parse_flags, uhint)) != 0)
         {
-          fprintf (stderr, "mu_url_create %s ERROR: [%d] %s",
+          fprintf (stderr, "mu_url_create %s ERROR: [%d] %s\n",
                    str, rc, mu_strerror (rc));
           exit (1);
         }
diff --git a/libmailutils/tests/url.at b/libmailutils/tests/url.at
index 8c392ea..c0669e2 100644
--- a/libmailutils/tests/url.at
+++ b/libmailutils/tests/url.at
@@ -20,10 +20,11 @@ dnl TESTURL([NAME], [KW = `'], [INPUT], [STDOUT = `'],
 dnl         [STDERR = `'], [RUN-IF-FAIL], [RUN-IF-PASS])
 dnl
 
+m4_pushdef([URL_PARSE_OPTIONS])
 m4_pushdef([TESTURL],[
 m4_pushdef([MU_TEST_GROUP],[Url])
 m4_pushdef([MU_TEST_KEYWORDS],[url])
-m4_pushdef([MU_TEST_COMMAND],[url-parse])
+m4_pushdef([MU_TEST_COMMAND],[url-parse URL_PARSE_OPTIONS])
 MU_GENERIC_TEST([$1],[$2 url-m4_translit($3,[ ],[_])],[$3],[],[$4],[$5])
 m4_popdef([MU_TEST_COMMAND])
 m4_popdef([MU_TEST_KEYWORDS])
@@ -32,6 +33,8 @@ m4_popdef([MU_TEST_GROUP])
 
 dnl ------------------------------------------------------------
 
+m4_define([URL_PARSE_OPTIONS],[default dslash_optional])
+
 TESTURL([],[],
 [scheme:],
 [scheme <scheme>
@@ -76,6 +79,10 @@ port 0
 path </absolute/path>
 ])
 
+dnl ------------------------------------------------------------
+
+m4_define([URL_PARSE_OPTIONS],[default])
+
 TESTURL([],[],
 [scheme://%75%73%65%72:address@hidden,
 [scheme <scheme>
@@ -198,7 +205,7 @@ path </a/path>
 ])
 
 TESTURL([],[],
-[ftp:/a/path],
+[ftp:///a/path],
 [scheme <ftp>
 user <>
 passwd <>
@@ -716,6 +723,7 @@ path <mbox/address@hidden>
 param[0] <type=pass>
 ]])
 
+m4_pushdef([URL_PARSE_OPTIONS],[default dslash_optional])
 TESTURL([],[],
 [mbox:/var/spool/mail;type=index;param=2;user=gray],
 [[scheme <mbox>
@@ -729,6 +737,7 @@ param[0] <type=index>
 param[1] <param=2>
 param[2] <user=gray>
 ]])
+m4_popdef([URL_PARSE_OPTIONS])
 
 TESTURL([],[],
 [mbox:///var/spool/mail;type=index;param=2;user=gray],
@@ -823,3 +832,4 @@ query[1] <address@hidden>
 ]])
 
 m4_popdef([TESTURL])
+m4_popdef([URL_PARSE_OPTIONS])
diff --git a/libmailutils/url/create.c b/libmailutils/url/create.c
index e580640..130b7a2 100644
--- a/libmailutils/url/create.c
+++ b/libmailutils/url/create.c
@@ -59,9 +59,9 @@ getkn (struct mu_url_ctx *ctx, char *delim)
   size_t n;
 
   if (*ctx->cur == 0)
-    return -1;
+    return MU_ERR_PARSE;
   n = strcspn (ctx->cur, delim);
-  if (n > ctx->toksize)
+  if (n + 1 > ctx->toksize)
     {
       char *p = realloc (ctx->tokbuf, n + 1);
       if (!p)
@@ -220,11 +220,28 @@ _mu_url_ctx_parse_host (struct mu_url_ctx *ctx, int 
has_host)
   int rc;
   mu_url_t url = ctx->url;
   
-  rc = getkn (ctx, ":/;?");
+  rc = getkn (ctx, "[:/;?");
   if (rc)
     return rc;
 
-  if (ctx->toklen)
+  if (*ctx->cur == '[')
+    {
+      /* Possibly IPv6 address */
+      rc = getkn (ctx, "]/;?");
+      if (rc)
+       return rc;
+      if (*ctx->cur == ']')
+       {
+         ctx->cur++;
+         rc = str_assign (&url->host, ctx->tokbuf + 1);
+         if (rc)
+           return rc;
+         url->flags |= MU_URL_HOST | MU_URL_IPV6;
+         has_host = 1;
+       }
+    }
+
+  if (!(url->flags & MU_URL_HOST) && ctx->toklen)
     {
       rc = str_assign (&url->host, ctx->tokbuf);
       if (rc)
@@ -232,22 +249,20 @@ _mu_url_ctx_parse_host (struct mu_url_ctx *ctx, int 
has_host)
       url->flags |= MU_URL_HOST;
       has_host = 1;
     }
-
+  
   if (*ctx->cur == ':')
     {
-      ctx->cur++;
       has_host = 1;
-
-      rc = getkn (ctx, "/;?");
+      ctx->cur++;
+      rc = getkn (ctx, ":/;?");
       if (rc)
        return rc;
-      
       rc = str_assign (&url->portstr, ctx->tokbuf);
       if (rc)
        return rc;
       url->flags |= MU_URL_PORT;
     }
-
+    
   if (*ctx->cur == '/')
     {
       if (has_host)
@@ -269,7 +284,9 @@ _mu_url_ctx_parse_cred (struct mu_url_ctx *ctx)
   int rc, has_cred;
   mu_url_t url = ctx->url;
   const char *save = ctx->cur;
-  
+
+  if (*ctx->cur == 0)
+    return 0;
   rc = getkn (ctx, "@");
   if (rc)
     return rc;
@@ -343,12 +360,18 @@ _mu_url_ctx_parse (struct mu_url_ctx *ctx)
 {
   int rc;
   mu_url_t url = ctx->url;
+  const char *save = ctx->cur;
   
   /* Parse the scheme part */
+  if (*ctx->cur == ':')
+    return _mu_url_ctx_parse_cred (ctx);
+  
   rc = getkn (ctx, ":/");
   if (rc)
     return rc;
-  if (*ctx->cur == ':')
+  if (*ctx->cur == ':'
+      && ((ctx->flags & MU_URL_PARSE_DSLASH_OPTIONAL)
+         || (ctx->cur[1] == '/' && ctx->cur[2] == '/')))
     {
       rc = str_assign (&url->scheme, ctx->tokbuf);
       if (rc)
@@ -356,7 +379,12 @@ _mu_url_ctx_parse (struct mu_url_ctx *ctx)
       url->flags |= MU_URL_SCHEME;
       ctx->cur++;
     }
-
+  else
+    {
+      ctx->cur = save;
+      return _mu_url_ctx_parse_cred (ctx);
+    }
+  
   if (*ctx->cur == 0)
     return 0;
 
@@ -535,5 +563,6 @@ mu_url_create (mu_url_t *purl, const char *str)
                             MU_URL_PARSE_HIDEPASS |
                             MU_URL_PARSE_PORTSRV |
                             MU_URL_PARSE_PIPE |
-                            MU_URL_PARSE_SLASH, NULL);
+                            MU_URL_PARSE_SLASH |
+                            MU_URL_PARSE_DSLASH_OPTIONAL, NULL);
 }
diff --git a/libmu_cfg/acl.c b/libmu_cfg/acl.c
index cfa9a54..e39b5fb 100644
--- a/libmu_cfg/acl.c
+++ b/libmu_cfg/acl.c
@@ -22,6 +22,7 @@
 #include "mailutils/libcfg.h"
 #include "mailutils/acl.h"
 #include "mailutils/argcv.h"
+#include "mailutils/cidr.h"
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -53,53 +54,13 @@ getword (mu_config_value_t *val, int *pn)
   return v->v.string;
 }
 
-struct netdef
-{
-  struct sockaddr *sa;
-  int len;
-  unsigned long netmask;
-};
-
-#ifndef INADDR_ANY
-# define INADDR_ANY 0
-#endif
-
-int
-parse_address (const char *str, struct netdef *nd)
-{
-  struct sockaddr_in in;
-  
-  in.sin_family = AF_INET;
-  if (strcmp (str, "any") == 0)
-    {
-      in.sin_addr.s_addr = INADDR_ANY;
-      nd->netmask = 0;
-    }
-  else if (inet_aton (str, &in.sin_addr) == 0)
-    {
-      mu_error (_("invalid IPv4: %s"), str);
-      return 1;
-    }
-  in.sin_port = 0;
-  nd->len = sizeof (in);
-  nd->sa = malloc (nd->len);
-  if (!nd->sa)
-    {
-      mu_error ("%s", mu_strerror (errno));
-      return 1;
-    }
-  memcpy (nd->sa, &in, sizeof (in));
-  return 0;
-}
-
 static int
-parsearg (mu_config_value_t *val, struct netdef *pnd, char **prest) 
+parsearg (mu_config_value_t *val, struct mu_cidr *cidr, char **prest) 
 {
   const char *w;
-  char *p;  
-  unsigned long netmask;
   int n = 0;
-
+  int rc;
+  
   if (mu_cfg_assert_value_type (val, MU_CFG_ARRAY))
     return 1;
   
@@ -111,51 +72,19 @@ parsearg (mu_config_value_t *val, struct netdef *pnd, char 
**prest)
     if (!w)
       return 1;
   }
-  
-  p = strchr (w, '/');
-  if (p)
-    {
-      char *q;
-      unsigned netlen;
 
-      /* FIXME: This modifies a const char! */
-      *p++ = 0;
-      netlen = strtoul (p, &q, 10);
-      if (*q == 0)
-       {
-         if (netlen == 0)
-           netmask = 0;
-         else
-           {
-             netmask = 0xfffffffful >> (32 - netlen);
-             netmask <<= (32 - netlen);
-             netmask = htonl (netmask);
-           }
-       }
-      else if (*q == '.')
-       {
-         struct in_addr addr;
-             
-         if (inet_aton (p, &addr) == 0)
-           {
-             mu_error (_("invalid netmask"));
-             return 1;
-           }
-         netmask = addr.s_addr;
-       }
-      else
+  if (strcmp (w, "any") == 0)
+    cidr->len = 0;
+  else
+    {
+      rc = mu_cidr_from_string (cidr, w);
+      if (rc)
        {
-         mu_error (_("invalid netmask"));
+         mu_error (_("invalid source CIDR: %s"), mu_strerror (rc));
          return 1;
        }
     }
-  else
-    netmask = 0xfffffffful;
-
-  pnd->netmask = netmask;
-  if (parse_address (w, pnd))
-    return 1;
-
+  
   if (prest)
     {
       if (n == val->v.arg.c)
@@ -204,15 +133,13 @@ cb_allow (void *data, mu_config_value_t *val)
 {
   int rc;
   mu_acl_t acl = *(mu_acl_t*)data;
-  struct netdef ndef;
+  struct mu_cidr cidr;
   
-  if (parsearg (val, &ndef, NULL))
+  if (parsearg (val, &cidr, NULL))
     return 1;
-  rc = mu_acl_append (acl, mu_acl_accept, NULL, ndef.sa, ndef.len,
-                     ndef.netmask);
+  rc = mu_acl_append (acl, mu_acl_accept, NULL, &cidr);
   if (rc)
     mu_error (_("cannot append acl entry: %s"), mu_strerror (rc));
-  free (ndef.sa);
   return rc;
 }
 
@@ -221,15 +148,13 @@ cb_deny (void *data, mu_config_value_t *val)
 {
   int rc;
   mu_acl_t acl = *(mu_acl_t*)data;
-  struct netdef ndef;
+  struct mu_cidr cidr;
   
-  if (parsearg (val, &ndef, NULL))
+  if (parsearg (val, &cidr, NULL))
     return 1;
-  rc = mu_acl_append (acl, mu_acl_deny, NULL, ndef.sa, ndef.len,
-                     ndef.netmask);
+  rc = mu_acl_append (acl, mu_acl_deny, NULL, &cidr);
   if (rc)
     mu_error (_("cannot append acl entry: %s"), mu_strerror (rc));
-  free (ndef.sa);
   return rc;
 }
 
@@ -238,16 +163,14 @@ cb_log (void *data, mu_config_value_t *val)
 {
   int rc;
   mu_acl_t acl = *(mu_acl_t*)data;
-  struct netdef ndef;
+  struct mu_cidr cidr;
   char *rest;
   
-  if (parsearg (val, &ndef, &rest))
+  if (parsearg (val, &cidr, &rest))
     return 1;
-  rc = mu_acl_append (acl, mu_acl_log, rest, ndef.sa, ndef.len,
-                     ndef.netmask);
+  rc = mu_acl_append (acl, mu_acl_log, rest, &cidr);
   if (rc)
     mu_error (_("cannot append acl entry: %s"), mu_strerror (rc));
-  free (ndef.sa);
   return rc;
 }
 
@@ -256,16 +179,14 @@ cb_exec (void *data, mu_config_value_t *val)
 {
   int rc;
   mu_acl_t acl = *(mu_acl_t*)data;
-  struct netdef ndef;
+  struct mu_cidr cidr;
   char *rest;
   
-  if (parsearg (val, &ndef, &rest))
+  if (parsearg (val, &cidr, &rest))
     return 1;
-  rc = mu_acl_append (acl, mu_acl_exec, rest, ndef.sa, ndef.len,
-                     ndef.netmask);
+  rc = mu_acl_append (acl, mu_acl_exec, rest, &cidr);
   if (rc)
     mu_error (_("cannot append acl entry: %s"), mu_strerror (rc));
-  free (ndef.sa);
   return rc;
 }
 
@@ -274,16 +195,14 @@ cb_ifexec (void *data, mu_config_value_t *val)
 {
   int rc;
   mu_acl_t acl = *(mu_acl_t*)data;
-  struct netdef ndef;
+  struct mu_cidr cidr;
   char *rest;
   
-  if (parsearg (val, &ndef, &rest))
+  if (parsearg (val, &cidr, &rest))
     return 1;
-  rc = mu_acl_append (acl, mu_acl_ifexec, rest, ndef.sa, ndef.len,
-                     ndef.netmask);
+  rc = mu_acl_append (acl, mu_acl_ifexec, rest, &cidr);
   if (rc)
     mu_error (_("cannot append acl entry: %s"), mu_strerror (rc));
-  free (ndef.sa);
   return rc;
 }
 
diff --git a/libproto/mailer/smtp.c b/libproto/mailer/smtp.c
index fdda4b6..892a0ce 100644
--- a/libproto/mailer/smtp.c
+++ b/libproto/mailer/smtp.c
@@ -48,6 +48,7 @@
 #include <mailutils/smtp.h>
 #include <mailutils/tls.h>
 #include <mailutils/cstr.h>
+#include <mailutils/sockaddr.h>
 #include <mailutils/sys/mailer.h>
 #include <mailutils/sys/url.h>
 #include <mailutils/sys/registrar.h>
@@ -114,8 +115,7 @@ smtp_mailer_add_auth_mech (struct _smtp_mailer 
*smtp_mailer, const char *str)
 static int
 smtp_open (mu_mailer_t mailer, int flags)
 {
-  const char *host, *auth;
-  unsigned port;
+  const char *auth;
   struct _smtp_mailer *smtp_mailer = mailer->data;
   int rc;
   size_t parmc = 0;
@@ -138,12 +138,6 @@ smtp_open (mu_mailer_t mailer, int flags)
   mu_smtp_set_param (smtp_mailer->smtp, MU_SMTP_PARAM_URL,
                     mu_url_to_string (mailer->url));
 
-  rc = mu_url_sget_host (mailer->url, &host);
-  if (rc)
-    return rc;
-  if (mu_url_get_port (mailer->url, &port))
-    port = 25;
-
   if (mu_url_sget_auth (mailer->url, &auth) == 0)
     smtp_mailer_add_auth_mech (smtp_mailer, auth);
   
@@ -166,7 +160,20 @@ smtp_open (mu_mailer_t mailer, int flags)
   
   if (mailer->stream == NULL)
     {
-      rc = mu_tcp_stream_create (&mailer->stream, host, port, mailer->flags);
+      struct mu_sockaddr *sa;
+      struct mu_sockaddr_hints hints;
+
+      memset (&hints, 0, sizeof (hints));
+      hints.flags = MU_AH_DETECT_FAMILY;
+      hints.port = 25;
+      hints.protocol = IPPROTO_TCP;
+      hints.socktype = SOCK_STREAM;
+      rc = mu_sockaddr_from_url (&sa, mailer->url, &hints);
+      if (rc)
+       return rc;
+      
+      rc = mu_tcp_stream_create_from_sa (&mailer->stream, sa, NULL,
+                                        mailer->flags);
       if (rc)
        return rc;
       mu_stream_set_buffer (mailer->stream, mu_buffer_line, 0);
diff --git a/libproto/pop/mbox.c b/libproto/pop/mbox.c
index 67d97a9..79854ae 100644
--- a/libproto/pop/mbox.c
+++ b/libproto/pop/mbox.c
@@ -27,6 +27,7 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <netdb.h>
 
 #include <mailutils/pop3.h>
 #include <mailutils/attribute.h>
@@ -50,6 +51,7 @@
 #include <mailutils/cstr.h>
 #include <mailutils/cctype.h>
 #include <mailutils/opool.h>
+#include <mailutils/sockaddr.h>
 
 #include <mailutils/sys/folder.h>
 #include <mailutils/sys/mailbox.h>
@@ -109,23 +111,26 @@ pop_open (mu_mailbox_t mbox, int flags)
 {
   struct _pop3_mailbox *mpd = mbox->data;
   int status;
-  const char *host;
-  unsigned port = mpd->pops ? MU_POPS_PORT : MU_POP_PORT;
   mu_stream_t stream;
-  
+  struct mu_sockaddr *sa;
+  struct mu_sockaddr_hints hints;
+
   /* Sanity checks. */
   if (mpd == NULL)
     return EINVAL;
   
-  /* Fetch the pop server name and the port in the mu_url_t.  */
-  status = mu_url_sget_host (mbox->url, &host);
-  if (status != 0)
-    return status;
-  mu_url_get_port (mbox->url, &port);
-
   mbox->flags = flags;
-
-  status = mu_tcp_stream_create (&stream, host, port, mbox->flags);
+  
+  memset (&hints, 0, sizeof (hints));
+  hints.flags = MU_AH_DETECT_FAMILY;
+  hints.port = mpd->pops ? MU_POPS_PORT : MU_POP_PORT;
+  hints.protocol = IPPROTO_TCP;
+  hints.socktype = SOCK_STREAM;
+  status = mu_sockaddr_from_url (&sa, mbox->url, &hints);
+  if (status)
+    return status;
+      
+  status = mu_tcp_stream_create_from_sa (&stream, sa, NULL, mbox->flags);
   if (status)
     return status;
 #ifdef WITH_TLS
diff --git a/mh/tests/comp.at b/mh/tests/comp.at
index a7367c2..30af571 100644
--- a/mh/tests/comp.at
+++ b/mh/tests/comp.at
@@ -18,8 +18,8 @@ m4_pushdef([MH_KEYWORDS],[comp])
 m4_pushdef([compcmd],[comp -editor $abs_top_srcdir/mh/tests/mhed])
 
 MH_CHECK([comp -file],[comp00 comp-file],[
-echo quit | compcmd -file ./infile | remove_curdir
-cat infile
+echo quit | compcmd -file ./infile | remove_curdir | sed 's/ *$//'
+sed 's/ *$//' infile
 ],
 [0],
 [-- Editor invocation: ./infile
@@ -51,8 +51,8 @@ Subject:
 What now?])
 
 MH_CHECK([comp file],[comp02 comp_file],[
-echo 'quit' | compcmd file | remove_curdir
-cat Mail/file 
+echo 'quit' | compcmd file | remove_curdir | sed 's/ *$//'
+sed 's/ *$//' Mail/file 
 ],
 [0], 
 [-- Editor invocation: Mail/file
@@ -78,8 +78,8 @@ Subject: test input
 message body
 ])
 
-echo 'quit' | compcmd -use file | remove_curdir
-cat Mail/file 
+echo 'quit' | compcmd -use file | remove_curdir | sed 's/ *$//'
+sed 's/ *$//' Mail/file 
 ],
 [0], 
 [-- Editor invocation: Mail/file
@@ -108,11 +108,11 @@ Subject: test input
 message body
 ])
 
-echo 'quit' | compcmd +inbox 1 | remove_curdir
+echo 'quit' | compcmd +inbox 1 | remove_curdir | sed 's/ *$//'
 echo Mail/draft
-cat Mail/draft
+sed 's/ *$//' Mail/draft
 echo Message
-cat Mail/inbox/1
+sed 's/ *$//' Mail/inbox/1
 ],
 [0], 
 [-- Editor invocation: Mail/draft
@@ -141,8 +141,8 @@ message body
 
 MH_CHECK([comp -draftfolder],[comp05 comp-draftfolder draftfolder],[
 mkdir Mail/drafts
-echo 'quit' | compcmd -draftfolder drafts | remove_curdir
-cat Mail/drafts/1
+echo 'quit' | compcmd -draftfolder drafts | remove_curdir | sed 's/ *$//'
+sed 's/ *$//' Mail/drafts/1
 ],
 [0],
 [-- Editor invocation: Mail/drafts/1
@@ -170,8 +170,8 @@ message body
 ])
 echo "cur: 1" > Mail/drafts/.mh_sequences
 
-echo 'quit' | compcmd -draftfolder drafts -use| remove_curdir
-cat Mail/drafts/1
+echo 'quit' | compcmd -draftfolder drafts -use| remove_curdir | sed 's/ *$//'
+sed 's/ *$//' Mail/drafts/1
 ],
 [0],
 [-- Editor invocation: Mail/drafts/1
diff --git a/mu/acl.c b/mu/acl.c
index 9e9fd8b..4f796c5 100644
--- a/mu/acl.c
+++ b/mu/acl.c
@@ -41,36 +41,10 @@ static struct argp_option acl_options[] = {
 };
 
 static char *input_file_name;
-static struct sockaddr *target_sa;
-static socklen_t target_salen;
+static struct mu_sockaddr *target_sa;
 static mu_acl_t acl;
 static const char *path = "acl";
 
-static struct sockaddr *
-parse_address (socklen_t *psalen, const char *str)
-{
-  struct sockaddr_in in;
-  struct sockaddr *sa;
-  
-  in.sin_family = AF_INET;
-  if (inet_aton (str, &in.sin_addr) == 0)
-    {
-      mu_error ("Invalid IPv4: %s", str);
-      exit (1);
-    }
-  in.sin_port = 0;
-  *psalen = sizeof (in);
-  sa = malloc (*psalen);
-  if (!sa)
-    {
-      mu_error ("%s", mu_strerror (errno));
-      exit (1);
-    }
-  
-  memcpy (sa, &in, sizeof (in));
-  return sa;
-}
-
 static error_t
 acl_parse_opt (int key, char *arg, struct argp_state *state)
 {
@@ -160,9 +134,17 @@ mutool_acl (int argc, char **argv)
     {
       const char *ap = *argv++;
 
-      target_sa = parse_address (&target_salen, ap);
+      rc = mu_sockaddr_from_node (&target_sa, ap, NULL, NULL);
+      if (rc)
+       {
+         mu_error ("mu_sockaddr_from_node: %s", mu_strerror (rc));
+         exit (1);
+       }
+
       mu_printf ("Testing %s:\n", ap);
-      rc = mu_acl_check_sockaddr (acl, target_sa, target_salen, &result);
+      rc = mu_acl_check_sockaddr (acl, target_sa->addr, target_sa->addrlen,
+                                 &result);
+      mu_sockaddr_free_list (target_sa);
       if (rc)
        {
          mu_error ("mu_acl_check_sockaddr failed: %s", mu_strerror (rc));
diff --git a/mu/imap.c b/mu/imap.c
index 85a27a3..deea939 100644
--- a/mu/imap.c
+++ b/mu/imap.c
@@ -113,7 +113,6 @@ com_verbose (int argc, char **argv)
 static int connect_argc;
 static char **connect_argv;
 #define host connect_argv[0]
-static int port = MU_IMAP_DEFAULT_PORT;
 
 static char *username;
 
@@ -171,7 +170,6 @@ static int
 com_connect (int argc, char **argv)
 {
   int status;
-  int n = 0;
   int tls = 0;
   int i = 1;
   enum mu_imap_state state;
@@ -194,16 +192,6 @@ com_connect (int argc, char **argv)
   argc -= i;
   argv += i;
   
-  if (argc >= 2)
-    {
-      if (get_port (argv[1], &n))
-       return 0;
-    }
-  else if (tls)
-    n = MU_IMAP_DEFAULT_SSL_PORT;
-  else
-    n = MU_IMAP_DEFAULT_PORT;
-
   state = current_imap_state ();
   
   if (state != MU_IMAP_STATE_INIT)
@@ -213,13 +201,23 @@ com_connect (int argc, char **argv)
   if (status == 0)
     {
       mu_stream_t tcp;
+      struct mu_sockaddr *sa;
+      struct mu_sockaddr_hints hints;
 
       if (QRY_VERBOSE ())
        {
          imap_set_verbose ();
          imap_set_verbose_mask ();
        }
-      status = mu_tcp_stream_create (&tcp, argv[0], n, MU_STREAM_READ);
+
+      memset (&hints, 0, sizeof (hints));
+      hints.flags = MU_AH_DETECT_FAMILY;
+      hints.port = tls ? MU_IMAP_DEFAULT_SSL_PORT : MU_IMAP_DEFAULT_PORT;
+      hints.protocol = IPPROTO_TCP;
+      hints.socktype = SOCK_STREAM;
+      status = mu_sockaddr_from_node (&sa, argv[0], argv[1], &hints);
+      if (status == 0)
+       status = mu_tcp_stream_create_from_sa (&tcp, sa, NULL, 0);
       if (status == 0)
        {
 #ifdef WITH_TLS
@@ -263,7 +261,6 @@ com_connect (int argc, char **argv)
       for (i = 0; i < argc; i++)
        connect_argv[i] = xstrdup (argv[i]);
       connect_argv[i] = NULL;
-      port = n;
     
       imap_prompt_env ();
     }
diff --git a/mu/pop.c b/mu/pop.c
index d72091c..de092cd 100644
--- a/mu/pop.c
+++ b/mu/pop.c
@@ -20,6 +20,10 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netdb.h>
 #include <mailutils/mailutils.h>
 #include "mu.h"
 #include "argp.h"
@@ -470,12 +474,28 @@ com_disconnect (int argc MU_ARG_UNUSED, char **argv 
MU_ARG_UNUSED)
 }
 
 static int
+port_from_sa (struct mu_sockaddr *sa)
+{
+  switch (sa->addr->sa_family)
+    {
+    case AF_INET:
+      return ntohs (((struct sockaddr_in *)sa->addr)->sin_port);
+
+#ifdef MAILUTILS_IPV6
+    case AF_INET6:
+      return ntohs (((struct sockaddr_in6 *)sa->addr)->sin6_port);
+#endif
+    }
+  return 0;
+}
+
+static int
 com_connect (int argc, char **argv)
 {
   int status;
-  int n = 0;
   int tls = 0;
   int i = 1;
+  int n;
   
   for (i = 1; i < argc; i++)
     {
@@ -496,16 +516,6 @@ com_connect (int argc, char **argv)
   argc -= i;
   argv += i;
   
-  if (argc >= 2)
-    {
-      if (get_port (argv[1], &n))
-       return 0;
-    }
-  else if (tls)
-    n = MU_POP3_DEFAULT_SSL_PORT;
-  else
-    n = MU_POP3_DEFAULT_PORT;
-  
   if (pop_session_status != pop_session_disconnected)
     com_disconnect (0, NULL);
   
@@ -513,13 +523,26 @@ com_connect (int argc, char **argv)
   if (status == 0)
     {
       mu_stream_t tcp;
+      struct mu_sockaddr *sa;
+      struct mu_sockaddr_hints hints;
 
       if (QRY_VERBOSE ())
        {
          pop_set_verbose ();
          pop_set_verbose_mask ();
        }
-      status = mu_tcp_stream_create (&tcp, argv[0], n, MU_STREAM_READ);
+
+      memset (&hints, 0, sizeof (hints));
+      hints.flags = MU_AH_DETECT_FAMILY;
+      hints.port = tls ? MU_POP3_DEFAULT_SSL_PORT : MU_POP3_DEFAULT_PORT;
+      hints.protocol = IPPROTO_TCP;
+      hints.socktype = SOCK_STREAM;
+      status = mu_sockaddr_from_node (&sa, argv[0], argv[1], &hints);
+      if (status == 0)
+       {
+         n = port_from_sa (sa);
+         status = mu_tcp_stream_create_from_sa (&tcp, sa, NULL, 0);
+       }
       if (status == 0)
        {
 #ifdef WITH_TLS
diff --git a/testsuite/smtpsend.c b/testsuite/smtpsend.c
index e831968..2fe2d9f 100644
--- a/testsuite/smtpsend.c
+++ b/testsuite/smtpsend.c
@@ -20,6 +20,7 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <netdb.h>
 #include <mailutils/cctype.h>
 #include <mailutils/mailutils.h>
 #include <mailutils/smtp.h>
@@ -85,7 +86,7 @@ main (int argc, char **argv)
   int i;
   char *host = NULL;
   char *infile = NULL;
-  int port = 25;
+  char *port = NULL;
   int tls = 0;
   int raw = 1;
   int flags = 0;
@@ -96,6 +97,8 @@ main (int argc, char **argv)
   mu_list_t rcpt_list = NULL;
   mu_list_t meth_list = NULL;
   mu_list_t skiphdr_list = NULL;
+  struct mu_sockaddr *sa;
+  struct mu_sockaddr_hints hints;
   
   mu_set_program_name (argv[0]);
   mu_stdstream_setup ();
@@ -111,14 +114,7 @@ main (int argc, char **argv)
   for (i = 1; i < argc; i++)
     {
       if (strncmp (argv[i], "port=", 5) == 0)
-       {
-         port = atoi (argv[i] + 5);
-         if (port == 0)
-           {
-             mu_error ("invalid port");
-             return 1;
-           }
-       }
+       port = argv[i] + 5;
       else if (strncmp (argv[i], "trace=", 6) == 0)
        {
          char *arg = argv[i] + 6;
@@ -194,7 +190,16 @@ main (int argc, char **argv)
     MU_ASSERT (mu_stdio_stream_create (&instr, MU_STDIN_FD, flags));
   
   host = argv[1];
-  MU_ASSERT (mu_tcp_stream_create (&stream, host, port, MU_STREAM_RDWR));
+
+  memset (&hints, 0, sizeof (hints)); 
+  hints.flags = MU_AH_DETECT_FAMILY;
+  hints.port = 25;
+  hints.protocol = IPPROTO_TCP;
+  hints.socktype = SOCK_STREAM;
+  MU_ASSERT (mu_sockaddr_from_node (&sa, host, port, &hints));
+
+  MU_ASSERT (mu_tcp_stream_create_from_sa (&stream, sa, NULL, MU_STREAM_RDWR));
+  
   mu_smtp_set_carrier (smtp, stream);
   mu_stream_unref (stream);
   


hooks/post-receive
-- 
GNU Mailutils



reply via email to

[Prev in Thread] Current Thread [Next in Thread]