int imap_browse (char* path, struct browser_state* state)
{
IMAP_DATA* idata;
+ IMAP_LIST list;
char buf[LONG_STRING];
char buf2[LONG_STRING];
char nsbuf[LONG_STRING];
int nsup;
char ctmp;
int nns = 0;
- char *cur_folder;
short showparents = 0;
- int noselect;
- int noinferiors;
int save_lsub;
IMAP_MBOX mx;
{
snprintf (buf, sizeof (buf), "%s \"\" \"%s\"", list_cmd, mbox);
imap_cmd_start (idata, buf);
- do
+ idata->cmddata = &list;
+ do
{
- if ((rc = imap_parse_list_response (idata, &cur_folder, &noselect,
- &noinferiors, &idata->delim)) == IMAP_CMD_BAD)
- goto fail;
-
- if (cur_folder)
+ rc = imap_cmd_step (idata);
+ if (rc == IMAP_CMD_CONTINUE && list.name)
{
- imap_unmunge_mbox_name (cur_folder);
-
- if (!noinferiors && cur_folder[0] &&
+ if (!list.noinferiors && list.name[0] &&
(n = strlen (mbox)) < LONG_STRING-1)
{
- mbox[n++] = idata->delim;
+ mbox[n++] = list.delim;
mbox[n] = '\0';
}
}
}
while (rc == IMAP_CMD_CONTINUE);
+ idata->cmddata = NULL;
}
/* if we're descending a folder, mark it as current in browser_state */
- if (mbox[n-1] == idata->delim)
+ if (mbox[n-1] == list.delim)
{
/* don't show parents in the home namespace */
if (!home_namespace)
* and tack on delimiter ourselves.
* Further note: UW-IMAP servers return nothing when asked for
* NAMESPACES without delimiters at the end. Argh! */
- for (n--; n >= 0 && mbox[n] != idata->delim ; n--);
+ for (n--; n >= 0 && mbox[n] != list.delim ; n--);
if (n > 0) /* "aaaa/bbbb/" -> "aaaa" */
{
/* forget the check, it is too delicate (see above). Have we ever
if (showparents)
{
dprint (3, (debugfile, "imap_init_browse: adding parent %s\n", mbox));
- imap_add_folder (idata->delim, mbox, 1, 0, state, 1);
+ imap_add_folder (list.delim, mbox, 1, 0, state, 1);
}
/* if our target isn't a folder, we are in our superior */
static int browse_add_list_result (IMAP_DATA* idata, const char* cmd,
struct browser_state* state, short isparent)
{
- char *name;
- int noselect;
- int noinferiors;
+ IMAP_LIST list;
IMAP_MBOX mx;
int rc;
}
imap_cmd_start (idata, cmd);
-
- do
+ idata->cmddata = &list;
+ do
{
- if ((rc = imap_parse_list_response(idata, &name, &noselect, &noinferiors,
- &idata->delim)) == IMAP_CMD_BAD)
- {
- FREE (&mx.mbox);
- return -1;
- }
+ rc = imap_cmd_step (idata);
- if (name)
+ if (rc == IMAP_CMD_CONTINUE && list.name)
{
/* Let a parent folder never be selectable for navigation */
if (isparent)
- noselect = 1;
+ list.noselect = 1;
/* prune current folder from output */
- if (isparent || mutt_strncmp (name, mx.mbox, strlen (name)))
- imap_add_folder (idata->delim, name, noselect, noinferiors, state,
- isparent);
+ if (isparent || mutt_strncmp (list.name, mx.mbox, strlen (list.name)))
+ imap_add_folder (list.delim, list.name, list.noselect, list.noinferiors,
+ state, isparent);
}
}
while (rc == IMAP_CMD_CONTINUE);
+ idata->cmddata = NULL;
FREE (&mx.mbox);
- return 0;
+ return rc == IMAP_CMD_OK ? 0 : -1;
}
/* imap_add_folder: add a folder name to the browser list, formatting it as
IMAP_NAMESPACE_INFO *nsi, int nns)
{
char buf[LONG_STRING];
+ IMAP_LIST list;
int i = 0;
- char *name;
- char delim;
int rc;
for (i = 0; i < nns; i++, nsi++)
option (OPTIMAPLSUB) ? "LSUB" : "LIST", nsi->prefix);
imap_cmd_start (idata, buf);
-
+ idata->cmddata = &list;
nsi->listable = 0;
nsi->home_namespace = 0;
do
{
- if ((rc = imap_parse_list_response(idata, &name, &nsi->noselect,
- &nsi->noinferiors, &delim)) == IMAP_CMD_BAD)
- return -1;
- nsi->listable |= (name != NULL);
+ rc = imap_cmd_step (idata);
+ if (rc == IMAP_CMD_CONTINUE && list.name)
+ nsi->listable |= (list.name[0] != '\0');
}
while (rc == IMAP_CMD_CONTINUE);
+ idata->cmddata = NULL;
+
+ if (rc != IMAP_CMD_OK)
+ return -1;
}
return 0;
static int cmd_handle_untagged (IMAP_DATA* idata);
static void cmd_parse_capabilities (IMAP_DATA* idata, char* s);
static void cmd_parse_expunge (IMAP_DATA* idata, const char* s);
+static void cmd_parse_list (IMAP_DATA* idata, char* s);
static void cmd_parse_lsub (IMAP_DATA* idata, char* s);
static void cmd_parse_fetch (IMAP_DATA* idata, char* s);
static void cmd_parse_myrights (IMAP_DATA* idata, const char* s);
}
else if (ascii_strncasecmp ("CAPABILITY", s, 10) == 0)
cmd_parse_capabilities (idata, s);
+ else if (ascii_strncasecmp ("LIST", s, 4) == 0)
+ cmd_parse_list (idata, s);
else if (ascii_strncasecmp ("LSUB", s, 4) == 0)
cmd_parse_lsub (idata, s);
else if (ascii_strncasecmp ("MYRIGHTS", s, 8) == 0)
}
}
-static void cmd_parse_lsub (IMAP_DATA* idata, char* s)
+static void cmd_parse_list (IMAP_DATA* idata, char* s)
{
- char buf[STRING];
- char errstr[STRING];
- BUFFER err, token;
- ciss_url_t url;
- char *ep;
+ IMAP_LIST* list;
+ char delimbuf[5]; /* worst case: "\\"\0 */
- if (!option (OPTIMAPCHECKSUBSCRIBED))
+ if (!idata->cmddata)
+ {
+ dprint (2, (debugfile, "Ignoring LIST response\n"));
return;
+ }
- s = imap_next_word (s); /* flags */
-
+ list = (IMAP_LIST*)idata->cmddata;
+ memset (list, 0, sizeof (IMAP_LIST));
+
+ /* flags */
+ s = imap_next_word (s);
if (*s != '(')
{
- dprint (1, (debugfile, "Bad LSUB response\n"));
+ dprint (1, (debugfile, "Bad LIST response\n"));
return;
}
-
s++;
- ep = s;
- for (ep = s; *ep && *ep != ')'; ep++)
- ;
- do
+ while (*s)
{
if (!ascii_strncasecmp (s, "\\NoSelect", 9))
- return;
- while (s < ep && *s != ' ' && *s != ')')
- s++;
- if (*s == ' ')
- s++;
- } while (s != ep);
-
- s = imap_next_word (s); /* delim */
- s = imap_next_word (s); /* name */
-
- if (s)
- {
- imap_unmunge_mbox_name (s);
- dprint (2, (debugfile, "Subscribing to %s\n", s));
+ list->noselect = 1;
+ else if (!ascii_strncasecmp (s, "\\NoInferiors", 12))
+ list->noinferiors = 1;
+ /* See draft-gahrns-imap-child-mailbox-?? */
+ else if (!ascii_strncasecmp (s, "\\HasNoChildren", 14))
+ list->noinferiors = 1;
- strfcpy (buf, "mailboxes \"", sizeof (buf));
- mutt_account_tourl (&idata->conn->account, &url);
- url.path = s;
- if (!mutt_strcmp (url.user, ImapUser))
- url.user = NULL;
- url_ciss_tostring (&url, buf + 11, sizeof (buf) - 10, 0);
- safe_strcat (buf, sizeof (buf), "\"");
- memset (&token, 0, sizeof (token));
- err.data = errstr;
- err.dsize = sizeof (errstr);
- if (mutt_parse_rc_line (buf, &token, &err))
- dprint (1, (debugfile, "Error adding subscribed mailbox: %s\n", errstr));
- FREE (&token.data);
- }
- else
- dprint (1, (debugfile, "Bad LSUB response\n"));
+ s = imap_next_word (s);
+ if (*(s - 2) == ')')
+ break;
+ }
+
+ /* Delimiter */
+ if (ascii_strncasecmp (s, "NIL", 3))
+ {
+ delimbuf[0] = '\0';
+ safe_strcat (delimbuf, 5, s);
+ imap_unquote_string (delimbuf);
+ list->delim = delimbuf[0];
+ }
+
+ /* Name */
+ s = imap_next_word (s);
+ imap_unmunge_mbox_name (s);
+ list->name = s;
+}
+
+static void cmd_parse_lsub (IMAP_DATA* idata, char* s)
+{
+ char buf[STRING];
+ char errstr[STRING];
+ BUFFER err, token;
+ ciss_url_t url;
+ IMAP_LIST list;
+
+ if (idata->cmddata)
+ {
+ /* caller will handle response itself */
+ cmd_parse_list (idata, s);
+ return;
+ }
+
+ if (!option (OPTIMAPCHECKSUBSCRIBED))
+ return;
+
+ idata->cmddata = &list;
+ cmd_parse_list (idata, s);
+ idata->cmddata = NULL;
+ if (!list.name)
+ return;
+
+ dprint (2, (debugfile, "Subscribing to %s\n", list.name));
+
+ strfcpy (buf, "mailboxes \"", sizeof (buf));
+ mutt_account_tourl (&idata->conn->account, &url);
+ url.path = list.name;
+ if (!mutt_strcmp (url.user, ImapUser))
+ url.user = NULL;
+ url_ciss_tostring (&url, buf + 11, sizeof (buf) - 10, 0);
+ safe_strcat (buf, sizeof (buf), "\"");
+ memset (&token, 0, sizeof (token));
+ err.data = errstr;
+ err.dsize = sizeof (errstr);
+ if (mutt_parse_rc_line (buf, &token, &err))
+ dprint (1, (debugfile, "Error adding subscribed mailbox: %s\n", errstr));
+ FREE (&token.data);
}
/* cmd_parse_myrights: set rights bits according to MYRIGHTS response */
IMAP_STATUS *status, sb;
int olduv, oldun;
- dprint (2, (debugfile, "Handling STATUS\n"));
-
mailbox = imap_next_word (s);
s = imap_next_word (mailbox);
*(s - 1) = '\0';
return 0;
}
-/* all this listing/browsing is a mess. I don't like that name is a pointer
- * into idata->buf (used to be a pointer into the passed in buffer, just
- * as bad), nor do I like the fact that the fetch is done here. This
- * code can't possibly handle non-LIST untagged responses properly.
- * FIXME. ?! */
-int imap_parse_list_response(IMAP_DATA* idata, char **name, int *noselect,
- int *noinferiors, char *delim)
-{
- char *s;
- long bytes;
- int rc;
-
- *name = NULL;
-
- rc = imap_cmd_step (idata);
- if (rc == IMAP_CMD_OK)
- return rc;
- if (rc != IMAP_CMD_CONTINUE)
- return IMAP_CMD_BAD;
-
- s = imap_next_word (idata->buf);
- if ((ascii_strncasecmp ("LIST", s, 4) == 0) ||
- (ascii_strncasecmp ("LSUB", s, 4) == 0))
- {
- *noselect = 0;
- *noinferiors = 0;
-
- s = imap_next_word (s); /* flags */
- if (*s == '(')
- {
- char *ep;
-
- s++;
- ep = s;
- while (*ep && *ep != ')') ep++;
- do
- {
- if (!ascii_strncasecmp (s, "\\NoSelect", 9))
- *noselect = 1;
- if (!ascii_strncasecmp (s, "\\NoInferiors", 12))
- *noinferiors = 1;
- /* See draft-gahrns-imap-child-mailbox-?? */
- if (!ascii_strncasecmp (s, "\\HasNoChildren", 14))
- *noinferiors = 1;
- if (*s != ')')
- s++;
- while (*s && *s != '\\' && *s != ')') s++;
- } while (s != ep);
- }
- else
- return 0;
- s = imap_next_word (s); /* delim */
- /* Reset the delimiter, this can change */
- if (ascii_strncasecmp (s, "NIL", 3))
- {
- if (s && s[0] == '\"' && s[1] && s[2] == '\"')
- *delim = s[1];
- else if (s && s[0] == '\"' && s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
- *delim = s[2];
- }
- s = imap_next_word (s); /* name */
- if (s && *s == '{') /* Literal */
- {
- if (imap_get_literal_count(idata->buf, &bytes) < 0)
- return IMAP_CMD_BAD;
- if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE)
- return IMAP_CMD_BAD;
- *name = idata->buf;
- }
- else
- *name = s;
- }
-
- return IMAP_CMD_CONTINUE;
-}
-
int imap_subscribe (char *path, int subscribe)
{
CONNECTION *conn;
IMAP_DATA* idata;
char list[LONG_STRING];
char buf[LONG_STRING];
- char* list_word = NULL;
- int noselect, noinferiors;
- char delim;
+ IMAP_LIST listresp;
char completion[LONG_STRING];
int clen, matchlen = 0;
int completions = 0;
/* and see what the results are */
strfcpy (completion, NONULL(mx.mbox), sizeof(completion));
+ idata->cmddata = &listresp;
do
{
- if ((rc = imap_parse_list_response(idata, &list_word, &noselect, &noinferiors,
- &delim)) == IMAP_CMD_BAD)
- break;
+ rc = imap_cmd_step (idata);
- if (list_word)
+ if (rc == IMAP_CMD_CONTINUE && listresp.name)
{
- /* store unquoted */
- imap_unmunge_mbox_name (list_word);
-
/* if the folder isn't selectable, append delimiter to force browse
* to enter it on second tab. */
- if (noselect)
+ if (listresp.noselect)
{
- clen = strlen(list_word);
- list_word[clen++] = delim;
- list_word[clen] = '\0';
+ clen = strlen(listresp.name);
+ listresp.name[clen++] = listresp.delim;
+ listresp.name[clen] = '\0';
}
/* copy in first word */
if (!completions)
{
- strfcpy (completion, list_word, sizeof(completion));
+ strfcpy (completion, listresp.name, sizeof(completion));
matchlen = strlen (completion);
completions++;
continue;
}
- matchlen = longest_common_prefix (completion, list_word, 0, matchlen);
+ matchlen = longest_common_prefix (completion, listresp.name, 0, matchlen);
completions++;
}
}
while (rc == IMAP_CMD_CONTINUE);
+ idata->cmddata = NULL;
if (completions)
{
unsigned int unseen;
} IMAP_STATUS;
+typedef struct
+{
+ char* name;
+
+ char delim;
+ /* if we end up storing a lot of these we could turn this into a bitfield */
+ unsigned char noselect;
+ unsigned char noinferiors;
+} IMAP_LIST;
+
/* IMAP command structure */
typedef struct
{
int imap_make_msg_set (IMAP_DATA* idata, BUFFER* buf, int flag, int changed);
int imap_open_connection (IMAP_DATA* idata);
IMAP_DATA* imap_conn_find (const ACCOUNT* account, int flags);
-int imap_parse_list_response(IMAP_DATA* idata, char** name, int* noselect,
- int* noinferiors, char* delim);
int imap_read_literal (FILE* fp, IMAP_DATA* idata, long bytes, progress_t*);
void imap_expunge_mailbox (IMAP_DATA* idata);
void imap_logout (IMAP_DATA* idata);