summaryrefslogtreecommitdiff
path: root/libmailutils/mailbox/mbx_default.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmailutils/mailbox/mbx_default.c')
-rw-r--r--libmailutils/mailbox/mbx_default.c454
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;
+}

Return to:

Send suggestions and report system problems to the System administrator.