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 - 2015 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 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 " 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; " UAGENT
" will download the data again and will also\n\
87 write new cache entries if configured in this way. If you do not wish to use\n\
88 the cache anymore, delete the entire directory and unset the *imap-cache*\n\
89 variable in " UAGENT
"(1).\n";
90 static const char README5
[] = "\n\
91 For more information about " UAGENT
"(1), visit\n\
92 <https://www.sdaoden.eu/code.html>.\n"; /* TODO MAGIC CONSTANT */
95 encname(struct mailbox
*mp
, const char *name
, int same
, const char *box
)
97 char *cachedir
, *eaccount
, *ename
, *res
;
101 ename
= urlxenc(name
, TRU1
);
102 if (mp
->mb_cache_directory
&& same
&& box
== NULL
) {
103 res
= salloc(resz
= strlen(mp
->mb_cache_directory
) + strlen(ename
) + 2);
104 snprintf(res
, resz
, "%s%s%s", mp
->mb_cache_directory
,
105 (*ename
? "/" : ""), ename
);
109 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
110 (cachedir
= file_expand(cachedir
)) == 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
= salloc(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
, unsigned long uid
)
140 snprintf(buf
, sizeof buf
, "%lu", 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 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_have
|= HAVE_HEADER
| HAVE_BODY
;
243 m
->m_xlines
= m
->m_lines
;
248 m
->m_have
|= 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_have
& HAVE_BODY
)
287 else if (m
->m_have
& HAVE_HEADER
)
289 else if (m
->m_have
== HAVE_NOTHING
)
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 file_lock(fileno(obuf
), FLT_WRITE
, 0,0, 0); /* XXX err hdl */
300 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 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 (file_lock(fileno(uvfp
), FLT_READ
, 0,0, 0), 0) ||
387 fscanf(uvfp
, "%lu", &uv
) != 1 || uv
!= mp
->mb_uidvalidity
) {
388 if ((uvfp
= clean(mp
, &cw
)) == NULL
)
394 file_lock(fileno(uvfp
), FLT_WRITE
, 0,0, 0);
395 fprintf(uvfp
, "%lu\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
= file_expand(cachedir
)) == 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
= salloc(bufsz
= strlen(cachedir
) + strlen(eaccount
) +
447 strlen(emailbox
) + 40);
448 if (makedir(cachedir
) != OKAY
)
450 snprintf(buf
, bufsz
, "%s/README", cachedir
);
451 if ((fp
= Fopen(buf
, "wx")) != NULL
) {
460 snprintf(buf
, bufsz
, "%s/%s", cachedir
, eaccount
);
461 if (makedir(buf
) != OKAY
)
463 snprintf(buf
, bufsz
, "%s/%s/%s", cachedir
, eaccount
, emailbox
);
464 if (makedir(buf
) != OKAY
)
468 if ((dirp
= opendir(".")) == NULL
)
470 while ((dp
= readdir(dirp
)) != NULL
) {
471 if (dp
->d_name
[0] == '.' && (dp
->d_name
[1] == '\0' ||
472 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0')))
477 fp
= Fopen("UIDVALIDITY", "w");
479 if (cwret(cw
) == STOP
) {
480 n_err(_("Fatal: Cannot change back to current directory.\n"));
488 static unsigned long *
489 builds(long *contentelem
)
491 unsigned long n
, *contents
= NULL
;
492 long contentalloc
= 0;
499 if ((dirp
= opendir(".")) == NULL
)
501 while ((dp
= readdir(dirp
)) != NULL
) {
502 if (dp
->d_name
[0] == '.' && (dp
->d_name
[1] == '\0' ||
503 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0')))
505 n
= strtoul(dp
->d_name
, &x
, 10);
508 if (*contentelem
>= contentalloc
- 1)
509 contents
= srealloc(contents
,
510 (contentalloc
+= 200) * sizeof *contents
);
511 contents
[(*contentelem
)++] = n
;
514 if (*contentelem
> 0) {
515 contents
[*contentelem
] = 0;
516 qsort(contents
, *contentelem
, sizeof *contents
, longlt
);
524 purge(struct mailbox
*mp
, struct message
*m
, long mc
, struct cw
*cw
,
527 unsigned long *contents
;
528 long i
, j
, contentelem
;
534 contents
= builds(&contentelem
);
535 if (contents
!= NULL
) {
537 while (j
< contentelem
) {
538 if (i
< mc
&& m
[i
].m_uid
== contents
[j
]) {
541 } else if (i
< mc
&& m
[i
].m_uid
< contents
[j
])
544 remve(contents
[j
++]);
548 if (cwret(cw
) == STOP
) {
549 n_err(_("Fatal: Cannot change back to current directory.\n"));
557 longlt(const void *a
, const void *b
)
559 union {long l
; int i
;} u
;
562 u
.l
= *(long const*)a
- *(long const*)b
;
563 u
.i
= (u
.l
< 0) ? -1 : ((u
.l
> 0) ? 1 : 0);
569 remve(unsigned long n
)
574 snprintf(buf
, sizeof buf
, "%lu", n
);
580 delcache(struct mailbox
*mp
, struct message
*m
)
585 fn
= encuid(mp
, m
->m_uid
);
586 if (fn
&& unlink(fn
) == 0)
587 m
->m_flag
|= MUNLINKED
;
592 cache_setptr(enum fedit_mode fm
, int transparent
)
595 int i
, omsgCount
= 0;
597 unsigned long *contents
;
599 struct message
*omessage
= NULL
;
605 omsgCount
= msgCount
;
607 if (mb
.mb_cache_directory
!= NULL
) {
608 free(mb
.mb_cache_directory
);
609 mb
.mb_cache_directory
= NULL
;
611 if ((name
= encname(&mb
, "", 1, NULL
)) == NULL
)
613 mb
.mb_cache_directory
= sstrdup(name
);
614 if (cwget(&cw
) == STOP
)
618 contents
= builds(&contentelem
);
619 msgCount
= contentelem
;
620 message
= scalloc(msgCount
+ 1, sizeof *message
);
621 if (cwret(&cw
) == STOP
) {
622 n_err(_("Fatal: Cannot change back to current directory.\n"));
628 for (i
= 0; i
< msgCount
; i
++) {
629 message
[i
].m_uid
= contents
[i
];
630 getcache1(&mb
, &message
[i
], NEED_UNSPEC
, 3);
635 if (contents
!= NULL
)
637 mb
.mb_type
= MB_CACHE
;
638 mb
.mb_perm
= ((options
& OPT_R_FLAG
) || (fm
& FEDIT_RDONLY
)) ? 0 : MB_DELE
;
640 transflags(omessage
, omsgCount
, 1);
642 if (omessage
!= NULL
)
653 cache_list(struct mailbox
*mp
, const char *base
, int strip
, FILE *fp
)
655 char *name
, *cachedir
, *eaccount
;
658 const char *cp
, *bp
, *sp
;
663 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
664 (cachedir
= file_expand(cachedir
)) == NULL
)
666 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
667 name
= salloc(namesz
= strlen(cachedir
) + strlen(eaccount
) + 2);
668 snprintf(name
, namesz
, "%s/%s", cachedir
, eaccount
);
669 if ((dirp
= opendir(name
)) == NULL
)
671 while ((dp
= readdir(dirp
)) != NULL
) {
672 if (dp
->d_name
[0] == '.')
674 cp
= sp
= imap_path_decode(urlxdec(dp
->d_name
), NULL
);
675 for (bp
= base
; *bp
&& *bp
== *sp
; bp
++)
679 cp
= strip
? sp
: cp
;
680 fprintf(fp
, "%s\n", *cp
? cp
: "INBOX");
690 cache_remove(const char *name
)
696 int pathsize
, pathend
, n
;
700 if ((dir
= encname(&mb
, "", 0, imap_fileof(name
))) == NULL
)
702 pathend
= strlen(dir
);
703 path
= smalloc(pathsize
= pathend
+ 30);
704 memcpy(path
, dir
, pathend
);
705 path
[pathend
++] = '/';
706 path
[pathend
] = '\0';
707 if ((dirp
= opendir(path
)) == NULL
) {
711 while ((dp
= readdir(dirp
)) != NULL
) {
712 if (dp
->d_name
[0] == '.' && (dp
->d_name
[1] == '\0' ||
713 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0')))
715 n
= strlen(dp
->d_name
) + 1;
716 if (pathend
+ n
> pathsize
)
717 path
= srealloc(path
, pathsize
= pathend
+ n
+ 30);
718 memcpy(path
+ pathend
, dp
->d_name
, n
);
719 if (stat(path
, &st
) < 0 || (st
.st_mode
& S_IFMT
) != S_IFREG
)
721 if (unlink(path
) < 0) {
730 path
[pathend
] = '\0';
731 rmdir(path
); /* no error on failure, might contain submailboxes */
739 cache_rename(const char *old
, const char *new)
741 char *olddir
, *newdir
;
745 if ((olddir
= encname(&mb
, "", 0, imap_fileof(old
))) == NULL
||
746 (newdir
= encname(&mb
, "",0, imap_fileof(new))) == NULL
)
748 if (rename(olddir
, newdir
) < 0) {
758 cached_uidvalidity(struct mailbox
*mp
)
765 if ((uvname
= encname(mp
, "UIDVALIDITY", 1, NULL
)) == NULL
) {
769 if ((uvfp
= Fopen(uvname
, "r")) == NULL
||
770 (file_lock(fileno(uvfp
), FLT_READ
, 0,0, 0), 0) ||
771 fscanf(uvfp
, "%lu", &uv
) != 1)
781 cache_queue1(struct mailbox
*mp
, char const *mode
, char **xname
)
787 if ((name
= encname(mp
, "QUEUE", 0, NULL
)) == NULL
)
789 if ((fp
= Fopen(name
, mode
)) != NULL
)
790 file_lock(fileno(fp
), FLT_WRITE
, 0,0, 0);
799 cache_queue(struct mailbox
*mp
)
804 fp
= cache_queue1(mp
, "a", NULL
);
806 n_err(_("Cannot queue IMAP command. Retry when online.\n"));
812 cache_dequeue(struct mailbox
*mp
)
815 char *cachedir
, *eaccount
, *buf
, *oldbox
;
821 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
822 (cachedir
= file_expand(cachedir
)) == NULL
)
824 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
825 buf
= salloc(bufsz
= strlen(cachedir
) + strlen(eaccount
) + 2);
826 snprintf(buf
, bufsz
, "%s/%s", cachedir
, eaccount
);
827 if ((dirp
= opendir(buf
)) == NULL
)
829 oldbox
= mp
->mb_imap_mailbox
;
830 while ((dp
= readdir(dirp
)) != NULL
) {
831 if (dp
->d_name
[0] == '.')
833 /* FIXME MUST BLOCK SIGNALS IN ORDER TO ENSURE PROPER RESTORE!
834 * (but wuuuuh, what a shit!) */
835 mp
->mb_imap_mailbox
= sstrdup(
836 imap_path_decode(urlxdec(dp
->d_name
), NULL
));
838 { char *x
= mp
->mb_imap_mailbox
;
839 mp
->mb_imap_mailbox
= oldbox
;
850 dequeue1(struct mailbox
*mp
)
852 FILE *fp
= NULL
, *uvfp
= NULL
;
853 char *qname
, *uvname
;
860 fp
= cache_queue1(mp
, "r+", &qname
);
861 if (fp
!= NULL
&& fsize(fp
) > 0) {
862 if (imap_select(mp
, &is_size
, &is_count
, mp
->mb_imap_mailbox
, FEDIT_NONE
)
864 n_err(_("Cannot select \"%s\" for dequeuing.\n"), mp
->mb_imap_mailbox
);
867 if ((uvname
= encname(mp
, "UIDVALIDITY", 0, NULL
)) == NULL
||
868 (uvfp
= Fopen(uvname
, "r")) == NULL
||
869 (file_lock(fileno(uvfp
), FLT_READ
, 0,0, 0), 0) ||
870 fscanf(uvfp
, "%lu", &uv
) != 1 || uv
!= mp
->mb_uidvalidity
) {
871 n_err(_("Unique identifiers for \"%s\" are out of date. "
872 "Cannot commit IMAP commands.\n"), mp
->mb_imap_mailbox
);
874 n_err(_("Saving IMAP commands to *DEAD*\n"));
875 savedeadletter(fp
, 0);
876 ftruncate(fileno(fp
), 0);
884 printf("Committing IMAP commands for \"%s\"\n", mp
->mb_imap_mailbox
);
885 imap_dequeue(mp
, fp
);
895 #endif /* HAVE_IMAP */