/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999-2021 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/>. */
#include "mail.h"
#include <mailutils/mime.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
static int isfilename (const char *);
static int msg_to_pipe (const char *cmd, mu_message_t msg);
int multipart_alternative;
/* Additional message headers */
struct add_header
{
int mode;
char *name;
char *value;
};
static mu_list_t add_header_list;
static int
seed_headers (void *item, void *data)
{
struct add_header *hp = item;
compose_env_t *env = data;
compose_header_set (env, hp->name, hp->value, hp->mode);
return 0;
}
static int
list_headers (void *item, void *data)
{
struct add_header *hp = item;
char *name = data;
if (!name || strcmp (name, hp->name) == 0)
{
mu_printf ("%s: %s\n", hp->name, hp->value);
}
return 0;
}
static void
add_header (char *name, char *value, int mode)
{
struct add_header *hp;
if (!add_header_list)
{
int rc = mu_list_create (&add_header_list);
if (rc)
{
mu_error (_("Cannot create header list: %s"), mu_strerror (rc));
exit (1);
}
}
hp = mu_alloc (sizeof (*hp));
hp->mode = mode;
hp->name = name;
hp->value = value;
mu_list_append (add_header_list, hp);
}
void
send_append_header (char const *text)
{
char *p;
size_t len;
char *name;
p = strchr (text, ':');
if (!p)
{
mu_error (_("Invalid header: %s"), text);
return;
}
len = p - text;
name = mu_alloc (len + 1);
memcpy (name, text, len);
name[len] = 0;
for (p++; *p && mu_isspace (*p); p++)
;
add_header (name, mu_strdup (p), COMPOSE_APPEND);
}
void
send_append_header2 (char const *name, char const *value, int mode)
{
add_header (mu_strdup (name), mu_strdup (value), mode);
}
int
mail_sendheader (int argc, char **argv)
{
if (argc == 1)
mu_list_foreach (add_header_list, list_headers, NULL);
else if (argc == 2)
{
if (strchr (argv[1], ':'))
send_append_header (argv[1]);
else
mu_list_foreach (add_header_list, list_headers, argv[1]);
}
else
{
size_t len = strlen (argv[1]);
if (len > 0 && argv[1][len - 1] == ':')
argv[1][len - 1] = 0;
add_header (mu_strdup (argv[1]), mu_strdup (argv[2]), COMPOSE_APPEND);
}
return 0;
}
/* Attachments */
struct atchinfo
{
char *id; /* Attachment id (for listing) */
char *encoding; /* Encoding the attachment uses */
char *content_type; /* Full content type (type/subtype[; attrs]) */
char *name; /* Attachment name */
char *filename; /* Attachment file name */
mu_stream_t source; /* Attachment source stream */
int skip_empty; /* Skip this attachment if it is empty */
int disp_inline; /* Inline content disposition */
};
static void
atchinfo_free (void *p)
{
struct atchinfo *ap = p;
free (ap->id);
free (ap->encoding);
free (ap->content_type);
free (ap->name);
free (ap->filename);
mu_stream_destroy (&ap->source);
free (ap);
}
static mu_list_t
attlist_new (void)
{
mu_list_t lst;
int rc = mu_list_create (&lst);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_list_create", NULL, rc);
exit (1);
}
mu_list_set_destroy_item (lst, atchinfo_free);
return lst;
}
static void
attach_set_content_type (struct atchinfo *aptr, char const *content_type)
{
char *charset;
if (!content_type)
content_type = "text/plain";
if (strncmp (content_type, "text/", 5) == 0
&& !strstr (content_type, "charset=")
&& (charset = util_get_charset ()))
{
mu_asprintf (&aptr->content_type, "%s; charset=%s",
content_type, charset);
free (charset);
}
else
aptr->content_type = mu_strdup (content_type);
}
static void
attlist_add (mu_list_t attlist, char *id, char const *encoding,
char const *content_type, char const *content_name,
char const *content_filename,
mu_stream_t stream, int skip_empty, int disp_inline)
{
struct atchinfo *aptr;
int rc;
aptr = mu_alloc (sizeof (*aptr));
aptr->id = id ? mu_strdup (id) : id;
aptr->encoding = mu_strdup (encoding);
attach_set_content_type (aptr,
content_type
? content_type : "application/octet-stream");
aptr->name = content_name ? mu_strdup (content_name) : NULL;
aptr->filename = content_filename ? mu_strdup (content_filename) : NULL;
aptr->source = stream;
if (stream)
mu_stream_ref (stream);
aptr->skip_empty = skip_empty;
aptr->disp_inline = disp_inline;
rc = mu_list_append (attlist, aptr);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_list_append", NULL, rc);
exit (1);
}
}
int
attlist_attach_file (mu_list_t *attlist_ptr,
int fd,
const char *realname,
const char *content_filename, const char *content_name,
const char *content_type, const char *encoding)
{
int rc;
struct stat st;
mu_list_t list;
mu_stream_t stream = NULL;
char *id = NULL;
mu_list_t attlist;
if (fd >= 0)
{
rc = mu_fd_stream_create (&stream, NULL, fd, MU_STREAM_READ);
if (rc)
{
mu_error (_("can't open descriptor %d: %s"), fd, mu_strerror (rc));
return 1;
}
mu_asprintf (&id, "fd %d", fd);
if (fd == 0)
{
mu_stream_destroy (&mu_strin);
mu_nullstream_create (&mu_strin, MU_STREAM_READ);
mu_stream_ioctl (mu_strin, MU_IOCTL_NULLSTREAM,
MU_IOCTL_NULLSTREAM_SET_PATTERN, NULL);
util_do_command ("set nullbody nullbodymsg");
}
}
else if (realname)
{
if (!content_filename)
content_filename = realname;
if (stat (realname, &st))
{
if (errno == ENOENT)
{
mu_error (_("%s: file does not exist"), realname);
return 1;
}
else
{
mu_error (_("%s: cannot stat: %s"), realname,
mu_strerror (errno));
return 1;
}
}
if (S_ISREG (st.st_mode))
rc = mu_mapfile_stream_create (&stream, realname, MU_STREAM_READ);
else if (S_ISFIFO (st.st_mode))
rc = mu_file_stream_create (&stream, realname, MU_STREAM_READ);
else
{
mu_error (_("%s: not a regular file or FIFO"), realname);
return 1;
}
if (rc)
{
mu_error (_("can't open file %s: %s"),
realname, mu_strerror (rc));
return 1;
}
mu_asprintf (&id, "\"%s\"", realname);
}
else
abort ();
if (!encoding)
encoding = "base64";
mu_filter_get_list (&list);
rc = mu_list_locate (list, (void*) encoding, NULL);
if (rc)
{
mu_error (_("unsupported encoding: %s"), encoding);
free (id);
mu_stream_destroy (&stream);
return 1;
}
if (!*attlist_ptr)
{
attlist = attlist_new ();
*attlist_ptr = attlist;
}
else
attlist = *attlist_ptr;
attlist_add (attlist, id, encoding, content_type,
content_name, content_filename,
stream, skip_empty_attachments, 0);
if (stream)
mu_stream_unref (stream)
|