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 - 2017 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
, unsigned long uid
);
53 static FILE * clean(struct mailbox
*mp
, struct cw
*cw
);
54 static unsigned long * 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=MESSAGEFILE 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
= salloc(resz
= strlen(mp
->mb_cache_directory
) + strlen(ename
) + 2);
102 snprintf(res
, resz
, "%s%s%s", mp
->mb_cache_directory
,
103 (*ename
? "/" : ""), ename
);
107 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
108 (cachedir
= fexpand(cachedir
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
)
110 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
112 if (box
!= NULL
|| asccasecmp(box
= mp
->mb_imap_mailbox
, "INBOX")) {
115 box
= imap_path_encode(box
, &err
);
118 box
= urlxenc(box
, TRU1
);
122 res
= salloc(resz
= strlen(cachedir
) + strlen(eaccount
) +
123 strlen(box
) + strlen(ename
) + 4);
124 snprintf(res
, resz
, "%s/%s/%s%s%s", cachedir
, eaccount
, box
,
125 (*ename
? "/" : ""), ename
);
133 encuid(struct mailbox
*mp
, unsigned long uid
)
138 snprintf(buf
, sizeof buf
, "%lu", uid
);
139 cp
= encname(mp
, buf
, 1, NULL
);
145 getcache1(struct mailbox
*mp
, struct message
*m
, enum needspec need
,
149 long n
= 0, size
= 0, xsize
, xtime
, xlines
= -1, lines
= 0;
150 int lastc
= EOF
, i
, xflag
, inheader
= 1;
157 if (setflags
== 0 && ((mp
->mb_type
!= MB_IMAP
&& mp
->mb_type
!= MB_CACHE
) ||
160 if ((fp
= Fopen(encuid(mp
, m
->m_uid
), "r")) == NULL
)
163 n_file_lock(fileno(fp
), FLT_READ
, 0,0, 0);
164 if (fscanf(fp
, infofmt
, &b
, (unsigned long*)&xsize
, &xflag
,
165 (unsigned long*)&xtime
, &xlines
) < 4)
167 if (need
!= NEED_UNSPEC
) {
170 if (need
== NEED_HEADER
)
174 if (need
== NEED_HEADER
|| need
== NEED_BODY
)
184 if (fseek(fp
, INITSKIP
, SEEK_SET
) < 0)
187 if (fseek(mp
->mb_otf
, 0L, SEEK_END
) < 0) {
191 offset
= ftell(mp
->mb_otf
);
192 while (inheader
&& (n
= zread(zp
, iob
, sizeof iob
)) > 0) {
194 for (i
= 0; i
< n
; i
++) {
195 if (iob
[i
] == '\n') {
202 fwrite(iob
, 1, n
, mp
->mb_otf
);
204 if (n
> 0 && need
== NEED_BODY
) {
205 while ((n
= zread(zp
, iob
, sizeof iob
)) > 0) {
207 for (i
= 0; i
< n
; i
++)
210 fwrite(iob
, 1, n
, mp
->mb_otf
);
214 if (zfree(zp
) < 0 || n
< 0 || ferror(fp
) || ferror(mp
->mb_otf
))
219 m
->m_block
= mailx_blockof(offset
);
220 m
->m_offset
= mailx_offsetof(offset
);
226 m
->m_flag
= xflag
| MNOFROM
;
228 m
->m_flag
|= MHIDDEN
;
231 if (xlines
> 0 && m
->m_xlines
<= 0)
232 m
->m_xlines
= xlines
;
236 if (xflag
== MREAD
&& xlines
> 0)
237 m
->m_flag
|= MFULLYCACHED
;
238 if (need
== NEED_BODY
) {
239 m
->m_content_info
|= CI_HAVE_HEADER
| CI_HAVE_BODY
;
241 m
->m_xlines
= m
->m_lines
;
246 m
->m_content_info
|= CI_HAVE_HEADER
;
260 getcache(struct mailbox
*mp
, struct message
*m
, enum needspec need
)
265 rv
= getcache1(mp
, m
, need
, 0);
271 putcache(struct mailbox
*mp
, struct message
*m
)
273 char iob
[32768], *name
, ob
;
276 long n
, cnt
, oldoffset
, osize
, otime
, olines
= -1;
280 if ((mp
->mb_type
!= MB_IMAP
&& mp
->mb_type
!= MB_CACHE
) || m
->m_uid
== 0 ||
281 m
->m_time
== 0 || (m
->m_flag
& (MTOUCH
|MFULLYCACHED
)) == MFULLYCACHED
)
283 if (m
->m_content_info
& CI_HAVE_BODY
)
285 else if (m
->m_content_info
& CI_HAVE_HEADER
)
287 else if (!(m
->m_content_info
& CI_HAVE_MASK
))
291 if ((oldoffset
= ftell(mp
->mb_itf
)) < 0) /* XXX weird err hdling */
293 if ((obuf
= Fopen(name
= encuid(mp
, m
->m_uid
), "r+")) == NULL
) {
294 if ((obuf
= Fopen(name
, "w")) == NULL
)
296 n_file_lock(fileno(obuf
), FLT_WRITE
, 0,0, 0); /* XXX err hdl */
298 n_file_lock(fileno(obuf
), FLT_READ
, 0,0, 0); /* XXX err hdl */
299 if (fscanf(obuf
, infofmt
, &ob
, (unsigned long*)&osize
, &oflag
,
300 (unsigned long*)&otime
, &olines
) >= 4 && ob
!= '\0' &&
301 (ob
== 'B' || (ob
== 'H' && c
!= 'B'))) {
302 if (m
->m_xlines
<= 0 && olines
> 0)
303 m
->m_xlines
= olines
;
304 if ((c
!= 'N' && (size_t)osize
!= m
->m_xsize
) ||
305 oflag
!= (int)USEBITS(m
->m_flag
) || otime
!= m
->m_time
||
306 (m
->m_xlines
> 0 && olines
!= m
->m_xlines
)) {
309 fprintf(obuf
, infofmt
, ob
, (unsigned long)m
->m_xsize
,
310 USEBITS(m
->m_flag
), (unsigned long)m
->m_time
, m
->m_xlines
);
318 ftruncate(fileno(obuf
), 0);
320 if ((ibuf
= setinput(mp
, m
, NEED_UNSPEC
)) == NULL
) {
326 fseek(obuf
, INITSKIP
, SEEK_SET
);
330 n
= (cnt
> (long)sizeof iob
) ? (long)sizeof iob
: cnt
;
332 if ((size_t)n
!= fread(iob
, 1, n
, ibuf
) ||
333 n
!= (long)zwrite(zp
, iob
, n
)) {
345 fprintf(obuf
, infofmt
, c
, (unsigned long)m
->m_xsize
, USEBITS(m
->m_flag
),
346 (unsigned long)m
->m_time
, m
->m_xlines
);
352 if (c
== 'B' && USEBITS(m
->m_flag
) == MREAD
)
353 m
->m_flag
|= MFULLYCACHED
;
355 if (Fclose(obuf
) != 0) {
356 m
->m_flag
&= ~MFULLYCACHED
;
359 (void)fseek(mp
->mb_itf
, oldoffset
, SEEK_SET
);
365 initcache(struct mailbox
*mp
)
373 if (mp
->mb_cache_directory
!= NULL
)
374 free(mp
->mb_cache_directory
);
375 mp
->mb_cache_directory
= NULL
;
376 if ((name
= encname(mp
, "", 1, NULL
)) == NULL
)
378 mp
->mb_cache_directory
= sstrdup(name
);
379 if ((uvname
= encname(mp
, "UIDVALIDITY", 1, NULL
)) == NULL
)
381 if (cwget(&cw
) == STOP
)
383 if ((uvfp
= Fopen(uvname
, "r+")) == NULL
||
384 (n_file_lock(fileno(uvfp
), FLT_READ
, 0,0, 0), 0) ||
385 fscanf(uvfp
, "%lu", &uv
) != 1 || uv
!= mp
->mb_uidvalidity
) {
386 if ((uvfp
= clean(mp
, &cw
)) == NULL
)
392 n_file_lock(fileno(uvfp
), FLT_WRITE
, 0,0, 0);
393 fprintf(uvfp
, "%lu\n", mp
->mb_uidvalidity
);
394 if (ferror(uvfp
) || Fclose(uvfp
) != 0) {
396 mp
->mb_uidvalidity
= 0;
405 purgecache(struct mailbox
*mp
, struct message
*m
, long mc
)
411 if ((name
= encname(mp
, "", 1, NULL
)) == NULL
)
413 if (cwget(&cw
) == STOP
)
415 purge(mp
, m
, mc
, &cw
, name
);
422 clean(struct mailbox
*mp
, struct cw
*cw
)
424 char *cachedir
, *eaccount
, *buf
;
425 char const *emailbox
;
432 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
433 (cachedir
= fexpand(cachedir
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
)
435 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
436 if (asccasecmp(emailbox
= mp
->mb_imap_mailbox
, "INBOX")) {
439 emailbox
= imap_path_encode(emailbox
, &err
);
442 emailbox
= urlxenc(emailbox
, TRU1
);
444 buf
= salloc(bufsz
= strlen(cachedir
) + strlen(eaccount
) +
445 strlen(emailbox
) + 40);
446 if (!n_path_mkdir(cachedir
))
448 snprintf(buf
, bufsz
, "%s/README", cachedir
);
449 if ((fp
= Fopen(buf
, "wx")) != NULL
) {
457 snprintf(buf
, bufsz
, "%s/%s/%s", cachedir
, eaccount
, emailbox
);
458 if (!n_path_mkdir(buf
))
462 if ((dirp
= opendir(".")) == NULL
)
464 while ((dp
= readdir(dirp
)) != NULL
) {
465 if (dp
->d_name
[0] == '.' && (dp
->d_name
[1] == '\0' ||
466 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0')))
471 fp
= Fopen("UIDVALIDITY", "w");
473 if (cwret(cw
) == STOP
) {
474 n_err(_("Fatal: Cannot change back to current directory.\n"));
482 static unsigned long *
483 builds(long *contentelem
)
485 unsigned long n
, *contents
= NULL
;
486 long contentalloc
= 0;
493 if ((dirp
= opendir(".")) == NULL
)
495 while ((dp
= readdir(dirp
)) != NULL
) {
496 if (dp
->d_name
[0] == '.' && (dp
->d_name
[1] == '\0' ||
497 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0')))
499 n
= strtoul(dp
->d_name
, &x
, 10);
502 if (*contentelem
>= contentalloc
- 1)
503 contents
= srealloc(contents
,
504 (contentalloc
+= 200) * sizeof *contents
);
505 contents
[(*contentelem
)++] = n
;
508 if (*contentelem
> 0) {
509 contents
[*contentelem
] = 0;
510 qsort(contents
, *contentelem
, sizeof *contents
, longlt
);
518 purge(struct mailbox
*mp
, struct message
*m
, long mc
, struct cw
*cw
,
521 unsigned long *contents
;
522 long i
, j
, contentelem
;
528 contents
= builds(&contentelem
);
529 if (contents
!= NULL
) {
531 while (j
< contentelem
) {
532 if (i
< mc
&& m
[i
].m_uid
== contents
[j
]) {
535 } else if (i
< mc
&& m
[i
].m_uid
< contents
[j
])
538 remve(contents
[j
++]);
542 if (cwret(cw
) == STOP
) {
543 n_err(_("Fatal: Cannot change back to current directory.\n"));
551 longlt(const void *a
, const void *b
)
553 union {long l
; int i
;} u
;
556 u
.l
= *(long const*)a
- *(long const*)b
;
557 u
.i
= (u
.l
< 0) ? -1 : ((u
.l
> 0) ? 1 : 0);
563 remve(unsigned long n
)
568 snprintf(buf
, sizeof buf
, "%lu", n
);
574 delcache(struct mailbox
*mp
, struct message
*m
)
579 fn
= encuid(mp
, m
->m_uid
);
580 if (fn
&& unlink(fn
) == 0)
581 m
->m_flag
|= MUNLINKED
;
586 cache_setptr(enum fedit_mode fm
, int transparent
)
589 int i
, omsgCount
= 0;
591 unsigned long *contents
;
593 struct message
*omessage
= NULL
;
599 omsgCount
= msgCount
;
601 if (mb
.mb_cache_directory
!= NULL
) {
602 free(mb
.mb_cache_directory
);
603 mb
.mb_cache_directory
= NULL
;
605 if ((name
= encname(&mb
, "", 1, NULL
)) == NULL
)
607 mb
.mb_cache_directory
= sstrdup(name
);
608 if (cwget(&cw
) == STOP
)
612 contents
= builds(&contentelem
);
613 msgCount
= contentelem
;
614 message
= scalloc(msgCount
+ 1, sizeof *message
);
615 if (cwret(&cw
) == STOP
) {
616 n_err(_("Fatal: Cannot change back to current directory.\n"));
622 for (i
= 0; i
< msgCount
; i
++) {
623 message
[i
].m_uid
= contents
[i
];
624 getcache1(&mb
, &message
[i
], NEED_UNSPEC
, 3);
629 if (contents
!= NULL
)
631 mb
.mb_type
= MB_CACHE
;
632 mb
.mb_perm
= ((n_poption
& n_PO_R_FLAG
) || (fm
& FEDIT_RDONLY
)
635 transflags(omessage
, omsgCount
, 1);
637 if (omessage
!= NULL
)
648 cache_list(struct mailbox
*mp
, const char *base
, int strip
, FILE *fp
)
650 char *name
, *cachedir
, *eaccount
;
653 const char *cp
, *bp
, *sp
;
658 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
659 (cachedir
= fexpand(cachedir
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
)
661 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
662 name
= salloc(namesz
= strlen(cachedir
) + strlen(eaccount
) + 2);
663 snprintf(name
, namesz
, "%s/%s", cachedir
, eaccount
);
664 if ((dirp
= opendir(name
)) == NULL
)
666 while ((dp
= readdir(dirp
)) != NULL
) {
667 if (dp
->d_name
[0] == '.')
669 cp
= sp
= imap_path_decode(urlxdec(dp
->d_name
), NULL
);
670 for (bp
= base
; *bp
&& *bp
== *sp
; bp
++)
674 cp
= strip
? sp
: cp
;
675 fprintf(fp
, "%s\n", *cp
? cp
: "INBOX");
685 cache_remove(const char *name
)
691 int pathsize
, pathend
, n
;
695 if ((dir
= encname(&mb
, "", 0, imap_fileof(name
))) == NULL
)
697 pathend
= strlen(dir
);
698 path
= smalloc(pathsize
= pathend
+ 30);
699 memcpy(path
, dir
, pathend
);
700 path
[pathend
++] = '/';
701 path
[pathend
] = '\0';
702 if ((dirp
= opendir(path
)) == NULL
) {
706 while ((dp
= readdir(dirp
)) != NULL
) {
707 if (dp
->d_name
[0] == '.' && (dp
->d_name
[1] == '\0' ||
708 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0')))
710 n
= strlen(dp
->d_name
) + 1;
711 if (pathend
+ n
> pathsize
)
712 path
= srealloc(path
, pathsize
= pathend
+ n
+ 30);
713 memcpy(path
+ pathend
, dp
->d_name
, n
);
714 if (stat(path
, &st
) < 0 || (st
.st_mode
& S_IFMT
) != S_IFREG
)
716 if (unlink(path
) < 0) {
725 path
[pathend
] = '\0';
726 rmdir(path
); /* no error on failure, might contain submailboxes */
734 cache_rename(const char *old
, const char *new)
736 char *olddir
, *newdir
;
740 if ((olddir
= encname(&mb
, "", 0, imap_fileof(old
))) == NULL
||
741 (newdir
= encname(&mb
, "",0, imap_fileof(new))) == NULL
)
743 if (rename(olddir
, newdir
) < 0) {
753 cached_uidvalidity(struct mailbox
*mp
)
760 if ((uvname
= encname(mp
, "UIDVALIDITY", 1, NULL
)) == NULL
) {
764 if ((uvfp
= Fopen(uvname
, "r")) == NULL
||
765 (n_file_lock(fileno(uvfp
), FLT_READ
, 0,0, 0), 0) ||
766 fscanf(uvfp
, "%lu", &uv
) != 1)
776 cache_queue1(struct mailbox
*mp
, char const *mode
, char **xname
)
782 if ((name
= encname(mp
, "QUEUE", 0, NULL
)) == NULL
)
784 if ((fp
= Fopen(name
, mode
)) != NULL
)
785 n_file_lock(fileno(fp
), FLT_WRITE
, 0,0, 0);
794 cache_queue(struct mailbox
*mp
)
799 fp
= cache_queue1(mp
, "a", NULL
);
801 n_err(_("Cannot queue IMAP command. Retry when online.\n"));
807 cache_dequeue(struct mailbox
*mp
)
810 char *cachedir
, *eaccount
, *buf
, *oldbox
;
816 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
817 (cachedir
= fexpand(cachedir
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
)
819 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
820 buf
= salloc(bufsz
= strlen(cachedir
) + strlen(eaccount
) + 2);
821 snprintf(buf
, bufsz
, "%s/%s", cachedir
, eaccount
);
822 if ((dirp
= opendir(buf
)) == NULL
)
824 oldbox
= mp
->mb_imap_mailbox
;
825 while ((dp
= readdir(dirp
)) != NULL
) {
826 if (dp
->d_name
[0] == '.')
828 /* FIXME MUST BLOCK SIGNALS IN ORDER TO ENSURE PROPER RESTORE!
829 * (but wuuuuh, what a shit!) */
830 mp
->mb_imap_mailbox
= sstrdup(
831 imap_path_decode(urlxdec(dp
->d_name
), NULL
));
833 { char *x
= mp
->mb_imap_mailbox
;
834 mp
->mb_imap_mailbox
= oldbox
;
845 dequeue1(struct mailbox
*mp
)
847 FILE *fp
= NULL
, *uvfp
= NULL
;
848 char *qname
, *uvname
;
855 fp
= cache_queue1(mp
, "r+", &qname
);
856 if (fp
!= NULL
&& fsize(fp
) > 0) {
857 if (imap_select(mp
, &is_size
, &is_count
, mp
->mb_imap_mailbox
, FEDIT_NONE
)
859 n_err(_("Cannot select \"%s\" for dequeuing.\n"), mp
->mb_imap_mailbox
);
862 if ((uvname
= encname(mp
, "UIDVALIDITY", 0, NULL
)) == NULL
||
863 (uvfp
= Fopen(uvname
, "r")) == NULL
||
864 (n_file_lock(fileno(uvfp
), FLT_READ
, 0,0, 0), 0) ||
865 fscanf(uvfp
, "%lu", &uv
) != 1 || uv
!= mp
->mb_uidvalidity
) {
866 n_err(_("Unique identifiers for \"%s\" are out of date. "
867 "Cannot commit IMAP commands.\n"), mp
->mb_imap_mailbox
);
869 n_err(_("Saving IMAP commands to *DEAD*\n"));
870 savedeadletter(fp
, 0);
871 ftruncate(fileno(fp
), 0);
879 printf("Committing IMAP commands for \"%s\"\n", mp
->mb_imap_mailbox
);
880 imap_dequeue(mp
, fp
);
890 #endif /* HAVE_IMAP */