author | zautrix <zautrix> | 2005-03-18 20:17:03 (UTC) |
---|---|---|
committer | zautrix <zautrix> | 2005-03-18 20:17:03 (UTC) |
commit | 9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf (patch) (side-by-side diff) | |
tree | 2528e6cc740225ca0f47d5ac8ff70f7d3bb10621 /libetpan/src/low-level/imap/mailimap_sender.c | |
parent | 9319998f20f03dcc217fbb39656755dc65226276 (diff) | |
download | kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.zip kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.tar.gz kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.tar.bz2 |
Initial revision
Diffstat (limited to 'libetpan/src/low-level/imap/mailimap_sender.c') (more/less context) (show whitespace changes)
-rw-r--r-- | libetpan/src/low-level/imap/mailimap_sender.c | 2742 |
1 files changed, 2742 insertions, 0 deletions
diff --git a/libetpan/src/low-level/imap/mailimap_sender.c b/libetpan/src/low-level/imap/mailimap_sender.c new file mode 100644 index 0000000..caf86e5 --- a/dev/null +++ b/libetpan/src/low-level/imap/mailimap_sender.c @@ -0,0 +1,2742 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mailstream.h" +#include "mailimap_keywords.h" +#include "mailimap_sender.h" +#include "clist.h" +#include "mail.h" +#include <string.h> + +#include <stdio.h> +#include <ctype.h> + +/* + TODO : + implement progression for literal +*/ + +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ + + + + +static int mailimap_atom_send(mailstream * fd, const char * atom); + +static int mailimap_auth_type_send(mailstream * fd, const char * auth_type); + +static int mailimap_base64_send(mailstream * fd, const char * base64); + + +static int mailimap_date_send(mailstream * fd, + struct mailimap_date * date); + +static int mailimap_date_day_send(mailstream * fd, int day); + +static int mailimap_date_month_send(mailstream * fd, int month); + + +/* +static gboolean mailimap_date_text_send(mailstream * fd, + struct mailimap_date_text * date_text); +*/ + + +static int mailimap_date_year_send(mailstream *fd, int year); + +static int +mailimap_date_time_send(mailstream * fd, + struct mailimap_date_time * date_time); + +static int mailimap_digit_send(mailstream * fd, int digit); + + + +static int +mailimap_fetch_type_send(mailstream * fd, + struct mailimap_fetch_type * fetch_type); + + +static int mailimap_fetch_att_send(mailstream * fd, + struct mailimap_fetch_att * fetch_att); + + +static int mailimap_flag_send(mailstream * fd, + struct mailimap_flag * flag); + + +static int mailimap_flag_extension_send(mailstream * fd, + const char * flag_extension); + + +static int mailimap_flag_keyword_send(mailstream * fd, + const char * flag_keyword); + + +static int mailimap_flag_list_send(mailstream * fd, + struct mailimap_flag_list * flag_list); + + + +static int mailimap_header_fld_name_send(mailstream * fd, const char * header); + + +static int +mailimap_header_list_send(mailstream * fd, + struct mailimap_header_list * header_list); + +static int +mailimap_list_mailbox_send(mailstream * fd, const char * pattern); + + +static int mailimap_mailbox_send(mailstream * fd, const char * mb); + +static int mailimap_number_send(mailstream * fd, uint32_t number); + +static int mailimap_password_send(mailstream * fd, const char * pass); + +static int mailimap_quoted_char_send(mailstream * fd, char ch); + +static int mailimap_quoted_send(mailstream * fd, const char * quoted); + + +static int mailimap_search_key_send(mailstream * fd, + struct mailimap_search_key * key); + +static int +mailimap_section_send(mailstream * fd, + struct mailimap_section * section); + +static int +mailimap_section_msgtext_send(mailstream * fd, + struct mailimap_section_msgtext * + section_msgtext); + + +static int +mailimap_section_part_send(mailstream * fd, + struct mailimap_section_part * section); + + +static int +mailimap_section_spec_send(mailstream * fd, + struct mailimap_section_spec * section_spec); + + +static int +mailimap_section_text_send(mailstream * fd, + struct mailimap_section_text * section_text); + + +static int +mailimap_sequence_num_send(mailstream * fd, uint32_t sequence_num); + + +static int mailimap_set_item_send(mailstream * fd, + struct mailimap_set_item * item); + + +static int mailimap_set_send(mailstream * fd, + struct mailimap_set * set); + + + +static int mailimap_status_att_send(mailstream * fd, int * status_att); + + + +static int +mailimap_store_att_flags_send(mailstream * fd, + struct mailimap_store_att_flags * store_flags); + + +static int mailimap_userid_send(mailstream * fd, const char * user); + + + + + + + + + + + + + + +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ + + + + + +static inline int mailimap_sized_token_send(mailstream * fd, const char * atom, + size_t len) +{ + if (mailstream_send_data_crlf(fd, atom, len, 0, NULL) == -1) + return MAILIMAP_ERROR_STREAM; + + return MAILIMAP_NO_ERROR; +} + +static int mailimap_token_send(mailstream * fd, const char * atom) +{ + return mailimap_sized_token_send(fd, atom, strlen(atom)); +} + +static int mailimap_char_send(mailstream * fd, char ch) +{ + if (mailstream_write(fd, &ch, 1) == -1) + return MAILIMAP_ERROR_STREAM; + + return MAILIMAP_NO_ERROR; +} + +typedef int mailimap_struct_sender(mailstream * fd, void * data); + +static int +mailimap_struct_list_send(mailstream * fd, clist * list, + char symbol, + mailimap_struct_sender * sender) +{ + clistiter * cur; + void * elt; + int r; + + cur = clist_begin(list); + + if (cur == NULL) + return MAILIMAP_NO_ERROR; + + elt = clist_content(cur); + r = (* sender)(fd, elt); + if (r != MAILIMAP_NO_ERROR) + return r; + cur = clist_next(cur); + + while (cur != NULL) { + r = mailimap_char_send(fd, symbol); + if (r != MAILIMAP_NO_ERROR) + return r; + elt = clist_content(cur); + r = (* sender)(fd, elt); + if (r != MAILIMAP_NO_ERROR) + return r; + cur = clist_next(cur); + } + + return MAILIMAP_NO_ERROR; +} + + +static int +mailimap_struct_spaced_list_send(mailstream * fd, clist * list, + mailimap_struct_sender * sender) +{ + return mailimap_struct_list_send(fd, list, ' ', sender); +} + +int mailimap_space_send(mailstream * fd) +{ + return mailimap_char_send(fd, ' '); +} + +int mailimap_crlf_send(mailstream * fd) +{ + int r; + + r = mailimap_char_send(fd, '\r'); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_char_send(fd, '\n'); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +static int mailimap_oparenth_send(mailstream * fd) +{ + return mailimap_char_send(fd, '('); +} + +static int mailimap_cparenth_send(mailstream * fd) +{ + return mailimap_char_send(fd, ')'); +} + +static int mailimap_dquote_send(mailstream * fd) +{ + return mailimap_char_send(fd, '"'); +} + +/* + address = "(" addr-name SP addr-adl SP addr-mailbox SP + addr-host ")" + + addr-adl = nstring + ; Holds route from [RFC-822] route-addr if + ; non-NIL + + addr-host = nstring + ; NIL indicates [RFC-822] group syntax. + ; Otherwise, holds [RFC-822] domain name + + addr-mailbox = nstring + ; NIL indicates end of [RFC-822] group; if + ; non-NIL and addr-host is NIL, holds + ; [RFC-822] group name. + ; Otherwise, holds [RFC-822] local-part + ; after removing [RFC-822] quoting + + addr-name = nstring + ; If non-NIL, holds phrase from [RFC-822] + ; mailbox after removing [RFC-822] quoting +*/ + +/* +=> append = "APPEND" SP mailbox [SP flag-list] [SP date-time] SP + literal +*/ + +int mailimap_append_send(mailstream * fd, + const char * mailbox, + struct mailimap_flag_list * flag_list, + struct mailimap_date_time * date_time, + size_t literal_size) +{ + int r; + + r = mailimap_token_send(fd, "APPEND"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_mailbox_send(fd, mailbox); + if (r != MAILIMAP_NO_ERROR) + return r; + if (flag_list != NULL) { + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_flag_list_send(fd, flag_list); + if (r != MAILIMAP_NO_ERROR) + return r; + } + if (date_time != NULL) { + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_date_time_send(fd, date_time); + if (r != MAILIMAP_NO_ERROR) + return r; + } + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_literal_count_send(fd, literal_size); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* + astring = 1*ASTRING-CHAR / string + +=> ASTRING-CHAR = ATOM-CHAR / resp-specials +*/ + +static int is_atom(const char * str) +{ + if (* str == '\0') + return 0; + + while (* str != '\0') { + unsigned char uch = (unsigned char) * str; + + if (!isalnum(uch)) + return 0; + + str ++; + } + + return 1; +} + +static int mailimap_astring_send(mailstream * fd, const char * astring) +{ + /* + workaround for buggy Courier-IMAP that does not accept + quoted-strings for fields name but prefer atoms. + */ + if (is_atom(astring)) + return mailimap_atom_send(fd, astring); + else + return mailimap_quoted_send(fd, astring); +} + +/* +=> atom = 1*ATOM-CHAR +*/ + +static int mailimap_atom_send(mailstream * fd, const char * atom) +{ + return mailimap_token_send(fd, atom); +} + +/* +=> ATOM-CHAR = <any CHAR except atom-specials> +*/ + +/* +=> atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / + quoted-specials / resp-specials +*/ + +/* +=> authenticate = "AUTHENTICATE" SP auth-type *(CRLF base64) +*/ + +int mailimap_authenticate_send(mailstream * fd, + const char * auth_type) +{ + int r; + + r = mailimap_token_send(fd, "AUTHENTICATE"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_auth_type_send(fd, auth_type); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +int mailimap_authenticate_resp_send(mailstream * fd, + const char * base64) +{ + int r; + + r = mailimap_base64_send(fd, base64); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> auth-type = atom + ; Defined by [SASL] +*/ + +static int mailimap_auth_type_send(mailstream * fd, const char * auth_type) +{ + return mailimap_atom_send(fd, auth_type); +} + + +/* +=> base64 = *(4base64-char) [base64-terminal] +*/ + +static int mailimap_base64_send(mailstream * fd, const char * base64) +{ + return mailimap_token_send(fd, base64); +} + +/* +=> base64-char = ALPHA / DIGIT / "+" / "/" + ; Case-sensitive + + base64-terminal = (2base64-char "==") / (3base64-char "=") + + body = "(" (body-type-1part / body-type-mpart) ")" + + body-extension = nstring / number / + "(" body-extension *(SP body-extension) ")" + ; Future expansion. Client implementations + ; MUST accept body-extension fields. Server + ; implementations MUST NOT generate + ; body-extension fields except as defined by + ; future standard or standards-track + ; revisions of this specification. + + body-ext-1part = body-fld-md5 [SP body-fld-dsp [SP body-fld-lang + *(SP body-extension)]] + ; MUST NOT be returned on non-extensible + ; "BODY" fetch + + body-ext-mpart = body-fld-param [SP body-fld-dsp [SP body-fld-lang + *(SP body-extension)]] + ; MUST NOT be returned on non-extensible + ; "BODY" fetch + + body-fields = body-fld-param SP body-fld-id SP body-fld-desc SP + body-fld-enc SP body-fld-octets + + body-fld-desc = nstring + + body-fld-dsp = "(" string SP body-fld-param ")" / nil + + body-fld-enc = (DQUOTE ("7BIT" / "8BIT" / "BINARY" / "BASE64"/ + "QUOTED-PRINTABLE") DQUOTE) / string + + body-fld-id = nstring + + body-fld-lang = nstring / "(" string *(SP string) ")" + + body-fld-lines = number + + body-fld-md5 = nstring + + body-fld-octets = number + + body-fld-param = "(" string SP string *(SP string SP string) ")" / nil + + body-type-1part = (body-type-basic / body-type-msg / body-type-text) + [SP body-ext-1part] + + body-type-basic = media-basic SP body-fields + ; MESSAGE subtype MUST NOT be "RFC822" + + body-type-mpart = 1*body SP media-subtype + [SP body-ext-mpart] + + body-type-msg = media-message SP body-fields SP envelope + SP body SP body-fld-lines + + body-type-text = media-text SP body-fields SP body-fld-lines + + capability = ("AUTH=" auth-type) / atom + ; New capabilities MUST begin with "X" or be + ; registered with IANA as standard or + ; standards-track + + capability-data = "CAPABILITY" *(SP capability) SP "IMAP4rev1" + *(SP capability) + ; IMAP4rev1 servers which offer RFC 1730 + ; compatibility MUST list "IMAP4" as the first + ; capability. + + CHAR8 = %x01-ff + ; any OCTET except NUL, %x00 +*/ + +/* +=> command = tag SP (command-any / command-auth / command-nonauth / + command-select) CRLF + ; Modal based on state +*/ + +/* +=> command-any = "CAPABILITY" / "LOGOUT" / "NOOP" / x-command + ; Valid in all states +*/ + +int mailimap_capability_send(mailstream * fd) +{ + int r; + + r = mailimap_token_send(fd, "CAPABILITY"); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +int mailimap_logout_send(mailstream * fd) +{ + int r; + + r = mailimap_token_send(fd, "LOGOUT"); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +int mailimap_noop_send(mailstream * fd) +{ + int r; + + r = mailimap_token_send(fd, "NOOP"); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> command-auth = append / create / delete / examine / list / lsub / + rename / select / status / subscribe / unsubscribe + ; Valid only in Authenticated or Selected state +*/ + +/* +=> command-nonauth = login / authenticate + ; Valid only when in Not Authenticated state +*/ + +/* +=> command-select = "CHECK" / "CLOSE" / "EXPUNGE" / copy / fetch / store / + uid / search + ; Valid only when in Selected state +*/ + +int mailimap_check_send(mailstream * fd) +{ + int r; + + r = mailimap_token_send(fd, "CHECK"); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +int mailimap_close_send(mailstream * fd) +{ + int r; + + r = mailimap_token_send(fd, "CLOSE"); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +int mailimap_expunge_send(mailstream * fd) +{ + int r; + + r = mailimap_token_send(fd, "EXPUNGE"); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* + continue-req = "+" SP (resp-text / base64) CRLF +*/ + +/* +=> copy = "COPY" SP set SP mailbox +*/ + +int mailimap_copy_send(mailstream * fd, + struct mailimap_set * set, + const char * mb) +{ + int r; + + r = mailimap_token_send(fd, "COPY"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_set_send(fd, set); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_mailbox_send(fd, mb); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +int mailimap_uid_copy_send(mailstream * fd, + struct mailimap_set * set, + const char * mb) +{ + int r; + + r = mailimap_token_send(fd, "UID"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + return mailimap_copy_send(fd, set, mb); +} + +/* +=> create = "CREATE" SP mailbox + ; Use of INBOX gives a NO error +*/ + +int mailimap_create_send(mailstream * fd, + const char * mb) +{ + int r; + + r = mailimap_token_send(fd, "CREATE"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_mailbox_send(fd, mb); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> date = date-text / DQUOTE date-text DQUOTE +*/ + +static int mailimap_date_send(mailstream * fd, + struct mailimap_date * date) +{ + int r; + + r = mailimap_date_day_send(fd, date->dt_day); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_char_send(fd, '-'); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_date_month_send(fd, date->dt_month); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_char_send(fd, '-'); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_date_year_send(fd, date->dt_year); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> date-day = 1*2DIGIT + ; Day of month +*/ + +static int mailimap_date_day_send(mailstream * fd, int day) +{ + return mailimap_number_send(fd, day); +} + +/* +=> date-day-fixed = (SP DIGIT) / 2DIGIT + ; Fixed-format version of date-day +*/ + +static int mailimap_date_day_fixed_send(mailstream * fd, int day) +{ + int r; + + if (day < 10) { + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_number_send(fd, day); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; + } + else + return mailimap_number_send(fd, day); +} + +/* +=> date-month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / + "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec" +*/ + +static int mailimap_date_month_send(mailstream * fd, int month) +{ + const char * name; + int r; + + name = mailimap_month_get_token_str(month); + + if (name == NULL) + return MAILIMAP_ERROR_INVAL; + + r = mailimap_token_send(fd, name); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> date-text = date-day "-" date-month "-" date-year +*/ + +/* +static gboolean mailimap_date_text_send(mailstream * fd, + struct mailimap_date_text * date_text) +{ + if (!mailimap_date_day_send(fd, date_text->day)) + return FALSE; + if (!mailimap_char_send(fd, '-')) + return FALSE; + if (!mailimap_date_month_send(fd, date_text->month)) + return FALSE; + if (!mailimap_char_send(fd, '-')) + return FALSE; + if (!mailimap_date_year_send(fd, date_text->year)) + return FALSE; + + return TRUE; +} +*/ + +/* +=> date-year = 4DIGIT +*/ + +static int mailimap_fixed_digit_send(mailstream * fd, + int num, int count) +{ + int r; + + r = mailimap_fixed_digit_send(fd, num / 10, count); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_digit_send(fd, num % 10); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +static int mailimap_date_year_send(mailstream *fd, int year) +{ + int r; + + r = mailimap_fixed_digit_send(fd, year, 4); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> date-time = DQUOTE date-day-fixed "-" date-month "-" date-year + SP time SP zone DQUOTE +*/ + +static int +mailimap_date_time_send(mailstream * fd, + struct mailimap_date_time * date_time) +{ + int r; + + r = mailimap_date_day_fixed_send(fd, date_time->dt_day); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_char_send(fd, '-'); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_date_month_send(fd, date_time->dt_month); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_char_send(fd, '-'); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_date_year_send(fd, date_time->dt_month); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_fixed_digit_send(fd, date_time->dt_hour, 2); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_char_send(fd, ':'); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_fixed_digit_send(fd, date_time->dt_min, 2); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_char_send(fd, ':'); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_fixed_digit_send(fd, date_time->dt_sec, 2); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> delete = "DELETE" SP mailbox + ; Use of INBOX gives a NO error +*/ + +int mailimap_delete_send(mailstream * fd, const char * mb) +{ + int r; + + r = mailimap_token_send(fd, "DELETE"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_mailbox_send(fd, mb); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* + +digit + +digit-nz = %x31-39 + ; 1-9 +*/ + +static int mailimap_digit_send(mailstream * fd, int digit) +{ + return mailimap_char_send(fd, digit + '0'); +} + + +/* + envelope = "(" env-date SP env-subject SP env-from SP env-sender SP + env-reply-to SP env-to SP env-cc SP env-bcc SP + env-in-reply-to SP env-message-id ")" + + env-bcc = "(" 1*address ")" / nil + + env-cc = "(" 1*address ")" / nil + + env-date = nstring + + env-from = "(" 1*address ")" / nil + + env-in-reply-to = nstring + + env-message-id = nstring + + env-reply-to = "(" 1*address ")" / nil + + env-sender = "(" 1*address ")" / nil + + env-subject = nstring + + env-to = "(" 1*address ")" / nil +*/ + +/* +=> examine = "EXAMINE" SP mailbox +*/ + +int mailimap_examine_send(mailstream * fd, const char * mb) +{ + int r; + + r = mailimap_token_send(fd, "EXAMINE"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_mailbox_send(fd, mb); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> fetch = "FETCH" SP set SP ("ALL" / "FULL" / "FAST" / fetch-att / + "(" fetch-att *(SP fetch-att) ")") +*/ + +static int +mailimap_fetch_att_list_send(mailstream * fd, clist * fetch_att_list); + +static int +mailimap_fetch_type_send(mailstream * fd, + struct mailimap_fetch_type * fetch_type) +{ + switch (fetch_type->ft_type) { + case MAILIMAP_FETCH_TYPE_ALL: + return mailimap_token_send(fd, "ALL"); + case MAILIMAP_FETCH_TYPE_FULL: + return mailimap_token_send(fd, "FULL"); + case MAILIMAP_FETCH_TYPE_FAST: + return mailimap_token_send(fd, "FAST"); + case MAILIMAP_FETCH_TYPE_FETCH_ATT: + return mailimap_fetch_att_send(fd, fetch_type->ft_data.ft_fetch_att); + case MAILIMAP_FETCH_TYPE_FETCH_ATT_LIST: + return mailimap_fetch_att_list_send(fd, + fetch_type->ft_data.ft_fetch_att_list); + default: + /* should not happen */ + return MAILIMAP_ERROR_INVAL; + } +} + +int mailimap_fetch_send(mailstream * fd, + struct mailimap_set * set, + struct mailimap_fetch_type * fetch_type) +{ + int r; + + r = mailimap_token_send(fd, "FETCH"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_set_send(fd, set); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_fetch_type_send(fd, fetch_type); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +int +mailimap_uid_fetch_send(mailstream * fd, + struct mailimap_set * set, + struct mailimap_fetch_type * fetch_type) +{ + int r; + + r = mailimap_token_send(fd, "UID"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + return mailimap_fetch_send(fd, set, fetch_type); +} + +/* currently porting */ + +static int +mailimap_fetch_att_list_send(mailstream * fd, clist * fetch_att_list) +{ + int r; + + r = mailimap_oparenth_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_struct_spaced_list_send(fd, fetch_att_list, + (mailimap_struct_sender *) + mailimap_fetch_att_send); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_cparenth_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> fetch-att = "ENVELOPE" / "FLAGS" / "INTERNALDATE" / + "RFC822" [".HEADER" / ".SIZE" / ".TEXT"] / + "BODY" ["STRUCTURE"] / "UID" / + "BODY" [".PEEK"] section ["<" number "." nz-number ">"] +*/ + +static int mailimap_fetch_att_send(mailstream * fd, + struct mailimap_fetch_att * fetch_att) +{ + int r; + + switch(fetch_att->att_type) { + case MAILIMAP_FETCH_ATT_ENVELOPE: + return mailimap_token_send(fd, "ENVELOPE"); + + case MAILIMAP_FETCH_ATT_FLAGS: + return mailimap_token_send(fd, "FLAGS"); + + case MAILIMAP_FETCH_ATT_INTERNALDATE: + return mailimap_token_send(fd, "INTERNALDATE"); + + case MAILIMAP_FETCH_ATT_RFC822: + return mailimap_token_send(fd, "RFC822"); + + case MAILIMAP_FETCH_ATT_RFC822_HEADER: + return mailimap_token_send(fd, "RFC822.HEADER"); + + case MAILIMAP_FETCH_ATT_RFC822_SIZE: + return mailimap_token_send(fd, "RFC822.SIZE"); + + case MAILIMAP_FETCH_ATT_RFC822_TEXT: + return mailimap_token_send(fd, "RFC822.TEXT"); + + case MAILIMAP_FETCH_ATT_BODY: + return mailimap_token_send(fd, "BODY"); + + case MAILIMAP_FETCH_ATT_BODYSTRUCTURE: + return mailimap_token_send(fd, "BODYSTRUCTURE"); + + case MAILIMAP_FETCH_ATT_UID: + return mailimap_token_send(fd, "UID"); + + case MAILIMAP_FETCH_ATT_BODY_SECTION: + + r = mailimap_token_send(fd, "BODY"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_section_send(fd, fetch_att->att_section); + if (r != MAILIMAP_NO_ERROR) + return r; + if (fetch_att->att_size != 0) { + r = mailimap_char_send(fd, '<'); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_number_send(fd, fetch_att->att_offset); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_char_send(fd, '.'); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_number_send(fd, fetch_att->att_size); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_char_send(fd, '>'); + if (r != MAILIMAP_NO_ERROR) + return r; + } + + return MAILIMAP_NO_ERROR; + + case MAILIMAP_FETCH_ATT_BODY_PEEK_SECTION: + r = mailimap_token_send(fd, "BODY.PEEK"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_section_send(fd, fetch_att->att_section); + if (r != MAILIMAP_NO_ERROR) + return r; + if (fetch_att->att_size != 0) { + r = mailimap_char_send(fd, '<'); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_number_send(fd, fetch_att->att_offset); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_char_send(fd, '.'); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_number_send(fd, fetch_att->att_size); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_char_send(fd, '>'); + if (r != MAILIMAP_NO_ERROR) + return r; + } + return MAILIMAP_NO_ERROR; + + default: + /* should not happen */ + return MAILIMAP_ERROR_INVAL; + } +} + +/* +=> flag = "\Answered" / "\Flagged" / "\Deleted" / + "\Seen" / "\Draft" / flag-keyword / flag-extension + ; Does not include "\Recent" +*/ + +/* +enum { + FLAG_ANSWERED, + FLAG_FLAGGED, + FLAG_DELETED, + FLAG_SEEN, + FLAG_DRAFT, + FLAG_KEYWORD, + FLAG_EXTENSION +}; + +struct mailimap_flag { + gint type; + gchar * flag_keyword; + gchar * flag_extension; +}; +*/ + +static int mailimap_flag_send(mailstream * fd, + struct mailimap_flag * flag) +{ + switch(flag->fl_type) { + case MAILIMAP_FLAG_ANSWERED: + return mailimap_token_send(fd, "\\Answered"); + case MAILIMAP_FLAG_FLAGGED: + return mailimap_token_send(fd, "\\Flagged"); + case MAILIMAP_FLAG_DELETED: + return mailimap_token_send(fd, "\\Deleted"); + case MAILIMAP_FLAG_SEEN: + return mailimap_token_send(fd, "\\Seen"); + case MAILIMAP_FLAG_DRAFT: + return mailimap_token_send(fd, "\\Draft"); + case MAILIMAP_FLAG_KEYWORD: + return mailimap_flag_keyword_send(fd, flag->fl_data.fl_keyword); + case MAILIMAP_FLAG_EXTENSION: + return mailimap_flag_extension_send(fd, flag->fl_data.fl_extension); + default: + /* should not happen */ + return MAILIMAP_ERROR_INVAL; + } +} + + +/* +=> flag-extension = "\" atom + ; Future expansion. Client implementations + ; MUST accept flag-extension flags. Server + ; implementations MUST NOT generate + ; flag-extension flags except as defined by + ; future standard or standards-track + ; revisions of this specification. +*/ + +static int mailimap_flag_extension_send(mailstream * fd, + const char * flag_extension) +{ + int r; + + r = mailimap_char_send(fd, '\\'); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_atom_send(fd, flag_extension); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* + flag-fetch = flag / "\Recent" +*/ + +/* +=> flag-keyword = atom +*/ + +static int mailimap_flag_keyword_send(mailstream * fd, + const char * flag_keyword) +{ + return mailimap_token_send(fd, flag_keyword); +} + +/* +=> flag-list = "(" [flag *(SP flag)] ")" +*/ + +static int mailimap_flag_list_send(mailstream * fd, + struct mailimap_flag_list * flag_list) +{ + int r; + + r = mailimap_oparenth_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + if (flag_list->fl_list != NULL) { + r = mailimap_struct_spaced_list_send(fd, flag_list->fl_list, + (mailimap_struct_sender *) mailimap_flag_send); + if (r != MAILIMAP_NO_ERROR) + return r; + } + + r = mailimap_cparenth_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* + flag-perm = flag / "\*" + + greeting = "*" SP (resp-cond-auth / resp-cond-bye) CRLF +*/ + +/* +=> header-fld-name = astring +*/ + +static int mailimap_header_fld_name_send(mailstream * fd, const char * header) +{ + return mailimap_astring_send(fd, header); +} + +/* +=> header-list = "(" header-fld-name *(SP header-fld-name) ")" +*/ + +static int +mailimap_header_list_send(mailstream * fd, + struct mailimap_header_list * header_list) +{ + int r; + + r = mailimap_oparenth_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_struct_spaced_list_send(fd, header_list->hdr_list, + (mailimap_struct_sender *) mailimap_header_fld_name_send); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_cparenth_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> list = "LIST" SP mailbox SP list-mailbox +*/ + +int mailimap_list_send(mailstream * fd, + const char * mb, + const char * list_mb) +{ + int r; + + r = mailimap_token_send(fd, "LIST"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_mailbox_send(fd, mb); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_list_mailbox_send(fd, list_mb); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> list-mailbox = 1*list-char / string +*/ + +static int +mailimap_list_mailbox_send(mailstream * fd, const char * pattern) +{ + return mailimap_quoted_send(fd, pattern); +} + +/* + list-char = ATOM-CHAR / list-wildcards / resp-specials + + list-wildcards = "%" / "*" +*/ + +/* +=> literal = "{" number "}" CRLF *CHAR8 + ; Number represents the number of CHAR8s +*/ + +int +mailimap_literal_send(mailstream * fd, const char * literal, + size_t progr_rate, + progress_function * progr_fun) +{ + size_t len; + uint32_t literal_len; + int r; + + len = strlen(literal); + literal_len = mailstream_get_data_crlf_size(literal, len); + + r = mailimap_literal_count_send(fd, literal_len); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_literal_data_send(fd, literal, len, progr_rate, progr_fun); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* + "{" number "}" CRLF +*/ + +int +mailimap_literal_count_send(mailstream * fd, uint32_t count) +{ + int r; + + r = mailimap_char_send(fd, '{'); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_number_send(fd, count); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_char_send(fd, '}'); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_crlf_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* + *CHAR8 +*/ + +int +mailimap_literal_data_send(mailstream * fd, const char * literal, uint32_t len, + size_t progr_rate, + progress_function * progr_fun) +{ + int r; + + r = mailimap_sized_token_send(fd, literal, len); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + + +/* +=> login = "LOGIN" SP userid SP password +*/ + +int mailimap_login_send(mailstream * fd, + const char * userid, const char * password) +{ + int r; + + r = mailimap_token_send(fd, "LOGIN"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_userid_send(fd, userid); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_password_send(fd, password); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> lsub = "LSUB" SP mailbox SP list-mailbox +*/ + +int mailimap_lsub_send(mailstream * fd, + const char * mb, const char * list_mb) +{ + int r; + + r = mailimap_token_send(fd, "LSUB"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_mailbox_send(fd, mb); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_list_mailbox_send(fd, list_mb); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* + mailbox = "INBOX" / astring + ; INBOX is case-insensitive. All case variants of + ; INBOX (e.g. "iNbOx") MUST be interpreted as INBOX + ; not as an astring. An astring which consists of + ; the case-insensitive sequence "I" "N" "B" "O" "X" + ; is considered to be INBOX and not an astring. + ; Refer to section 5.1 for further + ; semantic details of mailbox names. +*/ + +static int mailimap_mailbox_send(mailstream * fd, const char * mb) +{ + return mailimap_astring_send(fd, mb); +} + +/* + mailbox-data = "FLAGS" SP flag-list / "LIST" SP mailbox-list / + "LSUB" SP mailbox-list / "SEARCH" *(SP nz-number) / + "STATUS" SP mailbox SP "(" + [status-att SP number *(SP status-att SP number)] ")" / + number SP "EXISTS" / number SP "RECENT" + + mailbox-list = "(" [mbx-list-flags] ")" SP + (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox + + mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag + *(SP mbx-list-oflag) / + mbx-list-oflag *(SP mbx-list-oflag) + + mbx-list-oflag = "\Noinferiors" / flag-extension + ; Other flags; multiple possible per LIST response + + mbx-list-sflag = "\Noselect" / "\Marked" / "\Unmarked" + ; Selectability flags; only one per LIST response + + media-basic = ((DQUOTE ("APPLICATION" / "AUDIO" / "IMAGE" / "MESSAGE" / + "VIDEO") DQUOTE) / string) SP media-subtype + ; Defined in [MIME-IMT] + + media-message = DQUOTE "MESSAGE" DQUOTE SP DQUOTE "RFC822" DQUOTE + ; Defined in [MIME-IMT] + + media-subtype = string + ; Defined in [MIME-IMT] + + media-text = DQUOTE "TEXT" DQUOTE SP media-subtype + ; Defined in [MIME-IMT] + + message-data = nz-number SP ("EXPUNGE" / ("FETCH" SP msg-att)) + + msg-att = "(" (msg-att-dynamic / msg-att-static) + *(SP (msg-att-dynamic / msg-att-static)) ")" + + msg-att-dynamic = "FLAGS" SP "(" [flag-fetch *(SP flag-fetch)] ")" + ; MAY change for a message + + msg-att-static = "ENVELOPE" SP envelope / "INTERNALDATE" SP date-time / + "RFC822" [".HEADER" / ".TEXT"] SP nstring / + "RFC822.SIZE" SP number / "BODY" ["STRUCTURE"] SP body / + "BODY" section ["<" number ">"] SP nstring / + "UID" SP uniqueid + ; MUST NOT change for a message + + nil = "NIL" + + nstring = string / nil +*/ + +/* +=> number = 1*DIGIT + ; Unsigned 32-bit integer + ; (0 <= n < 4,294,967,296) +*/ + +/* + nz-number = digit-nz *DIGIT + ; Non-zero unsigned 32-bit integer + ; (0 < n < 4,294,967,296) +*/ + +static int mailimap_number_send(mailstream * fd, uint32_t number) +{ + int r; + + if (number / 10 != 0) { + r = mailimap_number_send(fd, number / 10); + if (r != MAILIMAP_NO_ERROR) + return r; + } + + r = mailimap_digit_send(fd, number % 10); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> password = astring +*/ + +static int mailimap_password_send(mailstream * fd, const char * pass) +{ + return mailimap_astring_send(fd, pass); +} + +/* +=> quoted = DQUOTE *QUOTED-CHAR DQUOTE + +=> QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / + "\" quoted-specials + +=> quoted-specials = DQUOTE / "\" +*/ + +static int is_quoted_specials(char ch) +{ + return (ch == '\"') || (ch == '\\'); +} + +static int mailimap_quoted_char_send(mailstream * fd, char ch) +{ + int r; + + if (is_quoted_specials(ch)) { + r = mailimap_char_send(fd, '\\'); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_char_send(fd, ch); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; + } + else + return mailimap_char_send(fd, ch); +} + +static int mailimap_quoted_send(mailstream * fd, const char * quoted) +{ + const char * pos; + int r; + + pos = quoted; + + r = mailimap_dquote_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + while (* pos != 0) { + r = mailimap_quoted_char_send(fd, * pos); + if (r != MAILIMAP_NO_ERROR) + return r; + pos ++; + } + + r = mailimap_dquote_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> rename = "RENAME" SP mailbox SP mailbox + ; Use of INBOX as a destination gives a NO error +*/ + +int mailimap_rename_send(mailstream * fd, const char * mb, + const char * new_name) +{ + int r; + + r = mailimap_token_send(fd, "RENAME"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_mailbox_send(fd, mb); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_mailbox_send(fd, new_name); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* + response = *(continue-req / response-data) response-done + + response-data = "*" SP (resp-cond-state / resp-cond-bye / + mailbox-data / message-data / capability-data) CRLF + + response-done = response-tagged / response-fatal + + response-fatal = "*" SP resp-cond-bye CRLF + ; Server closes connection immediately + + response-tagged = tag SP resp-cond-state CRLF + + resp-cond-auth = ("OK" / "PREAUTH") SP resp-text + ; Authentication condition + + resp-cond-bye = "BYE" SP resp-text + + resp-cond-state = ("OK" / "NO" / "BAD") SP resp-text + ; Status condition + + resp-specials = "]" + + resp-text = ["[" resp-text-code "]" SP] text + + resp-text-code = "ALERT" / + "BADCHARSET" [SP "(" astring *(SP astring) ")" ] / + capability-data / "PARSE" / + "PERMANENTFLAGS" SP "(" [flag-perm *(SP flag-perm)] ")" / + "READ-ONLY" / "READ-WRITE" / "TRYCREATE" / + "UIDNEXT" SP nz-number / "UIDVALIDITY" SP nz-number / + "UNSEEN" SP nz-number / + atom [SP 1*<any TEXT-CHAR except "]">] +*/ + +/* +=> search = "SEARCH" [SP "CHARSET" SP astring] 1*(SP search-key) + ; CHARSET argument to MUST be registered with IANA +*/ + +int +mailimap_search_send(mailstream * fd, const char * charset, + struct mailimap_search_key * key) +{ + int r; + + r = mailimap_token_send(fd, "SEARCH"); + if (r != MAILIMAP_NO_ERROR) + return r; + + if (charset != NULL) { + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_token_send(fd, "CHARSET"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_astring_send(fd, charset); + if (r != MAILIMAP_NO_ERROR) + return r; + } + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_search_key_send(fd, key); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +int +mailimap_uid_search_send(mailstream * fd, const char * charset, + struct mailimap_search_key * key) +{ + int r; + + r = mailimap_token_send(fd, "UID"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + return mailimap_search_send(fd, charset, key); +} + + +/* +=> search-key = "ALL" / "ANSWERED" / "BCC" SP astring / + "BEFORE" SP date / "BODY" SP astring / + "CC" SP astring / "DELETED" / "FLAGGED" / + "FROM" SP astring / "KEYWORD" SP flag-keyword / "NEW" / + "OLD" / "ON" SP date / "RECENT" / "SEEN" / + "SINCE" SP date / "SUBJECT" SP astring / + "TEXT" SP astring / "TO" SP astring / + "UNANSWERED" / "UNDELETED" / "UNFLAGGED" / + "UNKEYWORD" SP flag-keyword / "UNSEEN" / + ; Above this line were in [IMAP2] + "DRAFT" / "HEADER" SP header-fld-name SP astring / + "LARGER" SP number / "NOT" SP search-key / + "OR" SP search-key SP search-key / + "SENTBEFORE" SP date / "SENTON" SP date / + "SENTSINCE" SP date / "SMALLER" SP number / + "UID" SP set / "UNDRAFT" / set / + "(" search-key *(SP search-key) ")" +*/ + + +static int mailimap_search_key_send(mailstream * fd, + struct mailimap_search_key * key) +{ + int r; + + switch (key->sk_type) { + + case MAILIMAP_SEARCH_KEY_ALL: + return mailimap_token_send(fd, "ALL"); + + case MAILIMAP_SEARCH_KEY_ANSWERED: + return mailimap_token_send(fd, "ANSWERED"); + + case MAILIMAP_SEARCH_KEY_BCC: + r = mailimap_token_send(fd, "BCC"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_astring_send(fd, key->sk_data.sk_bcc); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_BEFORE: + r = mailimap_token_send(fd, "BEFORE"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_date_send(fd, key->sk_data.sk_before); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_BODY: + r = mailimap_token_send(fd, "BODY"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_astring_send(fd, key->sk_data.sk_body); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_CC: + r = mailimap_token_send(fd, "CC"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_astring_send(fd, key->sk_data.sk_cc); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_DELETED: + return mailimap_token_send(fd, "DELETED"); + + case MAILIMAP_SEARCH_KEY_FLAGGED: + return mailimap_token_send(fd, "FLAGGED"); + + case MAILIMAP_SEARCH_KEY_FROM: + r = mailimap_token_send(fd, "FROM"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_astring_send(fd, key->sk_data.sk_from); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_KEYWORD: + r = mailimap_token_send(fd, "KEYWORD"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_flag_keyword_send(fd, key->sk_data.sk_keyword); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_NEW: + return mailimap_token_send(fd, "NEW"); + + case MAILIMAP_SEARCH_KEY_OLD: + return mailimap_token_send(fd, "OLD"); + + case MAILIMAP_SEARCH_KEY_ON: + r = mailimap_token_send(fd, "ON"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_date_send(fd, key->sk_data.sk_on); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_RECENT: + return mailimap_token_send(fd, "RECENT"); + + case MAILIMAP_SEARCH_KEY_SEEN: + return mailimap_token_send(fd, "SEEN"); + + case MAILIMAP_SEARCH_KEY_SINCE: + r = mailimap_token_send(fd, "SINCE"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_date_send(fd, key->sk_data.sk_since); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_SUBJECT: + r = mailimap_token_send(fd, "SUBJECT"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_astring_send(fd, key->sk_data.sk_subject); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_TEXT: + r = mailimap_token_send(fd, "TEXT"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_astring_send(fd, key->sk_data.sk_text); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_TO: + r = mailimap_token_send(fd, "TO"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_astring_send(fd, key->sk_data.sk_text); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_UNANSWERED: + return mailimap_token_send(fd, "UNANSWERED"); + + case MAILIMAP_SEARCH_KEY_UNDELETED: + return mailimap_token_send(fd, "UNDELETED"); + + case MAILIMAP_SEARCH_KEY_UNFLAGGED: + return mailimap_token_send(fd, "UNFLAGGED"); + + case MAILIMAP_SEARCH_KEY_UNKEYWORD: + r = mailimap_token_send(fd, "UNKEYWORD"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_flag_keyword_send(fd, key->sk_data.sk_keyword); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_UNSEEN: + return mailimap_token_send(fd, "UNSEEN"); + + case MAILIMAP_SEARCH_KEY_DRAFT: + return mailimap_token_send(fd, "DRAFT"); + + case MAILIMAP_SEARCH_KEY_HEADER: + r = mailimap_token_send(fd, "HEADER"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_header_fld_name_send(fd, + key->sk_data.sk_header.sk_header_name); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_astring_send(fd, + key->sk_data.sk_header.sk_header_value); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_LARGER: + r = mailimap_token_send(fd, "LARGER"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_number_send(fd, key->sk_data.sk_larger); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_NOT: + r = mailimap_token_send(fd, "NOT"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_search_key_send(fd, key->sk_data.sk_not); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_OR: + r = mailimap_token_send(fd, "OR"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_search_key_send(fd, key->sk_data.sk_or.sk_or1); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_search_key_send(fd, key->sk_data.sk_or.sk_or2); + if (r != MAILIMAP_NO_ERROR) + return r; + return TRUE; + + case MAILIMAP_SEARCH_KEY_SENTBEFORE: + r = mailimap_token_send(fd, "SENTBEFORE"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_date_send(fd, key->sk_data.sk_sentbefore); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_SENTON: + r = mailimap_token_send(fd, "SENTON"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_date_send(fd, key->sk_data.sk_senton); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_SENTSINCE: + r = mailimap_token_send(fd, "SENTSINCE"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_date_send(fd, key->sk_data.sk_sentsince); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_SMALLER: + r = mailimap_token_send(fd, "SMALLER"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_number_send(fd, key->sk_data.sk_smaller); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_UID: + r = mailimap_token_send(fd, "UID"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_set_send(fd, key->sk_data.sk_set); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SEARCH_KEY_UNDRAFT: + return mailimap_token_send(fd, "UNDRAFT"); + + case MAILIMAP_SEARCH_KEY_SET: + return mailimap_set_send(fd, key->sk_data.sk_set); + + case MAILIMAP_SEARCH_KEY_MULTIPLE: + r = mailimap_oparenth_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_struct_spaced_list_send(fd, key->sk_data.sk_multiple, + (mailimap_struct_sender *) + mailimap_search_key_send); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_cparenth_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; + default: + /* should not happend */ + return MAILIMAP_ERROR_INVAL; + } +} + +/* +=> section = "[" [section-spec] "]" +*/ + +static int +mailimap_section_send(mailstream * fd, + struct mailimap_section * section) +{ + int r; + + r = mailimap_char_send(fd, '['); + if (r != MAILIMAP_NO_ERROR) + return r; + + if (section != NULL) { + if (section->sec_spec != NULL) { + r = mailimap_section_spec_send(fd, section->sec_spec); + if (r != MAILIMAP_NO_ERROR) + return r; + } + } + + r = mailimap_char_send(fd, ']'); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> section-msgtext = "HEADER" / "HEADER.FIELDS" [".NOT"] SP header-list / + "TEXT" + ; top-level or MESSAGE/RFC822 part +*/ + +static int +mailimap_section_msgtext_send(mailstream * fd, + struct mailimap_section_msgtext * + section_msgtext) +{ + int r; + + switch (section_msgtext->sec_type) { + case MAILIMAP_SECTION_MSGTEXT_HEADER: + return mailimap_token_send(fd, "HEADER"); + + case MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS: + r = mailimap_token_send(fd, "HEADER.FIELDS"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_header_list_send(fd, section_msgtext->sec_header_list); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS_NOT: + r = mailimap_token_send(fd, "HEADER.FIELDS.NOT"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_header_list_send(fd, section_msgtext->sec_header_list); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + + case MAILIMAP_SECTION_MSGTEXT_TEXT: + return mailimap_token_send(fd, "TEXT"); + + default: + /* should not happend */ + return MAILIMAP_ERROR_INVAL; + } +} + +/* +=> section-part = nz-number *("." nz-number) + ; body part nesting +*/ + +static int +mailimap_pnumber_send(mailstream * fd, uint32_t * pnumber) +{ + return mailimap_number_send(fd, * pnumber); +} + +static int +mailimap_section_part_send(mailstream * fd, + struct mailimap_section_part * section) +{ + int r; + + r = mailimap_struct_list_send(fd, section->sec_id, '.', + (mailimap_struct_sender *) mailimap_pnumber_send); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> section-spec = section-msgtext / (section-part ["." section-text]) +*/ + +static int +mailimap_section_spec_send(mailstream * fd, + struct mailimap_section_spec * section_spec) +{ + int r; + + switch (section_spec->sec_type) { + case MAILIMAP_SECTION_SPEC_SECTION_MSGTEXT: + return mailimap_section_msgtext_send(fd, + section_spec->sec_data.sec_msgtext); + + case MAILIMAP_SECTION_SPEC_SECTION_PART: + r = mailimap_section_part_send(fd, section_spec->sec_data.sec_part); + if (r != MAILIMAP_NO_ERROR) + return r; + + if (section_spec->sec_text != NULL) { + r = mailimap_char_send(fd, '.'); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_section_text_send(fd, + section_spec->sec_text); + if (r != MAILIMAP_NO_ERROR) + return r; + } + + return MAILIMAP_NO_ERROR; + + default: + /* should not happen */ + return MAILIMAP_ERROR_INVAL; + } +} + +/* +=> section-text = section-msgtext / "MIME" + ; text other than actual body part (headers, etc.) +*/ + +static int +mailimap_section_text_send(mailstream * fd, + struct mailimap_section_text * section_text) +{ + switch (section_text->sec_type) { + case MAILIMAP_SECTION_TEXT_SECTION_MSGTEXT: + return mailimap_section_msgtext_send(fd, section_text->sec_msgtext); + + case MAILIMAP_SECTION_TEXT_MIME: + return mailimap_token_send(fd, "MIME"); + + default: + /* should not happen */ + return MAILIMAP_NO_ERROR; + } +} + +/* +=> select = "SELECT" SP mailbox +*/ + +int +mailimap_select_send(mailstream * fd, const char * mb) +{ + int r; + + r = mailimap_token_send(fd, "SELECT"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_mailbox_send(fd, mb); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> sequence-num = nz-number / "*" + ; * is the largest number in use. For message + ; sequence numbers, it is the number of messages + ; in the mailbox. For unique identifiers, it is + ; the unique identifier of the last message in + ; the mailbox. +*/ + +/* if sequence_num == 0 then "*" */ + +static int +mailimap_sequence_num_send(mailstream * fd, uint32_t sequence_num) +{ + if (sequence_num == 0) + return mailimap_char_send(fd, '*'); + else + return mailimap_number_send(fd, sequence_num); +} + +/* +=> set = sequence-num / (sequence-num ":" sequence-num) / + (set "," set) + ; Identifies a set of messages. For message + ; sequence numbers, these are consecutive + ; numbers from 1 to the number of messages in + ; the mailbox + ; Comma delimits individual numbers, colon + ; delimits between two numbers inclusive. + ; Example: 2,4:7,9,12:* is 2,4,5,6,7,9,12,13, + ; 14,15 for a mailbox with 15 messages. +*/ + +static int mailimap_set_item_send(mailstream * fd, + struct mailimap_set_item * item) +{ + int r; + + if (item->set_first == item->set_last) + return mailimap_sequence_num_send(fd, item->set_first); + else { + r = mailimap_sequence_num_send(fd, item->set_first); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_char_send(fd, ':'); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_sequence_num_send(fd, item->set_last); + if (r != MAILIMAP_NO_ERROR) + return r; + return MAILIMAP_NO_ERROR; + } +} + +static int mailimap_set_send(mailstream * fd, + struct mailimap_set * set) +{ + return mailimap_struct_list_send(fd, set->set_list, ',', + (mailimap_struct_sender *) mailimap_set_item_send); +} + +/* +=> status = "STATUS" SP mailbox SP "(" status-att *(SP status-att) ")" +*/ + +static int +mailimap_status_att_list_send(mailstream * fd, + struct mailimap_status_att_list * status_att_list) +{ + return mailimap_struct_spaced_list_send(fd, status_att_list->att_list, + (mailimap_struct_sender *) mailimap_status_att_send); +} + +int +mailimap_status_send(mailstream * fd, const char * mb, + struct mailimap_status_att_list * status_att_list) +{ + int r; + + r = mailimap_token_send(fd, "STATUS"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_mailbox_send(fd, mb); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_char_send(fd, '('); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_status_att_list_send(fd, status_att_list); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_char_send(fd, ')'); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> status-att = "MESSAGES" / "RECENT" / "UIDNEXT" / "UIDVALIDITY" / + "UNSEEN" +*/ + + +static int mailimap_status_att_send(mailstream * fd, int * status_att) +{ + const char * token; + + token = mailimap_status_att_get_token_str(* status_att); + if (token == NULL) { + /* should not happen */ + return MAILIMAP_ERROR_INVAL; + } + + return mailimap_token_send(fd, token); +} + +/* +=> store = "STORE" SP set SP store-att-flags +*/ + +int +mailimap_store_send(mailstream * fd, + struct mailimap_set * set, + struct mailimap_store_att_flags * store_att_flags) +{ + int r; + + r = mailimap_token_send(fd, "STORE"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_set_send(fd, set); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_store_att_flags_send(fd, store_att_flags); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +int +mailimap_uid_store_send(mailstream * fd, + struct mailimap_set * set, + struct mailimap_store_att_flags * store_att_flags) +{ + int r; + + r = mailimap_token_send(fd, "UID"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + return mailimap_store_send(fd, set, store_att_flags); +} + +/* +=> store-att-flags = (["+" / "-"] "FLAGS" [".SILENT"]) SP + (flag-list / (flag *(SP flag))) +*/ + +static int +mailimap_store_att_flags_send(mailstream * fd, + struct mailimap_store_att_flags * store_flags) +{ + int r; + + switch (store_flags->fl_sign) { + case 1: + r = mailimap_char_send(fd, '+'); + if (r != MAILIMAP_NO_ERROR) + return r; + case -1: + r = mailimap_char_send(fd, '-'); + if (r != MAILIMAP_NO_ERROR) + return r; + } + + r = mailimap_token_send(fd, "FLAGS"); + if (r != MAILIMAP_NO_ERROR) + return r; + + if (store_flags->fl_silent) { + r = mailimap_token_send(fd, ".SILENT"); + if (r != MAILIMAP_NO_ERROR) + return r; + } + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_flag_list_send(fd, store_flags->fl_flag_list); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* + string = quoted / literal +*/ + +/* +=> subscribe = "SUBSCRIBE" SP mailbox +*/ + +int mailimap_subscribe_send(mailstream * fd, const char * mb) +{ + int r; + + r = mailimap_token_send(fd, "SUBSCRIBE"); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + + r = mailimap_mailbox_send(fd, mb); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +/* +=> tag = 1*<any ASTRING-CHAR except "+"> +*/ + +int mailimap_tag_send(mailstream * fd, const char * tag) +{ + return mailimap_token_send(fd, tag); +} + +/* + text = 1*TEXT-CHAR + + TEXT-CHAR = <any CHAR except CR and LF> + + time = 2DIGIT ":" 2DIGIT ":" 2DIGIT + ; Hours minutes seconds +*/ + +/* +=> uid = "UID" SP (copy / fetch / search / store) + ; Unique identifiers used instead of message + ; sequence numbers + +functions uid_copy, uid_fetch ... +*/ + + +/* + uniqueid = nz-number + ; Strictly ascending +*/ + +/* +=> unsubscribe = "UNSUBSCRIBE" SP mailbox +*/ + +int mailimap_unsubscribe_send(mailstream * fd, + const char * mb) +{ + int r; + + r = mailimap_token_send(fd, "UNSUBSCRIBE"); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_space_send(fd); + if (r != MAILIMAP_NO_ERROR) + return r; + r = mailimap_mailbox_send(fd, mb); + if (r != MAILIMAP_NO_ERROR) + return r; + + return MAILIMAP_NO_ERROR; +} + +int mailimap_starttls_send(mailstream * fd) +{ + return mailimap_token_send(fd, "STARTTLS"); +} + +/* +=> userid = astring +*/ + +static int mailimap_userid_send(mailstream * fd, const char * user) +{ + return mailimap_astring_send(fd, user); +} + +/* + x-command = "X" atom <experimental command arguments> + + zone = ("+" / "-") 4DIGIT + ; Signed four-digit value of hhmm representing + ; hours and minutes east of Greenwich (that is, + ; the amount that the given time differs from + ; Universal Time). Subtracting the timezone + ; from the given time will give the UT form. + ; The Universal Time zone is "+0000". +*/ |