1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2010-2021 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <mailutils/errno.h>
25 #include <mailutils/assoc.h>
26 #include <mailutils/stream.h>
27 #include <mailutils/imap.h>
28 #include <mailutils/imaputil.h>
29 #include <mailutils/sys/imap.h>
30
31 static int
_collect_flags(void * item,void * data)32 _collect_flags (void *item, void *data)
33 {
34 struct imap_list_element *elt = item;
35 int *args = data;
36
37 if (elt->type == imap_eltype_string)
38 mu_imap_flag_to_attribute (elt->v.string, args);
39 return 0;
40 }
41
42 int
_mu_imap_collect_flags(struct imap_list_element * arg,int * res)43 _mu_imap_collect_flags (struct imap_list_element *arg, int *res)
44 {
45 if (arg->type != imap_eltype_list)
46 return EINVAL;
47 *res = 0;
48 mu_list_foreach (arg->v.list, _collect_flags, res);
49 return 0;
50 }
51
52 static void
_select_response_action(mu_imap_t imap,mu_list_t response,void * data)53 _select_response_action (mu_imap_t imap, mu_list_t response, void *data)
54 {
55 struct imap_list_element *elt;
56
57 elt = _mu_imap_list_at (response, 0);
58 if (elt && _mu_imap_list_element_is_string (elt, "FLAGS"))
59 {
60 struct imap_list_element *arg = _mu_imap_list_at (response, 1);
61 if (arg &&
62 _mu_imap_collect_flags (arg, &imap->mbox_stat.defined_flags) == 0)
63 imap->mbox_stat.flags |= MU_IMAP_STAT_DEFINED_FLAGS;
64 }
65 }
66
67 int
mu_imap_select(mu_imap_t imap,const char * mbox,int writable,struct mu_imap_stat * ps)68 mu_imap_select (mu_imap_t imap, const char *mbox, int writable,
69 struct mu_imap_stat *ps)
70 {
71 int status;
72
73 if (imap == NULL)
74 return EINVAL;
75 if (!imap->io)
76 return MU_ERR_NO_TRANSPORT;
77 if (imap->session_state != MU_IMAP_SESSION_AUTH &&
78 imap->session_state != MU_IMAP_SESSION_SELECTED)
79 return MU_ERR_SEQ;
80
81 if (!mbox)
82 {
83 if (imap->session_state == MU_IMAP_SESSION_SELECTED)
84 {
85 if (ps)
86 *ps = imap->mbox_stat;
87 return 0;
88 }
89 return MU_ERR_INFO_UNAVAILABLE;
90 }
91
92 if (imap->mbox_name && strcmp (imap->mbox_name, mbox) == 0
93 && writable == imap->mbox_writable)
94 {
95 if (ps)
96 *ps = imap->mbox_stat;
97 return 0;
98 }
99
100 switch (imap->client_state)
101 {
102 case MU_IMAP_CLIENT_READY:
103 status = _mu_imap_tag_next (imap);
104 MU_IMAP_CHECK_EAGAIN (imap, status);
105 status = mu_imapio_send_command (imap->io, imap->tag_str, NULL,
106 writable ? "SELECT" : "EXAMINE",
107 mbox, NULL);
108 MU_IMAP_CHECK_ERROR (imap, status);
109 MU_IMAP_FCLR (imap, MU_IMAP_RESP);
110 imap->client_state = MU_IMAP_CLIENT_SELECT_RX;
111
112 case MU_IMAP_CLIENT_SELECT_RX:
113 memset (&imap->mbox_stat, 0, sizeof (imap->mbox_stat));
114 status = _mu_imap_response (imap, _select_response_action, NULL);
115 MU_IMAP_CHECK_EAGAIN (imap, status);
116 switch (imap->response)
117 {
118 case MU_IMAP_OK:
119 imap->session_state = MU_IMAP_SESSION_SELECTED;
120 free (imap->mbox_name);
121 imap->mbox_name = strdup (mbox);
122 if (!imap->mbox_name)
123 {
124 imap->client_state = MU_IMAP_CLIENT_ERROR;
125 return errno;
126 }
127 imap->mbox_writable = writable;
128 if (ps)
129 *ps = imap->mbox_stat;
130 break;
131
132 case MU_IMAP_NO:
133 status = EACCES;
134 break;
135
136 case MU_IMAP_BAD:
137 status = MU_ERR_BADREPLY;
138 break;
139 }
140 imap->client_state = MU_IMAP_CLIENT_READY;
141 break;
142
143 default:
144 status = EINPROGRESS;
145 }
146 return status;
147 }
148