/* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 1999, 2001 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 2, 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 "imap4d.h" /*FIXME: should be global? */ typedef int (*nsfp_t) __P ((void *closure, int ns, char *path, int delim)); struct namespace_t { int subdir_c; char **subdir_v; }; struct namespace_t namespace[NS_MAX]; /* Note: str is not supposed to be NULL */ int set_namespace (int i, char *str) { char *p, *save; struct namespace_t ns; /* first, estimate the number of items in subdir_v array: */ ns.subdir_c = 1; for (p = strchr (str, ':'); p && *p; p = strchr (p + 1, ':')) ns.subdir_c++; /* Now allocate the memory */ ns.subdir_v = calloc (ns.subdir_c, sizeof (ns.subdir_v[0])); /* Fill in the array */ if (ns.subdir_c == 1) { ns.subdir_v[0] = mu_normalize_path (strdup (str), "/"); } else { ns.subdir_c = 0; for (p = strtok_r (str, ":", &save); p; p = strtok_r (NULL, ":", &save)) { ns.subdir_v[ns.subdir_c++] = mu_normalize_path (strdup (p), "/"); } } namespace[i] = ns; return 0; } static char * printable_pathname (char *str) { if (strncmp (str, homedir, strlen (homedir)) == 0) { str += strlen (homedir); if (str[0] == '/') str++; } return str; } static void print_namespace (int n) { int i; if (namespace[n].subdir_c == 0) { util_send ("NIL"); return; } util_send ("("); for (i = 0; i < namespace[n].subdir_c; i++) { util_send ("(\"%s\" \"/\")", printable_pathname (namespace[n].subdir_v[i])); } util_send (")"); } static int namespace_enumerate (int ns, nsfp_t f, void *closure) { int i, rc; for (i = 0; i < namespace[ns].subdir_c; i++) if ((rc = (*f) (closure, ns, namespace[ns].subdir_v[i], '/'))) return rc; return 0; } static int namespace_enumerate_all (nsfp_t f, void *closure) { return namespace_enumerate (NS_PRIVATE, f, closure) || namespace_enumerate (NS_OTHER, f, closure) || namespace_enumerate (NS_SHARED, f, closure); } int imap4d_namespace (struct imap4d_command *command, char *arg) { if (*arg) return util_finish (command, RESP_BAD, "Too many arguments"); util_send ("* NAMESPACE "); print_namespace (NS_PRIVATE); util_send (" "); print_namespace (NS_OTHER); util_send (" "); print_namespace (NS_SHARED); util_send ("\r\n"); return util_finish (command, RESP_OK, "Completed"); } struct namespace_info { char *name; int namelen; int ns; int exact; }; static int check_namespace (void *closure, int ns, char *path, int delim) { struct namespace_info *p = (struct namespace_info *) closure; int len = strlen (path); if ((len == 0 && p->namelen == len) || (len > 0 && strncmp (path, p->name, strlen (path)) == 0)) { p->ns = ns; p->exact = len == p->namelen; return 1; } return 0; } static int risky_pattern (const char *pattern, int delim) { for (; *pattern && *pattern != delim; pattern++) { if (*pattern == '%' || *pattern == '*') return 1; } return 0; } char * namespace_checkfullpath (char *name, const char *pattern, const char *delim) { struct namespace_info info; char *p, *path = NULL; char *scheme = NULL; p = strchr (name, ':'); if (p) { size_t size = p - name + 1; scheme = malloc (size + 1); if (!scheme) return NULL; memcpy (scheme, name, size); scheme[size] = 0; name = p + 1; } path = util_getfullpath (name, delim); if (!path) { free (scheme); return path; } info.name = path; info.namelen = strlen (path); if (!namespace_enumerate_all (check_namespace, &info)) { free (scheme); free (path); return NULL; } if (pattern && info.ns == NS_OTHER && info.exact && risky_pattern (pattern, '/')) { free (scheme); free (path); return NULL; } if (scheme) { char *pathstr = malloc (strlen (scheme) + strlen (path) + 2); if (pathstr) { strcpy (pathstr, scheme); strcat (pathstr, path); } free (scheme); free (path); path = pathstr; } return path; } char * namespace_getfullpath (char *name, const char *delim) { if (strcasecmp (name, "INBOX") == 0 && auth_data->change_uid) name = strdup (auth_data->mailbox); else name = namespace_checkfullpath (name, NULL, delim); return name; } int namespace_init (char *path) { set_namespace (NS_PRIVATE, path); return 0; }