2 * Copyright (C) 1996-8 Michael R. Elkins <me@mutt.org>
3 * Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
4 * Copyright (C) 1999-2006 Brendan Cully <brendan@kublai.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 /* command.c: routines for sending commands to an IMAP server and parsing
29 #include "imap_private.h"
37 #define IMAP_CMD_BUFSIZE 512
39 /* forward declarations */
40 static IMAP_COMMAND* cmd_new (IMAP_DATA* idata);
41 static int cmd_status (const char *s);
42 static void cmd_handle_fatal (IMAP_DATA* idata);
43 static int cmd_handle_untagged (IMAP_DATA* idata);
44 static void cmd_parse_capability (IMAP_DATA* idata, char* s);
45 static void cmd_parse_expunge (IMAP_DATA* idata, const char* s);
46 static void cmd_parse_list (IMAP_DATA* idata, char* s);
47 static void cmd_parse_lsub (IMAP_DATA* idata, char* s);
48 static void cmd_parse_fetch (IMAP_DATA* idata, char* s);
49 static void cmd_parse_myrights (IMAP_DATA* idata, const char* s);
50 static void cmd_parse_search (IMAP_DATA* idata, const char* s);
51 static void cmd_parse_status (IMAP_DATA* idata, char* s);
53 static char *Capabilities[] = {
70 /* imap_cmd_queue: Add command to command queue. Fails if the queue is full. */
71 int imap_cmd_queue (IMAP_DATA* idata, const char* cmdstr)
75 if (idata->status == IMAP_FATAL)
77 cmd_handle_fatal (idata);
81 if (!(cmd = cmd_new (idata)))
84 if (mutt_buffer_printf (idata->cmdbuf, "%s%s %s\r\n",
85 idata->state == IMAP_IDLE ? "DONE\r\n" : "", cmd->seq, cmdstr) < 0)
88 if (idata->state == IMAP_IDLE)
89 idata->state = IMAP_SELECTED;
94 /* imap_cmd_start: Given an IMAP command, send it to the server.
95 * If cmdstr is NULL, sends queued commands. */
96 int imap_cmd_start (IMAP_DATA* idata, const char* cmdstr)
100 if (cmdstr && (rc = imap_cmd_queue (idata, cmdstr)) < 0)
103 /* don't write old or empty commands */
104 if (idata->cmdbuf->dptr == idata->cmdbuf->data)
107 rc = mutt_socket_write (idata->conn, idata->cmdbuf->data);
108 idata->cmdbuf->dptr = idata->cmdbuf->data;
110 return (rc < 0) ? IMAP_CMD_BAD : 0;
113 /* imap_cmd_step: Reads server responses from an IMAP command, detects
114 * tagged completion response, handles untagged messages, can read
115 * arbitrarily large strings (using malloc, so don't make it _too_
117 int imap_cmd_step (IMAP_DATA* idata)
122 int stillrunning = 0;
125 if (idata->status == IMAP_FATAL)
127 cmd_handle_fatal (idata);
131 /* read into buffer, expanding buffer as necessary until we have a full
135 if (len == idata->blen)
137 safe_realloc (&idata->buf, idata->blen + IMAP_CMD_BUFSIZE);
138 idata->blen = idata->blen + IMAP_CMD_BUFSIZE;
139 dprint (3, (debugfile, "imap_cmd_step: grew buffer to %u bytes\n",
143 /* back up over '\0' */
146 c = mutt_socket_readln (idata->buf + len, idata->blen - len, idata->conn);
149 dprint (1, (debugfile, "imap_cmd_step: Error reading server response.\n"));
150 cmd_handle_fatal (idata);
156 /* if we've read all the way to the end of the buffer, we haven't read a
157 * full line (mutt_socket_readln strips the \r, so we always have at least
158 * one character free when we've read a full line) */
159 while (len == idata->blen);
161 /* don't let one large string make cmd->buf hog memory forever */
162 if ((idata->blen > IMAP_CMD_BUFSIZE) && (len <= IMAP_CMD_BUFSIZE))
164 safe_realloc (&idata->buf, IMAP_CMD_BUFSIZE);
165 idata->blen = IMAP_CMD_BUFSIZE;
166 dprint (3, (debugfile, "imap_cmd_step: shrank buffer to %u bytes\n", idata->blen));
169 idata->lastread = time (NULL);
171 /* handle untagged messages. The caller still gets its shot afterwards. */
172 if ((!ascii_strncmp (idata->buf, "* ", 2)
173 || !ascii_strncmp (imap_next_word (idata->buf), "OK [", 4))
174 && cmd_handle_untagged (idata))
177 /* server demands a continuation response from us */
178 if (idata->buf[0] == '+')
179 return IMAP_CMD_RESPOND;
181 /* look for tagged command completions */
182 rc = IMAP_CMD_CONTINUE;
186 cmd = &idata->cmds[c];
187 if (cmd->state == IMAP_CMD_NEW)
189 if (!ascii_strncmp (idata->buf, cmd->seq, SEQLEN)) {
192 /* first command in queue has finished - move queue pointer up */
193 idata->lastcmd = (idata->lastcmd + 1) % IMAP_PIPELINE_DEPTH;
195 cmd->state = cmd_status (idata->buf);
196 /* bogus - we don't know which command result to return here. Caller
197 * should provide a tag. */
204 c = (c + 1) % IMAP_PIPELINE_DEPTH;
206 while (c != idata->nextcmd);
209 rc = IMAP_CMD_CONTINUE;
212 dprint (3, (debugfile, "IMAP queue drained\n"));
213 imap_cmd_finish (idata);
220 /* imap_code: returns 1 if the command result was OK, or 0 if NO or BAD */
221 int imap_code (const char *s)
223 return cmd_status (s) == IMAP_CMD_OK;
226 /* imap_exec: execute a command, and wait for the response from the server.
227 * Also, handle untagged responses.
229 * IMAP_CMD_FAIL_OK: the calling procedure can handle failure. This is used
230 * for checking for a mailbox on append and login
231 * IMAP_CMD_PASS: command contains a password. Suppress logging.
232 * Return 0 on success, -1 on Failure, -2 on OK Failure
234 int imap_exec (IMAP_DATA* idata, const char* cmdstr, int flags)
238 if (idata->status == IMAP_FATAL)
240 cmd_handle_fatal (idata);
244 if (cmdstr && (rc = imap_cmd_queue (idata, cmdstr)) < 0)
247 /* don't write old or empty commands */
248 if (idata->cmdbuf->dptr == idata->cmdbuf->data)
251 rc = mutt_socket_write_d (idata->conn, idata->cmdbuf->data, -1,
252 flags & IMAP_CMD_PASS ? IMAP_LOG_PASS : IMAP_LOG_CMD);
253 idata->cmdbuf->dptr = idata->cmdbuf->data;
257 cmd_handle_fatal (idata);
262 rc = imap_cmd_step (idata);
263 while (rc == IMAP_CMD_CONTINUE);
265 if (rc == IMAP_CMD_NO && (flags & IMAP_CMD_FAIL_OK))
268 if (rc != IMAP_CMD_OK)
270 if (flags & IMAP_CMD_FAIL_OK && idata->status != IMAP_FATAL)
273 dprint (1, (debugfile, "imap_exec: command failed: %s\n", idata->buf));
280 /* imap_cmd_finish: Attempts to perform cleanup (eg fetch new mail if
281 * detected, do expunge). Called automatically by imap_cmd_step, but
282 * may be called at any time. Called by imap_check_mailbox just before
283 * the index is refreshed, for instance. */
284 void imap_cmd_finish (IMAP_DATA* idata)
286 if (idata->status == IMAP_FATAL)
288 cmd_handle_fatal (idata);
292 if (!(idata->state >= IMAP_SELECTED) || idata->ctx->closing)
295 if (idata->reopen & IMAP_REOPEN_ALLOW)
297 int count = idata->newMailCount;
299 if (!(idata->reopen & IMAP_EXPUNGE_PENDING) &&
300 (idata->reopen & IMAP_NEWMAIL_PENDING)
301 && count > idata->ctx->msgcount)
303 /* read new mail messages */
304 dprint (2, (debugfile, "imap_cmd_finish: Fetching new mail\n"));
305 /* check_status: curs_main uses imap_check_mailbox to detect
306 * whether the index needs updating */
307 idata->check_status = IMAP_NEWMAIL_PENDING;
308 imap_read_headers (idata, idata->ctx->msgcount, count-1);
310 else if (idata->reopen & IMAP_EXPUNGE_PENDING)
312 dprint (2, (debugfile, "imap_cmd_finish: Expunging mailbox\n"));
313 imap_expunge_mailbox (idata);
314 /* Detect whether we've gotten unexpected EXPUNGE messages */
315 if (idata->reopen & IMAP_EXPUNGE_PENDING &&
316 !(idata->reopen & IMAP_EXPUNGE_EXPECTED))
317 idata->check_status = IMAP_EXPUNGE_PENDING;
318 idata->reopen &= ~(IMAP_EXPUNGE_PENDING | IMAP_NEWMAIL_PENDING |
319 IMAP_EXPUNGE_EXPECTED);
326 /* sets up a new command control block and adds it to the queue.
327 * Returns NULL if the pipeline is full. */
328 static IMAP_COMMAND* cmd_new (IMAP_DATA* idata)
332 if ((idata->nextcmd + 1) % IMAP_PIPELINE_DEPTH == idata->lastcmd)
334 dprint (2, (debugfile, "cmd_new: IMAP command queue full\n"));
338 cmd = idata->cmds + idata->nextcmd;
339 idata->nextcmd = (idata->nextcmd + 1) % IMAP_PIPELINE_DEPTH;
341 snprintf (cmd->seq, sizeof (cmd->seq), "a%04u", idata->seqno++);
342 if (idata->seqno > 9999)
345 cmd->state = IMAP_CMD_NEW;
350 /* parse response line for tagged OK/NO/BAD */
351 static int cmd_status (const char *s)
353 s = imap_next_word((char*)s);
355 if (!ascii_strncasecmp("OK", s, 2))
357 if (!ascii_strncasecmp("NO", s, 2))
363 /* cmd_handle_fatal: when IMAP_DATA is in fatal state, do what we can */
364 static void cmd_handle_fatal (IMAP_DATA* idata)
366 idata->status = IMAP_FATAL;
368 if ((idata->state >= IMAP_SELECTED) &&
369 (idata->reopen & IMAP_REOPEN_ALLOW))
371 mx_fastclose_mailbox (idata->ctx);
372 mutt_error (_("Mailbox closed"));
374 idata->state = IMAP_DISCONNECTED;
377 if (idata->state < IMAP_SELECTED)
378 imap_close_connection (idata);
381 /* cmd_handle_untagged: fallback parser for otherwise unhandled messages. */
382 static int cmd_handle_untagged (IMAP_DATA* idata)
388 s = imap_next_word (idata->buf);
389 pn = imap_next_word (s);
391 if ((idata->state >= IMAP_SELECTED) && isdigit ((unsigned char) *s))
394 s = imap_next_word (s);
396 /* EXISTS and EXPUNGE are always related to the SELECTED mailbox for the
397 * connection, so update that one.
399 if (ascii_strncasecmp ("EXISTS", s, 6) == 0)
401 dprint (2, (debugfile, "Handling EXISTS\n"));
403 /* new mail arrived */
406 if ( !(idata->reopen & IMAP_EXPUNGE_PENDING) &&
407 count < idata->ctx->msgcount)
409 /* Notes 6.0.3 has a tendency to report fewer messages exist than
411 dprint (1, (debugfile, "Message count is out of sync"));
414 /* at least the InterChange server sends EXISTS messages freely,
415 * even when there is no new mail */
416 else if (count == idata->ctx->msgcount)
417 dprint (3, (debugfile,
418 "cmd_handle_untagged: superfluous EXISTS message.\n"));
421 if (!(idata->reopen & IMAP_EXPUNGE_PENDING))
423 dprint (2, (debugfile,
424 "cmd_handle_untagged: New mail in %s - %d messages total.\n",
425 idata->mailbox, count));
426 idata->reopen |= IMAP_NEWMAIL_PENDING;
428 idata->newMailCount = count;
431 /* pn vs. s: need initial seqno */
432 else if (ascii_strncasecmp ("EXPUNGE", s, 7) == 0)
433 cmd_parse_expunge (idata, pn);
434 else if (ascii_strncasecmp ("FETCH", s, 5) == 0)
435 cmd_parse_fetch (idata, pn);
437 else if (ascii_strncasecmp ("CAPABILITY", s, 10) == 0)
438 cmd_parse_capability (idata, s);
439 else if (!ascii_strncasecmp ("OK [CAPABILITY", s, 14))
440 cmd_parse_capability (idata, pn);
441 else if (!ascii_strncasecmp ("OK [CAPABILITY", pn, 14))
442 cmd_parse_capability (idata, imap_next_word (pn));
443 else if (ascii_strncasecmp ("LIST", s, 4) == 0)
444 cmd_parse_list (idata, s);
445 else if (ascii_strncasecmp ("LSUB", s, 4) == 0)
446 cmd_parse_lsub (idata, s);
447 else if (ascii_strncasecmp ("MYRIGHTS", s, 8) == 0)
448 cmd_parse_myrights (idata, s);
449 else if (ascii_strncasecmp ("SEARCH", s, 6) == 0)
450 cmd_parse_search (idata, s);
451 else if (ascii_strncasecmp ("STATUS", s, 6) == 0)
452 cmd_parse_status (idata, s);
453 else if (ascii_strncasecmp ("BYE", s, 3) == 0)
455 dprint (2, (debugfile, "Handling BYE\n"));
457 /* check if we're logging out */
458 if (idata->status == IMAP_BYE)
461 /* server shut down our connection */
464 mutt_error ("%s", s);
466 cmd_handle_fatal (idata);
470 else if (option (OPTIMAPSERVERNOISE) && (ascii_strncasecmp ("NO", s, 2) == 0))
472 dprint (2, (debugfile, "Handling untagged NO\n"));
474 /* Display the warning message from the server */
475 mutt_error ("%s", s+3);
482 /* cmd_parse_capabilities: set capability bits according to CAPABILITY
484 static void cmd_parse_capability (IMAP_DATA* idata, char* s)
489 dprint (3, (debugfile, "Handling CAPABILITY\n"));
491 s = imap_next_word (s);
492 if ((bracket = strchr (s, ']')))
494 FREE(&idata->capstr);
495 idata->capstr = safe_strdup (s);
497 memset (idata->capabilities, 0, sizeof (idata->capabilities));
501 for (x = 0; x < CAPMAX; x++)
502 if (imap_wordcasecmp(Capabilities[x], s) == 0)
504 mutt_bit_set (idata->capabilities, x);
507 s = imap_next_word (s);
511 /* cmd_parse_expunge: mark headers with new sequence ID and mark idata to
512 * be reopened at our earliest convenience */
513 static void cmd_parse_expunge (IMAP_DATA* idata, const char* s)
518 dprint (2, (debugfile, "Handling EXPUNGE\n"));
522 /* walk headers, zero seqno of expunged message, decrement seqno of those
523 * above. Possibly we could avoid walking the whole list by resorting
524 * and guessing a good starting point, but I'm guessing the resort would
525 * nullify the gains */
526 for (cur = 0; cur < idata->ctx->msgcount; cur++)
528 h = idata->ctx->hdrs[cur];
530 if (h->index+1 == expno)
532 else if (h->index+1 > expno)
536 idata->reopen |= IMAP_EXPUNGE_PENDING;
539 /* cmd_parse_fetch: Load fetch response into IMAP_DATA. Currently only
540 * handles unanticipated FETCH responses, and only FLAGS data. We get
541 * these if another client has changed flags for a mailbox we've selected.
542 * Of course, a lot of code here duplicates code in message.c. */
543 static void cmd_parse_fetch (IMAP_DATA* idata, char* s)
548 dprint (3, (debugfile, "Handling FETCH\n"));
552 if (msgno <= idata->ctx->msgcount)
553 /* see cmd_parse_expunge */
554 for (cur = 0; cur < idata->ctx->msgcount; cur++)
556 h = idata->ctx->hdrs[cur];
558 if (h && h->active && h->index+1 == msgno)
560 dprint (2, (debugfile, "Message UID %d updated\n", HEADER_DATA(h)->uid));
569 dprint (3, (debugfile, "FETCH response ignored for this message\n"));
574 s = imap_next_word (s);
575 s = imap_next_word (s);
579 dprint (1, (debugfile, "Malformed FETCH response"));
584 if (ascii_strncasecmp ("FLAGS", s, 5) != 0)
586 dprint (2, (debugfile, "Only handle FLAGS updates\n"));
590 /* If server flags could conflict with mutt's flags, reopen the mailbox. */
592 idata->reopen |= IMAP_EXPUNGE_PENDING;
594 imap_set_flags (idata, h, s);
595 idata->check_status = IMAP_FLAGS_PENDING;
599 static void cmd_parse_list (IMAP_DATA* idata, char* s)
603 char delimbuf[5]; /* worst case: "\\"\0 */
606 if (idata->cmddata && idata->cmdtype == IMAP_CT_LIST)
607 list = (IMAP_LIST*)idata->cmddata;
611 memset (list, 0, sizeof (IMAP_LIST));
614 s = imap_next_word (s);
617 dprint (1, (debugfile, "Bad LIST response\n"));
623 if (!ascii_strncasecmp (s, "\\NoSelect", 9))
625 else if (!ascii_strncasecmp (s, "\\NoInferiors", 12))
626 list->noinferiors = 1;
627 /* See draft-gahrns-imap-child-mailbox-?? */
628 else if (!ascii_strncasecmp (s, "\\HasNoChildren", 14))
629 list->noinferiors = 1;
631 s = imap_next_word (s);
637 if (ascii_strncasecmp (s, "NIL", 3))
640 safe_strcat (delimbuf, 5, s);
641 imap_unquote_string (delimbuf);
642 list->delim = delimbuf[0];
646 s = imap_next_word (s);
647 /* Notes often responds with literals here. We need a real tokenizer. */
648 if (!imap_get_literal_count (s, &litlen))
650 if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE)
652 idata->status = IMAP_FATAL;
655 list->name = idata->buf;
659 imap_unmunge_mbox_name (s);
663 if (list->name[0] == '\0')
665 idata->delim = list->delim;
666 dprint (2, (debugfile, "Root delimiter: %c\n", idata->delim));
670 static void cmd_parse_lsub (IMAP_DATA* idata, char* s)
678 if (idata->cmddata && idata->cmdtype == IMAP_CT_LIST)
680 /* caller will handle response itself */
681 cmd_parse_list (idata, s);
685 if (!option (OPTIMAPCHECKSUBSCRIBED))
688 idata->cmdtype = IMAP_CT_LIST;
689 idata->cmddata = &list;
690 cmd_parse_list (idata, s);
691 idata->cmddata = NULL;
695 dprint (2, (debugfile, "Subscribing to %s\n", list.name));
697 strfcpy (buf, "mailboxes \"", sizeof (buf));
698 mutt_account_tourl (&idata->conn->account, &url);
699 url.path = list.name;
700 if (!mutt_strcmp (url.user, ImapUser))
702 url_ciss_tostring (&url, buf + 11, sizeof (buf) - 10, 0);
703 safe_strcat (buf, sizeof (buf), "\"");
704 memset (&token, 0, sizeof (token));
706 err.dsize = sizeof (errstr);
707 if (mutt_parse_rc_line (buf, &token, &err))
708 dprint (1, (debugfile, "Error adding subscribed mailbox: %s\n", errstr));
712 /* cmd_parse_myrights: set rights bits according to MYRIGHTS response */
713 static void cmd_parse_myrights (IMAP_DATA* idata, const char* s)
715 dprint (2, (debugfile, "Handling MYRIGHTS\n"));
717 s = imap_next_word ((char*)s);
718 s = imap_next_word ((char*)s);
720 /* zero out current rights set */
721 memset (idata->ctx->rights, 0, sizeof (idata->ctx->rights));
723 while (*s && !isspace((unsigned char) *s))
728 mutt_bit_set (idata->ctx->rights, M_ACL_LOOKUP);
731 mutt_bit_set (idata->ctx->rights, M_ACL_READ);
734 mutt_bit_set (idata->ctx->rights, M_ACL_SEEN);
737 mutt_bit_set (idata->ctx->rights, M_ACL_WRITE);
740 mutt_bit_set (idata->ctx->rights, M_ACL_INSERT);
743 mutt_bit_set (idata->ctx->rights, M_ACL_POST);
746 mutt_bit_set (idata->ctx->rights, M_ACL_ADMIN);
749 mutt_bit_set (idata->ctx->rights, M_ACL_CREATE);
752 mutt_bit_set (idata->ctx->rights, M_ACL_DELMX);
755 mutt_bit_set (idata->ctx->rights, M_ACL_DELETE);
758 mutt_bit_set (idata->ctx->rights, M_ACL_EXPUNGE);
761 /* obsolete rights */
763 mutt_bit_set (idata->ctx->rights, M_ACL_CREATE);
764 mutt_bit_set (idata->ctx->rights, M_ACL_DELMX);
767 mutt_bit_set (idata->ctx->rights, M_ACL_DELETE);
768 mutt_bit_set (idata->ctx->rights, M_ACL_EXPUNGE);
771 dprint(1, (debugfile, "Unknown right: %c\n", *s));
777 /* This should be optimised (eg with a tree or hash) */
778 static int uid2msgno (IMAP_DATA* idata, unsigned int uid)
782 for (i = 0; i < idata->ctx->msgcount; i++)
784 HEADER* h = idata->ctx->hdrs[i];
785 if (HEADER_DATA(h)->uid == uid)
792 /* cmd_parse_search: store SEARCH response for later use */
793 static void cmd_parse_search (IMAP_DATA* idata, const char* s)
798 dprint (2, (debugfile, "Handling SEARCH\n"));
800 while ((s = imap_next_word ((char*)s)) && *s != '\0')
803 msgno = uid2msgno (idata, uid);
806 idata->ctx->hdrs[uid2msgno (idata, uid)]->matched = 1;
810 /* first cut: just do buffy update. Later we may wish to cache all
811 * mailbox information, even that not desired by buffy */
812 static void cmd_parse_status (IMAP_DATA* idata, char* s)
820 unsigned int olduv, oldun;
822 mailbox = imap_next_word (s);
823 s = imap_next_word (mailbox);
825 imap_unmunge_mbox_name (mailbox);
827 status = imap_mboxcache_get (idata, mailbox, 1);
828 olduv = status->uidvalidity;
829 oldun = status->uidnext;
833 dprint (1, (debugfile, "Error parsing STATUS\n"));
836 while (*s && *s != ')')
838 value = imap_next_word (s);
839 count = strtol (value, &value, 10);
841 if (!ascii_strncmp ("MESSAGES", s, 8))
842 status->messages = count;
843 else if (!ascii_strncmp ("RECENT", s, 6))
844 status->recent = count;
845 else if (!ascii_strncmp ("UIDNEXT", s, 7))
846 status->uidnext = count;
847 else if (!ascii_strncmp ("UIDVALIDITY", s, 11))
848 status->uidvalidity = count;
849 else if (!ascii_strncmp ("UNSEEN", s, 6))
850 status->unseen = count;
854 s = imap_next_word (s);
856 dprint (3, (debugfile, "%s (UIDVALIDITY: %d, UIDNEXT: %d) %d messages, %d recent, %d unseen\n",
857 status->name, status->uidvalidity, status->uidnext,
858 status->messages, status->recent, status->unseen));
860 /* caller is prepared to handle the result herself */
861 if (idata->cmddata && idata->cmdtype == IMAP_CT_STATUS)
863 memcpy (idata->cmddata, status, sizeof (IMAP_STATUS));
867 dprint (3, (debugfile, "Running default STATUS handler\n"));
869 /* should perhaps move this code back to imap_buffy_check */
870 for (inc = Incoming; inc; inc = inc->next)
872 if (inc->magic != M_IMAP)
875 if (imap_parse_path (inc->path, &mx) < 0)
877 dprint (1, (debugfile, "Error parsing mailbox %s, skipping\n", inc->path));
880 /* dprint (2, (debugfile, "Buffy entry: [%s] mbox: [%s]\n", inc->path, NONULL(mx.mbox))); */
882 if (mutt_account_match (&idata->conn->account, &mx.account))
886 value = safe_strdup (mx.mbox);
887 imap_fix_path (idata, mx.mbox, value, mutt_strlen (value) + 1);
891 value = safe_strdup ("INBOX");
893 if (value && !imap_mxcmp (mailbox, value))
895 dprint (3, (debugfile, "Found %s in buffy list (OV: %d ON: %d U: %d)\n",
896 mailbox, olduv, oldun, status->unseen));
898 if (olduv && olduv == status->uidvalidity)
900 if (oldun < status->uidnext)
901 inc->new = status->unseen;
903 else if (!olduv && !oldun)
904 /* first check per session, use recent. might need a flag for this. */
905 inc->new = status->recent;
907 inc->new = status->unseen;
910 /* force back to keep detecting new mail until the mailbox is
912 status->uidnext = oldun;