/* :comparator i;ascii-numeric */ static int i_ascii_numeric_is (const char *pattern, const char *text) { if (mu_isdigit (*pattern)) { if (mu_isdigit (*text)) return strtol (pattern, NULL, 10) == strtol (text, NULL, 10); else return 0; } else if (mu_isdigit (*text)) return 0; else return 1; }
static int i_ascii_numeric_eq (const char *pattern, const char *text) { if (mu_isdigit (*pattern)) { if (mu_isdigit (*text)) { size_t a = strtoul (pattern, NULL, 10); size_t b = strtoul (text, NULL, 10); if (b > a) return 1; else if (b < a) return -1; return 0; } else return 1; } else return 1; }
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; }
/* Parse a message specification from (argc;argv). Returned msgset is not sorted nor optimised */ int _mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv) { size_t msgcnt; size_t *msglist; size_t i, msgno; if (argc == 0) return 1; msgcnt = argc; msglist = calloc (msgcnt, sizeof(*msglist)); for (i = 0, msgno = 0; i < argc; i++) { char *p = NULL, *q; size_t start, end; size_t msg_first, n; long num; char *arg = msgset_preproc (mbox, argv[i]); if (!mu_isdigit (arg[0])) { int j; mh_msgset_t m; if (expand_user_seq (mbox, &m, arg)) { mu_error (_("message set %s does not exist"), arg); exit (1); } _expand (&msgcnt, &msglist, m.count); for (j = 0; j < m.count; j++) msglist[msgno++] = m.list[j]; mh_msgset_free (&m); } else { start = strtoul (arg, &p, 0); switch (*p) { case 0: n = mh_get_message (mbox, start, NULL); if (!n) { mu_error (_("message %lu does not exist"), (unsigned long) start); exit (1); } msglist[msgno++] = n; break; case '-': end = strtoul (p+1, &p, 0); if (*p) msgset_abort (argv[i]); if (end < start) { size_t t = start; start = end; end = t; } _expand (&msgcnt, &msglist, end - start); msg_first = msgno; for (; start <= end; start++) { n = mh_get_message (mbox, start, NULL); if (n) msglist[msgno++] = n; } if (msgno == msg_first) { mu_error (_("no messages in range %s"), argv[i]); exit (1); } break; case ':': num = strtoul (p+1, &q, 0); if (*q) msgset_abort (argv[i]); if (p[1] != '+' && p[1] != '-') { if (strncmp (argv[i], "last:", 5) == 0 || strncmp (argv[i], "prev:", 5) == 0) num = -num; } end = start + num; if (end < start) { size_t t = start; start = end + 1; end = t; } else end--; _expand (&msgcnt, &msglist, end - start); msg_first = msgno; for (; start <= end; start++) { n = mh_get_message (mbox, start, NULL); if (n) msglist[msgno++] = n; } if (msgno == msg_first) { mu_error (_("no messages in range %s"), argv[i]); exit (1); } break; default: msgset_abort (argv[i]); } } free (arg); } msgset->count = msgno; msgset->list = msglist; return 0; }
struct header_segm * compile_headline (const char *str) { struct header_segm *head = NULL, *tail = NULL; char *text; int align; size_t width; #define ALIGN_STRING (align == ALIGN_UNDEF ? ALIGN_LEFT : ALIGN_RIGHT) #define ALIGN_NUMBER (align == ALIGN_UNDEF ? ALIGN_RIGHT : ALIGN_LEFT) #define ATTACH(p) \ do \ { \ if (!head) \ head = p; \ else \ tail->next = p; \ tail = p; \ } \ while (0) while (*str) { struct header_segm *seg; size_t len; char *p = strchr (str, '%'); if (!p) len = strlen (str); else len = p - str; if (len) { text = xmalloc (len + 1); memcpy (text, str, len); text[len] = 0; seg = new_header_segment (ALIGN_LEFT, 0, text, hdr_text); ATTACH (seg); } if (!p) break; str = ++p; if (*str == '-') { str++; align = ALIGN_LEFT; } else if (*str == '+') { str++; align = ALIGN_RIGHT; } else align = ALIGN_UNDEF; if (mu_isdigit (*str)) width = strtoul (str, (char**)&str, 10); else width = 0; switch (*str++) { case '%': seg = new_header_segment (ALIGN_LEFT, 0, xstrdup ("%"), hdr_text); break; case 'a': /* Message attributes. */ seg = new_header_segment (ALIGN_STRING, width, NULL, hdr_attr); break; /* FIXME: %c The score of the message. */ case 'd': /* Message date */ seg = new_header_segment (ALIGN_STRING, width, NULL, hdr_date); break; /* FIXME: %e The indenting level in threaded mode. */ case 'f': /* Message sender */ seg = new_header_segment (ALIGN_STRING, width, NULL, hdr_from); break; /* FIXME: %i The message thread structure. */ case 'l': /* The number of lines of the message */ seg = new_header_segment (ALIGN_NUMBER, width, NULL, hdr_lines); break; case 'm': /* Message number */ seg = new_header_segment (ALIGN_NUMBER, width, NULL, hdr_number); break; case 'o': /* The number of octets (bytes) in the message */ seg = new_header_segment (ALIGN_NUMBER, width, NULL, hdr_size); break; case 's': /* Message subject (if any) */ seg = new_header_segment (ALIGN_STRING, width, NULL, hdr_subject); break; case 'S': /* Message subject (if any) in double quotes */ seg = new_header_segment (ALIGN_STRING, width, NULL, hdr_q_subject); break; /* FIXME: %t The position in threaded/sorted order. */ case '>': /* A `>' for the current message, otherwise ` ' */ seg = new_header_segment (ALIGN_STRING, width, xstrdup (">"), hdr_cur); break; case '<': /* A `<' for the current message, otherwise ` ' */ seg = new_header_segment (ALIGN_STRING, width, xstrdup ("<"), hdr_cur); break; default: mu_error (_("unknown escape: %%%c"), str[-1]); len = str - p; text = xmalloc (len); memcpy (text, p, len-1); text[len-1] = 0; seg = new_header_segment (ALIGN_STRING, width, text, hdr_text); } ATTACH (seg); } return head; #undef ALIGN_STRING #undef ALIGN_NUMBER #undef ATTACH }