Commit 55e0fbee 55e0fbee9e680aa2572284e0ed265d28b3400558 by Sergey Poznyakoff

* Makefile.am, configure.ac: Add maidag.

* frm/common.c, imap4d/sync.c, libsieve/runtime.c,
mh/scan.c: Update declaration of observable actions  .
* imap4d/select.c, imap4d/status.c, mh/anno.c, mh/forw.c,
mh/repl.c: Use mu_mailbox_sync instead of
mu_mailbox_save_attributes.
* include/mailutils/mailbox.h (mu_mailbox_sync): New function.
(mu_mailbox_save_attributes): Deprecated.
* include/mailutils/message.h (mu_message_get_qid)
(mu_message_set_qid): New functions.
* include/mailutils/observer.h (MU_EVT_MESSAGE_APPEND): New event.
(mu_observer_set_action_data): New function. Registers
action-specific data.
(mu_observable_notify): Get call-specific data as the third
argument.
* include/mailutils/types.hin (mu_message_qid_t): New data type.
* libproto/imap/folder.c, libproto/imap/mbox.c,
libproto/include/amd.h, libproto/maildir/mbox.c,
libproto/mailer/sendmail.c, libproto/mailer/smtp.c,
libproto/mbox/mboxscan.c, libproto/mh/mbox.c,
libproto/nntp/mbox.c, libproto/pop/mbox.c, mailbox/folder.c,
mailbox/mailer.c : Update calls to mu_observable_notify.
* libproto/include/mailbox0.h (struct _mu_mailbox): Rename
_save_attributes to _sync.
* mailbox/amd.c: Likewise
(_quick_get_message): New member.
(MAILBOX_NOTIFY): Remove.
* libproto/include/message0.h (struct _mu_message): New member
_get_qid.
* libproto/include/observer0.h (struct _mu_observer): New member
_action_data.
* libproto/mbox/mbox.c: Implement mbox_message_qid. Update calls
to mu_observable_notify.
(mbox_append_message): Report MU_EVT_MESSAGE_APPEND
* mailbox/observer.c (mu_observer_destroy): Call _destroy with
_action_data as its third argument.
(mu_observer_action, mu_observable_notify): Takes third argument
(call data)
(mu_observer_set_action, mu_observer_set_destroy): Update signature.
(mu_observer_set_action_data): New function.

* libproto/mbox/mbox0.h, mail.local/main.c: Minor change.

* mail.local/Makefile.am (mail_local_LDADD): Add MU_LIB_MAILER

* mailbox/file_stream.c (_file_open): Fix handling of
MU_STREAM_APPEND. Remove assertion.

* mailbox/mailbox.c (mu_mailbox_quick_get_message): New function
(mu_mailbox_sync): New function
(mu_mailbox_get_size): Implement brute-force approach in case the
mailbox does not provide a method.

* mailbox/message.c (mu_message_get_qid, mu_message_set_qid): New
function.

