Commit d8fc9605 d8fc960556176bf5fe11ff7fd0b3656b04c59326 by Sergey Poznyakoff

initial NAMESPACE implementation

1 parent 4d767fac
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include "imap4d.h"
19
20 /*FIXME: should be global? */
21 typedef int (*nsfp_t) __P((void *closure, int ns, char *path, int delim));
22
23 struct namespace_t
24 {
25 int subdir_c;
26 char **subdir_v;
27 };
28
29 struct namespace_t namespace[NS_MAX];
30
31 /* Note: str is not supposed to be NULL */
32 int
33 set_namespace(int i, char *str)
34 {
35 char *p, *save;
36 struct namespace_t ns;
37
38 /* first, estimate the number of items in subdir_v array: */
39 ns.subdir_c = 1;
40 for (p = strchr(str, ':'); p && *p; p = strchr(p+1, ':'))
41 ns.subdir_c++;
42
43 /* Now allocate the memory */
44 ns.subdir_v = calloc(ns.subdir_c, sizeof(ns.subdir_v[0]));
45
46 /* Fill in the array */
47 if (ns.subdir_c == 1)
48 {
49 ns.subdir_v[0] = util_normalize_path(strdup(str), "/");
50 }
51 else
52 {
53 ns.subdir_c = 0;
54 for (p = strtok_r(str, ":", &save); p; p = strtok_r(NULL, ":", &save))
55 {
56 ns.subdir_v[ns.subdir_c++] = util_normalize_path(strdup(p), "/");
57 }
58 }
59
60 namespace[i] = ns;
61
62 return 0;
63 }
64
65 static char *
66 printable_pathname(char *str)
67 {
68 if (strncmp(str, homedir, strlen(homedir)) == 0)
69 {
70 str += strlen(homedir);
71 if (str[0] == '/')
72 str++;
73 }
74 return str;
75 }
76
77 static int
78 print_namespace(int n)
79 {
80 int i;
81
82 if (namespace[n].subdir_c == 0)
83 {
84 util_send("NIL");
85 return;
86 }
87
88 util_send("(");
89 for (i = 0; i < namespace[n].subdir_c; i++)
90 {
91 util_send("(\"%s\" \"/\")", printable_pathname(namespace[n].subdir_v[i]));
92 }
93 util_send(")");
94 }
95
96 int
97 namespace_enumerate(int ns, nsfp_t f, void *closure)
98 {
99 int i, rc;
100
101 for (i = 0; i < namespace[ns].subdir_c; i++)
102 if (rc = (*f)(closure, ns, namespace[ns].subdir_v[i], '/'))
103 return rc;
104 return 0;
105 }
106
107 int
108 namespace_enumerate_all(nsfp_t f, void *closure)
109 {
110 return namespace_enumerate(NS_PRIVATE, f, closure)
111 || namespace_enumerate(NS_OTHER, f, closure)
112 || namespace_enumerate(NS_SHARED, f, closure);
113 }
114
115 int
116 imap4d_namespace(struct imap4d_command *command, char *arg)
117 {
118 if (! (command->states & state))
119 return util_finish (command, RESP_BAD, "Wrong state");
120 if (*arg)
121 return util_finish (command, RESP_BAD, "Too many arguments");
122
123 util_send("* NAMESPACE ");
124
125 print_namespace(NS_PRIVATE);
126 util_send(" ");
127 print_namespace(NS_OTHER);
128 util_send(" ");
129 print_namespace(NS_SHARED);
130 util_send("\r\n");
131
132 return util_finish (command, RESP_OK, "Completed");
133 }
134
135
136 struct namespace_info
137 {
138 char *name;
139 int namelen;
140 int ns;
141 int exact;
142 };
143
144 static int
145 check_namespace (void *closure, int ns, char *path, int delim)
146 {
147 struct namespace_info *p = (struct namespace_info *)closure;
148 int len = strlen(path);
149 if ((len == 0 && p->namelen == len)
150 || (len > 0 && strncmp(path, p->name, strlen(path)) == 0))
151 {
152 p->ns = ns;
153 p->exact = len == p->namelen;
154 return 1;
155 }
156 return 0;
157 }
158
159 static int
160 risky_pattern(const char *pattern, int delim)
161 {
162 for (; *pattern && *pattern != delim; pattern++)
163 {
164 if (*pattern == '%' || *pattern == '*')
165 return 1;
166 }
167 return 0;
168 }
169
170 char *
171 namespace_checkfullpath (char *name, const char *pattern, const char *delim)
172 {
173 struct namespace_info info;
174 char *path = util_getfullpath(name, delim);
175
176 if (!path)
177 return path;
178
179 util_normalize_path(path, "/");
180
181 info.name = path;
182 info.namelen = strlen(path);
183 if (!namespace_enumerate_all(check_namespace, &info))
184 {
185 free(path);
186 return NULL;
187 }
188
189 if (pattern &&
190 info.ns == NS_OTHER && info.exact && risky_pattern(pattern, '/'))
191 {
192 free(path);
193 return NULL;
194 }
195
196 return path;
197 }
198
199 char *
200 namespace_getfullpath (char *name, const char *delim)
201 {
202 return namespace_checkfullpath (name, NULL, delim);
203 }
204
205
206 int
207 namespace_init(char *path)
208 {
209 set_namespace(NS_PRIVATE, path);
210 }