diff options
author | James Cloos <cloos@jhcloos.com> | 2010-10-19 13:04:42 -0400 |
---|---|---|
committer | James Cloos <cloos@jhcloos.com> | 2010-10-20 17:35:21 -0400 |
commit | 0264abd4309597cfe1f23f416c1004b0a490529d (patch) | |
tree | cb1c91eb074c330f2ab3785cefc13ac44d5e768e | |
parent | 7554179074f7c81edb50e52d197439ac4479a2bb (diff) | |
parent | e17e163e3af0cbb6ac707a4d1851e6922a6bd708 (diff) |
Add support for the LIST-STATUS extension to IMAP4list-status
Signed-off-by: James Cloos <cloos@jhcloos.com>
-rw-r--r-- | db.c | 155 | ||||
-rw-r--r-- | dbmail.conf | 2 | ||||
-rw-r--r-- | dbmail.h.in | 2 | ||||
-rw-r--r-- | imap4.h | 2 | ||||
-rw-r--r-- | imapcommands.c | 243 | ||||
-rw-r--r-- | man/dbmail.conf.5 | 2 |
6 files changed, 245 insertions, 161 deletions
@@ -2809,9 +2809,21 @@ static int mailboxes_by_regex(u64_t user_idnr, int only_subscribed, const char * u64_t *all_mailbox_nosels; u64_t *all_mailbox_noinfs; u64_t *all_mailbox_children; + u64_t *all_mailbox_perms; + u64_t *all_mailbox_seenfs; + u64_t *all_mailbox_ansfs; + u64_t *all_mailbox_delfs; + u64_t *all_mailbox_flgfs; + u64_t *all_mailbox_rcntfs; + u64_t *all_mailbox_drftfs; + u64_t *all_mailbox_nextuids; + u64_t *all_mailbox_exists; + u64_t *all_mailbox_unseens; + u64_t *all_mailbox_recents; u64_t search_user_idnr = user_idnr; + u64_t exists, seen, unseen; unsigned n_rows; - char *matchname; + char *matchname, *lsub_join, *lsub_suid; const char *spattern; char *namespace, *username; mailbox_t *tmp_mb; @@ -2854,38 +2866,43 @@ static int mailboxes_by_regex(u64_t user_idnr, int only_subscribed, const char * matchname = g_strdup(""); } - if (only_subscribed) - snprintf(query, DEF_QUERYSIZE, - "SELECT distinct(mbx.name), mbx.mailbox_idnr, mbx.owner_idnr, mbx.no_select, mbx.no_inferiors, mbx.children " - "FROM %smailboxes mbx " - "LEFT JOIN %sacl acl ON mbx.mailbox_idnr = acl.mailbox_id " - "LEFT JOIN %susers usr ON acl.user_id = usr.user_idnr " - "LEFT JOIN %ssubscription sub ON sub.mailbox_id = mbx.mailbox_idnr " - "WHERE %s (sub.user_id = %" U64_T_FORMAT " " - "AND ((mbx.owner_idnr = %" U64_T_FORMAT ") " - "%s (acl.user_id = %" U64_T_FORMAT " AND acl.lookup_flag = 1) " - "OR (usr.userid = '%s' AND acl.lookup_flag = 1)))", - DBPFX, DBPFX, DBPFX, DBPFX, matchname, - user_idnr, search_user_idnr, - search_user_idnr == user_idnr?"OR":"AND", - user_idnr, - DBMAIL_ACL_ANYONE_USER); - else - snprintf(query, DEF_QUERYSIZE, - "SELECT distinct(mbx.name), mbx.mailbox_idnr, mbx.owner_idnr, mbx.no_select, mbx.no_inferiors, mbx.children " - "FROM %smailboxes mbx " - "LEFT JOIN %sacl acl ON mbx.mailbox_idnr = acl.mailbox_id " - "LEFT JOIN %susers usr ON acl.user_id = usr.user_idnr " - "WHERE %s 1=1 " - "AND ((mbx.owner_idnr = %" U64_T_FORMAT ") " - "%s (acl.user_id = %" U64_T_FORMAT " AND acl.lookup_flag = 1) " - "OR (usr.userid = '%s' AND acl.lookup_flag = 1))", - DBPFX, DBPFX, DBPFX, matchname, - search_user_idnr, - search_user_idnr == user_idnr?"OR":"AND", - user_idnr, DBMAIL_ACL_ANYONE_USER); + if (only_subscribed) { + lsub_join = g_strdup_printf("LEFT JOIN %ssubscription sub ON sub.mailbox_id = mbx.mailbox_idnr ", DBPFX); + lsub_suid = g_strdup_printf("sub.user_id = %" U64_T_FORMAT " ", user_idnr); + } else { + lsub_join = g_strdup(""); + lsub_suid = g_strdup("1=1 "); + } + + snprintf(query, DEF_QUERYSIZE, + "WITH " + "exists AS (SELECT count(*) AS exists, mailbox_idnr FROM dbmail_messages WHERE status < 3 GROUP BY mailbox_idnr), " + "seen AS (SELECT count(*) AS seen, mailbox_idnr FROM dbmail_messages WHERE (status < 3 AND seen_flag=1) GROUP BY mailbox_idnr), " + "recent AS (SELECT count(*) AS recent, mailbox_idnr FROM dbmail_messages WHERE (status < 3) AND recent_flag=1 GROUP BY mailbox_idnr) " + "SELECT distinct(mbx.name), mbx.mailbox_idnr, mbx.owner_idnr, mbx.no_select, mbx.no_inferiors, mbx.children, " + "mbx.permission, mbx.seen_flag, mbx.answered_flag, mbx.deleted_flag, mbx.flagged_flag, mbx.recent_flag, mbx.draft_flag, " + "mbx.next_uid, " + "exists.exists, seen.seen as seen, recent.recent " + "FROM %smailboxes mbx " + "LEFT JOIN %sacl acl ON mbx.mailbox_idnr = acl.mailbox_id " + "LEFT JOIN %susers usr ON acl.user_id = usr.user_idnr " + "%s " + "LEFT OUTER JOIN exists ON exists.mailbox_idnr = mbx.mailbox_idnr " + "LEFT OUTER JOIN seen ON seen.mailbox_idnr = mbx.mailbox_idnr " + "LEFT OUTER JOIN recent ON recent.mailbox_idnr = mbx.mailbox_idnr " + "WHERE %s (%s " + "AND ((mbx.owner_idnr = %" U64_T_FORMAT ") " + "%s (acl.user_id = %" U64_T_FORMAT " AND acl.lookup_flag = 1) " + "OR (usr.userid = '%s' AND acl.lookup_flag = 1)))", + DBPFX, DBPFX, DBPFX, lsub_join, matchname, + lsub_suid, search_user_idnr, + search_user_idnr == user_idnr?"OR":"AND", + user_idnr, + DBMAIL_ACL_ANYONE_USER); g_free(matchname); + g_free(lsub_join); + g_free(lsub_suid); if (db_query(query) == -1) { TRACE(TRACE_ERROR, "error during mailbox query"); @@ -2904,6 +2921,17 @@ static int mailboxes_by_regex(u64_t user_idnr, int only_subscribed, const char * all_mailbox_noinfs = g_new0(u64_t,n_rows); all_mailbox_children = g_new0(u64_t,n_rows); tmp_mailboxes = g_new0(u64_t,n_rows); + all_mailbox_perms = g_new0(u64_t,n_rows); + all_mailbox_seenfs = g_new0(u64_t,n_rows); + all_mailbox_ansfs = g_new0(u64_t,n_rows); + all_mailbox_delfs = g_new0(u64_t,n_rows); + all_mailbox_flgfs = g_new0(u64_t,n_rows); + all_mailbox_rcntfs = g_new0(u64_t,n_rows); + all_mailbox_drftfs = g_new0(u64_t,n_rows); + all_mailbox_nextuids = g_new0(u64_t,n_rows); + all_mailbox_exists = g_new0(u64_t,n_rows); + all_mailbox_unseens = g_new0(u64_t,n_rows); + all_mailbox_recents = g_new0(u64_t,n_rows); for (i = 0; i < n_rows; i++) { all_mailbox_names[i] = g_strdup(db_get_result(i, 0)); @@ -2912,7 +2940,23 @@ static int mailboxes_by_regex(u64_t user_idnr, int only_subscribed, const char * all_mailbox_nosels[i] = db_get_result_u64(i, 3); all_mailbox_noinfs[i] = db_get_result_u64(i, 4); all_mailbox_children[i] = db_get_result_u64(i, 5); - } + all_mailbox_perms[i] = db_get_result_u64(i, 6); + all_mailbox_seenfs[i] = db_get_result_u64(i, 7); + all_mailbox_ansfs[i] = db_get_result_u64(i, 8); + all_mailbox_delfs[i] = db_get_result_u64(i, 9); + all_mailbox_flgfs[i] = db_get_result_u64(i, 10); + all_mailbox_rcntfs[i] = db_get_result_u64(i, 11); + all_mailbox_drftfs[i] = db_get_result_u64(i, 12); + all_mailbox_nextuids[i] = db_get_result_u64(i, 13); + + exists = db_get_result_u64(i, 14); + seen = db_get_result_u64(i, 15); + unseen = exists - seen; + + all_mailbox_exists[i] = exists; + all_mailbox_unseens[i] = unseen; + all_mailbox_recents[i] = db_get_result_u64(i, 16); + } db_free_result(); @@ -2941,6 +2985,9 @@ static int mailboxes_by_regex(u64_t user_idnr, int only_subscribed, const char * g_string_free(fqname,FALSE); } + /* uid */ + tmp_mb[i].uid = mailbox_idnr; + /* owner_idnr */ tmp_mb[i].owner_idnr = owner_idnr; @@ -2951,7 +2998,29 @@ static int mailboxes_by_regex(u64_t user_idnr, int only_subscribed, const char * /* no_children */ tmp_mb[i].no_children=no_children?0:1; - + + /* status flags info */ + if (all_mailbox_seenfs[i]) + tmp_mb[i].flags |= IMAPFLAG_SEEN; + if (all_mailbox_ansfs[i]) + tmp_mb[i].flags |= IMAPFLAG_ANSWERED; + if (all_mailbox_delfs[i]) + tmp_mb[i].flags |= IMAPFLAG_DELETED; + if (all_mailbox_flgfs[i]) + tmp_mb[i].flags |= IMAPFLAG_FLAGGED; + if (all_mailbox_rcntfs[i]) + tmp_mb[i].flags |= IMAPFLAG_RECENT; + if (all_mailbox_drftfs[i]) + tmp_mb[i].flags |= IMAPFLAG_DRAFT; + + /* status mbx info */ + tmp_mb[i].msguidnext = all_mailbox_nextuids[i]; + + /* status counts info */ + tmp_mb[i].exists = all_mailbox_exists[i]; + tmp_mb[i].unseen = all_mailbox_unseens[i]; + tmp_mb[i].recent = all_mailbox_recents[i]; + g_free(mailbox_name); g_free(simple_mailbox_name); } @@ -4736,27 +4805,7 @@ int db_getmailbox_list_result(u64_t mailbox_idnr, u64_t user_idnr, mailbox_t * m mb->no_inferiors=db_get_result_bool(0,i++); /* no_children */ -<<<<<<< HEAD - mailbox_like = db_imap_utf7_like("name", name, "/%"); - - memset(query,0,DEF_QUERYSIZE); - - snprintf(query, DEF_QUERYSIZE, - "SELECT COUNT(*) AS nr_children " - "FROM %smailboxes WHERE owner_idnr = %" U64_T_FORMAT " " - "AND %s", - DBPFX, mb->owner_idnr, mailbox_like); - - g_free(mailbox_like); - - if (db_query(query) == -1) { - TRACE(TRACE_ERROR, "db error"); - return DM_EQUERY; - } - mb->no_children=db_get_result_u64(0,0)?0:1; -======= mb->no_children=db_get_result_u64(0,i++)?0:1; ->>>>>>> c03d2eb5128671bf602338c0eb497a07e7823e96 g_free(name); db_free_result(); diff --git a/dbmail.conf b/dbmail.conf index c98bbf03..d9fc68cb 100644 --- a/dbmail.conf +++ b/dbmail.conf @@ -247,7 +247,7 @@ IMAP_BEFORE_SMTP = no # # Provide a CAPABILITY to override the default # -# capability = IMAP4 IMAP4rev1 AUTH=LOGIN ACL NAMESPACE CHILDREN SORT QUOTA THREAD=ORDEREDSUBJECT UNSELECT IDLE +# capability = IMAP4 IMAP4rev1 AUTH=LOGIN ACL NAMESPACE CHILDREN SORT QUOTA THREAD=ORDEREDSUBJECT UNSELECT IDLE LIST-STATUS diff --git a/dbmail.h.in b/dbmail.h.in index 0c571262..5501fef0 100644 --- a/dbmail.h.in +++ b/dbmail.h.in @@ -207,7 +207,7 @@ #define MAX_LINESIZE (65*1024) /* string length for query */ -#define DEF_QUERYSIZE 1024 +#define DEF_QUERYSIZE 4096 #define DEF_FRAGSIZE 64 /** default table prefix */ @@ -28,7 +28,7 @@ #include "dbmail.h" #define IMAP_SERVER_VERSION VERSION -#define IMAP_CAPABILITY_STRING "IMAP4 IMAP4rev1 AUTH=LOGIN ACL NAMESPACE CHILDREN SORT QUOTA THREAD=ORDEREDSUBJECT UNSELECT IDLE ID" +#define IMAP_CAPABILITY_STRING "IMAP4 IMAP4rev1 AUTH=LOGIN ACL NAMESPACE CHILDREN SORT QUOTA THREAD=ORDEREDSUBJECT UNSELECT IDLE ID LIST-STATUS" #define IMAP_TIMEOUT_MSG "* BYE dbmail IMAP4 server signing off due to timeout\r\n" /* max number of BAD/NO responses */ diff --git a/imapcommands.c b/imapcommands.c index d231486d..bd6629d4 100644 --- a/imapcommands.c +++ b/imapcommands.c @@ -46,6 +46,121 @@ extern const char AcceptedMailboxnameChars[]; extern int imap_before_smtp; +static int _ic_do_status(struct ImapSession *self, mailbox_t *list_mbox, int argskip) +{ + imap_userdata_t *ud = (imap_userdata_t *) self->ci->userData; + mailbox_t mb; + int i, endfound, result; + GString *response; + GList *plst = NULL; + gchar *pstring, *astring; + + if (strcmp(self->args[argskip+1], "(") != 0) { + dbmail_imap_session_printf(self, "%s BAD %sargument list should be parenthesed\r\n", self->tag, list_mbox==NULL ? "" : "return "); + return 1; + } + + /* check final arg: should be ')' and no new '(' in between */ + for (i = argskip+2, endfound = 0; self->args[i]; i++) { + if (strcmp(self->args[i], ")") == 0) { + endfound = i; + break; + } + + if (strcmp(self->args[i], "(") == 0) { + dbmail_imap_session_printf(self, "%s BAD too many parentheses specified\r\n", self->tag); + return 1; + } + } + + if (endfound == argskip+2) { + dbmail_imap_session_printf(self, "%s BAD argument list empty\r\n", self->tag); + return 1; + } + + if (self->args[endfound + 1] && list_mbox == NULL) { + dbmail_imap_session_printf(self, "%s BAD argument list too long\r\n", self->tag); + return 1; + } + + if (list_mbox == NULL) { + + /* zero init */ + memset(&mb, 0, sizeof(mb)); + + /* check if mailbox exists */ + if (db_findmailbox(self->args[argskip+0], ud->userid, &(mb.uid)) == -1) { + dbmail_imap_session_printf(self, "* BYE internal dbase error\r\n"); + return -1; + } + + if (mb.uid == 0) { + /* mailbox does not exist */ + dbmail_imap_session_printf(self, "%s NO specified mailbox does not exist\r\n", self->tag); + return 1; + } + + result = acl_has_right(&mb, ud->userid, ACL_RIGHT_READ); + if (result == -1) { + dbmail_imap_session_printf(self, "* BYE internal database error\r\n"); + return -1; + } + if (result == 0) { + dbmail_imap_session_printf(self, "%s NO no rights to get status for mailbox\r\n", self->tag); + return 1; + } + + /* retrieve mailbox data */ + result = db_getmailbox(&mb); + + /* name */ + mb.name = g_strdup(self->args[0]); + + if (result == -1) { + dbmail_imap_session_printf(self, "* BYE internal dbase error\r\n"); + return -1; /* fatal */ + } + } else { + mb = *list_mbox; + } + + for (i = argskip+2; self->args[i]; i++) { + if (strcasecmp(self->args[i], "messages") == 0) + plst = g_list_append_printf(plst,"MESSAGES %u", mb.exists); + else if (strcasecmp(self->args[i], "recent") == 0) + plst = g_list_append_printf(plst,"RECENT %u", mb.recent); + else if (strcasecmp(self->args[i], "unseen") == 0) + plst = g_list_append_printf(plst,"UNSEEN %u", mb.unseen); + else if (strcasecmp(self->args[i], "uidnext") == 0) { + plst = g_list_append_printf(plst,"UIDNEXT %llu", mb.msguidnext); + } else if (strcasecmp(self->args[i], "uidvalidity") == 0) { + plst = g_list_append_printf(plst,"UIDVALIDITY %llu", mb.uid); + } else if (strcasecmp(self->args[i], ")") == 0) + break; + else { + dbmail_imap_session_printf(self, + "\r\n%s BAD unrecognized option '%s' specified\r\n", + self->tag, self->args[i]); + return 1; + } + } + astring = dbmail_imap_astring_as_string(mb.name); + pstring = dbmail_imap_plist_as_string(plst); + + response = g_string_new(""); + g_string_printf(response, "* STATUS %s %s", astring, pstring); + dbmail_imap_session_printf(self, "%s\r\n", response->str); + if (list_mbox == NULL) + dbmail_imap_session_printf(self, "%s OK STATUS completed\r\n", self->tag); + + g_list_destroy(plst); + g_string_free(response,TRUE); + g_free(astring); + g_free(pstring); + + return 0; +} + /* * RETURN VALUES _ic_ functions: * @@ -707,13 +822,15 @@ int _ic_list(struct ImapSession *self) unsigned nchildren; char *pattern; char *thisname = list_is_lsub ? "LSUB" : "LIST"; + int do_status=0; + int argskip=4; /* count of args to list which are before the return ( "status" */ mailbox_t *mb = NULL; GList * plist = NULL; gchar * pstring; - if (!check_state_and_args(self, thisname, 2, 2, IMAPCS_AUTHENTICATED)) + if (!check_state_and_args(self, thisname, 2, 0, IMAPCS_AUTHENTICATED)) return 1; /* check if self->args are both empty strings, i.e. A001 LIST "" "" @@ -739,11 +856,21 @@ int _ic_list(struct ImapSession *self) TRACE(TRACE_INFO, "search with pattern: [%s]",pattern); + // FIXME: there could be other return types ... + // it ought to seach through the rest of + // the args looking for status.... + if ( self->args[2] && self->args[3] && self->args[4] && + strcasecmp(self->args[2], "RETURN") == 0 && + strcasecmp(self->args[3], "(") == 0 && + strcasecmp(self->args[4], "STATUS") == 0 ) + do_status = 1; + result = db_getmailbox_list_by_regex(ud->userid, pattern, &children, &nchildren, list_is_lsub, &mb); if (result == -1) { dbmail_imap_session_printf(self, "* BYE internal dbase error\r\n"); g_free(children); g_free(pattern); + g_free(mb); return -1; } @@ -752,6 +879,7 @@ int _ic_list(struct ImapSession *self) self->tag); g_free(children); g_free(pattern); + g_free(mb); return 1; } @@ -813,6 +941,10 @@ int _ic_list(struct ImapSession *self) dbmail_imap_session_printf(self, "* %s %s \"%s\" \"%s\"\r\n", thisname, pstring, MAILBOX_SEPARATOR, mb[i].name); + /* do LIST-STATUS line*/ + if (do_status) + _ic_do_status(self, &mb[i], argskip); + g_list_destroy(plist); g_free(pstring); } @@ -847,7 +979,6 @@ int _ic_lsub(struct ImapSession *self) return result; } - /* * _ic_status() * @@ -855,112 +986,16 @@ int _ic_lsub(struct ImapSession *self) */ int _ic_status(struct ImapSession *self) { - imap_userdata_t *ud = (imap_userdata_t *) self->ci->userData; - mailbox_t mb; - int i, endfound, result; - GString *response; - GList *plst = NULL; - gchar *pstring, *astring; - - - if (!check_state_and_args(self, "STATUS", 3, 0, IMAPCS_AUTHENTICATED)) - return 1; - - if (strcmp(self->args[1], "(") != 0) { - dbmail_imap_session_printf(self, "%s BAD argument list should be parenthesed\r\n", self->tag); - return 1; - } - - /* check final arg: should be ')' and no new '(' in between */ - for (i = 2, endfound = 0; self->args[i]; i++) { - if (strcmp(self->args[i], ")") == 0) { - endfound = i; - break; - } - - if (strcmp(self->args[i], "(") == 0) { - dbmail_imap_session_printf(self, "%s BAD too many parentheses specified\r\n", self->tag); - return 1; - } - } - - if (endfound == 2) { - dbmail_imap_session_printf(self, "%s BAD argument list empty\r\n", self->tag); - return 1; - } - - if (self->args[endfound + 1]) { - dbmail_imap_session_printf(self, "%s BAD argument list too long\r\n", self->tag); - return 1; - } - - - /* zero init */ - memset(&mb, 0, sizeof(mb)); - - /* check if mailbox exists */ - if (db_findmailbox(self->args[0], ud->userid, &(mb.uid)) == -1) { - dbmail_imap_session_printf(self, "* BYE internal dbase error\r\n"); - return -1; - } - - if (mb.uid == 0) { - /* mailbox does not exist */ - dbmail_imap_session_printf(self, "%s NO specified mailbox does not exist\r\n", self->tag); - return 1; - } + int result; + int just_status=1; + int argskip=0; - result = acl_has_right(&mb, ud->userid, ACL_RIGHT_READ); - if (result == -1) { - dbmail_imap_session_printf(self, "* BYE internal database error\r\n"); - return -1; - } - if (result == 0) { - dbmail_imap_session_printf(self, "%s NO no rights to get status for mailbox\r\n", self->tag); + if (!check_state_and_args(self, "STATUS", 3, 0, IMAPCS_AUTHENTICATED)) return 1; - } - /* retrieve mailbox data */ - result = db_getmailbox(&mb); + result = _ic_do_status(self, NULL, argskip); - if (result == -1) { - dbmail_imap_session_printf(self, "* BYE internal dbase error\r\n"); - return -1; /* fatal */ - } - for (i = 2; self->args[i]; i++) { - if (strcasecmp(self->args[i], "messages") == 0) - plst = g_list_append_printf(plst,"MESSAGES %u", mb.exists); - else if (strcasecmp(self->args[i], "recent") == 0) - plst = g_list_append_printf(plst,"RECENT %u", mb.recent); - else if (strcasecmp(self->args[i], "unseen") == 0) - plst = g_list_append_printf(plst,"UNSEEN %u", mb.unseen); - else if (strcasecmp(self->args[i], "uidnext") == 0) { - plst = g_list_append_printf(plst,"UIDNEXT %" U64_T_FORMAT, mb.msguidnext); - } else if (strcasecmp(self->args[i], "uidvalidity") == 0) { - plst = g_list_append_printf(plst,"UIDVALIDITY %" U64_T_FORMAT, mb.uid); - } else if (strcasecmp(self->args[i], ")") == 0) - break; - else { - dbmail_imap_session_printf(self, - "\r\n%s BAD unrecognized option '%s' specified\r\n", - self->tag, self->args[i]); - return 1; - } - } - astring = dbmail_imap_astring_as_string(self->args[0]); - pstring = dbmail_imap_plist_as_string(plst); - - response = g_string_new(""); - g_string_printf(response, "* STATUS %s %s", astring, pstring); - dbmail_imap_session_printf(self, "%s\r\n", response->str); - dbmail_imap_session_printf(self, "%s OK STATUS completed\r\n", self->tag); - - g_list_destroy(plst); - g_string_free(response,TRUE); - g_free(astring); - g_free(pstring); - - return 0; + return result; } /* diff --git a/man/dbmail.conf.5 b/man/dbmail.conf.5 index a4657889..d8ea69d6 100644 --- a/man/dbmail.conf.5 +++ b/man/dbmail.conf.5 @@ -267,7 +267,7 @@ There are 8 sections: DBMAIL, SMTP, LMTP, POP, IMAP, SIEVE, LDAP, DELIVERY\&. Th # # Provide a CAPABILITY to override the default # - # capability = IMAP4 IMAP4rev1 AUTH=LOGIN ACL NAMESPACE CHILDREN SORT QUOTA THREAD=ORDEREDSUBJECT UNSELECT IDLE + # capability = IMAP4 IMAP4rev1 AUTH=LOGIN ACL NAMESPACE CHILDREN SORT QUOTA THREAD=ORDEREDSUBJECT UNSELECT IDLE LIST-STATUS |