static void ali_print_name_list (mu_list_t list, int off) { mu_iterator_t itr; char *item; mu_list_get_iterator (list, &itr); if (list_mode) { mu_iterator_first (itr); mu_iterator_current (itr, (void **)&item); printf ("%s\n", item); for (mu_iterator_next (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { int len; mu_iterator_current (itr, (void **)&item); len = off + strlen (item); printf ("%*.*s\n", len, len, item); } } else { int ncol = getcols (); int n = off; mu_iterator_first (itr); for (;;) { int len; mu_iterator_current (itr, (void **)&item); len = strlen (item) + 2; if (n + len > ncol) n = printf ("\n "); len = printf ("%s", item); mu_iterator_next (itr); if (!mu_iterator_is_done (itr)) len += printf (", "); else break; n += len; } printf ("\n"); } mu_iterator_destroy (&itr); }
static int is_known_folder (mu_url_t url, mu_folder_t *pfolder) { int ret = 0; mu_folder_t folder = NULL; mu_iterator_t iterator; if (url == NULL || pfolder == NULL) return ret; if (mu_list_get_iterator (known_folder_list, &iterator) != 0) return ret; for (mu_iterator_first (iterator); !mu_iterator_is_done (iterator); mu_iterator_next (iterator)) { mu_iterator_current (iterator, (void **)&folder); /* Check if the same URL type. */ if (folder && folder->url && mu_url_is_same_scheme (url, folder->url) && mu_url_is_same_user (url, folder->url) && mu_url_is_same_host (url, folder->url) && mu_url_is_same_path (url, folder->url) && mu_url_is_same_port (url, folder->url)) { ret = 1; break; } } if (ret) *pfolder = folder; mu_iterator_destroy (&iterator); return ret; }
int mu_registrar_lookup_scheme (const char *scheme, mu_record_t *precord) { size_t len; mu_iterator_t iterator; int status = mu_registrar_get_iterator (&iterator); if (status != 0) return status; status = MU_ERR_NOENT; len = strcspn (scheme, ":"); for (mu_iterator_first (iterator); !mu_iterator_is_done (iterator); mu_iterator_next (iterator)) { mu_record_t record; mu_iterator_current (iterator, (void **)&record); if (strlen (record->scheme) == len && memcmp (record->scheme, scheme, len) == 0) { if (precord) *precord = record; status = 0; break; } } mu_iterator_destroy (&iterator); return status; }
static void recursive_alias_expand (const char *name, mu_list_t exlist, mu_list_t origlist) { alias_t al; mu_iterator_t itr; if ((al = alias_lookup (name)) == NULL) { if (mu_list_locate (exlist, (void*)name, NULL) == MU_ERR_NOENT) mu_list_append (exlist, (void*)name); return; } mu_list_get_iterator (al->list, &itr); for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { char *word; mu_iterator_current (itr, (void **)&word); if (mu_list_locate (origlist, word, NULL) == MU_ERR_NOENT) { mu_list_push (origlist, word); recursive_alias_expand (word, exlist, origlist); mu_list_pop (origlist, NULL); } } mu_iterator_destroy (&itr); }
static void alias_print (char *name) { if (!name) { mu_iterator_t itr; if (!aliases) return; mu_assoc_get_iterator (aliases, &itr); for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { const char *name; alias_t al; if (mu_iterator_current_kv (itr, (const void **)&name, (void**)&al)) continue; alias_print_group (name, al); } } else { alias_t al; al = alias_lookup (name); if (!al) { mu_error (_("\"%s\": not a group"), name); return; } alias_print_group (name, al); } }
static int _construct_attr_array (size_t *pargc, char ***pargv) { size_t count, i; char **argv; mu_iterator_t itr = NULL; mu_assoc_count (ldap_param.field_map, &count); if (count == 0) return MU_ERR_FAILURE; argv = calloc (count + 1, sizeof argv[0]); mu_assoc_get_iterator (ldap_param.field_map, &itr); for (i = 0, mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr), i++) { char **str; mu_iterator_current (itr, (void**) &str); if ((argv[i] = strdup (*str)) == NULL) { mu_argcv_free (i, argv); return ENOMEM; } } mu_iterator_destroy (&itr); argv[i] = NULL; *pargc = count; *pargv = argv; return 0; }
int mu_list_foreach_dir (mu_list_t list, int dir, mu_list_action_t action, void *cbdata) { mu_iterator_t itr; int status = 0; if (list == NULL || action == NULL) return EINVAL; status = mu_list_get_iterator (list, &itr); if (status) return status; status = mu_iterator_ctl (itr, mu_itrctl_set_direction, &dir); if (status == 0) for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { void *item; mu_iterator_current (itr, &item); if ((status = action (item, cbdata))) break; } mu_iterator_destroy (&itr); return status; }
void cmd_iterate (int argc, char **argv) { if (check_args (argv[0], argc, 1, 2)) return; if (argc == 1) { mu_iterator_t itr; MU_ASSERT (mu_header_get_iterator (header, &itr)); for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { const char *hdr, *val; MU_ASSERT (mu_iterator_current_kv (itr, (const void**)&hdr, (void**)&val)); printf ("%s: %s\n", hdr, val); } mu_iterator_destroy (&itr); } else { const char *hdr, *val; if (!iterator) MU_ASSERT (mu_header_get_iterator (header, &iterator)); if (strcmp (argv[1], "first") == 0 || strcmp (argv[1], "1") == 0) mu_iterator_first (iterator); else if (strcmp (argv[1], "next") == 0 || strcmp (argv[1], "n") == 0) { mu_iterator_next (iterator); if (mu_iterator_is_done (iterator)) { printf ("Past end of headers. Use `itr first'.\n"); return; } } MU_ASSERT (mu_iterator_current_kv (iterator, (const void **)&hdr, (void**)&val)); printf ("%s: %s\n", hdr, val); } }
void mu_sieve_require (mu_list_t slist) { int status; mu_iterator_t itr; status = mu_list_get_iterator (slist, &itr); if (status) { mu_sv_compile_error (&mu_sieve_locus, _("cannot create iterator: %s"), mu_strerror (status)); return; } for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { char *name; int (*reqfn) (mu_sieve_machine_t mach, const char *name) = NULL; const char *text = NULL; mu_iterator_current (itr, (void **)&name); if (strncmp (name, "comparator-", 11) == 0) { name += 11; reqfn = mu_sieve_require_comparator; text = _("required comparator"); } else if (strncmp (name, "test-", 5) == 0) /* GNU extension */ { name += 5; reqfn = mu_sieve_require_test; text = _("required test"); } else if (strcmp (name, "relational") == 0) /* RFC 3431 */ { reqfn = mu_sieve_require_relational; text = ""; } else { reqfn = mu_sieve_require_action; text = _("required action"); } if (reqfn (mu_sieve_machine, name)) { mu_sv_compile_error (&mu_sieve_locus, _("source for the %s %s is not available"), text, name); } } mu_iterator_destroy (&itr); }
int mu_registrar_lookup_url (mu_url_t url, int flags, mu_record_t *precord, int *pflags) { mu_iterator_t iterator; mu_record_t last_record = NULL; int last_flags = 0; int status = mu_registrar_get_iterator (&iterator); if (status != 0) return status; status = MU_ERR_NOENT; for (mu_iterator_first (iterator); !mu_iterator_is_done (iterator); mu_iterator_next (iterator)) { int rc; mu_record_t record; mu_iterator_current (iterator, (void **)&record); if ((rc = mu_record_is_scheme (record, url, flags))) { if (rc == flags) { status = 0; last_record = record; last_flags = rc; break; } else if (rc > last_flags) { status = 0; last_record = record; last_flags = rc; } } } mu_iterator_destroy (&iterator); if (status == 0) { if (precord) *precord = last_record; if (pflags) *pflags = last_flags; } else if (!mu_is_proto (mu_url_to_string (url)) /* FIXME: This check is not enough. */ && mu_registrar_get_default_record (precord) == 0) { status = 0; if (pflags) *pflags = flags & MU_FOLDER_ATTRIBUTE_FILE; /* FIXME? */ } return status; }
/* FIXME: The checker interface should be redone. Until then this function is commented out. Problems: 1. Checkers are called per group, there's no way to call them per tag. 2. See FIXMEs in the code. */ static int index_checker (const char *name, mu_list_t tags, mu_list_t args) { mu_iterator_t itr; mu_sieve_runtime_tag_t *match = NULL; int err; if (!tags || mu_list_get_iterator (tags, &itr)) return 0; err = 0; for (mu_iterator_first (itr); !err && !mu_iterator_is_done (itr); mu_iterator_next (itr)) { mu_sieve_runtime_tag_t *t; mu_iterator_current (itr, (void **)&t); if (strcmp (t->tag, "index") == 0) { if (match) { /* FIXME: 1. This function must be public. 2. locus should be included in t */ mu_sv_compile_error (&mu_sieve_locus, _("index specified twice in call to `%s'"), name); err = 1; break; } } } mu_iterator_destroy (&itr); if (err) return 1; if (match) { if (match->arg->v.number < 1) { // See FIXME above mu_sv_compile_error (&mu_sieve_locus, _("invalid index value: %s"), match->arg->v.string); return 1; } } return 0; }
/* Computes an intersection of two lists and returns it in PDEST. The resulting list contains elements from A that are also encountered in B (as per comparison function of the latter). If DUP_ITEM is not NULL, it is used to create copies of items to be stored in PDEST. In this case, the destroy_item function of B is also attached to PDEST. Otherwise, if DUP_ITEM is NULL, pointers to elements are stored and no destroy_item function is assigned. */ int mu_list_intersect_dup (mu_list_t *pdest, mu_list_t a, mu_list_t b, int (*dup_item) (void **, void *, void *), void *dup_closure) { mu_list_t dest; int rc; mu_iterator_t itr; rc = mu_list_create (&dest); if (rc) return rc; mu_list_set_comparator (dest, b->comp); if (dup_item) mu_list_set_destroy_item (dest, b->destroy_item); rc = mu_list_get_iterator (a, &itr); if (rc) { mu_list_destroy (&dest); return rc; } rc = 0; for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { void *data; mu_iterator_current (itr, &data); if (mu_list_locate (b, data, NULL) == 0) { void *new_data; if (dup_item && data) { rc = dup_item (&new_data, data, dup_closure); if (rc) break; } else new_data = data; mu_list_append (dest, new_data); /* FIXME: Check return, and? */ } } mu_iterator_destroy (&itr); *pdest = dest; return rc; }
sieve_comparator_record_t * _lookup (mu_list_t list, const char *name) { mu_iterator_t itr; sieve_comparator_record_t *reg; if (!list || mu_list_get_iterator (list, &itr)) return NULL; for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { mu_iterator_current (itr, (void **)®); if (strcmp (reg->name, name) == 0) break; else reg = NULL; } mu_iterator_destroy (&itr); return reg; }
static int sub_msgno_last (mu_msgset_t mset, size_t beg) { int rc; struct mu_msgrange *range; if (beg == 1) mu_list_clear (mset->list); else { mu_iterator_t itr; rc = mu_list_get_iterator (mset->list, &itr); if (rc) return rc; rc = 1; rc = mu_iterator_ctl (itr, mu_itrctl_set_direction, &rc); if (rc) { mu_iterator_destroy (&itr); return rc; } for (mu_iterator_first (itr); rc == 0 && !mu_iterator_is_done (itr); mu_iterator_next (itr)) { mu_iterator_current (itr, (void **)&range); if (range->msg_beg > beg) rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); else if (range->msg_beg == beg) { rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); break; } else break; } mu_iterator_destroy (&itr); } return 0; }
void _mu_onexit_run (void) { mu_iterator_t itr; int rc, status = 0; if (!onexit_list) return; rc = mu_list_get_iterator (onexit_list, &itr); if (rc) { mu_error (_("cannot create iterator, onexit aborted: %s"), mu_strerror (rc)); mu_stream_destroy (&mu_strerr); _exit (127); } for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { struct onexit_closure *cp; int rc = mu_iterator_current (itr, (void**)&cp); if (rc) { status = 127; mu_error (_("cannot obtain current item while traversing the" " onexit action list: %s"), mu_strerror (rc)); } else cp->function (cp->data); mu_iterator_ctl (itr, mu_itrctl_delete, NULL); } mu_iterator_destroy (&itr); mu_list_destroy (&onexit_list); if (status) _exit (status); }
/* If the connection was not up it is open by the folder since the stream socket is actually created by the folder. It is not necessary to set select the mailbox/newsgoup right away, there are maybe on going operations. But on any operation by a particular mailbox, it will be selected first. */ static int nntp_mailbox_open (mu_mailbox_t mbox, int flags) { int status = 0; m_nntp_t m_nntp = mbox->data; f_nntp_t f_nntp = m_nntp->f_nntp; mu_iterator_t iterator; /* m_nntp must have been created during mailbox initialization. */ /* assert (mbox->data); assert (m_nntp->name); */ mbox->flags = flags; /* make sure the connection is up. */ if ((status = mu_folder_open (f_nntp->folder, flags))) return status; mu_nntp_set_debug (f_nntp->nntp, mbox->debug); /* We might not have to SELECT the newsgroup, but we need to know it exists. */ status = mu_nntp_list_active (f_nntp->nntp, m_nntp->name, &iterator); if (status == 0) { for (mu_iterator_first (iterator); !mu_iterator_is_done (iterator); mu_iterator_next (iterator)) { char *buffer = NULL; mu_iterator_current (iterator, (void **) &buffer); mu_nntp_parse_list_active (buffer, NULL, &m_nntp->high, &m_nntp->low, &m_nntp->status); } mu_iterator_destroy (&iterator); } return status; }
const char * alias_iterate_first (const char *prefix, alias_iterator_t *pc) { mu_iterator_t itr; alias_iterator_t atr; if (!aliases) { *pc = NULL; return NULL; } if (mu_assoc_get_iterator (aliases, &itr)) return NULL; mu_iterator_first (itr); atr = mu_alloc (sizeof *atr); atr->prefix = prefix; atr->prefixlen = strlen (prefix); atr->pos = 0; atr->itr = itr; *pc = atr; return alias_iterate_next (atr); }
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; }
static int _mu_entry_to_auth_data (LDAP *ld, LDAPMessage *msg, struct mu_auth_data **return_data) { int rc; BerElement *ber = NULL; struct berval bv; char *ufn = NULL; struct mu_auth_data d; mu_iterator_t itr = NULL; memset (&d, 0, sizeof d); rc = ldap_get_dn_ber (ld, msg, &ber, &bv); ufn = ldap_dn2ufn (bv.bv_val); /* FIXME: Use debug or diag functions */ mu_error ("INFO: %s", ufn); ldap_memfree (ufn); mu_assoc_get_iterator (ldap_param.field_map, &itr); for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { char *key; char **pattr; char *attr; struct berval **values; mu_iterator_current_kv (itr, (const void **)&key, (void**) &pattr); attr = *pattr; values = ldap_get_values_len (ld, msg, attr); if (!values || !values[0]) { mu_error ("LDAP field `%s' (`%s') has NULL value", key, *pattr); _free_partial_auth_data (&d); return MU_ERR_READ; } rc = _assign_partial_auth_data (&d, key, values[0]->bv_val); ldap_value_free_len (values); if (rc) { _free_partial_auth_data (&d); return rc; } } rc = mu_auth_data_alloc (return_data, d.name, d.passwd, d.uid, d.gid, d.gecos, d.dir, d.shell, d.mailbox, 1); if (rc == 0) mu_auth_data_set_quota (*return_data, d.quota); _free_partial_auth_data (&d); return rc; }
/* Syntax: deleteheader [:index <fieldno: number> [:last]] [COMPARATOR] [MATCH-TYPE] <field-name: string> [<value-patterns: string-list>] */ int sieve_deleteheader (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags) { mu_sieve_value_t *val; const char *field_name; const char *field_pattern; mu_message_t msg; mu_header_t hdr; int rc; mu_sieve_comparator_t comp; mu_iterator_t itr; unsigned long i, idx = 0; val = mu_sieve_value_get (args, 0); if (!val) { mu_sieve_error (mach, "%lu: %s", (unsigned long) mu_sieve_get_message_num (mach), _("cannot get field name")); mu_sieve_abort (mach); } field_name = val->v.string; val = mu_sieve_value_get (args, 1); if (!val) { field_pattern = NULL; mu_sieve_log_action (mach, "DELETEHEADER", "%s", field_name); } else { switch (val->type) { case SVT_STRING_LIST: if (mu_list_get (val->v.list, 0, (void**)&field_pattern)) { mu_sieve_error (mach, "%lu: %s", (unsigned long) mu_sieve_get_message_num (mach), _("cannot get list item")); mu_sieve_abort (mach); } mu_sieve_log_action (mach, "DELETEHEADER", "%s: (regexp)", field_name); break; case SVT_STRING: field_pattern = val->v.string; mu_sieve_log_action (mach, "DELETEHEADER", "%s: %s", field_name, field_pattern); break; default: mu_sieve_error (mach, "%lu: %s: %d", (unsigned long) mu_sieve_get_message_num (mach), _("unexpected value type"), val->type); mu_sieve_abort (mach); } } if (mu_sieve_is_dry_run (mach)) return 0; msg = mu_sieve_get_message (mach); rc = mu_message_get_header (msg, &hdr); if (rc) { mu_sieve_error (mach, "%lu: %s: %s", (unsigned long) mu_sieve_get_message_num (mach), _("cannot get message header"), mu_strerror (rc)); mu_sieve_abort (mach); } mu_header_get_iterator (hdr, &itr); if (mu_sieve_tag_lookup (tags, "last", NULL)) { int backwards = 1; mu_iterator_ctl (itr, mu_itrctl_set_direction, &backwards); } comp = mu_sieve_get_comparator (mach, tags); if (mu_sieve_tag_lookup (tags, "index", &val)) idx = val->v.number; for (i = 0, mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { const char *fn, *fv; mu_iterator_current_kv (itr, (const void **)&fn, (void **)&fv); if (strcmp (field_name, fn)) continue; if (idx && ++i < idx) continue; if (field_pattern) { if (comp (field_pattern, fv)) mu_iterator_ctl (itr, mu_itrctl_delete, NULL); } else mu_iterator_ctl (itr, mu_itrctl_delete, NULL); if (idx) break; } mu_iterator_destroy (&itr); return 0; }
/* Switch to the given UID/GID */ int mu_switch_to_privs (uid_t uid, gid_t gid, mu_list_t retain_groups) { int rc = 0; gid_t *emptygidset; size_t size = 1, j = 1; mu_iterator_t itr; if (uid == 0) return 0; /* Create a list of supplementary groups */ mu_list_count (retain_groups, &size); size++; emptygidset = xmalloc (size * sizeof emptygidset[0]); emptygidset[0] = gid ? gid : getegid (); if (mu_list_get_iterator (retain_groups, &itr) == 0) { for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) mu_iterator_current (itr, (void **)(emptygidset + j++)); mu_iterator_destroy (&itr); } /* Reset group permissions */ if (geteuid () == 0 && setgroups (j, emptygidset)) { mu_error(_("setgroups(1, %lu) failed: %s"), (unsigned long) emptygidset[0], mu_strerror (errno)); rc = 1; } free (emptygidset); /* Switch to the user's gid. On some OSes the effective gid must be reset first */ #if defined(HAVE_SETEGID) if ((rc = setegid (gid)) < 0) mu_error (_("setegid(%lu) failed: %s"), (unsigned long) gid, mu_strerror (errno)); #elif defined(HAVE_SETREGID) if ((rc = setregid (gid, gid)) < 0) mu_error (_("setregid(%lu,%lu) failed: %s"), (unsigned long) gid, (unsigned long) gid, mu_strerror (errno)); #elif defined(HAVE_SETRESGID) if ((rc = setresgid (gid, gid, gid)) < 0) mu_error (_("setresgid(%lu,%lu,%lu) failed: %s"), (unsigned long) gid, (unsigned long) gid, (unsigned long) gid, mu_strerror (errno)); #endif if (rc == 0 && gid != 0) { if ((rc = setgid (gid)) < 0 && getegid () != gid) mu_error (_("setgid(%lu) failed: %s"), (unsigned long) gid, mu_strerror (errno)); if (rc == 0 && getegid () != gid) { mu_error (_("Cannot set effective gid to %lu"), (unsigned long) gid); rc = 1; } } /* Now reset uid */ if (rc == 0 && uid != 0) { uid_t euid; if (setuid (uid) || geteuid () != uid || (getuid () != uid && (geteuid () == 0 || getuid () == 0))) { #if defined(HAVE_SETREUID) if (geteuid () != uid) { if (setreuid (uid, -1) < 0) { mu_error (_("setreuid(%lu,-1) failed: %s"), (unsigned long) uid, mu_strerror (errno)); rc = 1; } if (setuid (uid) < 0) { mu_error (_("second setuid(%lu) failed: %s"), (unsigned long) uid, mu_strerror (errno)); rc = 1; } } else #endif { mu_error (_("setuid(%lu) failed: %s"), (unsigned long) uid, mu_strerror (errno)); rc = 1; } } euid = geteuid (); if (uid != 0 && setuid (0) == 0) { mu_error (_("seteuid(0) succeeded when it should not")); rc = 1; } else if (uid != euid && setuid (euid) == 0) { mu_error (_("Cannot drop non-root setuid privileges")); rc = 1; } } return rc; }
int mu_sieve_match_part_checker (const char *name, mu_list_t tags, mu_list_t args) { mu_iterator_t itr; mu_sieve_runtime_tag_t *match = NULL; mu_sieve_runtime_tag_t *comp = NULL; mu_sieve_runtime_tag_t *tmp; mu_sieve_comparator_t compfun = NULL; char *compname = "false"; int matchtype; int err = 0; if (!tags || mu_list_get_iterator (tags, &itr)) return 0; for (mu_iterator_first (itr); !err && !mu_iterator_is_done (itr); mu_iterator_next (itr)) { mu_sieve_runtime_tag_t *t; mu_iterator_current (itr, (void **)&t); if (strcmp (t->tag, "is") == 0 || strcmp (t->tag, "contains") == 0 || strcmp (t->tag, "matches") == 0 || strcmp (t->tag, "regex") == 0 || strcmp (t->tag, "count") == 0 || strcmp (t->tag, "value") == 0) { if (match) { mu_sv_compile_error (&mu_sieve_locus, _("match type specified twice in call to `%s'"), name); err = 1; } else match = t; } else if (strcmp (t->tag, "comparator") == 0) comp = t; } mu_iterator_destroy (&itr); if (err) return 1; if (!match || strcmp (match->tag, "is") == 0) matchtype = MU_SIEVE_MATCH_IS; else if (strcmp (match->tag, "contains") == 0) matchtype = MU_SIEVE_MATCH_CONTAINS; else if (strcmp (match->tag, "matches") == 0) matchtype = MU_SIEVE_MATCH_MATCHES; else if (strcmp (match->tag, "regex") == 0) matchtype = MU_SIEVE_MATCH_REGEX; else { char *str = match->arg->v.string; if (strcmp (match->tag, "count") == 0) { mu_sieve_value_t *val; char *str; size_t count; if (comp && strcmp (comp->arg->v.string, "i;ascii-numeric")) { mu_sv_compile_error (&mu_sieve_locus, /* TRANSLATORS: Do not translate ':count'. It is the name of a Sieve tag */ _("comparator %s is incompatible with " ":count in call to `%s'"), comp->arg->v.string, name); return 1; } matchtype = MU_SIEVE_MATCH_LAST; /* to not leave it undefined */ compfun = comp_false; val = mu_sieve_value_get (args, 1); if (!val) return 1; /* shouldn't happen */ /* NOTE: Type of v is always SVT_STRING_LIST */ mu_list_count (val->v.list, &count); if (count > 1) { mu_sv_compile_error (&mu_sieve_locus, _("second argument must be a list of one element")); return 1; } mu_list_get (val->v.list, 0, (void **) &str); count = strtoul (str, &str, 10); if (*str) { mu_sv_compile_error (&mu_sieve_locus, _("second argument cannot be converted to number")); return 1; } } else matchtype = MU_SIEVE_MATCH_EQ; if (mu_sieve_str_to_relcmp (str, NULL, NULL)) { mu_sv_compile_error (&mu_sieve_locus, _("invalid relational match `%s' in call to `%s'"), str, name); return 1; } } if (!compfun) { compname = comp ? comp->arg->v.string : "i;ascii-casemap"; compfun = mu_sieve_comparator_lookup (mu_sieve_machine, compname, matchtype); if (!compfun) { mu_sv_compile_error (&mu_sieve_locus, _("comparator `%s' is incompatible with match type `%s' in call to `%s'"), compname, match ? match->tag : "is", name); return 1; } } tmp = mu_sieve_malloc (mu_sieve_machine, sizeof (*tmp)); tmp->tag = TAG_COMPFUN; tmp->arg = mu_sieve_value_create (SVT_POINTER, compfun); mu_list_append (tags, tmp); if (matchtype == MU_SIEVE_MATCH_REGEX) { /* To speed up things, compile all patterns at once. Notice that it is supposed that patterns are in arg 2 */ mu_sieve_value_t *val, *newval; struct regex_data rd; int rc; if (mu_list_get (args, 1, (void**)&val)) return 0; rd.flags = REG_EXTENDED; if (strcmp (compname, "i;ascii-casemap") == 0) rd.flags |= REG_ICASE; mu_list_create (&rd.list); rc = mu_sieve_vlist_do (val, _regex_compile, &rd); mu_sieve_machine_add_destructor (mu_sieve_machine, _free_reglist, rd.list); if (rc) return rc; newval = mu_sieve_value_create (SVT_STRING_LIST, rd.list); mu_list_replace (args, val, newval); } #ifndef FNM_CASEFOLD else if (matchtype == MU_SIEVE_MATCH_MATCHES && strcmp (compname, "i;ascii-casemap") == 0) { int rc; mu_sieve_value_t *val; if (mu_list_get (args, 1, (void**)&val)) return 0; rc = mu_sieve_vlist_do (val, _pattern_upcase, NULL); if (rc) return rc; } #endif return 0; }
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 mu_msgset_sub_range (mu_msgset_t mset, size_t beg, size_t end, int mode) { int rc; mu_iterator_t itr; struct mu_msgrange *mr; if (!mset) return EINVAL; if (mu_list_is_empty (mset->list)) return MU_ERR_NOENT; if (end && beg > end) { size_t t = end; end = beg; beg = t; } rc = _mu_msgset_translate_pair (mset, mode, &beg, &end); if (rc == MU_ERR_NOENT) return 0; else if (rc) return rc; rc = mu_msgset_aggregate (mset); if (rc) return rc; if (end == MU_MSGNO_LAST) return sub_msgno_last (mset, beg); /* Test border cases */ rc = mu_list_head (mset->list, (void**)&mr); if (rc) return rc; if (end < mr->msg_beg) return 0; if (beg < mr->msg_beg) beg = mr->msg_beg; rc = mu_list_tail (mset->list, (void**) &mr); if (mr->msg_end != MU_MSGNO_LAST) { if (beg > mr->msg_end) return 0; if (end > mr->msg_end) end = mr->msg_end; } rc = mu_list_get_iterator (mset->list, &itr); if (rc) return rc; for (mu_iterator_first (itr); rc == 0 && !mu_iterator_is_done (itr); mu_iterator_next (itr)) { mu_iterator_current (itr, (void **)&mr); if (mr->msg_end == MU_MSGNO_LAST) { /* This is the last element in list. */ if (mr->msg_beg == beg) rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); else if (mr->msg_beg > beg) mr->msg_beg = end + 1; break; } if (mr->msg_beg == beg && mr->msg_end == end) /* See case 2 above */ { rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); break; } else if (mr->msg_beg <= beg && beg <= mr->msg_end) { if (mr->msg_beg <= end && end <= mr->msg_end) /* Case 3 */ { /* Split the range */ if (end != mr->msg_end) { struct mu_msgrange *newrange = calloc (1, sizeof (*newrange)); if (!newrange) { rc = ENOMEM; break; } newrange->msg_beg = end + 1; newrange->msg_end = mr->msg_end; rc = mu_iterator_ctl (itr, mu_itrctl_insert, newrange); if (rc) { free (newrange); break; } } if (mr->msg_beg == beg) rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); else mr->msg_end = beg - 1; break; } else if (mr->msg_beg == beg) /* Case 4 */ { beg = mr->msg_end; rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); } else { size_t n = mr->msg_end; mr->msg_end = beg - 1; beg = n; } } else if (mr->msg_beg <= end && end <= mr->msg_end) /* Case 5 */ { mr->msg_beg = end + 1; if (mr->msg_beg >= mr->msg_end) rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); break; } else if (beg <= mr->msg_beg && mr->msg_beg <= end) { rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); } } mu_iterator_destroy (&itr); return rc; }
static int pop_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount) { int status; size_t i; size_t count = 0; struct _pop3_mailbox *mpd = mbox->data; int flags; mu_iterator_t itr; status = pop_messages_count (mbox, &count); if (status != 0) return status; if (pcount) *pcount = count; flags = _POP3_MSG_SIZE; if (!mu_pop3_capa_test (mpd->pop3, "XLINES", NULL)) flags |= _POP3_MSG_LINES; status = mu_pop3_list_all (mpd->pop3, &itr); if (status) return status; for (i = 0, mu_iterator_first (itr); i <= count && !mu_iterator_is_done (itr); i++, mu_iterator_next (itr)) { const char *str; char *p; size_t num; mu_iterator_current (itr, (void**) &str); num = strtoul (str, &p, 10); if (*p != ' ') { mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR, ("invalid reply to LIST command: %s", str)); status = MU_ERR_BADREPLY; break; } if (num >= msgno) { size_t size, lines; struct _pop3_message *mpm; size = strtoul (p + 1, &p, 10); if (flags & _POP3_MSG_LINES) { if (*p != ' ') { mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR, ("invalid reply to LIST command: %s", str)); status = MU_ERR_BADREPLY; break; } lines = strtoul (p + 1, &p, 10); } status = pop_create_pop3_message (mpd, num, &mpm); if (status) break; mpm->message_size = size; if (flags & _POP3_MSG_LINES) mpm->message_lines = lines; mpm->flags |= flags; if (mbox->observable) { if (((i + 1) % 10) == 0) mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_PROGRESS, NULL); } } } mu_iterator_destroy (&itr); if (mbox->observable) { /* MU_EVT_MESSAGE_ADD must be delivered only when it is already possible to retrieve the message in question. It could not be done in the main loop because no other pop3d function can be called while LIST is being handled. Hence the extra loop. */ for (i = 0; i <= count; i++) { if (mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD, &i) != 0) break; } } return status; }