/* For the expunge bits we took a very cautionnary approach, meaning we create a temporary mailbox in the tmpdir copy all the message not mark deleted(Actually we copy all the message that may have been modified i.e new header values set; UIDL or UID or etc .... and skip the deleted ones, truncate the real mailbox to the desired size and overwrite with the tmp mailbox. The approach to do everyting in core is tempting but require - to much memory, it is not rare nowadays to have 30 Megs mailbox, - also there is danger for filesystems with quotas, - if we run out of disk space everything is lost. - or some program may not respect the advisory lock and decide to append a new message while your expunging etc ... The real downside to the approach is that when things go wrong the temporary file may be left in /tmp, which is not all that bad because at least, we have something to recuperate when failure. */ static int mbox_expunge0 (mu_mailbox_t mailbox, int remove_deleted) { mbox_data_t mud = mailbox->data; mbox_message_t mum; int status = 0; sigset_t signalset; int tempfile; size_t i, j, dirty; /* dirty will indicate the first modified message. */ mu_off_t marker = 0; /* marker will be the position to truncate. */ mu_off_t total = 0; char *tmpmboxname = NULL; mu_mailbox_t tmpmailbox = NULL; size_t save_imapbase = 0; /* uidvalidity is save in the first message. */ #ifdef WITH_PTHREAD int state; #endif if (mud == NULL) return EINVAL; MU_DEBUG1 (mailbox->debug, MU_DEBUG_TRACE1, "mbox_expunge (%s)\n", mud->name); /* Noop. */ if (mud->messages_count == 0) return 0; /* Find the first dirty(modified) message. */ for (dirty = 0; dirty < mud->messages_count; dirty++) { mum = mud->umessages[dirty]; /* Message may have been tampered, break here. */ if ((mum->attr_flags & MU_ATTRIBUTE_MODIFIED) || (mum->attr_flags & MU_ATTRIBUTE_DELETED) || (mum->message && mu_message_is_modified (mum->message))) break; } /* Did something change ? */ if (dirty == mud->messages_count) return 0; /* Nothing change, bail out. */ /* Create a temporary file. */ tempfile = mbox_tmpfile (mailbox, &tmpmboxname); if (tempfile == -1) { if (tmpmboxname) free (tmpmboxname); mu_error (_("failed to create temporary file when expunging")); return errno; } /* This is redundant, we go to the loop again. But it's more secure here since we don't want to be disturb when expunging. Destroy all the messages mark for deletion. */ if (remove_deleted) { for (j = 0; j < mud->messages_count; j++) { mum = mud->umessages[j]; if (mum && mum->message && ATTRIBUTE_IS_DELETED (mum->attr_flags)) mu_message_destroy (&(mum->message), mum); } } /* Create temporary mu_mailbox_t. */ { mbox_data_t tmp_mud; char *m = malloc (5 + strlen (tmpmboxname) + 1); if (!m) return ENOMEM; /* Try via the mbox: protocol. */ sprintf (m, "mbox:%s", tmpmboxname); status = mu_mailbox_create (&tmpmailbox, m); if (status != 0) { /* Do not give up just yet, maybe they register the mu_path_record. */ sprintf (m, "%s", tmpmboxname); status = mu_mailbox_create (&tmpmailbox, m); if (status != 0) { /* Ok give up. */ close (tempfile); remove (tmpmboxname); free (m); free (tmpmboxname); return status; } } free (m); /* Must be flag CREATE if not the mu_mailbox_open will try to mmap() the file. */ status = mu_mailbox_open (tmpmailbox, MU_STREAM_CREAT | MU_STREAM_RDWR); if (status != 0) { close (tempfile); remove (tmpmboxname); free (tmpmboxname); return status; } close (tempfile); /* This one is useless the mailbox have its own. */ tmp_mud = tmpmailbox->data; /* May need when appending. */ tmp_mud->uidvalidity = mud->uidvalidity; tmp_mud->uidnext = mud->uidnext; } /* Get the File lock. */ if ((status = mu_locker_lock (mailbox->locker)) != 0) { mu_mailbox_close (tmpmailbox); mu_mailbox_destroy (&tmpmailbox); remove (tmpmboxname); free (tmpmboxname); mu_error (_("failed to grab the lock: %s"), mu_strerror (status)); return status; } /* Critical section, we can not allowed signal here. */ #ifdef WITH_PTHREAD pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state); #endif sigemptyset (&signalset); sigaddset (&signalset, SIGTERM); sigaddset (&signalset, SIGHUP); sigaddset (&signalset, SIGTSTP); sigaddset (&signalset, SIGINT); sigaddset (&signalset, SIGWINCH); sigprocmask (SIG_BLOCK, &signalset, 0); /* Set the marker position. */ marker = mud->umessages[dirty]->header_from; total = 0; /* Copy to the temporary mailbox emails not mark deleted. */ for (i = dirty; i < mud->messages_count; i++) { mum = mud->umessages[i]; /* Skip it, if mark for deletion. */ if (remove_deleted && ATTRIBUTE_IS_DELETED (mum->attr_flags)) { /* We save the uidvalidity in the first message, if it is being deleted we need to move the uidvalidity to the first available (non-deleted) message. */ if (i == save_imapbase) { save_imapbase = i + 1; if (save_imapbase < mud->messages_count) (mud->umessages[save_imapbase])->attr_flags |= MU_ATTRIBUTE_MODIFIED; } continue; } /* Do the expensive mbox_append_message0() only if mark dirty. */ if ((mum->attr_flags & MU_ATTRIBUTE_MODIFIED) || (mum->message && mu_message_is_modified (mum->message))) { /* The message was not instantiated, probably the dirty flag was set by mbox_scan(), create one here. */ if (mum->message == 0) { mu_message_t msg; status = mbox_get_message (mailbox, i + 1, &msg); if (status != 0) { mu_error (_("error expunging:%d: %s"), __LINE__, mu_strerror (status)); goto bailout0; } } status = mbox_append_message0 (tmpmailbox, mum->message, &total, 1, (i == save_imapbase)); if (status != 0) { mu_error (_("error expunging:%d: %s"), __LINE__, mu_strerror (status)); goto bailout0; } /* Clear the dirty bits. */ mum->attr_flags &= ~MU_ATTRIBUTE_MODIFIED; mu_message_clear_modified (mum->message); } else { /* Nothing changed copy the message straight. */ char buffer [1024]; size_t n; mu_off_t offset = mum->header_from; size_t len = mum->body_end - mum->header_from; while (len > 0) { n = (len < sizeof (buffer)) ? len : sizeof (buffer); if ((status = mu_stream_read (mailbox->stream, buffer, n, offset, &n) != 0) || (status = mu_stream_write (tmpmailbox->stream, buffer, n, total, &n) != 0)) { mu_error (_("error expunging:%d: %s"), __LINE__, mu_strerror (status)); goto bailout0; } len -= n; total += n; offset += n; } /* Add the newline separator. */ status = mu_stream_write (tmpmailbox->stream, "\n", 1, total, &n); if (status != 0) { mu_error (_("error expunging:%d: %s"), __LINE__, mu_strerror (status)); goto bailout0; } total++; } } /* for (;;) */ /* Caution: before ftruncate()ing the file see - if we've receive new mails. Some programs may not respect the lock, - or the lock was held for too long. - The mailbox may not have been properly updated before expunging. */ { mu_off_t size = 0; if (mu_stream_size (mailbox->stream, &size) == 0) { mu_off_t len = size - mud->size; mu_off_t offset = mud->size; char buffer [1024]; size_t n = 0; if (len > 0 ) { while ((status = mu_stream_read (mailbox->stream, buffer, sizeof (buffer), offset, &n)) == 0 && n > 0) { status = mu_stream_write (tmpmailbox->stream, buffer, n, total, &n); if (status != 0) { mu_error (_("error expunging:%d: %s"), __LINE__, mu_strerror (status)); goto bailout0; } total += n; offset += n; } } else if (len < 0) { /* Corrupted mailbox. */ mu_error (_("error expunging:%d: %s"), __LINE__, mu_strerror (status)); goto bailout0; } } } /* End of precaution. */ /* Seek and rewrite it. */ if (total > 0) { char buffer [1024]; size_t n = 0; mu_off_t off = 0; mu_off_t offset = marker; while ((status = mu_stream_read (tmpmailbox->stream, buffer, sizeof (buffer), off, &n)) == 0 && n > 0) { status = mu_stream_write (mailbox->stream, buffer, n, offset, &n); if (status != 0) { mu_error (_("error expunging:%d: %s"), __LINE__, mu_strerror (status)); goto bailout; } off += n; offset += n; } } /* Flush/truncation. Need to flush before truncate. */ mu_stream_flush (mailbox->stream); status = mu_stream_truncate (mailbox->stream, total + marker); if (status != 0) { mu_error (_("error expunging:%d: %s"), __LINE__, mu_strerror (status)); goto bailout; } /* Don't remove the tmp mbox in case of errors, when writing back. */ bailout0: remove (tmpmboxname); bailout: free (tmpmboxname); /* Release the File lock. */ mu_locker_unlock (mailbox->locker); mu_mailbox_close (tmpmailbox); mu_mailbox_destroy (&tmpmailbox); /* Reenable signal. */ #ifdef WITH_PTHREAD pthread_setcancelstate (state, &state); #endif sigprocmask (SIG_UNBLOCK, &signalset, 0); /* We need to readjust the pointers. It is a little hairy because we need to keep the message pointers alive So we are going through the array and "defragmentize". For example in (1 2 3 4) if 2 was deleted we need to move 3 4 up by one etc .. */ if (status == 0) { size_t dlast; mu_monitor_wrlock (mailbox->monitor); for (j = dirty, dlast = mud->messages_count - 1; j <= dlast; j++) { /* Clear all the references, any attach messages been already destroy above. */ mum = mud->umessages[j]; if (remove_deleted && ATTRIBUTE_IS_DELETED (mum->attr_flags)) { if ((j + 1) <= dlast) { /* Move all the pointers up. So the message pointer part of mum will be at the right position. */ memmove (mud->umessages + j, mud->umessages + j + 1, (dlast - j) * sizeof (mum)); #if 0 mum->header_from = mum->header_from_end = 0; mum->body = mum->body_end = 0; mum->header_lines = mum->body_lines = 0; #endif memset (mum, 0, sizeof (*mum)); /* We are not free()ing the useless mum, but instead we put it back in the pool, to be reuse. */ mud->umessages[dlast] = mum; dlast--; /* Set mum to the new value after the memmove so it gets cleared to. */ mum = mud->umessages[j]; } else { memset (mum, 0, sizeof (*mum)); } } mum->header_from = mum->header_from_end = 0; mum->body = mum->body_end = 0; mum->header_lines = mum->body_lines = 0; } mu_monitor_unlock (mailbox->monitor); /* This is should reset the messages_count, the last argument 0 means not to send event notification. */ mbox_scan0 (mailbox, dirty, NULL, 0); } return status; }
/* Handler for the timestamp test */ static int timestamp_test (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags) { mu_sieve_value_t *h, *v; mu_header_t hdr; char *val; time_t now = time (NULL); time_t tlimit, tval; int rc; if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE) { mu_sieve_debug (mach, "TIMESTAMP"); } /* Retrieve required arguments: */ /* First argument: header name */ h = mu_sieve_value_get (args, 0); if (!h) { mu_sieve_arg_error (mach, 1); mu_sieve_abort (mach); } /* Second argument: date displacement */ v = mu_sieve_value_get (args, 1); if (!v) { mu_sieve_arg_error (mach, 2); mu_sieve_abort (mach); } if (mu_parse_date (v->v.string, &tlimit, &now)) { mu_sieve_error (mach, _("cannot parse date specification (%s)"), v->v.string); mu_sieve_abort (mach); } rc = mu_message_get_header (mu_sieve_get_message (mach), &hdr); if (rc) { mu_sieve_error (mach, "mu_message_get_header: %s", mu_strerror (rc)); mu_sieve_abort (mach); } if (mu_header_aget_value (hdr, h->v.string, &val)) return 0; if (mu_parse_date (val, &tval, &now)) { mu_sieve_error (mach, "cannot parse header date specification (%s)", val); free (val); mu_sieve_abort (mach); } free (val); rc = tval > tlimit; if (mu_sieve_tag_lookup (tags, "before", NULL)) rc = !rc; return rc; }
int main (int argc, char **argv) { struct group *gr; int status = OK; static int sigtab[] = { SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGSTOP, SIGPIPE }; /* Native Language Support */ MU_APP_INIT_NLS (); MU_AUTH_REGISTER_ALL_MODULES(); /* Register the desired formats. */ mu_register_local_mbox_formats (); #ifdef WITH_TLS mu_gocs_register ("tls", mu_tls_module_init); #endif /* WITH_TLS */ mu_tcpwrapper_cfg_init (); manlock_cfg_init (); mu_acl_cfg_init (); mu_m_server_cfg_init (pop3d_srv_param); mu_argp_init (NULL, NULL); mu_m_server_create (&server, program_version); mu_m_server_set_config_size (server, sizeof (struct pop3d_srv_config)); mu_m_server_set_conn (server, pop3d_connection); mu_m_server_set_prefork (server, mu_tcp_wrapper_prefork); mu_m_server_set_mode (server, MODE_INTERACTIVE); mu_m_server_set_max_children (server, 20); /* FIXME mu_m_server_set_pidfile (); */ mu_m_server_set_default_port (server, 110); mu_m_server_set_timeout (server, 600); mu_m_server_set_strexit (server, mu_strexit); mu_alloc_die_hook = pop3d_alloc_die; mu_log_syslog = 1; manlock_mandatory_locking = 1; #ifdef ENABLE_DBM set_dbm_safety (); #endif if (mu_app_init (&argp, pop3d_argp_capa, pop3d_cfg_param, argc, argv, 0, NULL, server)) exit (EX_CONFIG); /* FIXME: No way to discern from EX_USAGE? */ if (expire == 0) expire_on_exit = 1; #ifdef USE_LIBPAM if (!mu_pam_service) mu_pam_service = "gnu-pop3d"; #endif if (mu_m_server_mode (server) == MODE_INTERACTIVE && isatty (0)) { /* If input is a tty, switch to debug mode */ debug_mode = 1; } else { errno = 0; gr = getgrnam ("mail"); if (gr == NULL) { if (errno == 0 || errno == ENOENT) { mu_error (_("%s: no such group"), "mail"); exit (EX_CONFIG); } else { mu_diag_funcall (MU_DIAG_ERROR, "getgrnam", "mail", errno); exit (EX_OSERR); } } if (setgid (gr->gr_gid) == -1) { mu_error (_("error setting mail group: %s"), mu_strerror (errno)); exit (EX_OSERR); } } /* Set the signal handlers. */ mu_set_signals (pop3d_master_signal, sigtab, MU_ARRAY_SIZE (sigtab)); mu_stdstream_strerr_setup (mu_log_syslog ? MU_STRERR_SYSLOG : MU_STRERR_STDERR); umask (S_IROTH | S_IWOTH | S_IXOTH); /* 007 */ /* Check TLS environment, i.e. cert and key files */ #ifdef WITH_TLS tls_available = mu_check_tls_environment (); if (tls_available) enable_stls (); #endif /* WITH_TLS */ /* Actually run the daemon. */ if (mu_m_server_mode (server) == MODE_DAEMON) { mu_m_server_begin (server); status = mu_m_server_run (server); mu_m_server_end (server); mu_m_server_destroy (&server); } else { /* Make sure we are in the root directory. */ chdir ("/"); status = pop3d_mainloop (MU_STDIN_FD, MU_STDOUT_FD, tls_mode); } if (status) mu_error (_("main loop status: %s"), mu_strerror (status)); /* Close the syslog connection and exit. */ closelog (); return status ? EX_SOFTWARE : EX_OK; }
void smtp (int fd) { int state, c; char *buf = NULL; size_t size = 0; mu_mailbox_t mbox; mu_message_t msg; char *tempfile; char *rcpt_addr; in = fdopen (fd, "r"); out = fdopen (fd, "w"); SETVBUF (in, NULL, _IOLBF, 0); SETVBUF (out, NULL, _IOLBF, 0); smtp_reply (220, "Ready"); for (state = STATE_INIT; state != STATE_QUIT; ) { int argc; char **argv; int kw, len; if (getline (&buf, &size, in) == -1) exit (1); len = strlen (buf); while (len > 0 && (buf[len-1] == '\n' || buf[len-1] == '\r')) len --; buf[len] = 0; if (mu_argcv_get (buf, "", NULL, &argc, &argv)) exit (1); kw = smtp_kw (argv[0]); if (kw == KW_QUIT) { smtp_reply (221, "Done"); state = STATE_QUIT; mu_argcv_free (argc, argv); continue; } switch (state) { case STATE_INIT: switch (kw) { case KW_EHLO: case KW_HELO: if (argc == 2) { smtp_reply (250, "pleased to meet you"); state = STATE_EHLO; } else smtp_reply (501, "%s requires domain address", argv[0]); break; default: smtp_reply (503, "Polite people say HELO first"); break; } break; case STATE_EHLO: switch (kw) { case KW_MAIL: if (argc == 2) from_person = check_prefix (argv[1], "from:"); else if (argc == 3 && mu_c_strcasecmp (argv[1], "from:") == 0) from_person = argv[2]; else from_person = NULL; if (from_person) { from_person = strdup (from_person); smtp_reply (250, "Sender OK"); state = STATE_MAIL; } else smtp_reply (501, "Syntax error"); break; default: smtp_reply (503, "Need MAIL command"); } break; case STATE_MAIL: switch (kw) { case KW_RCPT: if (argc == 2) rcpt_addr = check_prefix (argv[1], "to:"); else if (argc == 3 && mu_c_strcasecmp (argv[1], "to:") == 0) rcpt_addr = argv[2]; else rcpt_addr = NULL; if (rcpt_addr) { if (add_recipient (rcpt_addr)) smtp_reply (451, "Recipient not accepted"); else { smtp_reply (250, "Recipient OK"); state = STATE_RCPT; } } else smtp_reply (501, "Syntax error"); break; default: smtp_reply (503, "Need RCPT command"); } break; case STATE_RCPT: switch (kw) { case KW_RCPT: if (argc == 2) rcpt_addr = check_prefix (argv[1], "to:"); else if (argc == 3 && mu_c_strcasecmp (argv[1], "to:") == 0) rcpt_addr = argv[2]; else rcpt_addr = NULL; if (rcpt_addr) { if (add_recipient (rcpt_addr)) smtp_reply (451, "Recipient not accepted"); else { smtp_reply (250, "Recipient OK"); state = STATE_RCPT; } } else smtp_reply (501, "Syntax error"); break; case KW_DATA: smtp_reply (354, "Enter mail, end with \".\" on a line by itself"); make_tmp (in, from_person, &tempfile); if ((c = mu_mailbox_create_default (&mbox, tempfile)) != 0) { mu_error ("%s: can't create mailbox %s: %s", progname, tempfile, mu_strerror (c)); unlink (tempfile); exit (1); } if ((c = mu_mailbox_open (mbox, MU_STREAM_RDWR)) != 0) { mu_error ("%s: can't open mailbox %s: %s", progname, tempfile, mu_strerror (c)); unlink (tempfile); exit (1); } mu_mailbox_get_message (mbox, 1, &msg); if (message_finalize (msg, 0) == 0) mta_send (msg); else smtp_reply (501, "can't send message"); /*FIXME: code?*/ unlink (tempfile); mu_address_destroy (&recipients); from_person = NULL; smtp_reply (250, "Message accepted for delivery"); state = STATE_EHLO; break; default: smtp_reply (503, "Invalid command"); break; } break; } mu_argcv_free (argc, argv); } close (fd); }
static int pop_open (mu_mailbox_t mbox, int flags) { struct _pop3_mailbox *mpd = mbox->data; int status; mu_stream_t stream; struct mu_sockaddr *sa; struct mu_sockaddr_hints hints; /* Sanity checks. */ if (mpd == NULL) return EINVAL; mbox->flags = flags; memset (&hints, 0, sizeof (hints)); hints.flags = MU_AH_DETECT_FAMILY; hints.port = mpd->pops ? MU_POPS_PORT : MU_POP_PORT; hints.protocol = IPPROTO_TCP; hints.socktype = SOCK_STREAM; status = mu_sockaddr_from_url (&sa, mbox->url, &hints); if (status) return status; status = mu_tcp_stream_create_from_sa (&stream, sa, NULL, mbox->flags); if (status) { mu_sockaddr_free (sa); return status; } #ifdef WITH_TLS if (mpd->pops) { mu_stream_t newstr; status = mu_tls_client_stream_create (&newstr, stream, stream, 0); mu_stream_unref (stream); if (status) { mu_error ("pop_open: mu_tls_client_stream_create: %s", mu_strerror (status)); return status; } stream = newstr; } #endif /* WITH_TLS */ /* FIXME: How to configure buffer size? */ mu_stream_set_buffer (stream, mu_buffer_line, 0); status = mu_pop3_create (&mpd->pop3); if (status) { mu_stream_destroy (&stream); return status; } mu_pop3_set_carrier (mpd->pop3, stream); if (mu_debug_level_p (MU_DEBCAT_MAILBOX, MU_DEBUG_PROT)) mu_pop3_trace (mpd->pop3, MU_POP3_TRACE_SET); if (mu_debug_level_p (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE6)) mu_pop3_trace_mask (mpd->pop3, MU_POP3_TRACE_SET, MU_XSCRIPT_SECURE); if (mu_debug_level_p (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE7)) mu_pop3_trace_mask (mpd->pop3, MU_POP3_TRACE_SET, MU_XSCRIPT_PAYLOAD); do { status = mu_pop3_connect (mpd->pop3); if (status) break; status = mu_pop3_capa (mpd->pop3, 1, NULL); if (status) break; #ifdef WITH_TLS if (!mpd->pops && mu_url_sget_param (mbox->url, "notls", NULL) == MU_ERR_NOENT && mu_pop3_capa_test (mpd->pop3, "STLS", NULL) == 0) { status = mu_pop3_stls (mpd->pop3); if (status) break; } #endif status = mu_authority_authenticate (mbox->folder->authority); } while (0); if (status) mu_pop3_destroy (&mpd->pop3); return status; }
int main (int argc, const char **argv) { char *from; char *subject; mu_mailbox_t mbox; size_t msgno, total = 0; int status; /* Register the formats. */ mu_register_all_mbox_formats (); status = mu_mailbox_create_default (&mbox, argv[1]); if (status != 0) { mu_error ("mu_mailbox_create: %s", mu_strerror (status)); exit (EXIT_FAILURE); } status = mu_mailbox_open (mbox, MU_STREAM_READ); if (status != 0) { mu_error ("mu_mailbox_open: %s", mu_strerror (status)); exit (EXIT_FAILURE); } mu_mailbox_messages_count (mbox, &total); for (msgno = 1; msgno <= total; msgno++) { mu_message_t msg; mu_header_t hdr; if ((status = mu_mailbox_get_message (mbox, msgno, &msg)) != 0 || (status = mu_message_get_header (msg, &hdr)) != 0) { mu_error ("Error message: %s", mu_strerror (status)); exit (EXIT_FAILURE); } if (mu_header_aget_value (hdr, MU_HEADER_FROM, &from)) from = strdup ("(NO FROM)"); if (mu_header_aget_value (hdr, MU_HEADER_SUBJECT, &subject)) subject = strdup ("(NO SUBJECT)"); printf ("%s\t%s\n", from, subject); free (from); free (subject); } status = mu_mailbox_close (mbox); if (status != 0) { mu_error ("mu_mailbox_close: %s", mu_strerror (status)); exit (EXIT_FAILURE); } mu_mailbox_destroy (&mbox); return 0; }
int message_finalize (mu_message_t msg, int warn) { mu_header_t header = NULL; int have_to; char *value = NULL; mu_message_get_header (msg, &header); if (warn && from_person) { struct passwd *pwd = getpwuid (getuid ()); char *warn = malloc (strlen (pwd->pw_name) + 1 + sizeof (SENDER_WARNING)); if (warn == NULL) { mu_error ("%s: not enough memory", progname); return 1; } sprintf (warn, "%s %s", pwd->pw_name, SENDER_WARNING); mu_header_set_value (header, "X-Authentication-Warning", warn, 0); free (warn); } have_to = mu_header_aget_value (header, MU_HEADER_TO, &value) == 0; if (read_recipients) { if (value) { if (add_recipient (value)) { mu_error ("%s: bad address %s", progname, value); return 1; } free (value); } if (mu_header_aget_value (header, MU_HEADER_CC, &value) == 0) { if (add_recipient (value)) { mu_error ("%s: bad address %s", progname, value); return 1; } free (value); } if (mu_header_aget_value (header, MU_HEADER_BCC, &value) == 0) { if (add_recipient (value)) { mu_error ("%s: bad address %s", progname, value); return 1; } free (value); mu_header_set_value (header, MU_HEADER_BCC, NULL, 1); } } if (!have_to) { size_t n; int c; c = mu_address_to_string (recipients, NULL, 0, &n); if (c) { mu_error ("%s: mu_address_to_string failure: %s", progname, mu_strerror (c)); return 1; } value = malloc (n + 1); if (!value) { mu_error ("%s: not enough memory", progname); return 1; } mu_address_to_string (recipients, value, n + 1, &n); mu_header_set_value (header, MU_HEADER_TO, value, 1); free (value); } return 0; }
/* FIXME: How do we do this ??????: IF a new mailbox is created with the same name as a mailbox which was deleted, its unique identifiers MUST be greater than any unique identifiers used in the previous incarnation of the mailbox. */ int imap4d_create (struct imap4d_session *session, struct imap4d_command *command, imap4d_tokbuf_t tok) { char *name; int isdir = 0; int ns; int rc = RESP_OK; const char *msg = "Completed"; if (imap4d_tokbuf_argc (tok) != 3) return io_completion_response (command, RESP_BAD, "Invalid arguments"); name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1); if (*name == '\0') return io_completion_response (command, RESP_BAD, "Too few arguments"); /* Creating, "Inbox" should always fail. */ if (mu_c_strcasecmp (name, "INBOX") == 0) return io_completion_response (command, RESP_BAD, "Already exist"); /* RFC 3501: If the mailbox name is suffixed with the server's hierarchy separator character, this is a declaration that the client intends to create mailbox names under this name in the hierarchy. The trailing delimiter will be removed by namespace normalizer, so test for it now. */ if (name[strlen (name) - 1] == MU_HIERARCHY_DELIMITER) isdir = 1; /* Allocates memory. */ name = namespace_getfullpath (name, &ns); if (!name) return io_completion_response (command, RESP_NO, "Cannot create mailbox"); /* It will fail if the mailbox already exists. */ if (access (name, F_OK) != 0) { if (make_interdir (name, MU_HIERARCHY_DELIMITER, MKDIR_PERMISSIONS)) { rc = RESP_NO; msg = "Cannot create mailbox"; } if (rc == RESP_OK && !isdir) { mu_mailbox_t mbox; rc = mu_mailbox_create_default (&mbox, name); if (rc) { mu_diag_output (MU_DIAG_ERR, _("Cannot create mailbox %s: %s"), name, mu_strerror (rc)); rc = RESP_NO; msg = "Cannot create mailbox"; } else if ((rc = mu_mailbox_open (mbox, MU_STREAM_RDWR | MU_STREAM_CREAT | mailbox_mode[ns]))) { mu_diag_output (MU_DIAG_ERR, _("Cannot open mailbox %s: %s"), name, mu_strerror (rc)); rc = RESP_NO; msg = "Cannot create mailbox"; } else { mu_mailbox_close (mbox); mu_mailbox_destroy (&mbox); rc = RESP_OK; } } } else { rc = RESP_NO; msg = "already exists"; } return io_completion_response (command, rc, "%s", msg); }
/* This code is shared with EXAMINE. */ int imap4d_select0 (struct imap4d_command *command, const char *mboxname, int flags) { int status; char *mailbox_name; /* FIXME: Check state. */ /* Even if a mailbox is selected, a SELECT EXAMINE or LOGOUT command MAY be issued without previously issuing a CLOSE command. The SELECT, EXAMINE, and LOGUT commands implictly close the currently selected mailbox without doing an expunge. */ if (mbox) { imap4d_enter_critical (); mu_mailbox_sync (mbox); mu_mailbox_close (mbox); manlock_unlock (mbox); imap4d_leave_critical (); mu_mailbox_destroy (&mbox); /* Destroy the old uid table. */ imap4d_sync (); } if (strcmp (mboxname, "INBOX") == 0) flags |= MU_STREAM_CREAT; mailbox_name = namespace_getfullpath (mboxname, NULL); if (!mailbox_name) return io_completion_response (command, RESP_NO, "Couldn't open mailbox"); if (flags & MU_STREAM_RDWR) { status = manlock_open_mailbox (&mbox, mailbox_name, 1, flags); } else { status = mu_mailbox_create_default (&mbox, mailbox_name); if (status) mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_create_default", mailbox_name, status); else { status = mu_mailbox_open (mbox, flags); if (status) { mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_open", mailbox_name, status); mu_mailbox_destroy (&mbox); } } } if (status == 0) { select_flags = flags; state = STATE_SEL; imap4d_set_observer (mbox); if ((status = imap4d_select_status ()) == 0) { free (mailbox_name); /* Need to set the state explicitely for select. */ return io_sendf ("%s OK [%s] %s Completed\n", command->tag, ((flags & MU_STREAM_RDWR) == MU_STREAM_RDWR) ? "READ-WRITE" : "READ-ONLY", command->name); } } mu_mailbox_destroy (&mbox); status = io_completion_response (command, RESP_NO, "Could not open %s: %s", mboxname, mu_strerror (status)); free (mailbox_name); 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; }
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 offset, 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_stream (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 | MU_STREAM_NO_CLOSE); offset = 0; while (mu_stream_readline (str, buf, sizeof (buf), offset, &nbytes) == 0 && nbytes) { printf ("%*.*s%s", indent, indent, "", buf); offset += nbytes; } mu_stream_destroy (&str, NULL); } 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); } }
int main (int argc, char **argv) { int i = 1, rc; mu_url_t url = NULL; const char *arg; mu_set_program_name (argv[0]); if (argc > 1) { if (strcmp (argv[1], "help") == 0 || strcmp (argv[1], "--help") == 0 || strcmp (argv[1], "-h") == 0) usage (stdout, 0); if (strncmp (argv[1], "url=", 4) == 0) { MU_ASSERT (mu_url_create (&url, argv[1] + 4)); i = 2; } } if (!url) { MU_ASSERT (mu_url_create_null (&url)); i = 1; } for (; i < argc; i++) { if (strncmp (argv[i], "scheme=", 7) == 0) { MU_ASSERT (mu_url_set_scheme (url, strval (argv[i] + 7))); } else if (strncmp (argv[i], "user="******"path=", 5) == 0) { MU_ASSERT (mu_url_set_path (url, strval (argv[i] + 5))); } else if (strncmp (argv[i], "host=", 5) == 0) { MU_ASSERT (mu_url_set_host (url, strval (argv[i] + 5))); } else if (strncmp (argv[i], "port=", 5) == 0) { MU_ASSERT (mu_url_set_port (url, atoi (argv[i] + 5))); } else if (strncmp (argv[i], "service=", 8) == 0) { MU_ASSERT (mu_url_set_service (url, strval (argv[i] + 8))); } else if (strncmp (argv[i], "auth=", 5) == 0) { MU_ASSERT (mu_url_set_auth (url, strval (argv[i] + 5))); } else if (strncmp (argv[i], "pass="******"param=", 6) == 0) { arg = strval (argv[i] + 6); if (arg) MU_ASSERT (mu_url_add_param (url, 1, (const char **)&arg)); else MU_ASSERT (mu_url_clear_param (url)); } else if (strncmp (argv[i], "query=", 6) == 0) { arg = strval (argv[i] + 6); if (arg) MU_ASSERT (mu_url_add_query (url, 1, (const char **)&arg)); else MU_ASSERT (mu_url_clear_query (url)); } else { mu_error ("unrecognized argument: %s", argv[i]); return 1; } } rc = mu_url_sget_name (url, &arg); if (rc) { mu_error ("%s", mu_strerror (rc)); return 1; } printf ("%s\n", arg); return 0; }