/* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - 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 REGENTS 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 REGENTS 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 #include #include /* 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 int mailimap_sized_token_send(mailstream * fd, const char * atom, size_t len) { if (mailstream_write(fd, atom, len) == -1) return MAILIMAP_ERROR_STREAM; return MAILIMAP_NO_ERROR; } static int mailimap_token_send(mailstream * fd, const char * atom) { if (mailstream_write(fd, atom, strlen(atom)) == -1) return MAILIMAP_ERROR_STREAM; return MAILIMAP_NO_ERROR; } 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 = */ /* => 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) { uint32_t len; int r; len = strlen(literal); r = mailimap_literal_count_send(fd, 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 = / "\" 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*] */ /* => 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* */ int mailimap_tag_send(mailstream * fd, const char * tag) { return mailimap_token_send(fd, tag); } /* text = 1*TEXT-CHAR TEXT-CHAR = 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 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". */