1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
6 * SPDX-License-Identifier: BSD-4-Clause
10 * Gunnar Ritter. All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by Gunnar Ritter
23 * and his contributors.
24 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 #define n_FILE obs_imap_cache
43 #ifndef HAVE_AMALGAMATION
51 static char * encname(struct mailbox
*mp
, const char *name
, int same
,
53 static char * encuid(struct mailbox
*mp
, ui64_t uid
);
54 static FILE * clean(struct mailbox
*mp
, struct cw
*cw
);
55 static ui64_t
* builds(long *contentelem
);
56 static void purge(struct mailbox
*mp
, struct message
*m
, long mc
,
57 struct cw
*cw
, const char *name
);
58 static int longlt(const void *a
, const void *b
);
59 static void remve(unsigned long n
);
60 static FILE * cache_queue1(struct mailbox
*mp
, char const *mode
,
62 static enum okay
dequeue1(struct mailbox
*mp
);
64 static const char infofmt
[] = "%c %lu %d %lu %ld";
67 ((f) & (MSAVED|MDELETED|MREAD|MBOXED|MNEW|MFLAGGED|MANSWERED|MDRAFTED))
69 static const char README1
[] = "\
70 This is a cache directory maintained by " VAL_UAGENT
"(1).\n\
71 You should not change any files within.\n\
72 Nevertheless, the structure is as follows: Each subdirectory of the\n\
73 current directory represents an IMAP account, and each subdirectory\n\
74 below that represents a mailbox. Each mailbox directory contains a file\n\
75 named UIDVALIDITY which describes the validity in relation to the version\n\
76 on the server. Other files have names corresponding to their IMAP UID.\n";
77 static const char README2
[] = "\n\
78 The first 128 bytes of these files are used to store message attributes; the\n\
79 following data is equivalent to compress(1) output. So if you have to save a\n\
80 message by hand because of an emergency, throw away the first 128 bytes and\n\
81 decompress the rest, as e.g. \"dd if=FILE skip=1 bs=128 | zcat\" does.\n";
82 static const char README3
[] = "\n\
83 Files named QUEUE contain data that will be sent do the IMAP server next\n\
84 time a connection is made in online mode.\n";
85 static const char README4
[] = "\n\
86 You can safely delete any file or directory here, unless it contains a QUEUE\n\
87 file that is not empty; " VAL_UAGENT
88 " will download the data again and will also\n\
89 write new cache entries if configured in this way. If you do not wish to use\n\
90 the cache anymore, delete the entire directory and unset the *imap-cache*\n\
91 variable in " VAL_UAGENT
"(1).\n";
94 encname(struct mailbox
*mp
, const char *name
, int same
, const char *box
)
96 char *cachedir
, *eaccount
, *ename
, *res
;
100 ename
= urlxenc(name
, TRU1
);
101 if (mp
->mb_cache_directory
&& same
&& box
== NULL
) {
102 res
= n_autorec_alloc(resz
= strlen(mp
->mb_cache_directory
) +
104 snprintf(res
, resz
, "%s%s%s", mp
->mb_cache_directory
,
105 (*ename
? "/" : ""), ename
);
109 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
110 (cachedir
= fexpand(cachedir
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
)
112 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
114 if (box
!= NULL
|| asccasecmp(box
= mp
->mb_imap_mailbox
, "INBOX")) {
117 box
= imap_path_encode(box
, &err
);
120 box
= urlxenc(box
, TRU1
);
124 res
= n_autorec_alloc(resz
= strlen(cachedir
) + strlen(eaccount
) +
125 strlen(box
) + strlen(ename
) + 4);
126 snprintf(res
, resz
, "%s/%s/%s%s%s", cachedir
, eaccount
, box
,
127 (*ename
? "/" : ""), ename
);
135 encuid(struct mailbox
*mp
, ui64_t uid
)
140 snprintf(buf
, sizeof buf
, "%" PRIu64
, uid
);
141 cp
= encname(mp
, buf
, 1, NULL
);
147 getcache1(struct mailbox
*mp
, struct message
*m
, enum needspec need
,
151 long n
= 0, size
= 0, xsize
, xtime
, xlines
= -1, lines
= 0;
152 int lastc
= EOF
, i
, xflag
, inheader
= 1;
159 if (setflags
== 0 && ((mp
->mb_type
!= MB_IMAP
&& mp
->mb_type
!= MB_CACHE
) ||
162 if ((fp
= Fopen(encuid(mp
, m
->m_uid
), "r")) == NULL
)
165 n_file_lock(fileno(fp
), FLT_READ
, 0,0, 0);
166 if (fscanf(fp
, infofmt
, &b
, (unsigned long*)&xsize
, &xflag
,
167 (unsigned long*)&xtime
, &xlines
) < 4)
169 if (need
!= NEED_UNSPEC
) {
172 if (need
== NEED_HEADER
)
176 if (need
== NEED_HEADER
|| need
== NEED_BODY
)
186 if (fseek(fp
, INITSKIP
, SEEK_SET
) < 0)
189 if (fseek(mp
->mb_otf
, 0L, SEEK_END
) < 0) {
193 offset
= ftell(mp
->mb_otf
);
194 while (inheader
&& (n
= zread(zp
, iob
, sizeof iob
)) > 0) {
196 for (i
= 0; i
< n
; i
++) {
197 if (iob
[i
] == '\n') {
204 fwrite(iob
, 1, n
, mp
->mb_otf
);
206 if (n
> 0 && need
== NEED_BODY
) {
207 while ((n
= zread(zp
, iob
, sizeof iob
)) > 0) {
209 for (i
= 0; i
< n
; i
++)
212 fwrite(iob
, 1, n
, mp
->mb_otf
);
216 if (zfree(zp
) < 0 || n
< 0 || ferror(fp
) || ferror(mp
->mb_otf
))
221 m
->m_block
= mailx_blockof(offset
);
222 m
->m_offset
= mailx_offsetof(offset
);
228 m
->m_flag
= xflag
| MNOFROM
;
230 m
->m_flag
|= MHIDDEN
;
233 if (xlines
> 0 && m
->m_xlines
<= 0)
234 m
->m_xlines
= xlines
;
238 if (xflag
== MREAD
&& xlines
> 0)
239 m
->m_flag
|= MFULLYCACHED
;
240 if (need
== NEED_BODY
) {
241 m
->m_content_info
|= CI_HAVE_HEADER
| CI_HAVE_BODY
;
243 m
->m_xlines
= m
->m_lines
;
248 m
->m_content_info
|= CI_HAVE_HEADER
;
262 getcache(struct mailbox
*mp
, struct message
*m
, enum needspec need
)
267 rv
= getcache1(mp
, m
, need
, 0);
273 putcache(struct mailbox
*mp
, struct message
*m
)
275 char iob
[32768], *name
, ob
;
278 long n
, cnt
, oldoffset
, osize
, otime
, olines
= -1;
282 if ((mp
->mb_type
!= MB_IMAP
&& mp
->mb_type
!= MB_CACHE
) || m
->m_uid
== 0 ||
283 m
->m_time
== 0 || (m
->m_flag
& (MTOUCH
|MFULLYCACHED
)) == MFULLYCACHED
)
285 if (m
->m_content_info
& CI_HAVE_BODY
)
287 else if (m
->m_content_info
& CI_HAVE_HEADER
)
289 else if (!(m
->m_content_info
& CI_HAVE_MASK
))
293 if ((oldoffset
= ftell(mp
->mb_itf
)) < 0) /* XXX weird err hdling */
295 if ((obuf
= Fopen(name
= encuid(mp
, m
->m_uid
), "r+")) == NULL
) {
296 if ((obuf
= Fopen(name
, "w")) == NULL
)
298 n_file_lock(fileno(obuf
), FLT_WRITE
, 0,0, 0); /* XXX err hdl */
300 n_file_lock(fileno(obuf
), FLT_READ
, 0,0, 0); /* XXX err hdl */
301 if (fscanf(obuf
, infofmt
, &ob
, (unsigned long*)&osize
, &oflag
,
302 (unsigned long*)&otime
, &olines
) >= 4 && ob
!= '\0' &&
303 (ob
== 'B' || (ob
== 'H' && c
!= 'B'))) {
304 if (m
->m_xlines
<= 0 && olines
> 0)
305 m
->m_xlines
= olines
;
306 if ((c
!= 'N' && (size_t)osize
!= m
->m_xsize
) ||
307 oflag
!= (int)USEBITS(m
->m_flag
) || otime
!= m
->m_time
||
308 (m
->m_xlines
> 0 && olines
!= m
->m_xlines
)) {
311 fprintf(obuf
, infofmt
, ob
, (unsigned long)m
->m_xsize
,
312 USEBITS(m
->m_flag
), (unsigned long)m
->m_time
, m
->m_xlines
);
320 ftruncate(fileno(obuf
), 0);
322 if ((ibuf
= setinput(mp
, m
, NEED_UNSPEC
)) == NULL
) {
328 fseek(obuf
, INITSKIP
, SEEK_SET
);
332 n
= (cnt
> (long)sizeof iob
) ? (long)sizeof iob
: cnt
;
334 if ((size_t)n
!= fread(iob
, 1, n
, ibuf
) ||
335 n
!= (long)zwrite(zp
, iob
, n
)) {
347 fprintf(obuf
, infofmt
, c
, (unsigned long)m
->m_xsize
, USEBITS(m
->m_flag
),
348 (unsigned long)m
->m_time
, m
->m_xlines
);
354 if (c
== 'B' && USEBITS(m
->m_flag
) == MREAD
)
355 m
->m_flag
|= MFULLYCACHED
;
357 if (Fclose(obuf
) != 0) {
358 m
->m_flag
&= ~MFULLYCACHED
;
361 (void)fseek(mp
->mb_itf
, oldoffset
, SEEK_SET
);
367 initcache(struct mailbox
*mp
)
375 if (mp
->mb_cache_directory
!= NULL
)
376 n_free(mp
->mb_cache_directory
);
377 mp
->mb_cache_directory
= NULL
;
378 if ((name
= encname(mp
, "", 1, NULL
)) == NULL
)
380 mp
->mb_cache_directory
= sstrdup(name
);
381 if ((uvname
= encname(mp
, "UIDVALIDITY", 1, NULL
)) == NULL
)
383 if (cwget(&cw
) == STOP
)
385 if ((uvfp
= Fopen(uvname
, "r+")) == NULL
||
386 (n_file_lock(fileno(uvfp
), FLT_READ
, 0,0, 0), 0) ||
387 fscanf(uvfp
, "%" PRIu64
, &uv
) != 1 || uv
!= mp
->mb_uidvalidity
) {
388 if ((uvfp
= clean(mp
, &cw
)) == NULL
)
394 n_file_lock(fileno(uvfp
), FLT_WRITE
, 0,0, 0);
395 fprintf(uvfp
, "%" PRIu64
"\n", mp
->mb_uidvalidity
);
396 if (ferror(uvfp
) || Fclose(uvfp
) != 0) {
398 mp
->mb_uidvalidity
= 0;
407 purgecache(struct mailbox
*mp
, struct message
*m
, long mc
)
413 if ((name
= encname(mp
, "", 1, NULL
)) == NULL
)
415 if (cwget(&cw
) == STOP
)
417 purge(mp
, m
, mc
, &cw
, name
);
424 clean(struct mailbox
*mp
, struct cw
*cw
)
426 char *cachedir
, *eaccount
, *buf
;
427 char const *emailbox
;
434 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
435 (cachedir
= fexpand(cachedir
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
)
437 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
438 if (asccasecmp(emailbox
= mp
->mb_imap_mailbox
, "INBOX")) {
441 emailbox
= imap_path_encode(emailbox
, &err
);
444 emailbox
= urlxenc(emailbox
, TRU1
);
446 buf
= n_autorec_alloc(bufsz
= strlen(cachedir
) + strlen(eaccount
) +
447 strlen(emailbox
) + 40);
448 if (!n_path_mkdir(cachedir
))
450 snprintf(buf
, bufsz
, "%s/README", cachedir
);
451 if ((fp
= Fopen(buf
, "wx")) != NULL
) {
459 snprintf(buf
, bufsz
, "%s/%s/%s", cachedir
, eaccount
, emailbox
);
460 if (!n_path_mkdir(buf
))
464 if ((dirp
= opendir(".")) == NULL
)
466 while ((dp
= readdir(dirp
)) != NULL
) {
467 if (dp
->d_name
[0] == '.' && (dp
->d_name
[1] == '\0' ||
468 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0')))
473 fp
= Fopen("UIDVALIDITY", "w");
475 if (cwret(cw
) == STOP
) {
476 n_err(_("Fatal: Cannot change back to current directory.\n"));
485 builds(long *contentelem
)
487 ui64_t n
, *contents
= NULL
;
488 long contentalloc
= 0;
495 if ((dirp
= opendir(".")) == NULL
)
497 while ((dp
= readdir(dirp
)) != NULL
) {
498 if (dp
->d_name
[0] == '.' && (dp
->d_name
[1] == '\0' ||
499 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0')))
502 n_idec_ui64_cp(&n
, dp
->d_name
, 10, &x
);/* TODO errors? */
505 if (*contentelem
>= contentalloc
- 1)
506 contents
= n_realloc(contents
,
507 (contentalloc
+= 200) * sizeof *contents
);
508 contents
[(*contentelem
)++] = n
;
511 if (*contentelem
> 0) {
512 contents
[*contentelem
] = 0;
513 qsort(contents
, *contentelem
, sizeof *contents
, longlt
);
521 purge(struct mailbox
*mp
, struct message
*m
, long mc
, struct cw
*cw
,
525 long i
, j
, contentelem
;
531 contents
= builds(&contentelem
);
532 if (contents
!= NULL
) {
534 while (j
< contentelem
) {
535 if (i
< mc
&& m
[i
].m_uid
== contents
[j
]) {
538 } else if (i
< mc
&& m
[i
].m_uid
< contents
[j
])
541 remve(contents
[j
++]);
545 if (cwret(cw
) == STOP
) {
546 n_err(_("Fatal: Cannot change back to current directory.\n"));
554 longlt(const void *a
, const void *b
)
556 union {long l
; int i
;} u
;
559 u
.l
= *(long const*)a
- *(long const*)b
;
560 u
.i
= (u
.l
< 0) ? -1 : ((u
.l
> 0) ? 1 : 0);
566 remve(unsigned long n
)
571 snprintf(buf
, sizeof buf
, "%lu", n
);
577 delcache(struct mailbox
*mp
, struct message
*m
)
582 fn
= encuid(mp
, m
->m_uid
);
583 if (fn
&& unlink(fn
) == 0)
584 m
->m_flag
|= MUNLINKED
;
589 cache_setptr(enum fedit_mode fm
, int transparent
)
592 int i
, omsgCount
= 0;
596 struct message
*omessage
;
601 omsgCount
= msgCount
;
603 if (mb
.mb_cache_directory
!= NULL
) {
604 n_free(mb
.mb_cache_directory
);
605 mb
.mb_cache_directory
= NULL
;
607 if ((name
= encname(&mb
, "", 1, NULL
)) == NULL
)
609 mb
.mb_cache_directory
= sstrdup(name
);
610 if (cwget(&cw
) == STOP
)
614 contents
= builds(&contentelem
);
615 msgCount
= contentelem
;
616 message
= n_calloc(msgCount
+ 1, sizeof *message
);
617 if (cwret(&cw
) == STOP
) {
618 n_err(_("Fatal: Cannot change back to current directory.\n"));
624 for (i
= 0; i
< msgCount
; i
++) {
625 message
[i
].m_uid
= contents
[i
];
626 getcache1(&mb
, &message
[i
], NEED_UNSPEC
, 3);
631 if (contents
!= NULL
)
633 mb
.mb_type
= MB_CACHE
;
634 mb
.mb_perm
= ((n_poption
& n_PO_R_FLAG
) || (fm
& FEDIT_RDONLY
)
636 if(omessage
!= NULL
){
638 /* This frees the message */
639 transflags(omessage
, omsgCount
, 1);
651 cache_list(struct mailbox
*mp
, const char *base
, int strip
, FILE *fp
)
653 char *name
, *cachedir
, *eaccount
;
656 const char *cp
, *bp
, *sp
;
661 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
662 (cachedir
= fexpand(cachedir
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
)
664 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
665 name
= n_autorec_alloc(namesz
= strlen(cachedir
) + strlen(eaccount
) + 2);
666 snprintf(name
, namesz
, "%s/%s", cachedir
, eaccount
);
667 if ((dirp
= opendir(name
)) == NULL
)
669 while ((dp
= readdir(dirp
)) != NULL
) {
670 if (dp
->d_name
[0] == '.')
672 cp
= sp
= imap_path_decode(urlxdec(dp
->d_name
), NULL
);
673 for (bp
= base
; *bp
&& *bp
== *sp
; bp
++)
677 cp
= strip
? sp
: cp
;
678 fprintf(fp
, "%s\n", *cp
? cp
: "INBOX");
688 cache_remove(const char *name
)
694 int pathsize
, pathend
, n
;
698 if ((dir
= encname(&mb
, "", 0, imap_fileof(name
))) == NULL
)
700 pathend
= strlen(dir
);
701 path
= n_alloc(pathsize
= pathend
+ 30);
702 memcpy(path
, dir
, pathend
);
703 path
[pathend
++] = '/';
704 path
[pathend
] = '\0';
705 if ((dirp
= opendir(path
)) == NULL
) {
709 while ((dp
= readdir(dirp
)) != NULL
) {
710 if (dp
->d_name
[0] == '.' && (dp
->d_name
[1] == '\0' ||
711 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0')))
713 n
= strlen(dp
->d_name
) + 1;
714 if (pathend
+ n
> pathsize
)
715 path
= n_realloc(path
, pathsize
= pathend
+ n
+ 30);
716 memcpy(path
+ pathend
, dp
->d_name
, n
);
717 if (stat(path
, &st
) < 0 || (st
.st_mode
& S_IFMT
) != S_IFREG
)
719 if (unlink(path
) < 0) {
728 path
[pathend
] = '\0';
729 rmdir(path
); /* no error on failure, might contain submailboxes */
737 cache_rename(const char *old
, const char *new)
739 char *olddir
, *newdir
;
743 if ((olddir
= encname(&mb
, "", 0, imap_fileof(old
))) == NULL
||
744 (newdir
= encname(&mb
, "",0, imap_fileof(new))) == NULL
)
746 if (rename(olddir
, newdir
) < 0) {
756 cached_uidvalidity(struct mailbox
*mp
)
763 if ((uvname
= encname(mp
, "UIDVALIDITY", 1, NULL
)) == NULL
) {
767 if ((uvfp
= Fopen(uvname
, "r")) == NULL
||
768 (n_file_lock(fileno(uvfp
), FLT_READ
, 0,0, 0), 0) ||
769 fscanf(uvfp
, "%" PRIu64
, &uv
) != 1)
779 cache_queue1(struct mailbox
*mp
, char const *mode
, char **xname
)
785 if ((name
= encname(mp
, "QUEUE", 0, NULL
)) == NULL
)
787 if ((fp
= Fopen(name
, mode
)) != NULL
)
788 n_file_lock(fileno(fp
), FLT_WRITE
, 0,0, 0);
797 cache_queue(struct mailbox
*mp
)
802 fp
= cache_queue1(mp
, "a", NULL
);
804 n_err(_("Cannot queue IMAP command. Retry when online.\n"));
810 cache_dequeue(struct mailbox
*mp
)
813 char *cachedir
, *eaccount
, *buf
, *oldbox
;
819 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
820 (cachedir
= fexpand(cachedir
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
)
822 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
823 buf
= n_autorec_alloc(bufsz
= strlen(cachedir
) + strlen(eaccount
) + 2);
824 snprintf(buf
, bufsz
, "%s/%s", cachedir
, eaccount
);
825 if ((dirp
= opendir(buf
)) == NULL
)
827 oldbox
= mp
->mb_imap_mailbox
;
828 while ((dp
= readdir(dirp
)) != NULL
) {
829 if (dp
->d_name
[0] == '.')
831 /* FIXME MUST BLOCK SIGNALS IN ORDER TO ENSURE PROPER RESTORE!
832 * (but wuuuuh, what a shit!) */
833 mp
->mb_imap_mailbox
= sstrdup(
834 imap_path_decode(urlxdec(dp
->d_name
), NULL
));
836 { char *x
= mp
->mb_imap_mailbox
;
837 mp
->mb_imap_mailbox
= oldbox
;
848 dequeue1(struct mailbox
*mp
)
850 FILE *fp
= NULL
, *uvfp
= NULL
;
851 char *qname
, *uvname
;
858 fp
= cache_queue1(mp
, "r+", &qname
);
859 if (fp
!= NULL
&& fsize(fp
) > 0) {
860 if (imap_select(mp
, &is_size
, &is_count
, mp
->mb_imap_mailbox
, FEDIT_NONE
)
862 n_err(_("Cannot select \"%s\" for dequeuing.\n"), mp
->mb_imap_mailbox
);
865 if ((uvname
= encname(mp
, "UIDVALIDITY", 0, NULL
)) == NULL
||
866 (uvfp
= Fopen(uvname
, "r")) == NULL
||
867 (n_file_lock(fileno(uvfp
), FLT_READ
, 0,0, 0), 0) ||
868 fscanf(uvfp
, "%" PRIu64
, &uv
) != 1 || uv
!= mp
->mb_uidvalidity
) {
869 n_err(_("Unique identifiers for \"%s\" are out of date. "
870 "Cannot commit IMAP commands.\n"), mp
->mb_imap_mailbox
);
872 n_err(_("Saving IMAP commands to *DEAD*\n"));
873 savedeadletter(fp
, 0);
874 ftruncate(fileno(fp
), 0);
882 printf("Committing IMAP commands for \"%s\"\n", mp
->mb_imap_mailbox
);
883 imap_dequeue(mp
, fp
);
893 #endif /* HAVE_IMAP */