summaryrefslogtreecommitdiffabout
path: root/libetpan/src/low-level/imap/mailimap_sender.c
Unidiff
Diffstat (limited to 'libetpan/src/low-level/imap/mailimap_sender.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/low-level/imap/mailimap_sender.c2742
1 files changed, 2742 insertions, 0 deletions
diff --git a/libetpan/src/low-level/imap/mailimap_sender.c b/libetpan/src/low-level/imap/mailimap_sender.c
new file mode 100644
index 0000000..caf86e5
--- a/dev/null
+++ b/libetpan/src/low-level/imap/mailimap_sender.c
@@ -0,0 +1,2742 @@
1/*
2 * libEtPan! -- a mail stuff library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#include "mailstream.h"
37#include "mailimap_keywords.h"
38#include "mailimap_sender.h"
39#include "clist.h"
40#include "mail.h"
41#include <string.h>
42
43#include <stdio.h>
44#include <ctype.h>
45
46/*
47 TODO :
48 implement progression for literal
49*/
50
51/* ************************************************************************* */
52/* ************************************************************************* */
53/* ************************************************************************* */
54/* ************************************************************************* */
55/* ************************************************************************* */
56/* ************************************************************************* */
57
58
59
60
61static int mailimap_atom_send(mailstream * fd, const char * atom);
62
63static int mailimap_auth_type_send(mailstream * fd, const char * auth_type);
64
65static int mailimap_base64_send(mailstream * fd, const char * base64);
66
67
68static int mailimap_date_send(mailstream * fd,
69 struct mailimap_date * date);
70
71static int mailimap_date_day_send(mailstream * fd, int day);
72
73static int mailimap_date_month_send(mailstream * fd, int month);
74
75
76/*
77static gboolean mailimap_date_text_send(mailstream * fd,
78 struct mailimap_date_text * date_text);
79*/
80
81
82static int mailimap_date_year_send(mailstream *fd, int year);
83
84static int
85mailimap_date_time_send(mailstream * fd,
86 struct mailimap_date_time * date_time);
87
88static int mailimap_digit_send(mailstream * fd, int digit);
89
90
91
92static int
93mailimap_fetch_type_send(mailstream * fd,
94 struct mailimap_fetch_type * fetch_type);
95
96
97static int mailimap_fetch_att_send(mailstream * fd,
98 struct mailimap_fetch_att * fetch_att);
99
100
101static int mailimap_flag_send(mailstream * fd,
102 struct mailimap_flag * flag);
103
104
105static int mailimap_flag_extension_send(mailstream * fd,
106 const char * flag_extension);
107
108
109static int mailimap_flag_keyword_send(mailstream * fd,
110 const char * flag_keyword);
111
112
113static int mailimap_flag_list_send(mailstream * fd,
114 struct mailimap_flag_list * flag_list);
115
116
117
118static int mailimap_header_fld_name_send(mailstream * fd, const char * header);
119
120
121static int
122mailimap_header_list_send(mailstream * fd,
123 struct mailimap_header_list * header_list);
124
125static int
126mailimap_list_mailbox_send(mailstream * fd, const char * pattern);
127
128
129static int mailimap_mailbox_send(mailstream * fd, const char * mb);
130
131static int mailimap_number_send(mailstream * fd, uint32_t number);
132
133static int mailimap_password_send(mailstream * fd, const char * pass);
134
135static int mailimap_quoted_char_send(mailstream * fd, char ch);
136
137static int mailimap_quoted_send(mailstream * fd, const char * quoted);
138
139
140static int mailimap_search_key_send(mailstream * fd,
141 struct mailimap_search_key * key);
142
143static int
144mailimap_section_send(mailstream * fd,
145 struct mailimap_section * section);
146
147static int
148mailimap_section_msgtext_send(mailstream * fd,
149 struct mailimap_section_msgtext *
150 section_msgtext);
151
152
153static int
154mailimap_section_part_send(mailstream * fd,
155 struct mailimap_section_part * section);
156
157
158static int
159mailimap_section_spec_send(mailstream * fd,
160 struct mailimap_section_spec * section_spec);
161
162
163static int
164mailimap_section_text_send(mailstream * fd,
165 struct mailimap_section_text * section_text);
166
167
168static int
169mailimap_sequence_num_send(mailstream * fd, uint32_t sequence_num);
170
171
172static int mailimap_set_item_send(mailstream * fd,
173 struct mailimap_set_item * item);
174
175
176static int mailimap_set_send(mailstream * fd,
177 struct mailimap_set * set);
178
179
180
181static int mailimap_status_att_send(mailstream * fd, int * status_att);
182
183
184
185static int
186mailimap_store_att_flags_send(mailstream * fd,
187 struct mailimap_store_att_flags * store_flags);
188
189
190static int mailimap_userid_send(mailstream * fd, const char * user);
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205/* ************************************************************************* */
206/* ************************************************************************* */
207/* ************************************************************************* */
208/* ************************************************************************* */
209/* ************************************************************************* */
210/* ************************************************************************* */
211
212
213
214
215
216static inline int mailimap_sized_token_send(mailstream * fd, const char * atom,
217 size_t len)
218{
219 if (mailstream_send_data_crlf(fd, atom, len, 0, NULL) == -1)
220 return MAILIMAP_ERROR_STREAM;
221
222 return MAILIMAP_NO_ERROR;
223}
224
225static int mailimap_token_send(mailstream * fd, const char * atom)
226{
227 return mailimap_sized_token_send(fd, atom, strlen(atom));
228}
229
230static int mailimap_char_send(mailstream * fd, char ch)
231{
232 if (mailstream_write(fd, &ch, 1) == -1)
233 return MAILIMAP_ERROR_STREAM;
234
235 return MAILIMAP_NO_ERROR;
236}
237
238typedef int mailimap_struct_sender(mailstream * fd, void * data);
239
240static int
241mailimap_struct_list_send(mailstream * fd, clist * list,
242 char symbol,
243 mailimap_struct_sender * sender)
244{
245 clistiter * cur;
246 void * elt;
247 int r;
248
249 cur = clist_begin(list);
250
251 if (cur == NULL)
252 return MAILIMAP_NO_ERROR;
253
254 elt = clist_content(cur);
255 r = (* sender)(fd, elt);
256 if (r != MAILIMAP_NO_ERROR)
257 return r;
258 cur = clist_next(cur);
259
260 while (cur != NULL) {
261 r = mailimap_char_send(fd, symbol);
262 if (r != MAILIMAP_NO_ERROR)
263 return r;
264 elt = clist_content(cur);
265 r = (* sender)(fd, elt);
266 if (r != MAILIMAP_NO_ERROR)
267 return r;
268 cur = clist_next(cur);
269 }
270
271 return MAILIMAP_NO_ERROR;
272}
273
274
275static int
276mailimap_struct_spaced_list_send(mailstream * fd, clist * list,
277 mailimap_struct_sender * sender)
278{
279 return mailimap_struct_list_send(fd, list, ' ', sender);
280}
281
282int mailimap_space_send(mailstream * fd)
283{
284 return mailimap_char_send(fd, ' ');
285}
286
287int mailimap_crlf_send(mailstream * fd)
288{
289 int r;
290
291 r = mailimap_char_send(fd, '\r');
292 if (r != MAILIMAP_NO_ERROR)
293 return r;
294 r = mailimap_char_send(fd, '\n');
295 if (r != MAILIMAP_NO_ERROR)
296 return r;
297
298 return MAILIMAP_NO_ERROR;
299}
300
301static int mailimap_oparenth_send(mailstream * fd)
302{
303 return mailimap_char_send(fd, '(');
304}
305
306static int mailimap_cparenth_send(mailstream * fd)
307{
308 return mailimap_char_send(fd, ')');
309}
310
311static int mailimap_dquote_send(mailstream * fd)
312{
313 return mailimap_char_send(fd, '"');
314}
315
316/*
317 address = "(" addr-name SP addr-adl SP addr-mailbox SP
318 addr-host ")"
319
320 addr-adl = nstring
321 ; Holds route from [RFC-822] route-addr if
322 ; non-NIL
323
324 addr-host = nstring
325 ; NIL indicates [RFC-822] group syntax.
326 ; Otherwise, holds [RFC-822] domain name
327
328 addr-mailbox = nstring
329 ; NIL indicates end of [RFC-822] group; if
330 ; non-NIL and addr-host is NIL, holds
331 ; [RFC-822] group name.
332 ; Otherwise, holds [RFC-822] local-part
333 ; after removing [RFC-822] quoting
334
335 addr-name = nstring
336 ; If non-NIL, holds phrase from [RFC-822]
337 ; mailbox after removing [RFC-822] quoting
338*/
339
340/*
341=> append = "APPEND" SP mailbox [SP flag-list] [SP date-time] SP
342 literal
343*/
344
345int mailimap_append_send(mailstream * fd,
346 const char * mailbox,
347 struct mailimap_flag_list * flag_list,
348 struct mailimap_date_time * date_time,
349 size_t literal_size)
350{
351 int r;
352
353 r = mailimap_token_send(fd, "APPEND");
354 if (r != MAILIMAP_NO_ERROR)
355 return r;
356 r = mailimap_space_send(fd);
357 if (r != MAILIMAP_NO_ERROR)
358 return r;
359 r = mailimap_mailbox_send(fd, mailbox);
360 if (r != MAILIMAP_NO_ERROR)
361 return r;
362 if (flag_list != NULL) {
363 r = mailimap_space_send(fd);
364 if (r != MAILIMAP_NO_ERROR)
365 return r;
366 r = mailimap_flag_list_send(fd, flag_list);
367 if (r != MAILIMAP_NO_ERROR)
368 return r;
369 }
370 if (date_time != NULL) {
371 r = mailimap_space_send(fd);
372 if (r != MAILIMAP_NO_ERROR)
373 return r;
374 r = mailimap_date_time_send(fd, date_time);
375 if (r != MAILIMAP_NO_ERROR)
376 return r;
377 }
378
379 r = mailimap_space_send(fd);
380 if (r != MAILIMAP_NO_ERROR)
381 return r;
382 r = mailimap_literal_count_send(fd, literal_size);
383 if (r != MAILIMAP_NO_ERROR)
384 return r;
385
386 return MAILIMAP_NO_ERROR;
387}
388
389/*
390 astring = 1*ASTRING-CHAR / string
391
392=> ASTRING-CHAR = ATOM-CHAR / resp-specials
393*/
394
395static int is_atom(const char * str)
396{
397 if (* str == '\0')
398 return 0;
399
400 while (* str != '\0') {
401 unsigned char uch = (unsigned char) * str;
402
403 if (!isalnum(uch))
404 return 0;
405
406 str ++;
407 }
408
409 return 1;
410}
411
412static int mailimap_astring_send(mailstream * fd, const char * astring)
413{
414 /*
415 workaround for buggy Courier-IMAP that does not accept
416 quoted-strings for fields name but prefer atoms.
417 */
418 if (is_atom(astring))
419 return mailimap_atom_send(fd, astring);
420 else
421 return mailimap_quoted_send(fd, astring);
422}
423
424/*
425=> atom = 1*ATOM-CHAR
426*/
427
428static int mailimap_atom_send(mailstream * fd, const char * atom)
429{
430 return mailimap_token_send(fd, atom);
431}
432
433/*
434=> ATOM-CHAR = <any CHAR except atom-specials>
435*/
436
437/*
438=> atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards /
439 quoted-specials / resp-specials
440*/
441
442/*
443=> authenticate = "AUTHENTICATE" SP auth-type *(CRLF base64)
444*/
445
446int mailimap_authenticate_send(mailstream * fd,
447 const char * auth_type)
448{
449 int r;
450
451 r = mailimap_token_send(fd, "AUTHENTICATE");
452 if (r != MAILIMAP_NO_ERROR)
453 return r;
454 r = mailimap_space_send(fd);
455 if (r != MAILIMAP_NO_ERROR)
456 return r;
457 r = mailimap_auth_type_send(fd, auth_type);
458 if (r != MAILIMAP_NO_ERROR)
459 return r;
460
461 return MAILIMAP_NO_ERROR;
462}
463
464int mailimap_authenticate_resp_send(mailstream * fd,
465 const char * base64)
466{
467 int r;
468
469 r = mailimap_base64_send(fd, base64);
470 if (r != MAILIMAP_NO_ERROR)
471 return r;
472
473 return MAILIMAP_NO_ERROR;
474}
475
476/*
477=> auth-type = atom
478 ; Defined by [SASL]
479*/
480
481static int mailimap_auth_type_send(mailstream * fd, const char * auth_type)
482{
483 return mailimap_atom_send(fd, auth_type);
484}
485
486
487/*
488=> base64 = *(4base64-char) [base64-terminal]
489*/
490
491static int mailimap_base64_send(mailstream * fd, const char * base64)
492{
493 return mailimap_token_send(fd, base64);
494}
495
496/*
497=> base64-char = ALPHA / DIGIT / "+" / "/"
498 ; Case-sensitive
499
500 base64-terminal = (2base64-char "==") / (3base64-char "=")
501
502 body = "(" (body-type-1part / body-type-mpart) ")"
503
504 body-extension = nstring / number /
505 "(" body-extension *(SP body-extension) ")"
506 ; Future expansion. Client implementations
507 ; MUST accept body-extension fields. Server
508 ; implementations MUST NOT generate
509 ; body-extension fields except as defined by
510 ; future standard or standards-track
511 ; revisions of this specification.
512
513 body-ext-1part = body-fld-md5 [SP body-fld-dsp [SP body-fld-lang
514 *(SP body-extension)]]
515 ; MUST NOT be returned on non-extensible
516 ; "BODY" fetch
517
518 body-ext-mpart = body-fld-param [SP body-fld-dsp [SP body-fld-lang
519 *(SP body-extension)]]
520 ; MUST NOT be returned on non-extensible
521 ; "BODY" fetch
522
523 body-fields = body-fld-param SP body-fld-id SP body-fld-desc SP
524 body-fld-enc SP body-fld-octets
525
526 body-fld-desc = nstring
527
528 body-fld-dsp = "(" string SP body-fld-param ")" / nil
529
530 body-fld-enc = (DQUOTE ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
531 "QUOTED-PRINTABLE") DQUOTE) / string
532
533 body-fld-id = nstring
534
535 body-fld-lang = nstring / "(" string *(SP string) ")"
536
537 body-fld-lines = number
538
539 body-fld-md5 = nstring
540
541 body-fld-octets = number
542
543 body-fld-param = "(" string SP string *(SP string SP string) ")" / nil
544
545 body-type-1part = (body-type-basic / body-type-msg / body-type-text)
546 [SP body-ext-1part]
547
548 body-type-basic = media-basic SP body-fields
549 ; MESSAGE subtype MUST NOT be "RFC822"
550
551 body-type-mpart = 1*body SP media-subtype
552 [SP body-ext-mpart]
553
554 body-type-msg = media-message SP body-fields SP envelope
555 SP body SP body-fld-lines
556
557 body-type-text = media-text SP body-fields SP body-fld-lines
558
559 capability = ("AUTH=" auth-type) / atom
560 ; New capabilities MUST begin with "X" or be
561 ; registered with IANA as standard or
562 ; standards-track
563
564 capability-data = "CAPABILITY" *(SP capability) SP "IMAP4rev1"
565 *(SP capability)
566 ; IMAP4rev1 servers which offer RFC 1730
567 ; compatibility MUST list "IMAP4" as the first
568 ; capability.
569
570 CHAR8 = %x01-ff
571 ; any OCTET except NUL, %x00
572*/
573
574/*
575=> command = tag SP (command-any / command-auth / command-nonauth /
576 command-select) CRLF
577 ; Modal based on state
578*/
579
580/*
581=> command-any = "CAPABILITY" / "LOGOUT" / "NOOP" / x-command
582 ; Valid in all states
583*/
584
585int mailimap_capability_send(mailstream * fd)
586{
587 int r;
588
589 r = mailimap_token_send(fd, "CAPABILITY");
590 if (r != MAILIMAP_NO_ERROR)
591 return r;
592
593 return MAILIMAP_NO_ERROR;
594}
595
596int mailimap_logout_send(mailstream * fd)
597{
598 int r;
599
600 r = mailimap_token_send(fd, "LOGOUT");
601 if (r != MAILIMAP_NO_ERROR)
602 return r;
603
604 return MAILIMAP_NO_ERROR;
605}
606
607int mailimap_noop_send(mailstream * fd)
608{
609 int r;
610
611 r = mailimap_token_send(fd, "NOOP");
612 if (r != MAILIMAP_NO_ERROR)
613 return r;
614
615 return MAILIMAP_NO_ERROR;
616}
617
618/*
619=> command-auth = append / create / delete / examine / list / lsub /
620 rename / select / status / subscribe / unsubscribe
621 ; Valid only in Authenticated or Selected state
622*/
623
624/*
625=> command-nonauth = login / authenticate
626 ; Valid only when in Not Authenticated state
627*/
628
629/*
630=> command-select = "CHECK" / "CLOSE" / "EXPUNGE" / copy / fetch / store /
631 uid / search
632 ; Valid only when in Selected state
633*/
634
635int mailimap_check_send(mailstream * fd)
636{
637 int r;
638
639 r = mailimap_token_send(fd, "CHECK");
640 if (r != MAILIMAP_NO_ERROR)
641 return r;
642
643 return MAILIMAP_NO_ERROR;
644}
645
646int mailimap_close_send(mailstream * fd)
647{
648 int r;
649
650 r = mailimap_token_send(fd, "CLOSE");
651 if (r != MAILIMAP_NO_ERROR)
652 return r;
653
654 return MAILIMAP_NO_ERROR;
655}
656
657int mailimap_expunge_send(mailstream * fd)
658{
659 int r;
660
661 r = mailimap_token_send(fd, "EXPUNGE");
662 if (r != MAILIMAP_NO_ERROR)
663 return r;
664
665 return MAILIMAP_NO_ERROR;
666}
667
668/*
669 continue-req = "+" SP (resp-text / base64) CRLF
670*/
671
672/*
673=> copy = "COPY" SP set SP mailbox
674*/
675
676int mailimap_copy_send(mailstream * fd,
677 struct mailimap_set * set,
678 const char * mb)
679{
680 int r;
681
682 r = mailimap_token_send(fd, "COPY");
683 if (r != MAILIMAP_NO_ERROR)
684 return r;
685
686 r = mailimap_space_send(fd);
687 if (r != MAILIMAP_NO_ERROR)
688 return r;
689
690 r = mailimap_set_send(fd, set);
691 if (r != MAILIMAP_NO_ERROR)
692 return r;
693
694 r = mailimap_space_send(fd);
695 if (r != MAILIMAP_NO_ERROR)
696 return r;
697
698 r = mailimap_mailbox_send(fd, mb);
699 if (r != MAILIMAP_NO_ERROR)
700 return r;
701
702 return MAILIMAP_NO_ERROR;
703}
704
705int mailimap_uid_copy_send(mailstream * fd,
706 struct mailimap_set * set,
707 const char * mb)
708{
709 int r;
710
711 r = mailimap_token_send(fd, "UID");
712 if (r != MAILIMAP_NO_ERROR)
713 return r;
714
715 r = mailimap_space_send(fd);
716 if (r != MAILIMAP_NO_ERROR)
717 return r;
718
719 return mailimap_copy_send(fd, set, mb);
720}
721
722/*
723=> create = "CREATE" SP mailbox
724 ; Use of INBOX gives a NO error
725*/
726
727int mailimap_create_send(mailstream * fd,
728 const char * mb)
729{
730 int r;
731
732 r = mailimap_token_send(fd, "CREATE");
733 if (r != MAILIMAP_NO_ERROR)
734 return r;
735
736 r = mailimap_space_send(fd);
737 if (r != MAILIMAP_NO_ERROR)
738 return r;
739
740 r = mailimap_mailbox_send(fd, mb);
741 if (r != MAILIMAP_NO_ERROR)
742 return r;
743
744 return MAILIMAP_NO_ERROR;
745}
746
747/*
748=> date = date-text / DQUOTE date-text DQUOTE
749*/
750
751static int mailimap_date_send(mailstream * fd,
752 struct mailimap_date * date)
753{
754 int r;
755
756 r = mailimap_date_day_send(fd, date->dt_day);
757 if (r != MAILIMAP_NO_ERROR)
758 return r;
759
760 r = mailimap_char_send(fd, '-');
761 if (r != MAILIMAP_NO_ERROR)
762 return r;
763
764 r = mailimap_date_month_send(fd, date->dt_month);
765 if (r != MAILIMAP_NO_ERROR)
766 return r;
767
768 r = mailimap_char_send(fd, '-');
769 if (r != MAILIMAP_NO_ERROR)
770 return r;
771
772 r = mailimap_date_year_send(fd, date->dt_year);
773 if (r != MAILIMAP_NO_ERROR)
774 return r;
775
776 return MAILIMAP_NO_ERROR;
777}
778
779/*
780=> date-day = 1*2DIGIT
781 ; Day of month
782*/
783
784static int mailimap_date_day_send(mailstream * fd, int day)
785{
786 return mailimap_number_send(fd, day);
787}
788
789/*
790=> date-day-fixed = (SP DIGIT) / 2DIGIT
791 ; Fixed-format version of date-day
792*/
793
794static int mailimap_date_day_fixed_send(mailstream * fd, int day)
795{
796 int r;
797
798 if (day < 10) {
799 r = mailimap_space_send(fd);
800 if (r != MAILIMAP_NO_ERROR)
801 return r;
802
803 r = mailimap_number_send(fd, day);
804 if (r != MAILIMAP_NO_ERROR)
805 return r;
806
807 return MAILIMAP_NO_ERROR;
808 }
809 else
810 return mailimap_number_send(fd, day);
811}
812
813/*
814=> date-month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
815 "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
816*/
817
818static int mailimap_date_month_send(mailstream * fd, int month)
819{
820 const char * name;
821 int r;
822
823 name = mailimap_month_get_token_str(month);
824
825 if (name == NULL)
826 return MAILIMAP_ERROR_INVAL;
827
828 r = mailimap_token_send(fd, name);
829 if (r != MAILIMAP_NO_ERROR)
830 return r;
831
832 return MAILIMAP_NO_ERROR;
833}
834
835/*
836=> date-text = date-day "-" date-month "-" date-year
837*/
838
839/*
840static gboolean mailimap_date_text_send(mailstream * fd,
841 struct mailimap_date_text * date_text)
842{
843 if (!mailimap_date_day_send(fd, date_text->day))
844 return FALSE;
845 if (!mailimap_char_send(fd, '-'))
846 return FALSE;
847 if (!mailimap_date_month_send(fd, date_text->month))
848 return FALSE;
849 if (!mailimap_char_send(fd, '-'))
850 return FALSE;
851 if (!mailimap_date_year_send(fd, date_text->year))
852 return FALSE;
853
854 return TRUE;
855}
856*/
857
858/*
859=> date-year = 4DIGIT
860*/
861
862static int mailimap_fixed_digit_send(mailstream * fd,
863 int num, int count)
864{
865 int r;
866
867 r = mailimap_fixed_digit_send(fd, num / 10, count);
868 if (r != MAILIMAP_NO_ERROR)
869 return r;
870
871 r = mailimap_digit_send(fd, num % 10);
872 if (r != MAILIMAP_NO_ERROR)
873 return r;
874
875 return MAILIMAP_NO_ERROR;
876}
877
878static int mailimap_date_year_send(mailstream *fd, int year)
879{
880 int r;
881
882 r = mailimap_fixed_digit_send(fd, year, 4);
883 if (r != MAILIMAP_NO_ERROR)
884 return r;
885
886 return MAILIMAP_NO_ERROR;
887}
888
889/*
890=> date-time = DQUOTE date-day-fixed "-" date-month "-" date-year
891 SP time SP zone DQUOTE
892*/
893
894static int
895mailimap_date_time_send(mailstream * fd,
896 struct mailimap_date_time * date_time)
897{
898 int r;
899
900 r = mailimap_date_day_fixed_send(fd, date_time->dt_day);
901 if (r != MAILIMAP_NO_ERROR)
902 return r;
903
904 r = mailimap_char_send(fd, '-');
905 if (r != MAILIMAP_NO_ERROR)
906 return r;
907
908 r = mailimap_date_month_send(fd, date_time->dt_month);
909 if (r != MAILIMAP_NO_ERROR)
910 return r;
911
912 r = mailimap_char_send(fd, '-');
913 if (r != MAILIMAP_NO_ERROR)
914 return r;
915
916 r = mailimap_date_year_send(fd, date_time->dt_month);
917 if (r != MAILIMAP_NO_ERROR)
918 return r;
919
920 r = mailimap_space_send(fd);
921 if (r != MAILIMAP_NO_ERROR)
922 return r;
923
924 r = mailimap_fixed_digit_send(fd, date_time->dt_hour, 2);
925 if (r != MAILIMAP_NO_ERROR)
926 return r;
927
928 r = mailimap_char_send(fd, ':');
929 if (r != MAILIMAP_NO_ERROR)
930 return r;
931
932 r = mailimap_fixed_digit_send(fd, date_time->dt_min, 2);
933 if (r != MAILIMAP_NO_ERROR)
934 return r;
935
936 r = mailimap_char_send(fd, ':');
937 if (r != MAILIMAP_NO_ERROR)
938 return r;
939
940 r = mailimap_fixed_digit_send(fd, date_time->dt_sec, 2);
941 if (r != MAILIMAP_NO_ERROR)
942 return r;
943
944 return MAILIMAP_NO_ERROR;
945}
946
947/*
948=> delete = "DELETE" SP mailbox
949 ; Use of INBOX gives a NO error
950*/
951
952int mailimap_delete_send(mailstream * fd, const char * mb)
953{
954 int r;
955
956 r = mailimap_token_send(fd, "DELETE");
957 if (r != MAILIMAP_NO_ERROR)
958 return r;
959
960 r = mailimap_space_send(fd);
961 if (r != MAILIMAP_NO_ERROR)
962 return r;
963
964 r = mailimap_mailbox_send(fd, mb);
965 if (r != MAILIMAP_NO_ERROR)
966 return r;
967
968 return MAILIMAP_NO_ERROR;
969}
970
971/*
972
973digit
974
975digit-nz = %x31-39
976 ; 1-9
977*/
978
979static int mailimap_digit_send(mailstream * fd, int digit)
980{
981 return mailimap_char_send(fd, digit + '0');
982}
983
984
985/*
986 envelope = "(" env-date SP env-subject SP env-from SP env-sender SP
987 env-reply-to SP env-to SP env-cc SP env-bcc SP
988 env-in-reply-to SP env-message-id ")"
989
990 env-bcc = "(" 1*address ")" / nil
991
992 env-cc = "(" 1*address ")" / nil
993
994 env-date = nstring
995
996 env-from = "(" 1*address ")" / nil
997
998 env-in-reply-to = nstring
999
1000 env-message-id = nstring
1001
1002 env-reply-to = "(" 1*address ")" / nil
1003
1004 env-sender = "(" 1*address ")" / nil
1005
1006 env-subject = nstring
1007
1008 env-to = "(" 1*address ")" / nil
1009*/
1010
1011/*
1012=> examine = "EXAMINE" SP mailbox
1013*/
1014
1015int mailimap_examine_send(mailstream * fd, const char * mb)
1016{
1017 int r;
1018
1019 r = mailimap_token_send(fd, "EXAMINE");
1020 if (r != MAILIMAP_NO_ERROR)
1021 return r;
1022
1023 r = mailimap_space_send(fd);
1024 if (r != MAILIMAP_NO_ERROR)
1025 return r;
1026
1027 r = mailimap_mailbox_send(fd, mb);
1028 if (r != MAILIMAP_NO_ERROR)
1029 return r;
1030
1031 return MAILIMAP_NO_ERROR;
1032}
1033
1034/*
1035=> fetch = "FETCH" SP set SP ("ALL" / "FULL" / "FAST" / fetch-att /
1036 "(" fetch-att *(SP fetch-att) ")")
1037*/
1038
1039static int
1040mailimap_fetch_att_list_send(mailstream * fd, clist * fetch_att_list);
1041
1042static int
1043mailimap_fetch_type_send(mailstream * fd,
1044 struct mailimap_fetch_type * fetch_type)
1045{
1046 switch (fetch_type->ft_type) {
1047 case MAILIMAP_FETCH_TYPE_ALL:
1048 return mailimap_token_send(fd, "ALL");
1049 case MAILIMAP_FETCH_TYPE_FULL:
1050 return mailimap_token_send(fd, "FULL");
1051 case MAILIMAP_FETCH_TYPE_FAST:
1052 return mailimap_token_send(fd, "FAST");
1053 case MAILIMAP_FETCH_TYPE_FETCH_ATT:
1054 return mailimap_fetch_att_send(fd, fetch_type->ft_data.ft_fetch_att);
1055 case MAILIMAP_FETCH_TYPE_FETCH_ATT_LIST:
1056 return mailimap_fetch_att_list_send(fd,
1057 fetch_type->ft_data.ft_fetch_att_list);
1058 default:
1059 /* should not happen */
1060 return MAILIMAP_ERROR_INVAL;
1061 }
1062}
1063
1064int mailimap_fetch_send(mailstream * fd,
1065 struct mailimap_set * set,
1066 struct mailimap_fetch_type * fetch_type)
1067{
1068 int r;
1069
1070 r = mailimap_token_send(fd, "FETCH");
1071 if (r != MAILIMAP_NO_ERROR)
1072 return r;
1073
1074 r = mailimap_space_send(fd);
1075 if (r != MAILIMAP_NO_ERROR)
1076 return r;
1077
1078 r = mailimap_set_send(fd, set);
1079 if (r != MAILIMAP_NO_ERROR)
1080 return r;
1081
1082 r = mailimap_space_send(fd);
1083 if (r != MAILIMAP_NO_ERROR)
1084 return r;
1085
1086 r = mailimap_fetch_type_send(fd, fetch_type);
1087 if (r != MAILIMAP_NO_ERROR)
1088 return r;
1089
1090 return MAILIMAP_NO_ERROR;
1091}
1092
1093int
1094mailimap_uid_fetch_send(mailstream * fd,
1095 struct mailimap_set * set,
1096 struct mailimap_fetch_type * fetch_type)
1097{
1098 int r;
1099
1100 r = mailimap_token_send(fd, "UID");
1101 if (r != MAILIMAP_NO_ERROR)
1102 return r;
1103
1104 r = mailimap_space_send(fd);
1105 if (r != MAILIMAP_NO_ERROR)
1106 return r;
1107
1108 return mailimap_fetch_send(fd, set, fetch_type);
1109}
1110
1111/* currently porting */
1112
1113static int
1114mailimap_fetch_att_list_send(mailstream * fd, clist * fetch_att_list)
1115{
1116 int r;
1117
1118 r = mailimap_oparenth_send(fd);
1119 if (r != MAILIMAP_NO_ERROR)
1120 return r;
1121
1122 r = mailimap_struct_spaced_list_send(fd, fetch_att_list,
1123 (mailimap_struct_sender *)
1124 mailimap_fetch_att_send);
1125 if (r != MAILIMAP_NO_ERROR)
1126 return r;
1127
1128 r = mailimap_cparenth_send(fd);
1129 if (r != MAILIMAP_NO_ERROR)
1130 return r;
1131
1132 return MAILIMAP_NO_ERROR;
1133}
1134
1135/*
1136=> fetch-att = "ENVELOPE" / "FLAGS" / "INTERNALDATE" /
1137 "RFC822" [".HEADER" / ".SIZE" / ".TEXT"] /
1138 "BODY" ["STRUCTURE"] / "UID" /
1139 "BODY" [".PEEK"] section ["<" number "." nz-number ">"]
1140*/
1141
1142static int mailimap_fetch_att_send(mailstream * fd,
1143 struct mailimap_fetch_att * fetch_att)
1144{
1145 int r;
1146
1147 switch(fetch_att->att_type) {
1148 case MAILIMAP_FETCH_ATT_ENVELOPE:
1149 return mailimap_token_send(fd, "ENVELOPE");
1150
1151 case MAILIMAP_FETCH_ATT_FLAGS:
1152 return mailimap_token_send(fd, "FLAGS");
1153
1154 case MAILIMAP_FETCH_ATT_INTERNALDATE:
1155 return mailimap_token_send(fd, "INTERNALDATE");
1156
1157 case MAILIMAP_FETCH_ATT_RFC822:
1158 return mailimap_token_send(fd, "RFC822");
1159
1160 case MAILIMAP_FETCH_ATT_RFC822_HEADER:
1161 return mailimap_token_send(fd, "RFC822.HEADER");
1162
1163 case MAILIMAP_FETCH_ATT_RFC822_SIZE:
1164 return mailimap_token_send(fd, "RFC822.SIZE");
1165
1166 case MAILIMAP_FETCH_ATT_RFC822_TEXT:
1167 return mailimap_token_send(fd, "RFC822.TEXT");
1168
1169 case MAILIMAP_FETCH_ATT_BODY:
1170 return mailimap_token_send(fd, "BODY");
1171
1172 case MAILIMAP_FETCH_ATT_BODYSTRUCTURE:
1173 return mailimap_token_send(fd, "BODYSTRUCTURE");
1174
1175 case MAILIMAP_FETCH_ATT_UID:
1176 return mailimap_token_send(fd, "UID");
1177
1178 case MAILIMAP_FETCH_ATT_BODY_SECTION:
1179
1180 r = mailimap_token_send(fd, "BODY");
1181 if (r != MAILIMAP_NO_ERROR)
1182 return r;
1183 r = mailimap_section_send(fd, fetch_att->att_section);
1184 if (r != MAILIMAP_NO_ERROR)
1185 return r;
1186 if (fetch_att->att_size != 0) {
1187 r = mailimap_char_send(fd, '<');
1188 if (r != MAILIMAP_NO_ERROR)
1189 return r;
1190 r = mailimap_number_send(fd, fetch_att->att_offset);
1191 if (r != MAILIMAP_NO_ERROR)
1192 return r;
1193 r = mailimap_char_send(fd, '.');
1194 if (r != MAILIMAP_NO_ERROR)
1195 return r;
1196 r = mailimap_number_send(fd, fetch_att->att_size);
1197 if (r != MAILIMAP_NO_ERROR)
1198 return r;
1199 r = mailimap_char_send(fd, '>');
1200 if (r != MAILIMAP_NO_ERROR)
1201 return r;
1202 }
1203
1204 return MAILIMAP_NO_ERROR;
1205
1206 case MAILIMAP_FETCH_ATT_BODY_PEEK_SECTION:
1207 r = mailimap_token_send(fd, "BODY.PEEK");
1208 if (r != MAILIMAP_NO_ERROR)
1209 return r;
1210 r = mailimap_section_send(fd, fetch_att->att_section);
1211 if (r != MAILIMAP_NO_ERROR)
1212 return r;
1213 if (fetch_att->att_size != 0) {
1214 r = mailimap_char_send(fd, '<');
1215 if (r != MAILIMAP_NO_ERROR)
1216 return r;
1217 r = mailimap_number_send(fd, fetch_att->att_offset);
1218 if (r != MAILIMAP_NO_ERROR)
1219 return r;
1220 r = mailimap_char_send(fd, '.');
1221 if (r != MAILIMAP_NO_ERROR)
1222 return r;
1223 r = mailimap_number_send(fd, fetch_att->att_size);
1224 if (r != MAILIMAP_NO_ERROR)
1225 return r;
1226 r = mailimap_char_send(fd, '>');
1227 if (r != MAILIMAP_NO_ERROR)
1228 return r;
1229 }
1230 return MAILIMAP_NO_ERROR;
1231
1232 default:
1233 /* should not happen */
1234 return MAILIMAP_ERROR_INVAL;
1235 }
1236}
1237
1238/*
1239=> flag = "\Answered" / "\Flagged" / "\Deleted" /
1240 "\Seen" / "\Draft" / flag-keyword / flag-extension
1241 ; Does not include "\Recent"
1242*/
1243
1244/*
1245enum {
1246 FLAG_ANSWERED,
1247 FLAG_FLAGGED,
1248 FLAG_DELETED,
1249 FLAG_SEEN,
1250 FLAG_DRAFT,
1251 FLAG_KEYWORD,
1252 FLAG_EXTENSION
1253};
1254
1255struct mailimap_flag {
1256 gint type;
1257 gchar * flag_keyword;
1258 gchar * flag_extension;
1259};
1260*/
1261
1262static int mailimap_flag_send(mailstream * fd,
1263 struct mailimap_flag * flag)
1264{
1265 switch(flag->fl_type) {
1266 case MAILIMAP_FLAG_ANSWERED:
1267 return mailimap_token_send(fd, "\\Answered");
1268 case MAILIMAP_FLAG_FLAGGED:
1269 return mailimap_token_send(fd, "\\Flagged");
1270 case MAILIMAP_FLAG_DELETED:
1271 return mailimap_token_send(fd, "\\Deleted");
1272 case MAILIMAP_FLAG_SEEN:
1273 return mailimap_token_send(fd, "\\Seen");
1274 case MAILIMAP_FLAG_DRAFT:
1275 return mailimap_token_send(fd, "\\Draft");
1276 case MAILIMAP_FLAG_KEYWORD:
1277 return mailimap_flag_keyword_send(fd, flag->fl_data.fl_keyword);
1278 case MAILIMAP_FLAG_EXTENSION:
1279 return mailimap_flag_extension_send(fd, flag->fl_data.fl_extension);
1280 default:
1281 /* should not happen */
1282 return MAILIMAP_ERROR_INVAL;
1283 }
1284}
1285
1286
1287/*
1288=> flag-extension = "\" atom
1289 ; Future expansion. Client implementations
1290 ; MUST accept flag-extension flags. Server
1291 ; implementations MUST NOT generate
1292 ; flag-extension flags except as defined by
1293 ; future standard or standards-track
1294 ; revisions of this specification.
1295*/
1296
1297static int mailimap_flag_extension_send(mailstream * fd,
1298 const char * flag_extension)
1299{
1300 int r;
1301
1302 r = mailimap_char_send(fd, '\\');
1303 if (r != MAILIMAP_NO_ERROR)
1304 return r;
1305
1306 r = mailimap_atom_send(fd, flag_extension);
1307 if (r != MAILIMAP_NO_ERROR)
1308 return r;
1309
1310 return MAILIMAP_NO_ERROR;
1311}
1312
1313/*
1314 flag-fetch = flag / "\Recent"
1315*/
1316
1317/*
1318=> flag-keyword = atom
1319*/
1320
1321static int mailimap_flag_keyword_send(mailstream * fd,
1322 const char * flag_keyword)
1323{
1324 return mailimap_token_send(fd, flag_keyword);
1325}
1326
1327/*
1328=> flag-list = "(" [flag *(SP flag)] ")"
1329*/
1330
1331static int mailimap_flag_list_send(mailstream * fd,
1332 struct mailimap_flag_list * flag_list)
1333{
1334 int r;
1335
1336 r = mailimap_oparenth_send(fd);
1337 if (r != MAILIMAP_NO_ERROR)
1338 return r;
1339
1340 if (flag_list->fl_list != NULL) {
1341 r = mailimap_struct_spaced_list_send(fd, flag_list->fl_list,
1342 (mailimap_struct_sender *) mailimap_flag_send);
1343 if (r != MAILIMAP_NO_ERROR)
1344 return r;
1345 }
1346
1347 r = mailimap_cparenth_send(fd);
1348 if (r != MAILIMAP_NO_ERROR)
1349 return r;
1350
1351 return MAILIMAP_NO_ERROR;
1352}
1353
1354/*
1355 flag-perm = flag / "\*"
1356
1357 greeting = "*" SP (resp-cond-auth / resp-cond-bye) CRLF
1358*/
1359
1360/*
1361=> header-fld-name = astring
1362*/
1363
1364static int mailimap_header_fld_name_send(mailstream * fd, const char * header)
1365{
1366 return mailimap_astring_send(fd, header);
1367}
1368
1369/*
1370=> header-list = "(" header-fld-name *(SP header-fld-name) ")"
1371*/
1372
1373static int
1374mailimap_header_list_send(mailstream * fd,
1375 struct mailimap_header_list * header_list)
1376{
1377 int r;
1378
1379 r = mailimap_oparenth_send(fd);
1380 if (r != MAILIMAP_NO_ERROR)
1381 return r;
1382
1383 r = mailimap_struct_spaced_list_send(fd, header_list->hdr_list,
1384 (mailimap_struct_sender *) mailimap_header_fld_name_send);
1385 if (r != MAILIMAP_NO_ERROR)
1386 return r;
1387
1388 r = mailimap_cparenth_send(fd);
1389 if (r != MAILIMAP_NO_ERROR)
1390 return r;
1391
1392 return MAILIMAP_NO_ERROR;
1393}
1394
1395/*
1396=> list = "LIST" SP mailbox SP list-mailbox
1397*/
1398
1399int mailimap_list_send(mailstream * fd,
1400 const char * mb,
1401 const char * list_mb)
1402{
1403 int r;
1404
1405 r = mailimap_token_send(fd, "LIST");
1406 if (r != MAILIMAP_NO_ERROR)
1407 return r;
1408
1409 r = mailimap_space_send(fd);
1410 if (r != MAILIMAP_NO_ERROR)
1411 return r;
1412
1413 r = mailimap_mailbox_send(fd, mb);
1414 if (r != MAILIMAP_NO_ERROR)
1415 return r;
1416
1417 r = mailimap_space_send(fd);
1418 if (r != MAILIMAP_NO_ERROR)
1419 return r;
1420
1421 r = mailimap_list_mailbox_send(fd, list_mb);
1422 if (r != MAILIMAP_NO_ERROR)
1423 return r;
1424
1425 return MAILIMAP_NO_ERROR;
1426}
1427
1428/*
1429=> list-mailbox = 1*list-char / string
1430*/
1431
1432static int
1433mailimap_list_mailbox_send(mailstream * fd, const char * pattern)
1434{
1435 return mailimap_quoted_send(fd, pattern);
1436}
1437
1438/*
1439 list-char = ATOM-CHAR / list-wildcards / resp-specials
1440
1441 list-wildcards = "%" / "*"
1442*/
1443
1444/*
1445=> literal = "{" number "}" CRLF *CHAR8
1446 ; Number represents the number of CHAR8s
1447*/
1448
1449int
1450mailimap_literal_send(mailstream * fd, const char * literal,
1451 size_t progr_rate,
1452 progress_function * progr_fun)
1453{
1454 size_t len;
1455 uint32_t literal_len;
1456 int r;
1457
1458 len = strlen(literal);
1459 literal_len = mailstream_get_data_crlf_size(literal, len);
1460
1461 r = mailimap_literal_count_send(fd, literal_len);
1462 if (r != MAILIMAP_NO_ERROR)
1463 return r;
1464 r = mailimap_literal_data_send(fd, literal, len, progr_rate, progr_fun);
1465 if (r != MAILIMAP_NO_ERROR)
1466 return r;
1467
1468 return MAILIMAP_NO_ERROR;
1469}
1470
1471/*
1472 "{" number "}" CRLF
1473*/
1474
1475int
1476mailimap_literal_count_send(mailstream * fd, uint32_t count)
1477{
1478 int r;
1479
1480 r = mailimap_char_send(fd, '{');
1481 if (r != MAILIMAP_NO_ERROR)
1482 return r;
1483
1484 r = mailimap_number_send(fd, count);
1485 if (r != MAILIMAP_NO_ERROR)
1486 return r;
1487
1488 r = mailimap_char_send(fd, '}');
1489 if (r != MAILIMAP_NO_ERROR)
1490 return r;
1491
1492 r = mailimap_crlf_send(fd);
1493 if (r != MAILIMAP_NO_ERROR)
1494 return r;
1495
1496 return MAILIMAP_NO_ERROR;
1497}
1498
1499/*
1500 *CHAR8
1501*/
1502
1503int
1504mailimap_literal_data_send(mailstream * fd, const char * literal, uint32_t len,
1505 size_t progr_rate,
1506 progress_function * progr_fun)
1507{
1508 int r;
1509
1510 r = mailimap_sized_token_send(fd, literal, len);
1511 if (r != MAILIMAP_NO_ERROR)
1512 return r;
1513
1514 return MAILIMAP_NO_ERROR;
1515}
1516
1517
1518/*
1519=> login = "LOGIN" SP userid SP password
1520*/
1521
1522int mailimap_login_send(mailstream * fd,
1523 const char * userid, const char * password)
1524{
1525 int r;
1526
1527 r = mailimap_token_send(fd, "LOGIN");
1528 if (r != MAILIMAP_NO_ERROR)
1529 return r;
1530
1531 r = mailimap_space_send(fd);
1532 if (r != MAILIMAP_NO_ERROR)
1533 return r;
1534
1535 r = mailimap_userid_send(fd, userid);
1536 if (r != MAILIMAP_NO_ERROR)
1537 return r;
1538
1539 r = mailimap_space_send(fd);
1540 if (r != MAILIMAP_NO_ERROR)
1541 return r;
1542
1543 r = mailimap_password_send(fd, password);
1544 if (r != MAILIMAP_NO_ERROR)
1545 return r;
1546
1547 return MAILIMAP_NO_ERROR;
1548}
1549
1550/*
1551=> lsub = "LSUB" SP mailbox SP list-mailbox
1552*/
1553
1554int mailimap_lsub_send(mailstream * fd,
1555 const char * mb, const char * list_mb)
1556{
1557 int r;
1558
1559 r = mailimap_token_send(fd, "LSUB");
1560 if (r != MAILIMAP_NO_ERROR)
1561 return r;
1562
1563 r = mailimap_space_send(fd);
1564 if (r != MAILIMAP_NO_ERROR)
1565 return r;
1566
1567 r = mailimap_mailbox_send(fd, mb);
1568 if (r != MAILIMAP_NO_ERROR)
1569 return r;
1570
1571 r = mailimap_space_send(fd);
1572 if (r != MAILIMAP_NO_ERROR)
1573 return r;
1574
1575 r = mailimap_list_mailbox_send(fd, list_mb);
1576 if (r != MAILIMAP_NO_ERROR)
1577 return r;
1578
1579 return MAILIMAP_NO_ERROR;
1580}
1581
1582/*
1583 mailbox = "INBOX" / astring
1584 ; INBOX is case-insensitive. All case variants of
1585 ; INBOX (e.g. "iNbOx") MUST be interpreted as INBOX
1586 ; not as an astring. An astring which consists of
1587 ; the case-insensitive sequence "I" "N" "B" "O" "X"
1588 ; is considered to be INBOX and not an astring.
1589 ; Refer to section 5.1 for further
1590 ; semantic details of mailbox names.
1591*/
1592
1593static int mailimap_mailbox_send(mailstream * fd, const char * mb)
1594{
1595 return mailimap_astring_send(fd, mb);
1596}
1597
1598/*
1599 mailbox-data = "FLAGS" SP flag-list / "LIST" SP mailbox-list /
1600 "LSUB" SP mailbox-list / "SEARCH" *(SP nz-number) /
1601 "STATUS" SP mailbox SP "("
1602 [status-att SP number *(SP status-att SP number)] ")" /
1603 number SP "EXISTS" / number SP "RECENT"
1604
1605 mailbox-list = "(" [mbx-list-flags] ")" SP
1606 (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox
1607
1608 mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag
1609 *(SP mbx-list-oflag) /
1610 mbx-list-oflag *(SP mbx-list-oflag)
1611
1612 mbx-list-oflag = "\Noinferiors" / flag-extension
1613 ; Other flags; multiple possible per LIST response
1614
1615 mbx-list-sflag = "\Noselect" / "\Marked" / "\Unmarked"
1616 ; Selectability flags; only one per LIST response
1617
1618 media-basic = ((DQUOTE ("APPLICATION" / "AUDIO" / "IMAGE" / "MESSAGE" /
1619 "VIDEO") DQUOTE) / string) SP media-subtype
1620 ; Defined in [MIME-IMT]
1621
1622 media-message = DQUOTE "MESSAGE" DQUOTE SP DQUOTE "RFC822" DQUOTE
1623 ; Defined in [MIME-IMT]
1624
1625 media-subtype = string
1626 ; Defined in [MIME-IMT]
1627
1628 media-text = DQUOTE "TEXT" DQUOTE SP media-subtype
1629 ; Defined in [MIME-IMT]
1630
1631 message-data = nz-number SP ("EXPUNGE" / ("FETCH" SP msg-att))
1632
1633 msg-att = "(" (msg-att-dynamic / msg-att-static)
1634 *(SP (msg-att-dynamic / msg-att-static)) ")"
1635
1636 msg-att-dynamic = "FLAGS" SP "(" [flag-fetch *(SP flag-fetch)] ")"
1637 ; MAY change for a message
1638
1639 msg-att-static = "ENVELOPE" SP envelope / "INTERNALDATE" SP date-time /
1640 "RFC822" [".HEADER" / ".TEXT"] SP nstring /
1641 "RFC822.SIZE" SP number / "BODY" ["STRUCTURE"] SP body /
1642 "BODY" section ["<" number ">"] SP nstring /
1643 "UID" SP uniqueid
1644 ; MUST NOT change for a message
1645
1646 nil = "NIL"
1647
1648 nstring = string / nil
1649*/
1650
1651/*
1652=> number = 1*DIGIT
1653 ; Unsigned 32-bit integer
1654 ; (0 <= n < 4,294,967,296)
1655*/
1656
1657/*
1658 nz-number = digit-nz *DIGIT
1659 ; Non-zero unsigned 32-bit integer
1660 ; (0 < n < 4,294,967,296)
1661*/
1662
1663static int mailimap_number_send(mailstream * fd, uint32_t number)
1664{
1665 int r;
1666
1667 if (number / 10 != 0) {
1668 r = mailimap_number_send(fd, number / 10);
1669 if (r != MAILIMAP_NO_ERROR)
1670 return r;
1671 }
1672
1673 r = mailimap_digit_send(fd, number % 10);
1674 if (r != MAILIMAP_NO_ERROR)
1675 return r;
1676
1677 return MAILIMAP_NO_ERROR;
1678}
1679
1680/*
1681=> password = astring
1682*/
1683
1684static int mailimap_password_send(mailstream * fd, const char * pass)
1685{
1686 return mailimap_astring_send(fd, pass);
1687}
1688
1689/*
1690=> quoted = DQUOTE *QUOTED-CHAR DQUOTE
1691
1692=> QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> /
1693 "\" quoted-specials
1694
1695=> quoted-specials = DQUOTE / "\"
1696*/
1697
1698static int is_quoted_specials(char ch)
1699{
1700 return (ch == '\"') || (ch == '\\');
1701}
1702
1703static int mailimap_quoted_char_send(mailstream * fd, char ch)
1704{
1705 int r;
1706
1707 if (is_quoted_specials(ch)) {
1708 r = mailimap_char_send(fd, '\\');
1709 if (r != MAILIMAP_NO_ERROR)
1710 return r;
1711 r = mailimap_char_send(fd, ch);
1712 if (r != MAILIMAP_NO_ERROR)
1713 return r;
1714
1715 return MAILIMAP_NO_ERROR;
1716 }
1717 else
1718 return mailimap_char_send(fd, ch);
1719}
1720
1721static int mailimap_quoted_send(mailstream * fd, const char * quoted)
1722{
1723 const char * pos;
1724 int r;
1725
1726 pos = quoted;
1727
1728 r = mailimap_dquote_send(fd);
1729 if (r != MAILIMAP_NO_ERROR)
1730 return r;
1731
1732 while (* pos != 0) {
1733 r = mailimap_quoted_char_send(fd, * pos);
1734 if (r != MAILIMAP_NO_ERROR)
1735 return r;
1736 pos ++;
1737 }
1738
1739 r = mailimap_dquote_send(fd);
1740 if (r != MAILIMAP_NO_ERROR)
1741 return r;
1742
1743 return MAILIMAP_NO_ERROR;
1744}
1745
1746/*
1747=> rename = "RENAME" SP mailbox SP mailbox
1748 ; Use of INBOX as a destination gives a NO error
1749*/
1750
1751int mailimap_rename_send(mailstream * fd, const char * mb,
1752 const char * new_name)
1753{
1754 int r;
1755
1756 r = mailimap_token_send(fd, "RENAME");
1757 if (r != MAILIMAP_NO_ERROR)
1758 return r;
1759 r = mailimap_space_send(fd);
1760 if (r != MAILIMAP_NO_ERROR)
1761 return r;
1762 r = mailimap_mailbox_send(fd, mb);
1763 if (r != MAILIMAP_NO_ERROR)
1764 return r;
1765 r = mailimap_space_send(fd);
1766 if (r != MAILIMAP_NO_ERROR)
1767 return r;
1768 r = mailimap_mailbox_send(fd, new_name);
1769 if (r != MAILIMAP_NO_ERROR)
1770 return r;
1771
1772 return MAILIMAP_NO_ERROR;
1773}
1774
1775/*
1776 response = *(continue-req / response-data) response-done
1777
1778 response-data = "*" SP (resp-cond-state / resp-cond-bye /
1779 mailbox-data / message-data / capability-data) CRLF
1780
1781 response-done = response-tagged / response-fatal
1782
1783 response-fatal = "*" SP resp-cond-bye CRLF
1784 ; Server closes connection immediately
1785
1786 response-tagged = tag SP resp-cond-state CRLF
1787
1788 resp-cond-auth = ("OK" / "PREAUTH") SP resp-text
1789 ; Authentication condition
1790
1791 resp-cond-bye = "BYE" SP resp-text
1792
1793 resp-cond-state = ("OK" / "NO" / "BAD") SP resp-text
1794 ; Status condition
1795
1796 resp-specials = "]"
1797
1798 resp-text = ["[" resp-text-code "]" SP] text
1799
1800 resp-text-code = "ALERT" /
1801 "BADCHARSET" [SP "(" astring *(SP astring) ")" ] /
1802 capability-data / "PARSE" /
1803 "PERMANENTFLAGS" SP "(" [flag-perm *(SP flag-perm)] ")" /
1804 "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
1805 "UIDNEXT" SP nz-number / "UIDVALIDITY" SP nz-number /
1806 "UNSEEN" SP nz-number /
1807 atom [SP 1*<any TEXT-CHAR except "]">]
1808*/
1809
1810/*
1811=> search = "SEARCH" [SP "CHARSET" SP astring] 1*(SP search-key)
1812 ; CHARSET argument to MUST be registered with IANA
1813*/
1814
1815int
1816mailimap_search_send(mailstream * fd, const char * charset,
1817 struct mailimap_search_key * key)
1818{
1819 int r;
1820
1821 r = mailimap_token_send(fd, "SEARCH");
1822 if (r != MAILIMAP_NO_ERROR)
1823 return r;
1824
1825 if (charset != NULL) {
1826 r = mailimap_space_send(fd);
1827 if (r != MAILIMAP_NO_ERROR)
1828 return r;
1829
1830 r = mailimap_token_send(fd, "CHARSET");
1831 if (r != MAILIMAP_NO_ERROR)
1832 return r;
1833 r = mailimap_space_send(fd);
1834 if (r != MAILIMAP_NO_ERROR)
1835 return r;
1836 r = mailimap_astring_send(fd, charset);
1837 if (r != MAILIMAP_NO_ERROR)
1838 return r;
1839 }
1840
1841 r = mailimap_space_send(fd);
1842 if (r != MAILIMAP_NO_ERROR)
1843 return r;
1844
1845 r = mailimap_search_key_send(fd, key);
1846 if (r != MAILIMAP_NO_ERROR)
1847 return r;
1848
1849 return MAILIMAP_NO_ERROR;
1850}
1851
1852int
1853mailimap_uid_search_send(mailstream * fd, const char * charset,
1854 struct mailimap_search_key * key)
1855{
1856 int r;
1857
1858 r = mailimap_token_send(fd, "UID");
1859 if (r != MAILIMAP_NO_ERROR)
1860 return r;
1861
1862 r = mailimap_space_send(fd);
1863 if (r != MAILIMAP_NO_ERROR)
1864 return r;
1865
1866 return mailimap_search_send(fd, charset, key);
1867}
1868
1869
1870/*
1871=> search-key = "ALL" / "ANSWERED" / "BCC" SP astring /
1872 "BEFORE" SP date / "BODY" SP astring /
1873 "CC" SP astring / "DELETED" / "FLAGGED" /
1874 "FROM" SP astring / "KEYWORD" SP flag-keyword / "NEW" /
1875 "OLD" / "ON" SP date / "RECENT" / "SEEN" /
1876 "SINCE" SP date / "SUBJECT" SP astring /
1877 "TEXT" SP astring / "TO" SP astring /
1878 "UNANSWERED" / "UNDELETED" / "UNFLAGGED" /
1879 "UNKEYWORD" SP flag-keyword / "UNSEEN" /
1880 ; Above this line were in [IMAP2]
1881 "DRAFT" / "HEADER" SP header-fld-name SP astring /
1882 "LARGER" SP number / "NOT" SP search-key /
1883 "OR" SP search-key SP search-key /
1884 "SENTBEFORE" SP date / "SENTON" SP date /
1885 "SENTSINCE" SP date / "SMALLER" SP number /
1886 "UID" SP set / "UNDRAFT" / set /
1887 "(" search-key *(SP search-key) ")"
1888*/
1889
1890
1891static int mailimap_search_key_send(mailstream * fd,
1892 struct mailimap_search_key * key)
1893{
1894 int r;
1895
1896 switch (key->sk_type) {
1897
1898 case MAILIMAP_SEARCH_KEY_ALL:
1899 return mailimap_token_send(fd, "ALL");
1900
1901 case MAILIMAP_SEARCH_KEY_ANSWERED:
1902 return mailimap_token_send(fd, "ANSWERED");
1903
1904 case MAILIMAP_SEARCH_KEY_BCC:
1905 r = mailimap_token_send(fd, "BCC");
1906 if (r != MAILIMAP_NO_ERROR)
1907 return r;
1908 r = mailimap_space_send(fd);
1909 if (r != MAILIMAP_NO_ERROR)
1910 return r;
1911 r = mailimap_astring_send(fd, key->sk_data.sk_bcc);
1912 if (r != MAILIMAP_NO_ERROR)
1913 return r;
1914 return MAILIMAP_NO_ERROR;
1915
1916 case MAILIMAP_SEARCH_KEY_BEFORE:
1917 r = mailimap_token_send(fd, "BEFORE");
1918 if (r != MAILIMAP_NO_ERROR)
1919 return r;
1920 r = mailimap_space_send(fd);
1921 if (r != MAILIMAP_NO_ERROR)
1922 return r;
1923 r = mailimap_date_send(fd, key->sk_data.sk_before);
1924 if (r != MAILIMAP_NO_ERROR)
1925 return r;
1926 return MAILIMAP_NO_ERROR;
1927
1928 case MAILIMAP_SEARCH_KEY_BODY:
1929 r = mailimap_token_send(fd, "BODY");
1930 if (r != MAILIMAP_NO_ERROR)
1931 return r;
1932 r = mailimap_space_send(fd);
1933 if (r != MAILIMAP_NO_ERROR)
1934 return r;
1935 r = mailimap_astring_send(fd, key->sk_data.sk_body);
1936 if (r != MAILIMAP_NO_ERROR)
1937 return r;
1938 return MAILIMAP_NO_ERROR;
1939
1940 case MAILIMAP_SEARCH_KEY_CC:
1941 r = mailimap_token_send(fd, "CC");
1942 if (r != MAILIMAP_NO_ERROR)
1943 return r;
1944 r = mailimap_space_send(fd);
1945 if (r != MAILIMAP_NO_ERROR)
1946 return r;
1947 r = mailimap_astring_send(fd, key->sk_data.sk_cc);
1948 if (r != MAILIMAP_NO_ERROR)
1949 return r;
1950 return MAILIMAP_NO_ERROR;
1951
1952 case MAILIMAP_SEARCH_KEY_DELETED:
1953 return mailimap_token_send(fd, "DELETED");
1954
1955 case MAILIMAP_SEARCH_KEY_FLAGGED:
1956 return mailimap_token_send(fd, "FLAGGED");
1957
1958 case MAILIMAP_SEARCH_KEY_FROM:
1959 r = mailimap_token_send(fd, "FROM");
1960 if (r != MAILIMAP_NO_ERROR)
1961 return r;
1962 r = mailimap_space_send(fd);
1963 if (r != MAILIMAP_NO_ERROR)
1964 return r;
1965 r = mailimap_astring_send(fd, key->sk_data.sk_from);
1966 if (r != MAILIMAP_NO_ERROR)
1967 return r;
1968 return MAILIMAP_NO_ERROR;
1969
1970 case MAILIMAP_SEARCH_KEY_KEYWORD:
1971 r = mailimap_token_send(fd, "KEYWORD");
1972 if (r != MAILIMAP_NO_ERROR)
1973 return r;
1974 r = mailimap_space_send(fd);
1975 if (r != MAILIMAP_NO_ERROR)
1976 return r;
1977 r = mailimap_flag_keyword_send(fd, key->sk_data.sk_keyword);
1978 if (r != MAILIMAP_NO_ERROR)
1979 return r;
1980 return MAILIMAP_NO_ERROR;
1981
1982 case MAILIMAP_SEARCH_KEY_NEW:
1983 return mailimap_token_send(fd, "NEW");
1984
1985 case MAILIMAP_SEARCH_KEY_OLD:
1986 return mailimap_token_send(fd, "OLD");
1987
1988 case MAILIMAP_SEARCH_KEY_ON:
1989 r = mailimap_token_send(fd, "ON");
1990 if (r != MAILIMAP_NO_ERROR)
1991 return r;
1992 r = mailimap_space_send(fd);
1993 if (r != MAILIMAP_NO_ERROR)
1994 return r;
1995 r = mailimap_date_send(fd, key->sk_data.sk_on);
1996 if (r != MAILIMAP_NO_ERROR)
1997 return r;
1998 return MAILIMAP_NO_ERROR;
1999
2000 case MAILIMAP_SEARCH_KEY_RECENT:
2001 return mailimap_token_send(fd, "RECENT");
2002
2003 case MAILIMAP_SEARCH_KEY_SEEN:
2004 return mailimap_token_send(fd, "SEEN");
2005
2006 case MAILIMAP_SEARCH_KEY_SINCE:
2007 r = mailimap_token_send(fd, "SINCE");
2008 if (r != MAILIMAP_NO_ERROR)
2009 return r;
2010 r = mailimap_space_send(fd);
2011 if (r != MAILIMAP_NO_ERROR)
2012 return r;
2013 r = mailimap_date_send(fd, key->sk_data.sk_since);
2014 if (r != MAILIMAP_NO_ERROR)
2015 return r;
2016 return MAILIMAP_NO_ERROR;
2017
2018 case MAILIMAP_SEARCH_KEY_SUBJECT:
2019 r = mailimap_token_send(fd, "SUBJECT");
2020 if (r != MAILIMAP_NO_ERROR)
2021 return r;
2022 r = mailimap_space_send(fd);
2023 if (r != MAILIMAP_NO_ERROR)
2024 return r;
2025 r = mailimap_astring_send(fd, key->sk_data.sk_subject);
2026 if (r != MAILIMAP_NO_ERROR)
2027 return r;
2028 return MAILIMAP_NO_ERROR;
2029
2030 case MAILIMAP_SEARCH_KEY_TEXT:
2031 r = mailimap_token_send(fd, "TEXT");
2032 if (r != MAILIMAP_NO_ERROR)
2033 return r;
2034 r = mailimap_space_send(fd);
2035 if (r != MAILIMAP_NO_ERROR)
2036 return r;
2037 r = mailimap_astring_send(fd, key->sk_data.sk_text);
2038 if (r != MAILIMAP_NO_ERROR)
2039 return r;
2040 return MAILIMAP_NO_ERROR;
2041
2042 case MAILIMAP_SEARCH_KEY_TO:
2043 r = mailimap_token_send(fd, "TO");
2044 if (r != MAILIMAP_NO_ERROR)
2045 return r;
2046 r = mailimap_space_send(fd);
2047 if (r != MAILIMAP_NO_ERROR)
2048 return r;
2049 r = mailimap_astring_send(fd, key->sk_data.sk_text);
2050 if (r != MAILIMAP_NO_ERROR)
2051 return r;
2052 return MAILIMAP_NO_ERROR;
2053
2054 case MAILIMAP_SEARCH_KEY_UNANSWERED:
2055 return mailimap_token_send(fd, "UNANSWERED");
2056
2057 case MAILIMAP_SEARCH_KEY_UNDELETED:
2058 return mailimap_token_send(fd, "UNDELETED");
2059
2060 case MAILIMAP_SEARCH_KEY_UNFLAGGED:
2061 return mailimap_token_send(fd, "UNFLAGGED");
2062
2063 case MAILIMAP_SEARCH_KEY_UNKEYWORD:
2064 r = mailimap_token_send(fd, "UNKEYWORD");
2065 if (r != MAILIMAP_NO_ERROR)
2066 return r;
2067 r = mailimap_space_send(fd);
2068 if (r != MAILIMAP_NO_ERROR)
2069 return r;
2070 r = mailimap_flag_keyword_send(fd, key->sk_data.sk_keyword);
2071 if (r != MAILIMAP_NO_ERROR)
2072 return r;
2073 return MAILIMAP_NO_ERROR;
2074
2075 case MAILIMAP_SEARCH_KEY_UNSEEN:
2076 return mailimap_token_send(fd, "UNSEEN");
2077
2078 case MAILIMAP_SEARCH_KEY_DRAFT:
2079 return mailimap_token_send(fd, "DRAFT");
2080
2081 case MAILIMAP_SEARCH_KEY_HEADER:
2082 r = mailimap_token_send(fd, "HEADER");
2083 if (r != MAILIMAP_NO_ERROR)
2084 return r;
2085 r = mailimap_space_send(fd);
2086 if (r != MAILIMAP_NO_ERROR)
2087 return r;
2088 r = mailimap_header_fld_name_send(fd,
2089 key->sk_data.sk_header.sk_header_name);
2090 if (r != MAILIMAP_NO_ERROR)
2091 return r;
2092 r = mailimap_space_send(fd);
2093 if (r != MAILIMAP_NO_ERROR)
2094 return r;
2095 r = mailimap_astring_send(fd,
2096 key->sk_data.sk_header.sk_header_value);
2097 if (r != MAILIMAP_NO_ERROR)
2098 return r;
2099 return MAILIMAP_NO_ERROR;
2100
2101 case MAILIMAP_SEARCH_KEY_LARGER:
2102 r = mailimap_token_send(fd, "LARGER");
2103 if (r != MAILIMAP_NO_ERROR)
2104 return r;
2105 r = mailimap_space_send(fd);
2106 if (r != MAILIMAP_NO_ERROR)
2107 return r;
2108 r = mailimap_number_send(fd, key->sk_data.sk_larger);
2109 if (r != MAILIMAP_NO_ERROR)
2110 return r;
2111 return MAILIMAP_NO_ERROR;
2112
2113 case MAILIMAP_SEARCH_KEY_NOT:
2114 r = mailimap_token_send(fd, "NOT");
2115 if (r != MAILIMAP_NO_ERROR)
2116 return r;
2117 r = mailimap_space_send(fd);
2118 if (r != MAILIMAP_NO_ERROR)
2119 return r;
2120 r = mailimap_search_key_send(fd, key->sk_data.sk_not);
2121 if (r != MAILIMAP_NO_ERROR)
2122 return r;
2123 return MAILIMAP_NO_ERROR;
2124
2125 case MAILIMAP_SEARCH_KEY_OR:
2126 r = mailimap_token_send(fd, "OR");
2127 if (r != MAILIMAP_NO_ERROR)
2128 return r;
2129 r = mailimap_space_send(fd);
2130 if (r != MAILIMAP_NO_ERROR)
2131 return r;
2132 r = mailimap_search_key_send(fd, key->sk_data.sk_or.sk_or1);
2133 if (r != MAILIMAP_NO_ERROR)
2134 return r;
2135 r = mailimap_space_send(fd);
2136 if (r != MAILIMAP_NO_ERROR)
2137 return r;
2138 r = mailimap_search_key_send(fd, key->sk_data.sk_or.sk_or2);
2139 if (r != MAILIMAP_NO_ERROR)
2140 return r;
2141 return TRUE;
2142
2143 case MAILIMAP_SEARCH_KEY_SENTBEFORE:
2144 r = mailimap_token_send(fd, "SENTBEFORE");
2145 if (r != MAILIMAP_NO_ERROR)
2146 return r;
2147 r = mailimap_space_send(fd);
2148 if (r != MAILIMAP_NO_ERROR)
2149 return r;
2150 r = mailimap_date_send(fd, key->sk_data.sk_sentbefore);
2151 if (r != MAILIMAP_NO_ERROR)
2152 return r;
2153 return MAILIMAP_NO_ERROR;
2154
2155 case MAILIMAP_SEARCH_KEY_SENTON:
2156 r = mailimap_token_send(fd, "SENTON");
2157 if (r != MAILIMAP_NO_ERROR)
2158 return r;
2159 r = mailimap_space_send(fd);
2160 if (r != MAILIMAP_NO_ERROR)
2161 return r;
2162 r = mailimap_date_send(fd, key->sk_data.sk_senton);
2163 if (r != MAILIMAP_NO_ERROR)
2164 return r;
2165 return MAILIMAP_NO_ERROR;
2166
2167 case MAILIMAP_SEARCH_KEY_SENTSINCE:
2168 r = mailimap_token_send(fd, "SENTSINCE");
2169 if (r != MAILIMAP_NO_ERROR)
2170 return r;
2171 r = mailimap_space_send(fd);
2172 if (r != MAILIMAP_NO_ERROR)
2173 return r;
2174 r = mailimap_date_send(fd, key->sk_data.sk_sentsince);
2175 if (r != MAILIMAP_NO_ERROR)
2176 return r;
2177 return MAILIMAP_NO_ERROR;
2178
2179 case MAILIMAP_SEARCH_KEY_SMALLER:
2180 r = mailimap_token_send(fd, "SMALLER");
2181 if (r != MAILIMAP_NO_ERROR)
2182 return r;
2183 r = mailimap_space_send(fd);
2184 if (r != MAILIMAP_NO_ERROR)
2185 return r;
2186 r = mailimap_number_send(fd, key->sk_data.sk_smaller);
2187 if (r != MAILIMAP_NO_ERROR)
2188 return r;
2189 return MAILIMAP_NO_ERROR;
2190
2191 case MAILIMAP_SEARCH_KEY_UID:
2192 r = mailimap_token_send(fd, "UID");
2193 if (r != MAILIMAP_NO_ERROR)
2194 return r;
2195 r = mailimap_space_send(fd);
2196 if (r != MAILIMAP_NO_ERROR)
2197 return r;
2198 r = mailimap_set_send(fd, key->sk_data.sk_set);
2199 if (r != MAILIMAP_NO_ERROR)
2200 return r;
2201 return MAILIMAP_NO_ERROR;
2202
2203 case MAILIMAP_SEARCH_KEY_UNDRAFT:
2204 return mailimap_token_send(fd, "UNDRAFT");
2205
2206 case MAILIMAP_SEARCH_KEY_SET:
2207 return mailimap_set_send(fd, key->sk_data.sk_set);
2208
2209 case MAILIMAP_SEARCH_KEY_MULTIPLE:
2210 r = mailimap_oparenth_send(fd);
2211 if (r != MAILIMAP_NO_ERROR)
2212 return r;
2213
2214 r = mailimap_struct_spaced_list_send(fd, key->sk_data.sk_multiple,
2215 (mailimap_struct_sender *)
2216 mailimap_search_key_send);
2217 if (r != MAILIMAP_NO_ERROR)
2218 return r;
2219
2220 r = mailimap_cparenth_send(fd);
2221 if (r != MAILIMAP_NO_ERROR)
2222 return r;
2223
2224 return MAILIMAP_NO_ERROR;
2225 default:
2226 /* should not happend */
2227 return MAILIMAP_ERROR_INVAL;
2228 }
2229}
2230
2231/*
2232=> section = "[" [section-spec] "]"
2233*/
2234
2235static int
2236mailimap_section_send(mailstream * fd,
2237 struct mailimap_section * section)
2238{
2239 int r;
2240
2241 r = mailimap_char_send(fd, '[');
2242 if (r != MAILIMAP_NO_ERROR)
2243 return r;
2244
2245 if (section != NULL) {
2246 if (section->sec_spec != NULL) {
2247 r = mailimap_section_spec_send(fd, section->sec_spec);
2248 if (r != MAILIMAP_NO_ERROR)
2249 return r;
2250 }
2251 }
2252
2253 r = mailimap_char_send(fd, ']');
2254 if (r != MAILIMAP_NO_ERROR)
2255 return r;
2256
2257 return MAILIMAP_NO_ERROR;
2258}
2259
2260/*
2261=> section-msgtext = "HEADER" / "HEADER.FIELDS" [".NOT"] SP header-list /
2262 "TEXT"
2263 ; top-level or MESSAGE/RFC822 part
2264*/
2265
2266static int
2267mailimap_section_msgtext_send(mailstream * fd,
2268 struct mailimap_section_msgtext *
2269 section_msgtext)
2270{
2271 int r;
2272
2273 switch (section_msgtext->sec_type) {
2274 case MAILIMAP_SECTION_MSGTEXT_HEADER:
2275 return mailimap_token_send(fd, "HEADER");
2276
2277 case MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS:
2278 r = mailimap_token_send(fd, "HEADER.FIELDS");
2279 if (r != MAILIMAP_NO_ERROR)
2280 return r;
2281 r = mailimap_space_send(fd);
2282 if (r != MAILIMAP_NO_ERROR)
2283 return r;
2284 r = mailimap_header_list_send(fd, section_msgtext->sec_header_list);
2285 if (r != MAILIMAP_NO_ERROR)
2286 return r;
2287 return MAILIMAP_NO_ERROR;
2288
2289 case MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS_NOT:
2290 r = mailimap_token_send(fd, "HEADER.FIELDS.NOT");
2291 if (r != MAILIMAP_NO_ERROR)
2292 return r;
2293 r = mailimap_space_send(fd);
2294 if (r != MAILIMAP_NO_ERROR)
2295 return r;
2296 r = mailimap_header_list_send(fd, section_msgtext->sec_header_list);
2297 if (r != MAILIMAP_NO_ERROR)
2298 return r;
2299 return MAILIMAP_NO_ERROR;
2300
2301 case MAILIMAP_SECTION_MSGTEXT_TEXT:
2302 return mailimap_token_send(fd, "TEXT");
2303
2304 default:
2305 /* should not happend */
2306 return MAILIMAP_ERROR_INVAL;
2307 }
2308}
2309
2310/*
2311=> section-part = nz-number *("." nz-number)
2312 ; body part nesting
2313*/
2314
2315static int
2316mailimap_pnumber_send(mailstream * fd, uint32_t * pnumber)
2317{
2318 return mailimap_number_send(fd, * pnumber);
2319}
2320
2321static int
2322mailimap_section_part_send(mailstream * fd,
2323 struct mailimap_section_part * section)
2324{
2325 int r;
2326
2327 r = mailimap_struct_list_send(fd, section->sec_id, '.',
2328 (mailimap_struct_sender *) mailimap_pnumber_send);
2329 if (r != MAILIMAP_NO_ERROR)
2330 return r;
2331
2332 return MAILIMAP_NO_ERROR;
2333}
2334
2335/*
2336=> section-spec = section-msgtext / (section-part ["." section-text])
2337*/
2338
2339static int
2340mailimap_section_spec_send(mailstream * fd,
2341 struct mailimap_section_spec * section_spec)
2342{
2343 int r;
2344
2345 switch (section_spec->sec_type) {
2346 case MAILIMAP_SECTION_SPEC_SECTION_MSGTEXT:
2347 return mailimap_section_msgtext_send(fd,
2348 section_spec->sec_data.sec_msgtext);
2349
2350 case MAILIMAP_SECTION_SPEC_SECTION_PART:
2351 r = mailimap_section_part_send(fd, section_spec->sec_data.sec_part);
2352 if (r != MAILIMAP_NO_ERROR)
2353 return r;
2354
2355 if (section_spec->sec_text != NULL) {
2356 r = mailimap_char_send(fd, '.');
2357 if (r != MAILIMAP_NO_ERROR)
2358 return r;
2359 r = mailimap_section_text_send(fd,
2360 section_spec->sec_text);
2361 if (r != MAILIMAP_NO_ERROR)
2362 return r;
2363 }
2364
2365 return MAILIMAP_NO_ERROR;
2366
2367 default:
2368 /* should not happen */
2369 return MAILIMAP_ERROR_INVAL;
2370 }
2371}
2372
2373/*
2374=> section-text = section-msgtext / "MIME"
2375 ; text other than actual body part (headers, etc.)
2376*/
2377
2378static int
2379mailimap_section_text_send(mailstream * fd,
2380 struct mailimap_section_text * section_text)
2381{
2382 switch (section_text->sec_type) {
2383 case MAILIMAP_SECTION_TEXT_SECTION_MSGTEXT:
2384 return mailimap_section_msgtext_send(fd, section_text->sec_msgtext);
2385
2386 case MAILIMAP_SECTION_TEXT_MIME:
2387 return mailimap_token_send(fd, "MIME");
2388
2389 default:
2390 /* should not happen */
2391 return MAILIMAP_NO_ERROR;
2392 }
2393}
2394
2395/*
2396=> select = "SELECT" SP mailbox
2397*/
2398
2399int
2400mailimap_select_send(mailstream * fd, const char * mb)
2401{
2402 int r;
2403
2404 r = mailimap_token_send(fd, "SELECT");
2405 if (r != MAILIMAP_NO_ERROR)
2406 return r;
2407 r = mailimap_space_send(fd);
2408 if (r != MAILIMAP_NO_ERROR)
2409 return r;
2410 r = mailimap_mailbox_send(fd, mb);
2411 if (r != MAILIMAP_NO_ERROR)
2412 return r;
2413
2414 return MAILIMAP_NO_ERROR;
2415}
2416
2417/*
2418=> sequence-num = nz-number / "*"
2419 ; * is the largest number in use. For message
2420 ; sequence numbers, it is the number of messages
2421 ; in the mailbox. For unique identifiers, it is
2422 ; the unique identifier of the last message in
2423 ; the mailbox.
2424*/
2425
2426/* if sequence_num == 0 then "*" */
2427
2428static int
2429mailimap_sequence_num_send(mailstream * fd, uint32_t sequence_num)
2430{
2431 if (sequence_num == 0)
2432 return mailimap_char_send(fd, '*');
2433 else
2434 return mailimap_number_send(fd, sequence_num);
2435}
2436
2437/*
2438=> set = sequence-num / (sequence-num ":" sequence-num) /
2439 (set "," set)
2440 ; Identifies a set of messages. For message
2441 ; sequence numbers, these are consecutive
2442 ; numbers from 1 to the number of messages in
2443 ; the mailbox
2444 ; Comma delimits individual numbers, colon
2445 ; delimits between two numbers inclusive.
2446 ; Example: 2,4:7,9,12:* is 2,4,5,6,7,9,12,13,
2447 ; 14,15 for a mailbox with 15 messages.
2448*/
2449
2450static int mailimap_set_item_send(mailstream * fd,
2451 struct mailimap_set_item * item)
2452{
2453 int r;
2454
2455 if (item->set_first == item->set_last)
2456 return mailimap_sequence_num_send(fd, item->set_first);
2457 else {
2458 r = mailimap_sequence_num_send(fd, item->set_first);
2459 if (r != MAILIMAP_NO_ERROR)
2460 return r;
2461 r = mailimap_char_send(fd, ':');
2462 if (r != MAILIMAP_NO_ERROR)
2463 return r;
2464 r = mailimap_sequence_num_send(fd, item->set_last);
2465 if (r != MAILIMAP_NO_ERROR)
2466 return r;
2467 return MAILIMAP_NO_ERROR;
2468 }
2469}
2470
2471static int mailimap_set_send(mailstream * fd,
2472 struct mailimap_set * set)
2473{
2474 return mailimap_struct_list_send(fd, set->set_list, ',',
2475 (mailimap_struct_sender *) mailimap_set_item_send);
2476}
2477
2478/*
2479=> status = "STATUS" SP mailbox SP "(" status-att *(SP status-att) ")"
2480*/
2481
2482static int
2483mailimap_status_att_list_send(mailstream * fd,
2484 struct mailimap_status_att_list * status_att_list)
2485{
2486 return mailimap_struct_spaced_list_send(fd, status_att_list->att_list,
2487 (mailimap_struct_sender *) mailimap_status_att_send);
2488}
2489
2490int
2491mailimap_status_send(mailstream * fd, const char * mb,
2492 struct mailimap_status_att_list * status_att_list)
2493{
2494 int r;
2495
2496 r = mailimap_token_send(fd, "STATUS");
2497 if (r != MAILIMAP_NO_ERROR)
2498 return r;
2499
2500 r = mailimap_space_send(fd);
2501 if (r != MAILIMAP_NO_ERROR)
2502 return r;
2503
2504 r = mailimap_mailbox_send(fd, mb);
2505 if (r != MAILIMAP_NO_ERROR)
2506 return r;
2507
2508 r = mailimap_space_send(fd);
2509 if (r != MAILIMAP_NO_ERROR)
2510 return r;
2511
2512 r = mailimap_char_send(fd, '(');
2513 if (r != MAILIMAP_NO_ERROR)
2514 return r;
2515
2516 r = mailimap_status_att_list_send(fd, status_att_list);
2517 if (r != MAILIMAP_NO_ERROR)
2518 return r;
2519
2520 r = mailimap_char_send(fd, ')');
2521 if (r != MAILIMAP_NO_ERROR)
2522 return r;
2523
2524 return MAILIMAP_NO_ERROR;
2525}
2526
2527/*
2528=> status-att = "MESSAGES" / "RECENT" / "UIDNEXT" / "UIDVALIDITY" /
2529 "UNSEEN"
2530*/
2531
2532
2533static int mailimap_status_att_send(mailstream * fd, int * status_att)
2534{
2535 const char * token;
2536
2537 token = mailimap_status_att_get_token_str(* status_att);
2538 if (token == NULL) {
2539 /* should not happen */
2540 return MAILIMAP_ERROR_INVAL;
2541 }
2542
2543 return mailimap_token_send(fd, token);
2544}
2545
2546/*
2547=> store = "STORE" SP set SP store-att-flags
2548*/
2549
2550int
2551mailimap_store_send(mailstream * fd,
2552 struct mailimap_set * set,
2553 struct mailimap_store_att_flags * store_att_flags)
2554{
2555 int r;
2556
2557 r = mailimap_token_send(fd, "STORE");
2558 if (r != MAILIMAP_NO_ERROR)
2559 return r;
2560 r = mailimap_space_send(fd);
2561 if (r != MAILIMAP_NO_ERROR)
2562 return r;
2563 r = mailimap_set_send(fd, set);
2564 if (r != MAILIMAP_NO_ERROR)
2565 return r;
2566 r = mailimap_space_send(fd);
2567 if (r != MAILIMAP_NO_ERROR)
2568 return r;
2569
2570 r = mailimap_store_att_flags_send(fd, store_att_flags);
2571 if (r != MAILIMAP_NO_ERROR)
2572 return r;
2573
2574 return MAILIMAP_NO_ERROR;
2575}
2576
2577int
2578mailimap_uid_store_send(mailstream * fd,
2579 struct mailimap_set * set,
2580 struct mailimap_store_att_flags * store_att_flags)
2581{
2582 int r;
2583
2584 r = mailimap_token_send(fd, "UID");
2585 if (r != MAILIMAP_NO_ERROR)
2586 return r;
2587 r = mailimap_space_send(fd);
2588 if (r != MAILIMAP_NO_ERROR)
2589 return r;
2590
2591 return mailimap_store_send(fd, set, store_att_flags);
2592}
2593
2594/*
2595=> store-att-flags = (["+" / "-"] "FLAGS" [".SILENT"]) SP
2596 (flag-list / (flag *(SP flag)))
2597*/
2598
2599static int
2600mailimap_store_att_flags_send(mailstream * fd,
2601 struct mailimap_store_att_flags * store_flags)
2602{
2603 int r;
2604
2605 switch (store_flags->fl_sign) {
2606 case 1:
2607 r = mailimap_char_send(fd, '+');
2608 if (r != MAILIMAP_NO_ERROR)
2609 return r;
2610 case -1:
2611 r = mailimap_char_send(fd, '-');
2612 if (r != MAILIMAP_NO_ERROR)
2613 return r;
2614 }
2615
2616 r = mailimap_token_send(fd, "FLAGS");
2617 if (r != MAILIMAP_NO_ERROR)
2618 return r;
2619
2620 if (store_flags->fl_silent) {
2621 r = mailimap_token_send(fd, ".SILENT");
2622 if (r != MAILIMAP_NO_ERROR)
2623 return r;
2624 }
2625
2626 r = mailimap_space_send(fd);
2627 if (r != MAILIMAP_NO_ERROR)
2628 return r;
2629
2630 r = mailimap_flag_list_send(fd, store_flags->fl_flag_list);
2631 if (r != MAILIMAP_NO_ERROR)
2632 return r;
2633
2634 return MAILIMAP_NO_ERROR;
2635}
2636
2637/*
2638 string = quoted / literal
2639*/
2640
2641/*
2642=> subscribe = "SUBSCRIBE" SP mailbox
2643*/
2644
2645int mailimap_subscribe_send(mailstream * fd, const char * mb)
2646{
2647 int r;
2648
2649 r = mailimap_token_send(fd, "SUBSCRIBE");
2650 if (r != MAILIMAP_NO_ERROR)
2651 return r;
2652
2653 r = mailimap_space_send(fd);
2654 if (r != MAILIMAP_NO_ERROR)
2655 return r;
2656
2657 r = mailimap_mailbox_send(fd, mb);
2658 if (r != MAILIMAP_NO_ERROR)
2659 return r;
2660
2661 return MAILIMAP_NO_ERROR;
2662}
2663
2664/*
2665=> tag = 1*<any ASTRING-CHAR except "+">
2666*/
2667
2668int mailimap_tag_send(mailstream * fd, const char * tag)
2669{
2670 return mailimap_token_send(fd, tag);
2671}
2672
2673/*
2674 text = 1*TEXT-CHAR
2675
2676 TEXT-CHAR = <any CHAR except CR and LF>
2677
2678 time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
2679 ; Hours minutes seconds
2680*/
2681
2682/*
2683=> uid = "UID" SP (copy / fetch / search / store)
2684 ; Unique identifiers used instead of message
2685 ; sequence numbers
2686
2687functions uid_copy, uid_fetch ...
2688*/
2689
2690
2691/*
2692 uniqueid = nz-number
2693 ; Strictly ascending
2694*/
2695
2696/*
2697=> unsubscribe = "UNSUBSCRIBE" SP mailbox
2698*/
2699
2700int mailimap_unsubscribe_send(mailstream * fd,
2701 const char * mb)
2702{
2703 int r;
2704
2705 r = mailimap_token_send(fd, "UNSUBSCRIBE");
2706 if (r != MAILIMAP_NO_ERROR)
2707 return r;
2708 r = mailimap_space_send(fd);
2709 if (r != MAILIMAP_NO_ERROR)
2710 return r;
2711 r = mailimap_mailbox_send(fd, mb);
2712 if (r != MAILIMAP_NO_ERROR)
2713 return r;
2714
2715 return MAILIMAP_NO_ERROR;
2716}
2717
2718int mailimap_starttls_send(mailstream * fd)
2719{
2720 return mailimap_token_send(fd, "STARTTLS");
2721}
2722
2723/*
2724=> userid = astring
2725*/
2726
2727static int mailimap_userid_send(mailstream * fd, const char * user)
2728{
2729 return mailimap_astring_send(fd, user);
2730}
2731
2732/*
2733 x-command = "X" atom <experimental command arguments>
2734
2735 zone = ("+" / "-") 4DIGIT
2736 ; Signed four-digit value of hhmm representing
2737 ; hours and minutes east of Greenwich (that is,
2738 ; the amount that the given time differs from
2739 ; Universal Time). Subtracting the timezone
2740 ; from the given time will give the UT form.
2741 ; The Universal Time zone is "+0000".
2742*/