Imported Upstream version 2.4.15
Ondřej Surý
12 years ago
63 | 63 | COMPILE_ET = @COMPILE_ET@ |
64 | 64 | |
65 | 65 | PACKAGE = cyrus-imapd |
66 | VERSION = 2.4.14 | |
66 | VERSION = 2.4.15 | |
67 | 67 | GIT_VERSION = $(VERSION).git$(shell date +'%Y%m%d%H%M') |
68 | 68 | |
69 | 69 | all:: xversion |
7 | 7 | </head> |
8 | 8 | <body> |
9 | 9 | |
10 | <h1>Changes to the Cyrus IMAP Server since 2.4.14</h1> | |
11 | <ul> | |
12 | <li>Bug #3664, #3665 - Sieve filters don't work if mailbox contains dots</li> | |
13 | <li>Bug #3651 - 64 bit dirhash breaks existing systems. NOTE - this includes a complete | |
14 | rewrite of tools/rehash, making it much simpler and more reliable. Check the usage | |
15 | statement</li> | |
16 | <li>Bug #1228 - mailbox dumps need to dump quotaroots</li> | |
17 | <li>Bug #3613 - CATENATE command returns BADURL</li> | |
18 | <li>Bug #3627 - enabling improved_mboxlist_sort documentation mention subscription files</li> | |
19 | <li>Bug #3661 - Memory leaks in sync_server, nntpd, popd</li> | |
20 | <li>Bug #3621 - quota bug involving nested quota roots</li> | |
21 | <li>Bug #3667 - FLAGS.SILENT needs to return new MODSEQ if QRESYNC enabled</li> | |
22 | </ul> | |
23 | ||
24 | <h1>Changes to the Cyrus IMAP Server since 2.4.13</h1> | |
25 | <ul> | |
26 | <li>Bug #2685 - folder delete and annotations</li> | |
27 | <li>Bug #3381 - tools/rehash script is not 64bit safe</li> | |
28 | <li>Bug #3405 - Cyrus IMAP tls support for ctl_mboxlist</li> | |
29 | <li>Bug #3485 - cyr_expire tries to delete parent directories that are not empty</li> | |
30 | <li>Bug #3582 - Extra LF+SP characters been inserted in the middle of the XML attachments</li> | |
31 | <li>Bug #3598 - lmtp auditlog for murder proxy mode</li> | |
32 | <li>Bug #3623 - OpenBSD (and other platforms without working mmap) multiple bugs</li> | |
33 | <li>Bug #3626 - Renaming a mailbox doesn't remove old folder</li> | |
34 | <li>Bug #3628 - folders with spaces and subfolders with same prefix as parent folder don't show up</li> | |
35 | <li>Bug #3634 - RENAME INBOX no longer works</li> | |
36 | <li>Bug #3635 - cmd_rename() fails to check error codes</li> | |
37 | <li>Bug #3636 - unexpunge locks mailbox until all output is emitted</li> | |
38 | <li>Bug #3637 - imapd and ipop3d in 2.4 no longer log expunge events to syslog</li> | |
39 | <li>Bug #3638 - sessionid logging improvements for murder environments</li> | |
40 | <li>Bug #3640 - LMTP accepts NULL bytes in headers, resulting in incorrect header/mail size in meta-data</li> | |
41 | <li>Bug #3642 - iPhone 5 expects SPECIAL-USE in LIST output</li> | |
42 | <li>Bug #3649 - unable to remove mailbox</li> | |
43 | <li>Bug #3650 - ENVELOPE contains unexpected CRLF</li> | |
44 | <li>Bug #3645 - Ability to delete folder "shared"</li> | |
45 | </ul> | |
10 | 46 | |
11 | 47 | <h1>Changes to the Cyrus IMAP Server since 2.4.12</h1> |
12 | 48 | <ul> |
6 | 6 | <body> |
7 | 7 | |
8 | 8 | <h1>Upgrading From Previous Versions</h1> |
9 | ||
10 | <h2>Upgrading from 2.4.14</h2> | |
11 | <ul> | |
12 | <li>We recommend that ALL sites with fulldirhash enabled run | |
13 | tools/rehash on their mail spools after upgrading from | |
14 | 2.4.14. There were serious 32 vs 64 bit hashing bugs | |
15 | which were made worse with 2.4.14. NOTE: the syntax of | |
16 | tools/rehash has changed. Run it without arguments to | |
17 | see a usage statement.</li> | |
18 | </ul> | |
9 | 19 | |
10 | 20 | <h2>Upgrading from 2.4.12</h2> |
11 | 21 | <ul> |
0 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | |
1 | "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | |
2 | <html xmlns="http://www.w3.org/1999/xhtml"> | |
3 | <head> | |
4 | <title>Enabling improved_mboxlist_sort</title> | |
5 | </head> | |
6 | <body> | |
7 | <H1>Enabling improved_mboxlist_sort</H1> | |
8 | ||
9 | <p>You can't enable and disable improved_mboxlist_sort on a live | |
10 | system. You need to dump and load the necessary database after | |
11 | stopping and before starting the master process.<p> | |
12 | ||
13 | <p>Dumping the mailboxes.db file</p> | |
14 | <pre> | |
15 | ctl_mboxlist -d > /var/tmp/mailboxes.txt | |
16 | ctl_mboxlist -u < /var/tmp/mailboxes.txt | |
17 | </pre> | |
18 | ||
19 | <p>If your subscription databases are not in flat files you need to do | |
20 | something similar. Each user will have his own subscription file. Do | |
21 | the following for each subscription file.</p> | |
22 | ||
23 | <pre> | |
24 | cyr_dbtool -C $file skiplist show > $file.TXT | |
25 | cyr_dbtool -n $file skiplist set < $file.TXT | |
26 | </pre> | |
27 | ||
28 | <p>The above fragments will overwrite the original file. So you could | |
29 | redirect to a temporary file and overwrite the database if the import | |
30 | succeeds.</p> | |
31 | ||
32 | </body> | |
33 | </html> |
47 | 47 | |
48 | 48 | <li><a href="specials.html">Special Characters</a></li> |
49 | 49 | |
50 | <li><a href="improved_mboxlist_sort.html">Enabling improved_mboxlist_sort</a></li> | |
51 | ||
50 | 52 | </body> |
51 | 53 | </html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:30 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:05 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:31 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:05 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:31 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:05 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:31 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:05 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:31 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:06 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:31 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:06 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:31 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:06 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:31 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:06 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:31 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:06 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:31 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:06 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:31 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:06 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:31 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:06 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:31 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:06 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:31 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:06 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:31 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:06 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:31 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:06 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:32 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:07 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
660 | 660 | |
661 | 661 | <p style="margin-left:11%; margin-top: 1em">Note that this |
662 | 662 | option SHOULD NOT be changed on a live system. The mailboxes |
663 | database should be dumped before the option is changed, | |
664 | removed, and then undumped after changing the option. | |
663 | database should be dumped (ctl_mboxlist) before the option | |
664 | is changed, removed, and then undumped after changing the | |
665 | option. When not using flat files for the subscriptions | |
666 | databases the same has to be done (cyr_dbtool) for each | |
667 | subscription database See improved_mboxlist_sort.html. | |
665 | 668 | <b><br> |
666 | 669 | internaldate_heuristic:</b> standard</p> |
667 | 670 |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:32 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:07 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:32 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:07 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:32 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:07 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:32 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:07 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:32 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:07 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:32 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:07 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:32 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:07 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:32 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:07 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:32 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:07 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:32 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:07 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:33 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:08 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:33 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:08 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:33 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:08 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:33 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:08 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:33 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:08 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:33 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:08 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:33 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:08 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:33 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:08 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:33 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:08 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:33 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:08 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:33 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:08 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:33 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:08 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:33 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:08 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:34 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:09 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:34 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:09 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:34 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:09 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:34 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:09 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:34 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:09 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:34 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:09 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | 0 | <!-- Creator : groff version 1.21 --> |
1 | <!-- CreationDate: Mon Mar 12 11:59:34 2012 --> | |
1 | <!-- CreationDate: Wed Apr 18 12:30:09 2012 --> | |
2 | 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
3 | 3 | "http://www.w3.org/TR/html4/loose.dtd"> |
4 | 4 | <html> |
0 | Changes to the Cyrus IMAP Server since 2.4.14 | |
1 | ||
2 | * Bug #3664, #3665 - Sieve filters don't work if mailbox contains | |
3 | dots | |
4 | * Bug #3651 - 64 bit dirhash breaks existing systems. NOTE - this | |
5 | includes a complete rewrite of tools/rehash, making it much simpler | |
6 | and more reliable. Check the usage statement | |
7 | * Bug #1228 - mailbox dumps need to dump quotaroots | |
8 | * Bug #3613 - CATENATE command returns BADURL | |
9 | * Bug #3627 - enabling improved_mboxlist_sort documentation mention | |
10 | subscription files | |
11 | * Bug #3661 - Memory leaks in sync_server, nntpd, popd | |
12 | * Bug #3621 - quota bug involving nested quota roots | |
13 | * Bug #3667 - FLAGS.SILENT needs to return new MODSEQ if QRESYNC | |
14 | enabled | |
15 | ||
16 | Changes to the Cyrus IMAP Server since 2.4.13 | |
17 | ||
18 | * Bug #2685 - folder delete and annotations | |
19 | * Bug #3381 - tools/rehash script is not 64bit safe | |
20 | * Bug #3405 - Cyrus IMAP tls support for ctl_mboxlist | |
21 | * Bug #3485 - cyr_expire tries to delete parent directories that are | |
22 | not empty | |
23 | * Bug #3582 - Extra LF+SP characters been inserted in the middle of | |
24 | the XML attachments | |
25 | * Bug #3598 - lmtp auditlog for murder proxy mode | |
26 | * Bug #3623 - OpenBSD (and other platforms without working mmap) | |
27 | multiple bugs | |
28 | * Bug #3626 - Renaming a mailbox doesn't remove old folder | |
29 | * Bug #3628 - folders with spaces and subfolders with same prefix as | |
30 | parent folder don't show up | |
31 | * Bug #3634 - RENAME INBOX no longer works | |
32 | * Bug #3635 - cmd_rename() fails to check error codes | |
33 | * Bug #3636 - unexpunge locks mailbox until all output is emitted | |
34 | * Bug #3637 - imapd and ipop3d in 2.4 no longer log expunge events to | |
35 | syslog | |
36 | * Bug #3638 - sessionid logging improvements for murder environments | |
37 | * Bug #3640 - LMTP accepts NULL bytes in headers, resulting in | |
38 | incorrect header/mail size in meta-data | |
39 | * Bug #3642 - iPhone 5 expects SPECIAL-USE in LIST output | |
40 | * Bug #3649 - unable to remove mailbox | |
41 | * Bug #3650 - ENVELOPE contains unexpected CRLF | |
42 | * Bug #3645 - Ability to delete folder "shared" | |
43 | ||
0 | 44 | Changes to the Cyrus IMAP Server since 2.4.12 |
1 | 45 | |
2 | 46 | * Bug #3565 - fix gcc compiler warnings - thanks Dilyan Palauzov |
0 | 0 | Upgrading From Previous Versions |
1 | ||
2 | Upgrading from 2.4.14 | |
3 | ||
4 | * We recommend that ALL sites with fulldirhash enabled run | |
5 | tools/rehash on their mail spools after upgrading from 2.4.14. | |
6 | There were serious 32 vs 64 bit hashing bugs which were made worse | |
7 | with 2.4.14. NOTE: the syntax of tools/rehash has changed. Run it | |
8 | without arguments to see a usage statement. | |
1 | 9 | |
2 | 10 | Upgrading from 2.4.12 |
3 | 11 |
3078 | 3078 | } |
3079 | 3079 | |
3080 | 3080 | /* local mailbox */ |
3081 | if (!r) r = index_open(mailboxname, NULL, &state); | |
3081 | if (!r) { | |
3082 | struct index_init init; | |
3083 | memset(&init, 0, sizeof(init)); | |
3084 | init.qresync = imapd_client_capa & CAPA_QRESYNC; | |
3085 | init.userid = imapd_userid; | |
3086 | init.authstate = imapd_authstate; | |
3087 | init.out = imapd_out; | |
3088 | r = index_open(mailboxname, &init, &state); | |
3089 | } | |
3082 | 3090 | if (!r) doclose = 1; |
3083 | 3091 | |
3084 | 3092 | if (!r && !(state->myrights & ACL_READ)) |
3164 | 3172 | |
3165 | 3173 | if (!r) { |
3166 | 3174 | r = catenate_url(arg.s, cur_name, f, totalsize, parseerr); |
3167 | if (r) *url = arg.s; | |
3175 | if (r) { | |
3176 | *url = arg.s; | |
3177 | return r; | |
3178 | } | |
3168 | 3179 | } |
3169 | 3180 | } |
3170 | 3181 | else { |
2693 | 2693 | |
2694 | 2694 | r = mailbox_cacherecord(mailbox, &im->record); |
2695 | 2695 | if (r) return r; |
2696 | ||
2696 | ||
2697 | 2697 | /* Open the message file */ |
2698 | 2698 | if (mailbox_map_message(mailbox, im->record.uid, &msg_base, &msg_size)) |
2699 | 2699 | return IMAP_NO_MSGGONE; |
2704 | 2704 | if (size > msg_size) size = msg_size; |
2705 | 2705 | |
2706 | 2706 | cacheitem = cacheitem_base(&im->record, CACHE_SECTION); |
2707 | cacheitem += CACHE_ITEM_SIZE_SKIP; | |
2708 | 2707 | |
2709 | 2708 | /* Special-case BODY[] */ |
2710 | 2709 | if (!section || !*section) { |
2801 | 2800 | if (!data) { |
2802 | 2801 | /* failed to decode */ |
2803 | 2802 | prot_printf(pout, " NIL)"); |
2803 | r = 0; | |
2804 | 2804 | goto done; |
2805 | 2805 | } |
2806 | 2806 | } |
2836 | 2836 | |
2837 | 2837 | /* Complete extended URLFETCH response */ |
2838 | 2838 | if (params & (URLFETCH_BODY | URLFETCH_BINARY)) prot_printf(pout, ")"); |
2839 | ||
2840 | r = 0; | |
2839 | 2841 | |
2840 | 2842 | done: |
2841 | 2843 | /* Close the message file */ |
2968 | 2970 | r = mailbox_rewrite_index_record(mailbox, &im->record); |
2969 | 2971 | if (r) return r; |
2970 | 2972 | |
2971 | /* if it's silent and unchanged, update the seen value */ | |
2972 | if (storeargs->silent && im->told_modseq == oldmodseq) | |
2973 | /* if it's silent and unchanged, update the seen value, but | |
2974 | * not if qresync is enabled - RFC 4551 says that the MODSEQ | |
2975 | * must always been told, and we prefer just to tell flags | |
2976 | * as well in this case, it's simpler and not much more | |
2977 | * bandwidth */ | |
2978 | if (!state->qresync && storeargs->silent && im->told_modseq == oldmodseq) | |
2973 | 2979 | im->told_modseq = im->record.modseq; |
2974 | 2980 | |
2975 | 2981 | return 0; |
437 | 437 | sieve_reject_context_t *rc = (sieve_reject_context_t *) ac; |
438 | 438 | script_data_t *sd = (script_data_t *) sc; |
439 | 439 | message_data_t *md = ((deliver_data_t *) mc)->m; |
440 | char userbuf[MAX_MAILBOX_NAME]; | |
441 | 440 | const char **body; |
442 | 441 | const char *origreceip; |
443 | 442 | int res; |
457 | 456 | return SIEVE_OK; |
458 | 457 | } |
459 | 458 | |
460 | strlcpy(userbuf, sd->username, sizeof(userbuf)); | |
461 | /* append default domain if no domain given */ | |
462 | if (config_defdomain && !strchr(userbuf, '@')) { | |
463 | strlcat(userbuf, "@", sizeof(userbuf)); | |
464 | strlcat(userbuf, config_defdomain, sizeof(userbuf)); | |
465 | } | |
466 | ||
467 | 459 | body = msg_getheader(md, "original-recipient"); |
468 | 460 | origreceip = body ? body[0] : NULL; |
469 | 461 | if ((res = send_rejection(md->id, md->return_path, |
470 | origreceip, userbuf, | |
462 | origreceip, sd->username, | |
471 | 463 | rc->msg, md->data)) == 0) { |
472 | 464 | snmp_increment(SIEVE_REJECT, 1); |
473 | 465 | syslog(LOG_INFO, "sieve rejected: %s to: %s", |
907 | 899 | sieve_execute_t *bc = NULL; |
908 | 900 | script_data_t sdata; |
909 | 901 | char userbuf[MAX_MAILBOX_BUFFER] = ""; |
902 | char authuserbuf[MAX_MAILBOX_BUFFER]; | |
910 | 903 | int r = 0; |
911 | 904 | duplicate_key_t dkey = DUPLICATE_INITIALIZER; |
912 | 905 | |
932 | 925 | } |
933 | 926 | |
934 | 927 | if (user) strlcpy(userbuf, user, sizeof(userbuf)); |
935 | mboxname_hiersep_toexternal(msgdata->namespace, userbuf, 0); | |
936 | 928 | if (domain) { |
937 | 929 | strlcat(userbuf, "@", sizeof(userbuf)); |
938 | 930 | strlcat(userbuf, domain, sizeof(userbuf)); |
941 | 933 | sdata.mailboxname = mailbox; |
942 | 934 | |
943 | 935 | if (user) { |
944 | sdata.authstate = auth_newstate(userbuf); | |
936 | strlcpy(authuserbuf, userbuf, sizeof(authuserbuf)); | |
937 | if (config_getswitch(IMAPOPT_UNIXHIERARCHYSEP)) { | |
938 | mboxname_hiersep_toexternal(msgdata->namespace, authuserbuf, | |
939 | domain ? strcspn(authuserbuf, "@") : 0); | |
940 | } | |
941 | sdata.authstate = auth_newstate(authuserbuf); | |
945 | 942 | } |
946 | 943 | else { |
947 | 944 | sdata.authstate = msgdata->authstate; |
948 | } | |
945 | } | |
949 | 946 | |
950 | 947 | r = sieve_execute_bytecode(bc, interp, |
951 | 948 | (void *) &sdata, (void *) msgdata); |
953 | 950 | if ((r == SIEVE_OK) && (msgdata->m->id)) { |
954 | 951 | /* ok, we've run the script */ |
955 | 952 | char *sdb; |
956 | ||
953 | ||
957 | 954 | /* slap the mailbox back on so we hash the envelope & id |
958 | 955 | when we figure out whether or not to keep the message */ |
959 | 956 | snprintf(namebuf, sizeof(namebuf), "%s+%s@%s", |
960 | 957 | user ? user : "", mailbox ? mailbox : "", |
961 | 958 | domain ? domain : ""); |
962 | 959 | sdb = make_sieve_db(namebuf); |
963 | ||
960 | ||
964 | 961 | dkey.id = msgdata->m->id; |
965 | 962 | dkey.to = sdb; |
966 | 963 | dkey.date = msgdata->m->date; |
967 | 964 | duplicate_mark(&dkey, time(NULL), 0); |
968 | 965 | } |
969 | ||
966 | ||
970 | 967 | /* free everything */ |
971 | 968 | if (user && sdata.authstate) auth_freestate(sdata.authstate); |
972 | 969 | sieve_script_unload(&bc); |
973 | ||
970 | ||
974 | 971 | /* if there was an error, r is non-zero and |
975 | 972 | we'll do normal delivery */ |
976 | 973 | return r; |
1000 | 1000 | const char *root = NULL; |
1001 | 1001 | char *newpartition = NULL; |
1002 | 1002 | char *mboxent = NULL; |
1003 | char *p; | |
1004 | 1003 | mupdate_handle *mupdate_h = NULL; |
1005 | 1004 | |
1006 | 1005 | /* 1. open mailbox */ |
927 | 927 | if (strlen(name) > MAX_MAILBOX_NAME) |
928 | 928 | return IMAP_MAILBOX_BADNAME; |
929 | 929 | |
930 | /* because directory hashing could create ambiguous naming for | |
931 | * a folder if the first item is a single character long, reject | |
932 | * single character top level names */ | |
933 | if (name[1] == '.' || name[1] == '\0') | |
934 | return IMAP_MAILBOX_BADNAME; | |
935 | ||
930 | 936 | for (i = 0; i < NUM_BADMBOXPATTERNS; i++) { |
931 | 937 | g = glob_init(badmboxpatterns[i], GLOB_ICASE); |
932 | 938 | if (GLOB_TEST(g, name) != -1) { |
2092 | 2092 | |
2093 | 2093 | prot_printf(nntp_out, "281 User logged in\r\n"); |
2094 | 2094 | |
2095 | /* nntp_authstate may have been set as a side effect | |
2096 | * of sasl_checkpass() calling mysasl_proxy_policy */ | |
2097 | if (nntp_authstate) | |
2098 | auth_freestate(nntp_authstate); | |
2099 | ||
2095 | 2100 | nntp_authstate = auth_newstate(nntp_userid); |
2096 | 2101 | |
2097 | 2102 | /* Close IP-based telemetry log and create new log based on userid */ |
1502 | 1502 | } |
1503 | 1503 | } |
1504 | 1504 | |
1505 | /* popd_authstate may have been set as a side effect | |
1506 | * of sasl_checkpass() calling mysasl_proxy_policy */ | |
1507 | if (popd_authstate) | |
1508 | auth_freestate(popd_authstate); | |
1509 | ||
1505 | 1510 | popd_authstate = auth_newstate(popd_userid); |
1506 | 1511 | |
1507 | 1512 | openinbox(); |
122 | 122 | struct quotaentry *quota; |
123 | 123 | int quota_num = 0, quota_alloc = 0; |
124 | 124 | |
125 | int firstquota = 0; | |
126 | 125 | int redofix = 0; |
127 | 126 | |
128 | 127 | int main(int argc,char **argv) |
298 | 297 | |
299 | 298 | *thisquota = -1; |
300 | 299 | |
301 | for (i = firstquota; i < quota_num; i++) { | |
300 | for (i = 0; i < quota_num; i++) { | |
302 | 301 | const char *root = quota[i].quota.root; |
303 | 302 | |
304 | 303 | /* have we already passed the name, then there can |
305 | 304 | * be no further matches */ |
306 | 305 | if (compar(root, name) > 0) |
307 | return 0; | |
306 | break; | |
308 | 307 | |
309 | 308 | /* is the mailbox within this root? */ |
310 | 309 | if (mboxname_is_prefix(name, root)) { |
311 | 310 | /* fantastic, but don't return yet, we may find |
312 | 311 | * a more exact match */ |
313 | quota[i].refcount++; | |
314 | 312 | *thisquota = i; |
315 | 313 | } |
316 | else { | |
317 | /* not a match, so we can finish everything up to here */ | |
318 | while (firstquota < i) { | |
319 | int r = fixquota_finish(firstquota); | |
320 | if (r) return r; | |
321 | firstquota++; | |
322 | } | |
323 | } | |
324 | } | |
314 | } | |
315 | ||
316 | if (*thisquota >= 0) | |
317 | quota[*thisquota].refcount++; | |
325 | 318 | |
326 | 319 | return 0; |
327 | 320 | } |
451 | 444 | int i, r; |
452 | 445 | char buf[MAX_MAILBOX_BUFFER], *tail; |
453 | 446 | size_t domainlen = 0; |
447 | int firstquota = 0; | |
454 | 448 | |
455 | 449 | buf[0] = '\0'; |
456 | 450 | tail = buf; |
439 | 439 | /* If enabled, a special comparator will be used which will correctly |
440 | 440 | sort mailbox names that contain characters such as ' ' and '-'. |
441 | 441 | .PP |
442 | Note that this option SHOULD NOT be changed on a live system. | |
443 | The mailboxes database should be dumped before the option is changed, | |
444 | removed, and then undumped after changing the option. */ | |
442 | Note that this option SHOULD NOT be changed on a live system. The | |
443 | mailboxes database should be dumped (ctl_mboxlist) before the | |
444 | option is changed, removed, and then undumped after changing the | |
445 | option. When not using flat files for the subscriptions databases | |
446 | the same has to be done (cyr_dbtool) for each subscription database | |
447 | See improved_mboxlist_sort.html.*/ | |
445 | 448 | |
446 | 449 | { "internaldate_heuristic", "standard", ENUM("standard", "receivedheader") } |
447 | 450 | /* Mechanism to determine email internaldates on delivery/reconstruct. |
268 | 268 | |
269 | 269 | if (full) { |
270 | 270 | unsigned char *pt; |
271 | unsigned long long int n; | |
271 | unsigned int n; | |
272 | 272 | enum { |
273 | 273 | DIR_X = 3, |
274 | 274 | DIR_Y = 5, |
280 | 280 | pt = (unsigned char *)name; |
281 | 281 | while (*pt && *pt != '.') { |
282 | 282 | n = ((n << DIR_X) ^ (n >> DIR_Y)) ^ *pt; |
283 | n &= UINT32_MAX; | |
283 | 284 | ++pt; |
284 | 285 | } |
285 | 286 | c = DIR_A + (n % DIR_P); |
384 | 384 | If enabled, a special comparator will be used which will correctly |
385 | 385 | sort mailbox names that contain characters such as ' ' and '-'. |
386 | 386 | .PP |
387 | Note that this option SHOULD NOT be changed on a live system. | |
388 | The mailboxes database should be dumped before the option is changed, | |
389 | removed, and then undumped after changing the option. | |
387 | Note that this option SHOULD NOT be changed on a live system. The | |
388 | mailboxes database should be dumped (ctl_mboxlist) before the | |
389 | option is changed, removed, and then undumped after changing the | |
390 | option. When not using flat files for the subscriptions databases | |
391 | the same has to be done (cyr_dbtool) for each subscription database | |
392 | See improved_mboxlist_sort.html. | |
390 | 393 | .IP "\fBinternaldate_heuristic:\fR standard" 5 |
391 | 394 | Mechanism to determine email internaldates on delivery/reconstruct. |
392 | 395 | "standard" uses time() when delivering a message, mtime on reconstruct. |
123 | 123 | .\" ======================================================================== |
124 | 124 | .\" |
125 | 125 | .IX Title "SIEVESHELL 1" |
126 | .TH SIEVESHELL 1 "2012-03-12" "perl v5.14.2" "User Contributed Perl Documentation" | |
126 | .TH SIEVESHELL 1 "2012-04-18" "perl v5.14.2" "User Contributed Perl Documentation" | |
127 | 127 | .\" For nroff, turn off justification. Always turn off hyphenation; it makes |
128 | 128 | .\" way too many mistakes in technical documents. |
129 | 129 | .if n .ad l |
0 | #!/bin/sh | |
1 | # | |
2 | # Copyright (c) 1994-2008 Carnegie Mellon University. All rights reserved. | |
0 | #!/usr/bin/env perl | |
1 | # | |
2 | # Copyright (c) 1994-2012 Carnegie Mellon University. All rights reserved. | |
3 | 3 | # |
4 | 4 | # Redistribution and use in source and binary forms, with or without |
5 | 5 | # modification, are permitted provided that the following conditions |
37 | 37 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN |
38 | 38 | # AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
39 | 39 | # OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
40 | # | |
41 | # $Id: rehash,v 1.11 2010/01/06 17:02:01 murch Exp $ | |
42 | ||
43 | exec perl -x -S $0 ${1+"$@"} # -*-perl-*- | |
44 | #!perl -w | |
45 | # script to upgrade from simple hashing scheme to full hashing scheme | |
46 | # make sure you run it as the cyrus user | |
47 | # | |
48 | # Written by Gary Mills <mills@cc.UManitoba.CA> | |
49 | ||
50 | if ($] !~ /^5\..*/) { | |
51 | # uh-oh. this isn't perl 5. | |
52 | foreach (split(/:/, $ENV{PATH})) { # try to find "perl5". | |
53 | exec("$_/perl5", "-x", "-S", $0, @ARGV) if (-x "$_/perl5"); | |
54 | } | |
55 | # we failed. bail. | |
56 | die "Your perl is too old; I need perl 5.\n"; | |
57 | } | |
58 | ||
59 | # load the real script. this is isolated in an 'eval' so perl4 won't | |
60 | # choke on the perl5-isms. | |
61 | eval join("\n", <DATA>); | |
62 | if ($@) { die "$@"; } | |
63 | ||
64 | __END__ | |
65 | require 5; | |
66 | require Math::BigInt; | |
67 | ||
40 | ||
41 | use strict; | |
42 | use warnings; | |
43 | ||
44 | use Getopt::Std; | |
45 | ||
46 | my %Opts; | |
47 | getopts('vnhfFiI', \%Opts); | |
48 | usage() if $Opts{h}; | |
49 | ||
50 | my $OPT_NoAction = $Opts{n}; | |
51 | my $OPT_Verbose = $Opts{v} || $Opts{n}; | |
52 | ||
53 | # non-buffered output | |
68 | 54 | $| = 1; |
69 | 55 | |
56 | # XXX - actually read the cyrus username from the imapd.conf and | |
57 | # change ownership as appropriate? | |
70 | 58 | die "must not run as root" if ($< == 0); |
71 | 59 | |
72 | if ("-i" eq $ARGV[0]) { | |
73 | $interactive = 1; | |
74 | shift @ARGV; | |
75 | } | |
76 | if ("-f" eq $ARGV[0]) { | |
77 | $force = 1; | |
78 | shift @ARGV; | |
79 | } | |
80 | if ("-h" eq $ARGV[0] || @ARGV < 1) { | |
81 | print "usage: rehash [-i] [-f] none|basic|full [imapd.conf]\n"; | |
82 | print " -i interactive\n"; | |
83 | print " -f keep going on errors\n"; | |
84 | exit; | |
85 | } | |
86 | ||
87 | $MOVE_DOMAIN_CONF = 1; | |
88 | $MOVE_DOMAIN_SIEVE = 2; | |
89 | $MOVE_DOMAIN_PART = 3; | |
90 | ||
91 | $tonone = 1 if ("none" eq $ARGV[0]); | |
92 | $tobasic = 1 if ("basic" eq $ARGV[0]); | |
93 | $tofull = 1 if ("full" eq $ARGV[0]); | |
94 | unless ($tonone || $tobasic || $tofull) { | |
95 | print "rehash: one of none/basic/full required\n"; | |
96 | exit; | |
97 | } | |
98 | shift @ARGV; | |
60 | my $imapdconf = shift || usage(); | |
99 | 61 | |
100 | 62 | my @bdirs = ("a".."z"); |
101 | 63 | my @fdirs = ("A".."W"); |
102 | my $dirs = [@bdirs,@fdirs] if $tonone; | |
103 | ||
104 | if ($tobasic) { | |
105 | $dirs = \@bdirs; | |
106 | $old = \@fdirs; | |
107 | } | |
108 | ||
109 | if ($tofull) { | |
110 | $dirs = \@fdirs; | |
111 | $old = \@bdirs; | |
112 | } | |
113 | ||
114 | sub ouch { | |
115 | my $msg = shift; | |
116 | ||
117 | if ($force) { | |
118 | print "fatal error: $msg\n"; | |
119 | } else { | |
120 | print "error: $msg\n"; | |
121 | exit 1; | |
122 | } | |
123 | } | |
124 | ||
125 | sub dir_hash_c_32 { | |
64 | my %ishash = map { $_ => 1 } (@bdirs, @fdirs); | |
65 | ||
66 | # evil globals | |
67 | my @configs = ($imapdconf); | |
68 | my $confdir = "/var/imap"; | |
69 | my @parts; | |
70 | my $yn = "y"; | |
71 | my $sievedir = "/usr/sieve"; | |
72 | my $nosievedir = 0; | |
73 | my $hashimapspool = 0; | |
74 | my $fulldirhash = 0; | |
75 | my $virtdomains = 0; | |
76 | ||
77 | while (my $conf = shift @configs) { | |
78 | read_conf($conf); | |
79 | } | |
80 | ||
81 | $fulldirhash = 0 if $Opts{f}; | |
82 | $fulldirhash = 1 if $Opts{F}; | |
83 | $hashimapspool = 0 if $Opts{i}; | |
84 | $hashimapspool = 1 if $Opts{I}; | |
85 | ||
86 | print "converting configuration directory $confdir... "; | |
87 | ||
88 | foreach my $i ("user", "proc", "lock", "db", "socket", "log", "msg", "quota") { | |
89 | ensure_dir("$confdir/$i"); | |
90 | } | |
91 | ||
92 | # *** rehash the domain subdirectory to the new format, | |
93 | # don't worry about internal format yet | |
94 | if ($virtdomains) { | |
95 | print "domain "; | |
96 | ensure_dir("$confdir/domain"); | |
97 | move_domains("$confdir/domain", 'conf'); | |
98 | } | |
99 | ||
100 | # *** user subdirectory; holds subscription files | |
101 | print "user "; | |
102 | move_users("$confdir/user"); | |
103 | ||
104 | # *** quota subdirectory; holds quota files for each quotaroot | |
105 | print "quota "; | |
106 | move_quotas("$confdir/quota"); | |
107 | ||
108 | print "done\n"; | |
109 | ||
110 | # create the sieve stuff | |
111 | unless ($nosievedir) { | |
112 | print "sieve $sievedir... "; | |
113 | ||
114 | ensure_dir($sievedir); | |
115 | move_sieve($sievedir); | |
116 | ||
117 | print "done\n"; | |
118 | } | |
119 | ||
120 | # *** now for each data partition | |
121 | while (my $part = shift @parts) { | |
122 | print "partition $part... "; | |
123 | ||
124 | ensure_dir($part); | |
125 | # stage is good too | |
126 | ensure_dir("$part/stage."); | |
127 | ||
128 | move_part($part); | |
129 | ||
130 | print "done\n"; | |
131 | } | |
132 | ||
133 | sub usage { | |
134 | die <<EOF | |
135 | usage: $0 [-v] [-n] imapd.conf | |
136 | ||
137 | -v verbose | |
138 | -n no change - just show what would be done | |
139 | -f force fulldirhash: no | |
140 | -F force fulldirhash: yes | |
141 | -i force hashimapspool: no | |
142 | -I force hashimapspool: yes | |
143 | ||
144 | NOTE: imapd.conf must always be provided. On a normal system | |
145 | this will be /etc/imapd.conf. The correct hashing settings will | |
146 | be read from the provided imapd.conf, or can be overridden with | |
147 | options. | |
148 | ||
149 | In verbose mode, each rename command will be printed, as well as | |
150 | any creation or deletion of folders. | |
151 | ||
152 | In "no change" mode, it will just print the changes. Note, | |
153 | verbose is always turned on in no-change mode. | |
154 | ||
155 | NOTE 2: It should be safe to run fixhash on a running system, but | |
156 | it may mess things up horribly if you have some processes still | |
157 | running with old config, and some with new - so it is always | |
158 | recommended to fully shut down Cyrus, change the configuration | |
159 | file, run fixhash, and then start Cyrus again. | |
160 | EOF | |
161 | } | |
162 | ||
163 | # force 32 bit hashing only | |
164 | sub dir_hash_c { | |
126 | 165 | my $name = shift; |
127 | my $uint32 = (2**32); | |
166 | my $isspool = shift; | |
167 | ||
128 | 168 | my ($h, $n); |
129 | 169 | |
130 | if ($tofull) { | |
170 | if ($fulldirhash) { | |
171 | $name =~ s/\..*//; # remove trailing dots | |
131 | 172 | $n = 0; |
132 | 173 | foreach my $b (split(/ */, $name)) { |
133 | $n = ((($n << 3) ^ ($n >> 5)) % $uint32) ^ ord($b); | |
174 | $n = (($n << 3) ^ ($n >> 5)) ^ ord($b); | |
175 | $n &= 4294967295; # UINT32_MAX | |
134 | 176 | } |
135 | 177 | $h = chr(ord('A') + ($n % 23)); |
136 | 178 | return $h; |
137 | 179 | } |
138 | elsif ($tobasic) { | |
180 | else { | |
139 | 181 | $h = lc(substr($name, 0, 1)); |
140 | 182 | if (!($h =~ /[a-z]/)) { $h = 'q'; } |
141 | 183 | return $h; |
142 | 184 | } |
143 | 185 | } |
144 | 186 | |
145 | sub dir_hash_c_64 { | |
146 | my $name = shift; | |
147 | my ($h, $n); | |
148 | ||
149 | if ($tofull) { | |
150 | $n = Math::BigInt->new(0); | |
151 | foreach my $b (split(/ */, $name)) { | |
152 | $n = (($n << 3) ^ ($n >> 5)) ^ ord($b); | |
153 | } | |
154 | $h = chr(ord('A') + ($n % 23)); | |
155 | return $h; | |
156 | } | |
157 | elsif ($tobasic) { | |
158 | $h = lc(substr($name, 0, 1)); | |
159 | if (!($h =~ /[a-z]/)) { $h = 'q'; } | |
160 | return $h; | |
161 | } | |
187 | sub hash_path { | |
188 | my $path = shift; | |
189 | my $item = shift; | |
190 | my $isspool = shift; | |
191 | my $skiptochar = shift; | |
192 | ||
193 | return "$path/$item" unless ($hashimapspool or not $isspool); | |
194 | ||
195 | my $tohash = $item; | |
196 | if ($skiptochar) { | |
197 | # strip up to and including the character | |
198 | $tohash =~ s/^.*?\Q$skiptochar//; | |
199 | if ($skiptochar eq '/' and $tohash =~ m/\./) { | |
200 | # we've got a top level directory, oops | |
201 | $tohash = $item; | |
202 | $tohash =~ s{/.*$}{}; | |
203 | } | |
204 | } | |
205 | ||
206 | return "$path/" . dir_hash_c($tohash) . "/$item"; | |
162 | 207 | } |
163 | 208 | |
164 | 209 | sub read_conf { |
182 | 227 | push @parts, $1; |
183 | 228 | } |
184 | 229 | if (/^hashimapspool:\s*(1|t|yes|on)/) { |
185 | $hashispool = 1; | |
230 | $hashimapspool = 1; | |
186 | 231 | print "i will also hash partitions.\n"; |
232 | } | |
233 | if (/^fulldirhash/) { | |
234 | $fulldirhash = 1; | |
187 | 235 | } |
188 | 236 | if (/^sieveusehomedir:\s+(1|t|yes|on)/) { |
189 | 237 | $nosievedir = 1; |
193 | 241 | $sievedir = $1; |
194 | 242 | print "you are using $sievedir as your sieve directory.\n"; |
195 | 243 | } |
196 | if (/^virtdomains:\s+(1|t|yes|on)/) { | |
244 | if (/^virtdomains:\s+(1|t|yes|on|userid)/) { | |
197 | 245 | $virtdomains = 1; |
198 | 246 | print "i will deal with virtual domains.\n"; |
199 | 247 | } |
201 | 249 | close CONF; |
202 | 250 | } |
203 | 251 | |
204 | $imapdconf = shift || "/etc/imapd.conf"; | |
205 | ||
206 | $yn = "y"; | |
207 | $sievedir = "/usr/sieve"; | |
208 | $nosievedir = 0; | |
209 | $hashispool = 0; | |
210 | $virtdomains = 0; | |
211 | ||
212 | push @configs, $imapdconf; | |
213 | ||
214 | while ($conf = shift @configs) { | |
215 | read_conf($conf); | |
216 | } | |
217 | ||
218 | if (! $confdir) { $confdir = "/var/imap"; } | |
219 | ||
220 | if ($interactive) { | |
221 | print "upgrade $confdir? "; | |
222 | $yn = <STDIN>; | |
223 | } | |
224 | if ($yn =~ /^y/) { | |
225 | unless (-d $confdir) { print "creating $confdir...\n"; | |
226 | mkdir $confdir, 0755; | |
227 | } | |
228 | print "converting configuration directory $confdir..."; | |
229 | chdir $confdir or die "couldn't change to $confdir"; | |
230 | ||
231 | foreach $i ("user", "proc", "lock", "db", "socket", "log", "msg", "quota") { | |
232 | unless (-d $i) { | |
233 | print "creating $i...\n"; | |
234 | mkdir $i, 0755; | |
235 | } | |
236 | } | |
237 | ||
238 | # *** rehash the domain subdirectory to the new format, | |
239 | # don't worry about internal format yet | |
240 | if($virtdomains) { | |
241 | print "domain "; | |
242 | chdir "domain" or die "couldn't change to domain subdir"; | |
243 | &move_domains($MOVE_DOMAIN_CONF); | |
244 | chdir ".."; | |
245 | } | |
246 | ||
247 | # *** user subdirectory; holds subscription files | |
248 | print "user "; | |
249 | chdir "user" or die "couldn't change to user subdir"; | |
250 | &move_users; | |
251 | chdir ".."; | |
252 | ||
253 | # *** quota subdirectory; holds quota files for each quotaroot | |
254 | print "quota "; | |
255 | chdir "quota" or die "couldn't change to quota subdir"; | |
256 | &move_quotas; | |
257 | print "done\n"; | |
258 | } | |
259 | ||
260 | # create the sieve stuff | |
261 | unless ($nosievedir) { | |
262 | print "converting $sievedir...\n"; | |
263 | ||
264 | mkdir $sievedir, 0755; | |
265 | if (chdir $sievedir) { | |
266 | &move_sieve; | |
267 | } | |
268 | } | |
269 | ||
270 | # *** now for each data partition | |
271 | my $i; | |
272 | my $f; | |
273 | ||
274 | while ($part = shift @parts) { | |
275 | if ($interactive) { | |
276 | print "upgrade $part? "; | |
277 | $yn = <STDIN>; | |
278 | } | |
279 | if ($yn =~ /^y/) { | |
280 | unless (-d $part) { | |
281 | print "creating $part...\n"; | |
282 | mkdir $part, 0755; | |
283 | } | |
284 | print "converting data partition $part..."; | |
285 | chdir $part or die "couldn't chdir to $part"; | |
286 | ||
287 | if ($hashispool) { | |
288 | &move_part; | |
289 | ||
290 | chdir $part or die "couldn't chdir to $part"; | |
291 | mkdir "stage.", 0755; | |
292 | } | |
293 | ||
294 | print "done\n"; | |
295 | } | |
296 | } | |
297 | ||
298 | sub do_subdomain_conf { | |
299 | if(-d "quota") { | |
300 | chdir "quota"; | |
301 | &move_quotas; | |
302 | chdir ".."; | |
303 | } | |
304 | if(-d "user") { | |
305 | chdir "user"; | |
306 | &move_users; | |
307 | chdir ".."; | |
308 | } | |
309 | } | |
310 | ||
311 | sub move_domains { | |
312 | my $type_of_move = shift; | |
313 | ||
314 | if(!defined($type_of_move) || !$type_of_move) { | |
315 | die "move_domains called badly"; | |
316 | } | |
317 | ||
318 | my $i; | |
319 | my $s; | |
320 | my $h_32; | |
321 | my $h_64; | |
322 | my $mbox; | |
323 | ||
324 | foreach $i (@{$dirs}) { | |
325 | if ($tonone) { | |
326 | if (opendir SUB, $i) { | |
327 | while ($s = readdir SUB) { | |
328 | if ($s =~ /^\./s) { next; } | |
329 | chdir "$i/$s"; | |
330 | &do_subdomain; | |
331 | chdir "../.."; | |
332 | rename ("$i/$s", "$s") or die "couldn't move $s back!"; | |
333 | } | |
334 | closedir SUB; | |
335 | rmdir "$i" or die "couldn't remove $i"; | |
336 | } | |
252 | sub add_found { | |
253 | # here be dragons, eep | |
254 | my $type = shift; | |
255 | my $found = shift; | |
256 | my $name = shift; | |
257 | my $location = shift; | |
258 | ||
259 | if ($type ne 'part') { | |
260 | if ($found->{$name}) { | |
261 | die "FOUND BOTH $found->{$name} and $location - you need to fix this by hand\n"; | |
262 | } | |
263 | $found->{$name} = $location; | |
264 | return; | |
265 | } | |
266 | ||
267 | unless (opendir(SUB, $location)) { | |
268 | print "Failed to open directory $location\n"; | |
269 | die unless $OPT_NoAction; | |
270 | return; | |
271 | } | |
272 | while (my $sub = readdir SUB) { | |
273 | next if $sub =~ m/^\./; | |
274 | my $key = "$name/$sub"; | |
275 | if ($found->{$key}) { | |
276 | die "FOUND BOTH $found->{$key} and $location/$sub - you need to fix this by hand\n"; | |
277 | } | |
278 | $found->{$key} = "$location/$sub"; | |
279 | } | |
280 | closedir(SUB); | |
281 | } | |
282 | ||
283 | sub find_items { | |
284 | my $path = shift; | |
285 | my $type = shift; | |
286 | my %found; | |
287 | my @subs; | |
288 | ||
289 | unless (opendir(ITEMS, $path)) { | |
290 | print "Failed to open directory $path\n"; | |
291 | die unless $OPT_NoAction; | |
292 | return; | |
293 | } | |
294 | while (my $item = readdir ITEMS) { | |
295 | # guaranteed evil | |
296 | next if $item =~ m/^\./; | |
297 | next if $item eq 'lost+found'; | |
298 | next if $item eq 'stage.'; | |
299 | next if $item eq 'sync.'; | |
300 | next if $item eq 'domain'; # this is just stupid, it should at LEAST have a dot | |
301 | ||
302 | if ($ishash{$item}) { | |
303 | push @subs, $item; | |
337 | 304 | } |
338 | 305 | else { |
339 | unless (-d $i) { | |
340 | mkdir ("$i", 0755) or ouch "couldn't create $i"; | |
341 | } | |
342 | } | |
343 | } | |
344 | unless ($tonone) { | |
345 | foreach $i (@{$old}) { | |
346 | if (opendir SUB, $i) { | |
347 | while ($s = readdir SUB) { | |
348 | if ($s =~ /^\./s) { next; } | |
349 | ||
350 | chdir "$i/$s"; | |
351 | ||
352 | if($type_of_move == $MOVE_DOMAIN_CONF) { | |
353 | &do_subdomain_conf; | |
354 | } elsif ($type_of_move == $MOVE_DOMAIN_SIEVE) { | |
355 | &move_sieve; | |
356 | } elsif ($type_of_move == $MOVE_DOMAIN_PART) { | |
357 | &move_part; | |
358 | } else { | |
359 | die "bad domain move mode: $type_of_move"; | |
360 | } | |
361 | ||
362 | chdir "../.."; | |
363 | ||
364 | $h_32 = dir_hash_c_32($s); | |
365 | $h_64 = dir_hash_c_64($s); | |
366 | print "moving $i/$s to $h_64/$s\n"; | |
367 | if ("$h_32" eq "$h_64") { | |
368 | rename ("$i/$s", "$h_64/$s") or ouch "couldn't move $s back!"; | |
369 | } else { | |
370 | rename ("$i/$s", "$h_32/$s") or ouch "couldn't move $s back!"; | |
371 | rename ("$h_32/$s", "$h_64/$s") or ouch "couldn't move $s back!"; | |
372 | } | |
373 | } | |
374 | closedir SUB; | |
375 | rmdir "$i" or die "couldn't remove $i"; | |
376 | } | |
377 | } | |
378 | opendir (USER, "."); | |
379 | while ($f = readdir USER) { | |
380 | if ($f =~ /^\./s) { next; } | |
381 | ||
382 | # don't move the hashed directories themselves | |
383 | my $flag = 0; | |
384 | foreach $item (@{$dirs}) { | |
385 | if($item eq $f) { | |
386 | $flag = 1; | |
387 | $break; | |
388 | } | |
389 | } | |
390 | next if($flag); | |
391 | ||
392 | # hash on name before '.sub' suffix | |
393 | print "$f\n"; | |
394 | $h_32 = dir_hash_c_32($f); | |
395 | $h_64 = dir_hash_c_64($f); | |
396 | if ("$h_32" eq "$h_64") { | |
397 | rename ($f, "$h_64/$f") or ouch "couldn't move $f into $h_64"; | |
398 | } else { | |
399 | rename ($f, "$h_32/$f") or ouch "couldn't move $f into $h_32"; | |
400 | rename ("$h_32/$f", "$h_64/$f") or ouch "couldn't move $h_32 into $h_64"; | |
401 | } | |
402 | } | |
403 | closedir USER; | |
404 | } | |
405 | } | |
406 | ||
407 | sub move_users { | |
408 | my $i; | |
409 | my $s; | |
410 | my $h_32; | |
411 | my $h_64; | |
412 | my $f; | |
413 | my $mbox; | |
414 | ||
415 | foreach $i (@{$dirs}) { | |
416 | if ($tonone) { | |
417 | if (opendir SUB, $i) { | |
418 | while ($s = readdir SUB) { | |
419 | if ($s =~ /^\./s) { next; } | |
420 | rename ("$i/$s", "$s") or die "couldn't move $s back!"; | |
421 | } | |
422 | closedir SUB; | |
423 | rmdir "$i" or die "couldn't remove $i"; | |
424 | } | |
425 | } else { | |
426 | unless (-d $i) { | |
427 | mkdir ("$i", 0755) or ouch "couldn't create $i"; | |
428 | } | |
429 | } | |
430 | } | |
431 | unless ($tonone) { | |
432 | foreach $i (@{$old}) { | |
433 | if (opendir SUB, $i) { | |
434 | while ($s = readdir SUB) { | |
435 | if ($s =~ /^\./s) { next; } | |
436 | # hash on name before '.sub' suffix | |
437 | if ($s =~ /^(.+)\./) { | |
438 | $h_32 = dir_hash_c_32($1); | |
439 | $h_64 = dir_hash_c_64($1); | |
440 | if ("$h_32" eq "$h_64") { | |
441 | rename ("$i/$s", "$h_64/$s") or ouch "couldn't move $s back!"; | |
442 | } else { | |
443 | rename ("$i/$s", "$h_32/$s") or ouch "couldn't move $s back!"; | |
444 | rename ("$h_32/$s", "$h_64/$s") or ouch "couldn't move $s back!"; | |
445 | } | |
446 | } | |
447 | } | |
448 | closedir SUB; | |
449 | rmdir "$i" or die "couldn't remove $i"; | |
450 | } | |
451 | } | |
452 | opendir (USER, "."); | |
453 | while ($f = readdir USER) { | |
454 | if ($f =~ /^\./s) { next; } | |
455 | # hash on name before '.sub' suffix | |
456 | if ($f =~ /^(.+)\./) { | |
457 | print "$f\n"; | |
458 | $h_32 = dir_hash_c_32($1); | |
459 | $h_64 = dir_hash_c_64($1); | |
460 | if ("$h_32" eq "$h_64") { | |
461 | rename ($f, "$h_64/$f") or ouch "couldn't move $f into $h_64"; | |
462 | } else { | |
463 | rename ($f, "$h_32/$f") or ouch "couldn't move $f into $h_32"; | |
464 | rename ("$h_32/$f", "$h_64/$f") or ouch "couldn't move $h_32/$f into $h_64"; | |
465 | } | |
466 | } | |
467 | } | |
468 | closedir USER; | |
469 | } | |
470 | } | |
471 | ||
472 | sub move_quotas { | |
473 | my $i; | |
474 | my $s; | |
475 | my $h_32; | |
476 | my $h_64; | |
477 | my $mbox; | |
478 | ||
479 | # first, create directories we know can't conflict with existing files | |
480 | foreach $i (@{$dirs}) { | |
481 | if ($tonone) { | |
482 | if (-d $i) { | |
483 | rename ($i, ".$i") or die "couldn't rename $i to .$i"; | |
484 | opendir SUB, ".$i"; | |
485 | while ($s = readdir SUB) { | |
486 | if ($s =~ /^\./s) { next; } | |
487 | rename(".$i/$s", $s) or die "couldn't move $s back!"; | |
488 | } | |
489 | closedir SUB; | |
490 | rmdir ".$i" or die "couldn't remove .$i"; | |
491 | } | |
492 | } | |
493 | else { | |
494 | if (-d $i) { | |
495 | rename ($i, ".$i") or die "couldn't rename $i to .$i"; | |
496 | } | |
497 | else { | |
498 | mkdir (".$i", 0755); | |
499 | } | |
500 | } | |
501 | } | |
502 | ||
503 | # now for each file, move it into the appropriate directory | |
504 | unless ($tonone) { | |
505 | foreach $i (@{$old}) { | |
506 | if (opendir SUB, $i) { | |
507 | while ($s = readdir SUB) { | |
508 | # hash on name after 'user.' | |
509 | if ($s =~ /^.+\.(.+)$/) { | |
510 | $h_32 = dir_hash_c_32($1); | |
511 | $h_64 = dir_hash_c_64($1); | |
512 | if ("$h_32" eq "$h_64") { | |
513 | rename ("$i/$s", ".$h_64/$s") | |
514 | or ouch "couldn't move $s back!"; | |
515 | } else { | |
516 | rename ("$i/$s", ".$h_32/$s") | |
517 | or ouch "couldn't move $s back!"; | |
518 | rename (".$h_32/$s", ".$h_64/$s") | |
519 | or ouch "couldn't move $s back!"; | |
520 | } | |
521 | } | |
522 | } | |
523 | closedir SUB; | |
524 | rmdir "$i" or die "couldn't remove $i"; | |
525 | } | |
526 | } | |
527 | opendir QUOTA, "."; | |
528 | while ($mbox = readdir QUOTA) { | |
529 | if ($mbox =~ /^\./s) { next; } | |
530 | ||
531 | # hash on name after 'user.' | |
532 | if ($mbox =~ /^.*\.(.*)$/) { | |
533 | $h_32 = dir_hash_c_32($1); | |
534 | $h_64 = dir_hash_c_64($1); | |
535 | if ("$h_32" eq "$h_64") { | |
536 | rename ($mbox, ".$h_64/$mbox") | |
537 | or ouch "couldn't move $mbox into $h_64"; | |
538 | } else { | |
539 | rename ($mbox, ".$h_32/$mbox") | |
540 | or ouch "couldn't move $mbox into $h_32"; | |
541 | rename (".$h_32/$mbox", ".$h_64/$mbox") | |
542 | or ouch "couldn't move $mbox into $h_64"; | |
543 | } | |
306 | add_found($type, \%found, $item, "$path/$item"); | |
307 | } | |
308 | } | |
309 | closedir(ITEMS); | |
310 | ||
311 | foreach my $sub (@subs) { | |
312 | next unless opendir(ITEMS, "$path/$sub"); | |
313 | while (my $item = readdir ITEMS) { | |
314 | next if $item =~ m/^\./; | |
315 | # we can't fix duplicate directories ourselves! | |
316 | add_found($type, \%found, $item, "$path/$sub/$item"); | |
317 | } | |
318 | closedir(ITEMS); | |
319 | } | |
320 | ||
321 | return %found; | |
322 | } | |
323 | ||
324 | sub do_moves { | |
325 | my $path = shift; | |
326 | my $isspool = shift; | |
327 | my $skiptochar = shift; | |
328 | my %found = @_; | |
329 | ||
330 | foreach my $item (sort keys %found) { | |
331 | my $src = $found{$item}; | |
332 | my $dst = hash_path($path, $item, $isspool, $skiptochar); | |
333 | ||
334 | if ($src ne $dst) { | |
335 | ensure_parent($dst); | |
336 | print "rename $src to $dst: " if $OPT_Verbose; | |
337 | if ($OPT_NoAction) { | |
338 | print "skipped\n" if $OPT_Verbose; | |
544 | 339 | next; |
545 | 340 | } |
546 | ||
547 | # we should try to hash the entire file | |
548 | $h_32 = dir_hash_c_32($mbox); | |
549 | $h_64 = dir_hash_c_64($mbox); | |
550 | if ("$h_32" eq "$h_64") { | |
551 | rename ($mbox, ".$h_64/$mbox") | |
552 | or ouch "couldn't move $mbox into $h_64"; | |
553 | } else { | |
554 | rename ($mbox, ".$h_32/$mbox") | |
555 | or ouch "couldn't move $mbox into $h_32"; | |
556 | rename (".$h_32/$mbox", ".$h_64/$mbox") | |
557 | or ouch "couldn't move $mbox into $h_64"; | |
341 | rename($src, $dst) or die "failed to rename $src to $dst"; | |
342 | print "done\n" if $OPT_Verbose; | |
343 | } | |
344 | } | |
345 | } | |
346 | ||
347 | sub move_domains { | |
348 | my $path = shift; | |
349 | my $type_of_move = shift || die "move_domains called badly"; | |
350 | my $isspool = ($type_of_move eq 'part'); | |
351 | ||
352 | my %found = find_items($path, 'domain'); | |
353 | ||
354 | # let's do the subdirs first, then move the top levels | |
355 | foreach my $item (sort keys %found) { | |
356 | if ($type_of_move eq 'conf') { | |
357 | if (-d "$path/quota") { | |
358 | move_quotas("$path/quota"); | |
558 | 359 | } |
559 | next; | |
560 | ||
561 | } | |
562 | closedir QUOTA; | |
563 | ||
564 | # now move each temporary directory to the right place | |
565 | foreach $i (@{$dirs}) { | |
566 | rename (".$i", $i) or ouch "couldn't rename $i into place"; | |
567 | } | |
568 | } | |
569 | } | |
570 | ||
571 | sub move_sieve { | |
572 | my $i; | |
573 | my $s; | |
574 | my $h_32; | |
575 | my $h_64; | |
576 | my $mbox; | |
577 | ||
578 | foreach $i (@{$dirs}) { | |
579 | unless ($tonone) { | |
580 | if (-d $i) { | |
581 | rename ($i, ".$i") or die "couldn't rename $i to .$i"; | |
582 | } | |
583 | else { | |
584 | mkdir (".$i", 0755); | |
585 | } | |
360 | if (-d "$path/user") { | |
361 | move_users("$path/user"); | |
586 | 362 | } |
587 | else { | |
588 | rmdir "$i"; | |
363 | } elsif ($type_of_move eq 'sieve') { | |
364 | move_sieve($found{$item}, 1); | |
365 | } elsif ($type_of_move == 'part') { | |
366 | move_part($found{$item}, 1); | |
367 | } else { | |
368 | die "bad domain move mode: $type_of_move"; | |
369 | } | |
370 | } | |
371 | ||
372 | do_moves($path, $isspool, undef, %found); | |
373 | tidy_up($path, $isspool, 0); | |
374 | } | |
375 | ||
376 | sub move_users { | |
377 | my $path = shift; | |
378 | ||
379 | my %found = find_items($path, 'user'); | |
380 | do_moves($path, 0, undef, %found); | |
381 | tidy_up($path, 0, 0); | |
382 | } | |
383 | ||
384 | sub move_quotas { | |
385 | my $path = shift; | |
386 | ||
387 | my %found = find_items($path, 'quota'); | |
388 | do_moves($path, 0, '.', %found); | |
389 | tidy_up($path, 0, 0); | |
390 | } | |
391 | ||
392 | sub move_sieve { | |
393 | my $path = shift; | |
394 | my $indomain = shift; | |
395 | ||
396 | my %found = find_items($path, 'sieve'); | |
397 | ||
398 | if ($virtdomains and not $indomain) { | |
399 | ensure_dir("$path/domain"); | |
400 | move_domains("$path/domain", 'sieve'); | |
401 | } | |
402 | ||
403 | do_moves($path, 0, undef, %found); | |
404 | tidy_up($path, 0, 0); | |
405 | } | |
406 | ||
407 | # could be data or meta | |
408 | sub move_part { | |
409 | my $path = shift; | |
410 | my $indomain = shift; | |
411 | ||
412 | # let's just assume nobody is being stupid and creating 1 character toplevel names | |
413 | my %found = find_items($path, 'part'); | |
414 | ||
415 | if ($virtdomains and not $indomain) { | |
416 | ensure_dir("$path/domain"); | |
417 | move_domains("$path/domain", 'part'); | |
418 | } | |
419 | ||
420 | do_moves($path, 1, '/', %found); | |
421 | tidy_up($path, 1, 1); | |
422 | } | |
423 | ||
424 | sub ensure_dir { | |
425 | my $dir = shift; | |
426 | unless (-d $dir) { | |
427 | ensure_parent($dir); | |
428 | print "mkdir $dir: " if $OPT_Verbose; | |
429 | if ($OPT_NoAction) { | |
430 | print "skipped\n" if $OPT_Verbose; | |
431 | return; | |
432 | } | |
433 | mkdir($dir, 0755) || die "Failed to create $dir: $!"; | |
434 | print "done\n" if $OPT_Verbose; | |
435 | } | |
436 | return 1; | |
437 | } | |
438 | ||
439 | sub ensure_parent { | |
440 | my $path = shift; | |
441 | $path =~ s{/[^/]+$}{}; | |
442 | return ensure_dir($path); | |
443 | } | |
444 | ||
445 | sub remove_dir { | |
446 | my $dir = shift; | |
447 | return 1 unless -d $dir; | |
448 | print "rmdir $dir: " if $OPT_Verbose; | |
449 | if ($OPT_NoAction) { | |
450 | print "skipped\n" if $OPT_Verbose; | |
451 | return; | |
452 | } | |
453 | if (opendir(DH, $dir)) { | |
454 | my @extra; | |
455 | while (my $item = readdir(DH)) { | |
456 | next if $item eq '.'; | |
457 | next if $item eq '..'; | |
458 | push @extra, $item; | |
459 | } | |
460 | closedir(DH); | |
461 | if (@extra) { | |
462 | my $num = @extra; | |
463 | my $s = $num == 1 ? '' : 's'; | |
464 | print "skipped, $num extra item$s found, including $dir/$extra[0]\n"; | |
465 | return; | |
466 | } | |
467 | } | |
468 | rmdir($dir) || die "Failed to remove $dir: $!"; | |
469 | print "done\n" if $OPT_Verbose; | |
470 | return 1; | |
471 | } | |
472 | ||
473 | sub tidydir { | |
474 | my $dir = shift; | |
475 | my $onemore = shift; | |
476 | ||
477 | if ($onemore) { | |
478 | if (opendir(DIR, $dir)) { | |
479 | while (my $item = readdir DIR) { | |
480 | next if $item =~ m/^\./; | |
481 | remove_dir("$dir/$item"); | |
589 | 482 | } |
590 | } | |
591 | unless ($tonone) { | |
592 | foreach $i (@{$old}) { | |
593 | if (opendir SUB, $i) { | |
594 | while ($s = readdir SUB) { | |
595 | unless ($s =~ /^\./) { | |
596 | $h_32 = dir_hash_c_32($s); | |
597 | $h_64 = dir_hash_c_64($s); | |
598 | if ("$h_32" eq "$h_64") { | |
599 | rename ("$i/$s", ".$h_64/$s") | |
600 | or ouch "couldn't move $s back!"; | |
601 | } else { | |
602 | rename ("$i/$s", ".$h_32/$s") | |
603 | or ouch "couldn't move $s back!"; | |
604 | rename (".$h_32/$s", ".$h_64/$s") | |
605 | or ouch "couldn't move $s back!"; | |
606 | } | |
607 | } | |
608 | } | |
609 | closedir SUB; | |
610 | rmdir "$i" or die "couldn't remove $i"; | |
611 | } | |
612 | } | |
613 | # now move each temporary directory to the right place | |
614 | foreach $i (@{$dirs}) { | |
615 | rename (".$i", $i) or ouch "couldn't rename $i into place"; | |
616 | } | |
617 | } | |
618 | ||
619 | if($virtdomains && chdir "domain") { | |
620 | &move_domains($MOVE_DOMAIN_SIEVE); | |
621 | chdir ".."; | |
622 | } | |
623 | } | |
624 | ||
625 | sub move_part { | |
626 | my $i; | |
627 | my $s; | |
628 | my $t; | |
629 | my $h_32; | |
630 | my $h_64; | |
631 | my $dir; | |
632 | my $sub; | |
633 | my $ismbox; | |
634 | ||
635 | foreach $i (@{$dirs}) { | |
636 | if ($tonone) { | |
637 | if (-d $i) { | |
638 | rename ($i, ".$i") or die "couldn't rename $i to .$i"; | |
639 | print "$i "; | |
640 | ||
641 | opendir SUB, ".$i"; | |
642 | while ($s = readdir SUB) { | |
643 | if ($s =~ /^\./s) { next; } | |
644 | mkdir $s, 0755; # ignore errors as it might already exist | |
645 | ||
646 | opendir MV, ".$i/$s"; | |
647 | while ($t = readdir MV) { | |
648 | if ($t =~ /^\./s) { next; } | |
649 | rename (".$i/$s/$t", "$s/$t") | |
650 | or die "couldn't rename .$i/$s/$t to $s/$t"; | |
651 | } | |
652 | closedir MV; | |
653 | } | |
654 | closedir SUB; | |
655 | rmdir ".$i" or die "could not remove .$i"; | |
656 | } | |
657 | print "done\n"; | |
658 | } | |
659 | else { | |
660 | mkdir (".$i", 0755) or ouch "couldn't create .$i"; | |
661 | } | |
662 | } | |
663 | ||
664 | unless ($tonone) { | |
665 | foreach $i (@{$old}) { | |
666 | if (opendir SUB, $i) { | |
667 | while ($dir = readdir SUB) { | |
668 | if ($dir =~ /^\./s) { next; } | |
669 | # process $dir | |
670 | print "$i/$dir "; | |
671 | opendir DIR, "$i/$dir"; | |
672 | $ismbox = 0; | |
673 | while ($sub = readdir DIR) { | |
674 | if ($sub =~ /^\./s) { next; } | |
675 | # if there's a dot in this, we're a mbox and | |
676 | # this isn't a child | |
677 | if ($sub =~ /(.*)\.(.*)/) { $ismbox = 1; next; } | |
678 | ||
679 | print "/$sub "; | |
680 | $h_32 = dir_hash_c_32($sub); | |
681 | $h_64 = dir_hash_c_64($sub); | |
682 | mkdir (".$h_64/$dir", 0755); # might already be there | |
683 | if ("$h_32" eq "$h_64") { | |
684 | rename ("$i/$dir/$sub", ".$h_64/$dir/$sub") | |
685 | or ouch "couldn't move $dir/$sub into $h_64"; | |
686 | } else { | |
687 | mkdir (".$h_32/$dir", 0755); # might already be there | |
688 | rename ("$i/$dir/$sub", ".$h_32/$dir/$sub") | |
689 | or ouch "couldn't move $dir/$sub into $h_32"; | |
690 | rename (".$h_32/$dir/$sub", ".$h_64/$dir/$sub") | |
691 | or ouch "couldn't move $dir/$sub into $h_32"; | |
692 | rmdir ".$h_32/$dir"; | |
693 | } | |
694 | } | |
695 | closedir DIR; | |
696 | # if $ismbox is set, then $dir is a mailbox of it's own right | |
697 | if ($ismbox) { | |
698 | $h_32 = dir_hash_c_32($dir); | |
699 | $h_64 = dir_hash_c_64($dir); | |
700 | mkdir (".$h_64/$dir", 0755); # might already be there | |
701 | opendir DIR, "$i/$dir"; | |
702 | while ($sub = readdir DIR) { | |
703 | if ($sub =~ /^\./s) { next; } | |
704 | print "/$sub "; | |
705 | if ("$h_32" eq "$h_64") { | |
706 | rename ("$i/$dir/$sub", ".$h_64/$dir/$sub") | |
707 | or ouch "couldn't move $dir into $h_64"; | |
708 | } else { | |
709 | mkdir (".$h_32/$dir", 0755); # might already be there | |
710 | rename ("$i/$dir/$sub", ".$h_32/$dir/$sub") | |
711 | or ouch "couldn't move $dir into $h_32"; | |
712 | rename (".$h_32/$dir/$sub", ".$h_64/$dir/$sub") | |
713 | or ouch "couldn't move $dir into $h_64"; | |
714 | rmdir ".$h_32/$dir"; | |
715 | } | |
716 | } | |
717 | closedir DIR; | |
718 | } | |
719 | ||
720 | rmdir "$i/$dir" or print "\ncouldn't remove '$dir'??\n"; | |
721 | } | |
722 | closedir SUB; | |
723 | rmdir "$i" or die "couldn't remove $i"; | |
724 | } | |
725 | } | |
726 | opendir PART, "."; | |
727 | while ($dir = readdir PART) { | |
728 | if ($dir =~ /^\./s) { next; } | |
729 | if ($dir eq "lost+found") { next; } | |
730 | if ($dir eq "stage.") { next; } | |
731 | if ($dir eq "domain") { | |
732 | if(chdir "domain") { | |
733 | &move_domains($MOVE_DOMAIN_PART); | |
734 | chdir ".."; | |
735 | } | |
736 | next; | |
737 | } | |
738 | ||
739 | # process $dir | |
740 | print "$dir "; | |
741 | opendir DIR, $dir; | |
742 | $ismbox = 0; | |
743 | while ($sub = readdir DIR) { | |
744 | if ($sub =~ /^\./s) { next; } | |
745 | # if there's a dot in this, we're a mbox and | |
746 | # this isn't a child | |
747 | if ($sub =~ /(.*)\.(.*)/) { $ismbox = 1; next; } | |
748 | ||
749 | $h_32 = dir_hash_c_32($sub); | |
750 | $h_64 = dir_hash_c_64($sub); | |
751 | mkdir (".$h_64/$dir", 0755); # might already be there | |
752 | if ("$h_32" eq "$h_64") { | |
753 | rename ("$dir/$sub", ".$h_64/$dir/$sub") | |
754 | or ouch "couldn't move $dir/$sub into $h_64"; | |
755 | } else { | |
756 | mkdir (".$h_32/$dir", 0755); # might already be there | |
757 | rename ("$dir/$sub", ".$h_32/$dir/$sub") | |
758 | or ouch "couldn't move $dir/$sub into $h_32"; | |
759 | rename (".$h_32/$dir/$sub", ".$h_64/$dir/$sub") | |
760 | or ouch "couldn't move $dir/$sub into $h_64"; | |
761 | rmdir ".$h_32/$dir"; | |
762 | } | |
763 | } | |
764 | closedir DIR; | |
765 | # if $ismbox is set, then $dir is a mailbox of it's own right | |
766 | if ($ismbox) { | |
767 | $h_32 = dir_hash_c_32($dir); | |
768 | $h_64 = dir_hash_c_64($dir); | |
769 | mkdir (".$h_64/$dir", 0755); # might already be there | |
770 | opendir DIR, $dir; | |
771 | while ($sub = readdir DIR) { | |
772 | if ($sub =~ /^\./s) { next; } | |
773 | if ("$h_32" eq "$h_64") { | |
774 | rename ("$dir/$sub", ".$h_64/$dir/$sub") | |
775 | or ouch "couldn't move $dir into $h_64"; | |
776 | } else { | |
777 | mkdir (".$h_32/$dir", 0755); # might already be there | |
778 | rename ("$dir/$sub", ".$h_32/$dir/$sub") | |
779 | or ouch "couldn't move $dir into $h_32"; | |
780 | rename (".$h_32/$dir/$sub", ".$h_64/$dir/$sub") | |
781 | or ouch "couldn't move $dir into $h_64"; | |
782 | rmdir ".$h_32/$dir"; | |
783 | } | |
784 | } | |
785 | closedir DIR; | |
786 | } | |
787 | ||
788 | rmdir $dir or print "\ncouldn't remove '$dir'??\n"; | |
789 | } | |
790 | closedir PART; | |
791 | ||
792 | foreach $i (@{$dirs}) { | |
793 | rename (".$i", $i) or ouch "couldn't rename .$i to $i"; | |
794 | } | |
795 | } | |
796 | } | |
483 | closedir(DIR); | |
484 | } | |
485 | } | |
486 | ||
487 | remove_dir($dir); | |
488 | } | |
489 | ||
490 | sub tidy_up { | |
491 | my $path = shift; | |
492 | my $isspool = shift; | |
493 | my $onemore = shift; | |
494 | ||
495 | ||
496 | unless (not $fulldirhash and (not $isspool or $hashimapspool)) { | |
497 | tidydir("$path/$_", $onemore) for @bdirs; | |
498 | } | |
499 | unless ($fulldirhash and (not $isspool or $hashimapspool)) { | |
500 | tidydir("$path/$_", $onemore) for @fdirs; | |
501 | } | |
502 | } |