[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
4.1 Framework | The Core Library. | |
4.2 Authentication Library | Auxiliary Library for Authenticating Users. | |
4.3 Mailutils to Scheme Interface | ||
4.4 Sieve Library | GNU Implementation of Sieve Mail Filtering. |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
4.1.1 Folder | ||
4.1.2 Mailbox | ||
4.1.3 Mailer | Protocol Used to Send Mail. | |
4.1.4 Message | ||
4.1.5 Envelope | ||
4.1.6 Headers | ||
4.1.7 Body | ||
4.1.8 Attribute | ||
4.1.9 Stream | ||
4.1.10 Iterator | ||
4.1.11 Authenticator | ||
4.1.12 Address | ||
4.1.13 Locker | ||
4.1.14 URL | Uniform Resource Locators. | |
4.1.15 Parse822 | Parsing RFC 822 headers. | |
4.1.16 Mailcap | Parsing RFC 1524 file. |
Wherever the mail is and whatever format it is stored in, it is operated upon using the same set of functions. To unified the C API, GNU Mailutils offers a heteroclite set of objects that work in aggregation to do operations on emails. Each object does a specific task and delegates non-related tasks to others. The object comes alive by specifying a URL parameter when created, it will indicate the storage format or protocol (POP3, IMAP4, MH, MAILDIR, etc ..).
folder_t url_t -/var/mail- +- .. ->+-----------------+ +-->+------------+ ( alain *-)-+ | | url_t *-|---+ | port | ---------- | | |-----------------| | hostname | ( jakob *-)-+--+ | auth_t *-|---+ | file | ---------- | |-----------------| | | ... | ( jeff *-)-+ | stream_t | | +------------+ ---------- | |-----------------| | ( shaleh*-)-+ | ..... | | auth_t ---------- |-----------------| +-->+------------+ +---|-* mailbox_t[] | | ticket_t | mailbox_t | +-----------------+ +------------+ +----------------+<-+ | locker_t *--|-------------+ |----------------| | | url_t | | locker_t |----------------| +-------->+---------+ | stream_t | | lock | |----------------| | unlock | | message_t[] *-|-------+ +---------+ +----------------+ | envelope_t | +-------->+-----------+ message_t | | | date | +----------------+<------+ | | from | | envelope_t *-|------------------+ | to | |----------------| header_t +-----------+ | header_t *-|------------>+--------------+ |----------------| | stream_t | | body_t *-|----+ +--------------+ +----------------+ | body_t +-->+--------------+ | stream_t | +--------------+ |
As an example, here is a simplified version of from
command. It
lists the `From' and `Subject' headers of every mail in a mailbox.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <mailutils/mailutils.h> int main (int argc, const char **argv) { char *from; char *subject; mailbox_t mbox; size_t msgno, total = 0; int status; /* Register the formats. */ mu_register_all_mbox_formats (); status = mailbox_create_default (&mbox, argv[1]); if (status != 0) { mu_error ("mailbox_create: %s", mu_strerror (status)); exit (EXIT_FAILURE); } status = mailbox_open (mbox, MU_STREAM_READ); if (status != 0) { mu_error ("mailbox_open: %s", mu_strerror (status)); exit (EXIT_FAILURE); } mailbox_messages_count (mbox, &total); for (msgno = 1; msgno <= total; msgno++) { message_t msg; header_t hdr; if ((status = mailbox_get_message (mbox, msgno, &msg)) != 0 || (status = message_get_header (msg, &hdr)) != 0) { mu_error ("Error message: %s", mu_strerror (status)); exit (EXIT_FAILURE); } if (header_aget_value (hdr, MU_HEADER_FROM, &from)) from = strdup ("(NO FROM)"); if (header_aget_value (hdr, MU_HEADER_SUBJECT, &subject)) subject = strdup ("(NO SUBJECT)"); printf ("%s\t%s\n", from, subject); free (from); free (subject); } status = mailbox_close (mbox); if (status != 0) { mu_error ("mailbox_close: %s", mu_strerror (status)); exit (EXIT_FAILURE); } mailbox_destroy (&mbox); return 0; } |
Here is a sample output produced by this program:
% ./sfrom pop://alain@localhost Passwd: xxxx Jim Meyering <meyering@foo.org> fetish(shellutils) beta François Pinard <pinard@bar.org> recode new alpha ... |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
|
folder_t url_t -/var/mail- +---//--->/-----------------\ +-->/-----------\ ( alain *-)-+ | | url_t *-|---+ | port | ---------- | | |-----------------+ | hostname | ( jakob *-)-+--+ | observer_t *-| | file | ---------- | |-----------------+ | ... | ( jeff *-)-+ | stream_t | \-----------/ ---------- | |-----------------| ( sean *-)-+ | auth_t | ---------- |-----------------| | mailbox_t(1) | |-----------------| | mailbox_t(2) | | ...... | | mailbox_t(n) | \-----------------/ |
Data structures:
struct list_response { int type; int separator; char *name; }; struct folder_list { struct list_response **element; size_t num; }; |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
|
mailbox_t
object is used to hold information and it is an opaque
data structure to the user. Functions are provided to retrieve information
from the data structure.
mailbox_t url_t -/var/mail- +---//--->/-----------------\ +-->/-----------\ ( alain ) | | url_t *-|---+ | port | ---------- | |-----------------+ | hostname | ( jakob *-)----+ | observer_t *-| | file | ---------- |-----------------+ | ... | ( jeff ) | stream_t | \-----------/ ---------- |-----------------| ( sean ) | locker_t | ---------- |-----------------| | message_t(1) | |-----------------| | message_t(2) | | ...... | | message_t(n) | \-----------------/ |
mailbox_create
allocates and initializes mbox.
The concrete mailbox type instantiate is based on the scheme of the url name.
The return value is 0
on success and a code number on error conditions:
MU_ERR_OUT_PTR_NULL
NULL
.
MU_ERR_NO_HANDLER
EINVAL
ENOMEM
mailbox_create()
based on the environment
variable MAIL
or the string formed by
_PATH_MAILDIR/user" or LOGNAME
if user is null,
stream_create()
for flag's description.
The return value is 0
on success and a code number on error conditions:
EAGAIN
EINPROGRESS
EBUSY
MU_ERROR_INVALID_PARAMETER
NULL
or flag is invalid.
ENOMEM
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
or msgno is invalid.
ENOMEM
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
or message is invalid.
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
ENOMEM
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
ENOMEM
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
ENOMEM
The return value is 0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
.
ENOMEM
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
|
If from is not NULL
, it must contain a single fully qualified
RFC2822 email address which will be used as the envelope from
address. This is the address to which delivery status notifications
are sent, so it never matters what it is set to until it really
matters. This is equivalent to Sendmail's `-f' flag.
The default for from is provided by the specific mailer.
If to is not NULL
, then the message will be sent to the list of
addresses that it specifies.
The default for to is to use the contents of the standard "To:", "Cc:", and "Bcc:" fields, this is equivalent to Sendmail's `-t' flag.
Some possible use cases the API must support are:
- original submission
1 - fill in header addresses
2 - mailer_send_message(mailer, msg, NULL, NULL)
- from will be filled in if missing,
- Bcc's will be deleted before delivery to a non-bcc address,
- message-id and date will be added, if missing,
- a To: or Apparently-To: will be added if non is present (for RFC compliance)
- MTA-style `.forward' (and Sieve-style redirect)
1 - get the envelope from of the message to be forwarded
2 - mailer_send_message(mailer, msg, from, to)
- MUA-style bounce
1 - add Resent-[To,From,...]
2 - mailer_send_message(mailer, msg, NULL, to)
- DSN "bounce"
1 - compose DSN
2 - mailer_deliver(mailer, msg, address_t("<>"), to)
Don't want mail loops, so the null but valid SMTP address of `<>' is the envelope From.
`/sbin/sendmail' isn't always Sendmail... Sometimes it's a Sendmail-compatible wrapper, so assume `/sbin/sendmail' understands only a recipient list, `-f' and `-oi', these seem to be pretty basic. Cross fingers.
Pipe to "/sbin/sendmail -oi [-f from] [to...]", supplying `-f' if there was a from, and supplying the recipient list from the to (if there is no recipient list, assume it will read the message contents for the recipients).
Caution: since the stdout
and stderr
of Sendmail
is closed, we have no way of ever giving feedback on failure. Also, what
should the return code be from mailer_send_message()
when Sendmail
returns `1'? `1' maps to EPERM
, which is less than
descriptive!
This mailer does not canonicalize the message. This must be done before sending the message, or it may be assumed that the MTA will do so.
It does blind out the Bcc: header before sending, though.
Caution: Mutt always puts the recipient addresses on the command line, even Bcc: ones, do we strip the Bcc: before forwarding with SMTP?
An address that has no domain is not and RFC822 email address. What do I do with them? Should the user of the API be responsible for determining what is mean by email to "John" means? Or should the be able to configure Sendmail to decide globally what this means. If so, we can pass the address to Sendmail, but we have to decide for SMTP! So, right now these addresses are rejected. This could be changed.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
|
The message_t
object is a convenient way to manipulate messages. It
encapsulates the envelope_t
, the header_t
and the body_t
.
mailbox_t ---------- message_t (message[1]) +------>+--------------------+ ---------- | | envelope_t | (message[2]) | |--------------------| ---------- | | header_t | (message[3])--------+ |--------------------| ---------- | body_t | (message[n]) |--------------------| ---------- | attribute_t | |--------------------| | stream_t | +--------------------+ |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
|
envelope_t
depends
on the mailbox type, this allows the function which actually gets
the sender to be set by the creator of an envelope_t
.
ctime()
format: Mon Jul 05 13:08:27 1999.
envelope_t
depends
on the mailbox type, this allows the function which actually gets
the date to be set by the creator of an envelope_t
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
|
So far we plan support for RFC822 and plan for RFC1522. With RFC1522 non-ASCII characters will be encoded.
NULL
,
it is parsed.
Some basic macros are already provided for RFC822.
MU_HEADER_UNIX_FROM
MU_HEADER_RETURN_PATH
MU_HEADER_RECEIVED
MU_HEADER_DATE
MU_HEADER_FROM
MU_HEADER_SENDER
MU_HEADER_RESENT_FROM
MU_HEADER_SUBJECT
MU_HEADER_SENDER
MU_HEADER_RESENT_SENDER
MU_HEADER_TO
MU_HEADER_RESENT_TO
MU_HEADER_CC
MU_HEADER_RESENT_CC
MU_HEADER_BCC
MU_HEADER_RESENT_BCC
MU_HEADER_REPLY_TO
MU_HEADER_RESENT_REPLY_TO
MU_HEADER_MESSAGE_ID
MU_HEADER_RESENT_MESSAGE_ID
MU_HEADER_IN_REPLY_TO
MU_HEADER_REFERENCE
MU_HEADER_REFERENCES
MU_HEADER_ENCRYPTED
MU_HEADER_PRECEDENCE
MU_HEADER_STATUS
MU_HEADER_CONTENT_LENGTH
MU_HEADER_CONTENT_LANGUAGE
MU_HEADER_CONTENT_TRANSFER_ENCODING
MU_HEADER_CONTENT_ID
MU_HEADER_CONTENT_TYPE
MU_HEADER_CONTENT_DESCRIPTION
MU_HEADER_CONTENT_DISPOSITION
MU_HEADER_CONTENT_MD5
MU_HEADER_MIME_VERSION
MU_HEADER_X_UIDL
MU_HEADER_X_UID
MU_HEADER_X_IMAPBASE
MU_HEADER_ENV_SENDER
MU_HEADER_ENV_DATE
MU_HEADER_FCC
MU_HEADER_DELIVERY_DATE
MU_HEADER_ENVELOPE_TO
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
|
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
|
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
|
These generic flags are interpreted as appropriate to the specific streams.
MU_STREAM_READ
MU_STREAM_WRITE
MU_STREAM_RDWR
MU_STREAM_APPEND
MU_STREAM_CREAT
MU_STREAM_NONBLOCK
MU_STREAM_NO_CHECK
MU_STREAM_SEEKABLE
MU_STREAM_NO_CLOSE
MU_STREAM_ALLOW_LINKS
MU_STREAM_NO_CLOSE
is specified, fclose()
will not be called on
stdio when the stream is closed.
MU_STREAM_STATE_OPEN
stream_open
.
MU_STREAM_STATE_READ
stream_read
or stream_readline
.
MU_STREAM_STATE_WRITE
stream_write
.
MU_STREAM_STATE_CLOSE
stream_close
.
An example using tcp_stream_create()
to make a simple web client:
/* This is an example program to illustrate the use of stream functions. It connects to a remote HTTP server and prints the contents of its index page */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <mailutils/mailutils.h> const char *wbuf = "GET / HTTP/1.0\r\n\r\n"; char rbuf[1024]; int main (void) { int ret, off = 0, fd; stream_t stream; size_t nb; fd_set fds; ret = tcp_stream_create (&stream, "www.gnu.org", 80, MU_STREAM_NONBLOCK); if (ret != 0) { mu_error ("tcp_stream_create: %s", mu_strerror (ret)); exit (EXIT_FAILURE); } connect_again: ret = stream_open (stream); if (ret != 0) { if (ret == EAGAIN) { ret = stream_get_fd (stream, &fd); if (ret != 0) { mu_error ("stream_get_fd: %s", mu_strerror (ret)); exit (EXIT_FAILURE); } FD_ZERO (&fds); FD_SET (fd, &fds); select (fd + 1, NULL, &fds, NULL, NULL); goto connect_again; } mu_error ("stream_open: %s", mu_strerror (ret)); exit (EXIT_FAILURE); } ret = stream_get_fd (stream, &fd); if (ret != 0) { mu_error ("stream_get_fd: %s", mu_strerror (ret)); exit (EXIT_FAILURE); } write_again: ret = stream_write (stream, wbuf + off, strlen (wbuf), 0, &nb); if (ret != 0) { if (ret == EAGAIN) { FD_ZERO (&fds); FD_SET (fd, &fds); select (fd + 1, NULL, &fds, NULL, NULL); off += nb; goto write_again; } mu_error ("stream_write: %s", mu_strerror (ret)); exit (EXIT_FAILURE); } if (nb != strlen (wbuf)) { mu_error ("stream_write: %s", "nb != wbuf length"); exit (EXIT_FAILURE); } do { ret = stream_read (stream, rbuf, sizeof (rbuf), 0, &nb); if (ret != 0) { if (ret == EAGAIN) { FD_ZERO (&fds); FD_SET (fd, &fds); select (fd + 1, &fds, NULL, NULL, NULL); } else { mu_error ("stream_read: %s", mu_strerror (ret)); exit (EXIT_FAILURE); } } write (2, rbuf, nb); } while (nb || ret == EAGAIN); ret = stream_close (stream); if (ret != 0) { mu_error ("stream_close: %s", mu_strerror (ret)); exit (EXIT_FAILURE); } stream_destroy (&stream, NULL); exit (EXIT_SUCCESS); } |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
|
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
|
There are many ways to authenticate to a server. To be flexible the
authentication process is provided by three objects authority_t
,
ticket_t
, and wicket_t
. The authority_t
can implement
different protocol like APOP, MD5-AUTH, One Time Passwd, etc. By default
if a mailbox does not understand or know how to authenticate it falls back
to user/passwd authentication. The ticket_t
is a way for
Mailboxes and Mailers provide a way to authenticate when the URL does not
contain enough information. The default action is to call the function
authority_authenticate()
which will get the user and passwd
if not set, this function can be overridden by a custom method.
A simple example of an authenticate function:
#include <stdio.h> #include <string.h> #include <mailutils/auth.h> int my_authenticate (auth_t auth, char **user, char **passwd) { char u[128] = ""; char p[128] = ""; /* prompt the user name */ printf ("User: "); fflush (stdout); fgets (u, sizeof (u), stdin); u[strlen (u) - 1] = '\0'; /* nuke the trailing NL */ /* prompt the passwd */ printf ("Passwd: "); fflush (stdout); echo_off (); fgets (p, sizeof(p), stdin); echo_on (); p[strlen (p) - 1] = '\0'; /* duplicate */ *user = strdup (u); *passwd = strdup (p); return 0; } |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
|
The Internet address format is defined in RFC 822. RFC 822 has been updated, and is now superceeded by RFC 2822, which makes some corrections and clarifications. References to RFC 822 here apply equally to RFC 2822.
The RFC 822 format is more flexible than many people realize, here is a quick summary of the syntax this parser implements, see RFC 822 for the details. `[]' pairs mean "optional", `/' means "one or the other", and double-quoted characters are literals.
addr-spec = local-part "@" domain mailbox = addr-spec ["(" display-name ")"] / [display-name] "<" [route] addr-spec ">" mailbox-list = mailbox ["," mailbox-list] group = display-name ":" [mailbox-list] ";" address = mailbox / group / unix-mbox address-list = address ["," address-list] |
Unix-mbox is a non-standard extension meant to deal with the common practice of using user names as addresses in mail utilities. It allows addresses such as "root" to be parsed correctly. These are not valid internet email addresses, they must be qualified before use.
Several address functions have a set of common arguments with consistent semantics, these are described here to avoid repetition.
Since an address-list may contain multiple addresses, they are accessed by a one-based index number, no. The index is one-based because pop, imap, and other message stores commonly use one-based counts to access messages and attributes of messages.
If len is greater than 0
it is the length of the buffer
buf, and as much of the component as possible will be copied
into the buffer. The buffer will be NULL
terminated.
The size of a particular component may be queried by providing 0
for the len of the buffer, in which case the buffer is optional.
In this case, if n is provided *n is assigned the length of
the component string.
address_t
object is used to hold information about a parsed
RFC822 address list, and is an opaque
data structure to the user. Functions are provided to retrieve information
about an address in the address list.
The return value is 0
on success and a code number on error conditions:
EINVAL
NULL
.
ENOMEM
ENOENT
-1
, then sv must be NULL
terminated in the fashion of argv,
otherwise len is the length of the array.
The return value is 0
on success and a code number on error conditions:
EINVAL
NULL
.
ENOMEM
ENOENT
Note that the entry may be valid, but be a group name. In this case success
is returned, but the length of the address is 0
.
The return value is 0
on success and a code number on error conditions:
EINVAL
NULL
.
ENOENT
The return value is 0
on success and a code number on error conditions:
EINVAL
NULL
.
ENOENT
0
length for a unix-mbox.
The return value is 0
on success and a code number on error conditions:
EINVAL
NULL
.
ENOENT
A group is a kind of a special case. It has a display-name, followed
by an optional mailbox-list. The display-name will be allocated an address
all it's own, but all the other elements (local-part, domain, etc.) will
be zero-length. So "a group: ;" is valid, will have a count of 1, but
address_get_email()
, and all the rest, will return zero-length output.
The return value is 0
on success and a code number on error conditions:
EINVAL
NULL
.
ENOENT
The return value is 0
on success and a code number on error conditions:
EINVAL
NULL
.
ENOENT
The return value is 0
on success and a code number on error conditions:
EINVAL
NULL
.
ENOENT
NULL
if there is no email address to return.
The return value is 0
on success and a code number on error conditions:
EINVAL
NULL
.
ENOENT
1
if this address is just the name of a group,
0
otherwise. This is faster than checking if the address has
a non-zero length personal, and a zero-length local_part and domain.
yes can be NULL
, though that doesn't serve much purpose other
than determining that no refers to an address.
Currently, there is no way to determine the end of the group.
The return value is 0
on success and a code number on error conditions:
EINVAL
NULL
.
ENOENT
The return value is 0
on success and a code number on error conditions:
EINVAL
NULL
.
ENOMEM
If addr is NULL
, the count is 0
. If count is
not NULL
, the count will be written to *count.
The return value is 0
.
#include <stdio.h> #include <string.h> #include <errno.h> #include <mailutils/address.h> #include <mailutils/errno.h> #include <mailutils/mutil.h> #define EPARSE ENOENT static int parse (const char *str) { size_t no = 0; size_t pcount = 0; int status; char buf[BUFSIZ]; address_t address = NULL; mu_set_user_email_domain ("localhost"); status = address_create (&address, str); address_get_count (address, &pcount); if (status) { printf ("%s=> error %s\n\n", str, mu_errname (status)); return 0; } else { printf ("%s=> pcount %lu\n", str, (unsigned long) pcount); } for (no = 1; no <= pcount; no++) { size_t got = 0; int isgroup; address_is_group (address, no, &isgroup); printf ("%lu ", (unsigned long) no); if (isgroup) { address_get_personal (address, no, buf, sizeof (buf), &got); printf ("group <%s>\n", buf); } else { address_get_email (address, no, buf, sizeof (buf), 0); printf ("email <%s>\n", buf); } address_get_personal (address, no, buf, sizeof (buf), &got); if (got && !isgroup) printf (" personal <%s>\n", buf); address_get_comments (address, no, buf, sizeof (buf), &got); if (got) printf (" comments <%s>\n", buf); address_get_local_part (address, no, buf, sizeof (buf), &got); if (got) { printf (" local-part <%s>", buf); address_get_domain (address, no, buf, sizeof (buf), &got); if (got) printf (" domain <%s>", buf); printf ("\n"); } address_get_route (address, no, buf, sizeof (buf), &got); if (got) printf (" route <%s>\n", buf); } address_destroy (&address); printf ("\n"); return 0; } static int parseinput (void) { char buf[BUFSIZ]; while (fgets (buf, sizeof (buf), stdin) != 0) { buf[strlen (buf) - 1] = 0; parse (buf); } return 0; } int main (int argc, const char *argv[]) { argc = 1; if (!argv[argc]) return parseinput (); for (; argv[argc]; argc++) { if (strcmp (argv[argc], "-") == 0) parseinput (); else parse (argv[argc]); } return 0; } |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
|
A flags of 0 means that the default will be used.
Time is measured in seconds.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A mailbox or a mailer can be described in a URL, the string will contain the
necessary information to initialize mailbox_t
, or mailer_t
properly.
pop://[<user>[;AUTH=<auth>]@]<host>[:<port>] or pop://[<user>[:<passwd>]@]<host>[:<port>] |
If :port is omitted the default value is 110. Different forms of authentication can be specified with ;AUTH=type. The special string ;AUTH=* indicates that the client will use a default scheme base on the capability of the server.
pop://obelix@gaulois.org pop://asterix;AUTH=*@france.com pop://falbala;AUTH=+APOP@france.com pop://obelix;AUTH=+APOP@village.gaulois.org:2000 pop://obelix:menhir@village.gaulois.org:2000 |
For more complete information see RFC 2368.
imap://[<user>[;AUTH=<type>]]@<host>[:port][/<mailbox>] or imap://[<user>[:<passwd>]]@<host>[:port][/<mailbox>] |
If :port is omitted the default value is 143. Different forms of authentication can be specified with ;AUTH=type. The special string ;AUTH=* indicates that the client will use a default scheme base on the capability of the server.
imap://obelix@imap.gaulois.org imap://asterix;AUTH=*@imap.france.com imap://asterix:potion@imap.france.com |
For more complete information see RFC 2192.
Local folder should be handle by this URL. It is preferable to let the mailbox recognize the type of mailbox and take the appropriate action.
file://path file://var/mail/user file://home/obelix/Mail |
For MMDF, MH local mailboxes URLs are provided, but it is preferable to use file://path and let the library figure out which one.
mmdf://path mh://path |
After setting a mailer, mailto: is used to tell the mailer where and to whom the message is for.
mailto://hostname |
Mailto can be used to generate short messages, for example to subscribe to mailing lists.
mailto://bug-mailutils@gnu.org?body=subscribe mailto://bug-mailutils@gnu.org?Subject=hello&body=subscribe |
For more complete information see RFC 2368.
Helper functions are provided to retrieve and set the URL fields.
The syntax, condensed from RFC 1738, and extended with the ;auth= of RFC 2384 (for POP) and RFC 2192 (for IMAP) is:
url = scheme ":" [ "//" [ user [ ( ":" password ) | ( ";auth=" auth ) ] "@" ] host [ ":" port ] [ ( "/" urlpath ) | ( "?" query ) ] ] |
This is a generalized URL syntax, and may not be exactly appropriate for any particular scheme.
strdup()
.
#include <stdio.h> #include <string.h> #include <mailutils/errno.h> #include <mailutils/url.h> int main () { char str[1024]; char buffer[1024]; long port = 0; int len = sizeof (buffer); url_t u = NULL; while (fgets (str, sizeof (str), stdin) != NULL) { int rc; str[strlen (str) - 1] = '\0'; /* chop newline */ if (strspn (str, " \t") == strlen (str)) continue; /* skip empty lines */ if ((rc = url_create (&u, str)) != 0) { fprintf (stderr, "url_create %s ERROR: [%d] %s", str, rc, mu_strerror (rc)); exit (1); } if ((rc = url_parse (u)) != 0) { printf ("%s => FAILED: [%d] %s\n", str, rc, mu_strerror (rc)); continue; } printf ("%s => SUCCESS\n", str); url_get_scheme (u, buffer, len, NULL); printf ("\tscheme <%s>\n", buffer); url_get_user (u, buffer, len, NULL); printf ("\tuser <%s>\n", buffer); url_get_passwd (u, buffer, len, NULL); printf ("\tpasswd <%s>\n", buffer); url_get_auth (u, buffer, len, NULL); printf ("\tauth <%s>\n", buffer); url_get_host (u, buffer, len, NULL); printf ("\thost <%s>\n", buffer); url_get_port (u, &port); printf ("\tport %ld\n", port); url_get_path (u, buffer, len, NULL); printf ("\tpath <%s>\n", buffer); url_get_query (u, buffer, len, NULL); printf ("\tquery <%s>\n", buffer); url_destroy (&u); } return 0; } |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
|
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
|
The standard RFC 1524 (A User Agent Configuration Mechanism) suggests a file format to be used to inform a mail user agent about facilities for handling mail in various format. The configuration file is known also as mailcap and it is tipically found in UNIX platforms, a example of `/etc/mailcap':
application/pgp; gpg < %s | metamail; needsterminal; \ test=test %{encapsulation}=entity ; copiousoutput |
A mailcap file consits of a set of mailcap entries per line, lines beginning with `#' are considered comments and ignored. Long mailcap entry may be continued on multiple lines if each line ends with a backslash character `\', the multiline will be considered a single mailcap entry. The overall format in BNF:
Mailcap-File = *mailcap-line Mailcap-Line = comment | mailcap-entry Comment = newline | "#" * char newline Newline = <newline as defined by OS convention> |
Each mailcap entry consists of a number of fields, separated by semi-colons. The first two filds are required and must occur in the secified order, the remaining fields are optional.
Mailcap-Entry = typefield ";" view-command ";" *[ ";" field ] |
mu_mailcap_t
and mu_mailcap_entry_t
objects
are used to hold information and it is an opaque data structure
to the user. Functions are provided to retrieve information
from the data structure.
mu_mailcap_t mu_mailcap_entry_t -/etc/mailcap- +--->/------------------------\ +-->/------------------\ ( alain ) | mu_mailcap_entry[0]*--|--+ | typefield | | mu_mailcap_entry[1] | | view-command | | ..... | | field[0] | | mu_mailcap_entry[n] | | ..... | \------------------------/ | field[n] | \------------------/ |
#include <stdio.h> #include <mailutils/mailcap.h> #include <mailutils/stream.h> #include <mailutils/error.h> int main (int argc, char **argv) { stream_t stream = NULL; int status = 0; char *file = argc == 1 ? "/etc/mailcap" : argv[1]; mu_mailcap_t mailcap = NULL; status = file_stream_create (&stream, file, MU_STREAM_READ); if (status) { mu_error ("cannot create file stream %s: %s", file, mu_strerror (status)); exit (1); } status = stream_open (stream); if (status) { mu_error ("cannot open file stream %s: %s", file, mu_strerror (status)); exit (1); } status = mu_mailcap_create (&mailcap, stream); if (status == 0) { int i; size_t count = 0; char buffer[256]; mu_mailcap_entries_count (mailcap, &count); for (i = 1; i <= count; i++) { int j; mu_mailcap_entry_t entry = NULL; int fields_count = 0; printf ("entry[%d]\n", i); mu_mailcap_get_entry (mailcap, i, &entry); /* typefield. */ mu_mailcap_entry_get_typefield (entry, buffer, sizeof (buffer), NULL); printf ("\ttypefield: %s\n", buffer); /* view-command. */ mu_mailcap_entry_get_viewcommand (entry, buffer, sizeof (buffer), NULL); printf ("\tview-command: %s\n", buffer); /* fields. */ mu_mailcap_entry_fields_count (entry, &fields_count); for (j = 1; j <= fields_count; j++) { mu_mailcap_entry_get_field (entry, j, buffer, sizeof (buffer), NULL); printf ("\tfields[%d]: %s\n", j, buffer); } printf ("\n"); } mu_mailcap_destroy (&mailcap); } return 0; } |
0
on success and a code number on error conditions:
MU_ERROR_INVALID_PARAMETER
NULL
or stream is invalid.
0
on success and a code number on error conditions:
EINVAL
NULL
.
0
on success and a code number on error conditions:
EINVAL
NULL
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The functions from `libmailbox' library get user information from the system user database. The library `libmuauth' extends this functionality, allowing `libmailbox' functions to obtain information about a user from several places, like SQL database, etc. The method used is described in detail in 3.2 Authorization and Authentication Principles. This chapter contains a very succinct description of the underlying library mechanism.
4.2.1 Data Types | ||
4.2.2 Initializing `libmuauth' | ||
4.2.3 Module Creation and Destruction | ||
4.2.4 Obtaining Authorization Information | ||
4.2.5 Existing Modules | ||
4.2.6 Using `libmuauth' in Your Programs |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This is a pointer to authentication or authorization data. It is defined as follows:
typedef int (*mu_auth_fp) (struct mu_auth_data **return_data, void *key, void *func_data, void *call_data); |
Its arguments are:
mu_auth_data
structure
with the user's information.
For authentication handlers this argument is always NULL
and
should be ignored.
For authorization handlers it is const char*
if the handler is called by
mu_get_auth_by_name()
and uid_t *
if it is called by
mu_get_auth_by_uid()
.
For authentication handlers it is always struct mu_auth_data*
representing the user's data obtained by a previous call to a
mu_get_auth_by_...
function.
The mu_auth_data
is used to return the information about the
user. It is similar to system struct passwd
, except that it
is more mailutils-specific. Its definition is:
struct mu_auth_data { /* These are from struct passwd */ char *name; /* user name */ char *passwd; /* user password */ uid_t uid; /* user id */ gid_t gid; /* group id */ char *gecos; /* real name */ char *dir; /* home directory */ char *shell; /* shell program */ /* */ char *mailbox; /* Path to the user's system mailbox */ int change_uid; /* Should the uid be changed? */ }; |
The mu_auth_module
structure contains full information about a
libmuauth module. It is declared as follows:
struct mu_auth_module { char *name; /* Module name */ struct argp *argp; /* Corresponding argp structure */ mu_auth_fp authenticate; /* Authentication function ... */ void *authenticate_data; /* ... and its specific data */ mu_auth_fp auth_by_name; /* Get user info by user name */ void *auth_by_name_data; /* ... and its specific data */ mu_auth_fp auth_by_uid; /* Get user info by user id */ void *auth_by_uid_data; /* ... and its specific data */ }; |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
mu_agrp_parse()
. If an error occurs, this function prints
diagnostic message and aborts the program.
mu_auth_init()
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Create a mu_auth_data
structure and initialize it with the given
values. Returns 0 on success and 1 otherwise.
mu_auth_data
structure allocated by a call to
mu_auth_data_alloc()
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
mu_auth_fp
pointers. Each of them
is dereferenced and executed until either the list is exhausted or any
of the functions returns non-zero, whichever occurs first. The
return_data and key arguments are passed as the first two
parameters to the function (see the definition of mu_auth_fp
,
notice the footnote), the call_data
is passed as its last
parameter.
The function returns 0 if none of the functions from list
succeeded, i.e. returned non-zero value. Otherwise it returns the
return code from the succeeded function.
getpwnam
call).
getpwuid
call).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
ENOSYS
.
mu_auth_nosupport
. Its
authentication handler computes the MD5 or DES hash over the supplied
password with the seed taken from passwd
member of its key
argument. Then it compares the obtained hash with the passwd
member itself and returns 1 if both strings match.
mu_auth_nosupport()
.
sql_host
, sql_port
, sql_user
, sql_passwd
and sql_db
. The SQL queries for retrieving user information
from global variables sql_getpwnam_query
and
sql_getpwuid_query
. The variable sql_getpass_query
keeps
the query used for retrieving user's password. See section 3.1.6 Auth, for
information on command line options used to set these variables.
mu_get_auth_by_name
method using virtual mail domains.
Neither mu_get_auth_by_uid
nor mu_authenticate
is
implemented. This module must be used together with generic
module.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
To link your program against `libmuauth', obtain loader arguments
by running mailutils-config
as follows:
mailutils-config --link auth |
See section 3.16 mailutils-config
-- Get the Information about the Mailutils Build, for more information about this utility.
Here is a sample Makefile fragment:
MU_LDFLAGS=`mailutils-config --link auth` MU_INCLUDES=`mailutils-config --include` myprog: myprog.c $(CC) -omyprog $(CFLAGS) $(MU_INCLUDES) myprog.c $(MU_LDFLAGS) |
If your program will be using only default modules provided by the
library, then it will suffice to call
MU_AUTH_REGISTER_ALL_MODULES()
somewhere near the start of
your program. As an example, consider the following code fragment
(it is taken from the imap4d
daemon):
int main (int argc, char **argv) { struct group *gr; int status = EXIT_SUCCESS; state = STATE_NONAUTH; /* Starting state in non-auth. */ MU_AUTH_REGISTER_ALL_MODULES (); mu_argp_parse (&argp, &argc, &argv, 0, imap4d_capa, NULL, &daemon_param); ... |
Otherwise, if your program will use it's own modules, first register
them with mu_auth_register_module
and then call
mu_auth_init()
, e.g.:
struct mu_auth_module radius_module = { ... }; struct mu_auth_module ext_module = { ... }; int main (int argc, char **argv) { mu_auth_register_module (&radius_module); mu_auth_register_module (&ext_module); mu_auth_init (); ... |
These two approaches may be combined, allowing you to use both your modules and the ones provided by Mailutils. Consider the example below:
int main (int argc, char **argv) { mu_auth_register_module (&radius_module); mu_auth_register_module (&ext_module); MU_AUTH_REGISTER_ALL_MODULES (); ... } |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The library `libmu_scm' provides an interface between Mailutils and Guile, allowing to access the Mailutils functionality from a Scheme program. For more information about Guile, refer to section `Overview' in The Guile Reference Manual. For information about Scheme programming language, See section `Top' in Revised(4) Report on the Algorithmic Language Scheme.
Functions Provided by `libmu_scm' | ||
---|---|---|
4.3.1 Address Functions | ||
4.3.2 Mailbox Functions | ||
4.3.3 Message Functions | ||
4.3.4 MIME Functions | ||
4.3.5 Logging Functions | ||
Using `libmu_scm' | ||
4.3.6 Direct Linking | ||
4.3.7 Dynamic Linking |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
#t
. Otherwise new header is created and appended.
(cons HEADER VALUE)
.
Optional parameter REPLACE specifies whether the new header
values should replace the headers already present in the message.
#t
and undeleted
if it is #f
.
#f
, the attribute is unset.
#f
, the attribute is unset.
#t
then the returned port will allow access to any
part of the message (including headers). If it is #f
then the port
accesses only the message body (the default).
mu-mailer
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
#t
if MIME is a multipart object.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
syslogd
.
mu-openlog
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
If you plan to link your program directly to `libguile', it will probably make sense to link `libmu_scm' directly as well. The arguments to the program loader may be obtained by running
mailutils-config --link guile |
See section 3.16 mailutils-config
-- Get the Information about the Mailutils Build, for more information about this utility.
Here is a sample Makefile fragment:
MU_LDFLAGS=`mailutils-config --link guile` MU_INCLUDES=`mailutils-config --include` myprog: myprog.c $(CC) -omyprog $(CFLAGS) $(MU_INCLUDES) myprog.c $(MU_LDFLAGS) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Dynamic linking is the preferred method of using `libmu_scm'. It uses Guile "use-modules" mechanism. An interface module `mailutils.scm' is provided in order to facilitate using this method. This module is installed in the package data directory (by default it is `prefix/share/mailutils'). A sample use of this module is:
(set! %load-path (list "/usr/local/share/mailutils")) (use-modules (mailutils)) # Now you may use mailutils functions: (let ((mb (mu-mailbox-open "/var/spool/mail/gray" "r"))) ... |
Note, that you should explicitly modify the %load-path
before calling use-modules
, otherwise Guile will not be able to
find `mailutils.scm'.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Libsieve
is GNU implementation of the mail filtering
language Sieve. The library is built around a Sieve Machine -- an
abstract computer constructed specially to handle mail filtering tasks.
This computer has two registers: program counter and numeric accumulator;
a runtime stack of unlimited depth and the code segment. A set of
functions is provided for creating and destroying instances of Sieve
Machine, manipulating its internal data, compiling and executing a
sieve program.
The following is a typical scenario of using libsieve
:
sieve_compile
function is called to translate
the Sieve source into an equivalent program executable by the
Machine
keep
are marked with the delete
flag. Thus, running mailbox_expunge
upon the mailbox finishes
the job, leaving in the mailbox only those messages that were preserved
by the filter.
The following sections describe in detail the functions from the Sieve Library.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
sieve_machine_t
keeps all information necessary
for compiling and executing the script.
It is created by sieve_machine_create()
and destroyed by
sieve_machine_destroy()
. The functions for manipulating this data
type are described in 4.4.2 Manipulating the Sieve Machine.
SVT_VOID
SVT_NUMBER
SVT_STRING
SVT_STRING_LIST
list_t
. Each item in this list represents a character string.
SVT_TAG
sieve_runtime_tag_t
below.
SVT_IDENT
SVT_VALUE_LIST
list_t
. Each item in this list is of sieve_value_t
.
SVT_POINTER
sieve_value_t
keeps an instance of sieve data. It is defined
as follows:
typedef struct { sieve_data_type type; /* Type of the data */ union { char *string; /* String value or identifier */ size_t number; /* Numeric value */ list_t list; /* List value */ sieve_runtime_tag_t *tag; /* Tag value */ void *ptr; /* Pointer value */ } v; } sieve_value_t; |
Depending on the value of type
member, following members of the
union v
keep the actual value:
SVT_VOID
SVT_NUMBER
number
member.
SVT_STRING
string
member.
SVT_STRING_LIST
SVT_VALUE_LIST
list
member
SVT_TAG
tag
member.
SVT_IDENT
string
member points to the identifier name.
SVT_POINTER
ptr
member.
typedef struct { char *name; /* Tag name */ sieve_data_type argtype; /* Type of tag argument. */ } sieve_tag_def_t; |
The name
member points to the tag's name without leading
colon. The argtype
is set to SVT_VOID
if the tag does
not take argument, or to the type of the argument otherwise.
struct sieve_runtime_tag { char *tag; /* Tag name */ sieve_value_t *arg; /* Tag argument (if any) */ }; |
The arg
member is NULL
if the tag does not take an argument.
This is a pointer to function handler for a sieve action or test. It is defined as follows:
typedef int (*sieve_handler_t) (sieve_machine_t mach, list_t args, list_t tags); |
The arguments to the handler have the following meaning:
typedef int (*sieve_printf_t) (void *data, const char *fmt, va_list ap); |
sieve_machine_init()
.
typedef int (*sieve_parse_error_t) (void *data, const char *filename, int lineno, const char *fmt, va_list ap); |
It is used to declare error handlers for parsing errors. The application-specific data are passed in the data argument. Arguments filename and line indicate the location of the error in the source text, while fmt and ap give verbose description of the error.
typedef void (*sieve_action_log_t) (void *data, const char *script, size_t msgno, message_t msg, const char *action, const char *fmt, va_list ap); |
sieve_message()
, this argument is zero.
typedef int (*sieve_relcmp_t) (int, int); typedef int (*sieve_relcmpn_t) (size_t, size_t); |
typedef int (*sieve_comparator_t) (const char *, const char *); |
A pointer to the comparator handler function. The function compares
its two operands and returns 1 if they are equal, and 0 otherwise.
Notice, that the sense of the return value is inverted
in comparison with most standard libc functions like stcmp()
, etc.
typedef int (*sieve_retrieve_t) (void *item, void *data, int idx, char **pval); |
A pointer to generic retriever function. See description of
sieve_vlist_compare()
for details of its usage.
typedef void (*sieve_destructor_t) (void *data); |
A pointer to destructor function. The function frees any resources
associated with data
. See the description of
sieve_machine_add_destructor()
for more information.
typedef int (*sieve_tag_checker_t) (const char *name, list_t tags, list_t args) |
A pointer to tag checker function. The purpose of the function is to perform compilation-time consistency test on tags. Its arguments are:
sieve_runtime_tag_t
representing tags.
sieve_value_t
representing required arguments to
name.
The function is allowed to make any changes in tags and args. It should return 0 if the syntax is correct and non-zero otherwise. It is responsible for issuing the diagnostics in the latter case. [FIXME: describe how to do that]
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This subsection describes functions used to create an instance of the sieve machine, read or alter its internal fields and destroy it.
The sieve_machine_init()
function creates an instance of a sieve
machine. A pointer to the instance itself is returned in the argument
mach. The user-specific data to be associated with the new machine
are passed in data argument. The function returns 0 on success,
non-zero error code otherwise,
This function destroys the instance of sieve machine pointed to by
mach parameter. After execution of sieve_machine_destroy()
pmach contains NULL
. The destructors registered with
sieve_machine_add_destructor()
are executed in LIFO
order.
This function registers a destructor function dest. The purpose
of the destructor is to free any resources associated with the item
ptr. The destructor function takes a single argument -- a
pointer to the data being destroyed. All registered destructors are
called in reverse order upon execution of
sieve_machine_destroy()
. Here's a short example of the use
of this function:
static void free_regex (void *data) { regfree ((regex_t*)data); } int match_part_checker (const char *name, list_t tags, list_t args) { regex_t *regex; /* Initialise the regex: */ regex = sieve_malloc (mach, sizeof (*regex)); /* Make sure it will be freed when necessary */ sieve_machine_add_destructor (sieve_machine, free_regex, regex); . . . } |
sieve_machine_init()
.
sieve_message
, this function returns 1.
int _sieve_default_error_printer (void *unused, const char *fmt, va_list ap) { return mu_verror (fmt, ap); } |
int _sieve_default_parse_error (void *unused, const char *filename, int lineno, const char *fmt, va_list ap) { if (filename) fprintf (stderr, "%s:%d: ", filename, lineno); vfprintf (stderr, fmt, ap); fprintf (stderr, "\n"); return 0; } |
NULL
which means no
debugging information will be displayed.
mu_debug_t
object to be
used with mailutils library, the level argument specifies the
debugging level for the sieve library itself. It is a bitwise or of
the following values:
MU_SIEVE_DEBUG_TRACE
MU_SIEVE_DEBUG_INSTR
MU_SIEVE_DEBUG_DISAS
MU_SIEVE_DRY_RUN
NULL
, which means that the executed actions are not logged.
"sendmail:"
.
reject
and
redirect
actions.
sieve_is_dry_run()
returns 1 if the machine is in dry
run state, i.e. it will only log the actions that would have been
executed without actually executing them. The dry run state is set
by calling sieve_set_debug_level()
if its last argument has
the MU_SIEVE_DRY_RUN
bit set.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
NULL
if no such test exists.
NULL
if no such action exists.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The following functions act as their libc counterparts. The allocated
memory is associated with the mach argument and is automatically
freed upon the call to sieve_machine_destroy (mach)
.
NULL
, the call is equivalent to
sieve_malloc(mach, size)
; if size is equal to
zero, the call is equivalent to sieve_mfree(ptr)
. Unless
ptr is NULL
, it must have been returned by an earlier
call to sieve_malloc()
or sieve_mrealloc()
.
sieve_mfree()
frees the memory space pointed to by ptr and
detaches it from the destructor list of mach. The ptr must
have been returned by a previous call to sieve_malloc()
or
sieve_mrealloc()
. Otherwise, or if sieve_mfree(ptr)
has already been called before, undefined behaviour occurs.
If ptr is NULL
, no operation is performed.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This section contains an example of how to write external loadable commands for GNU libsieve.
/* This is an example on how to write extension tests for GNU sieve. It provides test "numaddr". Syntax: numaddr [":over" / ":under"] <header-names: string-list> <limit: number> The "numaddr" test counts Internet addresses in structured headers that contain addresses. It returns true if the total number of addresses satisfies the requested relation: If the argument is ":over" and the number of addresses is greater than the number provided, the test is true; otherwise, it is false. If the argument is ":under" and the number of addresses is less than the number provided, the test is true; otherwise, it is false. If the argument is empty, ":over" is assumed. */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include <stdlib.h> #include <mailutils/libsieve.h> struct val_ctr { /* Data passed to the counter function */ header_t hdr; /* Headers of the current message */ size_t limit; /* Limit for the number of addresses */ size_t count; /* Number of addresses counted so far */ }; /* Count addresses in a single header value. Input: ITEM is the name of the header to scan. DATA is a pointer to the val_ctr structure Return value: non-zero if the limit on the number of addresses has been reached. */ static int _count_items (void *item, void *data) { char *name = item; struct val_ctr *vp = data; char *val; address_t addr; size_t count = 0; if (header_aget_value (vp->hdr, name, &val)) return 0; if (address_create (&addr, val) == 0) { address_get_count (addr, &count); address_destroy (&addr); vp->count += count; } free (val); return vp->count >= vp->limit; } /* Handler for the numaddr test */ static int numaddr_test (sieve_machine_t mach, list_t args, list_t tags) { sieve_value_t *h, *v; struct val_ctr vc; int rc; if (sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE) { sieve_locus_t locus; sieve_get_locus (mach, &locus); sieve_debug (mach, "%s:%lu: NUMADDR\n", locus.source_file, (unsigned long) locus.source_line); } /* Retrieve required arguments: */ /* First argument: list of header names */ h = sieve_value_get (args, 0); if (!h) { sieve_error (mach, "numaddr: can't get argument 1"); sieve_abort (mach); } /* Second argument: Limit on the number of addresses */ v = sieve_value_get (args, 1); if (!v) { sieve_error (mach, "numaddr: can't get argument 2"); sieve_abort (mach); } /* Fill in the val_ctr structure */ message_get_header (sieve_get_message (mach), &vc.hdr); vc.count = 0; vc.limit = v->v.number; /* Count the addresses */ rc = sieve_vlist_do (h, _count_items, &vc); /* Here rc >= 1 iff the counted number of addresses is greater or equal to vc.limit. If `:under' tag was given we reverse the return value */ if (sieve_tag_lookup (tags, "under", NULL)) rc = !rc; return rc; } /* Syntactic definitions for the numaddr test */ /* Required arguments: */ static sieve_data_type numaddr_req_args[] = { SVT_STRING_LIST, SVT_NUMBER, SVT_VOID }; /* Tagged arguments: */ static sieve_tag_def_t numaddr_tags[] = { { "over", SVT_VOID }, { "under", SVT_VOID }, { NULL } }; static sieve_tag_group_t numaddr_tag_groups[] = { { numaddr_tags, NULL }, { NULL } }; /* Initialization function. It is the only function exported from this module. */ int SIEVE_EXPORT(numaddr,init) (sieve_machine_t mach) { return sieve_register_test (mach, "numaddr", numaddr_test, numaddr_req_args, numaddr_tag_groups, 1); } |
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |