1 /* mbtool.c - tool to fiddle mailboxes
2 *
3 * Copyright (c) 1994-2008 Carnegie Mellon University. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * 3. The name "Carnegie Mellon University" must not be used to
18 * endorse or promote products derived from this software without
19 * prior written permission. For permission or any legal
20 * details, please contact
21 * Carnegie Mellon University
22 * Center for Technology Transfer and Enterprise Creation
23 * 4615 Forbes Avenue
24 * Suite 302
25 * Pittsburgh, PA 15213
26 * (412) 268-7393, fax: (412) 268-7395
27 * innovation@andrew.cmu.edu
28 *
29 * 4. Redistributions of any form whatsoever must retain the following
30 * acknowledgment:
31 * "This product includes software developed by Computing Services
32 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
33 *
34 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
35 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
36 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
37 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
38 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
39 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
40 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
41 */
42
43 #include <config.h>
44
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <fcntl.h>
52 #include <sysexits.h>
53 #include <syslog.h>
54 #include <sys/types.h>
55 #include <netinet/in.h>
56 #include <sys/stat.h>
57
58 #if HAVE_DIRENT_H
59 # include <dirent.h>
60 # define NAMLEN(dirent) strlen((dirent)->d_name)
61 #else
62 # define dirent direct
63 # define NAMLEN(dirent) (dirent)->d_namlen
64 # if HAVE_SYS_NDIR_H
65 # include <sys/ndir.h>
66 # endif
67 # if HAVE_SYS_DIR_H
68 # include <sys/dir.h>
69 # endif
70 # if HAVE_NDIR_H
71 # include <ndir.h>
72 # endif
73 #endif
74
75 #include "assert.h"
76 #include "index.h"
77 #include "global.h"
78 #include "mailbox.h"
79 #include "message.h"
80 #include "message_guid.h"
81 #include "mboxname.h"
82 #include "mboxlist.h"
83 #include "seen.h"
84 #include "times.h"
85 #include "util.h"
86 #include "xmalloc.h"
87
88 /* generated headers are not necessarily in current directory */
89 #include "imap/imap_err.h"
90
91 extern int optind;
92 extern char *optarg;
93
94 /* current namespace */
95 static struct namespace mbtool_namespace;
96
97 /* forward declarations */
98 static int do_cmd(struct findall_data *data, void *rock);
99
100 static void usage(void);
101 void shut_down(int code);
102
103 enum {
104 CMD_TIME = 1,
105 CMD_REID = 2,
106 };
107
main(int argc,char ** argv)108 int main(int argc, char **argv)
109 {
110 int opt, i, r;
111 int cmd = 0;
112 char *alt_config = NULL;
113
114 while ((opt = getopt(argc, argv, "C:rt")) != EOF) {
115 switch (opt) {
116 case 'C': /* alt config file */
117 alt_config = optarg;
118 break;
119
120 case 'r':
121 if (cmd == 0) cmd = CMD_REID;
122 else usage();
123 break;
124 case 't':
125 if (cmd == 0) cmd = CMD_TIME;
126 else usage();
127 break;
128
129 default:
130 usage();
131 }
132 }
133
134 /* must provide a command */
135 if (!cmd) usage();
136
137 /* must provide some mailboxes */
138 if (optind == argc) usage();
139
140 cyrus_init(alt_config, "mbtool", 0, 0);
141
142 /* Set namespace -- force standard (internal) */
143 if ((r = mboxname_init_namespace(&mbtool_namespace, 1)) != 0) {
144 syslog(LOG_ERR, "%s", error_message(r));
145 fatal(error_message(r), EX_CONFIG);
146 }
147
148 signals_set_shutdown(&shut_down);
149 signals_add_handlers(0);
150
151 for (i = optind; i < argc; i++) {
152 mboxlist_findall(&mbtool_namespace, argv[i], 1, 0, 0, do_cmd, &cmd);
153 }
154
155 exit(0);
156 }
157
usage(void)158 static void usage(void)
159 {
160 fprintf(stderr, "Usage:\n");
161 fprintf(stderr, " mbtool [options] {-r|-t} mailbox...\n");
162 fprintf(stderr, "\nCommands:\n");
163 fprintf(stderr, " -r create new unique IDs for specified mailboxes\n");
164 fprintf(stderr, " -t normalise internaldates in specified mailboxes\n");
165 fprintf(stderr, "\nOptions:\n");
166 fprintf(stderr, " -C alt_config use alternate imapd.conf file\n");
167 exit(EX_USAGE);
168 }
169
170 /*
171 * mboxlist_findall() callback function to examine a mailbox
172 */
do_timestamp(const mbname_t * mbname)173 static int do_timestamp(const mbname_t *mbname)
174 {
175 int r = 0;
176 struct mailbox *mailbox = NULL;
177 char olddate[RFC5322_DATETIME_MAX+1];
178 char newdate[RFC5322_DATETIME_MAX+1];
179
180 signals_poll();
181
182 /* Convert internal name to external */
183 const char *extname = mbname_extname(mbname, &mbtool_namespace, "cyrus");
184 printf("Working on %s...\n", extname);
185
186 const char *name = mbname_intname(mbname);
187
188 /* Open/lock header */
189 r = mailbox_open_iwl(name, &mailbox);
190 if (r) return r;
191
192 struct mailbox_iter *iter = mailbox_iter_init(mailbox, 0, ITER_SKIP_EXPUNGED);
193 const message_t *msg;
194 while ((msg = mailbox_iter_step(iter))) {
195 const struct index_record *record = msg_record(msg);
196 /* 1 day is close enough */
197 if (labs(record->internaldate - record->gmtime) < 86400)
198 continue;
199
200 struct index_record copyrecord = *record;
201
202 time_to_rfc5322(copyrecord.internaldate, olddate, sizeof(olddate));
203 time_to_rfc5322(copyrecord.gmtime, newdate, sizeof(newdate));
204 printf(" %u: %s => %s\n", copyrecord.uid, olddate, newdate);
205
206 /* switch internaldate */
207 copyrecord.internaldate = copyrecord.gmtime;
208
209 r = mailbox_rewrite_index_record(mailbox, ©record);
210 if (r) goto done;
211 }
212
213 done:
214 mailbox_iter_done(&iter);
215 mailbox_close(&mailbox);
216
217 return r;
218 }
219
do_reid(const mbname_t * mbname)220 static int do_reid(const mbname_t *mbname)
221 {
222 int r = 0;
223 struct mailbox *mailbox = NULL;
224 mbentry_t *mbentry = NULL;
225
226 /* Convert internal name to external */
227 const char *extname = mbname_extname(mbname, &mbtool_namespace, "cyrus");
228 printf("Working on %s...\n", extname);
229
230 const char *name = mbname_intname(mbname);
231
232 r = mailbox_open_iwl(name, &mailbox);
233 if (r) return r;
234
235 mailbox_make_uniqueid(mailbox);
236
237 r = mboxlist_lookup(name, &mbentry, NULL);
238 if (r) return r;
239
240 free(mbentry->uniqueid);
241 mbentry->uniqueid = xstrdup(mailbox->uniqueid);
242
243 mboxlist_update(mbentry, 0);
244
245 mailbox_close(&mailbox);
246
247 /* printf("did reid %s\n", mboxname); */
248 return r;
249 }
250
251
do_cmd(struct findall_data * data,void * rock)252 int do_cmd(struct findall_data *data, void *rock)
253 {
254 if (!data) return 0;
255 if (!data->is_exactmatch) return 0;
256
257 int *valp = (int *)rock;
258
259 if (*valp == CMD_TIME)
260 return do_timestamp(data->mbname);
261
262 if (*valp == CMD_REID)
263 return do_reid(data->mbname);
264
265 return 0;
266 }
267
268 /*
269 * Cleanly shut down and exit
270 */
271 void shut_down(int code) __attribute__((noreturn));
shut_down(int code)272 void shut_down(int code)
273 {
274 in_shutdown = 1;
275
276 mboxlist_close();
277 mboxlist_done();
278 exit(code);
279 }
280