Line 0
Link Here
|
|
|
1 |
/* |
2 |
* Maildir Module for PINE 4.0x - fourth release, use with CARE! |
3 |
* |
4 |
* Author: Mattias Larsson <ml@techno.org> |
5 |
* |
6 |
* Version: 21.07.98 |
7 |
* |
8 |
* Please read the README.maildir file before using this module! |
9 |
* |
10 |
* If you have any questions, please e-mail ml@techno.org |
11 |
* |
12 |
* Multiple inboxes patch by Dean Gaudet <dgaudet@arctic.org> |
13 |
* |
14 |
* ================================================= |
15 |
* |
16 |
* Based on the IMAP2 maildir routines by: |
17 |
* |
18 |
* Author: Eric Green |
19 |
* Bloodhounds International Inc. |
20 |
* thrytis@imaxx.net |
21 |
* |
22 |
* Additional contributions from: |
23 |
* Aidas Kasparas (kaspar@soften.ktu.lt) |
24 |
* |
25 |
* Date: 27 April 1997 |
26 |
* Last Edited: 13 June 1997 |
27 |
* |
28 |
* Based (heavily) on mh.c and other c-client library files by Mark Crispin: |
29 |
* |
30 |
* Mark Crispin |
31 |
* Networks and Distributed Computing |
32 |
* Computing & Communications |
33 |
* University of Washington |
34 |
* Administration Building, AG-44 |
35 |
* Seattle, WA 98195 |
36 |
* Internet: MRC@CAC.Washington.EDU |
37 |
* |
38 |
* Copyright 1995 by the University of Washington |
39 |
* |
40 |
* Permission to use, copy, modify, and distribute this software and its |
41 |
* documentation for any purpose and without fee is hereby granted, provided |
42 |
* that the above copyright notice appears in all copies and that both the |
43 |
* above copyright notice and this permission notice appear in supporting |
44 |
* documentation, and that the name of the University of Washington not be |
45 |
* used in advertising or publicity pertaining to distribution of the software |
46 |
* without specific, written prior permission. This software is made |
47 |
* available "as is", and |
48 |
* THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, |
49 |
* WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED |
50 |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN |
51 |
* NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL, |
52 |
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM |
53 |
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT |
54 |
* (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION |
55 |
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
56 |
* |
57 |
*/ |
58 |
|
59 |
/* CONFIGURABLE OPTIONS - PLEASE CHECK THESE OUT */ |
60 |
|
61 |
#define NO_MAILDIR_FIDDLE /* disallow Maildir with Maildir in the |
62 |
name. This is useful in an ISP setup |
63 |
using the IMAP daemon. #undef it if you |
64 |
are running a normal pine and know what |
65 |
you are doing */ |
66 |
|
67 |
#define NO_ABSOLUTE_PATHS /* if you define this, all paths |
68 |
use your HOMEDIR is the root instead |
69 |
of the actual root of the machine. This |
70 |
is also useful in an ISP setup with |
71 |
IMAP */ |
72 |
|
73 |
#undef NO_UID_VALIDITIY /* define this if you want the UID's not |
74 |
to be persistent over sessions. Use this |
75 |
if you use another client to read the |
76 |
maildir that screws up the special way |
77 |
in which we store UIDs. Do not enable |
78 |
unless you are sure you need it. */ |
79 |
|
80 |
/* END CONFIGURATION */ |
81 |
|
82 |
#define MTA_DEBUG /* debugging sent to stdout */ |
83 |
#undef MTA_DEBUG |
84 |
|
85 |
#include <stdio.h> |
86 |
#include <ctype.h> |
87 |
#include <errno.h> |
88 |
extern int errno; /* just in case */ |
89 |
#include "mail.h" |
90 |
#include "osdep.h" |
91 |
#include <pwd.h> |
92 |
#include <sys/stat.h> |
93 |
#include <sys/time.h> |
94 |
#include <sys/types.h> |
95 |
#include <utime.h> |
96 |
#include "maildir.h" |
97 |
#include "misc.h" |
98 |
#include "dummy.h" |
99 |
|
100 |
/* Driver dispatch used by MAIL */ |
101 |
|
102 |
DRIVER maildirdriver = { |
103 |
"maildir", /* driver name */ |
104 |
/* driver flags */ |
105 |
DR_MAIL|DR_LOCAL|DR_NOFAST|DR_NAMESPACE, |
106 |
(DRIVER *) NIL, /* next driver */ |
107 |
maildir_valid, /* mailbox is valid for us */ |
108 |
maildir_parameters, /* manipulate parameters */ |
109 |
NIL, /* scan mailboxes */ |
110 |
maildir_list, /* find mailboxes */ |
111 |
maildir_lsub, /* find subscribed mailboxes */ |
112 |
maildir_sub, /* subscribe to mailbox */ |
113 |
maildir_unsub, /* unsubscribe from mailbox */ |
114 |
maildir_create, /* create mailbox */ |
115 |
maildir_delete, /* delete mailbox */ |
116 |
maildir_rename, /* rename mailbox */ |
117 |
NIL, /* status of mailbox */ |
118 |
maildir_open, /* open mailbox */ |
119 |
maildir_close, /* close mailbox */ |
120 |
maildir_fast, /* fetch message "fast" attributes */ |
121 |
NIL, /* fetch message flags */ |
122 |
NIL, /* fetch overview */ |
123 |
NIL, /* fetch message envelopes */ |
124 |
maildir_fetchheader, /* fetch message header */ |
125 |
maildir_fetchtext, /* fetch message body */ |
126 |
NIL, /* fetch partial message text */ |
127 |
NIL, /* unique identifier */ |
128 |
NIL, /* message number */ |
129 |
NIL, /* modify flags */ |
130 |
maildir_flagmsg, /* per-message modify flags */ |
131 |
NIL, /* search for message based on criteria */ |
132 |
NIL, /* sort messages */ |
133 |
NIL, /* thread messages */ |
134 |
maildir_ping, /* ping mailbox to see if still alive */ |
135 |
maildir_check, /* check for new messages */ |
136 |
maildir_expunge, /* expunge deleted messages */ |
137 |
maildir_copy, /* copy messages to another mailbox */ |
138 |
maildir_append, /* append string message to mailbox */ |
139 |
maildir_gc /* garbage collect stream */ |
140 |
}; |
141 |
|
142 |
/* prototype stream */ |
143 |
MAILSTREAM maildirproto = {&maildirdriver}; |
144 |
|
145 |
/* Check validity of mailbox |
146 |
*/ |
147 |
|
148 |
DRIVER *maildir_valid (char *name) |
149 |
{ |
150 |
return maildir_isvalid(name,T) ? &maildirdriver : NIL; |
151 |
} |
152 |
|
153 |
int maildir_isvalid (char *name,long justname) |
154 |
{ |
155 |
char tmp[MAILTMPLEN]; |
156 |
struct stat sbuf; |
157 |
|
158 |
if (!name || (!*name) || |
159 |
((*name == '#') && |
160 |
(*(name+1) == 0 || |
161 |
(*(name+1) != 'm' && *(name+1) != 'M') || |
162 |
(*(name+2) != 'd' && *(name+1) != 'D') || |
163 |
*(name+3) != '/')) || (*name == '.')) |
164 |
return NIL; |
165 |
|
166 |
/* okay, anything containing the name Maildir will be ignored |
167 |
this is to prevent anyone from fiddling with their incoming Maildir |
168 |
directly, it should be accessed via the INBOX alias */ |
169 |
|
170 |
#ifdef NO_MAILDIR_FIDDLE |
171 |
if (strstr(name, ".maildir")) { |
172 |
return NIL; |
173 |
} |
174 |
#endif |
175 |
/* If we are requested only to check |
176 |
if the name is appropriate then we |
177 |
have done! */ |
178 |
if (justname && *name == '#') return T; |
179 |
|
180 |
|
181 |
/* must be valid local mailbox */ |
182 |
if ((*name != '*') && (*name != '{') && |
183 |
maildir_file (tmp,name) && |
184 |
/* assume its maildir if its a dir */ |
185 |
stat (tmp,&sbuf) == 0 && S_ISDIR (sbuf.st_mode)) |
186 |
return T; |
187 |
|
188 |
/* INBOX is for default Maildir */ |
189 |
if (!strcmp (ucase (strcpy (tmp,name)), "INBOX") && |
190 |
(stat (maildir_file (tmp,name),&sbuf) == 0) && |
191 |
S_ISDIR (sbuf.st_mode)) |
192 |
return T; |
193 |
|
194 |
return NIL; |
195 |
} |
196 |
|
197 |
/* Maildir mail generate file string |
198 |
*/ |
199 |
|
200 |
char *maildir_file (char *dst,char *name) |
201 |
{ |
202 |
char tmp[MAILTMPLEN]; |
203 |
|
204 |
if (strlen (name) > 3 && /* safe do other comparisons */ |
205 |
(*name == '#') && |
206 |
(name[1] == 'm' || name[1] == 'M') && |
207 |
(name[2] == 'd' || name[2] == 'D') && |
208 |
(name[3] == '/')) |
209 |
name += 4; |
210 |
|
211 |
#ifdef NO_ABSOLUTE_PATHS |
212 |
if (*name == '/') { |
213 |
/* we do not want to accept / absolute paths, so lets strip the first |
214 |
/ ... */ |
215 |
sprintf(dst,"%s/%s/cur", myhomedir(), name+1); |
216 |
|
217 |
/* strncpy (dst, name, MAILTMPLEN - 2); |
218 |
strncat (dst, "/cur", MAILTMPLEN - 2); |
219 |
dst[MAILTMPLEN - 1] = '\0'; */ |
220 |
} |
221 |
else |
222 |
sprintf (dst,"%s/%s/cur",myhomedir (), |
223 |
strcmp (ucase (strcpy (tmp, name)), "INBOX") ? name : MAILDIRPATH); |
224 |
#else |
225 |
if (*name == '/') { |
226 |
strncpy (dst, name, MAILTMPLEN - 2); |
227 |
strncat (dst, "/cur", MAILTMPLEN - 2); |
228 |
dst[MAILTMPLEN - 1] = '\0'; |
229 |
} |
230 |
else |
231 |
sprintf (dst,"%s/%s/cur",myhomedir (), |
232 |
strcmp (ucase (strcpy (tmp, name)), "INBOX") ? name : MAILDIRPATH); |
233 |
|
234 |
#endif |
235 |
|
236 |
#ifdef MTA_DEBUG |
237 |
printf("maildir_file '%s'\n", dst); |
238 |
#endif |
239 |
return dst; |
240 |
} |
241 |
|
242 |
/* Maildir open |
243 |
*/ |
244 |
|
245 |
MAILSTREAM *maildir_open (MAILSTREAM *stream) |
246 |
{ |
247 |
char tmp[MAILTMPLEN],tmp2[MAILTMPLEN]; |
248 |
|
249 |
if (!stream) return &maildirproto; |
250 |
if (LOCAL) { /* recycle stream */ |
251 |
maildir_close (stream, 0); |
252 |
stream->dtb = &maildirdriver; |
253 |
mail_free_cache (stream); |
254 |
stream->uid_last = 0; /* default UID validity */ |
255 |
stream->uid_validity = time (0); |
256 |
} |
257 |
|
258 |
stream->uid_validity = 0; /* was time(0) */ |
259 |
|
260 |
if (stream->uid_last < time(0)) |
261 |
stream->uid_last = time (0); |
262 |
|
263 |
stream->local = fs_get (sizeof (MAILDIRLOCAL)); |
264 |
LOCAL->inbox = !strcmp (ucase (strcpy (tmp,stream->mailbox)),"INBOX") || |
265 |
!strcmp (stream->mailbox,maildir_file (tmp2,"INBOX")); |
266 |
LOCAL->dir = cpystr (maildir_file (tmp,stream->mailbox)); /* copy dir name */ |
267 |
/* make temporary buffer */ |
268 |
LOCAL->buf = (char *) fs_get ((LOCAL->buflen = MAXMESSAGESIZE) + 1); |
269 |
LOCAL->scantime = 0; /* not scanned yet */ |
270 |
stream->sequence++; |
271 |
stream->nmsgs = stream->recent = 0; |
272 |
|
273 |
maildir_ping_core (stream); |
274 |
maildir_ping (stream); |
275 |
/* if (maildir_ping (stream) && !(stream->nmsgs || stream->silent)) |
276 |
printf("Mailbox is empty\n"); |
277 |
*/ |
278 |
return stream; |
279 |
|
280 |
} |
281 |
|
282 |
/* Maildir ping mailbox |
283 |
*/ |
284 |
|
285 |
long maildir_ping_core (MAILSTREAM *stream) |
286 |
{ |
287 |
char tmp[MAILTMPLEN]; |
288 |
MESSAGECACHE *elt; |
289 |
struct stat sbuf, sbuf2; |
290 |
DIR *dir; |
291 |
struct direct *d; |
292 |
int reloadall = NIL; |
293 |
int uidinvalid = NIL; |
294 |
unsigned long old; |
295 |
long i; |
296 |
long nmsgs = stream->nmsgs; |
297 |
long recent = stream->recent; |
298 |
long nfiles = stream->nmsgs; |
299 |
int silent = stream->silent; |
300 |
char *s, *s2; |
301 |
mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL); |
302 |
|
303 |
/* maildir_copynew (LOCAL->dir); |
304 |
*/ |
305 |
|
306 |
if (stat (LOCAL->dir,&sbuf) < 0) { |
307 |
sprintf (tmp,"Unable to open maildir: %s",strerror (errno)); |
308 |
mm_log (tmp,ERROR); |
309 |
return NIL; |
310 |
} |
311 |
|
312 |
/* okay, lets try to figure out the Maildir UID validity. This is done |
313 |
by checking the last modification time of the file .uidvalidity |
314 |
in the rootdir of the Maildir. Any program reordering the files |
315 |
in the directory have to touch this file */ |
316 |
|
317 |
sprintf(tmp, "%s/../.uidvalidity", LOCAL->dir); |
318 |
|
319 |
if (stat (tmp,&sbuf2) < 0) { |
320 |
/* no uid validity file found, if uid_validity == 0, we have |
321 |
to set it to something other than 0, and then create the |
322 |
.uidvalidity file for future accesses */ |
323 |
|
324 |
if (stream->uid_validity == 0) { |
325 |
FILE *fl; |
326 |
struct utimbuf tbuf; |
327 |
|
328 |
stream->uid_validity = time(0); |
329 |
tbuf.actime = stream->uid_validity; |
330 |
tbuf.modtime = stream->uid_validity; |
331 |
|
332 |
if ((fl = fopen(tmp, "w"))) { |
333 |
fclose(fl); |
334 |
chmod (tmp, S_IRUSR|S_IWUSR); |
335 |
utime(tmp, &tbuf); |
336 |
} |
337 |
} |
338 |
uidinvalid = T; /* UID's are invalid, update them */ |
339 |
} else { |
340 |
/* valid file, lets set UID if uid_validity = 0 */ |
341 |
if (stream->uid_validity == 0) { |
342 |
stream->uid_validity = sbuf2.st_mtime; |
343 |
} |
344 |
} |
345 |
|
346 |
#ifdef NO_UID_VALIDITY |
347 |
uidinvalid = T; /* force the UIDs to be invalid and reset every time, |
348 |
useful in an environment without imap servers and |
349 |
clients that screw up the UIDs.. i'd leave it to |
350 |
OFF until I really need it though... */ |
351 |
#endif |
352 |
|
353 |
stream->silent = T; |
354 |
if (sbuf.st_ctime != LOCAL->scantime) { |
355 |
/* update the message list */ |
356 |
struct direct **names = NIL; |
357 |
nfiles = scandir (LOCAL->dir,&names,maildir_select,maildir_namesort); |
358 |
|
359 |
for (i = 0; i < nfiles; i++) { |
360 |
|
361 |
/* check if file has executable bit set */ |
362 |
sprintf(tmp, "%s/%s", LOCAL->dir, names[i]->d_name); |
363 |
stat (tmp,&sbuf2); |
364 |
if (sbuf2.st_mode & S_IXUSR) { |
365 |
/* executable bit set, modtime is uid */ |
366 |
if (sbuf2.st_mtime > stream->uid_last) |
367 |
stream->uid_last = sbuf2.st_mtime+1; |
368 |
} |
369 |
/* this is kept for backwards compatibility */ |
370 |
if ((s = strstr (names[i]->d_name,":3,"))) |
371 |
s += 3; |
372 |
if (s && (s2 = strstr (s, ",U"))) { |
373 |
s2 += 2; |
374 |
sscanf(s2, "%d", &old); |
375 |
if (old > stream->uid_last) { |
376 |
stream->uid_last = old+1; |
377 |
} |
378 |
} |
379 |
|
380 |
} |
381 |
|
382 |
mm_critical (stream); /* go critical */ |
383 |
old = stream->uid_last; |
384 |
LOCAL->scantime = sbuf.st_ctime; |
385 |
|
386 |
/* check if old files same */ |
387 |
for (i = 0; i < stream->nmsgs; i++) { |
388 |
|
389 |
if (strcmp ((char *) mail_elt (stream, i + 1)->maildirp, |
390 |
names[i]->d_name)) { |
391 |
reloadall = T; |
392 |
break; |
393 |
} |
394 |
} |
395 |
|
396 |
if (reloadall) { /* files are out of order, rebuild cache */ |
397 |
|
398 |
i = 1; |
399 |
while (i <= stream->nmsgs) |
400 |
/* clean out cache */ |
401 |
if ((elt = (MESSAGECACHE *) (*mc) (stream,i,CH_ELT))) { |
402 |
fs_give ((void **) &elt->maildirp); |
403 |
mail_expunged (stream,i); |
404 |
} |
405 |
else |
406 |
i++; |
407 |
|
408 |
mm_log ("Warning: Mailbox has changed in an unexpected way. Reloading.", |
409 |
WARN); |
410 |
stream->nmsgs = 0; |
411 |
} |
412 |
nmsgs = stream->nmsgs; |
413 |
|
414 |
stream->nmsgs = nfiles; /* hm? */ |
415 |
|
416 |
for (i = nmsgs; i < nfiles; i++) { |
417 |
|
418 |
mail_exists(stream, i+1); |
419 |
/* if newly seen, add to list */ |
420 |
(elt = mail_elt (stream, i + 1))->maildirp = (long) cpystr (names[i]->d_name); |
421 |
elt->valid = T; |
422 |
|
423 |
/* grab the flags */ |
424 |
if ((s = strstr (names[i]->d_name,":3,"))) { |
425 |
s += 3; |
426 |
if (strchr (s,'F')) |
427 |
elt->flagged = T; |
428 |
if (strchr (s,'R')) |
429 |
elt->answered = T; |
430 |
if (strchr (s,'S')) |
431 |
elt->seen = T; |
432 |
if (strchr (s,'T')) |
433 |
elt->deleted = T; |
434 |
} else if ((s = strstr (names[i]->d_name,":2,"))) { |
435 |
/* this is the :2, id where all files go nowadays */ |
436 |
s += 3; |
437 |
if (strchr (s,'F')) |
438 |
elt->flagged = T; |
439 |
if (strchr (s,'R')) |
440 |
elt->answered = T; |
441 |
if (strchr (s,'S')) |
442 |
elt->seen = T; |
443 |
if (strchr (s,'T')) |
444 |
elt->deleted = T; |
445 |
sprintf(tmp, "%s/%s", LOCAL->dir, names[i]->d_name); |
446 |
stat (tmp,&sbuf2); |
447 |
if (sbuf2.st_mode & S_IXUSR) { |
448 |
/* executable bit set, modtime is uid */ |
449 |
elt->private.uid = sbuf2.st_mtime; |
450 |
} |
451 |
/* and if we could not retrieve UID from modtime, or if |
452 |
UIDs are invalid, go here */ |
453 |
if (elt->private.uid == 0 || uidinvalid) { |
454 |
stream->uid_last = (elt = mail_elt (stream,i+1))->private.uid = stream->uid_last+1; |
455 |
maildir_flagmsg(stream, elt); |
456 |
} |
457 |
s = 0; /* make sure next if statement does not trigger */ |
458 |
} |
459 |
|
460 |
if (s) |
461 |
if ((s2 = strstr (s, ",U"))) { |
462 |
s2 += 2; |
463 |
sscanf(s2, "%d", &elt->private.uid); |
464 |
if (elt->private.uid == 0 || uidinvalid) { |
465 |
stream->uid_last = (elt = mail_elt (stream,i+1))->private.uid = stream->uid_last+1; |
466 |
maildir_flagmsg(stream, elt); |
467 |
} |
468 |
|
469 |
} else { /* assign new UID */ |
470 |
stream->uid_last = (elt = mail_elt (stream,i+1))->private.uid = stream->uid_last+1; |
471 |
elt->recent = T; |
472 |
recent++; |
473 |
maildir_flagmsg(stream, elt); /* store the UID that we assigned to it */ |
474 |
} |
475 |
|
476 |
|
477 |
|
478 |
} |
479 |
|
480 |
mm_nocritical (stream); /* release critical */ |
481 |
/* free the names stuff */ |
482 |
for (i = 0; i < nfiles; i++) |
483 |
fs_give ((void **) &names[i]); |
484 |
if (names) |
485 |
fs_give ((void **) &names); |
486 |
} |
487 |
stream->silent = silent; |
488 |
mail_exists(stream,nfiles); |
489 |
/* if (!reloadall) */ |
490 |
mail_recent (stream,recent); |
491 |
|
492 |
return T; /* return that we are alive */ |
493 |
} |
494 |
|
495 |
long maildir_ping (MAILSTREAM *stream) |
496 |
{ |
497 |
maildir_copynew (LOCAL->dir); |
498 |
return maildir_ping_core (stream); |
499 |
} |
500 |
|
501 |
void maildir_copynew (const char *mailbox) |
502 |
{ |
503 |
char tmp[MAILTMPLEN],file[MAILTMPLEN],newfile[MAILTMPLEN]; |
504 |
DIR *dir; |
505 |
struct dirent *d; |
506 |
struct stat sbuf; |
507 |
|
508 |
sprintf (tmp,"%s/../new",mailbox); |
509 |
if (!(dir = opendir (tmp))) |
510 |
return; |
511 |
|
512 |
while (d = readdir (dir)) { |
513 |
if (d->d_name[0] == '.') |
514 |
continue; /* skip .files */ |
515 |
|
516 |
sprintf (file,"%s/%s",tmp,d->d_name); |
517 |
/* make sure this is a normal file */ |
518 |
if (stat (file,&sbuf) == 0 && S_ISREG (sbuf.st_mode)) { |
519 |
|
520 |
if (strstr (d->d_name,":3,")) /* this message already has flags */ |
521 |
sprintf (newfile,"%s/%s",mailbox,d->d_name); |
522 |
else |
523 |
sprintf (newfile,"%s/%s:3,",mailbox,d->d_name); |
524 |
|
525 |
/* move the new mail to the cur dir */ |
526 |
if (link (file,newfile) == -1) |
527 |
mm_log("Unable to read new mail!",WARN); |
528 |
else |
529 |
unlink (file); |
530 |
} |
531 |
} |
532 |
closedir (dir); |
533 |
} |
534 |
|
535 |
int maildir_select (struct direct *name) |
536 |
{ |
537 |
if (name->d_name[0] != '.') |
538 |
return T; |
539 |
|
540 |
return NIL; |
541 |
} |
542 |
|
543 |
int maildir_namesort (struct direct **d1,struct direct **d2) |
544 |
{ |
545 |
/* this maildir module is kind of lame and expects files it just moved |
546 |
* from new/ to cur/ to show up at the end of the sorting... this mostly |
547 |
* works fine when the timestamp is less than 1000000000 -- you can just |
548 |
* strcmp. but when the timestamp went past that point we need to do |
549 |
* this convoluted sort. |
550 |
*/ |
551 |
unsigned long t1, t2; |
552 |
|
553 |
t1 = strtoul((*d1)->d_name, NULL, 10); |
554 |
t2 = strtoul((*d2)->d_name, NULL, 10); |
555 |
if (t1 == t2) { |
556 |
return strcmp ((*d1)->d_name,(*d2)->d_name); |
557 |
} |
558 |
else if (t1 > t2) { |
559 |
return 1; |
560 |
} |
561 |
return -1; |
562 |
} |
563 |
|
564 |
|
565 |
/* Maildir garbage collect stream |
566 |
*/ |
567 |
|
568 |
void maildir_gc (MAILSTREAM *stream,long gcflags) |
569 |
{ |
570 |
unsigned long i; |
571 |
|
572 |
if (gcflags & GC_TEXTS) { /* garbage collect texts? */ |
573 |
/* flush texts from cache */ |
574 |
/* if (LOCAL->hdr) fs_give ((void **) &LOCAL->hdr); |
575 |
// if (stream->text) fs_give ((void **) &stream->text); |
576 |
// stream->msgno = 0; invalidate stream text |
577 |
*/ |
578 |
} |
579 |
} |
580 |
|
581 |
/* Maildir close |
582 |
*/ |
583 |
|
584 |
void maildir_close (MAILSTREAM *stream, long options) |
585 |
{ |
586 |
MESSAGECACHE *elt; |
587 |
int i; |
588 |
mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL); |
589 |
|
590 |
/* CL_EXPUNGE OPTION SUPPORT HERE SOMEWHERE! */ |
591 |
/* clean out the cached paths */ |
592 |
for (i = 1; i <= stream->nmsgs; i++) |
593 |
if ((elt = (MESSAGECACHE *) (*mc) (stream,i,CH_ELT)) && elt->maildirp) { |
594 |
fs_give ((void **) &elt->maildirp); |
595 |
elt->maildirp = 0; /* otherwise pine coredumps */ |
596 |
} |
597 |
|
598 |
if (LOCAL) { /* only if a stream is open */ |
599 |
if (LOCAL->dir) fs_give ((void **) &LOCAL->dir); |
600 |
maildir_gc (stream,GC_TEXTS); /* free local cache */ |
601 |
/* free local scratch buffer */ |
602 |
if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); |
603 |
/* nuke the local data */ |
604 |
fs_give ((void **) &stream->local); |
605 |
stream->dtb = NIL; /* log out the DTB */ |
606 |
} |
607 |
} |
608 |
|
609 |
void maildir_check (MAILSTREAM *stream) |
610 |
{ |
611 |
/* Perhaps in the future this will preserve flags */ |
612 |
if (maildir_ping (stream)) mm_log ("Check completed",(long) NIL); |
613 |
} |
614 |
|
615 |
long maildir_fetchtext (MAILSTREAM *stream,unsigned long msgno,STRING *bs, long flags) |
616 |
{ |
617 |
unsigned long i; |
618 |
MESSAGECACHE *elt; |
619 |
/* UID call "impossible" */ |
620 |
if (flags & FT_UID) return NIL; |
621 |
elt = mail_elt (stream,msgno);/* get elt */ |
622 |
/* snarf message if don't have it yet */ |
623 |
if (!elt->private.msg.text.text.data) { |
624 |
maildir_fetchheader (stream,msgno,&i,flags); |
625 |
if (!elt->private.msg.text.text.data) return NIL; |
626 |
} |
627 |
if (!(flags & FT_PEEK)) { /* mark as seen */ |
628 |
mail_elt (stream,msgno)->seen = T; |
629 |
maildir_flagmsg (stream, mail_elt(stream,msgno)); |
630 |
mm_flags (stream,msgno); |
631 |
} |
632 |
if (!elt->private.msg.text.text.data) return NIL; |
633 |
INIT (bs,mail_string,elt->private.msg.text.text.data, |
634 |
elt->private.msg.text.text.size); |
635 |
return T; |
636 |
} |
637 |
|
638 |
|
639 |
/* Maildir fetch message header |
640 |
*/ |
641 |
|
642 |
char *maildir_fetchheader (MAILSTREAM *stream,unsigned long msgno, |
643 |
unsigned long *length, long flags) |
644 |
{ |
645 |
unsigned long i,hdrsize; |
646 |
int fd; |
647 |
char *t; |
648 |
char tmp[MAILTMPLEN]; |
649 |
char *s,*b; |
650 |
struct stat sbuf; |
651 |
struct tm *tm; |
652 |
MESSAGECACHE *elt; |
653 |
*length = 0; /* default to empty */ |
654 |
if (flags & FT_UID) return "";/* UID call "impossible" */ |
655 |
elt = mail_elt (stream,msgno);/* get elt */ |
656 |
if (!elt->private.msg.header.text.data) { |
657 |
|
658 |
/* maildir_gc (stream,GC_TEXTS); invalidate current cache */ |
659 |
/* build message file name */ |
660 |
sprintf (tmp,"%s/%s",LOCAL->dir,(char *) elt->maildirp); |
661 |
if ((fd = open (tmp,O_RDONLY,NIL)) >= 0) { |
662 |
fstat (fd,&sbuf); /* get size of message */ |
663 |
/* make plausible IMAPish date string */ |
664 |
tm = gmtime (&sbuf.st_mtime); |
665 |
elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1; |
666 |
elt->year = tm->tm_year + 1900 - BASEYEAR; |
667 |
elt->hours = tm->tm_hour; elt->minutes = tm->tm_min; |
668 |
elt->seconds = tm->tm_sec; |
669 |
elt->zhours = 0; elt->zminutes = 0; |
670 |
/* slurp message */ |
671 |
read (fd,s = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size); |
672 |
s[sbuf.st_size] = '\0'; /* tie off file */ |
673 |
close (fd); /* close file */ |
674 |
|
675 |
for (i = 0,b = s; *b && !(i && (*b == '\n')); i = (*b++ == '\n')); |
676 |
hdrsize = (*b ? ++b:b)-s; /* number of header bytes */ |
677 |
|
678 |
elt->rfc822_size = /* size of entire message in CRLF form */ |
679 |
(elt->private.msg.header.text.size = |
680 |
strcrlfcpy ((char **) &elt->private.msg.header.text.data,&i,s, |
681 |
hdrsize)) + |
682 |
(elt->private.msg.text.text.size = |
683 |
strcrlfcpy ((char **) &elt->private.msg.text.text.data,&i,b, |
684 |
sbuf.st_size - hdrsize)); |
685 |
fs_give ((void **) &s); |
686 |
} else return ""; |
687 |
|
688 |
} |
689 |
|
690 |
*length = elt->private.msg.header.text.size; |
691 |
return (char *) elt->private.msg.header.text.data; |
692 |
} |
693 |
|
694 |
void maildir_fast (MAILSTREAM *stream,char *sequence,long flags) |
695 |
{ |
696 |
unsigned long i,j; |
697 |
/* ugly and slow */ |
698 |
if (stream && LOCAL && ((flags & FT_UID) ? |
699 |
mail_uid_sequence (stream,sequence) : |
700 |
mail_sequence (stream,sequence))) |
701 |
for (i = 1; i <= stream->nmsgs; i++) |
702 |
if (mail_elt (stream,i)->sequence) maildir_fetchheader (stream,i,&j,NIL); |
703 |
} |
704 |
|
705 |
/* Maildir find list of subscribed mailboxes |
706 |
* Accepts: mail stream |
707 |
* pattern to search |
708 |
*/ |
709 |
|
710 |
void maildir_list (MAILSTREAM *stream,char *ref, char *pat) |
711 |
{ |
712 |
return; |
713 |
} |
714 |
|
715 |
void *maildir_parameters (long function,void *value) |
716 |
{ |
717 |
return NIL; |
718 |
} |
719 |
|
720 |
long maildir_create (MAILSTREAM *stream,char *mailbox) |
721 |
{ |
722 |
char tmp[MAILTMPLEN]; |
723 |
char err[MAILTMPLEN]; |
724 |
char *s, *s2; |
725 |
int fnlen, i; |
726 |
char *subdir_names[] = {"/cur","/new","/tmp",NULL}; |
727 |
|
728 |
/* must not already exist */ |
729 |
if (access (maildir_file (tmp,mailbox),F_OK) == 0) { |
730 |
sprintf (err,"Can't create mailbox %s: mailbox already exists",mailbox); |
731 |
mm_log (err,ERROR); |
732 |
return NIL; |
733 |
} |
734 |
|
735 |
maildir_file (tmp,mailbox); /* get file name */ |
736 |
fnlen = strlen (tmp); |
737 |
/*syslog(LOG_INFO, "fname: '%s'", tmp);*/ |
738 |
tmp[fnlen - 4] = '\0'; /* making main directory's name */ |
739 |
fnlen -= 4; |
740 |
|
741 |
/* okay, try to add support for adding hiearchys of directories, this |
742 |
is done by scanning for /'s.... */ |
743 |
|
744 |
/*syslog(LOG_INFO, "tmp '%s'", tmp);*/ |
745 |
s = tmp; |
746 |
|
747 |
while ((s = strstr(s, "/")) != 0) { |
748 |
/*syslog(LOG_INFO, "Before make: '%s'", s);*/ |
749 |
*s = '\0'; |
750 |
/*syslog(LOG_INFO, "Trying to make: '%s'", tmp);*/ |
751 |
if (mkdir (tmp,0700) && *s != '\0') /* trying to make the dir */ |
752 |
if (errno != EEXIST) { |
753 |
sprintf (err,"Can't create mailbox %s: %s %s", |
754 |
mailbox,tmp,strerror (errno)); |
755 |
mm_log (err,ERROR); |
756 |
return NIL; |
757 |
} |
758 |
*s = '/'; |
759 |
s++; |
760 |
} |
761 |
|
762 |
if (mkdir (tmp,0700)) { /* try to make new dir */ |
763 |
sprintf (err,"Can't create mailbox %s: %s %s", |
764 |
mailbox,tmp,strerror (errno)); |
765 |
mm_log (err,ERROR); |
766 |
return NIL; |
767 |
} |
768 |
|
769 |
/*syslog(LOG_INFO, "create maildir");*/ |
770 |
for (i = 0; subdir_names[i]; i++) { |
771 |
strcpy (tmp + fnlen,subdir_names[i]); |
772 |
|
773 |
if (mkdir (tmp,0700)) { /* try to make new dir */ |
774 |
sprintf (err,"Can't create mailbox %s: %s %s", |
775 |
mailbox,tmp,strerror (errno)); |
776 |
mm_log (err,ERROR); |
777 |
return NIL; |
778 |
} |
779 |
} |
780 |
|
781 |
return T; /* return success */ |
782 |
} |
783 |
|
784 |
void maildir_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) |
785 |
{ |
786 |
char oldfile[MAILTMPLEN],newfile[MAILTMPLEN],fn[MAILTMPLEN]; |
787 |
struct utimbuf tbuf; |
788 |
char *s; |
789 |
|
790 |
/* build the new filename */ |
791 |
sprintf (oldfile,"%s/%s",LOCAL->dir,(char *) elt->maildirp); |
792 |
if ((s = strchr ((char *) elt->maildirp,':'))) *s = '\0'; |
793 |
sprintf (fn,"%s:2,%s%s%s%s",(char *) elt->maildirp,elt->flagged ? "F" : "", |
794 |
elt->answered ? "R" : "",elt->seen ? "S" : "", |
795 |
elt->deleted ? "T" : ""); |
796 |
sprintf (newfile,"%s/%s",LOCAL->dir,fn); |
797 |
/* rename the file with new flags */ |
798 |
if (rename (oldfile,newfile) < 0) { |
799 |
sprintf(oldfile,"Unable to write flags to disk: %s",strerror (errno)); |
800 |
mm_log(oldfile,ERROR); |
801 |
return; |
802 |
} |
803 |
/* update the file name in cache */ |
804 |
fs_give ((void **) &elt->maildirp); |
805 |
elt->maildirp = (long) cpystr (fn); |
806 |
|
807 |
/* fix the UID on the file */ |
808 |
tbuf.actime = elt->private.uid; |
809 |
tbuf.modtime = elt->private.uid; |
810 |
chmod (newfile, S_IRUSR|S_IWUSR|S_IXUSR); |
811 |
utime (newfile, &tbuf); |
812 |
|
813 |
} |
814 |
|
815 |
void maildir_expunge (MAILSTREAM *stream) |
816 |
{ |
817 |
MESSAGECACHE *elt; |
818 |
unsigned long i = 1; |
819 |
unsigned long n = 0; |
820 |
unsigned long recent = stream->recent; |
821 |
|
822 |
maildir_gc (stream,GC_TEXTS); /* invalidate texts */ |
823 |
mm_critical (stream); /* go critical */ |
824 |
while (i <= stream->nmsgs) { /* for each message */ |
825 |
/* if deleted, need to trash it */ |
826 |
if ((elt = mail_elt (stream,i))->deleted) { |
827 |
sprintf (LOCAL->buf,"%s/%s",LOCAL->dir,(char *) elt->maildirp); |
828 |
if (unlink (LOCAL->buf)) {/* try to delete the message */ |
829 |
sprintf (LOCAL->buf,"Expunge of message %ld failed, aborted: %s",i, |
830 |
strerror (errno)); |
831 |
mm_log (LOCAL->buf,WARN); |
832 |
break; |
833 |
} |
834 |
/* free the cached filename */ |
835 |
if (elt->maildirp) { |
836 |
fs_give ((void **) &elt->maildirp); |
837 |
elt->maildirp = 0; /* otherwise pine coredumps */ |
838 |
} |
839 |
if (elt->recent) --recent;/* if recent, note one less recent message */ |
840 |
mail_expunged (stream,i); /* notify upper levels */ |
841 |
n++; /* count up one more expunged message */ |
842 |
} |
843 |
else i++; /* otherwise try next message */ |
844 |
} |
845 |
if (n) { /* output the news if any expunged */ |
846 |
sprintf (LOCAL->buf,"Expunged %ld messages",n); |
847 |
mm_log (LOCAL->buf,(long) NIL); |
848 |
} |
849 |
else mm_log ("No messages deleted, so no update needed",(long) NIL); |
850 |
mm_nocritical (stream); /* release critical */ |
851 |
/* notify upper level of new mailbox size */ |
852 |
mail_exists (stream,stream->nmsgs); |
853 |
mail_recent (stream,recent); |
854 |
} |
855 |
|
856 |
/* dont forget to process options in here */ |
857 |
long maildir_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) |
858 |
{ |
859 |
STRING st; |
860 |
MESSAGECACHE *elt; |
861 |
struct stat sbuf; |
862 |
int fd; |
863 |
long i; |
864 |
char *s,tmp[MAILTMPLEN]; |
865 |
/* copy the messages */ |
866 |
if ((options & CP_UID) ? mail_uid_sequence (stream, sequence) : |
867 |
mail_sequence (stream,sequence)) |
868 |
for (i = 1; i <= stream->nmsgs; i++) |
869 |
if ((elt = mail_elt (stream,i))->sequence) { |
870 |
sprintf (LOCAL->buf,"%s/%s",LOCAL->dir,(char *) elt->maildirp); |
871 |
if ((fd = open (LOCAL->buf,O_RDONLY,NIL)) < 0) return NIL; |
872 |
fstat (fd,&sbuf); /* get size of message */ |
873 |
/* slurp message */ |
874 |
read (fd,s = (char *) fs_get (sbuf.st_size +1),sbuf.st_size); |
875 |
s[sbuf.st_size] = '\0'; /* tie off file */ |
876 |
close (fd); /* flush message file */ |
877 |
INIT (&st,mail_string,(void *) s,sbuf.st_size); |
878 |
sprintf (LOCAL->buf,"%s%s%s%s%s)", |
879 |
elt->seen ? " \\Seen" : "", |
880 |
elt->deleted ? " \\Deleted" : "", |
881 |
elt->flagged ? " \\Flagged" : "", |
882 |
elt->answered ? " \\Answered" : "", |
883 |
(elt->seen || elt->deleted || elt->flagged || elt->answered) ? |
884 |
"" : " "); |
885 |
LOCAL->buf[0] = '('; /* open list */ |
886 |
mail_date (tmp,elt); /* generate internal date */ |
887 |
if (!maildir_append (stream,mailbox,LOCAL->buf,tmp,&st)) { |
888 |
fs_give ((void **) &s); /* give back temporary space */ |
889 |
return NIL; |
890 |
} |
891 |
fs_give ((void **) &s); /* give back temporary space */ |
892 |
} |
893 |
return T; /* return success */ |
894 |
} |
895 |
|
896 |
long maildir_append (MAILSTREAM *stream,char *mailbox,char *flags,char *date, |
897 |
STRING *message) |
898 |
{ |
899 |
int fd; |
900 |
char c,*s; |
901 |
char tmp[MAILTMPLEN],file[MAILTMPLEN],path1[MAILTMPLEN],path2[MAILTMPLEN]; |
902 |
MESSAGECACHE elt; |
903 |
long i; |
904 |
long size = 0; |
905 |
long ret = LONGT; |
906 |
short uf = 0; |
907 |
|
908 |
/* |
909 |
This is intentionaly made static. Users can ask to save a LOT of messages |
910 |
at once and this program can do that within one second. Dan's assumption |
911 |
that time+pid+hostname always will be unique stops being true in this |
912 |
case. So we will add yet another number to host part of message file's |
913 |
name. Hostname is used only to make filename unique and Dan explicitly |
914 |
says that "<...> Other than this [skipping filenames starting at dot] , |
915 |
readers should not attempt to parse filenames. <...>". Therefore this |
916 |
addition should be no problem. Am I right, Dan? --AK |
917 |
*/ |
918 |
|
919 |
static unsigned int transact = 0; |
920 |
|
921 |
if (flags) /* get flags if given */ |
922 |
uf = maildir_getflags (user_flags (&maildirproto),flags); |
923 |
|
924 |
/* if (date) { want to preserve date? |
925 |
//syslog(LOG_INFO, "date: '%s'", date); |
926 |
// yes, parse date into an elt |
927 |
if (!mail_parse_date (&elt,date)) { |
928 |
sprintf (tmp,"Bad date in append: %s",date); |
929 |
mm_log (tmp,ERROR); |
930 |
return NIL; |
931 |
} |
932 |
} */ |
933 |
/* N.B.: can't use LOCAL->buf for tmp */ |
934 |
/* make sure valid mailbox */ |
935 |
if (!maildir_isvalid (mailbox, NIL)) { |
936 |
sprintf (tmp,"Not a valid Maildir mailbox: %s",mailbox); |
937 |
mm_log (tmp,ERROR); |
938 |
return NIL; |
939 |
} |
940 |
/* build file name we will use */ |
941 |
sprintf (file,"%u.%d.%09u.%s:3,%s%s%s%s", |
942 |
time (0),getpid (),transact++,mylocalhost (), |
943 |
uf&fFLAGGED ? "F" : "",uf&fANSWERED ? "R" : "", |
944 |
uf&fSEEN ? "S" : "",uf&fDELETED ? "T" : ""); |
945 |
/* build tmp file name */ |
946 |
sprintf (path1,"%s/../tmp/%s",maildir_file (tmp,mailbox),file); |
947 |
|
948 |
if ((fd = open (path1,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) < 0) { |
949 |
sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); |
950 |
mm_log (tmp,ERROR); |
951 |
return NIL; |
952 |
} |
953 |
i = SIZE (message); /* get size of message */ |
954 |
s = (char *) fs_get (i + 1); /* get space for the data */ |
955 |
/* copy the data w/o CR's */ |
956 |
while (i--) if ((c = SNX (message)) != '\015') s[size++] = c; |
957 |
mm_critical (stream); /* go critical */ |
958 |
/* write the data */ |
959 |
if ((write (fd,s,size) < 0) || fsync (fd)) { |
960 |
unlink (path1); /* delete message */ |
961 |
sprintf (tmp,"Message append failed: %s",strerror (errno)); |
962 |
mm_log (tmp,ERROR); |
963 |
ret = NIL; |
964 |
} |
965 |
/* build final filename to use */ |
966 |
sprintf (path2,"%s/../new/%s",maildir_file (tmp,mailbox),file); |
967 |
if (link (path1,path2) < 0) { |
968 |
sprintf (tmp,"Message append failed: %s",strerror (errno)); |
969 |
mm_log (tmp,ERROR); |
970 |
ret = NIL; |
971 |
} |
972 |
unlink (path1); |
973 |
|
974 |
close (fd); /* close the file */ |
975 |
mm_nocritical (stream); /* release critical */ |
976 |
fs_give ((void **) &s); /* flush the buffer */ |
977 |
return ret; |
978 |
} |
979 |
|
980 |
short bezerk_getflags (MAILSTREAM *stream,char *flag) |
981 |
{ |
982 |
char *t,tmp[MAILTMPLEN],err[MAILTMPLEN]; |
983 |
short f = 0; |
984 |
short i,j; |
985 |
if (flag && *flag) { /* no-op if no flag string */ |
986 |
/* check if a list and make sure valid */ |
987 |
if ((i = (*flag == '(')) ^ (flag[strlen (flag)-1] == ')')) { |
988 |
mm_log ("Bad flag list",ERROR); |
989 |
return NIL; |
990 |
} |
991 |
/* copy the flag string w/o list construct */ |
992 |
strncpy (tmp,flag+i,(j = strlen (flag) - (2*i))); |
993 |
tmp[j] = '\0'; |
994 |
t = ucase (tmp); /* uppercase only from now on */ |
995 |
|
996 |
while (t && *t) { /* parse the flags */ |
997 |
if (*t == '\\') { /* system flag? */ |
998 |
switch (*++t) { /* dispatch based on first character */ |
999 |
case 'S': /* possible \Seen flag */ |
1000 |
if (t[1] == 'E' && t[2] == 'E' && t[3] == 'N') i = fSEEN; |
1001 |
t += 4; /* skip past flag name */ |
1002 |
break; |
1003 |
case 'D': /* possible \Deleted flag */ |
1004 |
if (t[1] == 'E' && t[2] == 'L' && t[3] == 'E' && t[4] == 'T' && |
1005 |
t[5] == 'E' && t[6] == 'D') i = fDELETED; |
1006 |
t += 7; /* skip past flag name */ |
1007 |
break; |
1008 |
case 'F': /* possible \Flagged flag */ |
1009 |
if (t[1] == 'L' && t[2] == 'A' && t[3] == 'G' && t[4] == 'G' && |
1010 |
t[5] == 'E' && t[6] == 'D') i = fFLAGGED; |
1011 |
t += 7; /* skip past flag name */ |
1012 |
break; |
1013 |
case 'A': /* possible \Answered flag */ |
1014 |
if (t[1] == 'N' && t[2] == 'S' && t[3] == 'W' && t[4] == 'E' && |
1015 |
t[5] == 'R' && t[6] == 'E' && t[7] == 'D') i = fANSWERED; |
1016 |
t += 8; /* skip past flag name */ |
1017 |
break; |
1018 |
default: /* unknown */ |
1019 |
i = 0; |
1020 |
break; |
1021 |
} |
1022 |
/* add flag to flags list */ |
1023 |
if (i && ((*t == '\0') || (*t++ == ' '))) f |= i; |
1024 |
} |
1025 |
else { /* no user flags yet */ |
1026 |
t = strtok (t," "); /* isolate flag name */ |
1027 |
sprintf (err,"Unknown flag: %.80s",t); |
1028 |
t = strtok (NIL," "); /* get next flag */ |
1029 |
mm_log (err,ERROR); |
1030 |
} |
1031 |
} |
1032 |
} |
1033 |
return f; |
1034 |
} |
1035 |
|
1036 |
short maildir_getflags (MAILSTREAM *stream,char *flag) |
1037 |
{ |
1038 |
return bezerk_getflags (stream,flag); /* nothing exciting, reuse old code */ |
1039 |
} |
1040 |
|
1041 |
long maildir_delete (MAILSTREAM *stream,char *mailbox) |
1042 |
{ |
1043 |
DIR *dirp; |
1044 |
struct direct *d; |
1045 |
int i,j; |
1046 |
char tmp[MAILTMPLEN],err[MAILTMPLEN]; |
1047 |
char *subdir_names[] = {"cur/","new/","tmp/",NULL}; |
1048 |
|
1049 |
/* check if mailbox even exists */ |
1050 |
if (!maildir_isvalid (mailbox,NIL)) { |
1051 |
/* sprintf (tmp,"Can't delete mailbox %s: no such mailbox",mailbox); |
1052 |
mm_log (tmp,ERROR); |
1053 |
return NIL; */ |
1054 |
/*syslog(LOG_INFO, "Invalid maildir in delete()"); */ |
1055 |
return T; /* well.. a stupid hack to get by a problem in netscape .. |
1056 |
it remembers folders locally, and if a folder is deleted on |
1057 |
another machine, you have no way removing it on any other |
1058 |
netscapes... */ |
1059 |
} |
1060 |
|
1061 |
/* get name of directory */ |
1062 |
i = strlen (maildir_file (tmp,mailbox)) + 1; |
1063 |
for (j = 0; subdir_names[j]; j++) { |
1064 |
strcpy (tmp + i - 4,subdir_names[j]); |
1065 |
if (dirp = opendir (tmp)) { /* open directory */ |
1066 |
while (d = readdir (dirp)) /* empty the directory */ |
1067 |
if (strcmp (d->d_name,".") && strcmp (d->d_name,"..")) { |
1068 |
strcpy (tmp + i,d->d_name); |
1069 |
/*syslog(LOG_INFO, "unlink1: '%s'");*/ |
1070 |
unlink (tmp); |
1071 |
} |
1072 |
closedir (dirp); /* flush directory */ |
1073 |
} |
1074 |
/* remove the subdir */ |
1075 |
tmp[i + 3] = '\0'; |
1076 |
/*syslog(LOG_INFO, "tmp: '%s'", tmp);*/ |
1077 |
if (rmdir (tmp)) { |
1078 |
/* sprintf (err,"Can't delete directory %s: %s",tmp,strerror (errno)); |
1079 |
mm_log (err,ERROR);*/ |
1080 |
} |
1081 |
} |
1082 |
|
1083 |
/* try to remove the directory */ |
1084 |
*(tmp + i - 5) = '\0'; |
1085 |
/*syslog(LOG_INFO, "tmp2: '%s'", tmp);*/ |
1086 |
if (rmdir (tmp)) { |
1087 |
/* sprintf (err,"Can't delete mailbox %s: %s",mailbox,strerror (errno)); |
1088 |
mm_log (err,ERROR); |
1089 |
return NIL; */ |
1090 |
} |
1091 |
return T; /* return success */ |
1092 |
} |
1093 |
|
1094 |
long maildir_rename (MAILSTREAM *stream,char *old,char *new) |
1095 |
{ |
1096 |
char tmp[MAILTMPLEN],tmpnew[MAILTMPLEN]; |
1097 |
|
1098 |
/* old mailbox name must be valid */ |
1099 |
if (!maildir_isvalid (old,NIL)) { |
1100 |
sprintf (tmp,"Can't rename mailbox %s: no such mailbox",old); |
1101 |
mm_log (tmp,ERROR); |
1102 |
return NIL; |
1103 |
} |
1104 |
|
1105 |
/* new mailbox name must not exist */ |
1106 |
if (access (maildir_file (tmp,new),F_OK) == 0) { |
1107 |
sprintf (tmp,"Can't rename to mailbox %s: destination already exists",new); |
1108 |
mm_log (tmp,ERROR); |
1109 |
return NIL; |
1110 |
} |
1111 |
|
1112 |
/* try to rename the directory */ |
1113 |
if (rename (maildir_file (tmp,old),maildir_file (tmpnew,new))) { |
1114 |
sprintf (tmp,"Can't rename mailbox %s to %s: %s",old,new,strerror (errno)); |
1115 |
mm_log (tmp,ERROR); |
1116 |
return NIL; |
1117 |
} |
1118 |
return T; /* return success */ |
1119 |
} |
1120 |
|
1121 |
long maildir_sub (MAILSTREAM *stream,char *mailbox) |
1122 |
{ |
1123 |
char tmp[MAILTMPLEN]; |
1124 |
return sm_subscribe (mailbox); |
1125 |
} |
1126 |
|
1127 |
long maildir_unsub (MAILSTREAM *stream,char *mailbox) |
1128 |
{ |
1129 |
char tmp[MAILTMPLEN]; |
1130 |
return sm_unsubscribe (mailbox); |
1131 |
} |
1132 |
|
1133 |
void maildir_lsub (MAILSTREAM *stream,char *ref,char *pat) |
1134 |
{ |
1135 |
void *sdb = NIL; |
1136 |
char *s; |
1137 |
/* get canonical form of name */ |
1138 |
if ((s = sm_read (&sdb))) { |
1139 |
do if (pmatch_full (s,pat,'/')) mm_lsub (stream,'/',s,NIL); |
1140 |
while (s = sm_read (&sdb)); /* until no more subscriptions */ |
1141 |
} |
1142 |
|
1143 |
} |