Commit 966f07cc 966f07ccacdc8b1d13b87e28b1032192ac729fa4 by Sergey Poznyakoff

Initial implementation of a `prog' mailer.

* configure.ac: Enable/disable prog mailer support.
* include/mailutils/progmailer.h: New file.
* include/mailutils/Makefile.am (pkginclude_HEADERS): Add
progmailer.h
* include/mailutils/mailutils.h: Include progmailer.h
* include/mailutils/registrar.h (MU_PROG_PRIO): New define.
(mu_prog_record): New extern.
(mu_register_all_mailer_formats): Register mu_prog_record.
* include/mailutils/types.hin (mu_progmailer_t): New typedef.
* libproto/include/registrar0.h (MU_PROG_SCHEME)
(MU_PROG_SCHEME_LEN): New defines.
* libproto/mailer/prog.c: New file.
* libproto/mailer/Makefile.am (libmu_mailer_la_SOURCES): Add
prog.c
* libproto/mailer/sendmail.c: Rewrite using mu_progmailer_t
* libproto/remote/folder.c (_remote_is_scheme): Remove unused
variable.
* mailbox/progmailer.c: New file
* mailbox/Makefile.am (libmailutils_la_SOURCES): Add progmailer.c

* mailbox/acl.c (_expand_aclno): Add a fixme.
* mail/send.c (msg_to_pipe): Bugfix: use pclose, instead of fclose.
* examples/config/mailutils.schema: Update.
1 parent 5d3f1ff9
2008-10-25 Sergey Poznyakoff <gray@gnu.org.ua>
Initial implementation of a `prog' mailer.
* configure.ac: Enable/disable prog mailer support.
* include/mailutils/progmailer.h: New file.
* include/mailutils/Makefile.am (pkginclude_HEADERS): Add
progmailer.h
* include/mailutils/mailutils.h: Include progmailer.h
* include/mailutils/registrar.h (MU_PROG_PRIO): New define.
(mu_prog_record): New extern.
(mu_register_all_mailer_formats): Register mu_prog_record.
* include/mailutils/types.hin (mu_progmailer_t): New typedef.
* libproto/include/registrar0.h (MU_PROG_SCHEME)
(MU_PROG_SCHEME_LEN): New defines.
* libproto/mailer/prog.c: New file.
* libproto/mailer/Makefile.am (libmu_mailer_la_SOURCES): Add
prog.c
* libproto/mailer/sendmail.c: Rewrite using mu_progmailer_t
* libproto/remote/folder.c (_remote_is_scheme): Remove unused
variable.
* mailbox/progmailer.c: New file
* mailbox/Makefile.am (libmailutils_la_SOURCES): Add progmailer.c
* mailbox/acl.c (_expand_aclno): Add a fixme.
* mail/send.c (msg_to_pipe): Bugfix: use pclose, instead of fclose.
* examples/config/mailutils.schema: Update.
2008-10-24 Sergey Poznyakoff <gray@gnu.org.ua>
* examples/config/mailutils.dict: Use GNU OID number.
......
......@@ -767,10 +767,13 @@ MU_ENABLE_SUPPORT(nntp)
AC_SUBST(BUILD_SMTP_PROGRAMS)
AC_SUBST(RUN_SMTP_DEJATOOL)
MU_ENABLE_SUPPORT(smtp, [BUILD_SMTP_PROGRAMS='$(PROGRAMS_SMTP)'
RUN_SMTP_DEJATOOL='$(SMTP_DEJATOOL)'])
MU_ENABLE_SUPPORT(sendmail)
MU_ENABLE_SUPPORT(prog)
AC_SUBST(BUILD_MH_PROGRAMS)
AC_SUBST(BUILD_MH_LIBRARIES)
AC_SUBST(BUILD_MH_EXEC_HOOK)
......
# This file is part of GNU Mailutils -- a suite of utilities for electronic
# mail
# Copyright (C) 2008 Free Software Foundation, Inc.
# Copyright (C) 2007, 2008 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
......@@ -13,7 +13,7 @@
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
# Mailutuls LDAP schema items
#
......
......@@ -78,6 +78,7 @@ pkginclude_HEADERS = \
pam.h\
parse822.h\
pop3.h\
progmailer.h\
property.h\
radius.h\
refcount.h\
......
......@@ -50,6 +50,7 @@
#include <mailutils/opool.h>
#include <mailutils/parse822.h>
#include <mailutils/pop3.h>
#include <mailutils/progmailer.h>
#include <mailutils/property.h>
#include <mailutils/refcount.h>
#include <mailutils/registrar.h>
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2008 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301 USA */
#ifndef _MAILUTILS_PROGMAILER_H
#define _MAILUTILS_PROGMAILER_H
#include <mailutils/types.h>
#ifdef __cplusplus
extern "C" {
#endif
int mu_progmailer_create (mu_progmailer_t *pm);
int mu_progmailer_set_command (mu_progmailer_t pm, const char *command);
int mu_progmailer_sget_command (mu_progmailer_t pm, const char **command);
/* FIXME: missing _aget_ and _get_ */
int mu_progmailer_set_debug (mu_progmailer_t pm, mu_debug_t debug);
int mu_progmailer_open (mu_progmailer_t pm, char **argv);
int mu_progmailer_send (mu_progmailer_t pm, mu_message_t msg);
int mu_progmailer_close (mu_progmailer_t pm);
void mu_progmailer_destroy (mu_progmailer_t *pm);
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_PROGMAILER_H */
......@@ -121,12 +121,15 @@ extern mu_record_t mu_remote_mbox_record;
#define MU_REMOTE_MBOX_PRIO 10000
#define MU_SMTP_PRIO 10000
#define MU_SENDMAIL_PRIO 10000
#define MU_PROG_PRIO 10000
/* SMTP mailer, "smtp://" */
extern mu_record_t mu_smtp_record;
/* Sendmail, "sendmail:" */
extern mu_record_t mu_sendmail_record;
/* Program mailer, "prog://", "|" */
extern mu_record_t mu_prog_record;
#define mu_register_all_mbox_formats() do {\
mu_registrar_record (mu_path_record);\
mu_registrar_record (mu_mbox_record);\
......@@ -156,6 +159,7 @@ extern mu_record_t mu_sendmail_record;
#define mu_register_all_mailer_formats() do {\
mu_registrar_record (mu_sendmail_record);\
mu_registrar_record (mu_smtp_record);\
mu_registrar_record (mu_prog_record);\
} while (0)
#define mu_register_extra_formats() do {\
......
......@@ -111,7 +111,8 @@ typedef struct _mu_server *mu_server_t;
typedef struct _mu_ip_server *mu_ip_server_t;
typedef struct _mu_m_server *mu_m_server_t;
typedef struct _mu_opool *mu_opool_t;
typedef struct _mu_progmailer *mu_progmailer_t;
#define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001
#define MU_FOLDER_ATTRIBUTE_FILE 0x002
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2004, 2005, 2007 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2004, 2005, 2007, 2008 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
......@@ -19,10 +19,6 @@
#ifndef _REGISTRAR0_H
#define _REGISTRAR0_H
#ifdef DMALLOC
# include <dmalloc.h>
#endif
#include <mailutils/registrar.h>
#ifdef __cplusplus
......@@ -85,6 +81,9 @@ extern int _mailer_smtp_init (mu_mailer_t);
extern int _url_sendmail_init (mu_url_t);
extern int _mailer_sendmail_init (mu_mailer_t);
#define MU_PROG_SCHEME "prog"
#define MU_PROG_SCHEME_LEN (sizeof (MU_PROG_SCHEME) - 1)
#define MU_MH_SCHEME "mh"
#define MU_MH_SCHEME_LEN (sizeof (MU_MH_SCHEME) - 1)
extern int _mailbox_mh_init (mu_mailbox_t mailbox);
......
## Process this file with GNU Automake to create Makefile.in
## Copyright (C) 2007 Free Software Foundation, Inc.
## Copyright (C) 2007, 2008 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
......@@ -24,6 +24,7 @@ libmu_mailer_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
libmu_mailer_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@
libmu_mailer_la_SOURCES = \
prog.c\
sendmail.c\
smtp.c\
url_sendmail.c\
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2008 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
#ifdef ENABLE_PROG
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <mailutils/address.h>
#include <mailutils/argcv.h>
#include <mailutils/debug.h>
#include <mailutils/errno.h>
#include <mailutils/header.h>
#include <mailutils/message.h>
#include <mailutils/observer.h>
#include <mailutils/progmailer.h>
#include <mailutils/vartab.h>
#include <url0.h>
#include <mailer0.h>
#include <registrar0.h>
static int _url_prog_init (mu_url_t);
static int _url_pipe_init (mu_url_t);
static int _mailer_prog_init (mu_mailer_t);
static struct _mu_record _prog_record =
{
MU_PROG_PRIO,
MU_PROG_SCHEME,
_url_prog_init, /* url init. */
NULL, /* Mailbox entry. */
_mailer_prog_init, /* Mailer entry. */
NULL, /* Folder entry. */
NULL, /* No need for a back pointer. */
NULL, /* _is_scheme method. */
NULL, /* _get_url method. */
NULL, /* _get_mailbox method. */
NULL, /* _get_mailer method. */
NULL /* _get_folder method. */
};
mu_record_t mu_prog_record = &_prog_record;
static int
_url_prog_init (mu_url_t url)
{
int status = mu_url_init (url, 0, "prog");
if (status)
return status;
/* not valid in a sendmail url */
if (url->user || url->passwd || url->auth || url->host || url->port)
return EINVAL;
if (!url->path)
return EINVAL;
return 0;
}
static void prog_destroy (mu_mailer_t);
static int prog_open (mu_mailer_t, int);
static int prog_close (mu_mailer_t);
static int prog_send_message (mu_mailer_t, mu_message_t, mu_address_t,
mu_address_t);
static int
_mailer_prog_init (mu_mailer_t mailer)
{
int status;
mu_progmailer_t pm;
status = mu_progmailer_create (&pm);
if (status)
return status;
mailer->data = pm;
mailer->_destroy = prog_destroy;
mailer->_open = prog_open;
mailer->_close = prog_close;
mailer->_send_message = prog_send_message;
return 0;
}
static void
prog_destroy (mu_mailer_t mailer)
{
mu_progmailer_destroy ((mu_progmailer_t*)&mailer->data);
}
static int
prog_open (mu_mailer_t mailer, int flags)
{
mu_progmailer_t pm = mailer->data;
int status;
const char *path;
/* Sanity checks. */
if (pm == NULL)
return EINVAL;
mailer->flags = flags;
if ((status = mu_url_sget_path (mailer->url, &path)))
return status;
if (access (path, X_OK) == -1)
return errno;
mu_progmailer_set_debug (pm, mailer->debug);
status = mu_progmailer_set_command (pm, path);
MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE, "prog (%s)\n", path);
return status;
}
static int
prog_close (mu_mailer_t mailer)
{
return mu_progmailer_close (mailer->data);
}
static int
_expand_sender (const char *name, void *data, char **p)
{
mu_address_t addr = data;
const char *email;
int status = mu_address_sget_email (addr, 1, &email);
if (status != 0)
return status;
*(const char**)p = email;
return 0;
}
struct ex_rcpt
{
mu_message_t msg;
mu_address_t addr;
char *string;
};
static int
address_add (mu_address_t *paddr, const char *value)
{
mu_address_t addr = NULL;
int status;
status = mu_address_create (&addr, value);
if (status)
return status;
status = mu_address_union (paddr, addr);
mu_address_destroy (&addr);
return status;
}
static int
message_read_rcpt (mu_message_t msg, mu_address_t *paddr)
{
mu_header_t header = NULL;
const char *value;
int status;
status = mu_message_get_header (msg, &header);
if (status)
return status;
status = mu_header_sget_value (header, MU_HEADER_TO, &value);
if (status == 0)
address_add (paddr, value);
else if (status != MU_ERR_NOENT)
return status;
status = mu_header_sget_value (header, MU_HEADER_CC, &value);
if (status == 0)
address_add (paddr, value);
else if (status != MU_ERR_NOENT)
return status;
status = mu_header_sget_value (header, MU_HEADER_BCC, &value);
if (status == 0)
address_add (paddr, value);
else if (status != MU_ERR_NOENT)
return status;
return 0;
}
static int
_expand_rcpt (const char *name, void *data, char **p)
{
struct ex_rcpt *exrcpt = data;
int status;
if (!exrcpt->string)
{
size_t i, count = 0;
size_t len = 0;
char *str;
mu_address_t tmp_addr = NULL, addr;
if (exrcpt->addr)
addr = exrcpt->addr;
else
{
status = message_read_rcpt (exrcpt->msg, &tmp_addr);
if (status)
{
mu_address_destroy (&tmp_addr);
return status;
}
addr = tmp_addr;
}
mu_address_get_count (addr, &count);
for (i = 1; i <= count; i++)
{
const char *email;
if (i > 1)
len++;
if ((status = mu_address_sget_email (addr, i, &email)) != 0)
{
mu_address_destroy (&tmp_addr);
return status;
}
len += strlen (email);
}
str = malloc (len + 1);
if (!str)
{
mu_address_destroy (&tmp_addr);
return ENOMEM;
}
exrcpt->string = str;
for (i = 1; i <= count; i++)
{
const char *email;
if (i > 1)
*str++ = ' ';
if (mu_address_sget_email (addr, i, &email))
continue;
strcpy (str, email);
str += strlen (email);
}
*str = 0;
mu_address_destroy (&tmp_addr);
}
*p = exrcpt->string;
return 0;
}
void
_free_rcpt (void *data, char *value)
{
free (value);
}
static int
url_to_argv (mu_url_t url, mu_message_t msg,
mu_address_t from, mu_address_t to,
int *pargc, char ***pargv)
{
int rc;
mu_vartab_t vtab;
struct ex_rcpt ex_rcpt;
const char *query;
char *cmdargs;
int argc;
char **argv;
ex_rcpt.msg = msg;
ex_rcpt.addr = to;
ex_rcpt.string = NULL;
mu_vartab_create (&vtab);
mu_vartab_define_exp (vtab, "sender", _expand_sender, NULL, from);
mu_vartab_define_exp (vtab, "rcpt", _expand_rcpt, _free_rcpt, &ex_rcpt);
rc = mu_url_sget_query (url, &query);
if (rc)
return rc;
rc = mu_vartab_expand (vtab, query, &cmdargs);
mu_vartab_destroy (&vtab);
if (rc)
return rc;
rc = mu_argcv_get_np (cmdargs, strlen (cmdargs),
"&", NULL,
0, &argc, &argv, NULL);
free (cmdargs);
if (rc)
return rc;
argv = realloc (argv, (argc + 2) * sizeof (argv[0]));
memmove (argv + 1, argv, (argc + 1) * sizeof (argv[0]));
mu_url_aget_path (url, &argv[0]);
*pargc = argc + 1;
*pargv = argv;
return 0;
}
static int
prog_send_message (mu_mailer_t mailer, mu_message_t msg, mu_address_t from,
mu_address_t to)
{
mu_progmailer_t pm = mailer->data;
int argc;
char **argv;
int status;
status = url_to_argv(mailer->url, msg, from, to, &argc, &argv);
if (status)
{
MU_DEBUG1 (mailer->debug, MU_DEBUG_ERROR,
"cannot convert URL to command line: %s\n",
mu_strerror (status));
return status;
}
mu_progmailer_set_debug (pm, mailer->debug);
status = mu_progmailer_open (pm, argv);
if (status == 0)
{
status = mu_progmailer_send (pm, msg);
if (status == 0)
mu_observable_notify (mailer->observable, MU_EVT_MAILER_MESSAGE_SENT,
msg);
else
MU_DEBUG1 (mailer->debug, MU_DEBUG_ERROR,
"progmailer error: %s\n",
mu_strerror (status));
}
mu_argcv_free (argc, argv);
return status;
}
#else
#include <stdio.h>
#include <registrar0.h>
mu_record_t mu_prog_record = NULL;
#endif
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2004, 2005,
2006, 2007 Free Software Foundation, Inc.
2006, 2007, 2008 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
......@@ -30,19 +30,13 @@
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <mailutils/address.h>
#include <mailutils/debug.h>
#include <mailutils/message.h>
#include <mailutils/observer.h>
#include <mailutils/property.h>
#include <mailutils/stream.h>
#include <mailutils/url.h>
#include <mailutils/header.h>
#include <mailutils/body.h>
#include <mailutils/errno.h>
#include <mailutils/progmailer.h>
#include <mailer0.h>
#include <registrar0.h>
......@@ -66,33 +60,23 @@ static struct _mu_record _sendmail_record =
the mailbox, via the register entry/record. */
mu_record_t mu_sendmail_record = &_sendmail_record;
struct _sendmail
{
int dsn;
char *path;
pid_t pid;
off_t offset;
int fd;
enum sendmail_state { SENDMAIL_CLOSED, SENDMAIL_OPEN, SENDMAIL_SEND } state;
};
typedef struct _sendmail * sendmail_t;
static void sendmail_destroy (mu_mailer_t);
static int sendmail_open (mu_mailer_t, int);
static int sendmail_close (mu_mailer_t);
static int sendmail_send_message (mu_mailer_t, mu_message_t, mu_address_t, mu_address_t);
static int sendmail_send_message (mu_mailer_t, mu_message_t, mu_address_t,
mu_address_t);
int
_mailer_sendmail_init (mu_mailer_t mailer)
{
sendmail_t sendmail;
int status;
mu_progmailer_t pm;
/* Allocate memory specific to sendmail mailer. */
sendmail = mailer->data = calloc (1, sizeof (*sendmail));
if (mailer->data == NULL)
return ENOMEM;
sendmail->state = SENDMAIL_CLOSED;
status = mu_progmailer_create (&pm);
if (status)
return status;
mailer->data = pm;
mailer->_destroy = sendmail_destroy;
mailer->_open = sendmail_open;
mailer->_close = sendmail_close;
......@@ -108,61 +92,39 @@ _mailer_sendmail_init (mu_mailer_t mailer)
}
static void
sendmail_destroy(mu_mailer_t mailer)
sendmail_destroy (mu_mailer_t mailer)
{
sendmail_t sendmail = mailer->data;
if (sendmail)
{
if (sendmail->path)
free (sendmail->path);
free (sendmail);
mailer->data = NULL;
}
mu_progmailer_destroy ((mu_progmailer_t*)&mailer->data);
}
static int
sendmail_open (mu_mailer_t mailer, int flags)
{
sendmail_t sendmail = mailer->data;
mu_progmailer_t pm = mailer->data;
int status;
char *path;
const char *path;
/* Sanity checks. */
if (sendmail == NULL)
if (pm == NULL)
return EINVAL;
mailer->flags = flags;
if ((status = mu_url_aget_path (mailer->url, &path)))
if ((status = mu_url_sget_path (mailer->url, &path)))
return status;
if (access (path, X_OK) == -1)
{
free (path);
return errno;
}
sendmail->path = path;
sendmail->state = SENDMAIL_OPEN;
MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE, "sendmail (%s)\n", sendmail->path);
return 0;
return errno;
mu_progmailer_set_debug (pm, mailer->debug);
status = mu_progmailer_set_command (pm, path);
MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE, "sendmail (%s)\n", path);
return status;
}
static int
sendmail_close (mu_mailer_t mailer)
{
sendmail_t sendmail = mailer->data;
/* Sanity checks. */
if (sendmail == NULL)
return EINVAL;
if(sendmail->path)
free(sendmail->path);
sendmail->path = NULL;
sendmail->state = SENDMAIL_CLOSED;
return 0;
return mu_progmailer_close (mailer->data);
}
static int
......@@ -174,281 +136,139 @@ mailer_property_is_set (mu_mailer_t mailer, const char *name)
return mu_property_is_set (property, name);
}
/* Close FD unless it is part of pipe P */
#define SCLOSE(fd,p) if (p[0]!=fd&&p[1]!=fd) close(fd)
static int
sendmail_send_message (mu_mailer_t mailer, mu_message_t msg, mu_address_t from,
mu_address_t to)
{
sendmail_t sendmail = mailer->data;
int status = 0;
if (sendmail == NULL || msg == NULL)
mu_progmailer_t pm = mailer->data;
int argc = 0;
const char **argvec = NULL;
size_t tocount = 0;
const char *emailfrom = NULL;
int status;
if (!pm)
return EINVAL;
/* Count the length of the arg vec: */
switch (sendmail->state)
{
case SENDMAIL_CLOSED:
return EINVAL;
case SENDMAIL_OPEN:
{
int tunnel[2];
int argc = 0;
const char **argvec = NULL;
size_t tocount = 0;
const char *emailfrom = NULL;
/* Count the length of the arg vec: */
argc++; /* terminating NULL */
argc++; /* sendmail */
argc++; /* -oi (do not treat '.' as message
argc++; /* terminating NULL */
argc++; /* sendmail */
argc++; /* -oi (do not treat '.' as message
terminator) */
if (from)
{
if ((status = mu_address_sget_email (from, 1, &emailfrom)) != 0)
goto OPEN_STATE_CLEANUP;
if (!emailfrom)
{
/* the address wasn't fully qualified, choke (for now) */
status = EINVAL;
MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
"envelope from (%s) not fully qualifed\n",
emailfrom);
goto OPEN_STATE_CLEANUP;
}
argc += 2; /* -f from */
}
if (to)
{
status = mu_address_get_email_count (to, &tocount);
assert (!status);
assert (tocount);
argc += tocount; /* 1 per to address */
}
argc++; /* -t */
/* Allocate arg vec: */
if ((argvec = calloc (argc, sizeof (*argvec))) == 0)
{
status = ENOMEM;
goto OPEN_STATE_CLEANUP;
}
argc = 0;
argvec[argc++] = sendmail->path;
argvec[argc++] = "-oi";
if (from)
{
argvec[argc++] = "-f";
argvec[argc++] = emailfrom;
}
if (!to || mailer_property_is_set (mailer, "READ_RECIPIENTS"))
{
argvec[argc++] = "-t";
}
else
{
int i = 1;
size_t count = 0;
mu_address_get_count (to, &count);
for (; i <= count; i++)
{
const char *email;
if ((status = mu_address_sget_email (to, i, &email)) != 0)
goto OPEN_STATE_CLEANUP;
if (!email)
{
/* the address wasn't fully qualified, choke (for now) */
status = EINVAL;
MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
"envelope to (%s) not fully qualifed\n",
email);
goto OPEN_STATE_CLEANUP;
}
argvec[argc++] = email;
}
}
assert (argvec[argc] == NULL);
if (pipe (tunnel) == 0)
{
sendmail->fd = tunnel[1];
sendmail->pid = vfork ();
if (sendmail->pid == 0) /* Child. */
{
SCLOSE (STDIN_FILENO, tunnel);
SCLOSE (STDOUT_FILENO, tunnel);
SCLOSE (STDERR_FILENO, tunnel);
close (tunnel[1]);
dup2 (tunnel[0], STDIN_FILENO);
execv (sendmail->path, (char**) argvec);
exit (errno);
}
else if (sendmail->pid == -1)
{
status = errno;
MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
"vfork() failed: %s\n", strerror (status));
}
}
else
{
status = errno;
MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
"pipe() failed: %s\n", strerror (status));
}
OPEN_STATE_CLEANUP:
MU_DEBUG (mailer->debug, MU_DEBUG_TRACE, "exec argv:");
for (argc = 0; argvec && argvec[argc]; argc++)
MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE, " %s", argvec[argc]);
MU_DEBUG (mailer->debug, MU_DEBUG_TRACE, "\n");
free (argvec);
close (tunnel[0]);
if (status != 0)
{
close (sendmail->fd);
break;
}
sendmail->state = SENDMAIL_SEND;
}
case SENDMAIL_SEND:
{
mu_stream_t stream = NULL;
char buffer[512];
size_t len = 0;
int rc;
size_t offset = 0;
mu_header_t hdr;
mu_body_t body;
int found_nl = 0;
int exit_status;
mu_message_get_header (msg, &hdr);
mu_header_get_stream (hdr, &stream);
MU_DEBUG (mailer->debug, MU_DEBUG_TRACE, "Sending headers...\n");
while ((status = mu_stream_readline (stream, buffer, sizeof (buffer),
offset, &len)) == 0
&& len != 0)
{
if (strncasecmp (buffer, MU_HEADER_FCC,
sizeof (MU_HEADER_FCC) - 1))
{
MU_DEBUG1 (mailer->debug, MU_DEBUG_PROT, "Header: %s", buffer);
if (write (sendmail->fd, buffer, len) == -1)
{
status = errno;
MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
"write() failed: %s\n", strerror (status));
break;
}
}
found_nl = (len == 1 && buffer[0] == '\n');
offset += len;
sendmail->offset += len;
}
if (!found_nl)
{
if (write (sendmail->fd, "\n", 1) == -1)
{
status = errno;
MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
"write() failed: %s\n", strerror (status));
}
}
mu_message_get_body (msg, &body);
mu_body_get_stream (body, &stream);
MU_DEBUG (mailer->debug, MU_DEBUG_TRACE, "Sending body...\n");
offset = 0;
while ((status = mu_stream_read (stream, buffer, sizeof (buffer),
offset, &len)) == 0
&& len != 0)
{
if (write (sendmail->fd, buffer, len) == -1)
{
status = errno;
MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
"write() failed: %s\n", strerror (status));
break;
}
offset += len;
sendmail->offset += len;
}
if (status == EAGAIN)
if (from)
{
if ((status = mu_address_sget_email (from, 1, &emailfrom)) != 0)
{
MU_DEBUG1 (mailer->debug, MU_DEBUG_ERROR,
"cannot get recipient email: %s\n",
mu_strerror (status));
return status;
}
if (!emailfrom)
{
/* the address wasn't fully qualified, choke (for now) */
MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
"envelope from (%s) not fully qualifed\n",
emailfrom);
return MU_ERR_BAD_822_FORMAT;
}
argc += 2; /* -f from */
}
if (to)
{
status = mu_address_get_email_count (to, &tocount);
if (status)
return status;
if (tocount == 0)
{
MU_DEBUG (mailer->debug, MU_DEBUG_TRACE,
"missing recipients\n");
return MU_ERR_NOENT;
}
argc += tocount; /* 1 per to address */
}
close (sendmail->fd);
argc++; /* -t */
rc = waitpid (sendmail->pid, &exit_status, 0);
/* Allocate arg vec: */
if ((argvec = calloc (argc, sizeof (*argvec))) == 0)
return ENOMEM;
argc = 0;
if (mu_progmailer_sget_command (pm, &argvec[argc]) || argvec[argc] == NULL)
{
free (argvec);
return EINVAL;
}
argc++;
argvec[argc++] = "-oi";
if (rc < 0)
{
if (errno == ECHILD)
status = 0;
else
{
status = errno;
MU_DEBUG2 (mailer->debug, MU_DEBUG_TRACE,
"waitpid(%d) failed: %s\n",
sendmail->pid, strerror (status));
}
}
else if (WIFEXITED (exit_status))
{
exit_status = WEXITSTATUS (exit_status);
MU_DEBUG2 (mailer->debug, MU_DEBUG_TRACE,
"%s exited with: %d\n",
sendmail->path, exit_status);
status = (exit_status == 0) ? 0 : MU_ERR_PROCESS_EXITED;
}
else if (WIFSIGNALED (exit_status))
status = MU_ERR_PROCESS_SIGNALED;
else
status = MU_ERR_PROCESS_UNKNOWN_FAILURE;
if (from)
{
argvec[argc++] = "-f";
argvec[argc++] = emailfrom;
}
/* Shouldn't this notification only happen on success? */
mu_observable_notify (mailer->observable, MU_EVT_MAILER_MESSAGE_SENT,
msg);
}
default:
break;
if (!to || mailer_property_is_set (mailer, "READ_RECIPIENTS"))
{
argvec[argc++] = "-t";
}
sendmail->state = (status == 0) ? SENDMAIL_OPEN : SENDMAIL_CLOSED;
else
{
size_t i;
size_t count = 0;
mu_address_get_count (to, &count);
for (i = 1; i <= count; i++)
{
const char *email;
if ((status = mu_address_sget_email (to, i, &email)) != 0)
{
free (argvec);
MU_DEBUG2 (mailer->debug, MU_DEBUG_ERROR,
"cannot get email of recipient #%d: %s\n",
i, mu_strerror (status));
return status;
}
if (!email)
{
MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
"envelope to (%s) not fully qualifed\n",
email);
free (argvec);
return MU_ERR_BAD_822_FORMAT;
}
argvec[argc++] = email;
}
}
argvec[argc] = NULL;
mu_progmailer_set_debug (pm, mailer->debug);
status = mu_progmailer_open (pm, (char**) argvec);
if (status == 0)
{
status = mu_progmailer_send (pm, msg);
if (status == 0)
mu_observable_notify (mailer->observable, MU_EVT_MAILER_MESSAGE_SENT,
msg);
else
MU_DEBUG1 (mailer->debug, MU_DEBUG_ERROR,
"progmailer error: %s\n",
mu_strerror (status));
}
free (argvec);
return status;
}
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2007 Free Software Foundation, Inc.
Copyright (C) 2007, 2008 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
......@@ -46,7 +46,6 @@ _remote_is_scheme (mu_record_t record, mu_url_t url, int flags)
{
char *scheme = url->scheme;
size_t scheme_len = scheme ? strlen (scheme) : 0;
int rc;
struct _mu_url s_url;
if (!scheme
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2001, 2002, 2003, 2004,
2005, 2006, 2007 Free Software Foundation, Inc.
2005, 2006, 2007, 2008 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
......@@ -666,7 +666,7 @@ msg_to_pipe (const char *cmd, mu_message_t msg)
fprintf (fp, "%s", buffer);
off += n;
}
fclose (fp);
pclose (fp);
}
else
util_error (_("Piping %s failed"), cmd);
......
......@@ -108,6 +108,7 @@ libmailutils_la_SOURCES = \
opool.c\
parse822.c\
parsedate.c\
progmailer.c\
property.c\
registrar.c\
refcount.c\
......
......@@ -501,6 +501,7 @@ _expand_aclno (const char *name, void *data, char **p)
{
struct run_closure *rp = data;
char buf[UINTMAX_STRSIZE_BOUND];
/*FIXME: memory leak*/
*p = strdup (umaxtostr (rp->idx, buf));
return 0;
}
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2004, 2005,
2006, 2007, 2008 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301 USA */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sysexits.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <mailutils/debug.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
#include <mailutils/stream.h>
#include <mailutils/header.h>
#include <mailutils/body.h>
#include <mailutils/message.h>
#include <mailutils/progmailer.h>
struct _mu_progmailer
{
int fd;
pid_t pid;
RETSIGTYPE (*sighandler)();
mu_debug_t debug;
char *command;
};
/* Close FD unless it is part of pipe P */
#define SCLOSE(fd,p) if (p[0]!=fd&&p[1]!=fd) close(fd)
int
mu_progmailer_create (struct _mu_progmailer **ppm)
{
struct _mu_progmailer *pm = malloc (sizeof (*pm));
if (!pm)
return ENOMEM;
pm->fd = -1;
pm->pid = -1;
pm->sighandler = SIG_ERR;
pm->debug = NULL;
pm->command = NULL;
*ppm = pm;
return 0;
}
int
mu_progmailer_set_command (mu_progmailer_t pm, const char *command)
{
if (!pm)
return EINVAL;
free (pm->command);
if (command)
{
pm->command = strdup (command);
if (!pm->command)
return EINVAL;
}
else
pm->command = NULL;
return 0;
}
int
mu_progmailer_sget_command (mu_progmailer_t pm, const char **command)
{
if (!pm)
return EINVAL;
*command = pm->command;
return 0;
}
int
mu_progmailer_set_debug (mu_progmailer_t pm, mu_debug_t debug)
{
if (!pm)
return EINVAL;
pm->debug = debug;
}
void
mu_progmailer_destroy (struct _mu_progmailer **ppm)
{
if (*ppm)
{
free ((*ppm)->command);
free (*ppm);
*ppm = NULL;
}
}
int
mu_progmailer_open (struct _mu_progmailer *pm, char **argv)
{
int tunnel[2];
int status = 0;
int i;
if (!pm || !argv)
return EINVAL;
if ((pm->sighandler = signal (SIGCHLD, SIG_DFL)) == SIG_ERR)
{
status = errno;
MU_DEBUG1 (pm->debug, MU_DEBUG_ERROR,
"setting SIGCHLD failed: %s\n", mu_strerror (status));
return status;
}
if (pipe (tunnel) == 0)
{
pm->fd = tunnel[1];
pm->pid = fork ();
if (pm->pid == 0) /* Child. */
{
SCLOSE (STDIN_FILENO, tunnel);
SCLOSE (STDOUT_FILENO, tunnel);
SCLOSE (STDERR_FILENO, tunnel);
close (tunnel[1]);
dup2 (tunnel[0], STDIN_FILENO);
execv (pm->command ? pm->command : argv[0], argv);
exit (errno ? EX_CANTCREAT : 0);
}
else if (pm->pid == -1)
{
status = errno;
MU_DEBUG1 (pm->debug, MU_DEBUG_ERROR,
"fork failed: %s\n", mu_strerror (status));
}
}
else
{
status = errno;
MU_DEBUG1 (pm->debug, MU_DEBUG_ERROR,
"pipe() failed: %s\n", mu_strerror (status));
}
MU_DEBUG1 (pm->debug, MU_DEBUG_TRACE, "exec %s argv:", pm->command);
for (i = 0; argv[i]; i++)
MU_DEBUG1 (pm->debug, MU_DEBUG_TRACE, " %s", argv[i]);
MU_DEBUG (pm->debug, MU_DEBUG_TRACE, "\n");
close (tunnel[0]);
if (status != 0)
close (pm->fd);
return status;
}
int
mu_progmailer_send (struct _mu_progmailer *pm, mu_message_t msg)
{
int status;
mu_stream_t stream = NULL;
char buffer[512];
size_t len = 0;
int rc;
size_t offset = 0;
mu_header_t hdr;
mu_body_t body;
int found_nl = 0;
int exit_status;
if (!pm || !msg)
return EINVAL;
mu_message_get_header (msg, &hdr);
mu_header_get_stream (hdr, &stream);
MU_DEBUG (pm->debug, MU_DEBUG_TRACE, "Sending headers...\n");
while ((status = mu_stream_readline (stream, buffer, sizeof (buffer),
offset, &len)) == 0
&& len != 0)
{
if (strncasecmp (buffer, MU_HEADER_FCC, sizeof (MU_HEADER_FCC) - 1))
{
MU_DEBUG1 (pm->debug, MU_DEBUG_PROT, "Header: %s", buffer);
if (write (pm->fd, buffer, len) == -1)
{
status = errno;
MU_DEBUG1 (pm->debug, MU_DEBUG_TRACE,
"write failed: %s\n", strerror (status));
break;
}
}
found_nl = (len == 1 && buffer[0] == '\n');
offset += len;
}
if (!found_nl)
{
if (write (pm->fd, "\n", 1) == -1)
{
status = errno;
MU_DEBUG1 (pm->debug, MU_DEBUG_TRACE,
"write failed: %s\n", strerror (status));
}
}
mu_message_get_body (msg, &body);
mu_body_get_stream (body, &stream);
MU_DEBUG (pm->debug, MU_DEBUG_TRACE, "Sending body...\n");
offset = 0;
while ((status = mu_stream_read (stream, buffer, sizeof (buffer),
offset, &len)) == 0
&& len != 0)
{
if (write (pm->fd, buffer, len) == -1)
{
status = errno;
MU_DEBUG1 (pm->debug, MU_DEBUG_TRACE,
"write failed: %s\n", strerror (status));
break;
}
offset += len;
}
close (pm->fd);
rc = waitpid (pm->pid, &exit_status, 0);
if (status == 0)
{
if (rc < 0)
{
if (errno == ECHILD)
status = 0;
else
{
status = errno;
MU_DEBUG2 (pm->debug, MU_DEBUG_TRACE,
"waitpid(%lu) failed: %s\n",
(unsigned long) pm->pid, strerror (status));
}
}
else if (WIFEXITED (exit_status))
{
exit_status = WEXITSTATUS (exit_status);
MU_DEBUG2 (pm->debug, MU_DEBUG_TRACE,
"%s exited with: %d\n",
pm->command, exit_status);
status = (exit_status == 0) ? 0 : MU_ERR_PROCESS_EXITED;
}
else if (WIFSIGNALED (exit_status))
status = MU_ERR_PROCESS_SIGNALED;
else
status = MU_ERR_PROCESS_UNKNOWN_FAILURE;
}
pm->pid = -1;
return status;
}
int
mu_progmailer_close (struct _mu_progmailer *pm)
{
int status = 0;
if (!pm)
return EINVAL;
if (pm->pid > 0)
{
kill (SIGTERM, pm->pid);
pm->pid = -1;
}
if (pm->sighandler != SIG_ERR
&& signal (SIGCHLD, pm->sighandler) == SIG_ERR)
{
status = errno;
MU_DEBUG1 (pm->debug, MU_DEBUG_ERROR,
"resetting SIGCHLD failed: %s\n", mu_strerror (status));
}
pm->sighandler = SIG_ERR;
return status;
}