int mu_message_save_attachment (mu_message_t msg, const char *filename, mu_mime_io_buffer_t info) { mu_stream_t istream; int ret; mu_header_t hdr; const char *fname = NULL; char *partname = NULL; if (msg == NULL) return EINVAL; if ((ret = _attachment_setup (&info, msg, &istream)) != 0) return ret; if (ret == 0 && (ret = mu_message_get_header (msg, &hdr)) == 0) { if (filename == NULL) { ret = mu_message_aget_decoded_attachment_name (msg, info->charset, &partname, NULL); if (partname) fname = partname; } else fname = filename; if (fname && (ret = mu_file_stream_create (&info->fstream, fname, MU_STREAM_WRITE | MU_STREAM_CREAT)) == 0) { const char *content_encoding; if (mu_header_sget_value (hdr, MU_HEADER_CONTENT_TRANSFER_ENCODING, &content_encoding)) content_encoding = "7bit"; ret = mu_filter_create (&info->stream, istream, content_encoding, MU_FILTER_DECODE, MU_STREAM_READ); } } if (info->stream && istream) ret = mu_stream_copy (info->fstream, info->stream, 0, NULL); if (ret != EAGAIN && info) { mu_stream_close (info->fstream); mu_stream_destroy (&info->stream); mu_stream_destroy (&info->fstream); } mu_stream_destroy (&istream); _attachment_free (info, ret); /* FIXME: or 0? */ /* Free fname if we allocated it. */ if (partname) free (partname); return ret; }
int mail_tmp_begin (struct mail_tmp **pmtmp, const char *from) { int status; struct mail_tmp *mtmp = malloc (sizeof *mtmp); if (!mtmp) return ENOMEM; memset (mtmp, 0, sizeof *mtmp); mtmp->tempfile = mu_tempname (NULL); if ((status = mu_file_stream_create (&mtmp->stream, mtmp->tempfile, MU_STREAM_RDWR))) { free (mtmp); maidag_error (_("unable to open temporary file: %s"), mu_strerror (status)); return status; } if ((status = mu_stream_open (mtmp->stream))) { free (mtmp); maidag_error (_("unable to open temporary file: %s"), mu_strerror (status)); return status; } mtmp->from = from; *pmtmp = mtmp; return 0; }
/* Open the file. For MU_STREAM_READ, the code tries mmap() first and fall back to normal file. */ static int mbox_open (mu_mailbox_t mailbox, int flags) { mbox_data_t mud = mailbox->data; int status = 0; if (mud == NULL) return EINVAL; mailbox->flags = flags; /* Get a stream. */ if (mailbox->stream == NULL) { /* We do not try to mmap for CREAT or APPEND, it is not supported. */ status = (flags & MU_STREAM_CREAT) || (mailbox->flags & MU_STREAM_APPEND); /* Try to mmap () the file first. */ if (status == 0) { status = mu_mapfile_stream_create (&mailbox->stream, mud->name, mailbox->flags); if (status == 0) { status = mu_stream_open (mailbox->stream); } } /* Fall back to normal file if mmap() failed. */ if (status != 0) { status = mu_file_stream_create (&mailbox->stream, mud->name, mailbox->flags); if (status != 0) return status; status = mu_stream_open (mailbox->stream); } /* All failed, bail out. */ if (status != 0) { mu_stream_destroy (&mailbox->stream, NULL); return status; } /* Even on top of normal FILE *, lets agressively cache. But this may not be suitable for system tight on memory. */ mu_stream_setbufsiz (mailbox->stream, BUFSIZ); } else { status = mu_stream_open (mailbox->stream); if (status != 0) return status; } MU_DEBUG2 (mailbox->debug, MU_DEBUG_TRACE1, "mbox_open (%s, 0x%x)\n", mud->name, mailbox->flags); if (mailbox->locker == NULL) status = mu_locker_create (&(mailbox->locker), mud->name, 0); return status; }
static PyObject * api_file_stream_create (PyObject *self, PyObject *args) { int status, flags; char *filename; PyStream *py_stm; if (!PyArg_ParseTuple (args, "O!si", &PyStreamType, &py_stm, &filename, &flags)) return NULL; status = mu_file_stream_create (&py_stm->stm, filename, flags); return _ro (PyInt_FromLong (status)); }
static int _mh_prop_save (struct _mu_property *prop) { struct mu_mh_prop *mhprop = prop->_prop_init_data; mu_header_t header = prop->_prop_data; mu_stream_t stream; int rc; if (mhprop->ro) return 0; rc = mu_file_stream_create (&stream, mhprop->filename, MU_STREAM_WRITE|MU_STREAM_CREAT); if (rc) return rc; rc = _mh_prop_write_stream (header, mhprop, stream); mu_stream_unref (stream); return rc; }
void mh_comp_draft (const char *formfile, const char *draftfile) { char *s; if (mh_find_file (formfile, &s) == 0) { if (mh_file_copy (s, draftfile)) exit (1); free (s); } else { /* I doubt if we need that: */ int rc; mu_stream_t stream; if ((rc = mu_file_stream_create (&stream, draftfile, MU_STREAM_WRITE|MU_STREAM_CREAT))) { mu_error (_("cannot open output file \"%s\": %s"), draftfile, mu_strerror (rc)); exit (1); } rc = mu_stream_write (stream, default_format_str, strlen (default_format_str), NULL); mu_stream_close (stream); mu_stream_destroy (&stream); if (rc) { mu_error (_("error writing to \"%s\": %s"), draftfile, mu_strerror (rc)); exit (1); } } }
/* Display the contents of the given file on the terminal */ static void display_file (const char *name) { const char *pager = mh_global_profile_get ("moreproc", getenv ("PAGER")); if (pager) mh_spawnp (pager, name); else { mu_stream_t stream; int rc; size_t off = 0; size_t n; char buffer[512]; rc = mu_file_stream_create (&stream, name, MU_STREAM_READ); if (rc) { mu_error ("mu_file_stream_create: %s", mu_strerror (rc)); return; } rc = mu_stream_open (stream); if (rc) { mu_error ("mu_stream_open: %s", mu_strerror (rc)); return; } while (mu_stream_read (stream, buffer, sizeof buffer - 1, off, &n) == 0 && n != 0) { buffer[n] = '\0'; printf ("%s", buffer); off += n; } mu_stream_destroy (&stream, NULL); } }
mu_property_t open_subscription () { int rc; mu_property_t prop; mu_stream_t str; char *filename = mu_make_file_name (real_homedir, ".mu-subscr"); rc = mu_file_stream_create (&str, filename, MU_STREAM_RDWR|MU_STREAM_CREAT); if (rc) { mu_diag_funcall (MU_DIAG_ERROR, "mu_file_stream_create", filename, rc); return NULL; } rc = mu_property_create_init (&prop, mu_assoc_property_init, str); free (filename); if (rc) { mu_diag_funcall (MU_DIAG_ERROR, "mu_property_create_init", NULL, rc); return NULL; } return prop; }
static int _mh_prop_fill (struct _mu_property *prop) { struct mu_mh_prop *mhprop = prop->_prop_init_data; int rc; mu_stream_t stream; mu_header_t header; rc = mu_file_stream_create (&stream, mhprop->filename, MU_STREAM_READ); if (rc) { if ((rc = mu_header_create (&header, NULL, 0)) != 0) mu_error (_("cannot create context %s: %s"), mhprop->filename, mu_strerror (rc)); } else { rc = _mh_prop_read_stream (&header, stream); mu_stream_unref (stream); } if (rc == 0) prop->_prop_data = header; return rc; }
/* Check and update the vacation database. Return 0 if the mail should be answered, 0 if it should not, and throw exception if an error occurs. */ static int check_db (mu_sieve_machine_t mach, mu_list_t tags, char *from) { mu_property_t prop; char *file; mu_sieve_value_t *arg; unsigned int days; int rc; mu_stream_t str; mu_locker_t locker; if (mu_sieve_tag_lookup (tags, "days", &arg)) { days = arg->v.number; if (days > DAYS_MAX) days = DAYS_MAX; } else days = DAYS_DEFAULT; file = mu_tilde_expansion ("~/.vacation", MU_HIERARCHY_DELIMITER, NULL); if (!file) { mu_sieve_error (mach, _("%lu: cannot build db file name"), (unsigned long) mu_sieve_get_message_num (mach)); mu_sieve_abort (mach); } rc = mu_locker_create (&locker, file, 0); if (rc) { mu_sieve_error (mach, _("%lu: cannot lock %s: %s"), (unsigned long) mu_sieve_get_message_num (mach), file, mu_strerror (rc)); free (file); mu_sieve_abort (mach); } rc = mu_file_stream_create (&str, file, MU_STREAM_RDWR|MU_STREAM_CREAT); if (rc) { mu_sieve_error (mach, "%lu: mu_file_stream_create(%s): %s", (unsigned long) mu_sieve_get_message_num (mach), file, mu_strerror (rc)); mu_locker_destroy (&locker); free (file); mu_sieve_abort (mach); } free (file); rc = mu_property_create_init (&prop, mu_assoc_property_init, str); if (rc) { mu_sieve_error (mach, "%lu: mu_property_create_init: %s", (unsigned long) mu_sieve_get_message_num (mach), mu_strerror (rc)); mu_locker_destroy (&locker); mu_sieve_abort (mach); } rc = mu_locker_lock (locker); if (rc) { mu_sieve_error (mach, "%lu: cannot lock vacation database: %s", (unsigned long) mu_sieve_get_message_num (mach), mu_strerror (rc)); mu_property_destroy (&prop); mu_sieve_abort (mach); } rc = test_and_update_prop (prop, from, time (NULL), days, mach); mu_property_destroy (&prop); mu_locker_unlock (locker); mu_locker_destroy (&locker); if (rc == -1) mu_sieve_abort (mach); return rc; }
int main (int argc, char **argv) { int i; char *host = NULL; char *infile = NULL; char *port = NULL; int tls = 0; int raw = 1; int flags = 0; mu_stream_t stream; mu_smtp_t smtp; mu_stream_t instr; char *from = NULL; 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 (MU_STDSTREAM_RESET_NONE); if (argc < 2) usage (); 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_smtp_create (&smtp)); for (i = 1; i < argc; i++) { if (strncmp (argv[i], "port=", 5) == 0) port = argv[i] + 5; else if (strncmp (argv[i], "family=", 7) == 0) { hints.flags &= ~MU_AH_DETECT_FAMILY; switch (argv[i][7]) { case '4': hints.family = AF_INET; break; case '6': hints.family = AF_INET6; break; default: mu_error ("invalid family name: %s", argv[i]+7); exit (1); } } else if (strncmp (argv[i], "trace=", 6) == 0) { char *arg = argv[i] + 6; if (mu_isdigit (arg[0])) mu_smtp_trace (smtp, atoi (argv[i] + 6) ? MU_SMTP_TRACE_SET : MU_SMTP_TRACE_CLR); else { mu_smtp_trace (smtp, MU_SMTP_TRACE_SET); if (strcmp (arg, "secure") == 0) mu_smtp_trace_mask (smtp, MU_SMTP_TRACE_SET, MU_XSCRIPT_SECURE); else if (strcmp (arg, "payload") == 0) mu_smtp_trace_mask (smtp, MU_SMTP_TRACE_SET, MU_XSCRIPT_PAYLOAD); } } else if (strncmp (argv[i], "tls=", 4) == 0) tls = atoi (argv[i] + 4); else if (strncmp (argv[i], "domain=", 7) == 0) MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_DOMAIN, argv[i] + 7)); else if (strncmp (argv[i], "user="******"pass="******"service=", 8) == 0) MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_SERVICE, argv[i] + 8)); else if (strncmp (argv[i], "realm=", 6) == 0) MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_REALM, argv[i] + 6)); else if (strncmp (argv[i], "host=", 5) == 0) MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_HOST, argv[i] + 5)); else if (strncmp (argv[i], "url=", 4) == 0) MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_URL, argv[i] + 4)); else if (strncmp (argv[i], "input=", 6) == 0) infile = argv[i] + 6; else if (strncmp (argv[i], "raw=", 4) == 0) raw = atoi (argv[i] + 4); else if (strncmp (argv[i], "rcpt=", 5) == 0) { if (!rcpt_list) MU_ASSERT (mu_list_create (&rcpt_list)); MU_ASSERT (mu_list_append (rcpt_list, argv[i] + 5)); } else if (strncmp (argv[i], "from=", 5) == 0) from = argv[i] + 5; else if (strncmp (argv[i], "auth=", 5) == 0) update_list (&meth_list, argv[i] + 5); else if (strncmp (argv[i], "skiphdr=", 8) == 0) { update_list (&skiphdr_list, argv[i] + 8); raw = 0; } else if (host) { mu_error ("server name already given: %s, new name %s?", host, argv[i]); exit (1); } else host = argv[i]; } if (!host) usage (); if (!raw) flags = MU_STREAM_SEEK; if (infile) MU_ASSERT (mu_file_stream_create (&instr, infile, MU_STREAM_READ|flags)); else MU_ASSERT (mu_stdio_stream_create (&instr, MU_STDIN_FD, flags)); host = argv[1]; 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); if (!from) { from = getenv ("USER"); if (!from) { mu_error ("cannot determine sender name"); exit (1); } } if (raw && !rcpt_list) { mu_error ("no recipients"); exit (1); } MU_ASSERT (mu_smtp_open (smtp)); MU_ASSERT (mu_smtp_ehlo (smtp)); if (tls && mu_smtp_capa_test (smtp, "STARTTLS", NULL) == 0) { MU_ASSERT (mu_smtp_starttls (smtp)); MU_ASSERT (mu_smtp_ehlo (smtp)); } if (meth_list) { int status; MU_ASSERT (mu_smtp_add_auth_mech_list (smtp, meth_list)); status = mu_smtp_auth (smtp); switch (status) { case 0: MU_ASSERT (mu_smtp_ehlo (smtp)); break; case ENOSYS: case MU_ERR_NOENT: /* Ok, skip it */ break; default: mu_error ("authentication failed: %s", mu_strerror (status)); exit (1); } } MU_ASSERT (mu_smtp_mail_basic (smtp, from, NULL)); mu_list_foreach (rcpt_list, send_rcpt_command, smtp); if (raw) { /* Raw sending mode: send from the stream directly */ MU_ASSERT (mu_smtp_send_stream (smtp, instr)); } else { /* Message (standard) sending mode: send a MU message. */ mu_message_t msg; mu_stream_t ostr, bstr; mu_header_t hdr; mu_iterator_t itr; mu_body_t body; if (skiphdr_list) mu_list_set_comparator (skiphdr_list, headercmp); MU_ASSERT (mu_stream_to_message (instr, &msg)); mu_stream_unref (instr); MU_ASSERT (mu_smtp_data (smtp, &ostr)); MU_ASSERT (mu_message_get_header (msg, &hdr)); MU_ASSERT (mu_header_get_iterator (hdr, &itr)); for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { const char *name; void *value; mu_iterator_current_kv (itr, (void*) &name, &value); if (mu_list_locate (skiphdr_list, (void*) name, NULL) == 0) continue; mu_stream_printf (ostr, "%s: %s\n", name, (char*)value); } mu_iterator_destroy (&itr); MU_ASSERT (mu_stream_write (ostr, "\n", 1, NULL)); MU_ASSERT (mu_message_get_body (msg, &body)); MU_ASSERT (mu_body_get_streamref (body, &bstr)); MU_ASSERT (mu_stream_copy (ostr, bstr, 0, NULL)); mu_stream_destroy (&bstr); mu_stream_close (ostr); mu_stream_destroy (&ostr); } MU_ASSERT (mu_smtp_dot (smtp)); MU_ASSERT (mu_smtp_quit (smtp)); mu_smtp_destroy (&smtp); mu_stream_close (instr); mu_stream_destroy (&instr); return 0; }
int mu_message_create_attachment (const char *content_type, const char *encoding, const char *filename, mu_message_t *newmsg) { mu_header_t hdr; mu_body_t body; mu_stream_t fstream = NULL, tstream = NULL; char *header = NULL, *name = NULL, *fname = NULL; int ret; if (newmsg == NULL) return MU_ERR_OUT_PTR_NULL; if (filename == NULL) return EINVAL; if ((ret = mu_message_create (newmsg, NULL)) == 0) { if (content_type == NULL) content_type = "text/plain"; if (encoding == NULL) encoding = "7bit"; if ((fname = strdup (filename)) != NULL) { name = strrchr (fname, '/'); if (name) name++; else name = fname; ret = mu_asprintf (&header, "Content-Type: %s; name=%s\n" "Content-Transfer-Encoding: %s\n" "Content-Disposition: attachment; filename=%s\n\n", content_type, name, encoding, name); if (ret == 0) { if ((ret = mu_header_create (&hdr, header, strlen (header))) == 0) { mu_stream_t bstr; mu_message_get_body (*newmsg, &body); mu_body_get_streamref (body, &bstr); if ((ret = mu_file_stream_create (&fstream, filename, MU_STREAM_READ)) == 0) { if ((ret = mu_filter_create (&tstream, fstream, encoding, MU_FILTER_ENCODE, MU_STREAM_READ)) == 0) { mu_stream_copy (bstr, tstream, 0, NULL); mu_stream_unref (tstream); mu_message_set_header (*newmsg, hdr, NULL); } } mu_stream_unref (bstr); free (header); } } } } if (ret) { if (*newmsg) mu_message_destroy (newmsg, NULL); if (hdr) mu_header_destroy (&hdr); if (fstream) mu_stream_destroy (&fstream); if (fname) free (fname); } return ret; }
int main (int argc, char **argv) { int index; int rc; mu_stream_t in, tmp; mu_message_t msg; mu_header_t hdr; mu_iterator_t itr; const char *file; char *newval; mu_off_t size; mu_body_t body; mu_stream_t bstr; MU_APP_INIT_NLS (); mh_argp_init (); mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc, opt_handler, NULL, &index); if (index == argc) { mu_error (_("file name not given")); exit (1); } file = argv[index]; prompter_init (); if (erase_seq) prompter_set_erase (erase_seq); if (kill_seq) prompter_set_erase (kill_seq); if ((rc = mu_stdio_stream_create (&strout, MU_STDOUT_FD, MU_STREAM_WRITE))) { mu_error (_("cannot open stdout: %s"), mu_strerror (rc)); return 1; } if ((rc = mu_file_stream_create (&in, file, MU_STREAM_RDWR))) { mu_error (_("cannot open input file `%s': %s"), file, mu_strerror (rc)); return 1; } rc = mu_stream_to_message (in, &msg); mu_stream_unref (in); if (rc) { mu_error (_("input stream %s is not a message (%s)"), file, mu_strerror (rc)); return 1; } if ((rc = mu_temp_file_stream_create (&tmp, NULL, 0))) { mu_error (_("Cannot open temporary file: %s"), mu_strerror (rc)); return 1; } /* Copy headers */ mu_message_get_header (msg, &hdr); mu_header_get_iterator (hdr, &itr); for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { const char *name, *val; mu_iterator_current_kv (itr, (const void **)&name, (void**)&val); if (!is_empty_string (val)) { mu_stream_printf (tmp, "%s: %s\n", name, val); mu_stream_printf (strout, "%s: %s\n", name, val); } else { int cont = 0; mu_opool_t opool; const char *prompt = name; mu_opool_create (&opool, 1); do { size_t len; char *p; p = prompter_get_value (prompt); if (!p) return 1; prompt = NULL; if (cont) { mu_opool_append_char (opool, '\n'); if (!mu_isspace (p[0])) mu_opool_append_char (opool, '\t'); } len = strlen (p); if (len > 0 && p[len-1] == '\\') { len--; cont = 1; } else cont = 0; mu_opool_append (opool, p, len); free (p); } while (cont); mu_opool_append_char (opool, 0); newval = mu_opool_finish (opool, NULL); if (!is_empty_string (newval)) mu_stream_printf (tmp, "%s: %s\n", name, newval); mu_opool_destroy (&opool); } } mu_iterator_destroy (&itr); mu_stream_printf (strout, "--------\n"); mu_stream_write (tmp, "\n", 1, NULL); /* Copy body */ if (prepend_option) { mu_stream_printf (strout, "\n--------%s\n\n", _("Enter initial text")); while ((newval = prompter_get_line ())) { mu_stream_write (tmp, newval, strlen (newval), NULL); free (newval); mu_stream_write (tmp, "\n", 1, NULL); } } mu_message_get_body (msg, &body); mu_body_get_streamref (body, &bstr); if (!prepend_option && !rapid_option) { mu_stream_copy (strout, bstr, 0, NULL); mu_stream_seek (bstr, 0, MU_SEEK_SET, NULL); } mu_stream_copy (tmp, bstr, 0, NULL); mu_stream_unref (bstr); if (!prepend_option && !rapid_option) { printf ("\n--------%s\n\n", _("Enter additional text")); while ((newval = prompter_get_line ())) { mu_stream_write (tmp, newval, strlen (newval), NULL); free (newval); mu_stream_write (tmp, "\n", 1, NULL); } } /* Destroy the message */ mu_message_destroy (&msg, mu_message_get_owner (msg)); /* Rewind the streams and copy data back to in. */ mu_stream_seek (in, 0, MU_SEEK_SET, NULL); mu_stream_seek (tmp, 0, MU_SEEK_SET, NULL); mu_stream_copy (in, tmp, 0, &size); mu_stream_truncate (in, size); mu_stream_destroy (&in); mu_stream_destroy (&tmp); mu_stream_destroy (&strout); prompter_done (); return 0; }
int mutool_send (int argc, char **argv) { int index; char *infile; mu_stream_t instr; mu_message_t msg; size_t count; mu_url_t urlhint, url; mu_mailer_t mailer; MU_ASSERT (mu_address_create_null (&rcpt_addr)); mu_register_all_mailer_formats (); if (argp_parse (&send_argp, argc, argv, 0, &index, NULL)) return 1; argc -= index; argv += index; if (argc < 1) { mu_error (_("not enough arguments")); return 1; } infile = argv[1]; if (infile) MU_ASSERT (mu_file_stream_create (&instr, infile, MU_STREAM_READ|MU_STREAM_SEEK)); else MU_ASSERT (mu_stdio_stream_create (&instr, MU_STDIN_FD, MU_STREAM_READ|MU_STREAM_SEEK)); MU_ASSERT (mu_stream_to_message (instr, &msg)); mu_stream_unref (instr); mu_address_get_count (rcpt_addr, &count); if (count == 0) read_recipients = 1; if (read_recipients) { int rc; mu_header_t header; const char *value; MU_ASSERT (mu_message_get_header (msg, &header)); rc = mu_header_sget_value (header, MU_HEADER_TO, &value); if (rc == 0) send_address_add (&rcpt_addr, value); else if (rc != MU_ERR_NOENT) { mu_diag_funcall (MU_DIAG_ERROR, "mu_header_sget_value", MU_HEADER_TO, rc); exit (1); } rc = mu_header_sget_value (header, MU_HEADER_CC, &value); if (rc == 0) send_address_add (&rcpt_addr, value); else if (rc != MU_ERR_NOENT) { mu_diag_funcall (MU_DIAG_ERROR, "mu_header_sget_value", MU_HEADER_CC, rc); exit (1); } rc = mu_header_sget_value (header, MU_HEADER_BCC, &value); if (rc == 0) send_address_add (&rcpt_addr, value); else if (rc != MU_ERR_NOENT) { mu_diag_funcall (MU_DIAG_ERROR, "mu_header_sget_value", MU_HEADER_BCC, rc); exit (1); } } mu_address_get_count (rcpt_addr, &count); if (count == 0) { mu_error (_("no recipients")); exit (1); } MU_ASSERT (mu_url_create (&urlhint, "smtp://")); MU_ASSERT (mu_url_create_hint (&url, argv[0], MU_URL_PARSE_DEFAULT, urlhint)); mu_url_invalidate (url); MU_ASSERT (mu_mailer_create_from_url (&mailer, url)); MU_ASSERT (mu_mailer_open (mailer, MU_STREAM_RDWR)); MU_ASSERT (mu_mailer_send_message (mailer, msg, from_addr, rcpt_addr)); mu_mailer_close (mailer); mu_mailer_destroy (&mailer); return 0; }