libetpan - fdik
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

3265 lines
80 KiB

/*
* 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: mailimap_sender.c,v 1.32 2010/11/28 17:01:26 hoa Exp $
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "mailstream.h"
#include "mailimap_keywords.h"
#include "mailimap_sender.h"
#include "mailimap_parser.h"
#include "clist.h"
#include "mail.h"
#include "base64.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
/*
TODO :
implement progression for literal
*/
/* ************************************************************************* */
/* ************************************************************************* */
/* ************************************************************************* */
/* ************************************************************************* */
/* ************************************************************************* */
/* ************************************************************************* */
static int is_ascii(const char * str);
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_password_send(mailstream * fd, const char * pass);
static int mailimap_quoted_char_send(mailstream * fd, char ch);
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_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_astring_literalplus_send(mailstream * fd, const char * astring,
int literalplus_enabled);
static int
mailimap_literalplus_count_send(mailstream * fd, uint32_t count);
/* ************************************************************************* */
/* ************************************************************************* */
/* ************************************************************************* */
/* ************************************************************************* */
/* ************************************************************************* */
/* ************************************************************************* */
static inline int mailimap_sized_token_send_with_context(mailstream * fd, const char * atom,
size_t len,
mailprogress_function * progr_fun,
void * context);
static inline int mailimap_sized_token_send(mailstream * fd, const char * atom,
size_t len)
{
return mailimap_sized_token_send_with_context(fd, atom, len, NULL, NULL);
}
static inline int mailimap_sized_token_send_with_context(mailstream * fd, const char * atom,
size_t len,
mailprogress_function * progr_fun,
void * context)
{
if (mailstream_send_data_crlf_with_context(fd, atom, len, progr_fun, context) == -1)
return MAILIMAP_ERROR_STREAM;
return MAILIMAP_NO_ERROR;
}
int mailimap_token_send(mailstream * fd, const char * atom)
{
return mailimap_sized_token_send(fd, atom, strlen(atom));
}
int mailimap_char_send(mailstream * fd, char ch)
{
if (mailstream_write(fd, &ch, 1) == -1)
return MAILIMAP_ERROR_STREAM;
return MAILIMAP_NO_ERROR;
}
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;
}
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;
}
int mailimap_oparenth_send(mailstream * fd)
{
return mailimap_char_send(fd, '(');
}
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 (uch != '-') {
if (!isalnum(uch))
return 0;
}
str ++;
}
return 1;
}
static int mailimap_literalplus_send(mailstream * fd, const char * literal)
{
size_t len;
uint32_t literal_len;
int r;
len = strlen(literal);
literal_len = mailstream_get_data_crlf_size(literal, len);
r = mailimap_literalplus_count_send(fd, literal_len);
if (r != MAILIMAP_NO_ERROR)
return r;
r = mailimap_literal_data_send(fd, literal, literal_len, 0, NULL);
if (r != MAILIMAP_NO_ERROR)
return r;
return MAILIMAP_NO_ERROR;
}
static int mailimap_astring_literalplus_send(mailstream * fd, const char * astring,
int literalplus_enabled)
{
if (is_ascii(astring) || !literalplus_enabled) {
return mailimap_astring_send(fd, astring);
}
else {
return mailimap_literalplus_send(fd, astring);
}
}
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;
if (count == 0)
return MAILIMAP_NO_ERROR;
r = mailimap_fixed_digit_send(fd, num / 10, count - 1);
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;
int zone;
r = mailimap_dquote_send(fd);
if (r != MAILIMAP_NO_ERROR)
return 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_year);
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;
r = mailimap_space_send(fd);
if (r != MAILIMAP_NO_ERROR)
return r;
if (date_time->dt_zone < 0) {
r = mailimap_char_send(fd, '-');
if (r != MAILIMAP_NO_ERROR)
return r;
zone = -date_time->dt_zone;
}
else {
r = mailimap_char_send(fd, '+');
if (r != MAILIMAP_NO_ERROR)
return r;
zone = date_time->dt_zone;
}
r = mailimap_fixed_digit_send(fd, zone, 4);
if (r != MAILIMAP_NO_ERROR)
return r;
r = mailimap_dquote_send(fd);
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 condstore)
{
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;
if (condstore) {
r = mailimap_space_send(fd);
if (r != MAILIMAP_NO_ERROR)
return r;
r = mailimap_oparenth_send(fd);
if (r != MAILIMAP_NO_ERROR)
return r;
r = mailimap_token_send(fd, "CONDSTORE");
if (r != MAILIMAP_NO_ERROR)
return r;
r = mailimap_cparenth_send(fd);
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;
case MAILIMAP_FETCH_ATT_EXTENSION:
r = mailimap_token_send(fd, fetch_att->att_extension);
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
*/
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
*/
static int literal_count_send(mailstream * fd, uint32_t count, int literalplus_enabled)
{
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;
if (literalplus_enabled) {
r = mailimap_char_send(fd, '+');
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;
}
int
mailimap_literal_count_send(mailstream * fd, uint32_t count)
{
return literal_count_send(fd, count, 0);
}
static int
mailimap_literalplus_count_send(mailstream * fd, uint32_t count)
{
return literal_count_send(fd, count, 1);
}
/*
*CHAR8
*/
int
mailimap_literal_data_send(mailstream * fd, const char * literal, uint32_t len,
size_t progr_rate,
progress_function * progr_fun)
{
return mailimap_literal_data_send_with_context(fd, literal, len, NULL, NULL);
}
int
mailimap_literal_data_send_with_context(mailstream * fd, const char * literal, uint32_t len,
mailprogress_function * progr_fun,
void * context)
{
int r;
r = mailimap_sized_token_send_with_context(fd, literal, len, progr_fun, context);
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.
*/
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)
*/
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);
}
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;
}
static int is_ascii(const char * str)
{
const char * p = str;
while (* p != 0) {
if ((unsigned char) * p >= 128) {
return 0;
}
p ++;
}
return 1;
}
/*
=> 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_need_to_send_charset(struct mailimap_search_key * key)
{
clistiter * cur;
struct mailimap_search_key * elt;
int r;
switch (key->sk_type) {
case MAILIMAP_SEARCH_KEY_ALL:
return 0;
case MAILIMAP_SEARCH_KEY_ANSWERED:
return 0;
case MAILIMAP_SEARCH_KEY_BCC:
return !is_ascii(key->sk_data.sk_bcc);
case MAILIMAP_SEARCH_KEY_BEFORE:
return 0;
case MAILIMAP_SEARCH_KEY_BODY:
return !is_ascii(key->sk_data.sk_body);
case MAILIMAP_SEARCH_KEY_CC:
return !is_ascii(key->sk_data.sk_cc);
case MAILIMAP_SEARCH_KEY_DELETED:
return 0;
case MAILIMAP_SEARCH_KEY_FLAGGED:
return 0;
case MAILIMAP_SEARCH_KEY_FROM:
return !is_ascii(key->sk_data.sk_from);
case MAILIMAP_SEARCH_KEY_KEYWORD:
return !is_ascii(key->sk_data.sk_keyword);
case MAILIMAP_SEARCH_KEY_NEW:
return 0;
case MAILIMAP_SEARCH_KEY_OLD:
return 0;
case MAILIMAP_SEARCH_KEY_ON:
return 0;
case MAILIMAP_SEARCH_KEY_RECENT:
return 0;
case MAILIMAP_SEARCH_KEY_SEEN:
return 0;
case MAILIMAP_SEARCH_KEY_SINCE:
return 0;
case MAILIMAP_SEARCH_KEY_SUBJECT:
return !is_ascii(key->sk_data.sk_subject);
case MAILIMAP_SEARCH_KEY_TEXT:
return !is_ascii(key->sk_data.sk_text);
case MAILIMAP_SEARCH_KEY_TO:
return !is_ascii(key->sk_data.sk_to);
case MAILIMAP_SEARCH_KEY_UNANSWERED:
return 0;
case MAILIMAP_SEARCH_KEY_UNDELETED:
return 0;
case MAILIMAP_SEARCH_KEY_UNFLAGGED:
return 0;
case MAILIMAP_SEARCH_KEY_UNKEYWORD:
return !is_ascii(key->sk_data.sk_unkeyword);
case MAILIMAP_SEARCH_KEY_UNSEEN:
return 0;
case MAILIMAP_SEARCH_KEY_DRAFT:
return 0;
case MAILIMAP_SEARCH_KEY_HEADER:
return !is_ascii(key->sk_data.sk_header.sk_header_name) || !is_ascii(key->sk_data.sk_header.sk_header_value);
case MAILIMAP_SEARCH_KEY_LARGER:
return 0;
case MAILIMAP_SEARCH_KEY_NOT:
return mailimap_search_key_need_to_send_charset(key->sk_data.sk_not);
case MAILIMAP_SEARCH_KEY_OR:
return mailimap_search_key_need_to_send_charset(key->sk_data.sk_or.sk_or1) ||
mailimap_search_key_need_to_send_charset(key->sk_data.sk_or.sk_or2);
case MAILIMAP_SEARCH_KEY_SENTBEFORE:
return 0;
case MAILIMAP_SEARCH_KEY_SENTON:
return 0;
case MAILIMAP_SEARCH_KEY_SENTSINCE:
return 0;
case MAILIMAP_SEARCH_KEY_SMALLER:
return 0;
case MAILIMAP_SEARCH_KEY_UID:
return 0;
case MAILIMAP_SEARCH_KEY_UNDRAFT:
return 0;
case MAILIMAP_SEARCH_KEY_SET:
return 0;
case MAILIMAP_SEARCH_KEY_XGMTHRID:
return !is_ascii(key->sk_data.sk_xgmthrid);
case MAILIMAP_SEARCH_KEY_MULTIPLE:
{
cur = clist_begin(key->sk_data.sk_multiple);
if (cur == NULL)
return 0;
elt = (struct mailimap_search_key *) clist_content(cur);
r = mailimap_search_key_need_to_send_charset(elt);
if (r != 0)
return r;
cur = clist_next(cur);
while (cur != NULL) {
elt = (struct mailimap_search_key *) clist_content(cur);
r = mailimap_search_key_need_to_send_charset(elt);
if (r != 0)
return r;
cur = clist_next(cur);
}
return 0;
}
case MAILIMAP_SEARCH_KEY_MODSEQ:
return 0;
case MAILIMAP_SEARCH_KEY_XGMMSGID:
return !is_ascii(key->sk_data.sk_xgmmsgid);
default:
/* don't know, better send */
return 1;
}
}
/*
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;
int needToSendCharset = 1;
r = mailimap_token_send(fd, "SEARCH");
if (r != MAILIMAP_NO_ERROR)
return r;
needToSendCharset = mailimap_search_key_need_to_send_charset(key);
if (charset != NULL && needToSendCharset) {
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);
}
int mailimap_search_literalplus_send(mailstream * fd, const char * charset,
struct mailimap_search_key * key)
{
int r;
int needToSendCharset = 1;
r = mailimap_token_send(fd, "SEARCH");
if (r != MAILIMAP_NO_ERROR)
return r;
needToSendCharset = mailimap_search_key_need_to_send_charset(key);
if (charset != NULL && needToSendCharset) {
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_literalplus_send(fd, key);
if (r != MAILIMAP_NO_ERROR)
return r;
return MAILIMAP_NO_ERROR;
}
int mailimap_uid_search_literalplus_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_literalplus_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 search_key_send(mailstream * fd,
struct mailimap_search_key * key,
int literalplus_enabled)
{
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_literalplus_send(fd, key->sk_data.sk_bcc, literalplus_enabled);
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_literalplus_send(fd, key->sk_data.sk_body, literalplus_enabled);
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_literalplus_send(fd, key->sk_data.sk_cc, literalplus_enabled);
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_literalplus_send(fd, key->sk_data.sk_from, literalplus_enabled);
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_literalplus_send(fd, key->sk_data.sk_subject, literalplus_enabled);
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_literalplus_send(fd, key->sk_data.sk_text, literalplus_enabled);
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_literalplus_send(fd, key->sk_data.sk_text, literalplus_enabled);
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_astring_literalplus_send(fd, key->sk_data.sk_unkeyword, literalplus_enabled);
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_literalplus_send(fd, key->sk_data.sk_header.sk_header_value,
literalplus_enabled);
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 MAILIMAP_NO_ERROR;
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_XGMTHRID:
r = mailimap_token_send(fd, "X-GM-THRID");
if (r != MAILIMAP_NO_ERROR)
return r;
r = mailimap_space_send(fd);
if (r != MAILIMAP_NO_ERROR)
return r;
r = mailimap_uint64_send(fd, key->sk_data.sk_xgmthrid);
if (r != MAILIMAP_NO_ERROR)
return r;
return MAILIMAP_NO_ERROR;
case MAILIMAP_SEARCH_KEY_XGMMSGID:
r = mailimap_token_send(fd, "X-GM-MSGID");
if (r != MAILIMAP_NO_ERROR)
return r;
r = mailimap_space_send(fd);
if (r != MAILIMAP_NO_ERROR)
return r;
r = mailimap_uint64_send(fd, key->sk_data.sk_xgmmsgid);
if (r != MAILIMAP_NO_ERROR)
return r;
return MAILIMAP_NO_ERROR;
case MAILIMAP_SEARCH_KEY_XGMRAW:
r = mailimap_token_send(fd, "X-GM-RAW");
if (r != MAILIMAP_NO_ERROR)
return r;
r = mailimap_space_send(fd);
if (r != MAILIMAP_NO_ERROR)
return r;
r = mailimap_quoted_send(fd, key->sk_data.sk_xgmraw);
if (r != MAILIMAP_NO_ERROR)
return r;
return MAILIMAP_NO_ERROR;
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;
case MAILIMAP_SEARCH_KEY_MODSEQ:
r = mailimap_token_send(fd, "MODSEQ");
if (r != MAILIMAP_NO_ERROR)
return r;
if (key->sk_data.sk_modseq.sk_entry_name != NULL) {
r = mailimap_space_send(fd);
if (r != MAILIMAP_NO_ERROR)
return r;
mailimap_dquote_send(fd);
r = mailimap_token_send(fd, "/flags/");
if (r != MAILIMAP_NO_ERROR)
return r;
if (key->sk_data.sk_modseq.sk_entry_name->fl_type != MAILIMAP_FLAG_KEYWORD) {
r = mailimap_token_send(fd, "\\");
if (r != MAILIMAP_NO_ERROR)
return r;
}
r = mailimap_flag_send(fd, key->sk_data.sk_modseq.sk_entry_name);
if (r != MAILIMAP_NO_ERROR)
return r;
mailimap_dquote_send(fd);
r = mailimap_space_send(fd);
if (r != MAILIMAP_NO_ERROR)
return r;
switch (key->sk_data.sk_modseq.sk_entry_type_req) {
case MAILIMAP_SEARCH_KEY_MODSEQ_ENTRY_TYPE_REQ_PRIV:
r = mailimap_token_send(fd, "priv");
if (r != MAILIMAP_NO_ERROR)
return r;
break;
case MAILIMAP_SEARCH_KEY_MODSEQ_ENTRY_TYPE_REQ_SHARED:
r = mailimap_token_send(fd, "shared");
if (r != MAILIMAP_NO_ERROR)
return r;
break;
case MAILIMAP_SEARCH_KEY_MODSEQ_ENTRY_TYPE_REQ_ALL:
r = mailimap_token_send(fd, "all");
if (r != MAILIMAP_NO_ERROR)
return r;
break;
}
}
r = mailimap_space_send(fd);
if (r != MAILIMAP_NO_ERROR)
return r;
r = mailimap_mod_sequence_value_send(fd, key->sk_data.sk_modseq.sk_modseq_valzer);
if (r != MAILIMAP_NO_ERROR)
return r;
return MAILIMAP_NO_ERROR;
default:
/* should not happend */
return MAILIMAP_ERROR_INVAL;
}
}
int mailimap_search_key_send(mailstream * fd,
struct mailimap_search_key * key)
{
return search_key_send(fd, key, 0);
}
int mailimap_search_key_literalplus_send(mailstream * fd,
struct mailimap_search_key * key)
{
return search_key_send(fd, key, 1);
}
int mailimap_mod_sequence_value_send(mailstream * fd, uint64_t number)
{
return mailimap_uint64_send(fd, number);
}
int mailimap_uint64_send(mailstream * fd, uint64_t number)
{
char numberval[30];
snprintf(numberval, sizeof(numberval), "%llu", (long long unsigned) number);
return mailimap_token_send(fd, numberval);
}
/*
=> 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 condstore)
{
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;
if (condstore) {
r = mailimap_space_send(fd);
if (r != MAILIMAP_NO_ERROR)
return r;
r = mailimap_oparenth_send(fd);
if (r != MAILIMAP_NO_ERROR)
return r;
r = mailimap_token_send(fd, "CONDSTORE");
if (r != MAILIMAP_NO_ERROR)
return r;
r = mailimap_cparenth_send(fd);
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;
}
}
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, int use_unchangedsince, uint64_t mod_sequence_valzer,