Merge lp:~james-page/ubuntu/oneiric/dovecot-metadata-plugin/new-upstream-release into lp:ubuntu/oneiric/dovecot-metadata-plugin
- Oneiric (11.10)
- new-upstream-release
- Merge into oneiric
Proposed by
James Page
Status: | Merged |
---|---|
Merge reported by: | Luke Yelavich |
Merged at revision: | not available |
Proposed branch: | lp:~james-page/ubuntu/oneiric/dovecot-metadata-plugin/new-upstream-release |
Merge into: | lp:ubuntu/oneiric/dovecot-metadata-plugin |
Diff against target: |
4296 lines (+3039/-687) 43 files modified
.hg_archival.txt (+2/-3) .hgignore (+11/-2) .hgsigs (+1/-0) .hgtags (+1/-0) AUTHORS (+1/-0) INSTALL (+189/-60) Makefile.am (+2/-0) NEWS (+9/-2) TODO (+1/-0) autogen.sh (+5/-10) configure.ac (+20/-0) configure.in (+0/-56) debian/changelog (+11/-0) debian/control (+3/-3) debian/copyright (+25/-46) debian/rules (+4/-0) src/Makefile.am (+40/-16) src/dict-ext.c (+139/-0) src/dict-ext.h (+58/-0) src/imap-annotatemore-plugin.c (+475/-120) src/imap-annotatemore-plugin.h (+0/-7) src/imap-arg-ext.c (+83/-0) src/imap-arg-ext.h (+32/-0) src/imap-metadata-plugin.c (+699/-0) src/mailbox-ext.c (+30/-0) src/mailbox-ext.h (+30/-0) src/metadata-backend.c (+296/-0) src/metadata-backend.h (+49/-0) src/metadata-entry-private.h (+32/-0) src/metadata-entry.c (+173/-0) src/metadata-entry.h (+83/-0) src/metadata-global.h (+52/-0) src/metadata-mail-storage-module.c (+92/-0) src/metadata-mail-storage-module.h (+28/-0) src/metadata-mail-user-module-private.h (+40/-0) src/metadata-mail-user-module.c (+56/-0) src/metadata-mail-user-module.h (+28/-0) src/metadata-plugin.c (+34/-345) src/metadata-plugin.h (+0/-17) src/metadata-settings.c (+85/-0) src/metadata-settings.h (+40/-0) src/str-ext.c (+42/-0) src/str-ext.h (+38/-0) |
To merge this branch: | bzr merge lp:~james-page/ubuntu/oneiric/dovecot-metadata-plugin/new-upstream-release |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Dave Walker (community) | Approve | ||
Matthias Klose | Approve | ||
Ubuntu branches | Pending | ||
Review via email: mp+77597@code.launchpad.net |
Commit message
Description of the change
New upstream release - existing version is not compatible with v2 of dovecot.
Had to switch upstream source to dovecot rather than kolab as development appears to be active there.
General tidy and update of copyright at the same time
To post a comment you must log in.
Revision history for this message
Dave Walker (davewalker) wrote : | # |
I think it's probably better to have something that should hopefully work, rather than something we know doesn't work and FTBFS.
I'd rather we have this new upstream snapshot rather than dropping from the archive.
Thanks.
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.hg_archival.txt' |
2 | --- .hg_archival.txt 2010-08-11 17:11:01 +0000 |
3 | +++ .hg_archival.txt 2011-09-29 19:49:50 +0000 |
4 | @@ -1,5 +1,4 @@ |
5 | repo: ae7e8348c8755ea0c8209c5b5efcc81228530b5e |
6 | -node: 4372f4ab8b0ee66b8c8e88e3661a67d441537b2d |
7 | +node: bdf2445e101fefc55ffa7bb2c4c5807af0799bd2 |
8 | branch: default |
9 | -latesttag: works-with-dovecot-1.1 |
10 | -latesttagdistance: 10 |
11 | +tag: v8 |
12 | |
13 | === modified file '.hgignore' |
14 | --- .hgignore 2010-08-11 17:11:01 +0000 |
15 | +++ .hgignore 2011-09-29 19:49:50 +0000 |
16 | @@ -1,17 +1,26 @@ |
17 | Makefile$ |
18 | Makefile\.in$ |
19 | +^stamp-h1$ |
20 | +^metadata-config\.h$ |
21 | +^metadata-config\.h\.in$ |
22 | +^ChangeLog$ |
23 | +^\.cscope |
24 | ^aclocal\.m4$ |
25 | ^autom4te\.cache |
26 | ^configure$ |
27 | +^configure.lineno$ |
28 | ^config\. |
29 | ^depcomp$ |
30 | ^libtool$ |
31 | ^install-sh |
32 | ^ltmain\.sh$ |
33 | +^m4 |
34 | ^missing$ |
35 | -^src/.deps |
36 | -^src/.libs |
37 | +^patches |
38 | +^src/\.deps |
39 | +^src/\.libs |
40 | ~$ |
41 | +\.tar\.gz$ |
42 | \.pyc$ |
43 | \.lo$ |
44 | \.la$ |
45 | |
46 | === added file '.hgsigs' |
47 | --- .hgsigs 1970-01-01 00:00:00 +0000 |
48 | +++ .hgsigs 2011-09-29 19:49:50 +0000 |
49 | @@ -0,0 +1,1 @@ |
50 | +fc360cf4ef81fe0b54ea56074d6b6ee9dcb1c3d5 0 iEYEABECAAYFAk30p6cACgkQjqfyF1DtJW689QCfU6UysrMwwqCycZ9EFbyN9Iof5D0AoL/np56Phl9xCZN9hzeaq0qIcszU |
51 | |
52 | === modified file '.hgtags' |
53 | --- .hgtags 2010-08-11 17:11:01 +0000 |
54 | +++ .hgtags 2011-09-29 19:49:50 +0000 |
55 | @@ -1,1 +1,2 @@ |
56 | 604f64c0f4852e3c0b5fd20b46cb7372791ec91b works-with-dovecot-1.1 |
57 | +fc360cf4ef81fe0b54ea56074d6b6ee9dcb1c3d5 v7 |
58 | |
59 | === modified file 'AUTHORS' |
60 | --- AUTHORS 2010-08-11 17:11:01 +0000 |
61 | +++ AUTHORS 2011-09-29 19:49:50 +0000 |
62 | @@ -1,1 +1,2 @@ |
63 | Bernhard Herzog <bh@intevation.de> |
64 | +Dennis Schridde <devurandom@gna.org> |
65 | |
66 | === modified file 'INSTALL' |
67 | --- INSTALL 2010-08-11 17:11:01 +0000 |
68 | +++ INSTALL 2011-09-29 19:49:50 +0000 |
69 | @@ -1,16 +1,25 @@ |
70 | Installation Instructions |
71 | ************************* |
72 | |
73 | -Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free |
74 | -Software Foundation, Inc. |
75 | +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, |
76 | +2006, 2007, 2008, 2009 Free Software Foundation, Inc. |
77 | |
78 | -This file is free documentation; the Free Software Foundation gives |
79 | -unlimited permission to copy, distribute and modify it. |
80 | + Copying and distribution of this file, with or without modification, |
81 | +are permitted in any medium without royalty provided the copyright |
82 | +notice and this notice are preserved. This file is offered as-is, |
83 | +without warranty of any kind. |
84 | |
85 | Basic Installation |
86 | ================== |
87 | |
88 | -These are generic installation instructions. |
89 | + Briefly, the shell commands `./configure; make; make install' should |
90 | +configure, build, and install this package. The following |
91 | +more-detailed instructions are generic; see the `README' file for |
92 | +instructions specific to this package. Some packages provide this |
93 | +`INSTALL' file but do not implement all of the features documented |
94 | +below. The lack of an optional feature in a given package is not |
95 | +necessarily a bug. More recommendations for GNU packages can be found |
96 | +in *note Makefile Conventions: (standards)Makefile Conventions. |
97 | |
98 | The `configure' shell script attempts to guess correct values for |
99 | various system-dependent variables used during compilation. It uses |
100 | @@ -23,9 +32,9 @@ |
101 | |
102 | It can also use an optional file (typically called `config.cache' |
103 | and enabled with `--cache-file=config.cache' or simply `-C') that saves |
104 | -the results of its tests to speed up reconfiguring. (Caching is |
105 | +the results of its tests to speed up reconfiguring. Caching is |
106 | disabled by default to prevent problems with accidental use of stale |
107 | -cache files.) |
108 | +cache files. |
109 | |
110 | If you need to do unusual things to compile the package, please try |
111 | to figure out how `configure' could check whether to do them, and mail |
112 | @@ -35,30 +44,37 @@ |
113 | may remove or edit it. |
114 | |
115 | The file `configure.ac' (or `configure.in') is used to create |
116 | -`configure' by a program called `autoconf'. You only need |
117 | -`configure.ac' if you want to change it or regenerate `configure' using |
118 | -a newer version of `autoconf'. |
119 | +`configure' by a program called `autoconf'. You need `configure.ac' if |
120 | +you want to change it or regenerate `configure' using a newer version |
121 | +of `autoconf'. |
122 | |
123 | -The simplest way to compile this package is: |
124 | + The simplest way to compile this package is: |
125 | |
126 | 1. `cd' to the directory containing the package's source code and type |
127 | - `./configure' to configure the package for your system. If you're |
128 | - using `csh' on an old version of System V, you might need to type |
129 | - `sh ./configure' instead to prevent `csh' from trying to execute |
130 | - `configure' itself. |
131 | + `./configure' to configure the package for your system. |
132 | |
133 | - Running `configure' takes awhile. While running, it prints some |
134 | - messages telling which features it is checking for. |
135 | + Running `configure' might take a while. While running, it prints |
136 | + some messages telling which features it is checking for. |
137 | |
138 | 2. Type `make' to compile the package. |
139 | |
140 | 3. Optionally, type `make check' to run any self-tests that come with |
141 | - the package. |
142 | + the package, generally using the just-built uninstalled binaries. |
143 | |
144 | 4. Type `make install' to install the programs and any data files and |
145 | - documentation. |
146 | - |
147 | - 5. You can remove the program binaries and object files from the |
148 | + documentation. When installing into a prefix owned by root, it is |
149 | + recommended that the package be configured and built as a regular |
150 | + user, and only the `make install' phase executed with root |
151 | + privileges. |
152 | + |
153 | + 5. Optionally, type `make installcheck' to repeat any self-tests, but |
154 | + this time using the binaries in their final installed location. |
155 | + This target does not install anything. Running this target as a |
156 | + regular user, particularly if the prior `make install' required |
157 | + root privileges, verifies that the installation completed |
158 | + correctly. |
159 | + |
160 | + 6. You can remove the program binaries and object files from the |
161 | source code directory by typing `make clean'. To also remove the |
162 | files that `configure' created (so you can compile the package for |
163 | a different kind of computer), type `make distclean'. There is |
164 | @@ -67,45 +83,69 @@ |
165 | all sorts of other programs in order to regenerate files that came |
166 | with the distribution. |
167 | |
168 | + 7. Often, you can also type `make uninstall' to remove the installed |
169 | + files again. In practice, not all packages have tested that |
170 | + uninstallation works correctly, even though it is required by the |
171 | + GNU Coding Standards. |
172 | + |
173 | + 8. Some packages, particularly those that use Automake, provide `make |
174 | + distcheck', which can by used by developers to test that all other |
175 | + targets like `make install' and `make uninstall' work correctly. |
176 | + This target is generally not run by end users. |
177 | + |
178 | Compilers and Options |
179 | ===================== |
180 | |
181 | -Some systems require unusual options for compilation or linking that the |
182 | -`configure' script does not know about. Run `./configure --help' for |
183 | -details on some of the pertinent environment variables. |
184 | + Some systems require unusual options for compilation or linking that |
185 | +the `configure' script does not know about. Run `./configure --help' |
186 | +for details on some of the pertinent environment variables. |
187 | |
188 | You can give `configure' initial values for configuration parameters |
189 | by setting variables in the command line or in the environment. Here |
190 | is an example: |
191 | |
192 | - ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix |
193 | + ./configure CC=c99 CFLAGS=-g LIBS=-lposix |
194 | |
195 | *Note Defining Variables::, for more details. |
196 | |
197 | Compiling For Multiple Architectures |
198 | ==================================== |
199 | |
200 | -You can compile the package for more than one kind of computer at the |
201 | + You can compile the package for more than one kind of computer at the |
202 | same time, by placing the object files for each architecture in their |
203 | -own directory. To do this, you must use a version of `make' that |
204 | -supports the `VPATH' variable, such as GNU `make'. `cd' to the |
205 | +own directory. To do this, you can use GNU `make'. `cd' to the |
206 | directory where you want the object files and executables to go and run |
207 | the `configure' script. `configure' automatically checks for the |
208 | -source code in the directory that `configure' is in and in `..'. |
209 | - |
210 | - If you have to use a `make' that does not support the `VPATH' |
211 | -variable, you have to compile the package for one architecture at a |
212 | -time in the source code directory. After you have installed the |
213 | -package for one architecture, use `make distclean' before reconfiguring |
214 | -for another architecture. |
215 | +source code in the directory that `configure' is in and in `..'. This |
216 | +is known as a "VPATH" build. |
217 | + |
218 | + With a non-GNU `make', it is safer to compile the package for one |
219 | +architecture at a time in the source code directory. After you have |
220 | +installed the package for one architecture, use `make distclean' before |
221 | +reconfiguring for another architecture. |
222 | + |
223 | + On MacOS X 10.5 and later systems, you can create libraries and |
224 | +executables that work on multiple system types--known as "fat" or |
225 | +"universal" binaries--by specifying multiple `-arch' options to the |
226 | +compiler but only a single `-arch' option to the preprocessor. Like |
227 | +this: |
228 | + |
229 | + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ |
230 | + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ |
231 | + CPP="gcc -E" CXXCPP="g++ -E" |
232 | + |
233 | + This is not guaranteed to produce working output in all cases, you |
234 | +may have to build one architecture at a time and combine the results |
235 | +using the `lipo' tool if you have problems. |
236 | |
237 | Installation Names |
238 | ================== |
239 | |
240 | -By default, `make install' installs the package's commands under |
241 | + By default, `make install' installs the package's commands under |
242 | `/usr/local/bin', include files under `/usr/local/include', etc. You |
243 | can specify an installation prefix other than `/usr/local' by giving |
244 | -`configure' the option `--prefix=PREFIX'. |
245 | +`configure' the option `--prefix=PREFIX', where PREFIX must be an |
246 | +absolute file name. |
247 | |
248 | You can specify separate installation prefixes for |
249 | architecture-specific files and architecture-independent files. If you |
250 | @@ -116,16 +156,47 @@ |
251 | In addition, if you use an unusual directory layout you can give |
252 | options like `--bindir=DIR' to specify different values for particular |
253 | kinds of files. Run `configure --help' for a list of the directories |
254 | -you can set and what kinds of files go in them. |
255 | +you can set and what kinds of files go in them. In general, the |
256 | +default for these options is expressed in terms of `${prefix}', so that |
257 | +specifying just `--prefix' will affect all of the other directory |
258 | +specifications that were not explicitly provided. |
259 | + |
260 | + The most portable way to affect installation locations is to pass the |
261 | +correct locations to `configure'; however, many packages provide one or |
262 | +both of the following shortcuts of passing variable assignments to the |
263 | +`make install' command line to change installation locations without |
264 | +having to reconfigure or recompile. |
265 | + |
266 | + The first method involves providing an override variable for each |
267 | +affected directory. For example, `make install |
268 | +prefix=/alternate/directory' will choose an alternate location for all |
269 | +directory configuration variables that were expressed in terms of |
270 | +`${prefix}'. Any directories that were specified during `configure', |
271 | +but not in terms of `${prefix}', must each be overridden at install |
272 | +time for the entire installation to be relocated. The approach of |
273 | +makefile variable overrides for each directory variable is required by |
274 | +the GNU Coding Standards, and ideally causes no recompilation. |
275 | +However, some platforms have known limitations with the semantics of |
276 | +shared libraries that end up requiring recompilation when using this |
277 | +method, particularly noticeable in packages that use GNU Libtool. |
278 | + |
279 | + The second method involves providing the `DESTDIR' variable. For |
280 | +example, `make install DESTDIR=/alternate/directory' will prepend |
281 | +`/alternate/directory' before all installation names. The approach of |
282 | +`DESTDIR' overrides is not required by the GNU Coding Standards, and |
283 | +does not work on platforms that have drive letters. On the other hand, |
284 | +it does better at avoiding recompilation issues, and works well even |
285 | +when some directory options were not specified in terms of `${prefix}' |
286 | +at `configure' time. |
287 | + |
288 | +Optional Features |
289 | +================= |
290 | |
291 | If the package supports it, you can cause programs to be installed |
292 | with an extra prefix or suffix on their names by giving `configure' the |
293 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. |
294 | |
295 | -Optional Features |
296 | -================= |
297 | - |
298 | -Some packages pay attention to `--enable-FEATURE' options to |
299 | + Some packages pay attention to `--enable-FEATURE' options to |
300 | `configure', where FEATURE indicates an optional part of the package. |
301 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE |
302 | is something like `gnu-as' or `x' (for the X Window System). The |
303 | @@ -137,14 +208,53 @@ |
304 | you can use the `configure' options `--x-includes=DIR' and |
305 | `--x-libraries=DIR' to specify their locations. |
306 | |
307 | + Some packages offer the ability to configure how verbose the |
308 | +execution of `make' will be. For these packages, running `./configure |
309 | +--enable-silent-rules' sets the default to minimal output, which can be |
310 | +overridden with `make V=1'; while running `./configure |
311 | +--disable-silent-rules' sets the default to verbose, which can be |
312 | +overridden with `make V=0'. |
313 | + |
314 | +Particular systems |
315 | +================== |
316 | + |
317 | + On HP-UX, the default C compiler is not ANSI C compatible. If GNU |
318 | +CC is not installed, it is recommended to use the following options in |
319 | +order to use an ANSI C compiler: |
320 | + |
321 | + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" |
322 | + |
323 | +and if that doesn't work, install pre-built binaries of GCC for HP-UX. |
324 | + |
325 | + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot |
326 | +parse its `<wchar.h>' header file. The option `-nodtk' can be used as |
327 | +a workaround. If GNU CC is not installed, it is therefore recommended |
328 | +to try |
329 | + |
330 | + ./configure CC="cc" |
331 | + |
332 | +and if that doesn't work, try |
333 | + |
334 | + ./configure CC="cc -nodtk" |
335 | + |
336 | + On Solaris, don't put `/usr/ucb' early in your `PATH'. This |
337 | +directory contains several dysfunctional programs; working variants of |
338 | +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' |
339 | +in your `PATH', put it _after_ `/usr/bin'. |
340 | + |
341 | + On Haiku, software installed for all users goes in `/boot/common', |
342 | +not `/usr/local'. It is recommended to use the following options: |
343 | + |
344 | + ./configure --prefix=/boot/common |
345 | + |
346 | Specifying the System Type |
347 | ========================== |
348 | |
349 | -There may be some features `configure' cannot figure out automatically, |
350 | -but needs to determine by the type of machine the package will run on. |
351 | -Usually, assuming the package is built to be run on the _same_ |
352 | -architectures, `configure' can figure that out, but if it prints a |
353 | -message saying it cannot guess the machine type, give it the |
354 | + There may be some features `configure' cannot figure out |
355 | +automatically, but needs to determine by the type of machine the package |
356 | +will run on. Usually, assuming the package is built to be run on the |
357 | +_same_ architectures, `configure' can figure that out, but if it prints |
358 | +a message saying it cannot guess the machine type, give it the |
359 | `--build=TYPE' option. TYPE can either be a short name for the system |
360 | type, such as `sun4', or a canonical name which has the form: |
361 | |
362 | @@ -152,7 +262,8 @@ |
363 | |
364 | where SYSTEM can have one of these forms: |
365 | |
366 | - OS KERNEL-OS |
367 | + OS |
368 | + KERNEL-OS |
369 | |
370 | See the file `config.sub' for the possible values of each field. If |
371 | `config.sub' isn't included in this package, then this package doesn't |
372 | @@ -170,9 +281,9 @@ |
373 | Sharing Defaults |
374 | ================ |
375 | |
376 | -If you want to set default values for `configure' scripts to share, you |
377 | -can create a site shell script called `config.site' that gives default |
378 | -values for variables like `CC', `cache_file', and `prefix'. |
379 | + If you want to set default values for `configure' scripts to share, |
380 | +you can create a site shell script called `config.site' that gives |
381 | +default values for variables like `CC', `cache_file', and `prefix'. |
382 | `configure' looks for `PREFIX/share/config.site' if it exists, then |
383 | `PREFIX/etc/config.site' if it exists. Or, you can set the |
384 | `CONFIG_SITE' environment variable to the location of the site script. |
385 | @@ -181,7 +292,7 @@ |
386 | Defining Variables |
387 | ================== |
388 | |
389 | -Variables not defined in a site shell script can be set in the |
390 | + Variables not defined in a site shell script can be set in the |
391 | environment passed to `configure'. However, some packages may run |
392 | configure again during the build, and the customized values of these |
393 | variables may be lost. In order to avoid this problem, you should set |
394 | @@ -190,21 +301,29 @@ |
395 | ./configure CC=/usr/local2/bin/gcc |
396 | |
397 | causes the specified `gcc' to be used as the C compiler (unless it is |
398 | -overridden in the site shell script). Here is a another example: |
399 | - |
400 | - /bin/bash ./configure CONFIG_SHELL=/bin/bash |
401 | - |
402 | -Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent |
403 | -configuration-related scripts to be executed by `/bin/bash'. |
404 | +overridden in the site shell script). |
405 | + |
406 | +Unfortunately, this technique does not work for `CONFIG_SHELL' due to |
407 | +an Autoconf bug. Until the bug is fixed you can use this workaround: |
408 | + |
409 | + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash |
410 | |
411 | `configure' Invocation |
412 | ====================== |
413 | |
414 | -`configure' recognizes the following options to control how it operates. |
415 | + `configure' recognizes the following options to control how it |
416 | +operates. |
417 | |
418 | `--help' |
419 | `-h' |
420 | - Print a summary of the options to `configure', and exit. |
421 | + Print a summary of all of the options to `configure', and exit. |
422 | + |
423 | +`--help=short' |
424 | +`--help=recursive' |
425 | + Print a summary of the options unique to this package's |
426 | + `configure', and exit. The `short' variant lists options used |
427 | + only in the top level, while the `recursive' variant lists options |
428 | + also present in any nested packages. |
429 | |
430 | `--version' |
431 | `-V' |
432 | @@ -231,6 +350,16 @@ |
433 | Look for the package's source code in directory DIR. Usually |
434 | `configure' can determine that directory automatically. |
435 | |
436 | +`--prefix=DIR' |
437 | + Use DIR as the installation prefix. *note Installation Names:: |
438 | + for more details, including other options available for fine-tuning |
439 | + the installation locations. |
440 | + |
441 | +`--no-create' |
442 | +`-n' |
443 | + Run the configure checks, but stop before creating any output |
444 | + files. |
445 | + |
446 | `configure' also accepts some other, not widely useful, options. Run |
447 | `configure --help' for more details. |
448 | |
449 | |
450 | === modified file 'Makefile.am' |
451 | --- Makefile.am 2010-08-11 17:11:01 +0000 |
452 | +++ Makefile.am 2011-09-29 19:49:50 +0000 |
453 | @@ -1,3 +1,5 @@ |
454 | +ACLOCAL_AMFLAGS = -I m4 |
455 | + |
456 | SUBDIRS = src |
457 | |
458 | EXTRA_DIST = \ |
459 | |
460 | === modified file 'NEWS' |
461 | --- NEWS 2010-08-11 17:11:01 +0000 |
462 | +++ NEWS 2011-09-29 19:49:50 +0000 |
463 | @@ -1,2 +1,9 @@ |
464 | -There hasn't been a release yet. See the mercurial logs details on the |
465 | -changes that happened so far. |
466 | +2011-06-12: Version 8 |
467 | + * Fix compliance with RFC 5464 Section 4.2.2 |
468 | + * Minor cleanups |
469 | + |
470 | +2011-06-10: Version 7 - "Works with Akonadi" |
471 | + * RFC 5464 compatible |
472 | + * imap-annotatemore is a partial implementation of draft-daboo-imap-annotatemore-08 |
473 | + Based on work by Bernhard Herzog (Intevation GmbH) |
474 | + * imap-metadata is a complete implementation of RFC 5464 |
475 | |
476 | === added file 'TODO' |
477 | --- TODO 1970-01-01 00:00:00 +0000 |
478 | +++ TODO 2011-09-29 19:49:50 +0000 |
479 | @@ -0,0 +1,1 @@ |
480 | +* Handle mailbox moves/renames |
481 | |
482 | === modified file 'autogen.sh' |
483 | --- autogen.sh 2010-08-11 17:11:01 +0000 |
484 | +++ autogen.sh 2011-09-29 19:49:50 +0000 |
485 | @@ -1,12 +1,7 @@ |
486 | #!/bin/sh |
487 | |
488 | -# If you've non-standard directories, set these |
489 | -#ACLOCAL_DIR= |
490 | -#GETTEXT_DIR= |
491 | - |
492 | -if test "$ACLOCAL_DIR" != ""; then |
493 | - ACLOCAL="aclocal -I $ACLOCAL_DIR" |
494 | - export ACLOCAL |
495 | -fi |
496 | - |
497 | -autoreconf -i |
498 | +echo '+ creating m4/ ...' |
499 | +test -d m4 || mkdir m4 |
500 | + |
501 | +echo '+ running autoreconf ...' |
502 | +autoreconf --force --install |
503 | |
504 | === added file 'configure.ac' |
505 | --- configure.ac 1970-01-01 00:00:00 +0000 |
506 | +++ configure.ac 2011-09-29 19:49:50 +0000 |
507 | @@ -0,0 +1,20 @@ |
508 | +AC_PREREQ(2.65) |
509 | +AC_INIT([dovecot-metadata],[8],[devurandom@gmx.net]) |
510 | + |
511 | +AM_INIT_AUTOMAKE([1.10 silent-rules]) |
512 | +AM_MAINTAINER_MODE |
513 | + |
514 | +AC_CONFIG_MACRO_DIR([m4]) |
515 | +AC_CONFIG_SRCDIR([src]) |
516 | + |
517 | +AC_PROG_CC_STDC |
518 | +LT_INIT |
519 | + |
520 | +DC_DOVECOT([2.0]) |
521 | + |
522 | +AC_CONFIG_HEADERS([metadata-config.h]) |
523 | +AC_CONFIG_FILES([ |
524 | + Makefile |
525 | + src/Makefile |
526 | +]) |
527 | +AC_OUTPUT |
528 | |
529 | === removed file 'configure.in' |
530 | --- configure.in 2010-08-11 17:11:01 +0000 |
531 | +++ configure.in 1970-01-01 00:00:00 +0000 |
532 | @@ -1,56 +0,0 @@ |
533 | -AC_INIT(dovecot-metadata, 0.0.1, [bh@intevation.de]) |
534 | -AC_CONFIG_SRCDIR([src]) |
535 | - |
536 | -AC_CONFIG_HEADERS([metadata-config.h]) |
537 | -AM_INIT_AUTOMAKE |
538 | - |
539 | -AM_MAINTAINER_MODE |
540 | - |
541 | -AC_PROG_CC |
542 | -AM_PROG_LIBTOOL |
543 | - |
544 | -AC_ARG_WITH(dovecot, |
545 | -[ --with-dovecot[=DIR] Dovecot base directory (../dovecot)], |
546 | - dovecotdir="$withval", |
547 | - dovecotdir=../dovecot |
548 | -) |
549 | -old=`pwd` |
550 | -cd $dovecotdir |
551 | -dovecotdir=`pwd` |
552 | -cd $old |
553 | -AC_SUBST(dovecotdir) |
554 | - |
555 | -if ! test -f "$dovecotdir/dovecot-config"; then |
556 | - echo |
557 | - echo "dovecot-config not found from $dovecotdir, use --with-dovecot=PATH" |
558 | - echo "to give path to compiled Dovecot sources or to a directory with the" |
559 | - echo "installed dovecot-config file." |
560 | - AC_MSG_ERROR([dovecot-config not found]) |
561 | -fi |
562 | - |
563 | -if test -d "$dovecotdir/src"; then |
564 | - # compiling against sources |
565 | - have_dovecot_libs=yes |
566 | -else |
567 | - # compiling against installed headers |
568 | - have_dovecot_libs=no |
569 | -fi |
570 | -AM_CONDITIONAL(HAVE_DOVECOT_LIBS, test "$have_dovecot_libs" = "yes") |
571 | - |
572 | -dnl replace relative ../ paths in the file with full paths |
573 | -eval `cat $dovecotdir/dovecot-config|sed 's,\$(top_builddir)/,$dovecotdir/,g'` |
574 | - |
575 | -if test $have_dovecot_libs = yes; then |
576 | - dovecot_incdir="$dovecotdir" |
577 | -fi |
578 | - |
579 | - |
580 | -AC_SUBST(dovecot_incdir) |
581 | -AC_SUBST(moduledir) |
582 | - |
583 | -AC_CONFIG_FILES([ |
584 | -Makefile |
585 | -src/Makefile |
586 | -]) |
587 | - |
588 | -AC_OUTPUT |
589 | |
590 | === modified file 'debian/changelog' |
591 | --- debian/changelog 2010-08-11 17:11:01 +0000 |
592 | +++ debian/changelog 2011-09-29 19:49:50 +0000 |
593 | @@ -1,3 +1,14 @@ |
594 | +dovecot-metadata-plugin (8-0ubuntu1) oneiric; urgency=low |
595 | + |
596 | + * New upstream release, fixes FTBFS with dovecot >= 2.0.0 (LP: #831179). |
597 | + - d/control: Switched upstream source to http://hg.dovecot.org as original |
598 | + source appears to be inactive. |
599 | + - d/control: Bumped Standards-Version, no changes. |
600 | + - d/copyright: Updated and converted to DEP-5. |
601 | + - d/rules: Cleared dependency_libs in .la files. |
602 | + |
603 | + -- James Page <james.page@ubuntu.com> Thu, 29 Sep 2011 20:35:51 +0100 |
604 | + |
605 | dovecot-metadata-plugin (0.0.1~hg144-0ubuntu1) maverick; urgency=low |
606 | |
607 | * Initial release to support Kolab server |
608 | |
609 | === modified file 'debian/control' |
610 | --- debian/control 2010-08-11 17:11:01 +0000 |
611 | +++ debian/control 2011-09-29 19:49:50 +0000 |
612 | @@ -4,14 +4,14 @@ |
613 | Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com> |
614 | XSBC-Original-Maintainer: Scott Kitterman <scott@kitterman.com> |
615 | Build-Depends: debhelper (>= 7.0.50), automake, libtool, dovecot-dev, libldap2-dev |
616 | -Standards-Version: 3.9.1 |
617 | -Homepage: http://hg.intevation.org/kolab/dovecot-metadata-plugin |
618 | +Standards-Version: 3.9.2 |
619 | +Homepage: http://hg.dovecot.org/dovecot-metadata-plugin |
620 | |
621 | Package: dovecot-metadata-plugin |
622 | Architecture: any |
623 | Depends: ${shlibs:Depends}, ${misc:Depends} |
624 | Description: Experimental IMAP METADATA Extension for Dovecot |
625 | - This is a set of plugins for the Dovecot IMAP server version 1.2 that |
626 | + This is a set of plugins for the Dovecot IMAP server version 2.0 that |
627 | implement the IMAP METADATA Extension. The goal of the development is |
628 | to extend dovecot so that it can be used as the IMAP component instead |
629 | of Cyrus IMAPd in the Kolab server. |
630 | |
631 | === modified file 'debian/copyright' |
632 | --- debian/copyright 2010-08-11 17:11:01 +0000 |
633 | +++ debian/copyright 2011-09-29 19:49:50 +0000 |
634 | @@ -1,46 +1,25 @@ |
635 | -This work was packaged for Ubuntu by: |
636 | - |
637 | - Scott Kitterman <scott@kitterman.com> on Wed, 11 Aug 2010 17:11:01 -0400 |
638 | - |
639 | -It was downloaded from: |
640 | - |
641 | -http://hg.intevation.org/kolab/dovecot-metadata-plugin/archive/tip.tar.gz |
642 | - |
643 | -Upstream Author: |
644 | - |
645 | - Bernhard Herzog <bh@intevation.de> |
646 | - |
647 | -Copyright: |
648 | - |
649 | - src/imap-annotatemore-plugin.c:/* Copyright (C) 2008 by Intevation GmbH |
650 | - src/metadata-plugin.c:/* Copyright (C) 2008, 2009 by Intevation GmbH |
651 | - test/imapsupport.py:# Copyright (C) 2008 by Intevation GmbH |
652 | - test/test_annotatemore.py:# Copyright (C) 2008 by Intevation GmbH |
653 | - test/runtests.py:# Copyright (C) 2004, 2005, 2006, 2007, 2008 by Intevation GmbH |
654 | - test/test_annotatemore_private.py:# Copyright (C) 2008 by Intevation GmbH |
655 | - |
656 | -License: |
657 | - |
658 | - This library is free software; you can redistribute it and/or |
659 | - modify it under the terms of the GNU Lesser General Public |
660 | - License as published by the Free Software Foundation; either |
661 | - version 2.1 of the License, or (at your option) any later version. |
662 | - |
663 | - This library is distributed in the hope that it will be useful, |
664 | - but WITHOUT ANY WARRANTY; without even the implied warranty of |
665 | - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
666 | - Lesser General Public License for more details. |
667 | - |
668 | - You should have received a copy of the GNU Lesser General Public |
669 | - License along with this library; if not, write to the Free Software |
670 | - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
671 | - |
672 | -On Debian systems, the complete text of the GNU Lesser General Public License |
673 | -2.1 can be found in '/usr/share/common-licenses/GPL/LGPL-2.1 |
674 | - |
675 | -The Debian packaging is: |
676 | - |
677 | - Copyright (C) 2010 Scott Kitterman <scott@kitterman.com> |
678 | - |
679 | -and is licensed under the smae terms as the upstream source. See above. |
680 | - |
681 | +Format: http://dep.debian.net/deps/dep5/ |
682 | +Upstream-Name: Dovecot Metadata Plugin |
683 | +Source: http://hg.dovecot.org/dovecot-metadata-plugin |
684 | + |
685 | +Files: * |
686 | +Copyright: 2008, by Intevation GmbH |
687 | + 2010, Dennis Schridde |
688 | + 2008, Bernhard Herzog <bh@intevation.de> |
689 | +License: LGPL-3 |
690 | + |
691 | +Files: test/* |
692 | +Copyright: 2004-2008, by Intevation GmbH |
693 | +License: LGPL-2.1 |
694 | + |
695 | +Files: debian/* |
696 | +Copyright: 2010 Scott Kitterman <scott@kitterman.com> |
697 | +License: LGPL-2.1 |
698 | + |
699 | +License: LGPL-3 |
700 | + On Debian systems, the complete text of the GNU Lesser General Public License |
701 | + 3 can be found in '/usr/share/common-licenses/GPL/LGPL-3 |
702 | + |
703 | +License: LGPL-2.1 |
704 | + On Debian systems, the complete text of the GNU Lesser General Public License |
705 | + 2.1 can be found in '/usr/share/common-licenses/GPL/LGPL-2.1 |
706 | |
707 | === modified file 'debian/rules' |
708 | --- debian/rules 2010-08-11 17:11:01 +0000 |
709 | +++ debian/rules 2011-09-29 19:49:50 +0000 |
710 | @@ -13,6 +13,10 @@ |
711 | dh $@ |
712 | |
713 | override_dh_auto_configure: |
714 | + test -d m4 || mkdir m4 |
715 | autoreconf -f -i -Wall,no-obsolete |
716 | dh_auto_configure -- --with-dovecot=/usr/lib/dovecot/ |
717 | |
718 | +override_dh_install: |
719 | + sed -i "/dependency_libs/ s/'.*'/''/" `find . -name '*.la'` |
720 | + dh_install |
721 | |
722 | === modified file 'src/Makefile.am' |
723 | --- src/Makefile.am 2010-08-11 17:11:01 +0000 |
724 | +++ src/Makefile.am 2011-09-29 19:49:50 +0000 |
725 | @@ -1,26 +1,50 @@ |
726 | -AM_CPPFLAGS = \ |
727 | - -I$(dovecot_incdir) \ |
728 | - -I$(dovecot_incdir)/src/lib \ |
729 | - -I$(dovecot_incdir)/src/lib-mail \ |
730 | - -I$(dovecot_incdir)/src/lib-imap \ |
731 | - -I$(dovecot_incdir)/src/lib-storage \ |
732 | - -I$(dovecot_incdir)/src/lib-dict \ |
733 | - -I$(dovecot_incdir)/src/imap \ |
734 | - -DPKG_RUNDIR=\""$(rundir)"\" |
735 | - |
736 | - |
737 | -imap_moduledir = $(moduledir)/imap |
738 | - |
739 | +AM_CPPFLAGS = $(LIBDOVECOT_INCLUDE) $(LIBDOVECOT_STORAGE_INCLUDE) $(LIBDOVECOT_IMAP_INCLUDE) |
740 | + |
741 | +imap_moduledir = $(dovecot_moduledir) |
742 | imap_module_LTLIBRARIES = \ |
743 | lib80_metadata_plugin.la \ |
744 | + lib90_imap_metadata_plugin.la \ |
745 | lib90_imap_annotatemore_plugin.la |
746 | |
747 | lib80_metadata_plugin_la_LDFLAGS = -module -avoid-version |
748 | - |
749 | lib80_metadata_plugin_la_SOURCES = \ |
750 | - metadata-plugin.c |
751 | + metadata-plugin.c \ |
752 | + metadata-backend.c \ |
753 | + metadata-entry.c \ |
754 | + metadata-mail-user-module.c \ |
755 | + metadata-mail-storage-module.c \ |
756 | + metadata-settings.c \ |
757 | + dict-ext.c \ |
758 | + imap-arg-ext.c \ |
759 | + mailbox-ext.c \ |
760 | + str-ext.c |
761 | + |
762 | +lib90_imap_metadata_plugin_la_LDFLAGS = -module -avoid-version |
763 | +lib90_imap_metadata_plugin_la_SOURCES = \ |
764 | + imap-metadata-plugin.c |
765 | +if DOVECOT_PLUGIN_DEPS |
766 | +lib90_imap_metadata_plugin_la_LIBADD = \ |
767 | + lib80_metadata_plugin.la |
768 | +endif |
769 | |
770 | lib90_imap_annotatemore_plugin_la_LDFLAGS = -module -avoid-version |
771 | - |
772 | lib90_imap_annotatemore_plugin_la_SOURCES = \ |
773 | imap-annotatemore-plugin.c |
774 | +if DOVECOT_PLUGIN_DEPS |
775 | +lib90_imap_annotatemore_plugin_la_LIBADD = \ |
776 | + lib80_metadata_plugin.la |
777 | +endif |
778 | + |
779 | +noinst_HEADERS = \ |
780 | + metadata-backend.h \ |
781 | + metadata-entry.h \ |
782 | + metadata-entry-private.h \ |
783 | + metadata-global.h \ |
784 | + metadata-mail-user-module.h \ |
785 | + metadata-mail-user-module-private.h \ |
786 | + metadata-mail-storage-module.h \ |
787 | + metadata-settings.h \ |
788 | + dict-ext.h \ |
789 | + imap-arg-ext.h \ |
790 | + mailbox-ext.h \ |
791 | + str-ext.h |
792 | |
793 | === added file 'src/dict-ext.c' |
794 | --- src/dict-ext.c 1970-01-01 00:00:00 +0000 |
795 | +++ src/dict-ext.c 2011-09-29 19:49:50 +0000 |
796 | @@ -0,0 +1,139 @@ |
797 | +/* |
798 | + Copyright (c) 2010 by Dennis Schridde |
799 | + |
800 | + This file is part of dovecot-metadata. |
801 | + |
802 | + dovecot-metadata is free software: you can redistribute it and/or modify |
803 | + it under the terms of the GNU Lesser General Public License as published by |
804 | + the Free Software Foundation, either version 3 of the License, or |
805 | + (at your option) any later version. |
806 | + |
807 | + dovecot-metadata is distributed in the hope that it will be useful, |
808 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
809 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
810 | + GNU Lesser General Public License for more details. |
811 | + |
812 | + You should have received a copy of the GNU Lesser General Public License |
813 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
814 | +*/ |
815 | +#include "dict-ext.h" |
816 | + |
817 | +#include "str.h" |
818 | +#include "dict.h" |
819 | + |
820 | +enum dict_scope |
821 | +dict_get_scope(const char *path) { |
822 | + if (strncasecmp(DICT_PATH_SHARED, path, sizeof(DICT_PATH_SHARED)) == 0) |
823 | + return DICT_SCOPE_SHARED; |
824 | + else if (strncasecmp(DICT_PATH_PRIVATE, path, sizeof(DICT_PATH_PRIVATE)) == 0) |
825 | + return DICT_SCOPE_PRIVATE; |
826 | + |
827 | + return DICT_SCOPE_INVALID; |
828 | +} |
829 | + |
830 | +const char * |
831 | +dict_path_from_scope(enum dict_scope scope) { |
832 | + switch (scope) { |
833 | + case DICT_SCOPE_SHARED: |
834 | + return DICT_PATH_SHARED; |
835 | + case DICT_SCOPE_PRIVATE: |
836 | + return DICT_PATH_PRIVATE; |
837 | + case DICT_SCOPE_INVALID: |
838 | + return ""; |
839 | + } |
840 | + |
841 | + return ""; |
842 | +} |
843 | + |
844 | +struct dict_iterate_multiscope_context { |
845 | + struct dict_iterate_context *dict_ctx; |
846 | + struct dict *dict; |
847 | + enum dict_iterate_flags flags; |
848 | + string_t *path; |
849 | + bool do_shared; |
850 | + bool failed; |
851 | +}; |
852 | + |
853 | +struct dict_iterate_multiscope_context * |
854 | +dict_iterate_multiscope_init(struct dict *dict, const char *path, enum dict_iterate_multiscope_flags flags) { |
855 | + struct dict_iterate_multiscope_context *ctx = i_new(struct dict_iterate_multiscope_context, 1); |
856 | + memset(ctx, 0, sizeof(*ctx)); |
857 | + |
858 | + ctx->dict = dict; |
859 | + ctx->flags = flags & ~DICT_ITERATE_MULTISCOPE_FLAG_MULTISCOPE; |
860 | + |
861 | + ctx->path = str_new(default_pool, 128); |
862 | + if (flags & DICT_ITERATE_MULTISCOPE_FLAG_MULTISCOPE) |
863 | + str_append(ctx->path, DICT_PATH_PRIVATE); |
864 | + str_append(ctx->path, path); |
865 | + |
866 | + ctx->do_shared = (flags & DICT_ITERATE_MULTISCOPE_FLAG_MULTISCOPE); |
867 | + ctx->failed = false; |
868 | + |
869 | + ctx->dict_ctx = dict_iterate_init(ctx->dict, str_c(ctx->path), ctx->flags); |
870 | + |
871 | + return ctx; |
872 | +} |
873 | + |
874 | +bool |
875 | +dict_iterate_multiscope(struct dict_iterate_multiscope_context *ctx, const char **name, const char **value) { |
876 | + i_assert(ctx != NULL); |
877 | + if (ctx == NULL) |
878 | + return false; |
879 | + |
880 | + if (ctx->failed) |
881 | + return false; |
882 | + |
883 | + *name = NULL; |
884 | + while (*name == NULL) { |
885 | + bool ret = dict_iterate(ctx->dict_ctx, name, value); |
886 | + |
887 | + /* we have no more shared/ keys and priv/ was also already iterated over */ |
888 | + if (!ret && !ctx->do_shared) { |
889 | + return false; |
890 | + } |
891 | + /* no more priv/ keys, continue with shared/ */ |
892 | + else if (!ret && ctx->do_shared) { |
893 | + if (dict_iterate_deinit(&ctx->dict_ctx) < 0) { |
894 | + ctx->failed = true; |
895 | + return false; |
896 | + } |
897 | + |
898 | + /* replace priv/ with shared/ */ |
899 | + str_delete(ctx->path, 0, sizeof(DICT_PATH_SHARED)); |
900 | + str_insert(ctx->path, 0, DICT_PATH_PRIVATE); |
901 | + |
902 | + ctx->do_shared = false; |
903 | + |
904 | + ctx->dict_ctx = dict_iterate_init(ctx->dict, str_c(ctx->path), ctx->flags); |
905 | + if (ctx->dict_ctx == NULL) { |
906 | + ctx->failed = true; |
907 | + } |
908 | + |
909 | + continue; |
910 | + } |
911 | + } |
912 | + |
913 | + return true; |
914 | +} |
915 | + |
916 | +int |
917 | +dict_iterate_multiscope_deinit(struct dict_iterate_multiscope_context **ctx) { |
918 | + i_assert(ctx != NULL); |
919 | + if (ctx == NULL) |
920 | + return -1; |
921 | + |
922 | + i_assert(*ctx != NULL); |
923 | + if (*ctx == NULL) |
924 | + return -1; |
925 | + |
926 | + int ret = (*ctx)->failed ? -1 : 0; |
927 | + |
928 | + if (dict_iterate_deinit(&(*ctx)->dict_ctx) < 0) |
929 | + ret = -1; |
930 | + |
931 | + str_free(&(*ctx)->path); |
932 | + i_free(*ctx); |
933 | + |
934 | + return ret; |
935 | +} |
936 | |
937 | === added file 'src/dict-ext.h' |
938 | --- src/dict-ext.h 1970-01-01 00:00:00 +0000 |
939 | +++ src/dict-ext.h 2011-09-29 19:49:50 +0000 |
940 | @@ -0,0 +1,58 @@ |
941 | +/* |
942 | + Copyright (c) 2010 by Dennis Schridde |
943 | + |
944 | + This file is part of dovecot-metadata. |
945 | + |
946 | + dovecot-metadata is free software: you can redistribute it and/or modify |
947 | + it under the terms of the GNU Lesser General Public License as published by |
948 | + the Free Software Foundation, either version 3 of the License, or |
949 | + (at your option) any later version. |
950 | + |
951 | + dovecot-metadata is distributed in the hope that it will be useful, |
952 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
953 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
954 | + GNU Lesser General Public License for more details. |
955 | + |
956 | + You should have received a copy of the GNU Lesser General Public License |
957 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
958 | +*/ |
959 | +#ifndef DOVECOT_DICT_EXT_H |
960 | +#define DOVECOT_DICT_EXT_H |
961 | + |
962 | +#include "metadata-global.h" |
963 | + |
964 | +#include <stdbool.h> |
965 | + |
966 | +#include "dict.h" |
967 | + |
968 | +enum dict_scope { |
969 | + DICT_SCOPE_SHARED, |
970 | + DICT_SCOPE_PRIVATE, |
971 | + DICT_SCOPE_INVALID |
972 | +}; |
973 | + |
974 | +enum dict_scope |
975 | +dict_get_scope(const char *key) |
976 | + ATTR_NONNULL(1); |
977 | + |
978 | +const char * |
979 | +dict_path_from_scope(enum dict_scope scope); |
980 | + |
981 | +struct dict_iterate_multiscope_context; |
982 | + |
983 | +enum dict_iterate_multiscope_flags { |
984 | + DICT_ITERATE_MULTISCOPE_FLAG_MULTISCOPE = 0x1000 |
985 | +}; |
986 | + |
987 | +struct dict_iterate_multiscope_context * |
988 | +dict_iterate_multiscope_init(struct dict *dict, const char *path, enum dict_iterate_multiscope_flags flags) |
989 | + ATTR_NONNULL(1,2); |
990 | +bool |
991 | +dict_iterate_multiscope(struct dict_iterate_multiscope_context *ctx, const char **name, const char **value) |
992 | + ATTR_NONNULL(1,2,3); |
993 | +int |
994 | +dict_iterate_multiscope_deinit(struct dict_iterate_multiscope_context **ctx) |
995 | + ATTR_NONNULL(1); |
996 | + |
997 | + |
998 | +#endif |
999 | |
1000 | === modified file 'src/imap-annotatemore-plugin.c' |
1001 | --- src/imap-annotatemore-plugin.c 2010-08-11 17:11:01 +0000 |
1002 | +++ src/imap-annotatemore-plugin.c 2011-09-29 19:49:50 +0000 |
1003 | @@ -1,20 +1,43 @@ |
1004 | -/* Copyright (C) 2008 by Intevation GmbH |
1005 | - * Authors: |
1006 | - * Bernhard Herzog <bh@intevation.de> |
1007 | - * |
1008 | - * This program is free software under the LGPL (>=v2.1) |
1009 | - * Read the file COPYING coming with the software for details. |
1010 | - */ |
1011 | - |
1012 | -#include "lib.h" |
1013 | +/* |
1014 | + Copyright (c) 2008 by Intevation GmbH / Bernhard Herzog <bh@intevation.de> |
1015 | + Copyright (c) 2010 by Dennis Schridde |
1016 | + |
1017 | + This file is part of dovecot-metadata. |
1018 | + |
1019 | + dovecot-metadata is free software: you can redistribute it and/or modify |
1020 | + it under the terms of the GNU Lesser General Public License as published by |
1021 | + the Free Software Foundation, either version 3 of the License, or |
1022 | + (at your option) any later version. |
1023 | + |
1024 | + dovecot-metadata is distributed in the hope that it will be useful, |
1025 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
1026 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1027 | + GNU Lesser General Public License for more details. |
1028 | + |
1029 | + You should have received a copy of the GNU Lesser General Public License |
1030 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
1031 | +*/ |
1032 | +#include "metadata-global.h" |
1033 | + |
1034 | #include "str.h" |
1035 | -#include "common.h" |
1036 | +#include "imap-common.h" |
1037 | +#include "imap-client.h" |
1038 | #include "imap-quote.h" |
1039 | +#include "mailbox-list.h" |
1040 | |
1041 | #include <string.h> |
1042 | |
1043 | -#include "metadata-plugin.h" |
1044 | -#include "imap-annotatemore-plugin.h" |
1045 | +#include "str-ext.h" |
1046 | +#include "metadata-entry-private.h" |
1047 | +#include "metadata-backend.h" |
1048 | + |
1049 | +/* The IMAP Annotatemore plugin is a partial implementation of draft-daboo-imap-annotatemore-08 */ |
1050 | + |
1051 | +const char *imap_annotatemore_plugin_version = DOVECOT_VERSION; |
1052 | +const char *imap_annotatemore_plugin_dependencies[] = { "metadata", NULL }; |
1053 | + |
1054 | +static struct module *imap_annotatemore_module; |
1055 | +static void (*next_hook_client_created)(struct client **client); |
1056 | |
1057 | enum attribute_properties { |
1058 | ATTR_INVALID = 0x0001, |
1059 | @@ -23,30 +46,32 @@ |
1060 | ATTR_BOTH = ATTR_PUBLIC | ATTR_PRIVATE, |
1061 | }; |
1062 | |
1063 | + |
1064 | static bool validate_entry_name(struct client_command_context *cmd, |
1065 | const char *entry) |
1066 | { |
1067 | if (entry == NULL) { |
1068 | - client_send_tagline(cmd, "BAD Missing entry name."); |
1069 | + client_send_command_error(cmd, "Missing entry name."); |
1070 | return FALSE; |
1071 | } |
1072 | |
1073 | - if (entry[0] != '/') { |
1074 | - client_send_tagline(cmd, |
1075 | - "BAD entry name must start with slash."); |
1076 | + if (entry[0] != '/' && entry[0] != '*' && entry[0] != '%') { |
1077 | + client_send_command_error(cmd, |
1078 | + "Entry name must start with slash or be a glob."); |
1079 | return FALSE; |
1080 | } |
1081 | |
1082 | return TRUE; |
1083 | } |
1084 | |
1085 | + |
1086 | static enum attribute_properties |
1087 | validate_attribute_name(struct client_command_context *cmd, |
1088 | const char *attribute) |
1089 | { |
1090 | if (attribute == NULL) { |
1091 | - client_send_tagline(cmd, |
1092 | - "BAD Missing or NIL attribute name."); |
1093 | + client_send_command_error(cmd, |
1094 | + "Missing or NIL attribute name."); |
1095 | return ATTR_INVALID; |
1096 | } |
1097 | |
1098 | @@ -56,64 +81,273 @@ |
1099 | return ATTR_PRIVATE; |
1100 | } else if (strcmp(attribute, "value") == 0) { |
1101 | return ATTR_BOTH; |
1102 | + } else if (strchr(attribute, '*')) { |
1103 | + return ATTR_BOTH; |
1104 | + } else if (strchr(attribute, '%')) { |
1105 | + client_send_command_error(cmd, "'%' globs not supported."); |
1106 | + return ATTR_INVALID; |
1107 | } else { |
1108 | - client_send_tagline(cmd, |
1109 | - "BAD only 'value.shared' and" |
1110 | - " 'value.priv' attributes are" |
1111 | - " supported '.'"); |
1112 | + client_send_command_error(cmd, |
1113 | + "Only 'value.shared' and 'value.priv' attributes" |
1114 | + " are supported '.'"); |
1115 | return ATTR_INVALID; |
1116 | } |
1117 | } |
1118 | |
1119 | |
1120 | +static const char * |
1121 | +entry_scopes[ENTRY_SCOPE_MAX] = { |
1122 | + "private/", /* ENTRY_SCOPE_PRIVATE */ |
1123 | + "shared/" /* ENTRY_SCOPE_SHARED */ |
1124 | +}; |
1125 | + |
1126 | +static const char * |
1127 | +entry_types[ENTRY_TYPE_MAX] = { |
1128 | + "vendor/", /* ENTRY_TYPE_VENDOR */ |
1129 | + "", /* ENTRY_TYPE_RFC */ |
1130 | +}; |
1131 | + |
1132 | +static const char ** |
1133 | +entry_subtypes_rfc[ENTRY_SUBJECT_MAX] = { |
1134 | + (const char*[]){ // server |
1135 | + "comment", |
1136 | + "admin", |
1137 | + NULL |
1138 | + }, |
1139 | + (const char*[]){ // mailbox |
1140 | + "comment", |
1141 | + NULL |
1142 | + } |
1143 | +}; |
1144 | + |
1145 | + |
1146 | +/* validates that the part after /vendor conforms to the RFC */ |
1147 | +static ATTR_NONNULL(1) |
1148 | +bool is_valid_annotatemore_vendor_name(const char *name) { |
1149 | + const char *lastslash = NULL, *lastcr = NULL; |
1150 | + int num_components = 2; |
1151 | + |
1152 | + for (const char *c = name; *c != '\0'; c++) { |
1153 | + switch (*c) { |
1154 | + case '/': |
1155 | + // Two consecutive slashes, or a slash at the end are an error |
1156 | + if (lastslash == c-1 || *(c+1) == '\0') { |
1157 | + return false; |
1158 | + } |
1159 | + lastslash = c; |
1160 | + num_components++; |
1161 | + break; |
1162 | + case '*': |
1163 | + case '%': |
1164 | + return false; |
1165 | + case '\r': |
1166 | + lastcr = c; |
1167 | + break; |
1168 | + case '\n': |
1169 | + // line ending has to be CRLF |
1170 | + if (lastcr != c-1) { |
1171 | + return false; |
1172 | + } |
1173 | + break; |
1174 | + default: |
1175 | + break; |
1176 | + } |
1177 | + } |
1178 | + |
1179 | + return num_components >= 4; |
1180 | +} |
1181 | + |
1182 | + |
1183 | +static ATTR_NONNULL(1) |
1184 | +bool is_valid_annotatemore_subtype_name(const char *name, enum metadata_entry_subject subject) { |
1185 | + bool found_subtype = false; |
1186 | + |
1187 | + i_assert(subject > 0 && subject < ENTRY_SUBJECT_MAX); |
1188 | + |
1189 | + for (const char **subtype = entry_subtypes_rfc[subject]; *subtype != NULL; subtype++) { |
1190 | + size_t subtype_len = strlen(*subtype); |
1191 | + |
1192 | + if (strncasecmp(name, *subtype, subtype_len) == 0) { |
1193 | + found_subtype = true; |
1194 | + } |
1195 | + } |
1196 | + |
1197 | + return found_subtype; |
1198 | +} |
1199 | + |
1200 | + |
1201 | +/* sets entry->type and returns remaining string */ |
1202 | +static ATTR_NONNULL(1) |
1203 | +enum metadata_entry_type |
1204 | +parse_entry_type(const char **name, enum metadata_entry_subject subject) { |
1205 | + if (**name == '\0') |
1206 | + return ENTRY_TYPE_NONE; |
1207 | + |
1208 | + for (int type = 0; type < ENTRY_TYPE_MAX; type++) { |
1209 | + size_t type_len = strlen(entry_types[type]); |
1210 | + |
1211 | + if (strncasecmp(*name, entry_types[type], type_len) == 0) { |
1212 | + *name += type_len; |
1213 | + |
1214 | + switch (type) { |
1215 | + case ENTRY_TYPE_RFC: |
1216 | + if (!is_valid_annotatemore_subtype_name(*name, subject)) |
1217 | + return ENTRY_TYPE_MAX; |
1218 | + break; |
1219 | + case ENTRY_TYPE_VENDOR: |
1220 | + if (!is_valid_annotatemore_vendor_name(*name)) |
1221 | + return ENTRY_TYPE_MAX; |
1222 | + break; |
1223 | + } |
1224 | + |
1225 | + return type; |
1226 | + } |
1227 | + } |
1228 | + |
1229 | + return ENTRY_TYPE_MAX; |
1230 | +} |
1231 | + |
1232 | + |
1233 | +static ATTR_NONNULL(2) |
1234 | +const char * |
1235 | +backend_name(enum metadata_entry_scope scope, const char *name) { |
1236 | + if (name == NULL) |
1237 | + return NULL; |
1238 | + |
1239 | + string_t *backend_name = t_str_new(128); |
1240 | + str_append(backend_name, "/"); |
1241 | + str_append(backend_name, entry_scopes[scope]); |
1242 | + str_append(backend_name, name); |
1243 | + |
1244 | + return str_c(backend_name); |
1245 | +} |
1246 | + |
1247 | + |
1248 | +/* fill entry with data parsed from entry->full_name */ |
1249 | +static ATTR_NONNULL(3) |
1250 | +struct metadata_entry * |
1251 | +parse_entry(struct mailbox *box, enum metadata_entry_scope scope, const char *name, const char *value) { |
1252 | + if (name == NULL || *name == '\0' || *name++ != '/') |
1253 | + return NULL; |
1254 | + |
1255 | + string_t *backend_name = t_str_new(128); |
1256 | + str_append(backend_name, "/"); |
1257 | + str_append(backend_name, entry_scopes[scope]); |
1258 | + str_append(backend_name, name); |
1259 | + |
1260 | + enum metadata_entry_type type = parse_entry_type(&name, box ? ENTRY_SUBJECT_MAILBOX : ENTRY_SUBJECT_SERVER); |
1261 | + if (type >= ENTRY_TYPE_MAX) |
1262 | + return NULL; |
1263 | + |
1264 | + return metadata_entry_alloc(box, str_c(backend_name), value); |
1265 | +} |
1266 | + |
1267 | + |
1268 | static void send_annotation_line(struct client_command_context *cmd, |
1269 | - const char *mailbox, |
1270 | - const char *entry, |
1271 | + struct mailbox *box, |
1272 | + const char *entry_name, |
1273 | const char *value, |
1274 | bool private) |
1275 | { |
1276 | if (value != NULL) { |
1277 | - string_t *str = t_str_new(128); |
1278 | - str_append(str, "* ANNOTATION "); |
1279 | - imap_quote_append_string(str, mailbox, FALSE); |
1280 | - str_append(str, " "); |
1281 | - imap_quote_append_string(str, entry, FALSE); |
1282 | - str_printfa(str, " (\"value.%s\" ", |
1283 | - private ? "priv" : "shared"); |
1284 | - imap_quote_append_string(str, value, FALSE); |
1285 | - str_append(str, ")"); |
1286 | - client_send_line(cmd->client, str_c(str)); |
1287 | + const char *mailbox_name = mailbox_get_vname(box); |
1288 | + const char *str = t_strdup_printf( |
1289 | + "* ANNOTATION %s %s (value.%s %s)", |
1290 | + mailbox_name, entry_name, private ? "priv" : "shared", value |
1291 | + ); |
1292 | + |
1293 | + client_send_line(cmd->client, str); |
1294 | } |
1295 | } |
1296 | |
1297 | |
1298 | -static bool get_and_send_annotation(struct client_command_context *cmd, |
1299 | - const char *mailbox, |
1300 | - const char *entry, |
1301 | +static void get_and_send_annotation(struct client_command_context *cmd, |
1302 | + struct mailbox *box, |
1303 | + const char *entry_name, |
1304 | enum attribute_properties scope) |
1305 | { |
1306 | - const char *value; |
1307 | - bool success = TRUE; |
1308 | - |
1309 | - if ((scope & ATTR_PUBLIC) != 0) { |
1310 | - value = NULL; |
1311 | - success = metadata_get_metadata_entry(cmd, mailbox, entry, |
1312 | - &value, FALSE); |
1313 | - send_annotation_line(cmd, mailbox, entry, value, FALSE); |
1314 | - } |
1315 | - |
1316 | - if (!success) { |
1317 | - return FALSE; |
1318 | - } |
1319 | - |
1320 | - if ((scope & ATTR_PRIVATE) != 0) { |
1321 | - value = NULL; |
1322 | - success = metadata_get_metadata_entry(cmd, mailbox, entry, |
1323 | - &value, TRUE); |
1324 | - send_annotation_line(cmd, mailbox, entry, value, TRUE); |
1325 | - } |
1326 | - |
1327 | - return success; |
1328 | + if (strchr(entry_name, '*')) { |
1329 | + int entrylastchar = strlen(entry_name); |
1330 | + if (entrylastchar > 0) |
1331 | + entrylastchar--; |
1332 | + |
1333 | + /* We do not support more than one glob, and at no other location than the end */ |
1334 | + if (strchr_num(entry_name, '*') == 1 && entry_name[entrylastchar] == '*') { |
1335 | + const char *entrypattern = t_strdup_until(entry_name, &entry_name[entrylastchar]); |
1336 | + |
1337 | + if ((scope & ATTR_PUBLIC) != 0) { |
1338 | + struct metadata_entry *entry = metadata_entry_alloc(box, backend_name(ENTRY_SCOPE_SHARED, entrypattern), NULL); |
1339 | + |
1340 | + struct metadata_iterate_context *iter = metadata_iterate_init(box, entry, METADATA_ITERATE_DEPTH_INF); |
1341 | + while (metadata_iterate(iter, entry)) { |
1342 | + const char *name = metadata_entry_get_name(entry) + strlen(entry_scopes[ENTRY_SCOPE_SHARED]); |
1343 | + const char *value = metadata_entry_get_value(entry); |
1344 | + |
1345 | + send_annotation_line(cmd, box, name, value, FALSE); |
1346 | + } |
1347 | + if (metadata_iterate_deinit(&iter) < 0) { |
1348 | + client_send_tagline(cmd, "NO Iterating metadata failed."); |
1349 | + return; |
1350 | + } |
1351 | + } |
1352 | + |
1353 | + if ((scope & ATTR_PRIVATE) != 0) { |
1354 | + struct metadata_entry *entry = metadata_entry_alloc(box, backend_name(ENTRY_SCOPE_PRIVATE, entrypattern), NULL); |
1355 | + |
1356 | + struct metadata_iterate_context *iter = metadata_iterate_init(box, entry, METADATA_ITERATE_DEPTH_INF); |
1357 | + while (metadata_iterate(iter, entry)) { |
1358 | + const char *name = metadata_entry_get_name(entry) + strlen(entry_scopes[ENTRY_SCOPE_SHARED]); |
1359 | + const char *value = metadata_entry_get_value(entry); |
1360 | + |
1361 | + send_annotation_line(cmd, box, name, value, TRUE); |
1362 | + } |
1363 | + if (metadata_iterate_deinit(&iter) < 0) { |
1364 | + client_send_tagline(cmd, "NO Iterating metadata failed."); |
1365 | + return; |
1366 | + } |
1367 | + } |
1368 | + } else { |
1369 | + client_send_command_error(cmd, "'*' globs only supported at end of pattern."); |
1370 | + return; |
1371 | + } |
1372 | + } else if (strchr(entry_name, '%')) { |
1373 | + client_send_command_error(cmd, "'%' globs not supported."); |
1374 | + return; |
1375 | + } else { |
1376 | + if ((scope & ATTR_PUBLIC) != 0) { |
1377 | + struct metadata_entry *entry = metadata_entry_alloc(box, backend_name(ENTRY_SCOPE_SHARED, entry_name), NULL); |
1378 | + if (entry == NULL) { |
1379 | + client_send_tagline(cmd, "NO Allocating entry failed."); |
1380 | + return; |
1381 | + } |
1382 | + |
1383 | + int success = metadata_get_entry(entry, cmd->client->user); |
1384 | + if (success < 0) { |
1385 | + client_send_tagline(cmd, "NO Getting entry failed."); |
1386 | + return; |
1387 | + } |
1388 | + else if (success > 0) { |
1389 | + send_annotation_line(cmd, box, entry->name, entry->value, FALSE); |
1390 | + } |
1391 | + } |
1392 | + |
1393 | + if ((scope & ATTR_PRIVATE) != 0) { |
1394 | + struct metadata_entry *entry = metadata_entry_alloc(box, backend_name(ENTRY_SCOPE_PRIVATE, entry_name), NULL); |
1395 | + if (entry == NULL) { |
1396 | + client_send_tagline(cmd, "NO Allocating entry failed."); |
1397 | + return; |
1398 | + } |
1399 | + |
1400 | + int success = metadata_get_entry(entry, cmd->client->user); |
1401 | + if (success < 0) { |
1402 | + client_send_tagline(cmd, "NO Getting entry failed."); |
1403 | + return; |
1404 | + } |
1405 | + else if (success > 0) { |
1406 | + send_annotation_line(cmd, box, entry->name, entry->value, TRUE); |
1407 | + } |
1408 | + } |
1409 | + } |
1410 | } |
1411 | |
1412 | |
1413 | @@ -121,11 +355,22 @@ |
1414 | const struct imap_arg *attribute, |
1415 | const char **value_r) |
1416 | { |
1417 | - const struct imap_arg *attrlist; |
1418 | - |
1419 | - if (IMAP_ARG_LIST_COUNT(attribute) == 1) { |
1420 | - attrlist = IMAP_ARG_LIST_ARGS(attribute); |
1421 | - *value_r = IMAP_ARG_STR(&attrlist[0]); |
1422 | + const struct imap_arg *attrlist = NULL; |
1423 | + unsigned int attrcount = 0; |
1424 | + |
1425 | + if (!imap_arg_get_list_full(attribute, &attrlist, &attrcount)) { |
1426 | + // Actually this should never happen, since we first test args[1].type == IMAP_ARG_LIST ! */ |
1427 | + i_error("metadata: got attributes of non-list type after confirming they were of correct type!"); |
1428 | + client_send_command_error(cmd, "Attributes must be of list type."); |
1429 | + return FALSE; |
1430 | + } |
1431 | + |
1432 | + if (attrcount == 1) { |
1433 | + if (!imap_arg_get_astring(&attrlist[0], value_r)) { |
1434 | + client_send_command_error(cmd, |
1435 | + "Value must be of string type."); |
1436 | + return FALSE; |
1437 | + } |
1438 | return TRUE; |
1439 | } else { |
1440 | client_send_tagline(cmd, |
1441 | @@ -138,22 +383,26 @@ |
1442 | static bool cmd_getannotation(struct client_command_context *cmd) |
1443 | { |
1444 | const struct imap_arg *args; |
1445 | - const char *mailbox; |
1446 | - const char *entry; |
1447 | + const char *mailbox_name; |
1448 | + const char *entry_name; |
1449 | const char *attribute; |
1450 | enum attribute_properties attribute_properties; |
1451 | |
1452 | if (!client_read_args(cmd, 3, 0, &args)) |
1453 | return FALSE; |
1454 | |
1455 | - mailbox = IMAP_ARG_STR(&args[0]); |
1456 | - if (mailbox == NULL) { |
1457 | - client_send_tagline(cmd, |
1458 | - "BAD Missing mailbox name."); |
1459 | + if (!imap_arg_get_astring(&args[0], &mailbox_name)) { |
1460 | + client_send_command_error(cmd, |
1461 | + "Mailbox name must be of string type."); |
1462 | + return TRUE; |
1463 | + } |
1464 | + if (mailbox_name == NULL) { |
1465 | + client_send_command_error(cmd, |
1466 | + "Missing mailbox name."); |
1467 | return TRUE; |
1468 | } |
1469 | |
1470 | - if (*mailbox == '\0') { |
1471 | + if (*mailbox_name == '\0') { |
1472 | client_send_tagline(cmd, |
1473 | "NO Server annotations not yet" |
1474 | " implemented."); |
1475 | @@ -161,26 +410,77 @@ |
1476 | } |
1477 | |
1478 | if (args[1].type == IMAP_ARG_LIST) { |
1479 | - if (!extract_single_value(cmd, &args[1], &entry)) |
1480 | - return TRUE; |
1481 | - } else |
1482 | - entry = IMAP_ARG_STR(&args[1]); |
1483 | + if (!extract_single_value(cmd, &args[1], &entry_name)) |
1484 | + return TRUE; |
1485 | + } else { |
1486 | + if (!imap_arg_get_astring(&args[1], &entry_name)) { |
1487 | + client_send_command_error(cmd, |
1488 | + "Entry name must be of string type."); |
1489 | + return TRUE; |
1490 | + } |
1491 | + } |
1492 | |
1493 | - if (!validate_entry_name(cmd, entry)) |
1494 | + if (!validate_entry_name(cmd, entry_name)) |
1495 | return TRUE; |
1496 | |
1497 | if (args[2].type == IMAP_ARG_LIST) { |
1498 | if (!extract_single_value(cmd, &args[2], &attribute)) |
1499 | return TRUE; |
1500 | - } else |
1501 | - attribute = IMAP_ARG_STR(&args[2]); |
1502 | + } else { |
1503 | + if (!imap_arg_get_astring(&args[2], &attribute)) { |
1504 | + client_send_command_error(cmd, |
1505 | + "Attribute must be of string type."); |
1506 | + return TRUE; |
1507 | + } |
1508 | + } |
1509 | |
1510 | attribute_properties = validate_attribute_name(cmd, attribute); |
1511 | if (attribute_properties & ATTR_INVALID) |
1512 | return TRUE; |
1513 | |
1514 | - if (get_and_send_annotation(cmd, mailbox, entry, attribute_properties)) |
1515 | - client_send_tagline(cmd, "OK Completed."); |
1516 | + if (str_has_wildcards(mailbox_name)) { |
1517 | + for (const struct mail_namespace *ns = cmd->client->user->namespaces; ns != NULL; ns = ns->next) { |
1518 | + const struct mailbox_info *info = NULL; |
1519 | + |
1520 | + struct mailbox_list_iterate_context *ctx = mailbox_list_iter_init(ns->list, mailbox_name, 0); |
1521 | + while ((info = mailbox_list_iter_next(ctx)) != NULL) { |
1522 | + i_debug("Getting info for mailbox '%s'", info->name); |
1523 | + |
1524 | + struct mailbox *box = mailbox_alloc(ns->list, info->name, MAILBOX_FLAG_READONLY); |
1525 | + if (box == NULL) { |
1526 | + client_send_tagline(cmd, "NO Allocating mailbox failed."); |
1527 | + return TRUE; |
1528 | + } |
1529 | + |
1530 | + get_and_send_annotation(cmd, box, entry_name, attribute_properties); |
1531 | + |
1532 | + mailbox_free(&box); |
1533 | + } |
1534 | + if (mailbox_list_iter_deinit(&ctx) < 0) { |
1535 | + client_send_tagline(cmd, "NO Iterating mailboxes failed."); |
1536 | + } |
1537 | + } |
1538 | + } else { |
1539 | + struct mail_namespace *ns = mail_namespace_find(cmd->client->user->namespaces, &mailbox_name); |
1540 | + if (ns == NULL) { |
1541 | + client_send_tagline(cmd, |
1542 | + "NO Mailbox not found."); |
1543 | + return TRUE; |
1544 | + } |
1545 | + |
1546 | + struct mailbox *box = mailbox_alloc(ns->list, mailbox_name, MAILBOX_FLAG_READONLY); |
1547 | + if (box == NULL) { |
1548 | + client_send_tagline(cmd, |
1549 | + "NO Allocating mailbox failed."); |
1550 | + return TRUE; |
1551 | + } |
1552 | + |
1553 | + get_and_send_annotation(cmd, box, entry_name, attribute_properties); |
1554 | + |
1555 | + mailbox_free(&box); |
1556 | + } |
1557 | + |
1558 | + client_send_tagline(cmd, "OK Completed."); |
1559 | |
1560 | return TRUE; |
1561 | } |
1562 | @@ -194,44 +494,50 @@ |
1563 | const struct imap_arg *pairs; |
1564 | unsigned int count; |
1565 | |
1566 | - if (attributes->type != IMAP_ARG_LIST) { |
1567 | - client_send_tagline(cmd, |
1568 | - "BAD attributes parameter must be a list" |
1569 | + if (!imap_arg_get_list_full(attributes, &pairs, &count)) { |
1570 | + client_send_command_error(cmd, |
1571 | + "Attributes parameter must be a list" |
1572 | " of attribute value pairs."); |
1573 | return FALSE; |
1574 | } |
1575 | |
1576 | - count = IMAP_ARG_LIST_COUNT(attributes); |
1577 | - pairs = IMAP_ARG_LIST_ARGS(attributes); |
1578 | - |
1579 | if (count % 2 != 0) { |
1580 | - client_send_tagline(cmd, |
1581 | - "BAD list of attribute value pairs" |
1582 | + client_send_command_error(cmd, |
1583 | + "List of attribute value pairs" |
1584 | " must have an even number of elements"); |
1585 | return FALSE; |
1586 | } |
1587 | |
1588 | if (count == 0) { |
1589 | - client_send_tagline(cmd, |
1590 | - "BAD list of attribute value pairs" |
1591 | + client_send_command_error(cmd, |
1592 | + "List of attribute value pairs" |
1593 | " is empty"); |
1594 | return FALSE; |
1595 | } |
1596 | |
1597 | if (count == 2) { |
1598 | enum attribute_properties properties; |
1599 | - properties = validate_attribute_name(cmd, |
1600 | - IMAP_ARG_STR(&pairs[0])); |
1601 | + const char *tmp; |
1602 | + if (!imap_arg_get_astring(&pairs[0], &tmp)) { |
1603 | + client_send_command_error(cmd, |
1604 | + "Attribute must be of string type."); |
1605 | + return FALSE; |
1606 | + } |
1607 | + properties = validate_attribute_name(cmd, tmp); |
1608 | if ((properties & ATTR_INVALID) != 0) |
1609 | return FALSE; |
1610 | if ((properties & ATTR_BOTH) == ATTR_BOTH) { |
1611 | - client_send_tagline(cmd, |
1612 | - "BAD attribute must end in .priv" |
1613 | + client_send_command_error(cmd, |
1614 | + "Attribute must end in .priv" |
1615 | " or .shared for SETANNOTATION"); |
1616 | return FALSE; |
1617 | } |
1618 | |
1619 | - *value_r = IMAP_ARG_STR(&pairs[1]); |
1620 | + if (!imap_arg_get_astring(&pairs[1], value_r)) { |
1621 | + client_send_command_error(cmd, |
1622 | + "Value must be of string type."); |
1623 | + return FALSE; |
1624 | + } |
1625 | *private_r = ((properties & ATTR_PRIVATE) != 0); |
1626 | return TRUE; |
1627 | } |
1628 | @@ -244,22 +550,25 @@ |
1629 | static bool cmd_setannotation(struct client_command_context *cmd) |
1630 | { |
1631 | const struct imap_arg *args; |
1632 | - const char *mailbox; |
1633 | - const char *entry; |
1634 | + const char *mailbox_name; |
1635 | + const char *entry_name; |
1636 | const char *value; |
1637 | bool private; |
1638 | - bool success; |
1639 | |
1640 | if (!client_read_args(cmd, 3, 0, &args)) |
1641 | return FALSE; |
1642 | |
1643 | - mailbox = IMAP_ARG_STR(&args[0]); |
1644 | - if (mailbox == NULL) { |
1645 | - client_send_tagline(cmd, |
1646 | - "BAD Missing mailbox name."); |
1647 | - return TRUE; |
1648 | - } |
1649 | - if (*mailbox == '\0') { |
1650 | + if (!imap_arg_get_astring(&args[0], &mailbox_name)) { |
1651 | + client_send_command_error(cmd, |
1652 | + "Mailbox name must be of string type."); |
1653 | + return TRUE; |
1654 | + } |
1655 | + if (mailbox_name == NULL) { |
1656 | + client_send_command_error(cmd, |
1657 | + "Missing mailbox name."); |
1658 | + return TRUE; |
1659 | + } |
1660 | + if (*mailbox_name == '\0') { |
1661 | client_send_tagline(cmd, |
1662 | "NO Server annotations not yet" |
1663 | " implemented."); |
1664 | @@ -271,38 +580,84 @@ |
1665 | "NO Lists of entries not yet implemented."); |
1666 | return TRUE; |
1667 | } |
1668 | - entry = IMAP_ARG_STR(&args[1]); |
1669 | - if (!validate_entry_name(cmd, entry)) |
1670 | + if (!imap_arg_get_astring(&args[1], &entry_name)) { |
1671 | + client_send_command_error(cmd, |
1672 | + "Entry name must be of string type."); |
1673 | + return TRUE; |
1674 | + } |
1675 | + if (entry_name == NULL) { |
1676 | + client_send_tagline(cmd, "NO Entry name is NULL."); |
1677 | + return true; |
1678 | + } |
1679 | + |
1680 | + if (!validate_entry_name(cmd, entry_name)) |
1681 | return TRUE; |
1682 | |
1683 | if (!pair_extract_value(cmd, &args[2], &value, &private)) |
1684 | return TRUE; |
1685 | |
1686 | - if (private && !metadata_private_allowed()) { |
1687 | - client_send_tagline(cmd, |
1688 | - "NO private annotations not supported."); |
1689 | - return TRUE; |
1690 | - } |
1691 | - |
1692 | - success = metadata_set_metadata_entry(cmd, mailbox, entry, value, |
1693 | - private); |
1694 | - if (success) { |
1695 | - client_send_tagline(cmd, "OK Completed."); |
1696 | - } |
1697 | + struct mail_namespace *ns = mail_namespace_find(cmd->client->user->namespaces, &mailbox_name); |
1698 | + if (ns == NULL) { |
1699 | + client_send_tagline(cmd, |
1700 | + "NO Mailbox not found."); |
1701 | + return TRUE; |
1702 | + } |
1703 | + |
1704 | + struct mailbox *box = mailbox_alloc(ns->list, mailbox_name, MAILBOX_FLAG_READONLY); |
1705 | + if (box == NULL) { |
1706 | + client_send_tagline(cmd, |
1707 | + "NO Allocating mailbox failed."); |
1708 | + return TRUE; |
1709 | + } |
1710 | + |
1711 | + struct metadata_entry *entry = parse_entry(box, private ? ENTRY_SCOPE_PRIVATE : ENTRY_SCOPE_SHARED, entry_name, value); |
1712 | + if (entry == NULL) { |
1713 | + client_send_tagline(cmd, |
1714 | + "NO Parsing entry failed."); |
1715 | + mailbox_free(&box); |
1716 | + return TRUE; |
1717 | + } |
1718 | + |
1719 | + if (metadata_set_entry(entry, cmd->client->user) < 0) { |
1720 | + client_send_tagline(cmd, |
1721 | + "NO Setting entry failed."); |
1722 | + mailbox_free(&box); |
1723 | + return TRUE; |
1724 | + } |
1725 | + |
1726 | + client_send_tagline(cmd, "OK Completed."); |
1727 | + |
1728 | + mailbox_free(&box); |
1729 | |
1730 | return TRUE; |
1731 | } |
1732 | |
1733 | |
1734 | -void imap_annotatemore_plugin_init(void) |
1735 | +static void imap_annotatemore_client_created(struct client **client) |
1736 | +{ |
1737 | + if (mail_user_is_plugin_loaded((*client)->user, imap_annotatemore_module)) |
1738 | + str_append((*client)->capability_string, " ANNOTATEMORE"); |
1739 | + |
1740 | + if (next_hook_client_created != NULL) |
1741 | + next_hook_client_created(client); |
1742 | +} |
1743 | + |
1744 | + |
1745 | +void imap_annotatemore_plugin_init(struct module *module) |
1746 | { |
1747 | command_register("GETANNOTATION", cmd_getannotation, 0); |
1748 | command_register("SETANNOTATION", cmd_setannotation, 0); |
1749 | - str_append(capability_string, " ANNOTATEMORE"); |
1750 | + |
1751 | + imap_annotatemore_module = module; |
1752 | + next_hook_client_created = hook_client_created; |
1753 | + hook_client_created = imap_annotatemore_client_created; |
1754 | } |
1755 | |
1756 | + |
1757 | void imap_annotatemore_plugin_deinit(void) |
1758 | { |
1759 | command_unregister("SETANNOTATION"); |
1760 | command_unregister("GETANNOTATION"); |
1761 | + |
1762 | + hook_client_created = next_hook_client_created; |
1763 | } |
1764 | |
1765 | === removed file 'src/imap-annotatemore-plugin.h' |
1766 | --- src/imap-annotatemore-plugin.h 2010-08-11 17:11:01 +0000 |
1767 | +++ src/imap-annotatemore-plugin.h 1970-01-01 00:00:00 +0000 |
1768 | @@ -1,7 +0,0 @@ |
1769 | -#ifndef __ANNOTATEMORE_PLUGIN |
1770 | -#define __ANNOTATEMORE_PLUGIN |
1771 | - |
1772 | -void imap_annotatemore_plugin_init(void); |
1773 | -void imap_annotatemore_plugin_deinit(void); |
1774 | - |
1775 | -#endif |
1776 | |
1777 | === added file 'src/imap-arg-ext.c' |
1778 | --- src/imap-arg-ext.c 1970-01-01 00:00:00 +0000 |
1779 | +++ src/imap-arg-ext.c 2011-09-29 19:49:50 +0000 |
1780 | @@ -0,0 +1,83 @@ |
1781 | +/* |
1782 | + Copyright (c) 2010 by Dennis Schridde |
1783 | + |
1784 | + This file is part of dovecot-metadata. |
1785 | + |
1786 | + dovecot-metadata is free software: you can redistribute it and/or modify |
1787 | + it under the terms of the GNU Lesser General Public License as published by |
1788 | + the Free Software Foundation, either version 3 of the License, or |
1789 | + (at your option) any later version. |
1790 | + |
1791 | + dovecot-metadata is distributed in the hope that it will be useful, |
1792 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
1793 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1794 | + GNU Lesser General Public License for more details. |
1795 | + |
1796 | + You should have received a copy of the GNU Lesser General Public License |
1797 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
1798 | +*/ |
1799 | +#include "imap-arg-ext.h" |
1800 | + |
1801 | +#include <stdlib.h> |
1802 | + |
1803 | +bool |
1804 | +imap_arg_get_astringlist(const struct imap_arg *arg, const char ***list_r) { |
1805 | + i_assert(list_r != NULL); |
1806 | + if (list_r == NULL) { |
1807 | + return false; |
1808 | + } |
1809 | + |
1810 | + if (*list_r != NULL) { |
1811 | + free(*list_r); |
1812 | + *list_r = NULL; |
1813 | + } |
1814 | + |
1815 | + size_t list_size = 0; |
1816 | + |
1817 | + if (arg->type == IMAP_ARG_LIST) { // entries |
1818 | + const struct imap_arg *arglist = NULL; |
1819 | + if (!imap_arg_get_list(arg, &arglist)) { |
1820 | + return false; |
1821 | + } |
1822 | + |
1823 | + while (arglist[list_size].type != IMAP_ARG_EOL) { |
1824 | + const char *astring = NULL; |
1825 | + if (!imap_arg_get_astring(&arglist[list_size], &astring)) { |
1826 | + free(*list_r); |
1827 | + *list_r = NULL; |
1828 | + return false; |
1829 | + } |
1830 | + |
1831 | + *list_r = realloc(*list_r, (list_size+2)*sizeof(*list_r)); |
1832 | + if (*list_r == NULL) { |
1833 | + return false; |
1834 | + } |
1835 | + |
1836 | + (*list_r)[list_size] = astring; |
1837 | + |
1838 | + list_size++; |
1839 | + } |
1840 | + } |
1841 | + else if (IMAP_ARG_TYPE_IS_ASTRING(arg->type)) { |
1842 | + const char *astring = NULL; |
1843 | + if (!imap_arg_get_astring(arg, &astring)) { |
1844 | + return false; |
1845 | + } |
1846 | + |
1847 | + *list_r = realloc(*list_r, (list_size+2)*sizeof(*list_r)); |
1848 | + if (*list_r == NULL) { |
1849 | + return false; |
1850 | + } |
1851 | + |
1852 | + (*list_r)[list_size] = astring; |
1853 | + |
1854 | + list_size++; |
1855 | + } |
1856 | + else { |
1857 | + return false; |
1858 | + } |
1859 | + |
1860 | + (*list_r)[list_size] = NULL; |
1861 | + |
1862 | + return true; |
1863 | +} |
1864 | |
1865 | === added file 'src/imap-arg-ext.h' |
1866 | --- src/imap-arg-ext.h 1970-01-01 00:00:00 +0000 |
1867 | +++ src/imap-arg-ext.h 2011-09-29 19:49:50 +0000 |
1868 | @@ -0,0 +1,32 @@ |
1869 | +/* |
1870 | + Copyright (c) 2010 by Dennis Schridde |
1871 | + |
1872 | + This file is part of dovecot-metadata. |
1873 | + |
1874 | + dovecot-metadata is free software: you can redistribute it and/or modify |
1875 | + it under the terms of the GNU Lesser General Public License as published by |
1876 | + the Free Software Foundation, either version 3 of the License, or |
1877 | + (at your option) any later version. |
1878 | + |
1879 | + dovecot-metadata is distributed in the hope that it will be useful, |
1880 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
1881 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1882 | + GNU Lesser General Public License for more details. |
1883 | + |
1884 | + You should have received a copy of the GNU Lesser General Public License |
1885 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
1886 | +*/ |
1887 | +#ifndef DOVECOT_IMAP_ARG_EXT_H |
1888 | +#define DOVECOT_IMAP_ARG_EXT_H |
1889 | + |
1890 | +#include "metadata-global.h" |
1891 | + |
1892 | +#include <stdbool.h> |
1893 | + |
1894 | +#include "imap-arg.h" |
1895 | + |
1896 | +bool |
1897 | +imap_arg_get_astringlist(const struct imap_arg *arg, const char ***list_r) |
1898 | + ATTR_WARN_UNUSED_RESULT; |
1899 | + |
1900 | +#endif |
1901 | |
1902 | === added file 'src/imap-metadata-plugin.c' |
1903 | --- src/imap-metadata-plugin.c 1970-01-01 00:00:00 +0000 |
1904 | +++ src/imap-metadata-plugin.c 2011-09-29 19:49:50 +0000 |
1905 | @@ -0,0 +1,699 @@ |
1906 | +/* |
1907 | + Copyright (c) 2010 by Dennis Schridde |
1908 | + |
1909 | + This file is part of dovecot-metadata. |
1910 | + |
1911 | + dovecot-metadata is free software: you can redistribute it and/or modify |
1912 | + it under the terms of the GNU Lesser General Public License as published by |
1913 | + the Free Software Foundation, either version 3 of the License, or |
1914 | + (at your option) any later version. |
1915 | + |
1916 | + dovecot-metadata is distributed in the hope that it will be useful, |
1917 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
1918 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1919 | + GNU Lesser General Public License for more details. |
1920 | + |
1921 | + You should have received a copy of the GNU Lesser General Public License |
1922 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
1923 | +*/ |
1924 | +#include "metadata-global.h" |
1925 | + |
1926 | +#include "imap-common.h" |
1927 | +#include "imap-client.h" |
1928 | +#include "imap-quote.h" |
1929 | + |
1930 | +#include <stdbool.h> |
1931 | +#include <stdlib.h> |
1932 | + |
1933 | +#include "str-ext.h" |
1934 | +#include "imap-arg-ext.h" |
1935 | +#include "dict-ext.h" |
1936 | +#include "metadata-entry.h" |
1937 | +#include "metadata-backend.h" |
1938 | +#include "metadata-mail-user-module-private.h" |
1939 | + |
1940 | +/* The IMAP Metadata plugin is an implementation of RFC 5464 */ |
1941 | + |
1942 | +const char *imap_metadata_plugin_version = DOVECOT_VERSION; |
1943 | +const char *imap_metadata_plugin_dependencies[] = { "metadata", NULL }; |
1944 | + |
1945 | +static struct module *imap_metadata_module; |
1946 | +static void (*next_hook_client_created)(struct client **client); |
1947 | + |
1948 | + |
1949 | +static const char * |
1950 | +entry_scopes[ENTRY_SCOPE_MAX] = { |
1951 | + "private/", /* ENTRY_SCOPE_PRIVATE */ |
1952 | + "shared/" /* ENTRY_SCOPE_SHARED */ |
1953 | +}; |
1954 | + |
1955 | +static const char * |
1956 | +entry_types[ENTRY_TYPE_MAX] = { |
1957 | + "vendor/", /* ENTRY_TYPE_VENDOR */ |
1958 | + "", /* ENTRY_TYPE_RFC */ |
1959 | +}; |
1960 | + |
1961 | +static const char ** |
1962 | +entry_subtypes_rfc[ENTRY_SUBJECT_MAX] = { |
1963 | + (const char*[]){ // server |
1964 | + "comment", |
1965 | + "admin", |
1966 | + NULL |
1967 | + }, |
1968 | + (const char*[]){ // mailbox |
1969 | + "comment", |
1970 | + NULL |
1971 | + } |
1972 | +}; |
1973 | + |
1974 | + |
1975 | +enum getmetadata_option { |
1976 | + GETMETADATA_OPTION_MAXSIZE, |
1977 | + GETMEDADATA_OPTION_DEPTH |
1978 | +}; |
1979 | + |
1980 | +struct option_definition { |
1981 | + const char *name; |
1982 | + int num_values; |
1983 | + enum getmetadata_option option; |
1984 | +}; |
1985 | + |
1986 | +static |
1987 | +struct option_definition |
1988 | +getmetadata_options[] = { |
1989 | + {"maxsize", 1, GETMETADATA_OPTION_MAXSIZE}, |
1990 | + {"depth", 1, GETMEDADATA_OPTION_DEPTH}, |
1991 | + {NULL, 0, 0} |
1992 | +}; |
1993 | + |
1994 | + |
1995 | +static |
1996 | +struct option_definition * |
1997 | +parse_getmetadata_option(const char *option) { |
1998 | + struct option_definition *optdef = getmetadata_options; |
1999 | + while (optdef->name != NULL) { |
2000 | + if (strcasecmp(optdef->name, option) == 0) { |
2001 | + return optdef; |
2002 | + } |
2003 | + optdef++; |
2004 | + } |
2005 | + return NULL; |
2006 | +} |
2007 | + |
2008 | + |
2009 | +static int |
2010 | +parse_getmetadata_depth(const char *value) { |
2011 | + if (!str_is_numeric(value, '\0')) { |
2012 | + if (strcasecmp(value, "infinity")) |
2013 | + return METADATA_ITERATE_DEPTH_INF; |
2014 | + |
2015 | + return -1; |
2016 | + } |
2017 | + |
2018 | + char *end = NULL; |
2019 | + long int val = strtol(value, &end, 10); |
2020 | + |
2021 | + if (end == value) |
2022 | + return -2; |
2023 | + if (val == LONG_MAX) |
2024 | + return -3; |
2025 | + if (val < 0) |
2026 | + return -4; |
2027 | + |
2028 | + return val; |
2029 | +} |
2030 | + |
2031 | + |
2032 | +static int |
2033 | +parse_getmetadata_maxsize(const char *value) { |
2034 | + if (!str_is_numeric(value, '\0')) |
2035 | + return -1; |
2036 | + |
2037 | + char *end = NULL; |
2038 | + long int val = strtol(value, &end, 10); |
2039 | + |
2040 | + if (end == value) |
2041 | + return -2; |
2042 | + if (val == LONG_MAX) |
2043 | + return -3; |
2044 | + if (val < 0) |
2045 | + return -4; |
2046 | + |
2047 | + return val; |
2048 | +} |
2049 | + |
2050 | + |
2051 | +/* validates that the part after /vendor conforms to the RFC */ |
2052 | +static ATTR_NONNULL(1) |
2053 | +bool |
2054 | +is_valid_rfc5464_vendor_name(const char *name) { |
2055 | + const char *lastslash = NULL, *lastcr = NULL; |
2056 | + int num_components = 3; // "vendor/" already includes the slash of component No3 |
2057 | + |
2058 | + for (const char *c = name; *c != '\0'; c++) { |
2059 | + switch (*c) { |
2060 | + case '/': |
2061 | + // Two consecutive slashes, or a slash at the end are an error |
2062 | + if (lastslash == c-1 || *(c+1) == '\0') { |
2063 | + return false; |
2064 | + } |
2065 | + lastslash = c; |
2066 | + num_components++; |
2067 | + break; |
2068 | + case '*': |
2069 | + case '%': |
2070 | + return false; |
2071 | + case '\r': |
2072 | + lastcr = c; |
2073 | + break; |
2074 | + case '\n': |
2075 | + // line ending has to be CRLF |
2076 | + if (lastcr != c-1) { |
2077 | + return false; |
2078 | + } |
2079 | + break; |
2080 | + default: |
2081 | + break; |
2082 | + } |
2083 | + } |
2084 | + |
2085 | + return num_components >= 4; |
2086 | +} |
2087 | + |
2088 | + |
2089 | +static ATTR_NONNULL(1) |
2090 | +bool |
2091 | +is_valid_rfc5464_subtype_name(const char *name, enum metadata_entry_subject subject) { |
2092 | + bool found_subtype = false; |
2093 | + |
2094 | + i_assert(subject > 0 && subject < ENTRY_SUBJECT_MAX); |
2095 | + |
2096 | + for (const char **subtype = entry_subtypes_rfc[subject]; *subtype != NULL; subtype++) { |
2097 | + size_t subtype_len = strlen(*subtype); |
2098 | + |
2099 | + if (strncasecmp(name, *subtype, subtype_len) == 0 |
2100 | + && name[subtype_len] == '\0') { |
2101 | + found_subtype = true; |
2102 | + } |
2103 | + } |
2104 | + |
2105 | + return found_subtype; |
2106 | +} |
2107 | + |
2108 | + |
2109 | +/* sets entry->scope and returns remaining string */ |
2110 | +static ATTR_NONNULL(1) |
2111 | +enum metadata_entry_scope |
2112 | +parse_entry_scope(const char **name) { |
2113 | + for (int scope = 0; scope < ENTRY_SCOPE_MAX; scope++) { |
2114 | + size_t scope_len = strlen(entry_scopes[scope]); |
2115 | + |
2116 | + if (strncasecmp(*name, entry_scopes[scope], scope_len) == 0) { |
2117 | + *name += scope_len; |
2118 | + return scope; |
2119 | + } |
2120 | + } |
2121 | + |
2122 | + return ENTRY_SCOPE_MAX; |
2123 | +} |
2124 | + |
2125 | + |
2126 | +/* sets entry->type and returns remaining string */ |
2127 | +static ATTR_NONNULL(1) |
2128 | +enum metadata_entry_type |
2129 | +parse_entry_type(const char **name, enum metadata_entry_subject subject) { |
2130 | + for (int type = 0; type < ENTRY_TYPE_MAX; type++) { |
2131 | + size_t type_len = strlen(entry_types[type]); |
2132 | + |
2133 | + if (strncasecmp(*name, entry_types[type], type_len) == 0) { |
2134 | + *name += type_len; |
2135 | + |
2136 | + switch (type) { |
2137 | + case ENTRY_TYPE_RFC: |
2138 | + if (!is_valid_rfc5464_subtype_name(*name, subject)) |
2139 | + return ENTRY_TYPE_MAX; |
2140 | + break; |
2141 | + case ENTRY_TYPE_VENDOR: |
2142 | + if (!is_valid_rfc5464_vendor_name(*name)) |
2143 | + return ENTRY_TYPE_MAX; |
2144 | + break; |
2145 | + } |
2146 | + |
2147 | + return type; |
2148 | + } |
2149 | + } |
2150 | + |
2151 | + return ENTRY_TYPE_MAX; |
2152 | +} |
2153 | + |
2154 | + |
2155 | +/* fill entry with data parsed from entry->full_name */ |
2156 | +static ATTR_NONNULL(2) |
2157 | +struct metadata_entry * |
2158 | +parse_entry(struct mailbox *box, const char *name, const char *value) { |
2159 | + const char *name_tmp = name; |
2160 | + if (name_tmp == NULL || *name_tmp++ != '/') |
2161 | + return NULL; |
2162 | + |
2163 | + enum metadata_entry_scope scope = parse_entry_scope(&name_tmp); |
2164 | + if (scope >= ENTRY_SCOPE_MAX) |
2165 | + return NULL; |
2166 | + |
2167 | + enum metadata_entry_type type = parse_entry_type(&name_tmp, box ? ENTRY_SUBJECT_MAILBOX : ENTRY_SUBJECT_SERVER); |
2168 | + if (type >= ENTRY_TYPE_MAX) |
2169 | + return NULL; |
2170 | + |
2171 | + return metadata_entry_alloc(box, name, value); |
2172 | +} |
2173 | + |
2174 | + |
2175 | +static int |
2176 | +get_and_send_entry(struct client_command_context *cmd, struct mailbox *box, const char *name, int depth, int maxsize, int *longentries) { |
2177 | + if (str_has_wildcards(name)) { |
2178 | + client_send_tagline(cmd, "NO Wildcards in entry name not allowed."); |
2179 | + return -1; |
2180 | + } |
2181 | + |
2182 | + if (depth == 0) { |
2183 | + struct metadata_entry *entry = parse_entry(box, name, NULL); |
2184 | + if (entry == NULL) { |
2185 | + client_send_tagline(cmd, "NO Parsing entry failed."); |
2186 | + return -1; |
2187 | + } |
2188 | + |
2189 | + int success = metadata_get_entry(entry, cmd->client->user); |
2190 | + if (success < 0) { |
2191 | + i_assert(0); |
2192 | + client_send_tagline(cmd, "NO Getting entry failed."); |
2193 | + return -1; |
2194 | + } |
2195 | + else if (success > 0) { |
2196 | + const char *str = t_strdup_printf( |
2197 | + "* METADATA %s (%s %s)", |
2198 | + mailbox_get_vname(box), metadata_entry_get_name(entry), metadata_entry_get_value(entry) |
2199 | + ); |
2200 | + |
2201 | + return client_send_line(cmd->client, str); |
2202 | + } |
2203 | + |
2204 | + return 0; |
2205 | + } |
2206 | + |
2207 | + struct metadata_entry *entry = metadata_entry_alloc(box, name, NULL); |
2208 | + |
2209 | + int num_entries = 0; |
2210 | + |
2211 | + string_t *str = t_str_new(128); |
2212 | + str_append_printf(str, "* METADATA %s (", mailbox_get_vname(box)); |
2213 | + |
2214 | + struct metadata_iterate_context *iter = metadata_iterate_init(box, entry, depth); |
2215 | + while (metadata_iterate(iter, entry)) { |
2216 | + const char *name = metadata_entry_get_name(entry); |
2217 | + const char *value = metadata_entry_get_value(entry); |
2218 | + |
2219 | + /* only respect maxsize if it is not 'undefined' */ |
2220 | + if (maxsize > 0) { |
2221 | + size_t val_len = strlen(value); |
2222 | + if (val_len > maxsize && val_len > *longentries) { |
2223 | + *longentries = val_len; |
2224 | + continue; |
2225 | + } |
2226 | + } |
2227 | + |
2228 | + str_append_printf(str, "%s %s ", name, value); |
2229 | + |
2230 | + num_entries++; |
2231 | + } |
2232 | + if (metadata_iterate_deinit(&iter) < 0) { |
2233 | + client_send_tagline(cmd, "NO Iterating metadata failed."); |
2234 | + return -1; |
2235 | + } |
2236 | + |
2237 | + str_append(str, ")"); |
2238 | + |
2239 | + if (num_entries > 0) { |
2240 | + return client_send_line(cmd->client, str_c(str)); |
2241 | + } |
2242 | + |
2243 | + return 0; |
2244 | +} |
2245 | + |
2246 | + |
2247 | +static bool |
2248 | +cmd_getmetadata(struct client_command_context *cmd) { |
2249 | + const struct imap_arg *args; |
2250 | + int maxsize = 0, depth = 0; |
2251 | + |
2252 | + if (!client_read_args(cmd, 0, 0, &args)) |
2253 | + return false; |
2254 | + |
2255 | + if (args[0].type == IMAP_ARG_LIST) { // options |
2256 | + const struct imap_arg *arglist = NULL; |
2257 | + if (!imap_arg_get_list(&args[0], &arglist)) { |
2258 | + client_send_command_error(cmd, "Cannot read options, list expected."); |
2259 | + return true; |
2260 | + } |
2261 | + |
2262 | + while (arglist->type != IMAP_ARG_EOL) { |
2263 | + if (!IMAP_ARG_TYPE_IS_ASTRING(arglist->type)) { |
2264 | + client_send_command_error(cmd, "Option not a string."); |
2265 | + return true; |
2266 | + } |
2267 | + |
2268 | + const char *option = NULL; |
2269 | + if (!imap_arg_get_astring(arglist, &option)){ |
2270 | + client_send_command_error(cmd, "Cannot read option, string expected."); |
2271 | + return true; |
2272 | + } |
2273 | + |
2274 | + struct option_definition *optdef = parse_getmetadata_option(option); |
2275 | + if (optdef == NULL) { |
2276 | + const char *estr = t_strdup_printf("Unknown option: %s.", option); |
2277 | + client_send_command_error(cmd, estr); |
2278 | + return true; |
2279 | + } |
2280 | + |
2281 | + arglist++; |
2282 | + |
2283 | + const char *values[optdef->num_values]; |
2284 | + memset(values, 0, sizeof(*values) * optdef->num_values); |
2285 | + |
2286 | + for (int i = 0; i < optdef->num_values; i++) { |
2287 | + if (!IMAP_ARG_TYPE_IS_ASTRING(arglist[i].type)) { |
2288 | + const char *estr = t_strdup_printf( |
2289 | + "Value %d/%d of %s not a string.", |
2290 | + i, optdef->num_values, option |
2291 | + ); |
2292 | + client_send_command_error(cmd, estr); |
2293 | + return true; |
2294 | + } |
2295 | + |
2296 | + if (!imap_arg_get_astring(&arglist[i], &values[i])){ |
2297 | + const char *estr = t_strdup_printf( |
2298 | + "Cannot read value %d/%d of %s, string expected.", |
2299 | + i, optdef->num_values, option |
2300 | + ); |
2301 | + client_send_command_error(cmd, estr); |
2302 | + return true; |
2303 | + } |
2304 | + } |
2305 | + |
2306 | + switch (optdef->option) { |
2307 | + case GETMEDADATA_OPTION_DEPTH: |
2308 | + depth = parse_getmetadata_depth(values[0]); |
2309 | + if (depth < 0) { |
2310 | + client_send_command_error(cmd, "Value 1/1 of DEPTH is not numeric and positive or \"infinity\"."); |
2311 | + return true; |
2312 | + } |
2313 | + break; |
2314 | + case GETMETADATA_OPTION_MAXSIZE: |
2315 | + maxsize = parse_getmetadata_maxsize(values[0]); |
2316 | + if (maxsize < 0) { |
2317 | + client_send_command_error(cmd, "Value 1/1 of MAXSIZE is not numeric and positive."); |
2318 | + return true; |
2319 | + } |
2320 | + break; |
2321 | + } |
2322 | + |
2323 | + arglist += optdef->num_values; |
2324 | + } |
2325 | + |
2326 | + args++; |
2327 | + } |
2328 | + |
2329 | + if (!IMAP_ARG_TYPE_IS_ASTRING(args[0].type)) { // mailbox name |
2330 | + client_send_command_error(cmd, "Mailbox name not a string."); |
2331 | + return true; |
2332 | + } |
2333 | + |
2334 | + const char *mailbox_name = NULL; |
2335 | + if (!imap_arg_get_astring(&args[0], &mailbox_name)){ |
2336 | + client_send_command_error(cmd, "Cannot read mailbox name, string expected."); |
2337 | + return true; |
2338 | + } |
2339 | + |
2340 | + if (mailbox_name == NULL) { |
2341 | + client_send_tagline(cmd, "NO Mailbox name is NULL."); |
2342 | + return true; |
2343 | + } |
2344 | + |
2345 | + const char **entry_names = NULL; |
2346 | + if (!imap_arg_get_astringlist(&args[1], &entry_names)) { |
2347 | + client_send_command_error(cmd, "Cannot read entries, string or list of strings expected."); |
2348 | + return true; |
2349 | + } |
2350 | + |
2351 | + int warn_longentries = 0; |
2352 | + |
2353 | + if (str_has_wildcards(mailbox_name)) { |
2354 | + for (const struct mail_namespace *ns = cmd->client->user->namespaces; ns != NULL; ns = ns->next) { |
2355 | + const struct mailbox_info *info = NULL; |
2356 | + |
2357 | + struct mailbox_list_iterate_context *ctx = mailbox_list_iter_init(ns->list, mailbox_name, 0); |
2358 | + while ((info = mailbox_list_iter_next(ctx)) != NULL) { |
2359 | + i_debug("Getting info for mailbox '%s'", info->name); |
2360 | + |
2361 | + struct mailbox *box = mailbox_alloc(ns->list, info->name, MAILBOX_FLAG_READONLY); |
2362 | + if (box == NULL) { |
2363 | + client_send_tagline(cmd, "NO Allocating mailbox failed."); |
2364 | + return TRUE; |
2365 | + } |
2366 | + |
2367 | + const char **entry_name = entry_names; |
2368 | + while (*entry_name != NULL) { |
2369 | + if (get_and_send_entry(cmd, box, *entry_name, depth, maxsize, &warn_longentries) < 0) { |
2370 | + /* get_and_send_entry outputs the response for the client, already */ |
2371 | + mailbox_free(&box); |
2372 | + return true; |
2373 | + } |
2374 | + |
2375 | + entry_name++; |
2376 | + } |
2377 | + |
2378 | + mailbox_free(&box); |
2379 | + } |
2380 | + |
2381 | + if (mailbox_list_iter_deinit(&ctx) < 0) { |
2382 | + client_send_tagline(cmd, "NO Iterating mailboxes failed."); |
2383 | + } |
2384 | + } |
2385 | + } |
2386 | + else { |
2387 | + struct mailbox *box = NULL; |
2388 | + /* empty mailbox_name -> box=NULL -> server scope */ |
2389 | + if (*mailbox_name != '\0') { |
2390 | + struct mail_namespace *ns = mail_namespace_find(cmd->client->user->namespaces, &mailbox_name); |
2391 | + if (ns == NULL) { |
2392 | + client_send_tagline(cmd, "NO Mailbox not found."); |
2393 | + return true; |
2394 | + } |
2395 | + |
2396 | + box = mailbox_alloc(ns->list, mailbox_name, MAILBOX_FLAG_READONLY); |
2397 | + if (box == NULL) { |
2398 | + client_send_tagline(cmd, "NO Allocating mailbox failed."); |
2399 | + return true; |
2400 | + } |
2401 | + } |
2402 | + |
2403 | + const char **entry_name = entry_names; |
2404 | + while (*entry_name != NULL) { |
2405 | + if (get_and_send_entry(cmd, box, *entry_name, depth, maxsize, &warn_longentries) < 0) { |
2406 | + /* get_and_send_entry outputs the response for the client, already */ |
2407 | + mailbox_free(&box); |
2408 | + return true; |
2409 | + } |
2410 | + |
2411 | + entry_name++; |
2412 | + } |
2413 | + |
2414 | + mailbox_free(&box); |
2415 | + } |
2416 | + |
2417 | + free(entry_names); |
2418 | + |
2419 | + const char *response; |
2420 | + if (warn_longentries > 0) { |
2421 | + response = t_strdup_printf("OK [METADATA LONGENTRIES %d] Completed.", warn_longentries); |
2422 | + } |
2423 | + else { |
2424 | + response = "OK Completed."; |
2425 | + } |
2426 | + client_send_tagline(cmd, response); |
2427 | + |
2428 | + return true; |
2429 | +} |
2430 | + |
2431 | + |
2432 | +static bool |
2433 | +cmd_setmetadata(struct client_command_context *cmd) { |
2434 | + const struct imap_arg *args; |
2435 | + |
2436 | + if (!client_read_args(cmd, 0, 0, &args)) |
2437 | + return false; |
2438 | + |
2439 | + if (!IMAP_ARG_TYPE_IS_ASTRING(args[0].type)) { // mailbox name |
2440 | + client_send_command_error(cmd, "Mailbox name not a string."); |
2441 | + return true; |
2442 | + } |
2443 | + |
2444 | + const char *mailbox_name = NULL; |
2445 | + if (!imap_arg_get_astring(&args[0], &mailbox_name)){ |
2446 | + client_send_command_error(cmd, "Cannot read mailbox name, string expected."); |
2447 | + return true; |
2448 | + } |
2449 | + |
2450 | + if (mailbox_name == NULL) { |
2451 | + client_send_tagline(cmd, "NO Mailbox name is NULL."); |
2452 | + return true; |
2453 | + } |
2454 | + |
2455 | + struct mailbox *box = NULL; |
2456 | + /* empty name -> box=NULL -> server scope */ |
2457 | + if (*mailbox_name != '\0') { |
2458 | + struct mail_namespace *ns = mail_namespace_find(cmd->client->user->namespaces, &mailbox_name); |
2459 | + if (ns == NULL) { |
2460 | + client_send_tagline(cmd, "NO Mailbox not found."); |
2461 | + return true; |
2462 | + } |
2463 | + |
2464 | + box = mailbox_alloc(ns->list, mailbox_name, MAILBOX_FLAG_READONLY); |
2465 | + if (box == NULL) { |
2466 | + client_send_tagline(cmd, "NO Allocating mailbox failed."); |
2467 | + return true; |
2468 | + } |
2469 | + } |
2470 | + |
2471 | + bool warn_maxsize = false, warn_toomany = false, warn_noprivate = false; |
2472 | + |
2473 | + if (args[1].type == IMAP_ARG_LIST) { // entries |
2474 | + const struct imap_arg *arglist = NULL; |
2475 | + if (!imap_arg_get_list(&args[1], &arglist)){ |
2476 | + client_send_command_error(cmd, "Cannot read entries, list expected."); |
2477 | + mailbox_free(&box); |
2478 | + return true; |
2479 | + } |
2480 | + |
2481 | + while (arglist[0].type != IMAP_ARG_EOL) { |
2482 | + if (!IMAP_ARG_TYPE_IS_ASTRING(arglist[0].type)) { |
2483 | + client_send_command_error(cmd, "Entry name not a string."); |
2484 | + mailbox_free(&box); |
2485 | + return true; |
2486 | + } |
2487 | + |
2488 | + const char *name = NULL; |
2489 | + if (!imap_arg_get_astring(&arglist[0], &name)){ |
2490 | + client_send_command_error(cmd, "Cannot read entry name, string expected."); |
2491 | + mailbox_free(&box); |
2492 | + return true; |
2493 | + } |
2494 | + |
2495 | + if (name == NULL) { |
2496 | + client_send_tagline(cmd, "NO Entry name is NULL."); |
2497 | + mailbox_free(&box); |
2498 | + return true; |
2499 | + } |
2500 | + |
2501 | + const char *value; |
2502 | + if (arglist[1].type == IMAP_ARG_NIL) { |
2503 | + value = NULL; |
2504 | + } |
2505 | + else if (IMAP_ARG_TYPE_IS_ASTRING(arglist[1].type)) { |
2506 | + if (!imap_arg_get_astring(&arglist[1], &value)){ |
2507 | + client_send_command_error(cmd, "Cannot read value, string expected."); |
2508 | + mailbox_free(&box); |
2509 | + return true; |
2510 | + } |
2511 | + } |
2512 | + else { |
2513 | + client_send_command_error(cmd, "Value not nil or string."); |
2514 | + mailbox_free(&box); |
2515 | + return true; |
2516 | + } |
2517 | + |
2518 | + struct metadata_entry *entry = parse_entry(box, name, value); |
2519 | + if (entry == NULL) { |
2520 | + client_send_tagline(cmd, "NO Parsing entry failed."); |
2521 | + mailbox_free(&box); |
2522 | + return true; |
2523 | + } |
2524 | + |
2525 | + int ret = metadata_set_entry(entry, cmd->client->user); |
2526 | + if (ret == -2) { |
2527 | + warn_maxsize = true; |
2528 | + } |
2529 | + else if (ret == -3) { |
2530 | + warn_toomany = true; |
2531 | + } |
2532 | + else if (ret < 0) { |
2533 | + client_send_tagline(cmd, "NO Setting entry failed."); |
2534 | + mailbox_free(&box); |
2535 | + return true; |
2536 | + } |
2537 | + |
2538 | + /* skip this name/value pair */ |
2539 | + arglist += 2; |
2540 | + } |
2541 | + } |
2542 | + else { |
2543 | + client_send_command_error(cmd, "Entries not a list."); |
2544 | + mailbox_free(&box); |
2545 | + return true; |
2546 | + } |
2547 | + |
2548 | + const char *response; |
2549 | + if (warn_maxsize) { |
2550 | + struct metadata_mail_user *muser = METADATA_USER_CONTEXT(cmd->client->user); |
2551 | + if (muser == NULL) { |
2552 | + i_error("metadata: found NULL user, can't set metadata"); |
2553 | + client_send_tagline(cmd, "NO Internal error."); |
2554 | + mailbox_free(&box); |
2555 | + return true; |
2556 | + } |
2557 | + |
2558 | + response = t_strdup_printf("OK [METADATA MAXSIZE %d] Completed.", muser->set->maxsize); |
2559 | + } |
2560 | + else if (warn_toomany) { |
2561 | + response = t_strdup_printf("OK [METADATA TOOMANY] Completed."); |
2562 | + } |
2563 | + else if (warn_noprivate) { |
2564 | + response = t_strdup_printf("OK [METADATA NOPRIVATE] Completed."); |
2565 | + } |
2566 | + else { |
2567 | + response = "OK Completed."; |
2568 | + } |
2569 | + client_send_tagline(cmd, response); |
2570 | + |
2571 | + mailbox_free(&box); |
2572 | + |
2573 | + return true; |
2574 | +} |
2575 | + |
2576 | + |
2577 | +static void imap_metadata_client_created(struct client **client) |
2578 | +{ |
2579 | + if (mail_user_is_plugin_loaded((*client)->user, imap_metadata_module)) |
2580 | + str_append((*client)->capability_string, " METADATA"); |
2581 | + |
2582 | + if (next_hook_client_created != NULL) |
2583 | + next_hook_client_created(client); |
2584 | +} |
2585 | + |
2586 | + |
2587 | +void imap_metadata_plugin_init(struct module *module) |
2588 | +{ |
2589 | + command_register("GETMETADATA", cmd_getmetadata, 0); |
2590 | + command_register("SETMETADATA", cmd_setmetadata, 0); |
2591 | + |
2592 | + imap_metadata_module = module; |
2593 | + next_hook_client_created = hook_client_created; |
2594 | + hook_client_created = imap_metadata_client_created; |
2595 | +} |
2596 | + |
2597 | + |
2598 | +void imap_metadata_plugin_deinit(void) |
2599 | +{ |
2600 | + command_unregister("SETMETADATA"); |
2601 | + command_unregister("GETMETADATA"); |
2602 | + |
2603 | + hook_client_created = next_hook_client_created; |
2604 | +} |
2605 | |
2606 | === added file 'src/mailbox-ext.c' |
2607 | --- src/mailbox-ext.c 1970-01-01 00:00:00 +0000 |
2608 | +++ src/mailbox-ext.c 2011-09-29 19:49:50 +0000 |
2609 | @@ -0,0 +1,30 @@ |
2610 | +/* |
2611 | + Copyright (c) 2010 by Dennis Schridde |
2612 | + |
2613 | + This file is part of dovecot-metadata. |
2614 | + |
2615 | + dovecot-metadata is free software: you can redistribute it and/or modify |
2616 | + it under the terms of the GNU Lesser General Public License as published by |
2617 | + the Free Software Foundation, either version 3 of the License, or |
2618 | + (at your option) any later version. |
2619 | + |
2620 | + dovecot-metadata is distributed in the hope that it will be useful, |
2621 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
2622 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2623 | + GNU Lesser General Public License for more details. |
2624 | + |
2625 | + You should have received a copy of the GNU Lesser General Public License |
2626 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
2627 | +*/ |
2628 | +#include "mailbox-ext.h" |
2629 | + |
2630 | +#include "hex-binary.h" |
2631 | + |
2632 | +const char * |
2633 | +mailbox_get_guid_string(struct mailbox *box) { |
2634 | + uint8_t guid[MAIL_GUID_128_SIZE]; |
2635 | + if (mailbox_get_guid(box, guid) < 0) |
2636 | + return NULL; |
2637 | + |
2638 | + return binary_to_hex(guid, sizeof(guid)); |
2639 | +} |
2640 | |
2641 | === added file 'src/mailbox-ext.h' |
2642 | --- src/mailbox-ext.h 1970-01-01 00:00:00 +0000 |
2643 | +++ src/mailbox-ext.h 2011-09-29 19:49:50 +0000 |
2644 | @@ -0,0 +1,30 @@ |
2645 | +/* |
2646 | + Copyright (c) 2010 by Dennis Schridde |
2647 | + |
2648 | + This file is part of dovecot-metadata. |
2649 | + |
2650 | + dovecot-metadata is free software: you can redistribute it and/or modify |
2651 | + it under the terms of the GNU Lesser General Public License as published by |
2652 | + the Free Software Foundation, either version 3 of the License, or |
2653 | + (at your option) any later version. |
2654 | + |
2655 | + dovecot-metadata is distributed in the hope that it will be useful, |
2656 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
2657 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2658 | + GNU Lesser General Public License for more details. |
2659 | + |
2660 | + You should have received a copy of the GNU Lesser General Public License |
2661 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
2662 | +*/ |
2663 | +#ifndef DOVECOT_MAILBOX_EXT_H |
2664 | +#define DOVECOT_MAILBOX_EXT_H |
2665 | + |
2666 | +#include "metadata-global.h" |
2667 | + |
2668 | +#include "mail-storage.h" |
2669 | + |
2670 | +const char * |
2671 | +mailbox_get_guid_string(struct mailbox *box) |
2672 | + ATTR_NONNULL(1); |
2673 | + |
2674 | +#endif |
2675 | |
2676 | === added file 'src/metadata-backend.c' |
2677 | --- src/metadata-backend.c 1970-01-01 00:00:00 +0000 |
2678 | +++ src/metadata-backend.c 2011-09-29 19:49:50 +0000 |
2679 | @@ -0,0 +1,296 @@ |
2680 | +/* |
2681 | + Copyright (c) 2010 by Dennis Schridde |
2682 | + |
2683 | + This file is part of dovecot-metadata. |
2684 | + |
2685 | + dovecot-metadata is free software: you can redistribute it and/or modify |
2686 | + it under the terms of the GNU Lesser General Public License as published by |
2687 | + the Free Software Foundation, either version 3 of the License, or |
2688 | + (at your option) any later version. |
2689 | + |
2690 | + dovecot-metadata is distributed in the hope that it will be useful, |
2691 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
2692 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2693 | + GNU Lesser General Public License for more details. |
2694 | + |
2695 | + You should have received a copy of the GNU Lesser General Public License |
2696 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
2697 | +*/ |
2698 | +#include "metadata-backend.h" |
2699 | + |
2700 | +#include "dict.h" |
2701 | +#include "mail-storage.h" |
2702 | + |
2703 | +#include <string.h> |
2704 | + |
2705 | +#include "str-ext.h" |
2706 | +#include "dict-ext.h" |
2707 | +#include "mailbox-ext.h" |
2708 | +#include "metadata-entry-private.h" |
2709 | +#include "metadata-mail-user-module-private.h" |
2710 | + |
2711 | +static const char * |
2712 | +dict_subjects[ENTRY_SUBJECT_MAX+1] = { |
2713 | + "server/", /* ENTRY_SUBJECT_SERVER */ |
2714 | + "mailbox/", /* ENTRY_SUBJECT_MAILBOX */ |
2715 | + NULL |
2716 | +}; |
2717 | + |
2718 | +static const char* |
2719 | +dictsubject_from_entry(struct metadata_entry *entry) { |
2720 | + switch (metadata_entry_get_subject(entry)) { |
2721 | + case ENTRY_SUBJECT_SERVER: |
2722 | + return dict_subjects[ENTRY_SUBJECT_SERVER]; |
2723 | + case ENTRY_SUBJECT_MAILBOX: |
2724 | + return t_strconcat(dict_subjects[ENTRY_SUBJECT_MAILBOX], entry->mailbox_guid, "/", NULL); |
2725 | + case ENTRY_SUBJECT_MAX: |
2726 | + return NULL; |
2727 | + } |
2728 | + |
2729 | + return NULL; |
2730 | +} |
2731 | + |
2732 | +static const char* |
2733 | +t_dictkey_from_entry(struct metadata_entry *entry) { |
2734 | + const char *subject = dictsubject_from_entry(entry); |
2735 | + if (subject == NULL) |
2736 | + return NULL; |
2737 | + |
2738 | + const char *path_prefix = NULL; |
2739 | + switch (metadata_entry_get_scope(entry)) { |
2740 | + case ENTRY_SCOPE_SHARED: |
2741 | + path_prefix = DICT_PATH_SHARED; |
2742 | + break; |
2743 | + case ENTRY_SCOPE_PRIVATE: |
2744 | + path_prefix = DICT_PATH_PRIVATE; |
2745 | + break; |
2746 | + case ENTRY_SCOPE_INVALID: |
2747 | + case ENTRY_SCOPE_NONE: |
2748 | + return NULL; |
2749 | + } |
2750 | + |
2751 | + // -> "prefix/" "subject/" "name" |
2752 | + return t_strconcat(path_prefix, subject, &entry->name[1], NULL); |
2753 | +} |
2754 | + |
2755 | +static int |
2756 | +count_entries(struct metadata_mail_user *muser) { |
2757 | + struct dict_iterate_context *iter; |
2758 | + const char *key; |
2759 | + const char *value; |
2760 | + int num = 0; |
2761 | + |
2762 | + iter = dict_iterate_init(muser->dict, DICT_PATH_SHARED, DICT_ITERATE_FLAG_RECURSE); |
2763 | + while (dict_iterate(iter, &key, &value)) { |
2764 | + num++; |
2765 | + } |
2766 | + if (dict_iterate_deinit(&iter) < 0) { |
2767 | + i_error("metadata: dict iteration failed, can't count shared entries"); |
2768 | + return -1; |
2769 | + } |
2770 | + iter = dict_iterate_init(muser->dict, DICT_PATH_PRIVATE, DICT_ITERATE_FLAG_RECURSE); |
2771 | + while (dict_iterate(iter, &key, &value)) { |
2772 | + num++; |
2773 | + } |
2774 | + if (dict_iterate_deinit(&iter) < 0) { |
2775 | + i_error("metadata: dict iteration failed, can't count private entries"); |
2776 | + return -1; |
2777 | + } |
2778 | + |
2779 | + return num; |
2780 | +} |
2781 | + |
2782 | +int |
2783 | +metadata_set_entry(struct metadata_entry *entry, struct mail_user *user) { |
2784 | + struct metadata_mail_user *muser = METADATA_USER_CONTEXT(user); |
2785 | + if (muser == NULL) { |
2786 | + i_error("metadata: found NULL user, can't set their metadata"); |
2787 | + return -1; |
2788 | + } |
2789 | + |
2790 | + if (!metadata_entry_is_valid(entry)) |
2791 | + return -4; |
2792 | + if (strlen(entry->name) > muser->set->maxsize) |
2793 | + return -2; |
2794 | + if (count_entries(muser) > muser->set->maxentries) |
2795 | + return -3; |
2796 | + |
2797 | + const char *key = t_dictkey_from_entry(entry); |
2798 | + if (key == NULL) |
2799 | + return -1; |
2800 | + |
2801 | + struct dict_transaction_context *dt = dict_transaction_begin(muser->dict); |
2802 | + |
2803 | + if (entry->value == NULL) |
2804 | + dict_unset(dt, key); |
2805 | + else |
2806 | + dict_set(dt, key, entry->value); |
2807 | + |
2808 | + if (dict_transaction_commit(&dt) < 0) { |
2809 | + i_error("metadata: dict commit failed"); |
2810 | + return -1; |
2811 | + } |
2812 | + |
2813 | + return 0; |
2814 | +} |
2815 | + |
2816 | +int |
2817 | +metadata_get_entry(struct metadata_entry *entry, struct mail_user *user) { |
2818 | + struct metadata_mail_user *muser = METADATA_USER_CONTEXT(user); |
2819 | + if (muser == NULL) { |
2820 | + i_error("metadata: found NULL user, can't get their metadata"); |
2821 | + return -1; |
2822 | + } |
2823 | + |
2824 | + if (!metadata_entry_is_valid(entry)) |
2825 | + return -4; |
2826 | + |
2827 | + const char *key = t_dictkey_from_entry(entry); |
2828 | + if (key == NULL) |
2829 | + return -1; |
2830 | + |
2831 | + return dict_lookup(muser->dict, user->pool, key, &entry->value); |
2832 | +} |
2833 | + |
2834 | +struct metadata_iterate_context { |
2835 | + struct dict_iterate_multiscope_context *dict_ctx; |
2836 | + int depth; |
2837 | + bool failed; |
2838 | +}; |
2839 | + |
2840 | +struct metadata_iterate_context* |
2841 | +metadata_iterate_init(struct mailbox *mailbox, struct metadata_entry *entry, int depth) { |
2842 | + struct metadata_iterate_context *ctx = i_new(struct metadata_iterate_context, 1); |
2843 | + memset(ctx, 0, sizeof(*ctx)); |
2844 | + |
2845 | + struct mail_storage *storage = mailbox_get_storage(mailbox); |
2846 | + struct mail_user *user = mail_storage_get_user(storage); |
2847 | + struct metadata_mail_user *muser = METADATA_USER_CONTEXT(user); |
2848 | + if (muser == NULL) { |
2849 | + i_error("metadata: found NULL user, can't iterate over their metadata"); |
2850 | + ctx->failed = true; |
2851 | + return ctx; |
2852 | + } |
2853 | + |
2854 | + i_assert(entry != NULL); |
2855 | + if (entry == NULL) { |
2856 | + ctx->failed = true; |
2857 | + return ctx; |
2858 | + } |
2859 | + |
2860 | + const char *entry_name = metadata_entry_get_name(entry); |
2861 | + const int root_depth = strchr_num(entry_name, '/'); |
2862 | + ctx->depth = root_depth + depth; |
2863 | + |
2864 | + enum dict_iterate_multiscope_flags flags = 0; |
2865 | + if (depth != 0) |
2866 | + flags |= DICT_ITERATE_FLAG_RECURSE; |
2867 | + |
2868 | + switch (metadata_entry_get_scope(entry)) { |
2869 | + case ENTRY_SCOPE_SHARED: |
2870 | + case ENTRY_SCOPE_PRIVATE: |
2871 | + break; |
2872 | + case ENTRY_SCOPE_INVALID: |
2873 | + ctx->failed = true; |
2874 | + return ctx; |
2875 | + case ENTRY_SCOPE_NONE: |
2876 | + flags |= DICT_ITERATE_MULTISCOPE_FLAG_MULTISCOPE; |
2877 | + break; |
2878 | + } |
2879 | + |
2880 | + const char *key = t_dictkey_from_entry(entry); |
2881 | + if (key == NULL) { |
2882 | + ctx->failed = true; |
2883 | + return ctx; |
2884 | + } |
2885 | + |
2886 | + ctx->dict_ctx = dict_iterate_multiscope_init(muser->dict, key, flags); |
2887 | + if (ctx->dict_ctx == NULL) { |
2888 | + ctx->failed = true; |
2889 | + return ctx; |
2890 | + } |
2891 | + |
2892 | + return ctx; |
2893 | +} |
2894 | + |
2895 | +static ATTR_NONNULL(2) |
2896 | +const char * |
2897 | +entry_name_from_dict_name(enum metadata_entry_subject subject, const char *dict_name) { |
2898 | + /* skip dict internal prefixes: priv/ or shared/ */ |
2899 | + const char *name_after_scope = strchr(dict_name, '/'); |
2900 | + if (name_after_scope == NULL) { |
2901 | + return NULL; |
2902 | + } |
2903 | + |
2904 | + /* skip '/' */ |
2905 | + name_after_scope++; |
2906 | + |
2907 | + /* skip dict internal prefixes: server/ or mailbox/ */ |
2908 | + const char *name_after_subject = strchr(name_after_scope, '/'); |
2909 | + if (name_after_subject == NULL) { |
2910 | + return NULL; |
2911 | + } |
2912 | + |
2913 | + /* do not skip '/', the name needs to start with a '/'! */ |
2914 | + |
2915 | + /* skip dict internal prefixes: <mailbox_guid>/ (for mailboxes only) */ |
2916 | + if (subject == ENTRY_SUBJECT_MAILBOX) { |
2917 | + name_after_subject = strchr(name_after_subject+1, '/'); |
2918 | + if (name_after_subject == NULL) { |
2919 | + return NULL; |
2920 | + } |
2921 | + } |
2922 | + |
2923 | + return name_after_subject; |
2924 | +} |
2925 | + |
2926 | +bool |
2927 | +metadata_iterate(struct metadata_iterate_context *ctx, struct metadata_entry *entry) { |
2928 | + i_assert(ctx != NULL); |
2929 | + if (ctx == NULL) |
2930 | + return false; |
2931 | + |
2932 | + if (ctx->failed) |
2933 | + return false; |
2934 | + |
2935 | + entry->name = NULL; |
2936 | + while (entry->name == NULL) { |
2937 | + const char *dict_name = NULL, *dict_value = NULL; |
2938 | + if (!dict_iterate_multiscope(ctx->dict_ctx, &dict_name, &dict_value)) |
2939 | + return false; |
2940 | + |
2941 | + const char *entry_name = entry_name_from_dict_name(metadata_entry_get_subject(entry), dict_name); |
2942 | + if (entry_name == NULL) { |
2943 | + ctx->failed = true; |
2944 | + return false; |
2945 | + } |
2946 | + |
2947 | + if (ctx->depth != METADATA_ITERATE_DEPTH_INF && strchr_num(entry_name, '/') > ctx->depth) |
2948 | + continue; |
2949 | + |
2950 | + entry->name = i_strdup(entry_name); |
2951 | + entry->value = i_strdup(dict_value); |
2952 | + } |
2953 | + |
2954 | + return true; |
2955 | +} |
2956 | + |
2957 | +int |
2958 | +metadata_iterate_deinit(struct metadata_iterate_context **ctx) { |
2959 | + i_assert(ctx != NULL); |
2960 | + if (ctx == NULL) |
2961 | + return -1; |
2962 | + |
2963 | + i_assert(*ctx != NULL); |
2964 | + if (*ctx == NULL) |
2965 | + return -1; |
2966 | + |
2967 | + int ret = (*ctx)->failed ? -1 : 0; |
2968 | + |
2969 | + if ((*ctx)->dict_ctx != NULL && dict_iterate_multiscope_deinit(&(*ctx)->dict_ctx) < 0) |
2970 | + ret = -1; |
2971 | + |
2972 | + i_free(*ctx); |
2973 | + |
2974 | + return ret; |
2975 | +} |
2976 | |
2977 | === added file 'src/metadata-backend.h' |
2978 | --- src/metadata-backend.h 1970-01-01 00:00:00 +0000 |
2979 | +++ src/metadata-backend.h 2011-09-29 19:49:50 +0000 |
2980 | @@ -0,0 +1,49 @@ |
2981 | +/* |
2982 | + Copyright (c) 2010 by Dennis Schridde |
2983 | + |
2984 | + This file is part of dovecot-metadata. |
2985 | + |
2986 | + dovecot-metadata is free software: you can redistribute it and/or modify |
2987 | + it under the terms of the GNU Lesser General Public License as published by |
2988 | + the Free Software Foundation, either version 3 of the License, or |
2989 | + (at your option) any later version. |
2990 | + |
2991 | + dovecot-metadata is distributed in the hope that it will be useful, |
2992 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
2993 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2994 | + GNU Lesser General Public License for more details. |
2995 | + |
2996 | + You should have received a copy of the GNU Lesser General Public License |
2997 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
2998 | +*/ |
2999 | +#ifndef DOVECOT_METADATA_BACKEND_H |
3000 | +#define DOVECOT_METADATA_BACKEND_H |
3001 | + |
3002 | +#include "metadata-global.h" |
3003 | + |
3004 | +#include <stdbool.h> |
3005 | + |
3006 | +#include "metadata-entry.h" |
3007 | + |
3008 | +int |
3009 | +metadata_get_entry(struct metadata_entry *entry, struct mail_user *user) |
3010 | + ATTR_NONNULL(1,2); |
3011 | +int |
3012 | +metadata_set_entry(struct metadata_entry *entry, struct mail_user *user) |
3013 | + ATTR_NONNULL(1,2); |
3014 | + |
3015 | +const int METADATA_ITERATE_DEPTH_INF = INT_MAX; |
3016 | + |
3017 | +struct metadata_iterate_context; |
3018 | + |
3019 | +struct metadata_iterate_context * |
3020 | +metadata_iterate_init(struct mailbox *mailbox, struct metadata_entry *entry, int depth) |
3021 | + ATTR_NONNULL(1,2); |
3022 | +bool |
3023 | +metadata_iterate(struct metadata_iterate_context *ctx, struct metadata_entry *entry) |
3024 | + ATTR_NONNULL(1,2); |
3025 | +int |
3026 | +metadata_iterate_deinit(struct metadata_iterate_context **ctx) |
3027 | + ATTR_NONNULL(1); |
3028 | + |
3029 | +#endif |
3030 | |
3031 | === added file 'src/metadata-entry-private.h' |
3032 | --- src/metadata-entry-private.h 1970-01-01 00:00:00 +0000 |
3033 | +++ src/metadata-entry-private.h 2011-09-29 19:49:50 +0000 |
3034 | @@ -0,0 +1,32 @@ |
3035 | +/* |
3036 | + Copyright (c) 2010 by Dennis Schridde |
3037 | + |
3038 | + This file is part of dovecot-metadata. |
3039 | + |
3040 | + dovecot-metadata is free software: you can redistribute it and/or modify |
3041 | + it under the terms of the GNU Lesser General Public License as published by |
3042 | + the Free Software Foundation, either version 3 of the License, or |
3043 | + (at your option) any later version. |
3044 | + |
3045 | + dovecot-metadata is distributed in the hope that it will be useful, |
3046 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
3047 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3048 | + GNU Lesser General Public License for more details. |
3049 | + |
3050 | + You should have received a copy of the GNU Lesser General Public License |
3051 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
3052 | +*/ |
3053 | +#ifndef DOVECOT_METADATA_ENTRY_PRIVATE_H |
3054 | +#define DOVECOT_METADATA_ENTRY_PRIVATE_H |
3055 | + |
3056 | +#include "metadata-entry.h" |
3057 | + |
3058 | +struct metadata_entry { |
3059 | + enum metadata_entry_scope scope; |
3060 | + enum metadata_entry_type type; |
3061 | + const char *mailbox_guid; // implicitly defines the subject! |
3062 | + const char *name; |
3063 | + const char *value; |
3064 | +}; |
3065 | + |
3066 | +#endif |
3067 | |
3068 | === added file 'src/metadata-entry.c' |
3069 | --- src/metadata-entry.c 1970-01-01 00:00:00 +0000 |
3070 | +++ src/metadata-entry.c 2011-09-29 19:49:50 +0000 |
3071 | @@ -0,0 +1,173 @@ |
3072 | +/* |
3073 | + Copyright (c) 2010 by Dennis Schridde |
3074 | + |
3075 | + This file is part of dovecot-metadata. |
3076 | + |
3077 | + dovecot-metadata is free software: you can redistribute it and/or modify |
3078 | + it under the terms of the GNU Lesser General Public License as published by |
3079 | + the Free Software Foundation, either version 3 of the License, or |
3080 | + (at your option) any later version. |
3081 | + |
3082 | + dovecot-metadata is distributed in the hope that it will be useful, |
3083 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
3084 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3085 | + GNU Lesser General Public License for more details. |
3086 | + |
3087 | + You should have received a copy of the GNU Lesser General Public License |
3088 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
3089 | +*/ |
3090 | +#include "metadata-entry-private.h" |
3091 | + |
3092 | +#include <stdlib.h> |
3093 | +#include <string.h> |
3094 | + |
3095 | + |
3096 | +#include "mailbox-ext.h" |
3097 | + |
3098 | +static |
3099 | +const char * |
3100 | +entry_scopes[ENTRY_SCOPE_MAX+1] = { |
3101 | + "private/", /* ENTRY_SCOPE_PRIVATE */ |
3102 | + "shared/", /* ENTRY_SCOPE_SHARED */ |
3103 | + NULL |
3104 | +}; |
3105 | + |
3106 | +static |
3107 | +enum metadata_entry_scope |
3108 | +parse_scope(const char *name) { |
3109 | + if (name == NULL) |
3110 | + return ENTRY_SCOPE_INVALID; |
3111 | + |
3112 | + /* scope must be empty or begin with '/' */ |
3113 | + if (name[0] != '/') { |
3114 | + if (name[0] == '\0') |
3115 | + return ENTRY_SCOPE_NONE; |
3116 | + |
3117 | + return ENTRY_SCOPE_INVALID; |
3118 | + } |
3119 | + |
3120 | + /* skip '/' */ |
3121 | + name++; |
3122 | + |
3123 | + /* scope is the first component */ |
3124 | + for (int i = 0; i < ENTRY_SCOPE_MAX; i++) { |
3125 | + if (strncasecmp(entry_scopes[i], name, strlen(entry_scopes[i])) == 0) |
3126 | + return i; |
3127 | + } |
3128 | + |
3129 | + return ENTRY_SCOPE_INVALID; |
3130 | +} |
3131 | + |
3132 | +static |
3133 | +const char * |
3134 | +entry_types[ENTRY_TYPE_MAX+1] = { |
3135 | + "vendor/", /* ENTRY_TYPE_VENDOR */ |
3136 | + "", /* ENTRY_TYPE_RFC */ |
3137 | + NULL |
3138 | +}; |
3139 | + |
3140 | +static |
3141 | +enum metadata_entry_type |
3142 | +parse_type(const char *name) { |
3143 | + /* lazy evaluation of scope existance */ |
3144 | + if (name == NULL || *name++ != '/') |
3145 | + return ENTRY_TYPE_INVALID; |
3146 | + |
3147 | + /* type is the second component */ |
3148 | + name = strchr(name, '/'); |
3149 | + if (name++ == NULL) |
3150 | + return ENTRY_TYPE_NONE; |
3151 | + |
3152 | + for (int i = 0; i < ENTRY_TYPE_MAX; i++) { |
3153 | + if (strncasecmp(entry_types[i], name, strlen(entry_types[i])) == 0) |
3154 | + return i; |
3155 | + } |
3156 | + |
3157 | + return ENTRY_TYPE_INVALID; |
3158 | +} |
3159 | + |
3160 | +/* create entry on mailbox with name=value */ |
3161 | +struct metadata_entry * |
3162 | +metadata_entry_alloc(struct mailbox *mailbox, const char *name, const char *value) { |
3163 | + struct metadata_entry *entry = i_new(struct metadata_entry, 1); |
3164 | + memset(entry, 0, sizeof(*entry)); |
3165 | + |
3166 | + if (mailbox != NULL) { |
3167 | + const char *mailbox_guid = mailbox_get_guid_string(mailbox); |
3168 | + if (mailbox_guid != NULL) |
3169 | + entry->mailbox_guid = strdup(mailbox_guid); |
3170 | + } |
3171 | + |
3172 | + entry->scope = parse_scope(name); |
3173 | + entry->type = parse_type(name); |
3174 | + if (metadata_entry_is_valid(entry)) { |
3175 | + if (name != NULL) |
3176 | + entry->name = strdup(name); |
3177 | + if (value != NULL) |
3178 | + entry->value = strdup(value); |
3179 | + } |
3180 | + |
3181 | + return entry; |
3182 | +} |
3183 | + |
3184 | +/* free structures allocated for entry and invalidate it */ |
3185 | +void |
3186 | +entry_free(struct metadata_entry *entry) { |
3187 | + free((char*)entry->value); |
3188 | + free((char*)entry->name); |
3189 | + memset(entry, 0, sizeof(*entry)); |
3190 | +} |
3191 | + |
3192 | +bool |
3193 | +metadata_entry_is_valid(struct metadata_entry *entry) { |
3194 | + i_assert(entry != NULL); |
3195 | + if (entry == NULL) |
3196 | + return false; |
3197 | + |
3198 | + return entry->scope < ENTRY_SCOPE_MAX && entry->type < ENTRY_TYPE_MAX; |
3199 | +} |
3200 | + |
3201 | +const char * |
3202 | +metadata_entry_get_name(struct metadata_entry *entry) { |
3203 | + i_assert(entry != NULL); |
3204 | + if (entry == NULL) |
3205 | + return NULL; |
3206 | + |
3207 | + return entry->name; |
3208 | +} |
3209 | + |
3210 | +const char * |
3211 | +metadata_entry_get_value(struct metadata_entry *entry) { |
3212 | + i_assert(entry != NULL); |
3213 | + if (entry == NULL) |
3214 | + return NULL; |
3215 | + |
3216 | + return entry->value; |
3217 | +} |
3218 | + |
3219 | +enum metadata_entry_subject |
3220 | +metadata_entry_get_subject(struct metadata_entry *entry) { |
3221 | + i_assert(entry != NULL); |
3222 | + if (entry == NULL) |
3223 | + return ENTRY_SUBJECT_INVALID; |
3224 | + |
3225 | + return entry->mailbox_guid ? ENTRY_SUBJECT_MAILBOX : ENTRY_SUBJECT_SERVER; |
3226 | +} |
3227 | + |
3228 | +enum metadata_entry_scope |
3229 | +metadata_entry_get_scope(struct metadata_entry *entry) { |
3230 | + i_assert(entry != NULL); |
3231 | + if (entry == NULL) |
3232 | + return ENTRY_SCOPE_INVALID; |
3233 | + |
3234 | + return entry->scope; |
3235 | +} |
3236 | + |
3237 | +enum metadata_entry_type |
3238 | +metadata_entry_get_type(struct metadata_entry *entry) { |
3239 | + i_assert(entry != NULL); |
3240 | + if (entry == NULL) |
3241 | + return ENTRY_TYPE_INVALID; |
3242 | + |
3243 | + return entry->type; |
3244 | +} |
3245 | |
3246 | === added file 'src/metadata-entry.h' |
3247 | --- src/metadata-entry.h 1970-01-01 00:00:00 +0000 |
3248 | +++ src/metadata-entry.h 2011-09-29 19:49:50 +0000 |
3249 | @@ -0,0 +1,83 @@ |
3250 | +/* |
3251 | + Copyright (c) 2010 by Dennis Schridde |
3252 | + |
3253 | + This file is part of dovecot-metadata. |
3254 | + |
3255 | + dovecot-metadata is free software: you can redistribute it and/or modify |
3256 | + it under the terms of the GNU Lesser General Public License as published by |
3257 | + the Free Software Foundation, either version 3 of the License, or |
3258 | + (at your option) any later version. |
3259 | + |
3260 | + dovecot-metadata is distributed in the hope that it will be useful, |
3261 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
3262 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3263 | + GNU Lesser General Public License for more details. |
3264 | + |
3265 | + You should have received a copy of the GNU Lesser General Public License |
3266 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
3267 | +*/ |
3268 | +#ifndef DOVECOT_METADATA_ENTRY_H |
3269 | +#define DOVECOT_METADATA_ENTRY_H |
3270 | + |
3271 | +#include "metadata-global.h" |
3272 | + |
3273 | +#include <stdbool.h> |
3274 | + |
3275 | +#include "mail-storage.h" |
3276 | + |
3277 | +enum metadata_entry_subject { |
3278 | + ENTRY_SUBJECT_SERVER = 0, |
3279 | + ENTRY_SUBJECT_MAILBOX = 1, |
3280 | + ENTRY_SUBJECT_MAX, |
3281 | + ENTRY_SUBJECT_INVALID = ENTRY_SUBJECT_MAX |
3282 | +}; |
3283 | + |
3284 | +enum metadata_entry_scope { |
3285 | + ENTRY_SCOPE_PRIVATE = 0, |
3286 | + ENTRY_SCOPE_SHARED = 1, |
3287 | + ENTRY_SCOPE_MAX, |
3288 | + ENTRY_SCOPE_INVALID = ENTRY_SCOPE_MAX, |
3289 | + ENTRY_SCOPE_NONE |
3290 | +}; |
3291 | + |
3292 | +enum metadata_entry_type { |
3293 | + ENTRY_TYPE_VENDOR = 0, |
3294 | + ENTRY_TYPE_RFC = 1, |
3295 | + ENTRY_TYPE_MAX, |
3296 | + ENTRY_TYPE_INVALID = ENTRY_TYPE_MAX, |
3297 | + ENTRY_TYPE_NONE |
3298 | +}; |
3299 | + |
3300 | +struct metadata_entry * |
3301 | +metadata_entry_alloc(struct mailbox *mailbox, const char *name, const char *value) |
3302 | + ATTR_NONNULL(2); |
3303 | + |
3304 | +void |
3305 | +metadata_entry_free(struct metadata_entry *entry) |
3306 | + ATTR_NONNULL(1); |
3307 | + |
3308 | +bool |
3309 | +metadata_entry_is_valid(struct metadata_entry *entry) |
3310 | + ATTR_NONNULL(1); |
3311 | + |
3312 | +const char * |
3313 | +metadata_entry_get_name(struct metadata_entry *entry) |
3314 | + ATTR_NONNULL(1); |
3315 | + |
3316 | +const char * |
3317 | +metadata_entry_get_value(struct metadata_entry *entry) |
3318 | + ATTR_NONNULL(1); |
3319 | + |
3320 | +enum metadata_entry_subject |
3321 | +metadata_entry_get_subject(struct metadata_entry *entry) |
3322 | + ATTR_NONNULL(1); |
3323 | + |
3324 | +enum metadata_entry_scope |
3325 | +metadata_entry_get_scope(struct metadata_entry *entry) |
3326 | + ATTR_NONNULL(1); |
3327 | + |
3328 | +enum metadata_entry_type |
3329 | +metadata_entry_get_type(struct metadata_entry *entry) |
3330 | + ATTR_NONNULL(1); |
3331 | + |
3332 | +#endif |
3333 | |
3334 | === added file 'src/metadata-global.h' |
3335 | --- src/metadata-global.h 1970-01-01 00:00:00 +0000 |
3336 | +++ src/metadata-global.h 2011-09-29 19:49:50 +0000 |
3337 | @@ -0,0 +1,52 @@ |
3338 | +/* |
3339 | + Copyright (c) 2010 by Dennis Schridde |
3340 | + |
3341 | + This file is part of dovecot-metadata. |
3342 | + |
3343 | + dovecot-metadata is free software: you can redistribute it and/or modify |
3344 | + it under the terms of the GNU Lesser General Public License as published by |
3345 | + the Free Software Foundation, either version 3 of the License, or |
3346 | + (at your option) any later version. |
3347 | + |
3348 | + dovecot-metadata is distributed in the hope that it will be useful, |
3349 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
3350 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3351 | + GNU Lesser General Public License for more details. |
3352 | + |
3353 | + You should have received a copy of the GNU Lesser General Public License |
3354 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
3355 | +*/ |
3356 | +#ifndef DOVECOT_METADATA_GLOBAL_H |
3357 | +#define DOVECOT_METADATA_GLOBAL_H |
3358 | + |
3359 | +/* |
3360 | + the dovecot include system needs its own special care: |
3361 | + * include lib.h first, always |
3362 | + * reset all the symbols we use by including metadata-config.h.in, |
3363 | + since dovecot's internal config.h leaks through their public headers |
3364 | +*/ |
3365 | +#include "lib.h" |
3366 | + |
3367 | +#define ATTR_NONNULL(...) __attribute__((__nonnull__(__VA_ARGS__))) |
3368 | + |
3369 | +/* |
3370 | + = error values = |
3371 | + < 0 is always an error |
3372 | + 0 means success or no-more-data |
3373 | + > 0 means more-data-available |
3374 | + |
3375 | + = return types = |
3376 | + void can never have errors |
3377 | + |
3378 | + == logical functions == |
3379 | + return bool and cannot have errors |
3380 | + |
3381 | + == functions returning pointers == |
3382 | + NULL is an error, everything else not |
3383 | + |
3384 | + == data handling functions == |
3385 | + bool is a continous function which cannot have errors |
3386 | + int is any function which can have errors |
3387 | +*/ |
3388 | + |
3389 | +#endif |
3390 | |
3391 | === added file 'src/metadata-mail-storage-module.c' |
3392 | --- src/metadata-mail-storage-module.c 1970-01-01 00:00:00 +0000 |
3393 | +++ src/metadata-mail-storage-module.c 2011-09-29 19:49:50 +0000 |
3394 | @@ -0,0 +1,92 @@ |
3395 | +/* |
3396 | + Copyright (c) 2010 by Dennis Schridde |
3397 | + |
3398 | + This file is part of dovecot-metadata. |
3399 | + |
3400 | + dovecot-metadata is free software: you can redistribute it and/or modify |
3401 | + it under the terms of the GNU Lesser General Public License as published by |
3402 | + the Free Software Foundation, either version 3 of the License, or |
3403 | + (at your option) any later version. |
3404 | + |
3405 | + dovecot-metadata is distributed in the hope that it will be useful, |
3406 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
3407 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3408 | + GNU Lesser General Public License for more details. |
3409 | + |
3410 | + You should have received a copy of the GNU Lesser General Public License |
3411 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
3412 | +*/ |
3413 | +#include "metadata-mail-storage-module.h" |
3414 | + |
3415 | +#include "dict.h" |
3416 | +#include "module-context.h" |
3417 | +#include "mail-storage-private.h" |
3418 | + |
3419 | +#include "mailbox-ext.h" |
3420 | +#include "metadata-mail-user-module-private.h" |
3421 | + |
3422 | +#define METADATA_MAILBOX_CONTEXT(obj) MODULE_CONTEXT(obj, metadata_mailbox_module) |
3423 | + |
3424 | +static MODULE_CONTEXT_DEFINE_INIT(metadata_mailbox_module, &mail_storage_module_register); |
3425 | + |
3426 | +static int |
3427 | +metadata_mailbox_delete(struct mailbox *box) { |
3428 | + union mailbox_module_context *mbox = METADATA_MAILBOX_CONTEXT(box); |
3429 | + if (mbox == NULL) { |
3430 | + i_error("metadata: found NULL mailbox, can't delete it"); |
3431 | + return -1; |
3432 | + } |
3433 | + |
3434 | + struct mail_storage *storage = mailbox_get_storage(box); |
3435 | + struct mail_user *user = mail_storage_get_user(storage); |
3436 | + struct metadata_mail_user *muser = METADATA_USER_CONTEXT(user); |
3437 | + if (muser == NULL) { |
3438 | + i_error("metadata: found NULL user, can't delete mailbox"); |
3439 | + return -1; |
3440 | + } |
3441 | + |
3442 | + struct dict_transaction_context *dt = dict_transaction_begin(muser->dict); |
3443 | + |
3444 | + const char *name; |
3445 | + const char *value; |
3446 | + |
3447 | + const char *skey = t_strconcat(DICT_PATH_SHARED, mailbox_get_guid_string(box), NULL); |
3448 | + |
3449 | + struct dict_iterate_context *siter = dict_iterate_init(muser->dict, skey, DICT_ITERATE_FLAG_RECURSE); |
3450 | + while (dict_iterate(siter, &name, &value)) { |
3451 | + dict_unset(dt, name); |
3452 | + } |
3453 | + if (dict_iterate_deinit(&siter) < 0) { |
3454 | + i_error("metadata: dict iteration (" DICT_PATH_SHARED ") failed, can't update dict"); |
3455 | + return -1; |
3456 | + } |
3457 | + |
3458 | + const char *pkey = t_strconcat(DICT_PATH_PRIVATE, mailbox_get_guid_string(box), NULL); |
3459 | + |
3460 | + struct dict_iterate_context *piter = dict_iterate_init(muser->dict, pkey, DICT_ITERATE_FLAG_RECURSE); |
3461 | + while (dict_iterate(piter, &name, &value)) { |
3462 | + dict_unset(dt, name); |
3463 | + } |
3464 | + if (dict_iterate_deinit(&piter) < 0) { |
3465 | + i_error("metadata: dict iteration (" DICT_PATH_PRIVATE ") failed, can't update dict"); |
3466 | + return -1; |
3467 | + } |
3468 | + |
3469 | + int super_ret = mbox->super.delete(box); |
3470 | + if (super_ret < 0) { |
3471 | + dict_transaction_rollback(&dt); |
3472 | + } else if (dict_transaction_commit(&dt) < 0) { |
3473 | + i_error("metadata: dict commit failed"); |
3474 | + return -1; |
3475 | + } |
3476 | + |
3477 | + return super_ret; |
3478 | +} |
3479 | + |
3480 | +void metadata_mailbox_allocated(struct mailbox *box) { |
3481 | + union mailbox_module_context *mbox = p_new(box->pool, union mailbox_module_context, 1); |
3482 | + mbox->super = box->v; |
3483 | + box->v.delete = metadata_mailbox_delete; |
3484 | + |
3485 | + MODULE_CONTEXT_SET_SELF(box, metadata_mailbox_module, mbox); |
3486 | +} |
3487 | |
3488 | === added file 'src/metadata-mail-storage-module.h' |
3489 | --- src/metadata-mail-storage-module.h 1970-01-01 00:00:00 +0000 |
3490 | +++ src/metadata-mail-storage-module.h 2011-09-29 19:49:50 +0000 |
3491 | @@ -0,0 +1,28 @@ |
3492 | +/* |
3493 | + Copyright (c) 2010 by Dennis Schridde |
3494 | + |
3495 | + This file is part of dovecot-metadata. |
3496 | + |
3497 | + dovecot-metadata is free software: you can redistribute it and/or modify |
3498 | + it under the terms of the GNU Lesser General Public License as published by |
3499 | + the Free Software Foundation, either version 3 of the License, or |
3500 | + (at your option) any later version. |
3501 | + |
3502 | + dovecot-metadata is distributed in the hope that it will be useful, |
3503 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
3504 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3505 | + GNU Lesser General Public License for more details. |
3506 | + |
3507 | + You should have received a copy of the GNU Lesser General Public License |
3508 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
3509 | +*/ |
3510 | +#ifndef DOVECOT_METADATA_MAIL_STORAGE_MODULE_H |
3511 | +#define DOVECOT_METADATA_MAIL_STORAGE_MODULE_H |
3512 | + |
3513 | +#include "metadata-global.h" |
3514 | + |
3515 | +#include "mail-storage.h" |
3516 | + |
3517 | +void metadata_mailbox_allocated(struct mailbox *box); |
3518 | + |
3519 | +#endif |
3520 | |
3521 | === added file 'src/metadata-mail-user-module-private.h' |
3522 | --- src/metadata-mail-user-module-private.h 1970-01-01 00:00:00 +0000 |
3523 | +++ src/metadata-mail-user-module-private.h 2011-09-29 19:49:50 +0000 |
3524 | @@ -0,0 +1,40 @@ |
3525 | +/* |
3526 | + Copyright (c) 2010 by Dennis Schridde |
3527 | + |
3528 | + This file is part of dovecot-metadata. |
3529 | + |
3530 | + dovecot-metadata is free software: you can redistribute it and/or modify |
3531 | + it under the terms of the GNU Lesser General Public License as published by |
3532 | + the Free Software Foundation, either version 3 of the License, or |
3533 | + (at your option) any later version. |
3534 | + |
3535 | + dovecot-metadata is distributed in the hope that it will be useful, |
3536 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
3537 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3538 | + GNU Lesser General Public License for more details. |
3539 | + |
3540 | + You should have received a copy of the GNU Lesser General Public License |
3541 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
3542 | +*/ |
3543 | +#ifndef DOVECOT_METADATA_MAIL_USER_MODULE_PRIVATE_H |
3544 | +#define DOVECOT_METADATA_MAIL_USER_MODULE_PRIVATE_H |
3545 | + |
3546 | +#include "metadata-mail-user-module.h" |
3547 | + |
3548 | +#include "dict.h" |
3549 | +#include "module-context.h" |
3550 | +#include "mail-user.h" |
3551 | + |
3552 | +#include "metadata-settings.h" |
3553 | + |
3554 | +#define METADATA_USER_CONTEXT(obj) MODULE_CONTEXT(obj, metadata_mail_user_module) |
3555 | + |
3556 | +extern MODULE_CONTEXT_DEFINE(metadata_mail_user_module, &mail_user_module_register); |
3557 | + |
3558 | +struct metadata_mail_user { |
3559 | + union mail_user_module_context module_ctx; |
3560 | + struct dict *dict; |
3561 | + struct metadata_settings *set; |
3562 | +}; |
3563 | + |
3564 | +#endif |
3565 | |
3566 | === added file 'src/metadata-mail-user-module.c' |
3567 | --- src/metadata-mail-user-module.c 1970-01-01 00:00:00 +0000 |
3568 | +++ src/metadata-mail-user-module.c 2011-09-29 19:49:50 +0000 |
3569 | @@ -0,0 +1,56 @@ |
3570 | +/* |
3571 | + Copyright (c) 2010 by Dennis Schridde |
3572 | + |
3573 | + This file is part of dovecot-metadata. |
3574 | + |
3575 | + dovecot-metadata is free software: you can redistribute it and/or modify |
3576 | + it under the terms of the GNU Lesser General Public License as published by |
3577 | + the Free Software Foundation, either version 3 of the License, or |
3578 | + (at your option) any later version. |
3579 | + |
3580 | + dovecot-metadata is distributed in the hope that it will be useful, |
3581 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
3582 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3583 | + GNU Lesser General Public License for more details. |
3584 | + |
3585 | + You should have received a copy of the GNU Lesser General Public License |
3586 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
3587 | +*/ |
3588 | +#include "metadata-mail-user-module-private.h" |
3589 | + |
3590 | +struct metadata_mail_user_module metadata_mail_user_module = |
3591 | + MODULE_CONTEXT_INIT(&mail_user_module_register); |
3592 | + |
3593 | +static void metadata_mail_user_deinit(struct mail_user *user) { |
3594 | + struct metadata_mail_user *muser = METADATA_USER_CONTEXT(user); |
3595 | + if (muser == NULL) { |
3596 | + i_error("metadata: found NULL user, can't deinit it"); |
3597 | + return; |
3598 | + } |
3599 | + |
3600 | + if (muser->dict != NULL) { |
3601 | + dict_deinit(&muser->dict); |
3602 | + } |
3603 | + |
3604 | + if (muser->set != NULL) { |
3605 | + metadata_settings_deinit(&muser->set); |
3606 | + } |
3607 | + |
3608 | + return muser->module_ctx.super.deinit(user); |
3609 | +} |
3610 | + |
3611 | +void metadata_mail_user_created(struct mail_user *user) { |
3612 | + struct metadata_mail_user *muser = p_new(user->pool, struct metadata_mail_user, 1); |
3613 | + muser->module_ctx.super = user->v; |
3614 | + user->v.deinit = metadata_mail_user_deinit; |
3615 | + |
3616 | + metadata_settings_init(&muser->set, user); |
3617 | + |
3618 | + if (muser->set->dict_uri != NULL) { |
3619 | + muser->dict = dict_init(muser->set->dict_uri, DICT_DATA_TYPE_STRING, user->username, user->set->base_dir); |
3620 | + if (muser->dict == NULL) |
3621 | + i_error("metadata: dict_init(%s) failed", muser->set->dict_uri); |
3622 | + } |
3623 | + |
3624 | + MODULE_CONTEXT_SET(user, metadata_mail_user_module, muser); |
3625 | +} |
3626 | |
3627 | === added file 'src/metadata-mail-user-module.h' |
3628 | --- src/metadata-mail-user-module.h 1970-01-01 00:00:00 +0000 |
3629 | +++ src/metadata-mail-user-module.h 2011-09-29 19:49:50 +0000 |
3630 | @@ -0,0 +1,28 @@ |
3631 | +/* |
3632 | + Copyright (c) 2010 by Dennis Schridde |
3633 | + |
3634 | + This file is part of dovecot-metadata. |
3635 | + |
3636 | + dovecot-metadata is free software: you can redistribute it and/or modify |
3637 | + it under the terms of the GNU Lesser General Public License as published by |
3638 | + the Free Software Foundation, either version 3 of the License, or |
3639 | + (at your option) any later version. |
3640 | + |
3641 | + dovecot-metadata is distributed in the hope that it will be useful, |
3642 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
3643 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3644 | + GNU Lesser General Public License for more details. |
3645 | + |
3646 | + You should have received a copy of the GNU Lesser General Public License |
3647 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
3648 | +*/ |
3649 | +#ifndef DOVECOT_METADATA_MAIL_USER_MODULE_H |
3650 | +#define DOVECOT_METADATA_MAIL_USER_MODULE_H |
3651 | + |
3652 | +#include "metadata-global.h" |
3653 | + |
3654 | +#include "mail-user.h" |
3655 | + |
3656 | +void metadata_mail_user_created(struct mail_user *user); |
3657 | + |
3658 | +#endif |
3659 | |
3660 | === modified file 'src/metadata-plugin.c' |
3661 | --- src/metadata-plugin.c 2010-08-11 17:11:01 +0000 |
3662 | +++ src/metadata-plugin.c 2011-09-29 19:49:50 +0000 |
3663 | @@ -1,352 +1,41 @@ |
3664 | -/* Copyright (C) 2008, 2009 by Intevation GmbH |
3665 | - * Authors: |
3666 | - * Bernhard Herzog <bh@intevation.de> |
3667 | - * |
3668 | - * This program is free software under the LGPL (>=v2.1) |
3669 | - * Read the file COPYING coming with the software for details. |
3670 | - */ |
3671 | - |
3672 | -#include "lib.h" |
3673 | -#include "dict.h" |
3674 | -#include "common.h" |
3675 | -#include "commands-util.h" |
3676 | -#include "module-context.h" |
3677 | -#include "mailbox-list-private.h" |
3678 | - |
3679 | -#include "metadata-plugin.h" |
3680 | - |
3681 | -#include <stdlib.h> |
3682 | - |
3683 | - |
3684 | -#define METADATA_LIST_CONTEXT(obj) \ |
3685 | - MODULE_CONTEXT((obj), metadata_mailbox_list_module) |
3686 | -static MODULE_CONTEXT_DEFINE_INIT(metadata_mailbox_list_module, |
3687 | - &mailbox_list_module_register); |
3688 | - |
3689 | -struct metadata_mailbox_list { |
3690 | - union mailbox_list_module_context module_ctx; |
3691 | +/* |
3692 | + Copyright (c) 2010 by Dennis Schridde |
3693 | + |
3694 | + This file is part of dovecot-metadata. |
3695 | + |
3696 | + dovecot-metadata is free software: you can redistribute it and/or modify |
3697 | + it under the terms of the GNU Lesser General Public License as published by |
3698 | + the Free Software Foundation, either version 3 of the License, or |
3699 | + (at your option) any later version. |
3700 | + |
3701 | + dovecot-metadata is distributed in the hope that it will be useful, |
3702 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
3703 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3704 | + GNU Lesser General Public License for more details. |
3705 | + |
3706 | + You should have received a copy of the GNU Lesser General Public License |
3707 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
3708 | +*/ |
3709 | +#include "metadata-global.h" |
3710 | + |
3711 | +#include "mail-storage-hooks.h" |
3712 | + |
3713 | +#include "metadata-mail-user-module.h" |
3714 | +#include "metadata-mail-storage-module.h" |
3715 | + |
3716 | +const char *metadata_plugin_version = DOVECOT_VERSION; |
3717 | + |
3718 | +static struct mail_storage_hooks metadata_mail_storage_hooks = { |
3719 | + .mail_user_created = metadata_mail_user_created, |
3720 | + .mailbox_allocated = metadata_mailbox_allocated |
3721 | }; |
3722 | |
3723 | -static void (*metadata_next_hook_mailbox_list_created)(struct mailbox_list *); |
3724 | - |
3725 | - |
3726 | -static struct dict *metadata_dict; |
3727 | -static bool metadata_allow_private = FALSE; |
3728 | -static bool metadata_debug = FALSE; |
3729 | - |
3730 | - |
3731 | -bool metadata_private_allowed(void) { |
3732 | - return metadata_allow_private; |
3733 | -} |
3734 | - |
3735 | - |
3736 | -static const char *mailbox_key_path(struct mailbox_list *list, |
3737 | - const char *mailboxname) |
3738 | -{ |
3739 | - return mailbox_list_get_path(list, mailboxname, |
3740 | - MAILBOX_LIST_PATH_TYPE_MAILBOX); |
3741 | -} |
3742 | - |
3743 | - |
3744 | -static const char *create_dict_key(struct mail_storage *storage, |
3745 | - const char *mailboxname, const char *entry, |
3746 | - bool private) |
3747 | -{ |
3748 | - return t_strconcat(private ? DICT_PATH_PRIVATE : DICT_PATH_SHARED, |
3749 | - mailbox_key_path(mail_storage_get_list(storage), |
3750 | - mailboxname), |
3751 | - "/", entry, NULL); |
3752 | -} |
3753 | - |
3754 | -static const char *renamed_key(const char *oldkey, const char *oldpath, |
3755 | - const char *newpath) |
3756 | -{ |
3757 | - const char *first_slash; |
3758 | - size_t oldlen; |
3759 | - |
3760 | - first_slash = strchr(oldkey, '/'); |
3761 | - if (!first_slash) |
3762 | - return NULL; |
3763 | - |
3764 | - oldlen = strlen(oldpath); |
3765 | - if (strncmp(first_slash + 1, oldpath, oldlen) == 0) { |
3766 | - return t_strconcat(t_strdup_until(oldkey, first_slash + 1), |
3767 | - newpath, |
3768 | - first_slash + 1 + oldlen, |
3769 | - NULL); |
3770 | - } |
3771 | - |
3772 | - return NULL; |
3773 | -} |
3774 | - |
3775 | -static void rename_metadata_of_mailbox(struct dict_transaction_context *dt, |
3776 | - struct mailbox_list *list, |
3777 | - const char *oldname, |
3778 | - const char *newname) |
3779 | -{ |
3780 | - struct dict_iterate_context *iter; |
3781 | - const char *oldpath; |
3782 | - const char *newpath; |
3783 | - const char *key; |
3784 | - const char *value; |
3785 | - const char *newkey; |
3786 | - |
3787 | - oldpath = mailbox_key_path(list, oldname); |
3788 | - newpath = mailbox_key_path(list, newname); |
3789 | - |
3790 | - iter = dict_iterate_init(metadata_dict, |
3791 | - t_strconcat(DICT_PATH_SHARED, oldpath, NULL), |
3792 | - DICT_ITERATE_FLAG_RECURSE |
3793 | - | DICT_ITERATE_FLAG_SORT_BY_KEY); |
3794 | - while (dict_iterate(iter, &key, &value) > 0) { |
3795 | - T_BEGIN { |
3796 | - newkey = renamed_key(key, oldpath, newpath); |
3797 | - dict_set(dt, newkey, value); |
3798 | - dict_unset(dt, key); |
3799 | - } T_END; |
3800 | - } |
3801 | - dict_iterate_deinit(&iter); |
3802 | -} |
3803 | - |
3804 | -static int rename_metadata_of_children(struct dict_transaction_context *dt, |
3805 | - struct mailbox_list *list, |
3806 | - const char *oldname, |
3807 | - const char *newname) |
3808 | -{ |
3809 | - struct mailbox_list_iterate_context *iter; |
3810 | - const struct mailbox_info *info; |
3811 | - const char *pattern; |
3812 | - size_t oldnamelen; |
3813 | - int ret; |
3814 | - |
3815 | - ret = 0; |
3816 | - |
3817 | - oldnamelen = strlen(oldname); |
3818 | - pattern = t_strdup_printf("%s%c*", oldname, |
3819 | - mailbox_list_get_hierarchy_sep(list)); |
3820 | - iter = mailbox_list_iter_init(list, pattern, |
3821 | - MAILBOX_LIST_ITER_RETURN_NO_FLAGS); |
3822 | - while ((info = mailbox_list_iter_next(iter)) != NULL) { |
3823 | - const char *renamed; |
3824 | - |
3825 | - /* verify that the prefix matches, otherwise we could have |
3826 | - problems with mailbox names containing '%' and '*' chars */ |
3827 | - if (strncmp(info->name, oldname, oldnamelen) == 0 && |
3828 | - info->name[oldnamelen] == |
3829 | - mailbox_list_get_hierarchy_sep(list)) { |
3830 | - T_BEGIN { |
3831 | - renamed = t_strconcat(newname, |
3832 | - info->name + oldnamelen, |
3833 | - NULL); |
3834 | - rename_metadata_of_mailbox(dt, list, |
3835 | - info->name, renamed); |
3836 | - } T_END; |
3837 | - } |
3838 | - } |
3839 | - |
3840 | - if (mailbox_list_iter_deinit(&iter) < 0) { |
3841 | - ret = -1; |
3842 | - } |
3843 | - |
3844 | - return ret; |
3845 | -} |
3846 | - |
3847 | -static int metadata_mailbox_list_rename(struct mailbox_list *list, |
3848 | - const char *oldname, |
3849 | - const char *newname) |
3850 | -{ |
3851 | - struct metadata_mailbox_list *mlist = METADATA_LIST_CONTEXT(list); |
3852 | - struct dict_transaction_context *dt; |
3853 | - int success; |
3854 | - |
3855 | - dt = dict_transaction_begin(metadata_dict); |
3856 | - |
3857 | - T_BEGIN { |
3858 | - rename_metadata_of_mailbox(dt, list, oldname, newname); |
3859 | - rename_metadata_of_children(dt, list, oldname, newname); |
3860 | - } T_END; |
3861 | - |
3862 | - |
3863 | - success = mlist->module_ctx.super.rename_mailbox(list, oldname, |
3864 | - newname); |
3865 | - if (success < 0) { |
3866 | - dict_transaction_rollback(&dt); |
3867 | - } else { |
3868 | - if (dict_transaction_commit(&dt) < 0) { |
3869 | - i_error("metadata_mailbox_list_rename:" |
3870 | - " could not update metadata dict"); |
3871 | - } |
3872 | - } |
3873 | - |
3874 | - return success; |
3875 | -} |
3876 | - |
3877 | -static int metadata_mailbox_list_delete(struct mailbox_list *list, |
3878 | - const char *name) |
3879 | -{ |
3880 | - struct metadata_mailbox_list *mlist = METADATA_LIST_CONTEXT(list); |
3881 | - struct dict_transaction_context *dt; |
3882 | - struct dict_iterate_context *iter; |
3883 | - const char *keypath; |
3884 | - const char *key; |
3885 | - const char *value; |
3886 | - int success; |
3887 | - |
3888 | - keypath = mailbox_key_path(list, name); |
3889 | - |
3890 | - dt = dict_transaction_begin(metadata_dict); |
3891 | - iter = dict_iterate_init(metadata_dict, t_strconcat(DICT_PATH_SHARED, |
3892 | - keypath, NULL), |
3893 | - DICT_ITERATE_FLAG_RECURSE |
3894 | - | DICT_ITERATE_FLAG_SORT_BY_KEY); |
3895 | - while (dict_iterate(iter, &key, &value) > 0) { |
3896 | - dict_unset(dt, key); |
3897 | - } |
3898 | - dict_iterate_deinit(&iter); |
3899 | - |
3900 | - success = mlist->module_ctx.super.delete_mailbox(list, name); |
3901 | - if (success < 0) { |
3902 | - dict_transaction_rollback(&dt); |
3903 | - } else { |
3904 | - if (dict_transaction_commit(&dt) < 0) { |
3905 | - i_error("metadata_mailbox_list_delete:" |
3906 | - " could not update metadata dict"); |
3907 | - } |
3908 | - } |
3909 | - |
3910 | - return success; |
3911 | -} |
3912 | - |
3913 | - |
3914 | -static void metadata_mailbox_list_created(struct mailbox_list *list) |
3915 | -{ |
3916 | - struct metadata_mailbox_list *mlist; |
3917 | - |
3918 | - mlist = p_new(list->pool, struct metadata_mailbox_list, 1); |
3919 | - mlist->module_ctx.super = list->v; |
3920 | - list->v.rename_mailbox = metadata_mailbox_list_rename; |
3921 | - list->v.delete_mailbox = metadata_mailbox_list_delete; |
3922 | - MODULE_CONTEXT_SET(list, metadata_mailbox_list_module, mlist); |
3923 | - |
3924 | - if (metadata_next_hook_mailbox_list_created != NULL) |
3925 | - metadata_next_hook_mailbox_list_created(list); |
3926 | -} |
3927 | - |
3928 | - |
3929 | -bool metadata_get_metadata_entry(struct client_command_context *cmd, |
3930 | - const char *mailboxname, const char *entry, |
3931 | - const char **value_r, bool private) |
3932 | -{ |
3933 | - int success; |
3934 | - struct mail_storage *storage; |
3935 | - const char *key; |
3936 | - |
3937 | - if (metadata_debug) |
3938 | - i_info("metadata_get_metadata_entry: mailboxname=%s, entry=%s," |
3939 | - " private=%d", mailboxname, entry, private); |
3940 | - |
3941 | - if (!client_verify_mailbox_name(cmd, mailboxname, |
3942 | - CLIENT_VERIFY_MAILBOX_SHOULD_EXIST)) |
3943 | - return FALSE; |
3944 | - |
3945 | - storage = client_find_storage(cmd, &mailboxname); |
3946 | - if (!storage) |
3947 | - return FALSE; |
3948 | - |
3949 | - key = create_dict_key(storage, mailboxname, entry, private); |
3950 | - if (metadata_debug) |
3951 | - i_info("metadata_get_metadata_entry: dict key=%s", key); |
3952 | - |
3953 | - success = dict_lookup(metadata_dict, cmd->pool, key, value_r); |
3954 | - |
3955 | - if (success == 0) { |
3956 | - *value_r = NULL; |
3957 | - } else if (success < 0) { |
3958 | - client_send_tagline(cmd, "NO Lookup failed."); |
3959 | - } |
3960 | - |
3961 | - return success >= 0; |
3962 | -} |
3963 | - |
3964 | -bool metadata_set_metadata_entry(struct client_command_context *cmd, |
3965 | - const char *mailboxname, const char *entry, |
3966 | - const char *value, bool private) |
3967 | -{ |
3968 | - struct dict_transaction_context *dt; |
3969 | - struct mail_storage *storage; |
3970 | - const char *key; |
3971 | - |
3972 | - if (metadata_debug) |
3973 | - i_info("metadata_set_metadata_entry: mailboxname=%s, entry=%s," |
3974 | - " value=%s, private=%d", mailboxname, entry, |
3975 | - value != NULL ? value : "<NULL>", private); |
3976 | - |
3977 | - if (!client_verify_mailbox_name(cmd, mailboxname, |
3978 | - CLIENT_VERIFY_MAILBOX_SHOULD_EXIST)) |
3979 | - return FALSE; |
3980 | - |
3981 | - storage = client_find_storage(cmd, &mailboxname); |
3982 | - if (!storage) |
3983 | - return FALSE; |
3984 | - |
3985 | - key = create_dict_key(storage, mailboxname, entry, private); |
3986 | - if (metadata_debug) |
3987 | - i_info("metadata_set_metadata_entry: dict key=%s", key); |
3988 | - |
3989 | - dt = dict_transaction_begin(metadata_dict); |
3990 | - |
3991 | - if (value != NULL) { |
3992 | - dict_set(dt, key, value); |
3993 | - } else { |
3994 | - dict_unset(dt, key); |
3995 | - } |
3996 | - |
3997 | - if (dict_transaction_commit(&dt) < 0) |
3998 | - { |
3999 | - client_send_tagline(cmd, "NO Setting meta-data failed."); |
4000 | - return FALSE; |
4001 | - } |
4002 | - |
4003 | - return TRUE; |
4004 | -} |
4005 | - |
4006 | -void metadata_plugin_init(void) |
4007 | -{ |
4008 | - const char *username; |
4009 | - const char *dict_uri; |
4010 | - const char *base_dir; |
4011 | - |
4012 | - username = getenv("USER"); |
4013 | - if (username == NULL) |
4014 | - i_fatal("metadata plugin: USER unset"); |
4015 | - |
4016 | - dict_uri = getenv("METADATA_DICT"); |
4017 | - if (dict_uri == NULL) |
4018 | - i_fatal("metadata plugin: METADATA_DICT unset"); |
4019 | - |
4020 | - metadata_allow_private = getenv("METADATA_ALLOW_PRIVATE") != NULL; |
4021 | - metadata_debug = getenv("METADATA_DEBUG") != NULL; |
4022 | - |
4023 | - base_dir = getenv("BASE_DIR"); |
4024 | - if (base_dir == NULL) |
4025 | - base_dir = PKG_RUNDIR; |
4026 | - metadata_dict = dict_init(dict_uri, DICT_DATA_TYPE_STRING, username, |
4027 | - base_dir); |
4028 | - |
4029 | - if (metadata_dict == NULL) |
4030 | - i_fatal("metadata plugin: dict_init() failed"); |
4031 | - |
4032 | - metadata_next_hook_mailbox_list_created = hook_mailbox_list_created; |
4033 | - hook_mailbox_list_created = metadata_mailbox_list_created; |
4034 | +void metadata_plugin_init(struct module *module) |
4035 | +{ |
4036 | + mail_storage_hooks_add(module, &metadata_mail_storage_hooks); |
4037 | } |
4038 | |
4039 | void metadata_plugin_deinit(void) |
4040 | { |
4041 | - if (metadata_dict != NULL) { |
4042 | - dict_deinit(&metadata_dict); |
4043 | - } |
4044 | - if (metadata_next_hook_mailbox_list_created) { |
4045 | - hook_mailbox_list_created = |
4046 | - metadata_next_hook_mailbox_list_created; |
4047 | - } |
4048 | + mail_storage_hooks_remove(&metadata_mail_storage_hooks); |
4049 | } |
4050 | |
4051 | === removed file 'src/metadata-plugin.h' |
4052 | --- src/metadata-plugin.h 2010-08-11 17:11:01 +0000 |
4053 | +++ src/metadata-plugin.h 1970-01-01 00:00:00 +0000 |
4054 | @@ -1,17 +0,0 @@ |
4055 | -#ifndef __METADATA_PLUGIN |
4056 | -#define __METADATA_PLUGIN |
4057 | - |
4058 | -void metadata_plugin_init(void); |
4059 | -void metadata_plugin_deinit(void); |
4060 | - |
4061 | -bool metadata_private_allowed(void); |
4062 | - |
4063 | -bool metadata_get_metadata_entry(struct client_command_context *cmd, |
4064 | - const char *mailboxname, const char *entry, |
4065 | - const char **value_r, bool private); |
4066 | - |
4067 | -bool metadata_set_metadata_entry(struct client_command_context *cmd, |
4068 | - const char *mailboxname, const char *entry, |
4069 | - const char *value, bool private); |
4070 | - |
4071 | -#endif |
4072 | |
4073 | === added file 'src/metadata-settings.c' |
4074 | --- src/metadata-settings.c 1970-01-01 00:00:00 +0000 |
4075 | +++ src/metadata-settings.c 2011-09-29 19:49:50 +0000 |
4076 | @@ -0,0 +1,85 @@ |
4077 | +/* |
4078 | + Copyright (c) 2010 by Dennis Schridde |
4079 | + |
4080 | + This file is part of dovecot-metadata. |
4081 | + |
4082 | + dovecot-metadata is free software: you can redistribute it and/or modify |
4083 | + it under the terms of the GNU Lesser General Public License as published by |
4084 | + the Free Software Foundation, either version 3 of the License, or |
4085 | + (at your option) any later version. |
4086 | + |
4087 | + dovecot-metadata is distributed in the hope that it will be useful, |
4088 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
4089 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4090 | + GNU Lesser General Public License for more details. |
4091 | + |
4092 | + You should have received a copy of the GNU Lesser General Public License |
4093 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
4094 | +*/ |
4095 | +#include "metadata-settings.h" |
4096 | + |
4097 | +#include <stdlib.h> |
4098 | + |
4099 | +#define METADATA_MAXSIZE_DEFAULT 1024 |
4100 | +#define METADATA_MAXENTRIES_DEFAULT 65336 |
4101 | + |
4102 | +void |
4103 | +metadata_settings_init(struct metadata_settings **set, struct mail_user *user) { |
4104 | + *set = i_new(struct metadata_settings, 1); |
4105 | + memset(*set, 0, sizeof(**set)); |
4106 | + |
4107 | + |
4108 | + const char *dict_uri = mail_user_plugin_getenv(user, "metadata_dict"); |
4109 | + if (dict_uri != NULL) { |
4110 | + (*set)->dict_uri = dict_uri; |
4111 | + } |
4112 | + else if (user->mail_debug) { |
4113 | + i_debug("metadata: No metadata_dict setting - " |
4114 | + "metadata storage is disabled"); |
4115 | + (*set)->dict_uri = NULL; |
4116 | + } |
4117 | + |
4118 | + const char *maxsize = mail_user_plugin_getenv(user, "metadata_maxsize"); |
4119 | + if (maxsize != NULL) { |
4120 | + (*set)->maxsize = strtol(maxsize, NULL, 10); |
4121 | + if ((*set)->maxsize < 0 || (*set)->maxsize == LONG_MAX) { |
4122 | + if (user->mail_debug) { |
4123 | + i_debug("metadata: Illegal metadata_maxsize setting - " |
4124 | + "using default of %d", METADATA_MAXSIZE_DEFAULT); |
4125 | + } |
4126 | + (*set)->maxsize = METADATA_MAXSIZE_DEFAULT; |
4127 | + } |
4128 | + } |
4129 | + else { |
4130 | + if (user->mail_debug) { |
4131 | + i_debug("metadata: No metadata_maxsize setting - " |
4132 | + "using default of %d", METADATA_MAXSIZE_DEFAULT); |
4133 | + } |
4134 | + (*set)->maxsize = METADATA_MAXSIZE_DEFAULT; |
4135 | + } |
4136 | + |
4137 | + const char *maxentries = mail_user_plugin_getenv(user, "metadata_maxentries"); |
4138 | + if (maxentries != NULL) { |
4139 | + (*set)->maxentries = strtol(maxentries, NULL, 10); |
4140 | + if ((*set)->maxentries < 0 || (*set)->maxentries == LONG_MAX) { |
4141 | + if (user->mail_debug) { |
4142 | + i_debug("metadata: Illegal metadata_maxentries setting - " |
4143 | + "using default of %d", METADATA_MAXENTRIES_DEFAULT); |
4144 | + } |
4145 | + (*set)->maxentries = METADATA_MAXENTRIES_DEFAULT; |
4146 | + } |
4147 | + } |
4148 | + else { |
4149 | + if (user->mail_debug) { |
4150 | + i_debug("metadata: No metadata_maxentries setting - " |
4151 | + "using default of %d", METADATA_MAXENTRIES_DEFAULT); |
4152 | + } |
4153 | + (*set)->maxentries = METADATA_MAXENTRIES_DEFAULT; |
4154 | + } |
4155 | +} |
4156 | + |
4157 | +void |
4158 | +metadata_settings_deinit(struct metadata_settings **set) { |
4159 | + free(*set); |
4160 | + *set = NULL; |
4161 | +} |
4162 | |
4163 | === added file 'src/metadata-settings.h' |
4164 | --- src/metadata-settings.h 1970-01-01 00:00:00 +0000 |
4165 | +++ src/metadata-settings.h 2011-09-29 19:49:50 +0000 |
4166 | @@ -0,0 +1,40 @@ |
4167 | +/* |
4168 | + Copyright (c) 2010 by Dennis Schridde |
4169 | + |
4170 | + This file is part of dovecot-metadata. |
4171 | + |
4172 | + dovecot-metadata is free software: you can redistribute it and/or modify |
4173 | + it under the terms of the GNU Lesser General Public License as published by |
4174 | + the Free Software Foundation, either version 3 of the License, or |
4175 | + (at your option) any later version. |
4176 | + |
4177 | + dovecot-metadata is distributed in the hope that it will be useful, |
4178 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
4179 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4180 | + GNU Lesser General Public License for more details. |
4181 | + |
4182 | + You should have received a copy of the GNU Lesser General Public License |
4183 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
4184 | +*/ |
4185 | +#ifndef DOVECOT_METADATA_SETTINGS_H |
4186 | +#define DOVECOT_METADATA_SETTINGS_H |
4187 | + |
4188 | +#include "metadata-global.h" |
4189 | + |
4190 | +#include "mail-user.h" |
4191 | + |
4192 | +struct metadata_settings { |
4193 | + bool metadata_debug; |
4194 | + const char *dict_uri; |
4195 | + int maxsize; |
4196 | + int maxentries; |
4197 | +}; |
4198 | + |
4199 | +void |
4200 | +metadata_settings_init(struct metadata_settings **set, struct mail_user *user) |
4201 | + ATTR_NONNULL(1,2); |
4202 | +void |
4203 | +metadata_settings_deinit(struct metadata_settings **set) |
4204 | + ATTR_NONNULL(1); |
4205 | + |
4206 | +#endif |
4207 | |
4208 | === added file 'src/str-ext.c' |
4209 | --- src/str-ext.c 1970-01-01 00:00:00 +0000 |
4210 | +++ src/str-ext.c 2011-09-29 19:49:50 +0000 |
4211 | @@ -0,0 +1,42 @@ |
4212 | +/* |
4213 | + Copyright (c) 2010 by Dennis Schridde |
4214 | + |
4215 | + This file is part of dovecot-metadata. |
4216 | + |
4217 | + dovecot-metadata is free software: you can redistribute it and/or modify |
4218 | + it under the terms of the GNU Lesser General Public License as published by |
4219 | + the Free Software Foundation, either version 3 of the License, or |
4220 | + (at your option) any later version. |
4221 | + |
4222 | + dovecot-metadata is distributed in the hope that it will be useful, |
4223 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
4224 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4225 | + GNU Lesser General Public License for more details. |
4226 | + |
4227 | + You should have received a copy of the GNU Lesser General Public License |
4228 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
4229 | +*/ |
4230 | +#include "str-ext.h" |
4231 | + |
4232 | +#include <string.h> |
4233 | + |
4234 | +int |
4235 | +strchr_num(const char *s, int c) { |
4236 | + int num = 0; |
4237 | + s = strchr(s, c); |
4238 | + while (s != NULL) { |
4239 | + num++; |
4240 | + s = strchr(s+1, c); |
4241 | + } |
4242 | + return num; |
4243 | +} |
4244 | + |
4245 | + |
4246 | +bool |
4247 | +str_has_wildcards(const char *s) { |
4248 | + for (; *s != '\0'; s++) { |
4249 | + if (*s == '*' || *s == '%') |
4250 | + return TRUE; |
4251 | + } |
4252 | + return FALSE; |
4253 | +} |
4254 | |
4255 | === added file 'src/str-ext.h' |
4256 | --- src/str-ext.h 1970-01-01 00:00:00 +0000 |
4257 | +++ src/str-ext.h 2011-09-29 19:49:50 +0000 |
4258 | @@ -0,0 +1,38 @@ |
4259 | +/* |
4260 | + Copyright (c) 2010 by Dennis Schridde |
4261 | + |
4262 | + This file is part of dovecot-metadata. |
4263 | + |
4264 | + dovecot-metadata is free software: you can redistribute it and/or modify |
4265 | + it under the terms of the GNU Lesser General Public License as published by |
4266 | + the Free Software Foundation, either version 3 of the License, or |
4267 | + (at your option) any later version. |
4268 | + |
4269 | + dovecot-metadata is distributed in the hope that it will be useful, |
4270 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
4271 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4272 | + GNU Lesser General Public License for more details. |
4273 | + |
4274 | + You should have received a copy of the GNU Lesser General Public License |
4275 | + along with dovecot-metadata. If not, see <http://www.gnu.org/licenses/>. |
4276 | +*/ |
4277 | +#ifndef DOVECOT_STR_EXT_H |
4278 | +#define DOVECOT_STR_EXT_H |
4279 | + |
4280 | +#include "metadata-global.h" |
4281 | + |
4282 | +#include <stdbool.h> |
4283 | + |
4284 | +#include "str.h" |
4285 | + |
4286 | +#define str_append_printf str_printfa |
4287 | + |
4288 | +int |
4289 | +strchr_num(const char *s, int c) |
4290 | + ATTR_NONNULL(1); |
4291 | + |
4292 | +bool |
4293 | +str_has_wildcards(const char *s) |
4294 | + ATTR_NONNULL(1); |
4295 | + |
4296 | +#endif |
this looks ok. the alternative is either to remove the package or upgrade to the new version.