Commit 203c6eb3 203c6eb363274b8463ff114b3e382952a2cff8b7 by Alain Magloire

supporting CC BCC when mailing.

1 parent ad9f147e
......@@ -47,8 +47,7 @@ extern void mailer_destroy __P ((mailer_t *));
extern int mailer_open __P ((mailer_t, int flags));
extern int mailer_close __P ((mailer_t));
extern int mailer_send_message __P ((mailer_t, const char *from,
const char *rcpt, int dsn, message_t));
extern int mailer_send_message __P ((mailer_t, message_t));
/* stream settings */
extern int mailer_get_stream __P ((mailer_t, stream_t *));
extern int mailer_set_stream __P ((mailer_t, stream_t));
......
......@@ -50,6 +50,9 @@ extern int message_create __P ((message_t *, void *owner));
extern void message_destroy __P ((message_t *, void *owner));
extern void * message_get_owner __P ((message_t));
extern int message_ref __P ((message_t));
#define message_unref(msg) message_destroy (&msg)
extern int message_get_header __P ((message_t, header_t *));
extern int message_set_header __P ((message_t, header_t, void *owner));
......
......@@ -74,8 +74,7 @@ struct _mailer
void (*_destroy) __P ((mailer_t));
int (*_open) __P ((mailer_t, int flags));
int (*_close) __P ((mailer_t));
int (*_send_message) __P ((mailer_t, const char *from, const char *rcpt,
int dsn, message_t));
int (*_send_message) __P ((mailer_t, message_t));
};
/* Mail locks. */
......
......@@ -52,6 +52,9 @@ struct _message
mime_t mime;
observable_t observable;
/* Reference count. */
int ref;
/* Holder for message_write. */
char *hdr_buf;
size_t hdr_buflen;
......
......@@ -156,12 +156,11 @@ mailer_close (mailer_t mailer)
/* messages */
int
mailer_send_message (mailer_t mailer, const char *from, const char *rcpt,
int dsn, message_t msg)
mailer_send_message (mailer_t mailer, message_t msg)
{
if (mailer == NULL || mailer->_send_message == NULL)
return ENOSYS;
return mailer->_send_message (mailer, from, rcpt, dsn, msg);
return mailer->_send_message (mailer, msg);
}
int
......
......@@ -50,6 +50,7 @@ message_create (message_t *pmsg, void *owner)
if (msg == NULL)
return ENOMEM;
msg->owner = owner;
msg->ref = 1;
*pmsg = msg;
return 0;
}
......@@ -61,6 +62,7 @@ message_destroy (message_t *pmsg, void *owner)
{
message_t msg = *pmsg;
msg->ref--;
if (msg->owner == owner)
{
/* Notify the listeners. */
......@@ -91,13 +93,22 @@ message_destroy (message_t *pmsg, void *owner)
if (msg->mime)
mime_destroy (&(msg->mime));
free (msg);
if (msg->ref <= 0)
free (msg);
}
/* Loose the link */
*pmsg = NULL;
}
}
int
message_ref (message_t msg)
{
if (msg)
msg->ref++;
return 0;
}
void *
message_get_owner (message_t msg)
{
......@@ -132,7 +143,7 @@ message_set_header (message_t msg, header_t hdr, void *owner)
return EACCES;
/* Make sure we destoy the old if it was own by the mesg */
/* FIXME: I do not know if somebody has already a ref on this ? */
/* header_destroy (&(msg->header), msg); */
header_destroy (&(msg->header), msg);
msg->header = hdr;
return 0;
}
......@@ -165,7 +176,7 @@ message_set_body (message_t msg, body_t body, void *owner)
return EACCES;
/* Make sure we destoy the old if it was own by the mesg. */
/* FIXME: I do not know if somebody has already a ref on this ? */
/* body_destroy (&(msg->body), msg); */
body_destroy (&(msg->body), msg);
msg->body = body;
return 0;
}
......@@ -177,6 +188,9 @@ message_set_stream (message_t msg, stream_t stream, void *owner)
return EINVAL;
if (msg->owner != owner)
return EACCES;
/* Make sure we destoy the old if it was own by the mesg. */
/* FIXME: I do not know if somebody has already a ref on this ? */
stream_destroy (&(msg->stream), msg);
msg->stream = stream;
return 0;
}
......
......@@ -72,8 +72,7 @@ typedef struct _sendmail * sendmail_t;
static void sendmail_destroy (mailer_t);
static int sendmail_open (mailer_t, int);
static int sendmail_close (mailer_t);
static int sendmail_send_message (mailer_t, const char *from, const char *rcpt,
int dsn, message_t);
static int sendmail_send_message (mailer_t, message_t);
int
sendmail_init (mailer_t mailer)
......@@ -148,8 +147,7 @@ sendmail_close (mailer_t mailer)
}
static int
sendmail_send_message (mailer_t mailer, const char *from, const char *rcpt,
int dsn, message_t msg)
sendmail_send_message (mailer_t mailer, message_t msg)
{
sendmail_t sendmail = mailer->data;
int status = 0;
......@@ -157,8 +155,6 @@ sendmail_send_message (mailer_t mailer, const char *from, const char *rcpt,
if (sendmail == NULL || msg == NULL)
return EINVAL;
sendmail->dsn = dsn;
switch (sendmail->state)
{
case SENDMAIL_NO_STATE:
......@@ -173,45 +169,6 @@ sendmail_send_message (mailer_t mailer, const char *from, const char *rcpt,
argvec[1] = strdup ("-oi");
argvec[2] = strdup ("-t");
if (from)
{
size_t len = strlen (from) + 1;
char *addr = calloc (len, sizeof (char));
if (parseaddr (from, addr, len) == 0)
{
argc++;
argvec = realloc (argvec, argc * (sizeof (*argvec)));
argvec[argc - 1] = strdup ("-f");
argc++;
argvec = realloc (argvec, argc * (sizeof (*argvec)));
argvec[argc - 1] = addr;
}
else
free (addr);
}
if (rcpt)
{
const char *p = rcpt;
do
{
size_t len = strlen (p) + 1;
char *addr = calloc (len, sizeof (char));
if (parseaddr (rcpt, addr, len) == 0)
{
argc++;
argvec = realloc (argvec, argc * (sizeof (*argvec)));
argvec[argc - 1] = addr;
}
else
free (addr);
p = strchr (p, ',');
if (p != NULL)
p++;
}
while (p != NULL && *p != '\0');
}
argc++;
argvec = realloc (argvec, argc * (sizeof (*argvec)));
argvec[argc - 1] = NULL;
......
......@@ -29,6 +29,7 @@
#include <netdb.h>
#include <mailutils/stream.h>
#include <mailutils/address.h>
#include <mailer0.h>
#include <registrar0.h>
#include <bio.h>
......@@ -77,8 +78,9 @@ struct _smtp
SMTP_SEND_DOT
} state;
int extended;
char *from;
char *to;
address_t mail_from;
address_t rcpt_to;
size_t rcpt_index;
off_t offset;
int dsn;
message_t message;
......@@ -133,13 +135,15 @@ while (0)
static void smtp_destroy (mailer_t);
static int smtp_open (mailer_t, int);
static int smtp_close (mailer_t);
static int smtp_send_message (mailer_t, const char *from, const char *rcpt,
int dsn, message_t);
static int smtp_send_message (mailer_t, message_t);
static int smtp_writeline (smtp_t smtp, const char *format, ...);
static int smtp_readline (smtp_t);
static int smtp_read_ack (smtp_t);
static int smtp_write (smtp_t);
static int get_rcpt (message_t , address_t *);
static int get_from (message_t , char *, address_t *);
int
smtp_init (mailer_t mailer)
{
......@@ -173,10 +177,10 @@ smtp_destroy(mailer_t mailer)
bio_destroy (&(smtp->bio));
if (smtp->buffer)
free (smtp->buffer);
if (smtp->from)
free (smtp->from);
if (smtp->to)
free (smtp->to);
if (smtp->mail_from)
address_destroy (&(smtp->mail_from));
if (smtp->rcpt_to)
address_destroy (&(smtp->rcpt_to));
free (smtp);
mailer->data = NULL;
}
......@@ -404,8 +408,7 @@ smtp_close (mailer_t mailer)
}
static int
smtp_send_message(mailer_t mailer, const char *from, const char *rcpt,
int dsn, message_t msg)
smtp_send_message(mailer_t mailer, message_t msg)
{
smtp_t smtp = mailer->data;
int status;
......@@ -416,127 +419,30 @@ smtp_send_message(mailer_t mailer, const char *from, const char *rcpt,
switch (smtp->state)
{
case SMTP_NO_STATE:
smtp->dsn = dsn;
smtp->state = SMTP_ENV_FROM;
status = get_from (msg, smtp->localhost, &smtp->mail_from);
CHECK_ERROR (smtp, status);
status = get_rcpt (msg, &smtp->rcpt_to);
CHECK_ERROR (smtp, status);
case SMTP_ENV_FROM:
if (smtp->from)
{
free (smtp->from);
smtp->from = NULL;
}
/* Try to fetch it from the header. */
if (from == NULL)
{
header_t header;
size_t size;
message_get_header (msg, &header);
status = header_get_value (header, MU_HEADER_FROM, NULL, 0, &size);
if (status == EAGAIN)
return status;
/* If it's not in the header create one form the passwd. */
if (status != 0)
{
struct passwd *pwd = getpwuid (getuid ());
/* Not in the passwd ???? We have a problem. */
if (pwd == 0 || pwd->pw_name == NULL)
{
size_t len = 10 + strlen (smtp->localhost) + 1;
smtp->from = calloc (len, sizeof (char));
if (smtp->from == NULL)
{
CHECK_ERROR (smtp, ENOMEM);
}
snprintf (smtp->from, len, "%d@%s", getuid(),
smtp->localhost);
}
else
{
smtp->from = calloc (strlen (pwd->pw_name) + 1
+ strlen (smtp->localhost) + 1,
sizeof (char));
if (smtp->from == NULL)
{
CHECK_ERROR (smtp, ENOMEM);
}
sprintf(smtp->from, "%s@%s", pwd->pw_name, smtp->localhost);
}
}
else
{
smtp->from = calloc (size + 1, sizeof (char));
if (smtp->from == NULL)
{
CHECK_ERROR (smtp, ENOMEM);
}
status = header_get_value (header, MU_HEADER_FROM, smtp->from,
size + 1, NULL);
CHECK_EAGAIN (smtp, status);
}
}
else
{
smtp->from = strdup (from);
if (smtp->from == NULL)
{
CHECK_ERROR (smtp, ENOMEM);
}
}
/* Check if a Fully Qualified Name, some smtp servers
notably sendmail insists on it, for good reasons. */
if (strchr (smtp->from, '@') == NULL)
{
char *tmp;
tmp = malloc (strlen (smtp->from) + 1 +strlen (smtp->localhost) + 1);
if (tmp == NULL)
{
free (smtp->from);
smtp->from = NULL;
CHECK_ERROR (smtp, ENOMEM);
}
sprintf (tmp, "%s@%s", smtp->from, smtp->localhost);
free (smtp->from);
smtp->from = tmp;
}
smtp->state = SMTP_ENV_RCPT;
case SMTP_ENV_RCPT:
if (smtp->to)
{
free (smtp->to);
smtp->to = NULL;
}
if (rcpt == NULL)
{
header_t header;
size_t size;
message_get_header (msg, &header);
status = header_get_value (header, MU_HEADER_TO, NULL, 0, &size);
CHECK_EAGAIN (smtp, status);
smtp->to = calloc (size + 1, sizeof (char));
if (smtp->to == NULL)
{
CHECK_ERROR (smtp, ENOMEM);
}
status = header_get_value (header, MU_HEADER_TO, smtp->to,
size + 1, NULL);
CHECK_EAGAIN (smtp, status);
}
else
{
smtp->to = strdup (rcpt);
if (smtp->to == NULL)
{
CHECK_ERROR (smtp, ENOMEM);
}
}
status = smtp_writeline (smtp, "MAIL FROM: %s\r\n", smtp->from);
free (smtp->from);
smtp->from = NULL;
CHECK_ERROR (smtp, status);
MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer);
smtp->state = SMTP_MAIL_FROM;
{
size_t len = 0;
char *from;
address_get_email (smtp->mail_from, 1, NULL, 0, &len);
if (len == 0)
CHECK_ERROR (smtp, EINVAL);
from = calloc (len + 1, sizeof (char));
if (from == NULL)
CHECK_ERROR (smtp, ENOMEM);
address_get_email (smtp->mail_from, 1, from, len + 1, NULL);
status = smtp_writeline (smtp, "MAIL FROM: %s\r\n", from);
free (from);
address_destroy (&smtp->mail_from);
CHECK_ERROR (smtp, status);
MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer);
smtp->state = SMTP_MAIL_FROM;
}
case SMTP_MAIL_FROM:
status = smtp_write (smtp);
......@@ -553,68 +459,67 @@ smtp_send_message(mailer_t mailer, const char *from, const char *rcpt,
CLEAR_STATE (smtp);
return EACCES;
}
/* We use a goto, since we may have multiple recipients,
we come back here and doit all over again ... Not pretty. */
case SMTP_ENV_RCPT:
RCPT_TO:
{
char *buf;
size_t len = strlen (smtp->to) + 1;
buf = calloc (len, sizeof (char));
if (buf == NULL)
size_t i = 0;
smtp->rcpt_index++;
address_get_count (smtp->rcpt_to, &i);
if (smtp->rcpt_index <= i)
{
CHECK_ERROR (smtp, ENOMEM);
size_t len = 0;
char *to;
address_get_email (smtp->rcpt_to, smtp->rcpt_index, NULL, 0, &len);
if (len == 0)
CHECK_ERROR (smtp, EINVAL);
to = calloc (len + 1, sizeof (char));
if (to == NULL)
CHECK_ERROR (smtp, ENOMEM);
address_get_email (smtp->rcpt_to, smtp->rcpt_index, to, len + 1, NULL);
status = smtp_writeline (smtp, "RCPT TO: %s\r\n", to);
free (to);
CHECK_ERROR (smtp, status);
MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer);
smtp->state = SMTP_RCPT_TO;
}
if (parseaddr (smtp->to, buf, len) != 0)
else
{
free (buf);
CHECK_ERROR (smtp, EINVAL);
address_destroy (&(smtp->rcpt_to));
smtp->rcpt_index = 0;
smtp->state = SMTP_DATA;
}
status = smtp_writeline (smtp, "RCPT TO: %s\r\n", buf);
free (buf);
CHECK_ERROR (smtp, status);
MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer);
smtp->state = SMTP_RCPT_TO;
}
case SMTP_RCPT_TO:
status = smtp_write (smtp);
CHECK_EAGAIN (smtp, status);
smtp->state = SMTP_RCPT_TO_ACK;
if (smtp->rcpt_to)
{
status = smtp_write (smtp);
CHECK_EAGAIN (smtp, status);
smtp->state = SMTP_RCPT_TO_ACK;
}
case SMTP_RCPT_TO_ACK:
{
char *p;
status = smtp_read_ack (smtp);
CHECK_EAGAIN (smtp, status);
MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer);
if (smtp->buffer[0] != '2')
{
stream_close (mailer->stream);
CLEAR_STATE (smtp);
return EACCES;
}
/* Do we have multiple recipients ? */
p = strchr (smtp->to, ',');
if (p != NULL)
{
char *tmp = smtp->to;
smtp->to = strdup (p++);
if (smtp->to == NULL)
{
free (tmp);
CHECK_ERROR (smtp, ENOMEM);
}
free (tmp);
goto RCPT_TO;
}
/* We are done with the rcpt. */
free (smtp->to);
smtp->to = NULL;
status = smtp_writeline (smtp, "DATA\r\n");
CHECK_ERROR (smtp, status);
MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer);
smtp->state = SMTP_DATA;
}
if (smtp->rcpt_to)
{
status = smtp_read_ack (smtp);
CHECK_EAGAIN (smtp, status);
MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer);
if (smtp->buffer[0] != '2')
{
stream_close (mailer->stream);
CLEAR_STATE (smtp);
return EACCES;
}
goto RCPT_TO;
}
/* We are done with the rcpt. */
status = smtp_writeline (smtp, "DATA\r\n");
CHECK_ERROR (smtp, status);
MAILER_DEBUG0 (mailer, MU_DEBUG_PROT, smtp->buffer);
smtp->state = SMTP_DATA;
case SMTP_DATA:
status = smtp_write (smtp);
......@@ -669,10 +574,10 @@ smtp_send_message(mailer_t mailer, const char *from, const char *rcpt,
smtp->state = SMTP_SEND_DOT;
}
case SMTP_SEND_DOT:
status = smtp_write (smtp);
CHECK_EAGAIN (smtp, status);
smtp->state = SMTP_SEND_ACK;
case SMTP_SEND_DOT:
status = smtp_write (smtp);
CHECK_EAGAIN (smtp, status);
smtp->state = SMTP_SEND_ACK;
case SMTP_SEND_ACK:
status = smtp_read_ack (smtp);
......@@ -693,6 +598,125 @@ smtp_send_message(mailer_t mailer, const char *from, const char *rcpt,
}
static int
get_from (message_t msg, char *localhost, address_t *pmail_from)
{
int status;
size_t size = 0;
char *from;
header_t header = NULL;
message_get_header (msg, &header);
status = header_get_value (header, MU_HEADER_FROM, NULL, 0, &size);
/* If it's not in the header create one form the passwd. */
if (status != 0 || size == 0)
{
struct passwd *pwd = getpwuid (getuid ());
/* Not in the passwd ???? We have a problem. */
if (pwd == 0 || pwd->pw_name == NULL)
{
size = 10 + strlen (localhost) + 1;
from = calloc (size, sizeof (char));
if (from == NULL)
return ENOMEM;
snprintf (from, size, "%d@%s", getuid(), localhost);
}
else
{
from = calloc (strlen (pwd->pw_name) + 1
+ strlen (localhost) + 1, sizeof (char));
if (from == NULL)
return ENOMEM;
sprintf(from, "%s@%s", pwd->pw_name, localhost);
}
}
else
{
from = calloc (size + 1, sizeof (char));
if (from == NULL)
return ENOMEM;
header_get_value (header, MU_HEADER_FROM, from, size + 1, NULL);
}
/* Check if a Fully Qualified Name, some smtp servers
notably sendmail insists on it, for good reasons. */
if (strchr (from, '@') == NULL)
{
char *tmp;
tmp = malloc (strlen (from) + 1 +strlen (localhost) + 1);
if (tmp == NULL)
{
free (from);
return ENOMEM;
}
sprintf (tmp, "%s@%s", from, localhost);
free (from);
from = tmp;
}
status = address_create (pmail_from, from);
free (from);
return status;
}
static int
get_rcpt (message_t msg, address_t *prcpt_to)
{
char *rcpt;
int status;
size_t size = 0;
header_t header = NULL;
message_get_header (msg, &header);
status = header_get_value (header, MU_HEADER_TO, NULL, 0, &size);
if (status == 0 && size != 0)
{
char *tmp;
size_t len;
rcpt = calloc (size + 1, sizeof (char));
if (rcpt == NULL)
return ENOMEM;
header_get_value (header, MU_HEADER_TO, rcpt, size + 1, NULL);
size = 0;
status = header_get_value (header, MU_HEADER_CC, NULL, 0, &size);
if (status == 0 && size != 0)
{
len = strlen (rcpt);
tmp = realloc (rcpt, (len + 1 + size + 1) * sizeof (char));
if (tmp == NULL)
{
free (rcpt);
return ENOMEM;
}
else
rcpt = tmp;
rcpt[len] = ',';
header_get_value (header, MU_HEADER_CC, rcpt + len + 1,
size + 1, NULL);
size = 0;
status = header_get_value (header, MU_HEADER_BCC, NULL, 0, &size);
if (status == 0 && size != 0)
{
len = strlen (rcpt);
tmp = realloc (rcpt, (len + 1 + size + 1) * sizeof (char));
if (tmp == NULL)
{
free (rcpt);
return ENOMEM;
}
else
rcpt = tmp;
rcpt[len] = ',';
header_get_value (header, MU_HEADER_BCC, rcpt + len + 1,
size + 1, NULL);
}
}
status = address_create (prcpt_to, rcpt);
free (rcpt);
return status;
}
return EINVAL;
}
static int
smtp_writeline (smtp_t smtp, const char *format, ...)
{
int len;
......