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>.
9 * Gunnar Ritter. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Gunnar Ritter
22 * and his contributors.
23 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 #define n_FILE obs_imap_cache
42 #ifndef HAVE_AMALGAMATION
50 static char * encname(struct mailbox
*mp
, const char *name
, int same
,
52 static char * encuid(struct mailbox
*mp
, ui64_t uid
);
53 static FILE * clean(struct mailbox
*mp
, struct cw
*cw
);
54 static ui64_t
* builds(long *contentelem
);
55 static void purge(struct mailbox
*mp
, struct message
*m
, long mc
,
56 struct cw
*cw
, const char *name
);
57 static int longlt(const void *a
, const void *b
);
58 static void remve(unsigned long n
);
59 static FILE * cache_queue1(struct mailbox
*mp
, char const *mode
,
61 static enum okay
dequeue1(struct mailbox
*mp
);
63 static const char infofmt
[] = "%c %lu %d %lu %ld";
66 ((f) & (MSAVED|MDELETED|MREAD|MBOXED|MNEW|MFLAGGED|MANSWERED|MDRAFTED))
68 static const char README1
[] = "\
69 This is a cache directory maintained by " VAL_UAGENT
"(1).\n\
70 You should not change any files within.\n\
71 Nevertheless, the structure is as follows: Each subdirectory of the\n\
72 current directory represents an IMAP account, and each subdirectory\n\
73 below that represents a mailbox. Each mailbox directory contains a file\n\
74 named UIDVALIDITY which describes the validity in relation to the version\n\
75 on the server. Other files have names corresponding to their IMAP UID.\n";
76 static const char README2
[] = "\n\
77 The first 128 bytes of these files are used to store message attributes; the\n\
78 following data is equivalent to compress(1) output. So if you have to save a\n\
79 message by hand because of an emergency, throw away the first 128 bytes and\n\
80 decompress the rest, as e.g. \"dd if=FILE skip=1 bs=128 | zcat\" does.\n";
81 static const char README3
[] = "\n\
82 Files named QUEUE contain data that will be sent do the IMAP server next\n\
83 time a connection is made in online mode.\n";
84 static const char README4
[] = "\n\
85 You can safely delete any file or directory here, unless it contains a QUEUE\n\
86 file that is not empty; " VAL_UAGENT
87 " will download the data again and will also\n\
88 write new cache entries if configured in this way. If you do not wish to use\n\
89 the cache anymore, delete the entire directory and unset the *imap-cache*\n\
90 variable in " VAL_UAGENT
"(1).\n";
93 encname(struct mailbox
*mp
, const char *name
, int same
, const char *box
)
95 char *cachedir
, *eaccount
, *ename
, *res
;
99 ename
= urlxenc(name
, TRU1
);
100 if (mp
->mb_cache_directory
&& same
&& box
== NULL
) {
101 res
= n_autorec_alloc(resz
= strlen(mp
->mb_cache_directory
) +
103 snprintf(res
, resz
, "%s%s%s", mp
->mb_cache_directory
,
104 (*ename
? "/" : ""), ename
);
108 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
109 (cachedir
= fexpand(cachedir
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
)
111 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
113 if (box
!= NULL
|| asccasecmp(box
= mp
->mb_imap_mailbox
, "INBOX")) {
116 box
= imap_path_encode(box
, &err
);
119 box
= urlxenc(box
, TRU1
);
123 res
= n_autorec_alloc(resz
= strlen(cachedir
) + strlen(eaccount
) +
124 strlen(box
) + strlen(ename
) + 4);
125 snprintf(res
, resz
, "%s/%s/%s%s%s", cachedir
, eaccount
, box
,
126 (*ename
? "/" : ""), ename
);
134 encuid(struct mailbox
*mp
, ui64_t uid
)
139 snprintf(buf
, sizeof buf
, "%" PRIu64
, uid
);
140 cp
= encname(mp
, buf
, 1, NULL
);
146 getcache1(struct mailbox
*mp
, struct message
*m
, enum needspec need
,
150 long n
= 0, size
= 0, xsize
, xtime
, xlines
= -1, lines
= 0;
151 int lastc
= EOF
, i
, xflag
, inheader
= 1;
158 if (setflags
== 0 && ((mp
->mb_type
!= MB_IMAP
&& mp
->mb_type
!= MB_CACHE
) ||
161 if ((fp
= Fopen(encuid(mp
, m
->m_uid
), "r")) == NULL
)
164 n_file_lock(fileno(fp
), FLT_READ
, 0,0, 0);
165 if (fscanf(fp
, infofmt
, &b
, (unsigned long*)&xsize
, &xflag
,
166 (unsigned long*)&xtime
, &xlines
) < 4)
168 if (need
!= NEED_UNSPEC
) {
171 if (need
== NEED_HEADER
)
175 if (need
== NEED_HEADER
|| need
== NEED_BODY
)
185 if (fseek(fp
, INITSKIP
, SEEK_SET
) < 0)
188 if (fseek(mp
->mb_otf
, 0L, SEEK_END
) < 0) {
192 offset
= ftell(mp
->mb_otf
);
193 while (inheader
&& (n
= zread(zp
, iob
, sizeof iob
)) > 0) {
195 for (i
= 0; i
< n
; i
++) {
196 if (iob
[i
] == '\n') {
203 fwrite(iob
, 1, n
, mp
->mb_otf
);
205 if (n
> 0 && need
== NEED_BODY
) {
206 while ((n
= zread(zp
, iob
, sizeof iob
)) > 0) {
208 for (i
= 0; i
< n
; i
++)
211 fwrite(iob
, 1, n
, mp
->mb_otf
);
215 if (zfree(zp
) < 0 || n
< 0 || ferror(fp
) || ferror(mp
->mb_otf
))
220 m
->m_block
= mailx_blockof(offset
);
221 m
->m_offset
= mailx_offsetof(offset
);
227 m
->m_flag
= xflag
| MNOFROM
;
229 m
->m_flag
|= MHIDDEN
;
232 if (xlines
> 0 && m
->m_xlines
<= 0)
233 m
->m_xlines
= xlines
;
237 if (xflag
== MREAD
&& xlines
> 0)
238 m
->m_flag
|= MFULLYCACHED
;
239 if (need
== NEED_BODY
) {
240 m
->m_content_info
|= CI_HAVE_HEADER
| CI_HAVE_BODY
;
242 m
->m_xlines
= m
->m_lines
;
247 m
->m_content_info
|= CI_HAVE_HEADER
;
261 getcache(struct mailbox
*mp
, struct message
*m
, enum needspec need
)
266 rv
= getcache1(mp
, m
, need
, 0);
272 putcache(struct mailbox
*mp
, struct message
*m
)
274 char iob
[32768], *name
, ob
;
277 long n
, cnt
, oldoffset
, osize
, otime
, olines
= -1;
281 if ((mp
->mb_type
!= MB_IMAP
&& mp
->mb_type
!= MB_CACHE
) || m
->m_uid
== 0 ||
282 m
->m_time
== 0 || (m
->m_flag
& (MTOUCH
|MFULLYCACHED
)) == MFULLYCACHED
)
284 if (m
->m_content_info
& CI_HAVE_BODY
)
286 else if (m
->m_content_info
& CI_HAVE_HEADER
)
288 else if (!(m
->m_content_info
& CI_HAVE_MASK
))
292 if ((oldoffset
= ftell(mp
->mb_itf
)) < 0) /* XXX weird err hdling */
294 if ((obuf
= Fopen(name
= encuid(mp
, m
->m_uid
), "r+")) == NULL
) {
295 if ((obuf
= Fopen(name
, "w")) == NULL
)
297 n_file_lock(fileno(obuf
), FLT_WRITE
, 0,0, 0); /* XXX err hdl */
299 n_file_lock(fileno(obuf
), FLT_READ
, 0,0, 0); /* XXX err hdl */
300 if (fscanf(obuf
, infofmt
, &ob
, (unsigned long*)&osize
, &oflag
,
301 (unsigned long*)&otime
, &olines
) >= 4 && ob
!= '\0' &&
302 (ob
== 'B' || (ob
== 'H' && c
!= 'B'))) {
303 if (m
->m_xlines
<= 0 && olines
> 0)
304 m
->m_xlines
= olines
;
305 if ((c
!= 'N' && (size_t)osize
!= m
->m_xsize
) ||
306 oflag
!= (int)USEBITS(m
->m_flag
) || otime
!= m
->m_time
||
307 (m
->m_xlines
> 0 && olines
!= m
->m_xlines
)) {
310 fprintf(obuf
, infofmt
, ob
, (unsigned long)m
->m_xsize
,
311 USEBITS(m
->m_flag
), (unsigned long)m
->m_time
, m
->m_xlines
);
319 ftruncate(fileno(obuf
), 0);
321 if ((ibuf
= setinput(mp
, m
, NEED_UNSPEC
)) == NULL
) {
327 fseek(obuf
, INITSKIP
, SEEK_SET
);
331 n
= (cnt
> (long)sizeof iob
) ? (long)sizeof iob
: cnt
;
333 if ((size_t)n
!= fread(iob
, 1, n
, ibuf
) ||
334 n
!= (long)zwrite(zp
, iob
, n
)) {
346 fprintf(obuf
, infofmt
, c
, (unsigned long)m
->m_xsize
, USEBITS(m
->m_flag
),
347 (unsigned long)m
->m_time
, m
->m_xlines
);
353 if (c
== 'B' && USEBITS(m
->m_flag
) == MREAD
)
354 m
->m_flag
|= MFULLYCACHED
;
356 if (Fclose(obuf
) != 0) {
357 m
->m_flag
&= ~MFULLYCACHED
;
360 (void)fseek(mp
->mb_itf
, oldoffset
, SEEK_SET
);
366 initcache(struct mailbox
*mp
)
374 if (mp
->mb_cache_directory
!= NULL
)
375 n_free(mp
->mb_cache_directory
);
376 mp
->mb_cache_directory
= NULL
;
377 if ((name
= encname(mp
, "", 1, NULL
)) == NULL
)
379 mp
->mb_cache_directory
= sstrdup(name
);
380 if ((uvname
= encname(mp
, "UIDVALIDITY", 1, NULL
)) == NULL
)
382 if (cwget(&cw
) == STOP
)
384 if ((uvfp
= Fopen(uvname
, "r+")) == NULL
||
385 (n_file_lock(fileno(uvfp
), FLT_READ
, 0,0, 0), 0) ||
386 fscanf(uvfp
, "%" PRIu64
, &uv
) != 1 || uv
!= mp
->mb_uidvalidity
) {
387 if ((uvfp
= clean(mp
, &cw
)) == NULL
)
393 n_file_lock(fileno(uvfp
), FLT_WRITE
, 0,0, 0);
394 fprintf(uvfp
, "%" PRIu64
"\n", mp
->mb_uidvalidity
);
395 if (ferror(uvfp
) || Fclose(uvfp
) != 0) {
397 mp
->mb_uidvalidity
= 0;
406 purgecache(struct mailbox
*mp
, struct message
*m
, long mc
)
412 if ((name
= encname(mp
, "", 1, NULL
)) == NULL
)
414 if (cwget(&cw
) == STOP
)
416 purge(mp
, m
, mc
, &cw
, name
);
423 clean(struct mailbox
*mp
, struct cw
*cw
)
425 char *cachedir
, *eaccount
, *buf
;
426 char const *emailbox
;
433 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
434 (cachedir
= fexpand(cachedir
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
)
436 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
437 if (asccasecmp(emailbox
= mp
->mb_imap_mailbox
, "INBOX")) {
440 emailbox
= imap_path_encode(emailbox
, &err
);
443 emailbox
= urlxenc(emailbox
, TRU1
);
445 buf
= n_autorec_alloc(bufsz
= strlen(cachedir
) + strlen(eaccount
) +
446 strlen(emailbox
) + 40);
447 if (!n_path_mkdir(cachedir
))
449 snprintf(buf
, bufsz
, "%s/README", cachedir
);
450 if ((fp
= Fopen(buf
, "wx")) != NULL
) {
458 snprintf(buf
, bufsz
, "%s/%s/%s", cachedir
, eaccount
, emailbox
);
459 if (!n_path_mkdir(buf
))
463 if ((dirp
= opendir(".")) == NULL
)
465 while ((dp
= readdir(dirp
)) != NULL
) {
466 if (dp
->d_name
[0] == '.' && (dp
->d_name
[1] == '\0' ||
467 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0')))
472 fp
= Fopen("UIDVALIDITY", "w");
474 if (cwret(cw
) == STOP
) {
475 n_err(_("Fatal: Cannot change back to current directory.\n"));
484 builds(long *contentelem
)
486 ui64_t n
, *contents
= NULL
;
487 long contentalloc
= 0;
494 if ((dirp
= opendir(".")) == NULL
)
496 while ((dp
= readdir(dirp
)) != NULL
) {
497 if (dp
->d_name
[0] == '.' && (dp
->d_name
[1] == '\0' ||
498 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0')))
501 n_idec_ui64_cp(&n
, dp
->d_name
, 10, &x
);/* TODO errors? */
504 if (*contentelem
>= contentalloc
- 1)
505 contents
= n_realloc(contents
,
506 (contentalloc
+= 200) * sizeof *contents
);
507 contents
[(*contentelem
)++] = n
;
510 if (*contentelem
> 0) {
511 contents
[*contentelem
] = 0;
512 qsort(contents
, *contentelem
, sizeof *contents
, longlt
);
520 purge(struct mailbox
*mp
, struct message
*m
, long mc
, struct cw
*cw
,
524 long i
, j
, contentelem
;
530 contents
= builds(&contentelem
);
531 if (contents
!= NULL
) {
533 while (j
< contentelem
) {
534 if (i
< mc
&& m
[i
].m_uid
== contents
[j
]) {
537 } else if (i
< mc
&& m
[i
].m_uid
< contents
[j
])
540 remve(contents
[j
++]);
544 if (cwret(cw
) == STOP
) {
545 n_err(_("Fatal: Cannot change back to current directory.\n"));
553 longlt(const void *a
, const void *b
)
555 union {long l
; int i
;} u
;
558 u
.l
= *(long const*)a
- *(long const*)b
;
559 u
.i
= (u
.l
< 0) ? -1 : ((u
.l
> 0) ? 1 : 0);
565 remve(unsigned long n
)
570 snprintf(buf
, sizeof buf
, "%lu", n
);
576 delcache(struct mailbox
*mp
, struct message
*m
)
581 fn
= encuid(mp
, m
->m_uid
);
582 if (fn
&& unlink(fn
) == 0)
583 m
->m_flag
|= MUNLINKED
;
588 cache_setptr(enum fedit_mode fm
, int transparent
)
591 int i
, omsgCount
= 0;
595 struct message
*omessage
;
600 omsgCount
= msgCount
;
602 if (mb
.mb_cache_directory
!= NULL
) {
603 n_free(mb
.mb_cache_directory
);
604 mb
.mb_cache_directory
= NULL
;
606 if ((name
= encname(&mb
, "", 1, NULL
)) == NULL
)
608 mb
.mb_cache_directory
= sstrdup(name
);
609 if (cwget(&cw
) == STOP
)
613 contents
= builds(&contentelem
);
614 msgCount
= contentelem
;
615 message
= n_calloc(msgCount
+ 1, sizeof *message
);
616 if (cwret(&cw
) == STOP
) {
617 n_err(_("Fatal: Cannot change back to current directory.\n"));
623 for (i
= 0; i
< msgCount
; i
++) {
624 message
[i
].m_uid
= contents
[i
];
625 getcache1(&mb
, &message
[i
], NEED_UNSPEC
, 3);
630 if (contents
!= NULL
)
632 mb
.mb_type
= MB_CACHE
;
633 mb
.mb_perm
= ((n_poption
& n_PO_R_FLAG
) || (fm
& FEDIT_RDONLY
)
635 if(omessage
!= NULL
){
637 /* This frees the message */
638 transflags(omessage
, omsgCount
, 1);
650 cache_list(struct mailbox
*mp
, const char *base
, int strip
, FILE *fp
)
652 char *name
, *cachedir
, *eaccount
;
655 const char *cp
, *bp
, *sp
;
660 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
661 (cachedir
= fexpand(cachedir
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
)
663 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
664 name
= n_autorec_alloc(namesz
= strlen(cachedir
) + strlen(eaccount
) + 2);
665 snprintf(name
, namesz
, "%s/%s", cachedir
, eaccount
);
666 if ((dirp
= opendir(name
)) == NULL
)
668 while ((dp
= readdir(dirp
)) != NULL
) {
669 if (dp
->d_name
[0] == '.')
671 cp
= sp
= imap_path_decode(urlxdec(dp
->d_name
), NULL
);
672 for (bp
= base
; *bp
&& *bp
== *sp
; bp
++)
676 cp
= strip
? sp
: cp
;
677 fprintf(fp
, "%s\n", *cp
? cp
: "INBOX");
687 cache_remove(const char *name
)
693 int pathsize
, pathend
, n
;
697 if ((dir
= encname(&mb
, "", 0, imap_fileof(name
))) == NULL
)
699 pathend
= strlen(dir
);
700 path
= n_alloc(pathsize
= pathend
+ 30);
701 memcpy(path
, dir
, pathend
);
702 path
[pathend
++] = '/';
703 path
[pathend
] = '\0';
704 if ((dirp
= opendir(path
)) == NULL
) {
708 while ((dp
= readdir(dirp
)) != NULL
) {
709 if (dp
->d_name
[0] == '.' && (dp
->d_name
[1] == '\0' ||
710 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0')))
712 n
= strlen(dp
->d_name
) + 1;
713 if (pathend
+ n
> pathsize
)
714 path
= n_realloc(path
, pathsize
= pathend
+ n
+ 30);
715 memcpy(path
+ pathend
, dp
->d_name
, n
);
716 if (stat(path
, &st
) < 0 || (st
.st_mode
& S_IFMT
) != S_IFREG
)
718 if (unlink(path
) < 0) {
727 path
[pathend
] = '\0';
728 rmdir(path
); /* no error on failure, might contain submailboxes */
736 cache_rename(const char *old
, const char *new)
738 char *olddir
, *newdir
;
742 if ((olddir
= encname(&mb
, "", 0, imap_fileof(old
))) == NULL
||
743 (newdir
= encname(&mb
, "",0, imap_fileof(new))) == NULL
)
745 if (rename(olddir
, newdir
) < 0) {
755 cached_uidvalidity(struct mailbox
*mp
)
762 if ((uvname
= encname(mp
, "UIDVALIDITY", 1, NULL
)) == NULL
) {
766 if ((uvfp
= Fopen(uvname
, "r")) == NULL
||
767 (n_file_lock(fileno(uvfp
), FLT_READ
, 0,0, 0), 0) ||
768 fscanf(uvfp
, "%" PRIu64
, &uv
) != 1)
778 cache_queue1(struct mailbox
*mp
, char const *mode
, char **xname
)
784 if ((name
= encname(mp
, "QUEUE", 0, NULL
)) == NULL
)
786 if ((fp
= Fopen(name
, mode
)) != NULL
)
787 n_file_lock(fileno(fp
), FLT_WRITE
, 0,0, 0);
796 cache_queue(struct mailbox
*mp
)
801 fp
= cache_queue1(mp
, "a", NULL
);
803 n_err(_("Cannot queue IMAP command. Retry when online.\n"));
809 cache_dequeue(struct mailbox
*mp
)
812 char *cachedir
, *eaccount
, *buf
, *oldbox
;
818 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
819 (cachedir
= fexpand(cachedir
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
)
821 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
822 buf
= n_autorec_alloc(bufsz
= strlen(cachedir
) + strlen(eaccount
) + 2);
823 snprintf(buf
, bufsz
, "%s/%s", cachedir
, eaccount
);
824 if ((dirp
= opendir(buf
)) == NULL
)
826 oldbox
= mp
->mb_imap_mailbox
;
827 while ((dp
= readdir(dirp
)) != NULL
) {
828 if (dp
->d_name
[0] == '.')
830 /* FIXME MUST BLOCK SIGNALS IN ORDER TO ENSURE PROPER RESTORE!
831 * (but wuuuuh, what a shit!) */
832 mp
->mb_imap_mailbox
= sstrdup(
833 imap_path_decode(urlxdec(dp
->d_name
), NULL
));
835 { char *x
= mp
->mb_imap_mailbox
;
836 mp
->mb_imap_mailbox
= oldbox
;
847 dequeue1(struct mailbox
*mp
)
849 FILE *fp
= NULL
, *uvfp
= NULL
;
850 char *qname
, *uvname
;
857 fp
= cache_queue1(mp
, "r+", &qname
);
858 if (fp
!= NULL
&& fsize(fp
) > 0) {
859 if (imap_select(mp
, &is_size
, &is_count
, mp
->mb_imap_mailbox
, FEDIT_NONE
)
861 n_err(_("Cannot select \"%s\" for dequeuing.\n"), mp
->mb_imap_mailbox
);
864 if ((uvname
= encname(mp
, "UIDVALIDITY", 0, NULL
)) == NULL
||
865 (uvfp
= Fopen(uvname
, "r")) == NULL
||
866 (n_file_lock(fileno(uvfp
), FLT_READ
, 0,0, 0), 0) ||
867 fscanf(uvfp
, "%" PRIu64
, &uv
) != 1 || uv
!= mp
->mb_uidvalidity
) {
868 n_err(_("Unique identifiers for \"%s\" are out of date. "
869 "Cannot commit IMAP commands.\n"), mp
->mb_imap_mailbox
);
871 n_err(_("Saving IMAP commands to *DEAD*\n"));
872 savedeadletter(fp
, 0);
873 ftruncate(fileno(fp
), 0);
881 printf("Committing IMAP commands for \"%s\"\n", mp
->mb_imap_mailbox
);
882 imap_dequeue(mp
, fp
);
892 #endif /* HAVE_IMAP */