diff options
Diffstat (limited to 'libmailutils/mailbox/mbx_default.c')
-rw-r--r-- | libmailutils/mailbox/mbx_default.c | 454 |
1 files changed, 454 insertions, 0 deletions
diff --git a/libmailutils/mailbox/mbx_default.c b/libmailutils/mailbox/mbx_default.c new file mode 100644 index 000000000..348e7f7d9 --- /dev/null +++ b/libmailutils/mailbox/mbx_default.c @@ -0,0 +1,454 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008, + 2009, 2010 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <stdio.h> +#include <pwd.h> +#include <unistd.h> + +#include <confpaths.h> + +#include <mailutils/mailbox.h> +#include <mailutils/mutil.h> +#include <mailutils/debug.h> +#include <mailutils/error.h> +#include <mailutils/errno.h> +#include <mailutils/mu_auth.h> +#include <mailutils/vartab.h> +#include <mailutils/folder.h> +#include <mailutils/auth.h> + +#include <mailutils/sys/mailbox.h> + +char *mu_ticket_file = "~/.mu-tickets"; + +static char *_mu_mailbox_pattern; + +static char *_default_folder_dir = "Mail"; +static char *_mu_folder_dir; + +static int +mu_normalize_mailbox_url (char **pout, const char *dir) +{ + int len; + int addslash = 0; +#define USERSUFFIX "${user}" + + if (!pout) + return MU_ERR_OUT_PTR_NULL; + + len = strlen (dir); + if (dir[len-1] == '=') + { + if (len > 5 && strcmp (dir + len - 5, "user=") == 0) + *pout = strdup (dir); + else + return MU_ERR_BAD_FILENAME; + } + else if (dir[len-1] != '/') + addslash = 1; + + *pout = malloc (strlen (dir) + (addslash ? 1 : 0) + sizeof USERSUFFIX); + if (!*pout) + return ENOMEM; + + strcpy (*pout, dir); + if (addslash) + strcat (*pout, "/"); + strcat (*pout, USERSUFFIX); +#undef USERSUFFIX + return 0; +} + +int +mu_set_mail_directory (const char *p) +{ + if (_mu_mailbox_pattern) + free (_mu_mailbox_pattern); + if (!p) + { + _mu_mailbox_pattern = NULL; + return 0; + } + return mu_normalize_mailbox_url (&_mu_mailbox_pattern, p); +} + +int +mu_set_mailbox_pattern (const char *pat) +{ + if (_mu_mailbox_pattern) + free (_mu_mailbox_pattern); + if (!pat) + { + _mu_mailbox_pattern = NULL; + return 0; + } + _mu_mailbox_pattern = strdup (pat); + return _mu_mailbox_pattern ? 0 : ENOMEM; +} + +void +mu_set_folder_directory (const char *p) +{ + if (_mu_folder_dir != _default_folder_dir) + free (_mu_folder_dir); + _mu_folder_dir = strdup (p); +} + +const char * +mu_mailbox_url () +{ + if (!_mu_mailbox_pattern) + mu_set_mail_directory (MU_PATH_MAILDIR); + return _mu_mailbox_pattern; +} + +const char * +mu_folder_directory () +{ + if (!_mu_folder_dir) + _mu_folder_dir = _default_folder_dir; + return _mu_folder_dir; +} + +int +mu_construct_user_mailbox_url (char **pout, const char *name) +{ + int rc; + const char *pat = mu_mailbox_url (); + mu_vartab_t vtab; + + mu_vartab_create (&vtab); + mu_vartab_define (vtab, "user", name, 1); + rc = mu_vartab_expand (vtab, pat, pout); + mu_vartab_destroy (&vtab); + return rc; +} + +/* Is this a security risk? */ +#define USE_ENVIRON 1 + +static int +split_shortcut (const char *file, const char pfx[], char **user, char **rest) +{ + *user = NULL; + *rest = NULL; + + if (!strchr (pfx, file[0])) + return 0; + + if (*++file == 0) + return 0; + else + { + char *p = strchr (file, '/'); + int len; + if (p) + len = p - file + 1; + else + len = strlen (file) + 1; + + if (len == 1) + *user = NULL; + else + { + *user = calloc (1, len); + if (!*user) + return ENOMEM; + + memcpy (*user, file, len); + (*user)[len-1] = 0; + } + file += len-1; + if (file[0] == '/') + file++; + } + + if (file[0]) + { + *rest = strdup (file); + if (!*rest) + { + free (*user); + return ENOMEM; + } + } + + return 0; +} + +static char * +get_homedir (const char *user) +{ + char *homedir = NULL; + struct mu_auth_data *auth = NULL; + + if (user) + { + auth = mu_get_auth_by_name (user); + if (auth) + homedir = auth->dir; + } + else + { +#ifdef USE_ENVIRON + /* NOTE: Should we honor ${HOME}? */ + homedir = getenv ("HOME"); + if (homedir == NULL) + { + auth = mu_get_auth_by_name (user); + if (auth) + homedir = auth->dir; + } +#else + auth = mu_get_auth_by_name (user); + if (auth) + homedir = auth->dir; +#endif + } + + if (homedir) + homedir = strdup (homedir); + mu_auth_data_free (auth); + return homedir; +} + +static int +user_mailbox_name (const char *user, char **mailbox_name) +{ +#ifdef USE_ENVIRON + if (!user) + user = (getenv ("LOGNAME")) ? getenv ("LOGNAME") : getenv ("USER"); +#endif + + if (user) + { + int rc = mu_construct_user_mailbox_url (mailbox_name, user); + if (rc) + return rc; + } + else + { + struct mu_auth_data *auth = mu_get_auth_by_uid (getuid ()); + + if (!auth) + { + mu_error ("Who am I?"); + return EINVAL; + } + *mailbox_name = strdup (auth->mailbox); + mu_auth_data_free (auth); + } + + return 0; +} + +static int +plus_expand (const char *file, char **buf) +{ + char *home; + const char *folder_dir = mu_folder_directory (); + int len; + + home = get_homedir (NULL); + if (!home) + return ENOENT; + + file++; + + if (folder_dir[0] == '/' || mu_is_proto (folder_dir)) + { + len = strlen (folder_dir) + strlen (file) + 2; + *buf = malloc (len); + sprintf (*buf, "%s/%s", folder_dir, file); + } + else + { + len = strlen (home) + strlen (folder_dir) + strlen (file) + 3; + *buf = malloc (len); + sprintf (*buf, "%s/%s/%s", home, folder_dir, file); + } + (*buf)[len-1] = 0; + + free (home); + return 0; +} + +static int +percent_expand (const char *file, char **mbox) +{ + char *user = NULL; + char *path = NULL; + int status; + + if ((status = split_shortcut (file, "%", &user, &path))) + return status; + + if (path) + { + free (user); + free (path); + return ENOENT; + } + + status = user_mailbox_name (user, mbox); + free (user); + return status; +} + +static void +attach_auth_ticket (mu_mailbox_t mbox) +{ + mu_folder_t folder = NULL; + mu_authority_t auth = NULL; + + if (mu_mailbox_get_folder (mbox, &folder) == 0 + && mu_folder_get_authority (folder, &auth) == 0 + && auth) + { + char *filename = mu_tilde_expansion (mu_ticket_file, "/", NULL); + mu_wicket_t wicket; + int rc; + + MU_DEBUG1 (mbox->debug, MU_DEBUG_TRACE1, + "Reading user ticket file %s\n", filename); + if ((rc = mu_file_wicket_create (&wicket, filename)) == 0) + { + mu_ticket_t ticket; + + if ((rc = mu_wicket_get_ticket (wicket, NULL, &ticket)) == 0) + { + rc = mu_authority_set_ticket (auth, ticket); + MU_DEBUG1 (mbox->debug, MU_DEBUG_TRACE1, + "Retrieved and set ticket: %d\n", rc); + } + else + MU_DEBUG1 (mbox->debug, MU_DEBUG_ERROR, + "Error retrieving ticket: %s\n", + mu_strerror (rc)); + mu_wicket_destroy (&wicket); + } + else + MU_DEBUG1 (mbox->debug, MU_DEBUG_ERROR, + "Error creating wicket: %s\n", mu_strerror (rc)); + free (filename); + } +} + +/* We are trying to be smart about the location of the mail. + mu_mailbox_create() is not doing this. + % --> system mailbox for the real uid + %user --> system mailbox for the given user + ~/file --> /home/user/file + ~user/file --> /home/user/file + +file --> /home/user/Mail/file + =file --> /home/user/Mail/file +*/ +int +mu_mailbox_create_default (mu_mailbox_t *pmbox, const char *mail) +{ + char *mbox = NULL; + char *tmp_mbox = NULL; + char *p; + int status = 0; + + /* Sanity. */ + if (pmbox == NULL) + return MU_ERR_OUT_PTR_NULL; + + if (mail && *mail == 0) + mail = NULL; + + if (mail == NULL) + { + if (!_mu_mailbox_pattern) + { + /* Other utilities may not understand GNU mailutils url namespace, so + use FOLDER instead, to not confuse others by using MAIL. */ + mail = getenv ("FOLDER"); + if (!mail) + { + /* Fallback to well-known environment. */ + mail = getenv ("MAIL"); + } + } + + if (!mail) + { + if ((status = user_mailbox_name (NULL, &tmp_mbox))) + return status; + mail = tmp_mbox; + } + } + + p = mu_tilde_expansion (mail, "/", NULL); + if (tmp_mbox) + free (tmp_mbox); + tmp_mbox = p; + mail = tmp_mbox; + if (!mail) + return ENOMEM; + + switch (mail[0]) + { + case '%': + status = percent_expand (mail, &mbox); + break; + + case '+': + case '=': + status = plus_expand (mail, &mbox); + break; + + case '/': + mbox = strdup (mail); + break; + + default: + if (!mu_is_proto (mail)) + { + p = mu_getcwd(); + mbox = malloc (strlen (p) + strlen (mail) + 2); + sprintf (mbox, "%s/%s", p, mail); + free (p); + } + else + mbox = strdup (mail); + break; + } + + if (tmp_mbox) + free (tmp_mbox); + + if (status) + return status; + + status = mu_mailbox_create (pmbox, mbox); + free (mbox); + if (status == 0) + attach_auth_ticket (*pmbox); + + return status; +} |