int mu_msgset_add_range (mu_msgset_t mset, size_t beg, size_t end, int mode) { int rc; struct mu_msgrange *range; if (!mset || beg == 0) return EINVAL; if (end && beg > end) { size_t t = end; end = beg; beg = t; } range = calloc (1, sizeof (*range)); if (!range) return ENOMEM; range->msg_beg = beg; range->msg_end = end; rc = _mu_msgset_translate_range (mset, mode, range); if (rc) { free (range); return rc; } rc = mu_list_append (mset->list, range); if (rc) free (range); mset->flags &= ~_MU_MSGSET_AGGREGATED; return rc; }
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 int sieve_register (mu_list_t *pool, mu_list_t *list, const char *name, mu_sieve_handler_t handler, mu_sieve_data_type *req_arg_types, mu_sieve_data_type *opt_arg_types, mu_sieve_tag_group_t *tags, int required) { mu_sieve_register_t *reg = mu_sieve_palloc (pool, sizeof (*reg)); if (!reg) return ENOMEM; reg->name = name; reg->handler = handler; reg->req_args = req_arg_types; reg->opt_args = opt_arg_types; reg->tags = tags; reg->required = required; if (!*list) { int rc = mu_list_create (list); if (rc) { free (reg); return rc; } } return mu_list_append (*list, reg); }
static int _regex_compile (void *item, void *data) { struct regex_data *rd = data; int rc; regex_t *preg = mu_sieve_malloc (mu_sieve_machine, sizeof (*preg)); rc = regcomp (preg, (char*)item, rd->flags); if (rc) { size_t size = regerror (rc, preg, NULL, 0); char *errbuf = malloc (size + 1); if (errbuf) { regerror (rc, preg, errbuf, size); mu_sv_compile_error (&mu_sieve_locus, _("regex error: %s"), errbuf); free (errbuf); } else mu_sv_compile_error (&mu_sieve_locus, _("regex error")); return rc; } mu_list_append (rd->list, preg); return 0; }
int mu_sieve_register_comparator (mu_sieve_machine_t mach, const char *name, int required, mu_sieve_comparator_t is, mu_sieve_comparator_t contains, mu_sieve_comparator_t matches, mu_sieve_comparator_t regex, mu_sieve_comparator_t eq) { sieve_comparator_record_t *rp; if (!mach->comp_list) { int rc = mu_list_create (&mach->comp_list); if (rc) return rc; } rp = mu_sieve_malloc (mach, sizeof (*rp)); rp->required = required; rp->name = name; rp->comp[MU_SIEVE_MATCH_IS] = is; rp->comp[MU_SIEVE_MATCH_CONTAINS] = contains; rp->comp[MU_SIEVE_MATCH_MATCHES] = matches; rp->comp[MU_SIEVE_MATCH_REGEX] = regex; rp->comp[MU_SIEVE_MATCH_EQ] = eq; return mu_list_append (mach->comp_list, rp); }
static void list_untagged_handler (mu_imap_t imap, mu_list_t resp, void *data) { struct list_closure *clos = data; struct imap_list_element *elt; size_t count; if (clos->error_code) return; mu_list_count (resp, &count); if (count == 4 && _mu_imap_list_nth_element_is_string (resp, 0, clos->command)) { struct mu_list_response *rp; rp = calloc (1, sizeof (*rp)); if (!rp) { clos->error_code = ENOMEM; return; } elt = _mu_imap_list_at (resp, 1); if (!(elt && elt->type == imap_eltype_list)) return; rp->type = 0; mu_list_foreach (elt->v.list, list_attr_conv, rp); elt = _mu_imap_list_at (resp, 3); if (!(elt && elt->type == imap_eltype_string)) return; rp->name = strdup (elt->v.string); if (!rp->name) { free (rp); clos->error_code = ENOMEM; return; } elt = _mu_imap_list_at (resp, 2); if (!elt) return; if (_mu_imap_list_element_is_nil (elt)) { rp->separator = 0; rp->level = 0; } else if (elt->type != imap_eltype_string) return; else { rp->separator = elt->v.string[0]; rp->level = count_level (rp->name, rp->separator); } if ((clos->error_code = mu_list_append (clos->retlist, rp))) mu_list_response_free (rp); } }
static void add_sequence (char *name) { if (!seq_list && mu_list_create (&seq_list)) { mu_error (_("cannot create sequence list")); exit (1); } mu_list_append (seq_list, name); }
void imap4d_capability_add (const char *str) { if (!capa_list) { mu_list_create (&capa_list); mu_list_set_comparator (capa_list, comp); } mu_list_append (capa_list, (void*)str); }
static void pop3d_append_capa_string (struct pop3d_session *sess, const char *name, const char *value) { struct pop3d_capa *cp; cp = mu_alloc (sizeof (*cp)); cp->type = capa_string; cp->name = name; cp->value.string = value ? mu_strdup (value) : NULL; if (mu_list_append (sess->capa, cp)) mu_alloc_die (); }
/* 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; }
static void pop3d_append_capa_func (struct pop3d_session *sess, const char *name, void (*func) (const char *, struct pop3d_session *)) { struct pop3d_capa *cp; if (!func) return; cp = mu_alloc (sizeof (*cp)); cp->type = capa_func; cp->name = name; cp->value.func = func; if (mu_list_append (sess->capa, cp)) mu_alloc_die (); }
void auth_add (char *name, imap4d_auth_handler_fp handler) { struct imap_auth *p = mu_alloc (sizeof (*p)); p->name = name; p->handler = handler; if (!imap_auth_list) { mu_list_create (&imap_auth_list); mu_list_set_comparator (imap_auth_list, comp); mu_list_set_destroy_item (imap_auth_list, mu_list_free_item); } mu_list_append (imap_auth_list, (void*)p); }
int mu_registrar_record (mu_record_t record) { int status; mu_list_t list; mu_list_comparator_t comp; if (!record) return 0; _registrar_get_list (&list); comp = mu_list_set_comparator (list, _compare_prio); status = mu_list_insert (list, record, record, 1); if (status == MU_ERR_NOENT) status = mu_list_append (list, record); mu_list_set_comparator (list, comp); return status; }
int mu_onexit (mu_onexit_t func, void *data) { struct onexit_closure *clos = malloc (sizeof (*clos)); if (!clos) return ENOMEM; clos->function = func; clos->data = data; if (!onexit_list) { int rc = mu_list_create (&onexit_list); mu_list_set_destroy_item (onexit_list, mu_list_free_item); if (rc) return rc; atexit (_mu_onexit_run); } return mu_list_append (onexit_list, clos); }
static void addop (char *field, compfun comp) { struct comp_op *op = xmalloc (sizeof (*op)); if (!oplist) { if (mu_list_create (&oplist)) { mu_error (_("can't create operation list")); exit (1); } mu_list_set_destroy_item (oplist, mu_list_free_item); } op->field = field; op->comp = comp; mu_list_append (oplist, op); }
int mu_pop3_stream_to_list (mu_pop3_t pop3, mu_stream_t stream, mu_list_t list) { int status; size_t n; while ((status = mu_stream_getline (stream, &pop3->rdbuf, &pop3->rdsize, &n)) == 0 && n > 0) { char *np = strdup (pop3->rdbuf); if (!np) { status = ENOMEM; break; } mu_rtrim_class (np, MU_CTYPE_SPACE); status = mu_list_append (list, np); if (status) break; } return status; }
static void update_list (mu_list_t *plist, const char *arg) { size_t j; struct mu_wordsplit ws; mu_list_t list = *plist; if (!list) { MU_ASSERT (mu_list_create (&list)); *plist = list; } ws.ws_delim = ","; if (mu_wordsplit (arg, &ws, MU_WRDSF_DEFFLAGS | MU_WRDSF_DELIM)) { mu_error ("mu_wordsplit: %s", mu_wordsplit_strerror (&ws)); exit (1); } for (j = 0; j < ws.ws_wordc; j++) MU_ASSERT (mu_list_append (list, ws.ws_wordv[j])); ws.ws_wordc = 0; mu_wordsplit_free (&ws); }
int main (int argc, char **argv) { int i; char *host = NULL; char *infile = NULL; char *port = NULL; int tls = 0; int raw = 1; int flags = 0; mu_stream_t stream; mu_smtp_t smtp; mu_stream_t instr; char *from = NULL; mu_list_t rcpt_list = NULL; mu_list_t meth_list = NULL; mu_list_t skiphdr_list = NULL; struct mu_sockaddr *sa; struct mu_sockaddr_hints hints; mu_set_program_name (argv[0]); mu_stdstream_setup (MU_STDSTREAM_RESET_NONE); if (argc < 2) usage (); memset (&hints, 0, sizeof (hints)); hints.flags = MU_AH_DETECT_FAMILY; hints.port = 25; hints.protocol = IPPROTO_TCP; hints.socktype = SOCK_STREAM; MU_ASSERT (mu_smtp_create (&smtp)); for (i = 1; i < argc; i++) { if (strncmp (argv[i], "port=", 5) == 0) port = argv[i] + 5; else if (strncmp (argv[i], "family=", 7) == 0) { hints.flags &= ~MU_AH_DETECT_FAMILY; switch (argv[i][7]) { case '4': hints.family = AF_INET; break; case '6': hints.family = AF_INET6; break; default: mu_error ("invalid family name: %s", argv[i]+7); exit (1); } } else if (strncmp (argv[i], "trace=", 6) == 0) { char *arg = argv[i] + 6; if (mu_isdigit (arg[0])) mu_smtp_trace (smtp, atoi (argv[i] + 6) ? MU_SMTP_TRACE_SET : MU_SMTP_TRACE_CLR); else { mu_smtp_trace (smtp, MU_SMTP_TRACE_SET); if (strcmp (arg, "secure") == 0) mu_smtp_trace_mask (smtp, MU_SMTP_TRACE_SET, MU_XSCRIPT_SECURE); else if (strcmp (arg, "payload") == 0) mu_smtp_trace_mask (smtp, MU_SMTP_TRACE_SET, MU_XSCRIPT_PAYLOAD); } } else if (strncmp (argv[i], "tls=", 4) == 0) tls = atoi (argv[i] + 4); else if (strncmp (argv[i], "domain=", 7) == 0) MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_DOMAIN, argv[i] + 7)); else if (strncmp (argv[i], "user="******"pass="******"service=", 8) == 0) MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_SERVICE, argv[i] + 8)); else if (strncmp (argv[i], "realm=", 6) == 0) MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_REALM, argv[i] + 6)); else if (strncmp (argv[i], "host=", 5) == 0) MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_HOST, argv[i] + 5)); else if (strncmp (argv[i], "url=", 4) == 0) MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_URL, argv[i] + 4)); else if (strncmp (argv[i], "input=", 6) == 0) infile = argv[i] + 6; else if (strncmp (argv[i], "raw=", 4) == 0) raw = atoi (argv[i] + 4); else if (strncmp (argv[i], "rcpt=", 5) == 0) { if (!rcpt_list) MU_ASSERT (mu_list_create (&rcpt_list)); MU_ASSERT (mu_list_append (rcpt_list, argv[i] + 5)); } else if (strncmp (argv[i], "from=", 5) == 0) from = argv[i] + 5; else if (strncmp (argv[i], "auth=", 5) == 0) update_list (&meth_list, argv[i] + 5); else if (strncmp (argv[i], "skiphdr=", 8) == 0) { update_list (&skiphdr_list, argv[i] + 8); raw = 0; } else if (host) { mu_error ("server name already given: %s, new name %s?", host, argv[i]); exit (1); } else host = argv[i]; } if (!host) usage (); if (!raw) flags = MU_STREAM_SEEK; if (infile) MU_ASSERT (mu_file_stream_create (&instr, infile, MU_STREAM_READ|flags)); else MU_ASSERT (mu_stdio_stream_create (&instr, MU_STDIN_FD, flags)); host = argv[1]; MU_ASSERT (mu_sockaddr_from_node (&sa, host, port, &hints)); MU_ASSERT (mu_tcp_stream_create_from_sa (&stream, sa, NULL, MU_STREAM_RDWR)); mu_smtp_set_carrier (smtp, stream); mu_stream_unref (stream); if (!from) { from = getenv ("USER"); if (!from) { mu_error ("cannot determine sender name"); exit (1); } } if (raw && !rcpt_list) { mu_error ("no recipients"); exit (1); } MU_ASSERT (mu_smtp_open (smtp)); MU_ASSERT (mu_smtp_ehlo (smtp)); if (tls && mu_smtp_capa_test (smtp, "STARTTLS", NULL) == 0) { MU_ASSERT (mu_smtp_starttls (smtp)); MU_ASSERT (mu_smtp_ehlo (smtp)); } if (meth_list) { int status; MU_ASSERT (mu_smtp_add_auth_mech_list (smtp, meth_list)); status = mu_smtp_auth (smtp); switch (status) { case 0: MU_ASSERT (mu_smtp_ehlo (smtp)); break; case ENOSYS: case MU_ERR_NOENT: /* Ok, skip it */ break; default: mu_error ("authentication failed: %s", mu_strerror (status)); exit (1); } } MU_ASSERT (mu_smtp_mail_basic (smtp, from, NULL)); mu_list_foreach (rcpt_list, send_rcpt_command, smtp); if (raw) { /* Raw sending mode: send from the stream directly */ MU_ASSERT (mu_smtp_send_stream (smtp, instr)); } else { /* Message (standard) sending mode: send a MU message. */ mu_message_t msg; mu_stream_t ostr, bstr; mu_header_t hdr; mu_iterator_t itr; mu_body_t body; if (skiphdr_list) mu_list_set_comparator (skiphdr_list, headercmp); MU_ASSERT (mu_stream_to_message (instr, &msg)); mu_stream_unref (instr); MU_ASSERT (mu_smtp_data (smtp, &ostr)); MU_ASSERT (mu_message_get_header (msg, &hdr)); MU_ASSERT (mu_header_get_iterator (hdr, &itr)); for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { const char *name; void *value; mu_iterator_current_kv (itr, (void*) &name, &value); if (mu_list_locate (skiphdr_list, (void*) name, NULL) == 0) continue; mu_stream_printf (ostr, "%s: %s\n", name, (char*)value); } mu_iterator_destroy (&itr); MU_ASSERT (mu_stream_write (ostr, "\n", 1, NULL)); MU_ASSERT (mu_message_get_body (msg, &body)); MU_ASSERT (mu_body_get_streamref (body, &bstr)); MU_ASSERT (mu_stream_copy (ostr, bstr, 0, NULL)); mu_stream_destroy (&bstr); mu_stream_close (ostr); mu_stream_destroy (&ostr); } MU_ASSERT (mu_smtp_dot (smtp)); MU_ASSERT (mu_smtp_quit (smtp)); mu_smtp_destroy (&smtp); mu_stream_close (instr); mu_stream_destroy (&instr); return 0; }
int mu_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; }
/* A folder could be remote (IMAP), or local(a spool directory) like $HOME/Mail etc .. We maintain a list of known folders to avoid creating multiple folders for the same URL. So, when mu_folder_create is called we check if we already have a folder for that URL and return it, otherwise we create a new one. Downsides: the scheme to detect the same URL is very weak, and there could be cases where you'll want a different folder for the same URL, there is not easy way to do this. */ int mu_folder_create_from_record (mu_folder_t *pfolder, mu_url_t url, mu_record_t record) { if (!pfolder) return MU_ERR_OUT_PTR_NULL; if (record || /* Look in the registrar list(iterator), for a possible concrete mailbox implementation that could match the URL. */ mu_registrar_lookup_url (url, MU_FOLDER_ATTRIBUTE_DIRECTORY, &record, NULL) == 0) { int (*f_init) (mu_folder_t) = NULL; mu_record_get_folder (record, &f_init); if (f_init) { int status, mask; mu_folder_t folder; int (*u_init) (mu_url_t) = NULL; status = mu_record_check_url (record, url, &mask); if (status) /* FIXME: mask would provide more info */ return status; mu_record_get_url (record, &u_init); if (u_init) { status = u_init (url); if (status) return status; } mu_monitor_wrlock (&folder_lock); /* Check if we already have the same URL folder. */ if (is_known_folder (url, &folder)) { folder->ref++; *pfolder = folder; mu_url_destroy (&url); /* FIXME: Hmm */ mu_monitor_unlock (&folder_lock); return 0; } else mu_monitor_unlock (&folder_lock); /* Create a new folder. */ /* Allocate memory for the folder. */ folder = calloc (1, sizeof (*folder)); if (folder != NULL) { folder->url = url; /* Initialize the internal foilder lock, now so the concrete folder could use it. */ status = mu_monitor_create (&folder->monitor, 0, folder); if (status == 0) { /* Create the concrete folder type. */ status = f_init (folder); if (status == 0) { if (!folder->_match) folder->_match = mu_folder_imap_match; *pfolder = folder; folder->ref++; /* Put on the internal list of known folders. */ if (known_folder_list == NULL) mu_list_create (&known_folder_list); mu_list_append (known_folder_list, folder); } } /* Something went wrong, destroy the object. */ if (status) { if (folder->monitor) mu_monitor_destroy (&folder->monitor, folder); free (folder); } } return status; } } return MU_ERR_NOENT; }