From ce4ee132ed68d42ec8ed42e44668dd96c2476a91 Mon Sep 17 00:00:00 2001 From: Jim Nelson Date: Tue, 31 May 2011 18:47:54 -0700 Subject: [PATCH] Added STATUS command and decoder. Although no place in the code uses this yet, it will be useful in the near future. --- Makefile | 2 + src/engine/imap/Commands.vala | 17 ++++ src/engine/imap/StatusDataType.vala | 70 ++++++++++++++ src/engine/imap/decoders/StatusResults.vala | 100 ++++++++++++++++++++ 4 files changed, 189 insertions(+) create mode 100644 src/engine/imap/StatusDataType.vala create mode 100644 src/engine/imap/decoders/StatusResults.vala diff --git a/Makefile b/Makefile index f4af17bd..4058ec14 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,7 @@ ENGINE_SRC := \ src/engine/imap/ResponseCodeType.vala \ src/engine/imap/ServerResponse.vala \ src/engine/imap/StatusResponse.vala \ + src/engine/imap/StatusDataType.vala \ src/engine/imap/ServerData.vala \ src/engine/imap/ServerDataType.vala \ src/engine/imap/FetchDataType.vala \ @@ -46,6 +47,7 @@ ENGINE_SRC := \ src/engine/imap/decoders/NoopResults.vala \ src/engine/imap/decoders/ListResults.vala \ src/engine/imap/decoders/SelectExamineResults.vala \ + src/engine/imap/decoders/StatusResults.vala \ src/engine/rfc822/MailboxAddress.vala \ src/engine/rfc822/MessageData.vala \ src/engine/util/String.vala \ diff --git a/src/engine/imap/Commands.vala b/src/engine/imap/Commands.vala index 1b6aad74..533522da 100644 --- a/src/engine/imap/Commands.vala +++ b/src/engine/imap/Commands.vala @@ -109,3 +109,20 @@ public class Geary.Imap.FetchCommand : Command { } } +public class Geary.Imap.StatusCommand : Command { + public const string NAME = "status"; + + public StatusCommand(Tag tag, string mailbox, StatusDataType[] data_items) { + base (tag, NAME); + + add (new StringParameter(mailbox)); + + assert(data_items.length > 0); + ListParameter data_item_list = new ListParameter(this); + foreach (StatusDataType data_item in data_items) + data_item_list.add(data_item.to_parameter()); + + add(data_item_list); + } +} + diff --git a/src/engine/imap/StatusDataType.vala b/src/engine/imap/StatusDataType.vala new file mode 100644 index 00000000..1b2719eb --- /dev/null +++ b/src/engine/imap/StatusDataType.vala @@ -0,0 +1,70 @@ +/* Copyright 2011 Yorba Foundation + * + * This software is licensed under the GNU Lesser General Public License + * (version 2.1 or later). See the COPYING file in this distribution. + */ + +public enum Geary.Imap.StatusDataType { + MESSAGES, + RECENT, + UIDNEXT, + UIDVALIDITY, + UNSEEN; + + public static StatusDataType[] all() { + return { MESSAGES, RECENT, UIDNEXT, UIDVALIDITY, UNSEEN }; + } + + public string to_string() { + switch (this) { + case MESSAGES: + return "messages"; + + case RECENT: + return "recent"; + + case UIDNEXT: + return "uidnext"; + + case UIDVALIDITY: + return "uidvalidity"; + + case UNSEEN: + return "unseen"; + + default: + assert_not_reached(); + } + } + + public static StatusDataType decode(string value) throws ImapError { + switch (value.down()) { + case "messages": + return MESSAGES; + + case "recent": + return RECENT; + + case "uidnext": + return UIDNEXT; + + case "uidvalidity": + return UIDVALIDITY; + + case "unseen": + return UNSEEN; + + default: + throw new ImapError.PARSE_ERROR("Unknown status data type \"%s\"", value); + } + } + + public StringParameter to_parameter() { + return new StringParameter(to_string()); + } + + public static StatusDataType from_parameter(StringParameter stringp) throws ImapError { + return decode(stringp.value); + } +} + diff --git a/src/engine/imap/decoders/StatusResults.vala b/src/engine/imap/decoders/StatusResults.vala new file mode 100644 index 00000000..79febfb3 --- /dev/null +++ b/src/engine/imap/decoders/StatusResults.vala @@ -0,0 +1,100 @@ +/* Copyright 2011 Yorba Foundation + * + * This software is licensed under the GNU Lesser General Public License + * (version 2.1 or later). See the COPYING file in this distribution. + */ + +public class Geary.Imap.StatusResults : Geary.Imap.CommandResults { + public string mailbox { get; private set; } + /** + * -1 if not set. + */ + public int messages { get; private set; } + /** + * -1 if not set. + */ + public int recent { get; private set; } + public UID? uidnext { get; private set; } + public UID? uidvalidity { get; private set; } + /** + * -1 if not set. + */ + public int unseen { get; private set; } + + public StatusResults(StatusResponse status_response, string mailbox, int messages, int recent, + UID? uidnext, UID? uidvalidity, int unseen) { + base (status_response); + + this.mailbox = mailbox; + this.messages = messages; + this.recent = recent; + this.uidnext = uidnext; + this.uidvalidity = uidvalidity; + this.unseen = unseen; + } + + public static StatusResults decode(CommandResponse response) throws ImapError { + assert(response.is_sealed()); + + // only use the first untagged response of status; zero is a problem, more than one are + // ignored + if (response.server_data.size == 0) + throw new ImapError.PARSE_ERROR("No STATUS response line: \"%s\"", response.to_string()); + + ServerData data = response.server_data[0]; + StringParameter cmd = data.get_as_string(1); + StringParameter mailbox = data.get_as_string(2); + ListParameter values = data.get_as_list(3); + + if (!cmd.equals_ci(StatusCommand.NAME)) { + throw new ImapError.PARSE_ERROR("Bad STATUS command name in response \"%s\"", + response.to_string()); + } + + int messages = -1; + int recent = -1; + UID? uidnext = null; + UID? uidvalidity = null; + int unseen = -1; + + for (int ctr = 0; ctr < values.get_count(); ctr += 2) { + try { + StringParameter typep = values.get_as_string(ctr); + StringParameter valuep = values.get_as_string(ctr + 1); + + switch (StatusDataType.from_parameter(typep)) { + case StatusDataType.MESSAGES: + messages = valuep.as_int(-1, int.MAX); + break; + + case StatusDataType.RECENT: + recent = valuep.as_int(-1, int.MAX); + break; + + case StatusDataType.UIDNEXT: + uidnext = new UID(valuep.as_int()); + break; + + case StatusDataType.UIDVALIDITY: + uidvalidity = new UID(valuep.as_int()); + break; + + case StatusDataType.UNSEEN: + unseen = valuep.as_int(-1, int.MAX); + break; + + default: + message("Bad STATUS data type %s", typep.value); + break; + } + } catch (ImapError ierr) { + message("Bad value at %d/%d in STATUS response \"%s\": %s", ctr, ctr + 1, + response.to_string(), ierr.message); + } + } + + return new StatusResults(response.status_response, mailbox.value, messages, recent, uidnext, + uidvalidity, unseen); + } +} +