]>
Commit | Line | Data |
---|---|---|
1 | #include <stdlib.h> | |
2 | #include <sys/stat.h> | |
3 | #include <sys/types.h> | |
4 | #include <fcntl.h> | |
5 | #include <dirent.h> | |
6 | #include <stdio.h> | |
7 | #include <time.h> | |
8 | #include <string.h> | |
9 | #include <errno.h> | |
10 | ||
11 | #define ARCHIVE_PREFIX "Archive-" | |
12 | ||
13 | char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; | |
14 | char fromfolder[512]; | |
15 | char fromdirectory[512]; | |
16 | int skipped = 0; | |
17 | ||
18 | struct folder_list_t { | |
19 | char *name; | |
20 | int emails; | |
21 | struct folder_list_t *next; | |
22 | }; | |
23 | ||
24 | struct folder_list_t *folderhead; | |
25 | ||
26 | void move_email(const char *name, const char *folder) | |
27 | { | |
28 | struct folder_list_t *lp; | |
29 | int foundfolder = 0; | |
30 | char oldfilename[512]; | |
31 | char filename[512]; | |
32 | ||
33 | for (lp = folderhead; lp->next; lp = lp->next) | |
34 | if (!strcmp(folder, lp->name)) | |
35 | break; | |
36 | ||
37 | if (!lp->next) | |
38 | { | |
39 | int fd; | |
40 | ||
41 | lp = malloc(sizeof(*folderhead)); | |
42 | lp->next = folderhead; | |
43 | lp->emails = 0; | |
44 | lp->name = strdup(folder); | |
45 | folderhead = lp; | |
46 | ||
47 | /* create the folder */ | |
48 | sprintf(filename, ".INBOX.%s", folder); | |
49 | mkdir(filename, 0700); | |
50 | ||
51 | sprintf(filename, ".INBOX.%s/cur", folder); | |
52 | if (mkdir(filename, 0700) && (errno != EEXIST)) | |
53 | { | |
54 | perror("mkdir(cur)"); | |
55 | exit(1); | |
56 | } | |
57 | ||
58 | sprintf(filename, ".INBOX.%s/new", folder); | |
59 | if (mkdir(filename, 0700) && (errno != EEXIST)) | |
60 | { | |
61 | perror("mkdir(new)"); | |
62 | exit(1); | |
63 | } | |
64 | ||
65 | sprintf(filename, ".INBOX.%s/tmp", folder); | |
66 | if (mkdir(filename, 0700) && (errno != EEXIST)) | |
67 | { | |
68 | perror("mkdir(tmp)"); | |
69 | exit(1); | |
70 | } | |
71 | ||
72 | sprintf(filename, ".INBOX.%s/maildirfolder", folder); | |
73 | if ((fd = open(filename, O_CREAT | O_WRONLY, 0700)) < 0) | |
74 | { | |
75 | perror("open(maildirfolder)"); | |
76 | exit(1); | |
77 | } | |
78 | close(fd); | |
79 | } | |
80 | ||
81 | lp->emails++; | |
82 | ||
83 | sprintf(oldfilename, "%s/%s", fromdirectory, name); | |
84 | sprintf(filename, ".INBOX.%s/cur/%s", folder, name); | |
85 | ||
86 | /* skipped if it's the same thing, since the link won't catch it, and the unlink will kill it */ | |
87 | if (!strcmp(oldfilename, filename)) | |
88 | { | |
89 | skipped++; | |
90 | return; | |
91 | } | |
92 | ||
93 | if (link(oldfilename, filename) && (errno != EEXIST)) | |
94 | { | |
95 | char theerror[1024]; | |
96 | sprintf(theerror, "link(%s, %s)", oldfilename, filename); | |
97 | perror(theerror); | |
98 | exit(1); | |
99 | } | |
100 | ||
101 | if (unlink(oldfilename)) | |
102 | { | |
103 | char theerror[1024]; | |
104 | sprintf(theerror, "unlink(%s)", oldfilename); | |
105 | perror(theerror); | |
106 | exit(1); | |
107 | } | |
108 | } | |
109 | ||
110 | int spinnerstate = 0; | |
111 | char spinner[] = "/-\\|"; | |
112 | #define SPINNERSTATES 4 | |
113 | #define MAXAGE 7*24*60*60 | |
114 | ||
115 | void main(int argc, char **argv) | |
116 | { | |
117 | DIR *cur; | |
118 | struct dirent *de; | |
119 | off_t dirstart; | |
120 | int emails = 0, notemails = 0, toonew = 0, starttime = time(NULL); | |
121 | ||
122 | if (argc == 2) | |
123 | { | |
124 | strcpy(fromfolder, argv[1]); | |
125 | sprintf(fromdirectory, ".INBOX.%s/cur", fromfolder); | |
126 | } else if (argc == 1) { | |
127 | strcpy(fromdirectory, "cur"); | |
128 | strcpy(fromfolder, ""); | |
129 | } else { | |
130 | printf("maildir-archiver: Usage: %s [<folder name>]\n", argv[0]); | |
131 | exit(1); | |
132 | } | |
133 | ||
134 | folderhead = malloc(sizeof(*folderhead)); | |
135 | folderhead->next = NULL; | |
136 | ||
137 | printf("maildir-archiver: Opening %s/... ", fromdirectory); | |
138 | fflush(stdout); | |
139 | cur = opendir(fromdirectory); | |
140 | if (!cur) | |
141 | { | |
142 | perror("opendir(cur)"); | |
143 | exit(1); | |
144 | } | |
145 | dirstart = telldir(cur); | |
146 | printf("done\n"); | |
147 | ||
148 | printf("maildir-archiver: Doing preliminary scan of e-mails... ."); | |
149 | fflush(stdout); | |
150 | while ((de = readdir(cur))) | |
151 | { | |
152 | time_t tt; | |
153 | struct tm *tm; | |
154 | char archivefolder[128]; | |
155 | ||
156 | tt = atoi(de->d_name); | |
157 | if (tt == 0) | |
158 | { | |
159 | notemails++; | |
160 | continue; | |
161 | } | |
162 | if ((starttime - tt) < MAXAGE) | |
163 | { | |
164 | toonew++; | |
165 | continue; | |
166 | } | |
167 | emails++; | |
168 | if ((emails % 10000) == 0) | |
169 | { | |
170 | printf("\b%c", spinner[(spinnerstate++) % SPINNERSTATES]); | |
171 | fflush(stdout); | |
172 | } | |
173 | } | |
174 | printf("\bdone (%d mails to archive, %d too new, %d invalid)\n", emails, toonew, notemails); | |
175 | seekdir(cur, dirstart); | |
176 | ||
177 | printf("maildir-archiver: Archiving e-mail... [> ]"); | |
178 | fflush(stdout); | |
179 | while ((de = readdir(cur))) | |
180 | { | |
181 | static int progresscounter = 0; | |
182 | static int archived = 0; | |
183 | time_t tt; | |
184 | struct tm *tm; | |
185 | char archivefolder[128]; | |
186 | int islist = 0; | |
187 | char fn[256]; | |
188 | FILE *fp; | |
189 | ||
190 | tt = atoi(de->d_name); | |
191 | if (tt == 0) | |
192 | continue; | |
193 | if ((starttime - tt) < MAXAGE) | |
194 | continue; | |
195 | ||
196 | tm = localtime(&tt); | |
197 | ||
198 | /* Open the file to determine if it's a mailing list or what */ | |
199 | sprintf(fn, "%s/%s", fromdirectory, de->d_name); | |
200 | fp = fopen(fn, "r"); | |
201 | if (!fp) | |
202 | { | |
203 | perror("fopen(fn, r)"); | |
204 | exit(1); | |
205 | } | |
206 | { | |
207 | char line[512]; | |
208 | while (fgets(line, 512, fp)) | |
209 | { | |
210 | if (!strncmp(line, "X-BeenThere: ", 13)) | |
211 | islist++; | |
212 | if (!strncmp(line, "List-Unsubscribe: ", 18)) | |
213 | islist++; | |
214 | if (!strncmp(line, "X-Mailing-List", 14)) | |
215 | islist++; | |
216 | if (!strncmp(line, "Precedence: bulk", 16)) | |
217 | islist++; | |
218 | ||
219 | if (!line[0]) | |
220 | break; | |
221 | } | |
222 | } | |
223 | fclose(fp); | |
224 | ||
225 | /* sprintf(archivefolder, ARCHIVE_PREFIX "%d-%02d", 1900 + tm->tm_year, tm->tm_mon + 1); */ | |
226 | sprintf(archivefolder, ARCHIVE_PREFIX "%d-Q%d-%s", 1900 + tm->tm_year, (tm->tm_mon) / 3 + 1, islist ? "List" : "Personal"); | |
227 | move_email(de->d_name, archivefolder); | |
228 | archived++; | |
229 | ||
230 | if (((archived % 10) == 0) || (archived == emails)) | |
231 | { | |
232 | int i; | |
233 | progresscounter = archived * 32 / emails; | |
234 | printf("\rmaildir-archiver: Archiving e-mail... ["); | |
235 | for (i=0; i < progresscounter; i++) | |
236 | printf("="); | |
237 | if (progresscounter != 32) | |
238 | printf(">"); | |
239 | for (i=0; i < (31 - progresscounter); i++) | |
240 | printf(" "); | |
241 | printf("] "); | |
242 | printf("%c ", spinner[(spinnerstate++) % SPINNERSTATES]); | |
243 | printf("%d/%d", archived, emails); | |
244 | fflush(stdout); | |
245 | } | |
246 | } | |
247 | printf("\n"); | |
248 | printf("maildir-archiver: Statistics:\n"); | |
249 | printf("maildir-archiver: All operations performed in %d seconds\n", time(NULL)-starttime); | |
250 | printf("maildir-archiver:\n"); | |
251 | printf("maildir-archiver: -------------------------------+----------\n"); | |
252 | printf("maildir-archiver: %-30s | Emails\n", "Status"); | |
253 | printf("maildir-archiver: -------------------------------+----------\n"); | |
254 | printf("maildir-archived: %-30s | %6d\n", "Processed", emails); | |
255 | printf("maildir-archived: %-30s | %6d\n", "Too new", toonew); | |
256 | printf("maildir-archived: %-30s | %6d\n", "Not an e-mail", notemails); | |
257 | printf("maildir-archived: %-30s | %6d\n", "Already in correct folder", skipped); | |
258 | printf("maildir-archiver: -------------------------------+----------\n"); | |
259 | printf("maildir-archiver:\n"); | |
260 | printf("maildir-archiver: -------------------------------+----------\n"); | |
261 | printf("maildir-archiver: %-30s | Emails\n", "Folder"); | |
262 | printf("maildir-archiver: -------------------------------+----------\n"); | |
263 | { | |
264 | struct folder_list_t *lp; | |
265 | int total = 0; | |
266 | ||
267 | for (lp = folderhead; lp->next; lp = lp->next) | |
268 | { | |
269 | printf("maildir-archiver: %-30s | %6d\n", lp->name, lp->emails); | |
270 | total += lp->emails; | |
271 | } | |
272 | printf("maildir-archiver: %-30s | %6d\n", "Total", total); | |
273 | } | |
274 | printf("maildir-archiver: -------------------------------+----------\n"); | |
275 | } |