* maildag/: New directory. A general-purpose mail delivery agent.
* maildag/deliver.c: New file.
* maildag/lmtp.c: New file.
* maildag/maidag.c: New file.
* maildag/maidag.h: New file.
* maildag/mailtmp.c: New file.
* maildag/mailquota.c: New file.
* maildag/script.c: New file.
* maildag/util.c: New file.
* maildag/Makefile.am: New file.
* maildag/.cvsignore: New file.
1 parent 60ae1cd2
2007-11-10 Sergey Poznyakoff <gray@gnu.org.ua>
* Makefile.am, configure.ac: Add maidag.
* frm/common.c, imap4d/sync.c, libsieve/runtime.c,
mh/scan.c: Update declaration of observable actions.
* imap4d/select.c, imap4d/status.c, mh/anno.c, mh/forw.c,
mh/repl.c: Use mu_mailbox_sync instead of
mu_mailbox_save_attributes.
* include/mailutils/mailbox.h (mu_mailbox_sync): New function
(mu_mailbox_save_attributes): Deprecated.
* include/mailutils/message.h (mu_message_get_qid)
(mu_message_set_qid): New functions.
* include/mailutils/observer.h (MU_EVT_MESSAGE_APPEND): New event.
(mu_observer_set_action_data): New function. Registers
action-specific data.
(mu_observable_notify): Get call-specific data as the third
argument.
* include/mailutils/types.hin (mu_message_qid_t): New data type.
* libproto/imap/folder.c, libproto/imap/mbox.c,
libproto/include/amd.h, libproto/maildir/mbox.c,
libproto/mailer/sendmail.c, libproto/mailer/smtp.c,
libproto/mbox/mboxscan.c, libproto/mh/mbox.c,
libproto/nntp/mbox.c, libproto/pop/mbox.c, mailbox/folder.c,
mailbox/mailer.c : Update calls to mu_observable_notify.
* libproto/include/mailbox0.h (struct _mu_mailbox): Rename
_save_attributes to _sync.
* mailbox/amd.c: Likewise.
(_quick_get_message): New member.
(MAILBOX_NOTIFY): Remove.
* libproto/include/message0.h (struct _mu_message): New member
_get_qid.
* libproto/include/observer0.h (struct _mu_observer): New member
_action_data.
* libproto/mbox/mbox.c: Implement mbox_message_qid. Update calls
to mu_observable_notify.
(mbox_append_message): Report MU_EVT_MESSAGE_APPEND.
* mailbox/observer.c (mu_observer_destroy): Call _destroy with
_action_data as its third argument.
(mu_observer_action, mu_observable_notify): Takes third argument
(call data)
(mu_observer_set_action, mu_observer_set_destroy): Update signature.
(mu_observer_set_action_data): New function.
* libproto/mbox/mbox0.h, mail.local/main.c: Minor change
* mail.local/Makefile.am (mail_local_LDADD): Add MU_LIB_MAILER
* mailbox/file_stream.c (_file_open): Fix handling of
MU_STREAM_APPEND. Remove assertion.
* mailbox/mailbox.c (mu_mailbox_quick_get_message): New function
(mu_mailbox_sync): New function.
(mu_mailbox_get_size): Implement brute-force approach in case the
mailbox does not provide a method.
* mailbox/message.c (mu_message_get_qid, mu_message_set_qid): New
function.
* maildag/: New directory. A general-purpose mail delivery agent.
* maildag/deliver.c: New file.
* maildag/lmtp.c: New file.
* maildag/maidag.c: New file.
* maildag/maidag.h: New file.
* maildag/mailtmp.c: New file.
* maildag/mailquota.c: New file.
* maildag/script.c: New file.
* maildag/util.c: New file.
* maildag/Makefile.am: New file.
* maildag/.cvsignore: New file.
2007-11-08 Sergey Poznyakoff <gray@gnu.org.ua>
* mailbox/cfg_lexer.c: Do not use obstack.
......
......@@ -39,6 +39,7 @@ SUBDIRS = \
frm\
pop3d\
imap4d\
maidag\
mail\
sieve\
scripts\
......
......@@ -1169,6 +1169,7 @@ AC_CONFIG_FILES([Makefile
libproto/include/Makefile
libsieve/Makefile
libsieve/extensions/Makefile
maidag/Makefile
mail/Makefile
mail/testsuite/Makefile
mail.local/Makefile
......
......@@ -421,7 +421,7 @@ static size_t msg_index; /* Index (1-based) of the current
/* Observable action is being called on discovery of each message. */
/* FIXME: The format of the display is poorly done, please correct. */
static int
action (mu_observer_t o, size_t type)
action (mu_observer_t o, size_t type, void *data, void *action_data)
{
int status;
......
......@@ -49,7 +49,7 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags)
currently selected mailbox without doing an expunge. */
if (mbox)
{
mu_mailbox_save_attributes (mbox);
mu_mailbox_sync (mbox);
mu_mailbox_close (mbox);
mu_mailbox_destroy (&mbox);
/* Destroy the old uid table. */
......
......@@ -77,7 +77,7 @@ imap4d_status (struct imap4d_command *command, char *arg)
/* We may be opening the current mailbox, so make sure the attributes are
preserved */
mu_mailbox_save_attributes (mbox);
mu_mailbox_sync (mbox);
status = mu_mailbox_create_default (&smbox, mailbox_name);
if (status == 0)
......
......@@ -276,7 +276,7 @@ imap4d_sync_flags (size_t msgno)
static int mailbox_corrupt;
static int
action (mu_observer_t observer, size_t type)
action (mu_observer_t observer, size_t type, void *data, void *action_data)
{
switch (type)
{
......
......@@ -52,13 +52,18 @@ extern int mu_mailbox_uidvalidity (mu_mailbox_t, unsigned long *);
extern int mu_mailbox_uidnext (mu_mailbox_t, size_t *);
/* Messages. */
extern int mu_mailbox_get_message (mu_mailbox_t, size_t msgno, mu_message_t *);
extern int mu_mailbox_get_message (mu_mailbox_t, size_t msgno,
mu_message_t *);
extern int mu_mailbox_quick_get_message(mu_mailbox_t, mu_message_qid_t,
mu_message_t *);
extern int mu_mailbox_append_message (mu_mailbox_t, mu_message_t);
extern int mu_mailbox_messages_count (mu_mailbox_t, size_t *);
extern int mu_mailbox_messages_recent (mu_mailbox_t, size_t *);
extern int mu_mailbox_message_unseen (mu_mailbox_t, size_t *);
extern int mu_mailbox_expunge (mu_mailbox_t);
extern int mu_mailbox_save_attributes (mu_mailbox_t);
extern int mu_mailbox_sync (mu_mailbox_t);
extern int mu_mailbox_save_attributes (mu_mailbox_t)
__attribute__ ((deprecated));
/* Update and scanning. */
extern int mu_mailbox_get_size (mu_mailbox_t, mu_off_t *size);
......
......@@ -29,89 +29,102 @@ extern "C" {
/* A message is considered to be a container for:
mu_header_t, mu_body_t, and its mu_attribute_t. */
extern int mu_message_create (mu_message_t *, void *owner);
extern void mu_message_destroy (mu_message_t *, void *owner);
extern int mu_message_create (mu_message_t *, void *owner);
extern void mu_message_destroy (mu_message_t *, void *owner);
extern int mu_message_create_copy (mu_message_t *to, mu_message_t from);
extern int mu_message_create_copy (mu_message_t *to, mu_message_t from);
extern void * mu_message_get_owner (mu_message_t);
extern int mu_message_is_modified (mu_message_t);
extern int mu_message_clear_modified (mu_message_t);
extern int mu_message_get_mailbox (mu_message_t, mu_mailbox_t *);
extern int mu_message_set_mailbox (mu_message_t, mu_mailbox_t, void *);
extern void * mu_message_get_owner (mu_message_t);
extern int mu_message_is_modified (mu_message_t);
extern int mu_message_clear_modified (mu_message_t);
extern int mu_message_get_mailbox (mu_message_t, mu_mailbox_t *);
extern int mu_message_set_mailbox (mu_message_t, mu_mailbox_t, void *);
extern int mu_message_ref (mu_message_t);
#define mu_message_unref(msg) mu_message_destroy (&msg, NULL)
extern int mu_message_ref (mu_message_t);
#define mu_message_unref(msg) mu_message_destroy (&msg, NULL)
extern int mu_message_get_envelope (mu_message_t, mu_envelope_t *);
extern int mu_message_set_envelope (mu_message_t, mu_envelope_t, void *);
extern int mu_message_get_envelope (mu_message_t, mu_envelope_t *);
extern int mu_message_set_envelope (mu_message_t, mu_envelope_t, void *);
extern int mu_message_get_header (mu_message_t, mu_header_t *);
extern int mu_message_set_header (mu_message_t, mu_header_t, void *);
extern int mu_message_get_header (mu_message_t, mu_header_t *);
extern int mu_message_set_header (mu_message_t, mu_header_t, void *);
extern int mu_message_get_body (mu_message_t, mu_body_t *);
extern int mu_message_set_body (mu_message_t, mu_body_t, void *);
extern int mu_message_get_body (mu_message_t, mu_body_t *);
extern int mu_message_set_body (mu_message_t, mu_body_t, void *);
extern int mu_message_get_stream (mu_message_t, mu_stream_t *);
extern int mu_message_set_stream (mu_message_t, mu_stream_t, void *);
extern int mu_message_get_stream (mu_message_t, mu_stream_t *);
extern int mu_message_set_stream (mu_message_t, mu_stream_t, void *);
extern int mu_message_get_attribute (mu_message_t, mu_attribute_t *);
extern int mu_message_set_attribute (mu_message_t, mu_attribute_t, void *);
extern int mu_message_get_attribute (mu_message_t, mu_attribute_t *);
extern int mu_message_set_attribute (mu_message_t, mu_attribute_t, void *);
extern int mu_message_get_observable (mu_message_t, mu_observable_t *);
extern int mu_message_get_observable (mu_message_t, mu_observable_t *);
extern int mu_message_is_multipart (mu_message_t, int *);
extern int mu_message_is_multipart (mu_message_t, int *);
extern int mu_message_set_is_multipart (mu_message_t,
int (*_is_multipart) (mu_message_t, int *),
void *);
int (*_is_multipart) (mu_message_t,
int *),
void *);
extern int mu_message_size (mu_message_t, size_t *);
extern int mu_message_set_size (mu_message_t,
int (*_size) (mu_message_t, size_t *),
void *owner);
extern int mu_message_size (mu_message_t, size_t *);
extern int mu_message_set_size (mu_message_t,
int (*_size) (mu_message_t, size_t *),
void *owner);
extern int mu_message_lines (mu_message_t, size_t *);
extern int mu_message_set_lines (mu_message_t,
int (*_lines) (mu_message_t, size_t *),
void *owner);
extern int mu_message_lines (mu_message_t, size_t *);
extern int mu_message_set_lines (mu_message_t,
int (*_lines) (mu_message_t, size_t *),
void *owner);
extern int mu_message_get_num_parts (mu_message_t, size_t *nparts);
extern int mu_message_get_num_parts (mu_message_t, size_t *nparts);
extern int mu_message_set_get_num_parts (mu_message_t,
int (*_get_num_parts) (mu_message_t,
size_t *),
void *owner);
extern int mu_message_get_part (mu_message_t, size_t, mu_message_t *);
extern int mu_message_set_get_part (mu_message_t,
int (*_get_part) (mu_message_t, size_t,
mu_message_t *),
void *owner);
extern int mu_message_get_uidl (mu_message_t, char *, size_t, size_t *);
extern int mu_message_set_uidl (mu_message_t,
int (*_get_uidl) (mu_message_t, char *,
size_t, size_t *),
void *owner);
extern int mu_message_get_uid (mu_message_t, size_t *);
extern int mu_message_set_uid (mu_message_t,
int (*_get_uid) (mu_message_t, size_t *),
void *owner);
int (*_get_num_parts) (mu_message_t,
size_t *),
void *owner);
extern int mu_message_get_part (mu_message_t, size_t, mu_message_t *);
extern int mu_message_set_get_part (mu_message_t,
int (*_get_part) (mu_message_t, size_t,
mu_message_t *),
void *owner);
extern int mu_message_get_uidl (mu_message_t, char *, size_t, size_t *);
extern int mu_message_set_uidl (mu_message_t,
int (*_get_uidl) (mu_message_t,
char *,
size_t, size_t *),
void *owner);
extern int mu_message_get_uid (mu_message_t, size_t *);
extern int mu_message_set_uid (mu_message_t,
int (*_get_uid) (mu_message_t,
size_t *),
void *owner);
extern int mu_message_get_qid (mu_message_t, mu_message_qid_t *);
extern int mu_message_set_qid (mu_message_t,
int (*_get_qid) (mu_message_t,
mu_message_qid_t *),
void *owner);
/* misc functions */
extern int mu_message_create_attachment (const char *content_type,
const char *encoding,
const char *filename,
mu_message_t *newmsg);
const char *encoding,
const char *filename,
mu_message_t *newmsg);
extern int mu_message_save_attachment (mu_message_t msg,
const char *filename, void **data);
extern int mu_message_encapsulate (mu_message_t msg, mu_message_t *newmsg, void **data);
extern int mu_message_unencapsulate (mu_message_t msg, mu_message_t *newmsg, void **data);
extern int mu_message_get_attachment_name (mu_message_t, char *name, size_t bufsz, size_t* sz);
const char *filename, void **data);
extern int mu_message_encapsulate (mu_message_t msg, mu_message_t *newmsg,
void **data);
extern int mu_message_unencapsulate (mu_message_t msg, mu_message_t *newmsg,
void **data);
extern int mu_message_get_attachment_name (mu_message_t, char *name,
size_t bufsz, size_t* sz);
extern int mu_message_aget_attachment_name (mu_message_t, char **name);
extern int mu_message_save_to_mailbox (mu_message_t msg, mu_ticket_t ticket,
mu_debug_t debug, const char *toname);
mu_debug_t debug, const char *toname);
extern int mu_stream_to_message (mu_stream_t instream, mu_message_t *pmsg);
......
......@@ -24,36 +24,42 @@
#ifdef __cplusplus
extern "C" {
#endif
#define MU_EVT_MAILBOX_DESTROY 0x001
#define MU_EVT_FOLDER_DESTROY 0x002
#define MU_EVT_MAILER_DESTROY 0x004
#define MU_EVT_MESSAGE_DESTROY 0x008
#define MU_EVT_MESSAGE_ADD 0x010
#define MU_EVT_MAILBOX_PROGRESS 0x020
#define MU_EVT_AUTHORITY_FAILED 0x030
#define MU_EVT_MAILBOX_CORRUPT 0x040
#define MU_EVT_MAILER_MESSAGE_SENT 0x080
/* Call data type: */
#define MU_EVT_MAILBOX_DESTROY 0x001 /* mu_mailbox_t */
#define MU_EVT_FOLDER_DESTROY 0x002 /* mu_folder_t */
#define MU_EVT_MAILER_DESTROY 0x004 /* mu_mailer_t */
#define MU_EVT_MESSAGE_DESTROY 0x008 /* mu_message_t */
#define MU_EVT_MESSAGE_ADD 0x010 /* size_t *: FIXME */
#define MU_EVT_MAILBOX_PROGRESS 0x020 /* NULL: FIXME? */
#define MU_EVT_AUTHORITY_FAILED 0x030 /* NULL */
#define MU_EVT_MAILBOX_CORRUPT 0x040 /* mu_mailbox_t */
#define MU_EVT_MAILER_MESSAGE_SENT 0x080 /* mu_message_t */
#define MU_EVT_MESSAGE_APPEND 0x100 /* mu_message_qid_t: FIXME */
#define MU_OBSERVER_NO_CHECK 1
extern int mu_observer_create (mu_observer_t *, void *owner);
extern void mu_observer_destroy (mu_observer_t *, void *owner);
extern void * mu_observer_get_owner (mu_observer_t);
extern int mu_observer_action (mu_observer_t, size_t type);
extern void * mu_observer_get_owner(mu_observer_t);
extern int mu_observer_action (mu_observer_t, size_t type, void *data);
extern int mu_observer_set_action (mu_observer_t,
int (*_action) (mu_observer_t, size_t),
void *owner);
int (*_action) (mu_observer_t,
size_t, void *, void *),
void *owner);
extern int mu_observer_set_action_data (mu_observer_t, void *data,
void *owner);
extern int mu_observer_set_destroy (mu_observer_t,
int (*_destroy) (mu_observer_t), void *owner);
int (*_destroy) (mu_observer_t, void *),
void *owner);
extern int mu_observer_set_flags (mu_observer_t, int flags);
extern int mu_observable_create (mu_observable_t *, void *owner);
extern void mu_observable_destroy (mu_observable_t *, void *owner);
extern void * mu_observable_get_owner (mu_observable_t);
extern int mu_observable_attach (mu_observable_t, size_t type, mu_observer_t observer);
extern int mu_observable_attach (mu_observable_t, size_t type,
mu_observer_t observer);
extern int mu_observable_detach (mu_observable_t, mu_observer_t observer);
extern int mu_observable_notify (mu_observable_t, int type);
extern int mu_observable_notify (mu_observable_t, int type, void *data);
#ifdef __cplusplus
}
......
/* GNU Mailutils -- a suite of utilities for electronic mail
/* GNU Mailutils -- a suite of utilities for electronic mail -*- c -*-
Copyright (C) 1999, 2000, 2001, 2005, 2007 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
......@@ -99,6 +99,7 @@ typedef struct _mu_url *mu_url_t;
typedef struct _mu_wicket *mu_wicket_t;
typedef void *mu_transport_t;
typedef struct _mu_assoc *mu_assoc_t;
typedef char *mu_message_qid_t;
#define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001
#define MU_FOLDER_ATTRIBUTE_FILE 0x002
......
......@@ -2527,7 +2527,8 @@ imap_parse (f_imap_t f_imap)
{
mu_observable_t observable = NULL;
mu_folder_get_observable (f_imap->folder, &observable);
mu_observable_notify (observable, MU_EVT_AUTHORITY_FAILED);
mu_observable_notify (observable, MU_EVT_AUTHORITY_FAILED,
NULL);
status = MU_ERR_AUTH_FAILURE;
}
else if (strncasecmp (remainder, "LIST", 4) == 0)
......
......@@ -798,12 +798,13 @@ imap_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount, int notif)
for (i = msgno; i <= count; i++)
{
if (mu_observable_notify (mailbox->observable, MU_EVT_MESSAGE_ADD) != 0)
size_t tmp = i;
if (mu_observable_notify (mailbox->observable, MU_EVT_MESSAGE_ADD,
&tmp) != 0)
break;
if (((i + 1) % 100) == 0)
{
mu_observable_notify (mailbox->observable, MU_EVT_MAILBOX_PROGRESS);
}
if ((i + 1) % 100 == 0)
mu_observable_notify (mailbox->observable, MU_EVT_MAILBOX_PROGRESS,
NULL);
}
return 0;
}
......
......@@ -20,13 +20,17 @@
#define MAX_OPEN_STREAMS 16
/* Notifications ADD_MESG. */
#define DISPATCH_ADD_MSG(mbox,mhd) \
#define DISPATCH_ADD_MSG(mbox,mhd,n) \
do \
{ \
int bailing = 0; \
mu_monitor_unlock (mbox->monitor); \
if (mbox->observable) \
bailing = mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD); \
{ \
size_t tmp = (n); \
bailing = mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD, \
&tmp); \
} \
if (bailing != 0) \
{ \
if (pcount) \
......
......@@ -55,7 +55,7 @@ struct _mu_mailbox
int (*_open) (mu_mailbox_t, int);
int (*_close) (mu_mailbox_t);
/* messages */
int (*_get_message) (mu_mailbox_t, size_t, mu_message_t *);
int (*_append_message) (mu_mailbox_t, mu_message_t);
......@@ -63,7 +63,7 @@ struct _mu_mailbox
int (*_messages_recent) (mu_mailbox_t, size_t *);
int (*_message_unseen) (mu_mailbox_t, size_t *);
int (*_expunge) (mu_mailbox_t);
int (*_save_attributes) (mu_mailbox_t);
int (*_sync) (mu_mailbox_t);
int (*_uidvalidity) (mu_mailbox_t, unsigned long *);
int (*_uidnext) (mu_mailbox_t, size_t *);
int (*_get_property) (mu_mailbox_t, mu_property_t *);
......@@ -73,11 +73,9 @@ struct _mu_mailbox
int (*_get_size) (mu_mailbox_t, mu_off_t *);
int (*_quick_get_message) (mu_mailbox_t, mu_message_qid_t, mu_message_t *);
};
#define MAILBOX_NOTIFY(mbox, type) \
if (mbox->observer) observer_notify (mbox->observer, type)
/* Moro(?)ic kluge. */
#define MAILBOX_DEBUG0(mbox, type, format) \
if (mbox->debug) mu_debug_print (mbox->debug, type, format)
......
......@@ -60,6 +60,7 @@ struct _mu_message
int (*_get_uidl) (mu_message_t, char *, size_t, size_t *);
int (*_get_uid) (mu_message_t, size_t *);
int (*_get_qid) (mu_message_t, mu_message_qid_t *);
int (*_get_num_parts) (mu_message_t, size_t *);
int (*_get_part) (mu_message_t, size_t, mu_message_t *);
int (*_is_multipart) (mu_message_t, int *);
......
......@@ -33,8 +33,9 @@ struct _mu_observer
{
int flags;
void *owner;
int (*_action) (mu_observer_t, size_t);
int (*_destroy) (mu_observer_t);
int (*_action) (mu_observer_t, size_t, void *, void *);
void *_action_data;
int (*_destroy) (mu_observer_t, void *data);
};
struct _mu_observable
......
......@@ -623,7 +623,7 @@ maildir_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, size_t *pcount,
size_t i;
for (i = 0; i < amd->msg_count; i++)
{
DISPATCH_ADD_MSG(mailbox, amd);
DISPATCH_ADD_MSG(mailbox, amd, i);
}
}
......
......@@ -443,7 +443,8 @@ sendmail_send_message (mu_mailer_t mailer, mu_message_t msg, mu_address_t from,
status = MU_ERR_PROCESS_UNKNOWN_FAILURE;
/* Shouldn't this notification only happen on success? */
mu_observable_notify (mailer->observable, MU_EVT_MAILER_MESSAGE_SENT);
mu_observable_notify (mailer->observable, MU_EVT_MAILER_MESSAGE_SENT,
msg);
}
default:
break;
......
......@@ -870,7 +870,8 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t argmsg, mu_address_t argfrom
if (smtp->rcpt_index <= smtp->rcpt_bcc_count)
goto ENV_FROM;
mu_observable_notify (mailer->observable, MU_EVT_MAILER_MESSAGE_SENT);
mu_observable_notify (mailer->observable, MU_EVT_MAILER_MESSAGE_SENT,
argmsg);
default:
break;
......
......@@ -24,6 +24,7 @@
#endif
#include <mbox0.h>
#include <mu_umaxtostr.h>
#define ATTRIBUTE_IS_DELETED(flag) (flag & MU_ATTRIBUTE_DELETED)
#define ATTRIBUTE_IS_EQUAL(flag1, flag2) (flag1 == flag2)
......@@ -41,7 +42,7 @@ static int mbox_messages_recent (mu_mailbox_t, size_t *);
static int mbox_message_unseen (mu_mailbox_t, size_t *);
static int mbox_expunge0 (mu_mailbox_t, int);
static int mbox_expunge (mu_mailbox_t);
static int mbox_save_attributes (mu_mailbox_t);
static int mbox_sync (mu_mailbox_t);
static int mbox_uidvalidity (mu_mailbox_t, unsigned long *);
static int mbox_uidnext (mu_mailbox_t, size_t *);
static int mbox_scan (mu_mailbox_t, size_t, size_t *);
......@@ -49,24 +50,35 @@ static int mbox_is_updated (mu_mailbox_t);
static int mbox_get_size (mu_mailbox_t, mu_off_t *);
/* private stuff */
static int mbox_append_message0 (mu_mailbox_t, mu_message_t, mu_off_t *, int, int);
static int mbox_append_message0 (mu_mailbox_t, mu_message_t,
mu_off_t *, int, int);
static int mbox_message_uid (mu_message_t, size_t *);
static int mbox_header_fill (mu_header_t, char *, size_t, mu_off_t, size_t *);
static int mbox_get_body_transport (mu_stream_t, mu_transport_t *, mu_transport_t *);
static int mbox_get_transport2 (mbox_message_t, mu_transport_t *, mu_transport_t *);
static int mbox_message_qid (mu_message_t, mu_message_qid_t *);
static int mbox_header_fill (mu_header_t, char *, size_t,
mu_off_t, size_t *);
static int mbox_get_body_transport (mu_stream_t, mu_transport_t *,
mu_transport_t *);
static int mbox_get_transport2 (mbox_message_t, mu_transport_t *,
mu_transport_t *);
static int mbox_get_attr_flags (mu_attribute_t, int *);
static int mbox_set_attr_flags (mu_attribute_t, int);
static int mbox_unset_attr_flags (mu_attribute_t, int);
static int mbox_body_read (mu_stream_t, char *, size_t, mu_off_t, size_t *);
static int mbox_body_readline (mu_stream_t, char *, size_t, mu_off_t, size_t *);
static int mbox_body_read (mu_stream_t, char *, size_t,
mu_off_t, size_t *);
static int mbox_body_readline (mu_stream_t, char *, size_t,
mu_off_t, size_t *);
static int mbox_readstream (mbox_message_t, char *, size_t,
mu_off_t, size_t *, int, mu_off_t, mu_off_t);
mu_off_t, size_t *, int, mu_off_t,
mu_off_t);
static int mbox_stream_size (mu_stream_t stream, mu_off_t *psize);
static int mbox_body_size (mu_body_t, size_t *);
static int mbox_body_lines (mu_body_t, size_t *);
static int mbox_envelope_sender (mu_envelope_t, char *, size_t, size_t *);
static int mbox_envelope_date (mu_envelope_t, char *, size_t, size_t *);
static int mbox_envelope_sender (mu_envelope_t, char *, size_t,
size_t *);
static int mbox_envelope_date (mu_envelope_t, char *, size_t,
size_t *);
static int mbox_tmpfile (mu_mailbox_t, char **pbox);
/* Allocate the mbox_data_t struct(concrete mailbox), but don't do any
......@@ -121,7 +133,7 @@ _mailbox_mbox_init (mu_mailbox_t mailbox)
mailbox->_messages_recent = mbox_messages_recent;
mailbox->_message_unseen = mbox_message_unseen;
mailbox->_expunge = mbox_expunge;
mailbox->_save_attributes = mbox_save_attributes;
mailbox->_sync = mbox_sync;
mailbox->_uidvalidity = mbox_uidvalidity;
mailbox->_uidnext = mbox_uidnext;
......@@ -297,11 +309,14 @@ mbox_scan (mu_mailbox_t mailbox, size_t msgno, size_t *pcount)
msgno--; /* The fist message is number "1", decrement for the C array. */
for (i = msgno; i < mud->messages_count; i++)
{
if (mu_observable_notify (mailbox->observable, MU_EVT_MESSAGE_ADD) != 0)
size_t tmp = i;
if (mu_observable_notify (mailbox->observable, MU_EVT_MESSAGE_ADD,
&tmp) != 0)
break;
if (((i +1) % 50) == 0)
{
mu_observable_notify (mailbox->observable, MU_EVT_MAILBOX_PROGRESS);
mu_observable_notify (mailbox->observable, MU_EVT_MAILBOX_PROGRESS,
NULL);
}
}
*pcount = mud->messages_count;
......@@ -328,7 +343,8 @@ mbox_is_updated (mu_mailbox_t mailbox)
return 1;
if (size < mud->size)
{
mu_observable_notify (mailbox->observable, MU_EVT_MAILBOX_CORRUPT);
mu_observable_notify (mailbox->observable, MU_EVT_MAILBOX_CORRUPT,
mailbox);
/* And be verbose. ? */
mu_error (_("* BAD : Mailbox corrupted, shrank in size"));
/* FIXME: should I crash. */
......@@ -552,7 +568,7 @@ mbox_expunge0 (mu_mailbox_t mailbox, int remove_deleted)
if ((mum->attr_flags & MU_ATTRIBUTE_MODIFIED) ||
(mum->message && mu_message_is_modified (mum->message)))
{
/* The message was not instanciated, probably the dirty flag was
/* The message was not instantiated, probably the dirty flag was
set by mbox_scan(), create one here. */
if (mum->message == 0)
{
......@@ -764,7 +780,7 @@ mbox_expunge (mu_mailbox_t mailbox)
}
static int
mbox_save_attributes (mu_mailbox_t mailbox)
mbox_sync (mu_mailbox_t mailbox)
{
return mbox_expunge0 (mailbox, 0);
}
......@@ -779,6 +795,18 @@ mbox_message_uid (mu_message_t msg, size_t *puid)
}
static int
mbox_message_qid (mu_message_t msg, mu_message_qid_t *pqid)
{
mbox_message_t mum = mu_message_get_owner (msg);
char buf[UINTMAX_STRSIZE_BOUND];
const char *p = umaxtostr (mum->header_from, buf);
*pqid = strdup (p);
if (*pqid == NULL)
return ENOMEM;
return 0;
}
static int
mbox_get_body_transport (mu_stream_t is, mu_transport_t *pin,
mu_transport_t *pout)
{
......@@ -1150,7 +1178,8 @@ mbox_get_message (mu_mailbox_t mailbox, size_t msgno, mu_message_t *pmsg)
/* Set the UID. */
mu_message_set_uid (msg, mbox_message_uid, mum);
mu_message_set_qid (msg, mbox_message_qid, mum);
/* Attach the message to the mailbox mbox data. */
mum->message = msg;
mu_message_set_mailbox (msg, mailbox, mum);
......@@ -1164,7 +1193,8 @@ mbox_append_message (mu_mailbox_t mailbox, mu_message_t msg)
{
int status = 0;
mbox_data_t mud = mailbox->data;
mu_off_t size;
if (msg == NULL || mud == NULL)
return EINVAL;
......@@ -1184,7 +1214,6 @@ mbox_append_message (mu_mailbox_t mailbox, mu_message_t msg)
default:
{
mu_off_t size;
/* Move to the end of the file, not necesary if _APPEND mode. */
if ((status = mu_stream_size (mailbox->stream, &size)) != 0
|| (status = mbox_append_message0 (mailbox, msg,
......@@ -1197,6 +1226,14 @@ mbox_append_message (mu_mailbox_t mailbox, mu_message_t msg)
}
}
mu_locker_unlock (mailbox->locker);
if (mailbox->observable)
{
char buf[UINTMAX_STRSIZE_BOUND];
mu_observable_notify (mailbox->observable, MU_EVT_MESSAGE_APPEND,
umaxtostr (size, buf));
}
return 0;
}
......@@ -1294,10 +1331,10 @@ write_array (mu_stream_t stream, mu_off_t *poff, int count, const char **array)
}
/* FIXME: We need to escape body line that begins with "From ", this
will required to read the body by line instead of by chuncks hurting
perfomance big time when expunging. But should not this be the
responsability of the client ? */
/* FIXME: Do we need to escape body line that begins with "From "? This
will require reading the body line by line instead of by chunks,
considerably hurting perfomance when expunging. But should not this
be the responsibility of the client ? */
static int
mbox_append_message0 (mu_mailbox_t mailbox, mu_message_t msg, mu_off_t *psize,
int is_expunging, int first)
......@@ -1423,7 +1460,7 @@ mbox_append_message0 (mu_mailbox_t mailbox, mu_message_t msg, mu_off_t *psize,
do
{
status = mu_stream_readline (is, buffer, sizeof (buffer), mud->off,
&nread);
&nread);
if (status != 0)
{
if (status != EAGAIN)
......@@ -1453,7 +1490,7 @@ mbox_append_message0 (mu_mailbox_t mailbox, mu_message_t msg, mu_off_t *psize,
continue;
status = mu_stream_write (mailbox->stream, buffer, nread,
*psize, &n);
*psize, &n);
if (status)
break;
*psize += n;
......@@ -1537,7 +1574,7 @@ mbox_append_message0 (mu_mailbox_t mailbox, mu_message_t msg, mu_off_t *psize,
do
{
status = mu_stream_read (is, buffer, sizeof (buffer), mud->off,
&nread);
&nread);
if (status != 0)
{
if (status != EAGAIN)
......
......@@ -122,7 +122,8 @@ struct _mbox_data
mu_mailbox_t mailbox; /* Back pointer. */
};
int mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif);
int mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount,
int do_notif);
#ifdef WITH_PTHREAD
void mbox_cleanup (void *arg);
#endif
......
......@@ -412,7 +412,11 @@ do \
int bailing = 0; \
mu_monitor_unlock (mbox->monitor); \
if (mbox->observable) \
bailing = mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD); \
{ \
size_t tmp = mud->messages_count + 1; \
bailing = mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD, \
&tmp); \
} \
if (bailing != 0) \
{ \
if (pcount) \
......@@ -437,7 +441,7 @@ do \
mud->messages_count--; \
if (mbox->observable) \
bailing = mu_observable_notify (mbox->observable, \
MU_EVT_MAILBOX_PROGRESS); \
MU_EVT_MAILBOX_PROGRESS, NULL); \
if (bailing != 0) \
{ \
if (pcount) \
......@@ -517,7 +521,7 @@ mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
return status;
}
if((status = mu_locker_lock (mailbox->locker)))
if ((status = mu_locker_lock (mailbox->locker)))
{
mu_monitor_unlock (mailbox->monitor);
return status;
......@@ -540,7 +544,7 @@ mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
stream = mailbox->stream;
while ((status = mu_stream_readline (mailbox->stream, buf, sizeof (buf),
total, &n)) == 0 && n != 0)
total, &n)) == 0 && n != 0)
{
int nl;
total += n;
......@@ -577,7 +581,7 @@ mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
min_uid = mum->uid;
if (do_notif)
DISPATCH_ADD_MSG(mailbox, mud);
DISPATCH_ADD_MSG (mailbox, mud);
}
/* Allocate_msgs will initialize mum. */
......@@ -640,7 +644,7 @@ mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
min_uid = mum->uid;
if (do_notif)
DISPATCH_ADD_MSG(mailbox, mud);
DISPATCH_ADD_MSG (mailbox, mud);
}
if (pcount)
*pcount = mud->messages_count;
......
......@@ -211,7 +211,7 @@ mh_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, size_t *pcount,
for (i = 0; i < amd->msg_count; i++)
{
DISPATCH_ADD_MSG(mailbox, amd);
DISPATCH_ADD_MSG (mailbox, amd, i);
}
}
......
......@@ -446,12 +446,12 @@ nntp_mailbox_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount)
return 0;
for (i = msgno; i <= count; i++)
{
if (mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD) != 0)
size_t tmp = i;
if (mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD,
&tmp) != 0)
break;
if (((i +1) % 10) == 0)
{
mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_PROGRESS);
}
if ((i +1) % 10 == 0)
mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_PROGRESS, NULL);
}
return 0;
}
......
......@@ -528,7 +528,7 @@ _pop_user (mu_authority_t auth)
mu_observable_t observable = NULL;
mu_mailbox_get_observable (mbox, &observable);
CLEAR_STATE (mpd);
mu_observable_notify (observable, MU_EVT_AUTHORITY_FAILED);
mu_observable_notify (observable, MU_EVT_AUTHORITY_FAILED, NULL);
CHECK_ERROR_CLOSE (mbox, mpd, EACCES);
}
status = pop_get_passwd (auth);
......@@ -566,7 +566,7 @@ _pop_user (mu_authority_t auth)
mu_observable_t observable = NULL;
mu_mailbox_get_observable (mbox, &observable);
CLEAR_STATE (mpd);
mu_observable_notify (observable, MU_EVT_AUTHORITY_FAILED);
mu_observable_notify (observable, MU_EVT_AUTHORITY_FAILED, NULL);
return MU_ERR_AUTH_FAILURE;
}
mpd->state = POP_AUTH_DONE;
......@@ -638,7 +638,7 @@ _pop_apop (mu_authority_t auth)
mu_observable_t observable = NULL;
mu_mailbox_get_observable (mbox, &observable);
CLEAR_STATE (mpd);
mu_observable_notify (observable, MU_EVT_AUTHORITY_FAILED);
mu_observable_notify (observable, MU_EVT_AUTHORITY_FAILED, NULL);
CHECK_ERROR_CLOSE (mbox, mpd, EACCES);
}
mpd->state = POP_AUTH_DONE;
......@@ -1255,11 +1255,14 @@ pop_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount)
return 0;
for (i = msgno; i <= count; i++)
{
if (mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD) != 0)
size_t tmp = i;
if (mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD,
&tmp) != 0)
break;
if (((i +1) % 10) == 0)
{
mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_PROGRESS);
mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_PROGRESS,
NULL);
}
}
return 0;
......
......@@ -305,7 +305,7 @@ mu_sieve_disass (mu_sieve_machine_t mach)
}
static int
_sieve_action (mu_observer_t obs, size_t type)
_sieve_action (mu_observer_t obs, size_t type, void *data, void *action_data)
{
mu_sieve_machine_t mach;
......
.deps
.gdbinit
.libs
Makefile
Makefile.in
maidag
# Copyright (C) 2007 Free Software Foundation, Inc.
#
# GNU Mailutils is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
INCLUDES = -I${top_srcdir} @MU_COMMON_INCLUDES@ @GUILE_INCLUDES@
sbin_PROGRAMS=maidag
maidag_SOURCES=\
deliver.c\
lmtp.c\
maidag.c\
maidag.h\
mailtmp.c\
mailquota.c\
script.c\
util.c
maidag_LDADD = \
@LIBMU_SCM@ @GUILE_LIBS@\
@LIBMU_SCM_DEPS@\
../lib/libmuaux.la \
${MU_LIB_SIEVE}\
${MU_LIB_MBOX}\
${MU_LIB_IMAP}\
${MU_LIB_POP}\
${MU_LIB_NNTP}\
${MU_LIB_MH}\
${MU_LIB_MAILDIR}\
${MU_LIB_AUTH}\
${MU_LIB_MAILER}\
@MU_AUTHLIBS@\
${MU_LIB_MAILUTILS} \
@MU_COMMON_LIBRARIES@
install-exec-hook:
for i in $(sbin_PROGRAMS); do\
chown root:mail $(DESTDIR)$(sbindir)/$$i;\
chmod 4755 $(DESTDIR)$(sbindir)/$$i;\
done
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2005,
2007 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA */
#include "maidag.h"
void
make_tmp (const char *from, mu_mailbox_t *mbox)
{
struct mail_tmp *mtmp;
char *buf = NULL;
size_t n = 0;
int rc;
if (mail_tmp_begin (&mtmp, from))
exit (EX_TEMPFAIL);
while (getline (&buf, &n, stdin) > 0)
if ((rc = mail_tmp_add_line (mtmp, buf, strlen (buf))))
break;
free (buf);
if (rc == 0)
rc = mail_tmp_finish (mtmp, mbox);
mail_tmp_destroy (&mtmp);
if (rc)
exit (EX_TEMPFAIL);
}
int
mda (mu_mailbox_t mbx, char *username)
{
deliver (mbx, username, NULL);
if (multiple_delivery)
exit_code = EX_OK;
return exit_code;
}
int
maidag_stdio_delivery (int argc, char **argv)
{
mu_mailbox_t mbox;
make_tmp (sender_address, &mbox);
if (multiple_delivery)
multiple_delivery = argc > 1;
#ifdef WITH_GUILE
if (progfile_pattern)
{
struct mda_data mda_data;
memset (&mda_data, 0, sizeof mda_data);
mda_data.mbox = mbox;
mda_data.argv = argv;
mda_data.progfile_pattern = progfile_pattern;
return prog_mda (&mda_data);
}
#endif
for (; *argv; argv++)
mda (mbox, *argv);
return exit_code;
}
static int biff_fd = -1;
static struct sockaddr_in biff_in;
static char *biff_user_name;
static int
notify_action (mu_observer_t obs, size_t type, void *data, void *action_data)
{
if (type == MU_EVT_MESSAGE_APPEND)
{
mu_message_qid_t qid = data;
mu_mailbox_t mbox = mu_observer_get_owner (obs);
mu_url_t url;
char *buf;
mu_mailbox_get_url (mbox, &url);
asprintf (&buf, "%s@%s:%s", biff_user_name,
qid, mu_url_to_string (url));
if (buf)
{
sendto (biff_fd, buf, strlen (buf), 0,
(struct sockaddr *)&biff_in, sizeof biff_in);
free (buf);
}
}
return 0;
}
static void
attach_notify (mu_mailbox_t mbox)
{
struct servent *sp;
mu_observer_t observer;
mu_observable_t observable;
if (biff_fd == -1)
{
if ((sp = getservbyname ("biff", "udp")) == NULL)
{
biff_fd = -2;
return;
}
biff_in.sin_family = AF_INET;
biff_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
biff_in.sin_port = sp->s_port;
biff_fd = socket (PF_INET, SOCK_DGRAM, 0);
if (biff_fd < 0)
{
biff_fd = -2;
return;
}
}
if (biff_fd)
{
mu_observer_create (&observer, mbox);
mu_observer_set_action (observer, notify_action, mbox);
mu_mailbox_get_observable (mbox, &observable);
mu_observable_attach (observable, MU_EVT_MESSAGE_APPEND, observer);
}
}
int
deliver (mu_mailbox_t imbx, char *name, char **errp)
{
mu_mailbox_t mbox;
mu_message_t msg;
char *path;
mu_url_t url = NULL;
mu_locker_t lock;
struct mu_auth_data *auth;
int status;
int failed = 0;
auth = mu_get_auth_by_name (name);
if (!auth)
{
mailer_err (_("%s: no such user"), name);
if (errp)
asprintf (errp, "%s: no such user", name);
exit_code = EX_UNAVAILABLE;
return EX_UNAVAILABLE;
}
if (current_uid)
auth->change_uid = 0;
if (!sieve_test (auth, imbx))
{
exit_code = EX_OK;
mu_auth_data_free (auth);
return 0;
}
if ((status = mu_mailbox_get_message (imbx, 1, &msg)) != 0)
{
mailer_err (_("Cannot get message from the temporary mailbox: %s"),
mu_strerror (status));
mu_auth_data_free (auth);
return EX_TEMPFAIL;
}
if ((status = mu_mailbox_create (&mbox, auth->mailbox)) != 0)
{
mailer_err (_("Cannot open mailbox %s: %s"),
auth->mailbox, mu_strerror (status));
mu_auth_data_free (auth);
return EX_TEMPFAIL;
}
mu_mailbox_get_url (mbox, &url);
path = (char*) mu_url_to_string (url);
biff_user_name = name;
/* Actually open the mailbox. Switch to the user's euid to make
sure the maildrop file will have right privileges, in case it
will be created */
if (switch_user_id (auth, 1))
return EX_TEMPFAIL;
status = mu_mailbox_open (mbox, MU_STREAM_APPEND|MU_STREAM_CREAT);
if (switch_user_id (auth, 0))
return EX_TEMPFAIL;
if (status != 0)
{
mailer_err (_("Cannot open mailbox %s: %s"), path, mu_strerror (status));
mu_mailbox_destroy (&mbox);
return EX_TEMPFAIL;
}
attach_notify (mbox);
/* FIXME: This is superfluous, as mu_mailbox_append_message takes care
of locking anyway. But I leave it here for the time being. */
mu_mailbox_get_locker (mbox, &lock);
if (lock)
{
status = mu_locker_lock (lock);
if (status)
{
mailer_err (_("Cannot lock mailbox `%s': %s"), path,
mu_strerror (status));
mu_mailbox_destroy (&mbox);
exit_code = EX_TEMPFAIL;
return EX_TEMPFAIL;
}
}
#if defined(USE_MAILBOX_QUOTAS)
{
mu_off_t n;
mu_off_t msg_size;
mu_off_t mbsize;
if ((status = mu_mailbox_get_size (mbox, &mbsize)))
{
mailer_err (_("Cannot get size of mailbox %s: %s"),
path, mu_strerror (status));
if (status == ENOSYS)
mbsize = 0; /* Try to continue anyway */
else
{
mu_mailbox_destroy (&mbox);
return EX_TEMPFAIL;
}
}
switch (check_quota (auth, mbsize, &n))
{
case MQUOTA_EXCEEDED:
mailer_err (_("%s: mailbox quota exceeded for this recipient"), name);
if (errp)
asprintf (errp, "%s: mailbox quota exceeded for this recipient",
name);
exit_code = EX_QUOTA();
failed++;
break;
case MQUOTA_UNLIMITED:
break;
default:
if ((status = mu_mailbox_get_size (imbx, &msg_size)))
{
mailer_err (_("Cannot get message size (input message %s): %s"),
path, mu_strerror (status));
exit_code = EX_UNAVAILABLE;
failed++;
}
else if (msg_size > n)
{
mailer_err (_("%s: message would exceed maximum mailbox size for "
"this recipient"),
name);
if (errp)
asprintf (errp,
"%s: message would exceed maximum mailbox size "
"for this recipient",
name);
exit_code = EX_QUOTA();
failed++;
}
break;
}
}
#endif
if (!failed && switch_user_id (auth, 1) == 0)
{
status = mu_mailbox_append_message (mbox, msg);
if (status)
{
mailer_err (_("Error writing to mailbox %s: %s"),
path, mu_strerror (status));
failed++;
}
else
{
status = mu_mailbox_sync (mbox);
if (status)
{
mailer_err (_("Error flushing mailbox %s: %s"),
path, mu_strerror (status));
failed++;
}
}
switch_user_id (auth, 0);
}
mu_auth_data_free (auth);
mu_mailbox_close (mbox);
mu_locker_unlock (lock);
mu_mailbox_destroy (&mbox);
return failed ? exit_code : 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2007 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA */
#include "maidag.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <signal.h>
#include <mu_umaxtostr.h>
typedef union
{
struct sockaddr sa;
struct sockaddr_in s_in;
struct sockaddr_un s_un;
} all_addr_t;
static int
lmtp_open_internal (int *pfd, mu_url_t url, const char *urlstr)
{
int fd;
int rc;
int t = 1;
char buffer[64];
all_addr_t addr;
int addrsize;
mode_t saved_umask;
rc = mu_url_get_scheme (url, buffer, sizeof buffer, NULL);
if (rc)
{
mu_error (_("%s: cannot get scheme from URL: %s"),
urlstr, mu_strerror(rc));
return EX_CONFIG;
}
memset (&addr, 0, sizeof addr);
if (strcmp (buffer, "file") == 0 || strcmp (buffer, "socket") == 0)
{
size_t size;
rc = mu_url_get_path (url, NULL, 0, &size);
if (rc)
{
mu_error (_("%s: cannot get path: %s"), urlstr, mu_strerror(rc));
return EX_CONFIG;
}
if (size > sizeof addr.s_un.sun_path - 1)
{
mu_error (_("%s: file name too long"), urlstr);
return EX_TEMPFAIL;
}
mu_url_get_path (url, addr.s_un.sun_path, sizeof addr.s_un.sun_path,
NULL);
fd = socket (PF_UNIX, SOCK_STREAM, 0);
if (fd < 0)
{
mu_error ("socket: %s", mu_strerror (errno));
return EX_TEMPFAIL;
}
addr.s_un.sun_family = AF_UNIX;
addrsize = sizeof addr.s_un;
if (reuse_lmtp_address)
{
struct stat st;
if (stat (addr.s_un.sun_path, &st))
{
if (errno != ENOENT)
{
mu_error (_("file %s exists but cannot be stat'd"),
addr.s_un.sun_path);
return EX_TEMPFAIL;
}
}
else if (!S_ISSOCK (st.st_mode))
{
mu_error (_("file %s is not a socket"),
addr.s_un.sun_path);
return EX_TEMPFAIL;
}
else
unlink (addr.s_un.sun_path);
}
}
else if (strcmp (buffer, "tcp") == 0)
{
size_t size;
long n;
struct hostent *hp;
char *path = NULL;
short port = 0;
rc = mu_url_get_port (url, &n);
if (rc)
{
mu_error (_("%s: cannot get port: %s"), urlstr, mu_strerror(rc));
return EX_CONFIG;
}
if (n == 0 || (port = n) != n)
{
mu_error (_("Port out of range: %ld"), n);
return EX_CONFIG;
}
rc = mu_url_get_host (url, NULL, 0, &size);
if (rc)
{
mu_error (_("%s: cannot get host: %s"), urlstr, mu_strerror(rc));
return EX_CONFIG;
}
path = malloc (size + 1);
if (!path)
{
mu_error (_("Not enough memory"));
return EX_TEMPFAIL;
}
mu_url_get_host (url, path, size + 1, NULL);
fd = socket (PF_INET, SOCK_STREAM, 0);
if (fd < 0)
{
mu_error ("socket: %s", mu_strerror (errno));
return EX_TEMPFAIL;
}
addr.s_in.sin_family = AF_INET;
hp = gethostbyname (path);
if (hp)
{
char **ap;
int count = 0;
addr.s_in.sin_addr.s_addr = *(unsigned long*) hp->h_addr_list[0];
for (ap = hp->h_addr_list; *ap; ap++)
count++;
if (count > 1)
mu_error (_("warning: %s has several IP addresses, using %s"),
path, inet_ntoa (addr.s_in.sin_addr));
}
else if (inet_aton (path, &addr.s_in.sin_addr) == 0)
{
mu_error ("invalid IP address: %s", path);
return EX_TEMPFAIL;
}
addr.s_in.sin_port = htons (port);
addrsize = sizeof addr.s_in;
if (reuse_lmtp_address)
setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(t));
}
else
{
mu_error (_("%s: invalid scheme"), urlstr);
return EX_CONFIG;
}
saved_umask = umask (0117);
if (bind (fd, &addr.sa, addrsize) == -1)
{
mu_error ("bind: %s", strerror (errno));
close (fd);
return EXIT_FAILURE;
}
umask (saved_umask);
*pfd = fd;
return 0;
}
int
lmtp_open (int *pfd, char *urlstr)
{
mu_url_t url = NULL;
int rc;
rc = mu_url_create (&url, urlstr);
if (rc)
{
mu_error (_("%s: cannot create URL: %s"),
urlstr, mu_strerror (rc));
return EX_CONFIG;
}
rc = mu_url_parse (url);
if (rc)
{
mu_error (_("%s: error parsing URL: %s"),
urlstr, mu_strerror(rc));
return EX_CONFIG;
}
rc = lmtp_open_internal (pfd, url, urlstr);
mu_url_destroy (&url);
return rc;
}
size_t children;
static int need_cleanup = 0;
void
process_cleanup ()
{
pid_t pid;
int status;
if (need_cleanup)
{
need_cleanup = 0;
while ( (pid = waitpid (-1, &status, WNOHANG)) > 0)
--children;
}
}
RETSIGTYPE
lmtp_sigchld (int signo MU_ARG_UNUSED)
{
need_cleanup = 1;
#ifndef HAVE_SIGACTION
signal (signo, lmtp_sigchld);
#endif
}
void
lmtp_reply (FILE *fp, char *code, char *enh, char *fmt, ...)
{
va_list ap;
char *str;
va_start (ap, fmt);
vasprintf (&str, fmt, ap);
va_end (ap);
if (daemon_param.transcript)
{
if (enh)
syslog (LOG_INFO, "LMTP reply: %s %s %s", code, enh, str);
else
syslog (LOG_INFO, "LMTP reply: %s %s", code, str);
}
if (!str)
{
mu_error (_("Not enough memory"));
exit (EX_TEMPFAIL);
}
while (*str)
{
char *end = strchr (str, '\n');
if (end)
{
size_t len = end - str;
fprintf (fp, "%s-", code);
if (enh)
fprintf (fp, "%s ", enh);
fprintf (fp, "%.*s\r\n", len, str);
for (str = end; *str && *str == '\n'; str++);
}
else
{
fprintf (fp, "%s ", code);
if (enh)
fprintf (fp, "%s ", enh);
fprintf (fp, "%s\r\n", str);
str += strlen (str);
}
}
}
void
trimnl (char *arg)
{
size_t len = strlen (arg);
if (len > 0 && arg[len-1] == '\n')
arg[--len] = 0;
if (len > 0 && arg[len-1] == '\r')
arg[--len] = 0;
}
void
xlatnl (char *arg)
{
size_t len = strlen (arg);
if (len > 0 && arg[len-1] == '\n')
{
len--;
if (len > 0 && arg[len-1] == '\r')
{
arg[len-1] = '\n';
arg[len] = 0;
}
}
}
enum lmtp_state
{
state_none,
state_init,
state_lhlo,
state_mail,
state_rcpt,
state_data,
state_quit,
state_dot,
state_end
};
#define NSTATE ((int) state_end + 1)
enum lmtp_command
{
cmd_unknown,
cmd_lhlo,
cmd_mail,
cmd_rcpt,
cmd_data,
cmd_quit,
cmd_rset,
cmd_help,
cmd_dot
};
#define NCMD ((int)cmd_dot + 1)
#define SNO state_none
#define SIN state_init
#define SHL state_lhlo
#define SML state_mail
#define SRC state_rcpt
#define SDA state_data
#define SQT state_quit
#define SDT state_dot
#define SEN state_end
int transtab[NCMD][NSTATE] = {
/* state_ SNO SIN SHL SML SRC SDA SQT SDT SEN */
/* unkn */ { SNO, SNO, SNO, SNO, SNO, SNO, SNO, SNO, SEN },
/* lhlo */ { SNO, SHL, SNO, SNO, SNO, SNO, SNO, SNO, SNO },
/* mail */ { SNO, SNO, SML, SNO, SNO, SNO, SNO, SNO, SNO },
/* rcpt */ { SNO, SNO, SNO, SRC, SRC, SNO, SNO, SNO, SNO },
/* data */ { SNO, SNO, SNO, SNO, SDA, SNO, SNO, SNO, SNO },
/* quit */ { SNO, SEN, SEN, SEN, SEN, SEN, SEN, SEN, SEN },
/* rset */ { SNO, SIN, SIN, SIN, SIN, SIN, SIN, SIN, SNO },
/* help */ { SNO, SIN, SHL, SML, SRC, SDT, SQT, SDT, SEN },
/* dot */ { SNO, SNO, SNO, SNO, SNO, SQT, SNO, SNO, SNO },
};
/* Delivery data */
char *lhlo_domain; /* Sender domain */
char *mail_from; /* Sender address */
mu_list_t rcpt_list; /* Recipient addresses */
struct mail_tmp *mtmp; /* Temporary mail storage */
mu_mailbox_t mbox; /* Collected mail body */
static void
rcpt_to_destroy_item (void *ptr)
{
free (ptr);
}
int
cfun_unknown (FILE *out, char *arg)
{
lmtp_reply (out, "500", "5.5.1", "Command unrecognized");
return 0;
}
static void
add_default_domain (char *str, int len, char **pret)
{
*pret = malloc (len + 1 + strlen (lhlo_domain) + 1);
if (!*pret)
{
mu_error (_("Not enough memory"));
exit (EX_SOFTWARE);
}
memcpy (*pret, str, len);
(*pret)[len] = '@';
strcpy (*pret + len + 1, lhlo_domain);
}
#define MAILER_DAEMON "MAILER-DAEMON"
int
check_address (char *arg, int with_domain, char **pret)
{
if (strchr (arg, '@') == 0)
{
char *addr = NULL;
size_t addrlen = 0;
if (*arg == '<')
{
size_t len = strlen (arg);
if (arg[len - 1] == '>')
{
if (len == 2) /* null address */
{
if (!with_domain)
/* Null address is only legal in mail from */
return 1;
addr = MAILER_DAEMON;
addrlen = sizeof MAILER_DAEMON - 1;
}
else
{
addr = arg + 1;
addrlen = len - 2;
}
}
else
return 1;
}
else
{
addr = arg;
addrlen = strlen (arg);
}
if (with_domain)
add_default_domain (addr, addrlen, pret);
else
{
*pret = malloc (addrlen + 1);
memcpy (*pret, addr, addrlen);
(*pret)[addrlen] = 0;
}
}
else
{
mu_address_t addr;
int rc = mu_address_create (&addr, arg);
if (rc)
return 1;
if (with_domain)
mu_address_aget_email (addr, 1, pret);
else
mu_address_aget_local_part (addr, 1, pret);
mu_address_destroy (&addr);
}
return 0;
}
int
cfun_mail_from (FILE *out, char *arg)
{
if (*arg == 0)
{
lmtp_reply (out, "501", "5.5.2", "Oj-ej");
return 1;
}
if (check_address (arg, 1, &mail_from))
{
lmtp_reply (out, "553", "5.1.8", "Pomyliles sie");
return 1;
}
lmtp_reply (out, "250", "2.1.0", "Moje ty sloneczko");
return 0;
}
int
cfun_rcpt_to (FILE *out, char *arg)
{
char *user;
struct mu_auth_data *auth;
if (*arg == 0)
{
lmtp_reply (out, "501", "5.5.2", "Oj-ej");
return 1;
}
/* FIXME: Check if domain is OK */
if (check_address (arg, 0, &user))
{
lmtp_reply (out, "553", "5.1.8", "Pomyliles sie");
return 1;
}
auth = mu_get_auth_by_name (user);
if (!auth)
{
lmtp_reply (out, "550", "5.1.1", "Hm, nie znam takiego");
free (user);
return 1;
}
mu_auth_data_free (auth);
if (!rcpt_list)
{
mu_list_create (&rcpt_list);
mu_list_set_destroy_item (rcpt_list, rcpt_to_destroy_item);
}
mu_list_append (rcpt_list, user);
lmtp_reply (out, "250", "2.1.5", "%s bedzie uszczesliwiony", user);
return 0;
}
int
cfun_data (FILE *out, char *arg)
{
if (*arg)
{
lmtp_reply (out, "501", "5.5.2", "Co za bzdury?");
return 1;
}
if (mail_tmp_begin (&mtmp, mail_from))
{
/* FIXME: codes */
lmtp_reply (out, "450", "4.1.0", "Cos mi nieswojo, moze pozniej...");
return 1;
}
lmtp_reply (out, "354", NULL, "Jazda!");
return 0;
}
int
dot_temp_fail (void *item, void *cbdata)
{
char *name = item;
FILE *out = cbdata;
lmtp_reply (out, "450", "4.1.0", "%s: cos nawalilo, sprobuj pozniej", name);
return 0;
}
int
dot_deliver (void *item, void *cbdata)
{
char *name = item;
FILE *out = cbdata;
char *errp = NULL;
switch (deliver (mbox, name, &errp))
{
case 0:
lmtp_reply (out, "250", "2.0.0", "%s: dostarczono", name);
break;
case EX_UNAVAILABLE:
if (errp)
lmtp_reply (out, "553", "5.1.8", "%s", errp);
else
lmtp_reply (out, "553", "5.1.8", "%s: nie dostarczono", name);
break;
default:
if (errp)
lmtp_reply (out, "450", "4.1.0", "%s", errp);
else
lmtp_reply (out, "450", "4.1.0", "%s: cos nawalilo, sprobuj pozniej",
name);
break;
}
free (errp);
return 0;
}
int
cfun_dot (FILE *out, char *arg)
{
if (!mtmp)
mu_list_do (rcpt_list, dot_temp_fail, out);
else
{
int rc = mail_tmp_finish (mtmp, &mbox);
if (rc)
mu_list_do (rcpt_list, dot_temp_fail, out);
else
{
mu_list_do (rcpt_list, dot_deliver, out);
mail_tmp_destroy (&mtmp);
mu_mailbox_destroy (&mbox);
}
}
free (mail_from);
mu_list_destroy (&rcpt_list);
return 0;
}
int
cfun_rset (FILE *out, char *arg)
{
free (lhlo_domain);
free (mail_from);
mu_list_destroy (&rcpt_list);
mail_tmp_destroy (&mtmp);
mu_mailbox_destroy (&mbox);
lmtp_reply (out, "250", "2.0.0", "Dobrze, zapomnialem");
return 0;
}
char *capa_str = "ENHANCEDSTATUSCODES\n\
PIPELINING\n\
8BITMIME\n\
HELP";
int
cfun_lhlo (FILE *out, char *arg)
{
if (*arg == 0)
{
lmtp_reply (out, "501", "5.0.0", "Czy to wszystko?");
return 1;
}
lhlo_domain = strdup (arg);
lmtp_reply (out, "250", NULL, "Czolem\n");
lmtp_reply (out, "250", NULL, capa_str);
return 0;
}
int
cfun_quit (FILE *out, char *arg)
{
lmtp_reply (out, "221", "2.0.0", "Na razie");
return 0;
}
int
cfun_help (FILE *out, char *arg)
{
lmtp_reply (out, "200", "2.0.0", "Czlowieku, pomagaj sobie sam");
return 0;
}
struct command_tab
{
char *cmd_verb;
int cmd_len;
enum lmtp_command cmd_code;
int (*cmd_fun) (FILE *, char *);
} command_tab[] = {
#define S(s) #s, (sizeof #s - 1)
{ S(lhlo), cmd_lhlo, cfun_lhlo },
{ S(mail from:), cmd_mail, cfun_mail_from },
{ S(rcpt to:), cmd_rcpt, cfun_rcpt_to },
{ S(data), cmd_data, cfun_data },
{ S(quit), cmd_quit, cfun_quit },
{ S(rset), cmd_rset, cfun_rset },
{ S(help), cmd_help, cfun_help },
{ S(.), cmd_dot, cfun_dot },
{ NULL, 0, cmd_unknown, cfun_unknown }
};
struct command_tab *
getcmd (char *buf, char **sp)
{
struct command_tab *cp;
size_t len = strlen (buf);
for (cp = command_tab; cp->cmd_verb; cp++)
{
if (cp->cmd_len <= len
&& strncasecmp (cp->cmd_verb, buf, cp->cmd_len) == 0)
{
*sp = buf + cp->cmd_len;
return cp;
}
}
return cp;
}
int
lmtp_loop (FILE *in, FILE *out)
{
char buf[1024];
enum lmtp_state state = state_init;
setvbuf (in, NULL, _IOLBF, 0);
setvbuf (out, NULL, _IOLBF, 0);
lmtp_reply (out, "220", NULL, "Do uslug");
while (fgets (buf, sizeof buf, in))
{
if (state == state_data
&& !(buf[0] == '.'
&& (buf[1] == '\n' || (buf[1] == '\r' && buf[2] == '\n'))))
{
/* This is a special case */
if (mtmp)
{
size_t len;
int rc;
xlatnl (buf);
len = strlen (buf);
if ((rc = mail_tmp_add_line (mtmp, buf, len)))
{
mail_tmp_destroy (&mtmp);
/* Wait the dot to report the error */
}
}
}
else
{
char *sp;
struct command_tab *cp = getcmd (buf, &sp);
enum lmtp_command cmd = cp->cmd_code;
enum lmtp_state next_state = transtab[cmd][state];
trimnl (buf);
if (daemon_param.transcript)
syslog (LOG_INFO, "LMTP recieve: %s", buf);
if (next_state != state_none)
{
if (cp->cmd_fun)
{
while (*sp && isspace (*sp))
sp++;
if (cp->cmd_fun (out, sp))
continue;
}
state = next_state;
}
else
lmtp_reply (out, "503", "5.0.0", "Syntax error");
}
if (state == state_end)
break;
}
return 0;
}
void
log_connection (all_addr_t *addr, socklen_t addrlen)
{
switch (addr->sa.sa_family)
{
case PF_UNIX:
syslog (LOG_INFO, _("connect from socket"));
break;
case PF_INET:
syslog (LOG_INFO, _("connect from %s"), inet_ntoa (addr->s_in.sin_addr));
}
}
int
lmtp_daemon (char *urlstr)
{
int rc;
int listenfd, connfd;
all_addr_t addr;
socklen_t addrlen;
pid_t pid;
if (daemon_param.mode == MODE_DAEMON)
{
if (daemon (0, 0) < 0)
{
mu_error (_("Failed to become a daemon"));
return EX_UNAVAILABLE;
}
}
rc = lmtp_open (&listenfd, urlstr);
if (rc)
return rc;
if (listen (listenfd, 128) == -1)
{
mu_error ("listen: %s", strerror (errno));
close (listenfd);
return EX_UNAVAILABLE;
}
#ifdef HAVE_SIGACTION
{
struct sigaction act;
act.sa_handler = lmtp_sigchld;
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
sigaction (SIGCHLD, &act, NULL);
}
#else
signal (SIGCHLD, lmtp_sigchld);
#endif
for (;;)
{
process_cleanup ();
if (children > daemon_param.maxchildren)
{
mu_error (_("too many children (%lu)"),
(unsigned long) children);
pause ();
continue;
}
addrlen = sizeof addr;
connfd = accept (listenfd, (struct sockaddr *)&addr, &addrlen);
if (connfd == -1)
{
if (errno == EINTR)
continue;
mu_error ("accept: %s", strerror (errno));
continue;
/*exit (EXIT_FAILURE);*/
}
log_connection (&addr, addrlen);
pid = fork ();
if (pid == -1)
syslog (LOG_ERR, "fork: %s", strerror (errno));
else if (pid == 0) /* Child. */
{
int status;
close (listenfd);
status = lmtp_loop (fdopen (connfd, "r"), fdopen (connfd, "w"));
exit (status);
}
else
{
++children;
}
close (connfd);
}
}
#define DEFAULT_URL "tcp://127.0.0.1:"
int
maidag_lmtp_server ()
{
struct group *gr = getgrnam (lmtp_group);
if (gr == NULL)
{
mu_error (_("Error getting mail group"));
return EX_UNAVAILABLE;
}
if (setgid (gr->gr_gid) == -1)
{
mu_error (_("Error setting mail group"));
return EX_UNAVAILABLE;
}
if (lmtp_url_string)
return lmtp_daemon (lmtp_url_string);
else if (daemon_param.mode == MODE_INTERACTIVE)
return lmtp_loop (stdin, stdout);
else
{
const char *pstr = mu_umaxtostr (0, daemon_param.port);
char *urls = malloc (sizeof (DEFAULT_URL) + strlen (pstr));
if (!urls)
{
mu_error (_("Not enough memory"));
return EX_TEMPFAIL;
}
strcpy (urls, DEFAULT_URL);
strcat (urls, pstr);
return lmtp_daemon (urls);
}
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2007 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA */
#include "maidag.h"
int multiple_delivery; /* Don't return errors when delivering to multiple
recipients */
int ex_quota_tempfail; /* Return temporary failure if mailbox quota is
exceeded. If this variable is not set, maidag
will return "service unavailable" */
int exit_code = EX_OK; /* Exit code to be used */
uid_t current_uid; /* Current user id */
char *quotadbname = NULL; /* Name of mailbox quota database */
char *quota_query = NULL; /* SQL query to retrieve mailbox quota */
char *sender_address = NULL;
char *progfile_pattern = NULL;
char *sieve_pattern = NULL;
int log_to_stderr = -1;
/* Debuggig options */
int debug_level; /* General debugging level */
int debug_flags; /* Mailutils debugging flags */
int sieve_debug_flags; /* Sieve debugging flags */
int sieve_enable_log; /* Enables logging of executed Sieve actions */
char *message_id_header; /* Use the value of this header as message
identifier when logging Sieve actions */
mu_debug_t mudebug; /* Mailutils debugging object */
/* For LMTP mode */
int lmtp_mode;
char *lmtp_url_string;
int reuse_lmtp_address = 1;
char *lmtp_group = "mail";
struct daemon_param daemon_param = {
MODE_INTERACTIVE, /* Start in interactive (inetd) mode */
20, /* Default maximum number of children */
0, /* No standard port */
600, /* Idle timeout */
0, /* No transcript by default */
NULL /* No PID file by default */
};
const char *program_version = "maidag (" PACKAGE_STRING ")";
static char doc[] =
N_("GNU maildag -- the mail delivery agent")
"\v"
N_("Debug flags are:\n\
g - guimb stack traces\n\
T - mailutils traces (MU_DEBUG_TRACE)\n\
P - network protocols (MU_DEBUG_PROT)\n\
t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n\
i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n\
l - sieve action logs\n\
0-9 - Set mail.local debugging level\n");
static char args_doc[] = N_("[recipient...]");
#define STDERR_OPTION 256
#define MESSAGE_ID_HEADER_OPTION 257
#define LMTP_OPTION 258
static struct argp_option options[] =
{
{ "from", 'f', N_("EMAIL"), 0,
N_("Specify the sender's name") },
{ NULL, 'r', NULL, OPTION_ALIAS, NULL },
{ "sieve", 'S', N_("PATTERN"), 0,
N_("Set name pattern for user-defined Sieve mail filters"), 0 },
{ "message-id-header", MESSAGE_ID_HEADER_OPTION, N_("STRING"), 0,
N_("Identify messages by the value of this header when logging Sieve actions"), 0 },
#ifdef WITH_GUILE
{ "source", 's', N_("PATTERN"), 0,
N_("Set name pattern for user-defined Scheme mail filters"), 0 },
#endif
{ "lmtp", LMTP_OPTION, N_("URL"), OPTION_ARG_OPTIONAL,
N_("Operate in LMTP mode"), 0 },
{ "debug", 'x', N_("FLAGS"), 0,
N_("Enable debugging"), 0 },
{ "stderr", STDERR_OPTION, NULL, 0,
N_("Log to standard error"), 0 },
{ NULL, 0, NULL, 0, NULL, 0 }
};
static error_t parse_opt (int key, char *arg, struct argp_state *state);
static struct argp argp = {
options,
parse_opt,
args_doc,
doc,
NULL,
NULL, NULL
};
static const char *argp_capa[] = {
"daemon",
"auth",
"common",
"license",
"logging",
"mailbox",
"mailer",
"sieve",
NULL
};
#define D_DEFAULT "9,s"
static void
set_debug_flags (const mu_cfg_locus_t *locus, const char *arg)
{
while (*arg)
{
if (isdigit (*arg))
debug_level = strtoul (arg, (char**)&arg, 10);
else
for (; *arg && *arg != ','; arg++)
{
switch (*arg)
{
case 'g':
#ifdef WITH_GUILE
debug_guile = 1;
#endif
break;
case 't':
sieve_debug_flags |= MU_SIEVE_DEBUG_TRACE;
break;
case 'i':
sieve_debug_flags |= MU_SIEVE_DEBUG_INSTR;
break;
case 'l':
sieve_enable_log = 1;
break;
case 'T':
debug_flags |= MU_DEBUG_TRACE;
break;
case 'P':
debug_flags |= MU_DEBUG_PROT;
break;
default:
if (locus)
mu_error (_("%s:%d: %c is not a valid debug flag"),
locus->file, locus->line, *arg);
else
mu_error (_("%c is not a valid debug flag"), *arg);
break;
}
}
if (*arg == ',')
arg++;
else if (locus)
mu_error (_("%s:%d: expected comma, but found %c"),
locus->file, locus->line, *arg);
else
mu_error (_("expected comma, but found %c"), *arg);
}
}
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
switch (key)
{
case ARGP_KEY_INIT:
state->child_inputs[0] = state->input;
break;
case MESSAGE_ID_HEADER_OPTION:
message_id_header = arg;
break;
case LMTP_OPTION:
lmtp_mode = 1;
lmtp_url_string = arg;
break;
case 'r':
case 'f':
if (sender_address != NULL)
{
argp_error (state, _("Multiple --from options"));
return EX_USAGE;
}
sender_address = arg;
break;
#ifdef WITH_GUILE
case 's':
progfile_pattern = arg;
break;
#endif
case 'S':
sieve_pattern = arg;
break;
case 'x':
set_debug_flags (NULL, arg ? arg : D_DEFAULT);
break;
case STDERR_OPTION:
log_to_stderr = 1;
break;
default:
return ARGP_ERR_UNKNOWN;
case ARGP_KEY_ERROR:
exit (EX_USAGE);
}
return 0;
}
static int
cb_debug (mu_cfg_locus_t *locus, void *data, char *arg)
{
set_debug_flags (locus, arg);
return 0;
}
struct mu_cfg_param maidag_cfg_param[] = {
{ "exit-multiple-delivery-success", mu_cfg_bool, &multiple_delivery },
{ "exit-quota-tempfail", mu_cfg_bool, &ex_quota_tempfail },
#ifdef USE_DBM
{ "quota-db", mu_cfg_string, &quotadbname },
#endif
#ifdef USE_SQL
{ "quota-query", mu_cfg_string, &quota_query },
#endif
{ "sieve", mu_cfg_string, &sieve_pattern },
{ "message-id-header", mu_cfg_string, &message_id_header },
#ifdef WITH_GUILE
{ "source", mu_cfg_string, &progfile_pattern },
#endif
{ "debug", mu_cfg_callback, NULL, cb_debug },
{ "stderr", mu_cfg_bool, &log_to_stderr },
/* LMTP support */
{ "lmtp", mu_cfg_bool, &lmtp_mode },
{ "group", mu_cfg_string, &lmtp_group },
{ "listen", mu_cfg_string, &lmtp_url_string },
{ "reuse-address", mu_cfg_bool, &reuse_lmtp_address },
{ NULL }
};
/* Logging */
static int
_mu_debug_printer (mu_debug_t unused, size_t level, const char *fmt,
va_list ap)
{
if (log_to_stderr)
{
fprintf (stderr, "%s: ", (level == MU_DEBUG_ERROR) ? "ERROR" : "DEBUG");
vfprintf (stderr, fmt, ap);
fputc ('\n', stderr);
}
else
vsyslog ((level == MU_DEBUG_ERROR) ? LOG_ERR : LOG_DEBUG, fmt, ap);
return 0;
}
static int
_sieve_debug_printer (void *unused, const char *fmt, va_list ap)
{
if (log_to_stderr)
{
fprintf (stderr, "DEBUG: ");
vfprintf (stderr, fmt, ap);
fputc ('\n', stderr);
}
else
vsyslog (LOG_DEBUG, fmt, ap);
return 0;
}
static void
_sieve_action_log (void *user_name,
const mu_sieve_locus_t *locus, size_t msgno,
mu_message_t msg,
const char *action, const char *fmt, va_list ap)
{
char *text = NULL;
if (message_id_header)
{
mu_header_t hdr = NULL;
char *val = NULL;
mu_message_get_header (msg, &hdr);
if (mu_header_aget_value (hdr, message_id_header, &val) == 0
|| mu_header_aget_value (hdr, MU_HEADER_MESSAGE_ID, &val) == 0)
{
asprintf (&text, _("%s:%lu: %s on msg %s"),
locus->source_file,
(unsigned long) locus->source_line,
action, val);
free (val);
}
}
if (text == NULL)
{
size_t uid = 0;
mu_message_get_uid (msg, &uid);
asprintf (&text, _("%s:%lu: %s on msg uid %d"),
locus->source_file,
(unsigned long) locus->source_line,
action, uid);
}
if (fmt && strlen (fmt))
{
char *diag = NULL;
vasprintf (&diag, fmt, ap);
if (log_to_stderr)
fprintf (stderr, _("(user %s) %s: %s"), (char*) user_name,
text, diag);
else
syslog (LOG_NOTICE, _("(user %s) %s: %s"), (char*) user_name,
text, diag);
free (diag);
}
else if (log_to_stderr)
fprintf (stderr, _("(user %s) %s"), (char*) user_name, text);
else
syslog (LOG_NOTICE, _("(user %s) %s"), (char*) user_name, text);
free (text);
if (log_to_stderr)
fputc ('\n', stderr);
}
static int
_sieve_parse_error (void *user_name, const char *filename, int lineno,
const char *fmt, va_list ap)
{
char *text;
vasprintf (&text, fmt, ap);
if (filename)
{
char *loc;
asprintf (&loc, "%s:%d: ", filename, lineno);
if (log_to_stderr)
fprintf (stderr, "%s: %s", loc, text);
else
syslog (LOG_ERR, "%s: %s", loc, text);
free (loc);
}
else if (log_to_stderr)
fprintf (stderr, _("(user %s) %s"), (char*)user_name, text);
else
syslog (LOG_ERR, _("(user %s) %s"), (char*)user_name, text);
free (text);
if (log_to_stderr)
fputc ('\n', stderr);
return 0;
}
int
sieve_test (struct mu_auth_data *auth, mu_mailbox_t mbx)
{
int rc = 1;
char *progfile;
if (!sieve_pattern)
return 1;
progfile = mu_expand_path_pattern (sieve_pattern, auth->name);
if (access (progfile, R_OK))
{
if (debug_level > 2)
syslog (LOG_DEBUG, _("Access to %s failed: %m"), progfile);
}
else
{
mu_sieve_machine_t mach;
rc = mu_sieve_machine_init (&mach, auth->name);
if (rc)
{
mu_error (_("Cannot initialize sieve machine: %s"),
mu_strerror (rc));
}
else
{
mu_sieve_set_debug (mach, _sieve_debug_printer);
mu_sieve_set_debug_level (mach, mudebug, sieve_debug_flags);
mu_sieve_set_parse_error (mach, _sieve_parse_error);
if (sieve_enable_log)
mu_sieve_set_logger (mach, _sieve_action_log);
rc = mu_sieve_compile (mach, progfile);
if (rc == 0)
{
mu_attribute_t attr;
mu_message_t msg = NULL;
mu_mailbox_get_message (mbx, 1, &msg);
mu_message_get_attribute (msg, &attr);
mu_attribute_unset_deleted (attr);
if (switch_user_id (auth, 1) == 0)
{
chdir (auth->dir);
rc = mu_sieve_message (mach, msg);
if (rc == 0)
rc = mu_attribute_is_deleted (attr) == 0;
switch_user_id (auth, 0);
chdir ("/");
}
mu_sieve_machine_destroy (&mach);
}
}
}
free (progfile);
return rc;
}
int
main (int argc, char *argv[])
{
int arg_index;
/* Preparative work: close inherited fds, force a reasonable umask
and prepare a logging. */
close_fds ();
umask (0077);
/* Native Language Support */
mu_init_nls ();
/* Default locker settings */
mu_locker_set_default_flags (MU_LOCKER_PID|MU_LOCKER_RETRY,
mu_locker_assign);
mu_locker_set_default_retry_timeout (1);
mu_locker_set_default_retry_count (300);
/* Default error code for command line errors */
mu_argp_error_code = EX_CONFIG;
/* Register needed modules */
MU_AUTH_REGISTER_ALL_MODULES ();
/* Register mailbox formats */
mu_register_all_formats ();
/* Register the supported mailers. */
mu_registrar_record (mu_sendmail_record);
mu_registrar_record (mu_smtp_record);
mu_argp_init (program_version, NULL);
mu_sieve_argp_init ();
/* Parse command line */
mu_argp_set_config_param (maidag_cfg_param);
mu_argp_parse (&argp, &argc, &argv, 0, argp_capa, &arg_index, &daemon_param);
current_uid = getuid ();
if (log_to_stderr == -1)
log_to_stderr = (getuid () != 0);
if (!log_to_stderr)
{
openlog ("mail.local", LOG_PID, log_facility);
mu_error_set_print (mu_syslog_error_printer);
}
if (debug_flags)
{
int rc;
if ((rc = mu_debug_create (&mudebug, NULL)))
{
mu_error (_("mu_debug_create failed: %s\n"), mu_strerror (rc));
exit (EX_TEMPFAIL);
}
if ((rc = mu_debug_set_level (mudebug, debug_flags)))
{
mu_error (_("mu_debug_set_level failed: %s\n"),
mu_strerror (rc));
exit (EX_TEMPFAIL);
}
if ((rc = mu_debug_set_print (mudebug, _mu_debug_printer, NULL)))
{
mu_error (_("mu_debug_set_print failed: %s\n"),
mu_strerror (rc));
exit (EX_TEMPFAIL);
}
}
argc -= arg_index;
argv += arg_index;
if (lmtp_mode)
{
if (argc)
{
mu_error (_("Too many arguments"));
return EX_USAGE;
}
return maidag_lmtp_server ();
}
else
{
if (current_uid)
{
static char *s_argv[2];
struct mu_auth_data *auth = mu_get_auth_by_uid (current_uid);
if (!current_uid)
{
mu_error (_("Cannot get username"));
return EX_UNAVAILABLE;
}
if (argc > 1 || (argc > 0 && strcmp (auth->name, argv[0])))
{
mu_error (_("Recipients given when running as non-root"));
return EX_USAGE;
}
s_argv[0] = auth->name;
argv = s_argv;
argc = 1;
}
return maidag_stdio_delivery (argc, argv);
}
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2007 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA */
#if defined(HAVE_CONFIG_H)
# include <config.h>
#endif
#include <sys/types.h>
#include <errno.h>
#include <grp.h>
#include <netdb.h>
#include <pwd.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/stat.h>
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef HAVE_SYSEXITS_H
# include <sysexits.h>
#else
# define EX_OK 0 /* successful termination */
# define EX__BASE 64 /* base value for error messages */
# define EX_USAGE 64 /* command line usage error */
# define EX_DATAERR 65 /* data format error */
# define EX_NOINPUT 66 /* cannot open input */
# define EX_NOUSER 67 /* addressee unknown */
# define EX_NOHOST 68 /* host name unknown */
# define EX_UNAVAILABLE 69 /* service unavailable */
# define EX_SOFTWARE 70 /* internal software error */
# define EX_OSERR 71 /* system error (e.g., can't fork) */
# define EX_OSFILE 72 /* critical OS file missing */
# define EX_CANTCREAT 73 /* can't create (user) output file */
# define EX_IOERR 74 /* input/output error */
# define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
# define EX_PROTOCOL 76 /* remote error in protocol */
# define EX_NOPERM 77 /* permission denied */
# define EX_CONFIG 78 /* configuration error */
# define EX__MAX 78 /* maximum listed value */
#endif
#ifndef INADDR_LOOPBACK
# define INADDR_LOOPBAK 0x7f000001
#endif
#include <mailutils/attribute.h>
#include <mailutils/errno.h>
#include <mailutils/error.h>
#include <mailutils/list.h>
#include <mailutils/locker.h>
#include <mailutils/mailbox.h>
#include <mailutils/message.h>
#include <mailutils/mutil.h>
#include <mailutils/registrar.h>
#include <mailutils/stream.h>
#include <mailutils/url.h>
#include <mailutils/mu_auth.h>
#include <mailutils/libsieve.h>
#include <mailutils/nls.h>
#include <mu_dbm.h>
#include <mu_asprintf.h>
#include <getline.h>
#if defined (USE_DBM) || defined (USE_SQL)
# define USE_MAILBOX_QUOTAS 1
#endif
#include <mailutils/argp.h>
/* Debug */
extern int debug_level;
#define dbg() if (debug_level) debug
/* mailquota settings */
#define MQUOTA_OK 0
#define MQUOTA_EXCEEDED 1
#define MQUOTA_UNLIMITED 2
#define MAXFD 64
#define EX_QUOTA() (ex_quota_tempfail ? EX_TEMPFAIL : EX_UNAVAILABLE)
extern int exit_code;
extern int log_to_stderr;
extern int multiple_delivery;
extern int ex_quota_tempfail;
extern uid_t current_uid;
extern char *quotadbname;
extern char *quota_query;
extern char *sender_address;
extern char *progfile_pattern;
extern char *sieve_pattern;
extern int lmtp_mode;
extern char *lmtp_url_string;
extern int reuse_lmtp_address;
extern char *lmtp_group;
extern struct daemon_param daemon_param;
void close_fds (void);
int switch_user_id (struct mu_auth_data *auth, int user);
int maidag_stdio_delivery (int argc, char **argv);
int maidag_lmtp_server (void);
void mailer_err (char *fmt, ...);
void notify_biff (mu_mailbox_t mbox, char *name, size_t size);
void guess_retval (int ec);
int deliver (mu_mailbox_t imbx, char *name, char **errp);
int sieve_test (struct mu_auth_data *auth, mu_mailbox_t mbx);
int check_quota (struct mu_auth_data *auth, mu_off_t size, mu_off_t *rest);
#ifdef WITH_GUILE
struct mda_data
{
mu_mailbox_t mbox;
char *progfile;
char *progfile_pattern;
char **argv;
};
int prog_mda (struct mda_data *data);
extern int debug_guile;
#endif
struct mail_tmp;
int mail_tmp_begin (struct mail_tmp **pmtmp, const char *from);
int mail_tmp_add_line (struct mail_tmp *mtmp, char *buf, size_t buflen);
int mail_tmp_finish (struct mail_tmp *mtmp, mu_mailbox_t *mbox);
void mail_tmp_destroy (struct mail_tmp **pmtmp);
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004,
2005, 2007 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA */
#include "maidag.h"
#if defined (USE_MAILBOX_QUOTAS)
#define DEFRETVAL MQUOTA_UNLIMITED
mu_off_t groupquota = 5*1024*1024UL;
static int get_size (char *, mu_off_t *, char **);
int
get_size (char *str, mu_off_t *size, char **endp)
{
mu_off_t s;
s = strtol (str, &str, 0);
switch (*str)
{
case 0:
break;
case 'k':
case 'K':
s *= 1024;
break;
case 'm':
case 'M':
s *= 1024*1024;
break;
default:
*endp = str;
return -1;
}
*size = s;
return 0;
}
#define RETR_OK 0
#define RETR_UNLIMITED -1
#define RETR_FAILURE 1
int
fail_retrieve_quota (char *name, mu_off_t *quota)
{
mu_error (_("No quota retrieving mechanism"));
return RETR_FAILURE;
}
#ifdef USE_DBM
int
dbm_retrieve_quota (char *name, mu_off_t *quota)
{
DBM_FILE db;
DBM_DATUM named, contentd;
char buffer[64];
int unlimited = 0;
int rc;
if (!quotadbname)
return RETR_FAILURE;
if (mu_dbm_open (quotadbname, &db, MU_STREAM_READ, 0600))
{
mu_error (_("Cannot open %s: %s"), quotadbname, mu_strerror (errno));
return RETR_FAILURE;
}
memset (&named, 0, sizeof named);
memset (&contentd, 0, sizeof contentd);
MU_DATUM_PTR (named) = name;
MU_DATUM_SIZE (named) = strlen (name);
rc = mu_dbm_fetch (db, named, &contentd);
if (rc || !MU_DATUM_PTR (contentd))
{
/* User not in database, try default quota */
memset (&named, 0, sizeof named);
MU_DATUM_PTR (named) = "DEFAULT";
MU_DATUM_SIZE (named) = strlen ("DEFAULT");
rc = mu_dbm_fetch (db, named, &contentd);
if (rc)
{
/*mu_error (_("can't fetch data: %s"), strerror (rc));*/
return RETR_FAILURE;
}
if (!MU_DATUM_PTR (contentd))
return RETR_FAILURE;
}
if (strncasecmp("none",
MU_DATUM_PTR (contentd),
MU_DATUM_SIZE (contentd)) == 0)
unlimited = 1;
else if (MU_DATUM_SIZE (contentd) > sizeof(buffer)-1)
{
mu_error (ngettext ("Mailbox quota for `%s' is too big: %d digit",
"Mailbox quota for `%s' is too big: %d digits",
MU_DATUM_SIZE (contentd)),
name, MU_DATUM_SIZE (contentd));
*quota = groupquota;
}
else
{
char *p;
strncpy(buffer, MU_DATUM_PTR (contentd), MU_DATUM_SIZE (contentd));
buffer[MU_DATUM_SIZE (contentd)] = 0;
*quota = strtoul (buffer, &p, 0);
if (get_size (buffer, quota, &p))
{
mu_error (_("Bogus mailbox quota for `%s' (near `%s')"), name, p);
*quota = groupquota;
}
}
mu_dbm_close (db);
return unlimited ? RETR_UNLIMITED : RETR_OK;
}
# define default_retrieve_quota dbm_retrieve_quota
#else
# define default_retrieve_quota fail_retrieve_quota
#endif
#ifdef USE_SQL
#include <mailutils/sql.h>
/* FIXME: defined in auth/sql.c */
#include <auth/sql.h>
int
sql_retrieve_quota (char *name, mu_off_t *quota)
{
mu_sql_connection_t conn;
char *query_str;
int rc, status;
char *tmp;
size_t n;
query_str = mu_sql_expand_query (quota_query, name);
if (!query_str)
return RETR_FAILURE;
status = mu_sql_connection_init (&conn,
sql_interface,
mu_sql_host,
mu_sql_port,
mu_sql_user,
mu_sql_passwd,
mu_sql_db);
if (status)
{
mu_error ("%s. SQL error: %s",
mu_strerror (status), mu_sql_strerror (conn));
mu_sql_connection_destroy (&conn);
free (query_str);
return RETR_FAILURE;
}
status = mu_sql_connect (conn);
if (status)
{
mu_error ("%s. SQL error: %s",
mu_strerror (status), mu_sql_strerror (conn));
mu_sql_connection_destroy (&conn);
free (query_str);
return RETR_FAILURE;
}
status = mu_sql_query (conn, query_str);
free (query_str);
if (status)
{
mu_error (_("SQL Query failed: %s"),
(status == MU_ERR_SQL) ? mu_sql_strerror (conn) :
mu_strerror (status));
mu_sql_connection_destroy (&conn);
return RETR_FAILURE;
}
status = mu_sql_store_result (conn);
if (status)
{
mu_error (_("Cannot store SQL result: %s"),
(status == MU_ERR_SQL) ? mu_sql_strerror (conn) :
mu_strerror (status));
mu_sql_connection_destroy (&conn);
return RETR_FAILURE;
}
mu_sql_num_tuples (conn, &n);
if (n == 0)
{
rc = RETR_FAILURE;
}
else
{
rc = RETR_OK;
tmp = NULL;
status = mu_sql_get_column (conn, 0, 0, &tmp);
if (status)
{
mu_error (_("Cannot retrieve mailbox quota from SQL: %s"),
(status == MU_ERR_SQL) ? mu_sql_strerror (conn) :
mu_strerror (status));
rc = RETR_FAILURE;
}
else if (tmp == NULL || tmp[0] == 0 || strcasecmp (tmp, "none") == 0)
rc = RETR_UNLIMITED;
else
{
char *p;
if (get_size (tmp, quota, &p))
{
mu_error (_("Bogus mailbox quota for `%s' (near `%s')"),
name, p);
*quota = groupquota;
}
}
}
mu_sql_release_result (conn);
mu_sql_disconnect (conn);
mu_sql_connection_destroy (&conn);
return rc;
}
#endif
static int
retrieve_quota (struct mu_auth_data *auth, mu_off_t *quota)
{
if (MU_HAS_QUOTA (auth))
{
if (auth->quota == 0)
return RETR_UNLIMITED;
*quota = auth->quota;
return RETR_OK;
}
#ifdef USE_SQL
if (quota_query)
return sql_retrieve_quota (auth->name, quota);
#endif
return default_retrieve_quota (auth->name, quota);
}
int
check_quota (struct mu_auth_data *auth, mu_off_t size, mu_off_t *rest)
{
mu_off_t quota;
switch (retrieve_quota (auth, &quota))
{
case RETR_FAILURE:
return DEFRETVAL;
case RETR_UNLIMITED:
return MQUOTA_UNLIMITED;
case RETR_OK:
if (quota < size) /* Mailbox full */
return MQUOTA_EXCEEDED;
if (rest)
*rest = quota - size;
}
return MQUOTA_OK;
}
#endif /* USE_MAIL_QUOTA */
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2005,
2007 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA */
#include "maidag.h"
struct mail_tmp
{
mu_stream_t stream;
size_t line;
char *tempfile;
const char *from;
int had_nl;
};
int
mail_tmp_begin (struct mail_tmp **pmtmp, const char *from)
{
int status;
struct mail_tmp *mtmp = malloc (sizeof *mtmp);
if (!mtmp)
return ENOMEM;
memset (mtmp, 0, sizeof *mtmp);
mtmp->tempfile = mu_tempname (NULL);
if ((status = mu_file_stream_create (&mtmp->stream, mtmp->tempfile,
MU_STREAM_RDWR)))
{
free (mtmp);
mailer_err (_("Unable to open temporary file: %s"),
mu_strerror (status));
return status;
}
if ((status = mu_stream_open (mtmp->stream)))
{
free (mtmp);
mailer_err (_("unable to open temporary file: %s"),
mu_strerror (status));
return status;
}
mtmp->from = from;
*pmtmp = mtmp;
return 0;
}
int
mail_tmp_add_line (struct mail_tmp *mtmp, char *buf, size_t buflen)
{
int status = 0;
mtmp->line++;
if (mtmp->line == 1)
{
const char *from = mtmp->from;
if (buflen >= 5 && memcmp (buf, "From ", 5))
{
struct mu_auth_data *auth = NULL;
if (!from)
{
auth = mu_get_auth_by_uid (getuid ());
if (auth)
from = auth->name;
}
if (from)
{
time_t t;
char *envs;
time (&t);
asprintf (&envs, "From %s %s", from, ctime (&t));
status = mu_stream_sequential_write (mtmp->stream,
envs,
strlen (envs));
free (envs);
}
else
{
mailer_err (_("Cannot determine sender address"));
return EINVAL;
}
if (auth)
mu_auth_data_free (auth);
}
}
else if (buflen >= 5 && !memcmp (buf, "From ", 5))
{
static char *escape = ">";
status = mu_stream_sequential_write (mtmp->stream, escape, 1);
}
if (!status)
status = mu_stream_sequential_write (mtmp->stream, buf, buflen);
if (status)
{
mailer_err (_("Error writing temporary file: %s"), mu_strerror (status));
mu_stream_destroy (&mtmp->stream, mu_stream_get_owner (mtmp->stream));
}
mtmp->had_nl = buf[buflen-1] == '\n';
return status;
}
int
mail_tmp_finish (struct mail_tmp *mtmp, mu_mailbox_t *mbox)
{
int status;
static char *newline = "\n";
size_t n;
if (!mtmp->had_nl)
status = mu_stream_sequential_write (mtmp->stream, newline, 1);
status = mu_stream_sequential_write (mtmp->stream, newline, 1);
unlink (mtmp->tempfile);
free (mtmp->tempfile);
mtmp->tempfile = NULL;
if (status)
{
errno = status;
mailer_err (_("Error writing temporary file: %s"), mu_strerror (status));
mu_stream_destroy (&mtmp->stream, mu_stream_get_owner (mtmp->stream));
return status;
}
mu_stream_flush (mtmp->stream);
if ((status = mu_mailbox_create (mbox, "/dev/null"))
|| (status = mu_mailbox_open (*mbox, MU_STREAM_READ))
|| (status = mu_mailbox_set_stream (*mbox, mtmp->stream)))
{
mailer_err (_("Error opening temporary file: %s"), mu_strerror (status));
mu_stream_destroy (&mtmp->stream, mu_stream_get_owner (mtmp->stream));
return status;
}
status = mu_mailbox_messages_count (*mbox, &n);
if (status)
{
errno = status;
mailer_err (_("Error creating temporary message: %s"),
mu_strerror (status));
mu_stream_destroy (&mtmp->stream, mu_stream_get_owner (mtmp->stream));
return status;
}
mtmp->stream = NULL;
mtmp->line = 0;
return status;
}
void
mail_tmp_destroy (struct mail_tmp **pmtmp)
{
struct mail_tmp *mtmp = *pmtmp;
if (mtmp)
{
if (mtmp->tempfile)
{
unlink (mtmp->tempfile);
free (mtmp->tempfile);
}
mu_stream_destroy (&mtmp->stream, mu_stream_get_owner (mtmp->stream));
free (*pmtmp);
*pmtmp = NULL;
}
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2005,
2007 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA */
#include "maidag.h"
#ifdef WITH_GUILE
#include <mailutils/guile.h>
int debug_guile;
SCM mda_catch_body (void *data, mu_mailbox_t mbox);
SCM mda_catch_handler (void *unused, SCM tag, SCM throw_args);
int mda_next (void *data, mu_mailbox_t mbox);
int mda_exit (void *data, mu_mailbox_t mbox);
int mda_init (void *data);
int
prog_mda (struct mda_data *data)
{
char *x_argv[2];
mu_guimb_param_t param;
x_argv[0] = "maidag";
x_argv[1] = NULL;
param.debug_guile = debug_guile;
param.mbox = data->mbox;
param.user_name = NULL;
param.init = mda_init;
param.catch_body = mda_catch_body;
param.catch_handler = mda_catch_handler;
param.next = mda_next;
param.exit = mda_exit;
param.data = data;
mu_process_mailbox (1, x_argv, &param);
return EX_UNAVAILABLE;
}
int
mda_init (void *data)
{
struct mda_data *md = data;
md->progfile = mu_expand_path_pattern (md->progfile_pattern, md->argv[0]);
return 0;
}
static void
mda_switch_to_user (struct mda_data *md)
{
struct mu_auth_data *auth = NULL;
if (md && *md->argv != NULL)
auth = mu_get_auth_by_name (*md->argv);
if (auth)
{
switch_user_id (auth, 1);
chdir (auth->dir);
mu_auth_data_free (auth);
}
else
{
switch_user_id (auth, 0);
chdir ("/");
}
}
SCM
mda_catch_body (void *data, mu_mailbox_t mbox)
{
struct mda_data *md = data;
mu_message_t mesg = NULL;
mu_attribute_t attr = NULL;
if (access (md->progfile, R_OK))
{
if (debug_level > 2)
syslog (LOG_DEBUG, _("Access to %s failed: %m"), md->progfile);
}
else
{
mda_switch_to_user (md);
scm_primitive_load (scm_makfrom0str (md->progfile));
}
mu_mailbox_get_message (mbox, 1, &mesg);
mu_message_get_attribute (mesg, &attr);
if (mu_attribute_is_deleted (attr))
return SCM_BOOL_F;
mda_switch_to_user (NULL);
mda (md->mbox, md->argv[0]);
return SCM_BOOL_F;
}
SCM
mda_catch_handler (void *data, SCM tag, SCM throw_args)
{
exit_code = EX_TEMPFAIL;
return scm_handle_by_message_noexit ("mail.local", tag, throw_args);
}
int
mda_next (void *data, mu_mailbox_t mbox)
{
struct mda_data *md = data;
mu_message_t mesg = NULL;
mu_attribute_t attr = NULL;
md->argv++;
if (*md->argv == NULL)
return 0;
if (md->progfile)
free (md->progfile);
md->progfile = mu_expand_path_pattern (md->progfile_pattern, *md->argv);
mu_mailbox_get_message (mbox, 1, &mesg);
mu_message_get_attribute (mesg, &attr);
mu_attribute_unset_deleted (attr);
return md->progfile != NULL;
}
int
mda_exit (void *data, mu_mailbox_t mbox)
{
return exit_code;
}
#endif
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2007 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA */
#include "maidag.h"
void
close_fds ()
{
int i;
long fdlimit = MAXFD;
#if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX)
fdlimit = sysconf (_SC_OPEN_MAX);
#elif defined (HAVE_GETDTABLESIZE)
fdlimit = getdtablesize ();
#endif
for (i = 3; i < fdlimit; i++)
close (i);
}
int
switch_user_id (struct mu_auth_data *auth, int user)
{
int rc;
uid_t uid;
if (!auth || auth->change_uid == 0)
return 0;
if (user)
uid = auth->uid;
else
uid = 0;
#if defined(HAVE_SETREUID)
rc = setreuid (0, uid);
#elif defined(HAVE_SETRESUID)
rc = setresuid (-1, uid, -1);
#elif defined(HAVE_SETEUID)
rc = seteuid (uid);
#else
# error "No way to reset user privileges?"
#endif
if (rc < 0)
mailer_err ("setreuid(0, %d): %s (r=%d, e=%d)",
uid, strerror (errno), getuid (), geteuid ());
return rc;
}
void
mailer_err (char *fmt, ...)
{
va_list ap;
guess_retval (errno);
va_start (ap, fmt);
if (!lmtp_mode && !log_to_stderr)
{
vfprintf (stderr, fmt, ap);
fputc ('\n', stderr);
}
mu_verror (fmt, ap);
va_end (ap);
}
int temp_errors[] = {
#ifdef EAGAIN
EAGAIN, /* Try again */
#endif
#ifdef EBUSY
EBUSY, /* Device or resource busy */
#endif
#ifdef EPROCLIM
EPROCLIM, /* Too many processes */
#endif
#ifdef EUSERS
EUSERS, /* Too many users */
#endif
#ifdef ECONNABORTED
ECONNABORTED, /* Software caused connection abort */
#endif
#ifdef ECONNREFUSED
ECONNREFUSED, /* Connection refused */
#endif
#ifdef ECONNRESET
ECONNRESET, /* Connection reset by peer */
#endif
#ifdef EDEADLK
EDEADLK, /* Resource deadlock would occur */
#endif
#ifdef EDEADLOCK
EDEADLOCK, /* Resource deadlock would occur */
#endif
#ifdef EFBIG
EFBIG, /* File too large */
#endif
#ifdef EHOSTDOWN
EHOSTDOWN, /* Host is down */
#endif
#ifdef EHOSTUNREACH
EHOSTUNREACH, /* No route to host */
#endif
#ifdef EMFILE
EMFILE, /* Too many open files */
#endif
#ifdef ENETDOWN
ENETDOWN, /* Network is down */
#endif
#ifdef ENETUNREACH
ENETUNREACH, /* Network is unreachable */
#endif
#ifdef ENETRESET
ENETRESET, /* Network dropped connection because of reset */
#endif
#ifdef ENFILE
ENFILE, /* File table overflow */
#endif
#ifdef ENOBUFS
ENOBUFS, /* No buffer space available */
#endif
#ifdef ENOMEM
ENOMEM, /* Out of memory */
#endif
#ifdef ENOSPC
ENOSPC, /* No space left on device */
#endif
#ifdef EROFS
EROFS, /* Read-only file system */
#endif
#ifdef ESTALE
ESTALE, /* Stale NFS file handle */
#endif
#ifdef ETIMEDOUT
ETIMEDOUT, /* Connection timed out */
#endif
#ifdef EWOULDBLOCK
EWOULDBLOCK, /* Operation would block */
#endif
};
void
guess_retval (int ec)
{
int i;
/* Temporary failures override hard errors. */
if (exit_code == EX_TEMPFAIL)
return;
#ifdef EDQUOT
if (ec == EDQUOT)
{
exit_code = EX_QUOTA();
return;
}
#endif
for (i = 0; i < sizeof (temp_errors)/sizeof (temp_errors[0]); i++)
if (temp_errors[i] == ec)
{
exit_code = EX_TEMPFAIL;
return;
}
exit_code = EX_UNAVAILABLE;
}
......@@ -35,6 +35,7 @@ mail_local_LDADD = \
${MU_LIB_MH}\
${MU_LIB_MAILDIR}\
${MU_LIB_AUTH}\
${MU_LIB_MAILER}\
@MU_AUTHLIBS@\
${MU_LIB_MAILUTILS} \
@MU_COMMON_LIBRARIES@
......
......@@ -317,7 +317,8 @@ _sieve_action_log (void *user_name,
{
char *diag = NULL;
vasprintf (&diag, fmt, ap);
syslog (LOG_NOTICE, _("(user %s) %s: %s"), (char*) user_name, text, diag);
syslog (LOG_NOTICE, _("(user %s) %s: %s"),
(char*) user_name, text, diag);
free (diag);
}
else
......@@ -360,7 +361,7 @@ main (int argc, char *argv[])
/* Default locker settings */
mu_locker_set_default_flags (MU_LOCKER_PID|MU_LOCKER_RETRY,
mu_locker_assign);
mu_locker_assign);
mu_locker_set_default_retry_timeout (1);
mu_locker_set_default_retry_count (300);
......
......@@ -81,7 +81,7 @@ static int amd_messages_count (mu_mailbox_t, size_t *);
static int amd_messages_recent (mu_mailbox_t, size_t *);
static int amd_message_unseen (mu_mailbox_t, size_t *);
static int amd_expunge (mu_mailbox_t);
static int amd_save_attributes (mu_mailbox_t);
static int amd_sync (mu_mailbox_t);
static int amd_uidnext (mu_mailbox_t mailbox, size_t *puidnext);
static int amd_uidvalidity (mu_mailbox_t, unsigned long *);
static int amd_scan (mu_mailbox_t, size_t, size_t *);
......@@ -281,7 +281,7 @@ amd_init_mailbox (mu_mailbox_t mailbox, size_t amd_size,
mailbox->_messages_recent = amd_messages_recent;
mailbox->_message_unseen = amd_message_unseen;
mailbox->_expunge = amd_expunge;
mailbox->_save_attributes = amd_save_attributes;
mailbox->_sync = amd_sync;
mailbox->_uidvalidity = amd_uidvalidity;
mailbox->_uidnext = amd_uidnext;
......@@ -862,7 +862,7 @@ amd_expunge (mu_mailbox_t mailbox)
}
static int
amd_save_attributes (mu_mailbox_t mailbox)
amd_sync (mu_mailbox_t mailbox)
{
struct _amd_data *amd = mailbox->data;
struct _amd_message *mhm;
......
......@@ -419,24 +419,23 @@ _file_open (mu_stream_t stream)
char* filename = 0;
int flags = 0;
assert(fs);
if (!fs || !fs->filename)
return EINVAL;
filename = fs->filename;
assert(filename);
if (fs->file)
{
fclose (fs->file);
fs->file = NULL;
}
mu_stream_get_flags(stream, &flags);
mu_stream_get_flags (stream, &flags);
/* Map the flags to the system equivalent. */
if (flags & MU_STREAM_WRITE && flags & MU_STREAM_READ)
return EINVAL;
else if (flags & MU_STREAM_WRITE)
else if (flags & (MU_STREAM_WRITE|MU_STREAM_APPEND))
flg = O_WRONLY;
else if (flags & MU_STREAM_RDWR)
flg = O_RDWR;
......@@ -453,14 +452,14 @@ _file_open (mu_stream_t stream)
if (flags & MU_STREAM_CREAT)
{
/* First see if the file already exists. */
fd = open(filename, flg);
fd = open (filename, flg);
if (fd == -1)
{
/* Oops bail out. */
if (errno != ENOENT)
return errno;
/* Race condition here when creating the file ??. */
fd = open(filename, flg|O_CREAT|O_EXCL, 0600);
fd = open (filename, flg|O_CREAT|O_EXCL, 0600);
if (fd < 0)
return errno;
}
......@@ -474,16 +473,15 @@ _file_open (mu_stream_t stream)
/* We have to make sure that We did not open
a symlink. From Casper D. in bugtraq. */
if ((flg & MU_STREAM_CREAT) ||
(flg & MU_STREAM_RDWR) ||
(flg & MU_STREAM_WRITE))
if (flg & (MU_STREAM_CREAT | MU_STREAM_RDWR
| MU_STREAM_WRITE | MU_STREAM_APPEND))
{
struct stat fdbuf, filebuf;
/* The next two stats should never fail. */
if (fstat(fd, &fdbuf) == -1)
if (fstat (fd, &fdbuf) == -1)
return errno;
if (lstat(filename, &filebuf) == -1)
if (lstat (filename, &filebuf) == -1)
return errno;
/* Now check that: file and fd reference the same file,
......
......@@ -177,8 +177,9 @@ mu_folder_destroy (mu_folder_t *pfolder)
/* Notify the observers. */
if (folder->observable)
{
mu_observable_notify (folder->observable, MU_EVT_FOLDER_DESTROY);
mu_observable_destroy (&(folder->observable), folder);
mu_observable_notify (folder->observable, MU_EVT_FOLDER_DESTROY,
folder);
mu_observable_destroy (&folder->observable, folder);
}
if (folder->_destroy)
folder->_destroy (folder);
......
......@@ -174,8 +174,8 @@ mu_mailbox_destroy (mu_mailbox_t *pmbox)
/* Notify the observers. */
if (mbox->observable)
{
mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_DESTROY);
mu_observable_destroy (&(mbox->observable), mbox);
mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_DESTROY, mbox);
mu_observable_destroy (&mbox->observable, mbox);
}
/* Call the concrete mailbox _destroy method. So it can clean itself. */
......@@ -244,7 +244,8 @@ mu_mailbox_flush (mu_mailbox_t mbox, int expunge)
if (!mbox)
return EINVAL;
if (!(mbox->flags & (MU_STREAM_RDWR|MU_STREAM_WRITE|MU_STREAM_APPEND)))
return EACCES;
return 0;
mu_mailbox_messages_count (mbox, &total);
if (mbox->flags & MU_STREAM_APPEND)
i = total;
......@@ -258,10 +259,12 @@ mu_mailbox_flush (mu_mailbox_t mbox, int expunge)
mu_message_get_attribute (msg, &attr);
mu_attribute_set_seen (attr);
}
if (expunge)
status = mu_mailbox_expunge (mbox);
else
status = mu_mailbox_save_attributes (mbox);
status = mu_mailbox_sync (mbox);
return status;
}
......@@ -285,6 +288,15 @@ mu_mailbox_get_message (mu_mailbox_t mbox, size_t msgno, mu_message_t *pmsg)
}
int
mu_mailbox_quick_get_message (mu_mailbox_t mbox, mu_message_qid_t qid,
mu_message_t *pmsg)
{
if (mbox == NULL || mbox->_quick_get_message == NULL)
return MU_ERR_EMPTY_VFN;
return mbox->_quick_get_message (mbox, qid, pmsg);
}
int
mu_mailbox_messages_count (mu_mailbox_t mbox, size_t *num)
{
if (mbox == NULL || mbox->_messages_count == NULL)
......@@ -309,13 +321,24 @@ mu_mailbox_message_unseen (mu_mailbox_t mbox, size_t *num)
}
int
mu_mailbox_sync (mu_mailbox_t mbox)
{
if (mbox == NULL || mbox->_sync == NULL)
return MU_ERR_EMPTY_VFN;
if (!(mbox->flags & (MU_STREAM_RDWR|MU_STREAM_WRITE|MU_STREAM_APPEND)))
return 0;
return mbox->_sync (mbox);
}
/* Historic alias: */
int
mu_mailbox_save_attributes (mu_mailbox_t mbox)
{
if (mbox == NULL || mbox->_save_attributes == NULL)
if (mbox == NULL || mbox->_sync == NULL)
return MU_ERR_EMPTY_VFN;
if (!(mbox->flags & (MU_STREAM_RDWR|MU_STREAM_WRITE|MU_STREAM_APPEND)))
return EACCES;
return mbox->_save_attributes (mbox);
return mbox->_sync (mbox);
}
int
......@@ -347,9 +370,34 @@ mu_mailbox_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount)
int
mu_mailbox_get_size (mu_mailbox_t mbox, mu_off_t *psize)
{
if (mbox == NULL || mbox->_get_size == NULL)
int status;
if (mbox == NULL)
return MU_ERR_EMPTY_VFN;
return mbox->_get_size (mbox, psize);
if (mbox->_get_size == NULL
|| (status = mbox->_get_size (mbox, psize)) == ENOSYS)
{
/* Fall back to brute-force method */
size_t i, total;
mu_off_t size = 0;
status = mu_mailbox_messages_count (mbox, &total);
if (status)
return status;
for (i = 1; i <= total; i++)
{
mu_message_t msg;
size_t msgsize;
status = mu_mailbox_get_message (mbox, i, &msg);
if (status)
return status;
status = mu_message_size (msg, &msgsize);
if (status)
return status;
size += msgsize;
}
*psize = size;
}
return status;
}
int
......@@ -408,7 +456,7 @@ mu_mailbox_set_stream (mu_mailbox_t mbox, mu_stream_t stream)
if (mbox == NULL)
return MU_ERR_MBX_NULL;
if (mbox->stream)
mu_stream_destroy (&(mbox->stream), mbox);
mu_stream_destroy (&mbox->stream, mbox);
mbox->stream = stream;
return 0;
}
......@@ -451,7 +499,7 @@ mu_mailbox_get_observable (mu_mailbox_t mbox, mu_observable_t *pobservable)
if (mbox->observable == NULL)
{
int status = mu_observable_create (&(mbox->observable), mbox);
int status = mu_observable_create (&mbox->observable, mbox);
if (status != 0)
return status;
}
......
......@@ -157,8 +157,9 @@ mu_mailer_destroy (mu_mailer_t * pmailer)
if (mailer->observable)
{
mu_observable_notify (mailer->observable, MU_EVT_MAILER_DESTROY);
mu_observable_destroy (&(mailer->observable), mailer);
mu_observable_notify (mailer->observable, MU_EVT_MAILER_DESTROY,
mailer);
mu_observable_destroy (&mailer->observable, mailer);
}
/* Call the object destructor. */
......
......@@ -115,7 +115,8 @@ mu_message_destroy (mu_message_t *pmsg, void *owner)
/* FIXME: to be removed since we do not support this event. */
if (msg->observable)
{
mu_observable_notify (msg->observable, MU_EVT_MESSAGE_DESTROY);
mu_observable_notify (msg->observable, MU_EVT_MESSAGE_DESTROY,
msg);
mu_observable_destroy (&(msg->observable), msg);
}
......@@ -649,8 +650,31 @@ mu_message_get_uidl (mu_message_t msg, char *buffer, size_t buflen, size_t *pwri
}
int
mu_message_get_qid (mu_message_t msg, mu_message_qid_t *pqid)
{
if (msg == NULL)
return EINVAL;
if (!msg->_get_qid)
return ENOSYS;
return msg->_get_qid (msg, pqid);
}
int
mu_message_set_qid (mu_message_t msg,
int (*_get_qid) (mu_message_t, mu_message_qid_t *),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_get_qid = _get_qid;
return 0;
}
int
mu_message_set_uid (mu_message_t msg, int (*_get_uid) (mu_message_t, size_t *),
void *owner)
void *owner)
{
if (msg == NULL)
return EINVAL;
......
......@@ -49,7 +49,7 @@ mu_observer_destroy (mu_observer_t *pobserver, void *owner)
if (observer->owner == owner || observer->flags & MU_OBSERVER_NO_CHECK)
{
if (observer->_destroy)
observer->_destroy (observer);
observer->_destroy (observer, observer->_action_data);
free (observer);
}
*pobserver = NULL;
......@@ -63,18 +63,19 @@ mu_observer_get_owner (mu_observer_t observer)
}
int
mu_observer_action (mu_observer_t observer, size_t type)
mu_observer_action (mu_observer_t observer, size_t type, void *data)
{
if (observer == NULL)
return EINVAL;
if (observer->_action)
return observer->_action (observer, type);
return observer->_action (observer, type, data, observer->_action_data);
return 0;
}
int
mu_observer_set_action (mu_observer_t observer,
int (*_action) (mu_observer_t, size_t), void *owner)
int (*_action) (mu_observer_t, size_t, void *, void *),
void *owner)
{
if (observer == NULL)
return EINVAL;
......@@ -85,8 +86,20 @@ mu_observer_set_action (mu_observer_t observer,
}
int
mu_observer_set_destroy (mu_observer_t observer, int (*_destroy) (mu_observer_t),
void *owner)
mu_observer_set_action_data (mu_observer_t observer, void *data, void *owner)
{
if (observer == NULL)
return EINVAL;
if (observer->owner != owner)
return EACCES;
observer->_action_data = data;
return 0;
}
int
mu_observer_set_destroy (mu_observer_t observer,
int (*_destroy) (mu_observer_t, void *),
void *owner)
{
if (observer == NULL)
return EINVAL;
......@@ -214,7 +227,7 @@ mu_observable_detach (mu_observable_t observable, mu_observer_t observer)
}
int
mu_observable_notify (mu_observable_t observable, int type)
mu_observable_notify (mu_observable_t observable, int type, void *data)
{
mu_iterator_t iterator;
event_t event = NULL;
......@@ -231,7 +244,7 @@ mu_observable_notify (mu_observable_t observable, int type)
mu_iterator_current (iterator, (void **)&event);
if (event && event->type & type)
{
status |= mu_observer_action (event->observer, type);
status |= mu_observer_action (event->observer, type, data);
}
}
mu_iterator_destroy (&iterator);
......
......@@ -148,7 +148,7 @@ main (int argc, char **argv)
mh_msgset_current (mbox, &msgset, 0);
mh_global_save_state ();
mu_mailbox_save_attributes (mbox);
mu_mailbox_sync (mbox);
mu_mailbox_close (mbox);
mu_mailbox_destroy (&mbox);
return rc;
......
......@@ -469,7 +469,7 @@ main (int argc, char **argv)
rc = mh_whatnow (&wh_env, initial_edit);
mu_mailbox_save_attributes (mbox);
mu_mailbox_sync (mbox);
mu_mailbox_close (mbox);
mu_mailbox_destroy (&mbox);
return rc;
......
......@@ -442,7 +442,7 @@ main (int argc, char **argv)
rc = mh_whatnow (&wh_env, initial_edit);
mu_mailbox_save_attributes (mbox);
mu_mailbox_sync (mbox);
mu_mailbox_close (mbox);
mu_mailbox_destroy (&mbox);
return rc;
......
......@@ -147,9 +147,9 @@ opt_handler (int key, char *arg, void *unused, struct argp_state *state)
return 0;
}
/* Observable Action this is being call at every message discover. */
/* Observable Action this is called at every message discover. */
static int
action (mu_observer_t o, size_t type)
action (mu_observer_t o, size_t type, void *data, void *action_data)
{
static int counter;
mu_mailbox_t mbox;
......
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.