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
, 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=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
, 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
;
598 omsgCount
= msgCount
;
600 if (mb
.mb_cache_directory
!= NULL
) {
601 free(mb
.mb_cache_directory
);
602 mb
.mb_cache_directory
= NULL
;
604 if ((name
= encname(&mb
, "", 1, NULL
)) == NULL
)
606 mb
.mb_cache_directory
= sstrdup(name
);
607 if (cwget(&cw
) == STOP
)
611 contents
= builds(&contentelem
);
612 msgCount
= contentelem
;
613 message
= scalloc(msgCount
+ 1, sizeof *message
);
614 if (cwret(&cw
) == STOP
) {
615 n_err(_("Fatal: Cannot change back to current directory.\n"));
621 for (i
= 0; i
< msgCount
; i
++) {
622 message
[i
].m_uid
= contents
[i
];
623 getcache1(&mb
, &message
[i
], NEED_UNSPEC
, 3);
628 if (contents
!= NULL
)
630 mb
.mb_type
= MB_CACHE
;
631 mb
.mb_perm
= ((n_poption
& n_PO_R_FLAG
) || (fm
& FEDIT_RDONLY
)
633 if (transparent
&& omessage
!= NULL
)
634 transflags(omessage
, omsgCount
, 1);
635 if (omessage
!= NULL
)
645 cache_list(struct mailbox
*mp
, const char *base
, int strip
, FILE *fp
)
647 char *name
, *cachedir
, *eaccount
;
650 const char *cp
, *bp
, *sp
;
655 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
656 (cachedir
= fexpand(cachedir
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
)
658 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
659 name
= salloc(namesz
= strlen(cachedir
) + strlen(eaccount
) + 2);
660 snprintf(name
, namesz
, "%s/%s", cachedir
, eaccount
);
661 if ((dirp
= opendir(name
)) == NULL
)
663 while ((dp
= readdir(dirp
)) != NULL
) {
664 if (dp
->d_name
[0] == '.')
666 cp
= sp
= imap_path_decode(urlxdec(dp
->d_name
), NULL
);
667 for (bp
= base
; *bp
&& *bp
== *sp
; bp
++)
671 cp
= strip
? sp
: cp
;
672 fprintf(fp
, "%s\n", *cp
? cp
: "INBOX");
682 cache_remove(const char *name
)
688 int pathsize
, pathend
, n
;
692 if ((dir
= encname(&mb
, "", 0, imap_fileof(name
))) == NULL
)
694 pathend
= strlen(dir
);
695 path
= smalloc(pathsize
= pathend
+ 30);
696 memcpy(path
, dir
, pathend
);
697 path
[pathend
++] = '/';
698 path
[pathend
] = '\0';
699 if ((dirp
= opendir(path
)) == NULL
) {
703 while ((dp
= readdir(dirp
)) != NULL
) {
704 if (dp
->d_name
[0] == '.' && (dp
->d_name
[1] == '\0' ||
705 (dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0')))
707 n
= strlen(dp
->d_name
) + 1;
708 if (pathend
+ n
> pathsize
)
709 path
= srealloc(path
, pathsize
= pathend
+ n
+ 30);
710 memcpy(path
+ pathend
, dp
->d_name
, n
);
711 if (stat(path
, &st
) < 0 || (st
.st_mode
& S_IFMT
) != S_IFREG
)
713 if (unlink(path
) < 0) {
722 path
[pathend
] = '\0';
723 rmdir(path
); /* no error on failure, might contain submailboxes */
731 cache_rename(const char *old
, const char *new)
733 char *olddir
, *newdir
;
737 if ((olddir
= encname(&mb
, "", 0, imap_fileof(old
))) == NULL
||
738 (newdir
= encname(&mb
, "",0, imap_fileof(new))) == NULL
)
740 if (rename(olddir
, newdir
) < 0) {
750 cached_uidvalidity(struct mailbox
*mp
)
757 if ((uvname
= encname(mp
, "UIDVALIDITY", 1, NULL
)) == NULL
) {
761 if ((uvfp
= Fopen(uvname
, "r")) == NULL
||
762 (n_file_lock(fileno(uvfp
), FLT_READ
, 0,0, 0), 0) ||
763 fscanf(uvfp
, "%lu", &uv
) != 1)
773 cache_queue1(struct mailbox
*mp
, char const *mode
, char **xname
)
779 if ((name
= encname(mp
, "QUEUE", 0, NULL
)) == NULL
)
781 if ((fp
= Fopen(name
, mode
)) != NULL
)
782 n_file_lock(fileno(fp
), FLT_WRITE
, 0,0, 0);
791 cache_queue(struct mailbox
*mp
)
796 fp
= cache_queue1(mp
, "a", NULL
);
798 n_err(_("Cannot queue IMAP command. Retry when online.\n"));
804 cache_dequeue(struct mailbox
*mp
)
807 char *cachedir
, *eaccount
, *buf
, *oldbox
;
813 if ((cachedir
= ok_vlook(imap_cache
)) == NULL
||
814 (cachedir
= fexpand(cachedir
, FEXP_LOCAL
| FEXP_NOPROTO
)) == NULL
)
816 eaccount
= urlxenc(mp
->mb_imap_account
, TRU1
);
817 buf
= salloc(bufsz
= strlen(cachedir
) + strlen(eaccount
) + 2);
818 snprintf(buf
, bufsz
, "%s/%s", cachedir
, eaccount
);
819 if ((dirp
= opendir(buf
)) == NULL
)
821 oldbox
= mp
->mb_imap_mailbox
;
822 while ((dp
= readdir(dirp
)) != NULL
) {
823 if (dp
->d_name
[0] == '.')
825 /* FIXME MUST BLOCK SIGNALS IN ORDER TO ENSURE PROPER RESTORE!
826 * (but wuuuuh, what a shit!) */
827 mp
->mb_imap_mailbox
= sstrdup(
828 imap_path_decode(urlxdec(dp
->d_name
), NULL
));
830 { char *x
= mp
->mb_imap_mailbox
;
831 mp
->mb_imap_mailbox
= oldbox
;
842 dequeue1(struct mailbox
*mp
)
844 FILE *fp
= NULL
, *uvfp
= NULL
;
845 char *qname
, *uvname
;
852 fp
= cache_queue1(mp
, "r+", &qname
);
853 if (fp
!= NULL
&& fsize(fp
) > 0) {
854 if (imap_select(mp
, &is_size
, &is_count
, mp
->mb_imap_mailbox
, FEDIT_NONE
)
856 n_err(_("Cannot select \"%s\" for dequeuing.\n"), mp
->mb_imap_mailbox
);
859 if ((uvname
= encname(mp
, "UIDVALIDITY", 0, NULL
)) == NULL
||
860 (uvfp
= Fopen(uvname
, "r")) == NULL
||
861 (n_file_lock(fileno(uvfp
), FLT_READ
, 0,0, 0), 0) ||
862 fscanf(uvfp
, "%lu", &uv
) != 1 || uv
!= mp
->mb_uidvalidity
) {
863 n_err(_("Unique identifiers for \"%s\" are out of date. "
864 "Cannot commit IMAP commands.\n"), mp
->mb_imap_mailbox
);
866 n_err(_("Saving IMAP commands to *DEAD*\n"));
867 savedeadletter(fp
, 0);
868 ftruncate(fileno(fp
), 0);
876 printf("Committing IMAP commands for \"%s\"\n", mp
->mb_imap_mailbox
);
877 imap_dequeue(mp
, fp
);
887 #endif /* HAVE_IMAP */