static int _attachment_setup (mu_mime_io_buffer_t *pinfo, mu_message_t msg, mu_stream_t *pstream) { int ret; mu_body_t body; mu_mime_io_buffer_t info; mu_stream_t stream; if ((ret = mu_message_get_body (msg, &body)) != 0 || (ret = mu_body_get_streamref (body, &stream)) != 0) return ret; *pstream = stream; if (*pinfo) { info = *pinfo; info->refcnt++; } else { ret = mu_mime_io_buffer_create (&info); if (ret) return ret; } *pinfo = info; return 0; }
int moderator_message_get_part (mu_sieve_machine_t mach, mu_message_t msg, size_t index, mu_message_t *pmsg) { int rc; mu_message_t tmp; mu_header_t hdr = NULL; char *value; if ((rc = mu_message_get_part (msg, index, &tmp))) { mu_sieve_error (mach, _("cannot get message part #%lu: %s"), (unsigned long) index, mu_strerror (rc)); return 1; } mu_message_get_header (tmp, &hdr); if (mu_header_aget_value (hdr, MU_HEADER_CONTENT_TYPE, &value) == 0 && memcmp (value, "message/rfc822", 14) == 0) { mu_stream_t str; mu_body_t body; free (value); mu_message_get_body (tmp, &body); mu_body_get_stream (body, &str); rc = mu_stream_to_message (str, pmsg); if (rc) { mu_sieve_error (mach, _("cannot convert MIME part stream to message: %s"), mu_strerror (rc)); return 1; } } else if (value) { mu_sieve_error (mach, _("expected message type message/rfc822, but found %s"), value); free (value); return 1; } else { mu_sieve_error (mach, _("no Content-Type header found")); return 1; } return 0; }
static void print_message_part_sizes (mu_message_t part, int indent) { mu_body_t body; mu_header_t hdr; size_t msize, mlines, hsize, hlines, bsize, blines; MU_ASSERT (mu_message_size (part, &msize)); MU_ASSERT (mu_message_lines (part, &mlines)); MU_ASSERT (mu_message_get_header (part, &hdr)); MU_ASSERT (mu_header_size (hdr, &hsize)); MU_ASSERT (mu_header_lines (hdr, &hlines)); MU_ASSERT (mu_message_get_body (part, &body)); MU_ASSERT (mu_body_size (body, &bsize)); MU_ASSERT (mu_body_lines (body, &blines)); printf ("%*.*sMessage part size - %lu/%lu: %lu/%lu, %lu/%lu\n", indent, indent, "", (unsigned long) msize, (unsigned long) mlines, (unsigned long) hsize, (unsigned long) hlines, (unsigned long) bsize, (unsigned long) blines); }
/* Build a mime response message from original message MSG. TEXT is the message text. */ static int build_mime (mu_sieve_machine_t mach, mu_list_t tags, mu_mime_t *pmime, mu_message_t msg, const char *text) { mu_mime_t mime = NULL; mu_message_t newmsg; mu_stream_t stream, input; mu_header_t hdr; mu_body_t body; const char *header = "Content-Type: text/plain;charset=" MU_SIEVE_CHARSET "\n" "Content-Transfer-Encoding: 8bit\n\n"; int rc; mu_mime_create (&mime, NULL, 0); mu_message_create (&newmsg, NULL); mu_message_get_body (newmsg, &body); if ((rc = mu_static_memory_stream_create (&input, text, strlen (text)))) { mu_sieve_error (mach, _("cannot create temporary stream: %s"), mu_strerror (rc)); mu_mime_destroy (&mime); mu_message_destroy (&newmsg, NULL); return 1; } if (mu_sieve_tag_lookup (tags, "mime", NULL)) { mu_stream_t fstr; rc = mu_filter_create (&fstr, input, "base64", MU_FILTER_ENCODE, MU_STREAM_READ); mu_stream_unref (input); if (rc == 0) { header = "Content-Type: text/plain;charset=" MU_SIEVE_CHARSET "\n" "Content-Transfer-Encoding: base64\n\n"; input = fstr; } } rc = mu_body_get_streamref (body, &stream); if (rc) { mu_sieve_error (mach, _("cannot get input body stream: %s"), mu_strerror (rc)); mu_mime_destroy (&mime); mu_message_destroy (&newmsg, NULL); mu_stream_destroy (&input); return 1; } rc = mu_stream_copy (stream, input, 0, NULL); if (rc) { mu_sieve_error (mach, _("stream copy failed: %s"), mu_strerror (rc)); mu_mime_destroy (&mime); mu_message_destroy (&newmsg, NULL); mu_stream_destroy (&input); mu_stream_destroy (&stream); return 1; } mu_stream_destroy (&input); mu_header_create (&hdr, header, strlen (header)); mu_message_set_header (newmsg, hdr, NULL); mu_mime_add_part (mime, newmsg); mu_message_unref (newmsg); *pmime = mime; return 0; }
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; }
oo\n\ "; int main (int argc, char **argv) { int i; char *p; mu_message_t msg; mu_stream_t stream = NULL; mu_header_t hdr; mu_body_t body; mu_set_program_name (argv[0]); mu_static_memory_stream_create (&stream, text, strlen (text)); assert (mu_stream_to_message (stream, &msg) == 0); mu_stream_unref (stream); assert (mu_message_get_header (msg, &hdr) == 0); assert (mu_message_get_body (msg, &body) == 0); assert (mu_body_get_streamref (body, &stream) == 0); assert (mu_stream_seek (stream, 0, MU_SEEK_END, NULL) == 0); for (i = 1; i < argc; i++) { if (strcmp (argv[i], "-h") == 0) { mu_printf ("usage: %s [-a HDR:VAL] [-t TEXT]\n", mu_program_name); return 0; } if (strcmp (argv[i], "-a") == 0) { i++; assert (argv[i] != NULL); p = strchr (argv[i], ':'); assert (p != NULL); *p++ = 0; while (*p && mu_isspace (*p)) p++; assert (mu_header_set_value (hdr, argv[i], p, 1) == 0); } else if (strcmp (argv[i], "-l") == 0) { mu_off_t off; int whence = MU_SEEK_SET; i++; assert (argv[i] != NULL); off = strtol (argv[i], &p, 10); assert (*p == 0); if (off < 0) whence = MU_SEEK_END; assert (mu_stream_seek (stream, off, whence, NULL) == 0); } else if (strcmp (argv[i], "-t") == 0) { mu_wordsplit_t ws; i++; assert (argv[i] != NULL); if (mu_wordsplit (argv[i], &ws, MU_WRDSF_NOSPLIT | MU_WRDSF_DEFFLAGS)) { mu_error ("mu_wordsplit: %s", mu_wordsplit_strerror (&ws)); exit (1); } else assert (mu_stream_write (stream, ws.ws_wordv[0], strlen (ws.ws_wordv[0]), NULL) == 0); mu_wordsplit_free (&ws); } else mu_error ("ignoring unknown argument %s", argv[i]); } mu_stream_unref (stream); assert (mu_message_get_streamref (msg, &stream) == 0); assert (mu_stream_copy (mu_strout, stream, 0, NULL) == 0); mu_stream_unref (stream); 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; }
void message_display_parts (mu_message_t msg, int indent) { int ret, j; size_t nparts; mu_message_t part; mu_header_t hdr; mu_stream_t str; mu_body_t body; int ismulti; size_t nbytes; /* How many parts does the message has? */ if ((ret = mu_message_get_num_parts (msg, &nparts)) != 0) { fprintf (stderr, "mu_message_get_num_parts - %s\n", mu_strerror (ret)); exit (2); } /* Iterate through all the parts. Treat type "message/rfc822" differently, since it is a message of its own that can have other subparts(recursive). */ for (j = 1; j <= nparts; j++) { int status; const char *hvalue; char *type = NULL; const char *encoding = ""; MU_ASSERT (mu_message_get_part (msg, j, &part)); MU_ASSERT (mu_message_get_header (part, &hdr)); status = mu_header_sget_value (hdr, MU_HEADER_CONTENT_TYPE, &hvalue); if (status == MU_ERR_NOENT) /* nothing */; else if (status != 0) mu_error ("Cannot get header value: %s", mu_strerror (status)); else { status = mu_mimehdr_aget_disp (hvalue, &type); if (status) mu_error ("Cannot extract content type field: %s", mu_strerror (status)); } printf ("%*.*sType of part %d = %s\n", indent, indent, "", j, type ? type : ""); print_message_part_sizes (part, indent); if (mu_header_sget_value (hdr, MU_HEADER_CONTENT_TRANSFER_ENCODING, &encoding)) encoding = ""; ismulti = 0; if ((type && mu_c_strcasecmp (type, "message/rfc822") == 0) || (mu_message_is_multipart (part, &ismulti) == 0 && ismulti)) { if (!ismulti) MU_ASSERT (mu_message_unencapsulate (part, &part, NULL)); MU_ASSERT (mu_message_get_header (part, &hdr)); if (mu_header_sget_value (hdr, MU_HEADER_FROM, &from)) from = ""; if (mu_header_sget_value (hdr, MU_HEADER_SUBJECT, &subject)) subject = ""; printf ("%*.*sEncapsulated message : %s\t%s\n", indent, indent, "", from, subject); printf ("%*.*sBegin\n", indent, indent, ""); message_display_parts (part, indent + indent_level); mu_message_destroy (&part, NULL); } else if (!type || (mu_c_strcasecmp (type, "text/plain") == 0) || (mu_c_strcasecmp (type, "text/html")) == 0) { printf ("%*.*sText Message\n", indent, indent, ""); printf ("%*.*sBegin\n", indent, indent, ""); mu_message_get_body (part, &body); mu_body_get_streamref (body, &str); /* Make sure the original body stream is not closed when str gets destroyed */ mu_filter_create (&str, str, encoding, MU_FILTER_DECODE, MU_STREAM_READ); while (mu_stream_readline (str, buf, sizeof (buf), &nbytes) == 0 && nbytes) { printf ("%*.*s%s", indent, indent, "", buf); } mu_stream_destroy (&str); } else { /* Save the attachements. */ char *fname = NULL; mu_message_aget_decoded_attachment_name (part, charset, &fname, NULL); if (fname == NULL) fname = mu_tempname (NULL); printf ("%*.*sAttachment - saving [%s]\n", indent, indent, "", fname); printf ("%*.*sBegin\n", indent, indent, ""); if (charset) { mu_mime_io_buffer_t info; mu_mime_io_buffer_create (&info); mu_mime_io_buffer_set_charset (info, charset); MU_ASSERT (mu_message_save_attachment (part, NULL, info)); mu_mime_io_buffer_destroy (&info); } else MU_ASSERT (mu_message_save_attachment (part, fname, NULL)); if (print_attachments) print_file (fname, indent); free (fname); } printf ("\n%*.*sEnd\n", indent, indent, ""); free (type); } }
/* FIXME: Do we need to escape body line that begins with "From "? This will require reading the body line by line instead of by chunks, considerably hurting perfomance when expunging. But should not this be the responsibility of the client ? */ static int mbox_append_message0 (mu_mailbox_t mailbox, mu_message_t msg, mu_off_t *psize, int is_expunging, int first) { mbox_data_t mud = mailbox->data; int status = 0; size_t n = 0; char nl = '\n'; size_t orig_size = *psize; char *s; switch (mud->state) { case MBOX_NO_STATE: mud->off = 0; mud->state = MBOX_STATE_APPEND_SENDER; case MBOX_STATE_APPEND_SENDER: /* Generate the sender for the "From " separator. */ { char *s; mu_envelope_t envelope = NULL; mu_message_get_envelope (msg, &envelope); status = mu_envelope_aget_sender (envelope, &mud->sender); switch (status) { case 0: break; case EAGAIN: return status; case MU_ERR_NOENT: /* Envelope headers not found: try to guess */ free (mud->sender); mud->sender = NULL; status = restore_sender (msg, mud); if (status == 0) break; default: free (mud->sender); free (mud->date); mud->date = mud->sender = NULL; mud->state = MBOX_NO_STATE; return status; } /* Nuke trailing newline. */ s = strchr (mud->sender, nl); if (s) *s = '\0'; mud->state = MBOX_STATE_APPEND_DATE; } case MBOX_STATE_APPEND_DATE: /* Generate a date for the "From " separator. */ { mu_envelope_t envelope = NULL; const char *envarr[5]; mu_message_get_envelope (msg, &envelope); status = mu_envelope_aget_date (envelope, &mud->date); switch (status) { case 0: break; case EAGAIN: return status; case MU_ERR_NOENT: /* Envelope headers not found: try to guess */ free (mud->date); mud->date = NULL; status = restore_date (msg, mud); if (status == 0) break; default: free (mud->sender); free (mud->date); mud->date = mud->sender = NULL; mud->state = MBOX_NO_STATE; return status; } /* Nuke trailing newline. */ s = strchr (mud->date, nl); if (s) *s = '\0'; /* Write the separator to the mailbox. */ envarr[0] = "From "; envarr[1] = mud->sender; envarr[2] = " "; envarr[3] = mud->date; envarr[4] = "\n"; status = write_array (mailbox->stream, psize, 5, envarr); if (status) break; free (mud->sender); free (mud->date); mud->sender = mud->date = NULL; /* If we are not expunging get the message in one block via the stream message instead of the header/body. This is good for POP where there is no separation between header and body(RETR). */ if (! is_expunging) { mud->state = MBOX_STATE_APPEND_MESSAGE; break; } mud->state = MBOX_STATE_APPEND_HEADER; } case MBOX_STATE_APPEND_HEADER: /* Append the Header. */ { char buffer[1024]; size_t nread = 0; mu_stream_t is = NULL; mu_header_t header = NULL; mu_message_get_header (msg, &header); mu_header_get_stream (header, &is); do { status = mu_stream_readline (is, buffer, sizeof (buffer), mud->off, &nread); if (status != 0) { if (status != EAGAIN) { mud->state = MBOX_NO_STATE; mud->off = 0; } mu_stream_truncate (mailbox->stream, orig_size); return status; } mud->off += nread; if (*buffer == '\n') break; /* We do not copy the Status since it is rewritten by the attribute code below. Ditto for X-UID and X-IMAPBase. FIXME: - We have a problem here the header may not fit the buffer. - Should we skip the IMAP "X-Status"? */ if ((mu_c_strncasecmp (buffer, "Status", 6) == 0) || (mu_c_strncasecmp (buffer, "X-IMAPbase", 10) == 0) /* FIXME: isn't the length of "X-UID" 5, not 4? And this will match X-UID and X-UIDL, is this intended? */ || (mu_c_strncasecmp (buffer, "X-UID", 4) == 0 && (buffer[5] == ':' || buffer[5] == ' ' || buffer[5] == '\t'))) continue; status = mu_stream_write (mailbox->stream, buffer, nread, *psize, &n); if (status) break; *psize += n; } while (nread > 0); mud->off = 0; /* Rewrite the X-IMAPbase marker. */ if (first && is_expunging) { n = sprintf (buffer, "X-IMAPbase: %lu %u\n", (unsigned long) mud->uidvalidity, (unsigned) mud->uidnext); status = mu_stream_write (mailbox->stream, buffer, n, *psize, &n); if (status) break; *psize += n; } mud->state = MBOX_STATE_APPEND_ATTRIBUTE; } case MBOX_STATE_APPEND_ATTRIBUTE: /* Put the new attributes. */ { #define STATUS_PREFIX_LEN (sizeof(MU_HEADER_STATUS) - 1 + 2) char abuf[STATUS_PREFIX_LEN + MU_STATUS_BUF_SIZE + 1]; size_t na = 0; mu_attribute_t attr = NULL; strcpy(abuf, MU_HEADER_STATUS); strcat(abuf, ": "); mu_message_get_attribute (msg, &attr); mu_attribute_to_string (attr, abuf + STATUS_PREFIX_LEN, sizeof(abuf) - STATUS_PREFIX_LEN - 1, &na); strcat (abuf, "\n"); na = strlen (abuf); mu_stream_write (mailbox->stream, abuf, na, *psize, &n); if (status != 0) break; *psize += n; mud->state = MBOX_STATE_APPEND_UID; } case MBOX_STATE_APPEND_UID: /* The new X-UID. */ { char suid[64]; size_t uid = 0; if (is_expunging) { status = mu_message_get_uid (msg, &uid); if (status == EAGAIN) return status; } else uid = mud->uidnext++; if (status == 0 || uid != 0) { n = sprintf (suid, "X-UID: %u\n", (unsigned) uid); /* Put the UID. */ status = mu_stream_write (mailbox->stream, suid, n, *psize, &n); if (status) break; *psize += n; } /* New line separator of the Header. */ status = mu_stream_write (mailbox->stream, &nl , 1, *psize, &n); if (status) break; *psize += n; mud->state = MBOX_STATE_APPEND_BODY; } case MBOX_STATE_APPEND_BODY: /* Append the Body. */ { char buffer[1024]; size_t nread = 0; mu_stream_t is = NULL; mu_body_t body = NULL; mu_message_get_body (msg, &body); mu_body_get_stream (body, &is); do { status = mu_stream_read (is, buffer, sizeof (buffer), mud->off, &nread); if (status != 0) { if (status != EAGAIN) { mud->state = MBOX_NO_STATE; mud->off = 0; } return status; } mud->off += nread; status = mu_stream_write (mailbox->stream, buffer, nread, *psize, &n); if (status) break; *psize += n; } while (nread > 0); mud->off = 0; n = 0; status = mu_stream_write (mailbox->stream, &nl, 1, *psize, &n); if (status) break; *psize += n; } default: break; } /* If not expunging we are taking the stream message. */ if (!is_expunging) { switch (mud->state) { case MBOX_STATE_APPEND_MESSAGE: { /* Append the Message. */ char buffer[1024]; size_t nread = 0; mu_stream_t is = NULL; mu_message_get_stream (msg, &is); do { status = mu_stream_read (is, buffer, sizeof (buffer), mud->off, &nread); if (status != 0) { if (status != EAGAIN) { mud->state = MBOX_NO_STATE; mud->off = 0; } mu_stream_truncate (mailbox->stream, orig_size); return status; } status = mu_stream_write (mailbox->stream, buffer, nread, *psize, &n); if (status) break; mud->off += nread; *psize += n; } while (nread > 0); if (status) break; status = mu_stream_write (mailbox->stream, &nl, 1, *psize, &n); if (status == 0) *psize += n; } default: break; } } /* is_expunging */ mud->state = MBOX_NO_STATE; if (status) mu_stream_truncate (mailbox->stream, orig_size); else mu_stream_flush (mailbox->stream); 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; 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); status = mu_header_get_streamref (hdr, &stream); if (status) { mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR, ("cannot get header stream: %s", mu_strerror (status))); return status; } mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_TRACE, ("Sending headers...")); mu_stream_seek (stream, 0, MU_SEEK_SET, NULL); while ((status = mu_stream_readline (stream, buffer, sizeof (buffer), &len)) == 0 && len != 0) { if (mu_c_strncasecmp (buffer, MU_HEADER_FCC, sizeof (MU_HEADER_FCC) - 1)) { mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_PROT, ("Header: %s", buffer)); if (write (pm->fd, buffer, len) == -1) { status = errno; mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR, ("write failed: %s", strerror (status))); break; } } found_nl = (len == 1 && buffer[0] == '\n'); } if (!found_nl) { if (write (pm->fd, "\n", 1) == -1) { status = errno; mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR, ("write failed: %s", strerror (status))); } } mu_stream_destroy (&stream); mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_TRACE, ("Sending body...")); mu_message_get_body (msg, &body); status = mu_body_get_streamref (body, &stream); if (status) { mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR, ("cannot get body stream: %s\n", mu_strerror (status))); return status; } mu_stream_seek (stream, 0, MU_SEEK_SET, NULL); while ((status = mu_stream_read (stream, buffer, sizeof (buffer), &len)) == 0 && len != 0) { if (write (pm->fd, buffer, len) == -1) { status = errno; mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR, ("write failed: %s\n", strerror (status))); break; } } mu_body_get_streamref (body, &stream); 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_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR, ("waitpid(%lu) failed: %s\n", (unsigned long) pm->pid, strerror (status))); } } else if (WIFEXITED (exit_status)) { exit_status = WEXITSTATUS (exit_status); mu_debug (MU_DEBCAT_MAILER, 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; }