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
= 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
, ui64_t uid
)
138 snprintf(buf
, sizeof buf
, "%" PRIu64
, 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"));
483 builds(long *contentelem
)
485 ui64_t 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')))
500 n_idec_ui64_cp(&n
, dp
->d_name
, 10, &x
);/* TODO errors? */
503 if (*contentelem
>= contentalloc
- 1)
504 contents
= n_realloc(contents
,
505 (contentalloc
+= 200) * sizeof *contents
);
506 contents
[(*contentelem
)++] = n
;
509 if (*contentelem
> 0) {
510 contents
[*contentelem
] = 0;
511 qsort(contents
, *contentelem
, sizeof *contents
, longlt
);
519 purge(struct mailbox
*mp
, struct message
*m
, long mc
, struct cw
*cw
,
523 long i
, j
, contentelem
;
529 contents
= builds(&contentelem
);
530 if (contents
!= NULL
) {
532 while (j
< contentelem
) {
533 if (i
< mc
&& m
[i
].m_uid
== contents
[j
]) {
536 } else if (i
< mc
&& m
[i
].m_uid
< contents
[j
])
539 remve(contents
[j
++]);
543 if (cwret(cw
) == STOP
) {
544 n_err(_("Fatal: Cannot change back to current directory.\n"));
552 longlt(const void *a
, const void *b
)
554 union {long l
; int i
;} u
;
557 u
.l
= *(long const*)a
- *(long const*)b
;
558 u
.i
= (u
.l
< 0) ? -1 : ((u
.l
> 0) ? 1 : 0);
564 remve(unsigned long n
)
569 snprintf(buf
, sizeof buf
, "%lu", n
);
575 delcache(struct mailbox
*mp
, struct message
*m
)
580 fn
= encuid(mp
, m
->m_uid
);
581 if (fn
&& unlink(fn
) == 0)
582 m
->m_flag
|= MUNLINKED
;
587 cache_setptr(enum fedit_mode fm
, int transparent
)
590 int i
, omsgCount
= 0;
594 struct message
*omessage
;
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
)
634 if(omessage
!= NULL
){
636 /* This frees the message */
637 transflags(omessage
, omsgCount
, 1);
649 cache_list(struct mailbox
*mp
, const char *base
, int strip
, FILE *fp
)
651 char *name
, *cachedir
, *eaccount
;
654 const char *cp
, *bp
, *sp
;
659 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
660 (cachedir
= fexpand(cachedir
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
)
662 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
663 name
= salloc(namesz
= strlen(cachedir
) + strlen(eaccount
) + 2);
664 snprintf(name
, namesz
, "%s/%s", cachedir
, eaccount
);
665 if ((dirp
= opendir(name
)) == NULL
)
667 while ((dp
= readdir(dirp
)) != NULL
) {
668 if (dp
->d_name
[0] == '.')
670 cp
= sp
= imap_path_decode(urlxdec(dp
->d_name
), NULL
);
671 for (bp
= base
; *bp
&& *bp
== *sp
; bp
++)
675 cp
= strip
? sp
: cp
;
676 fprintf(fp
, "%s\n", *cp
? cp
: "INBOX");
686 cache_remove(const char *name
)
692 int pathsize
, pathend
, n
;
696 if ((dir
= encname(&mb
, "", 0, imap_fileof(name
))) == NULL
)
698 pathend
= strlen(dir
);
699 path
= smalloc(pathsize
= pathend
+ 30);
700 memcpy(path
, dir
, pathend
);
701 path
[pathend
++] = '/';
702 path
[pathend
] = '\0';
703 if ((dirp
= opendir(path
)) == NULL
) {
707 while ((dp
= readdir(dirp
)) != NULL
) {
708 if (dp
->d_name
[0] == '.' && (dp
->d_name
[1] == '\0' ||
709 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0')))
711 n
= strlen(dp
->d_name
) + 1;
712 if (pathend
+ n
> pathsize
)
713 path
= srealloc(path
, pathsize
= pathend
+ n
+ 30);
714 memcpy(path
+ pathend
, dp
->d_name
, n
);
715 if (stat(path
, &st
) < 0 || (st
.st_mode
& S_IFMT
) != S_IFREG
)
717 if (unlink(path
) < 0) {
726 path
[pathend
] = '\0';
727 rmdir(path
); /* no error on failure, might contain submailboxes */
735 cache_rename(const char *old
, const char *new)
737 char *olddir
, *newdir
;
741 if ((olddir
= encname(&mb
, "", 0, imap_fileof(old
))) == NULL
||
742 (newdir
= encname(&mb
, "",0, imap_fileof(new))) == NULL
)
744 if (rename(olddir
, newdir
) < 0) {
754 cached_uidvalidity(struct mailbox
*mp
)
761 if ((uvname
= encname(mp
, "UIDVALIDITY", 1, NULL
)) == NULL
) {
765 if ((uvfp
= Fopen(uvname
, "r")) == NULL
||
766 (n_file_lock(fileno(uvfp
), FLT_READ
, 0,0, 0), 0) ||
767 fscanf(uvfp
, "%lu", &uv
) != 1)
777 cache_queue1(struct mailbox
*mp
, char const *mode
, char **xname
)
783 if ((name
= encname(mp
, "QUEUE", 0, NULL
)) == NULL
)
785 if ((fp
= Fopen(name
, mode
)) != NULL
)
786 n_file_lock(fileno(fp
), FLT_WRITE
, 0,0, 0);
795 cache_queue(struct mailbox
*mp
)
800 fp
= cache_queue1(mp
, "a", NULL
);
802 n_err(_("Cannot queue IMAP command. Retry when online.\n"));
808 cache_dequeue(struct mailbox
*mp
)
811 char *cachedir
, *eaccount
, *buf
, *oldbox
;
817 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
818 (cachedir
= fexpand(cachedir
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
)
820 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
821 buf
= salloc(bufsz
= strlen(cachedir
) + strlen(eaccount
) + 2);
822 snprintf(buf
, bufsz
, "%s/%s", cachedir
, eaccount
);
823 if ((dirp
= opendir(buf
)) == NULL
)
825 oldbox
= mp
->mb_imap_mailbox
;
826 while ((dp
= readdir(dirp
)) != NULL
) {
827 if (dp
->d_name
[0] == '.')
829 /* FIXME MUST BLOCK SIGNALS IN ORDER TO ENSURE PROPER RESTORE!
830 * (but wuuuuh, what a shit!) */
831 mp
->mb_imap_mailbox
= sstrdup(
832 imap_path_decode(urlxdec(dp
->d_name
), NULL
));
834 { char *x
= mp
->mb_imap_mailbox
;
835 mp
->mb_imap_mailbox
= oldbox
;
846 dequeue1(struct mailbox
*mp
)
848 FILE *fp
= NULL
, *uvfp
= NULL
;
849 char *qname
, *uvname
;
856 fp
= cache_queue1(mp
, "r+", &qname
);
857 if (fp
!= NULL
&& fsize(fp
) > 0) {
858 if (imap_select(mp
, &is_size
, &is_count
, mp
->mb_imap_mailbox
, FEDIT_NONE
)
860 n_err(_("Cannot select \"%s\" for dequeuing.\n"), mp
->mb_imap_mailbox
);
863 if ((uvname
= encname(mp
, "UIDVALIDITY", 0, NULL
)) == NULL
||
864 (uvfp
= Fopen(uvname
, "r")) == NULL
||
865 (n_file_lock(fileno(uvfp
), FLT_READ
, 0,0, 0), 0) ||
866 fscanf(uvfp
, "%lu", &uv
) != 1 || uv
!= mp
->mb_uidvalidity
) {
867 n_err(_("Unique identifiers for \"%s\" are out of date. "
868 "Cannot commit IMAP commands.\n"), mp
->mb_imap_mailbox
);
870 n_err(_("Saving IMAP commands to *DEAD*\n"));
871 savedeadletter(fp
, 0);
872 ftruncate(fileno(fp
), 0);
880 printf("Committing IMAP commands for \"%s\"\n", mp
->mb_imap_mailbox
);
881 imap_dequeue(mp
, fp
);
891 #endif /* HAVE_IMAP */