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 #ifndef _MAILUTILS_SYS_IMAP_H
19 # define _MAILUTILS_SYS_IMAP_H
20 
21 # include <mailutils/sys/folder.h>
22 # include <mailutils/sys/mailbox.h>
23 # include <mailutils/sys/registrar.h>
24 # include <mailutils/sys/auth.h>
25 # include <mailutils/imapio.h>
26 # include <mailutils/imap.h>
27 
28 # ifdef __cplusplus
29 extern "C" {
30 # endif
31 
32 #define MU_IMAP_RESP  0x01
33 #define MU_IMAP_TRACE 0x02
34 #define MU_IMAP_XSCRIPT_MASK(n) (1<<((n)+1))
35 #define MU_IMAP_SET_XSCRIPT_MASK(imap,n)	\
36   do						\
37     (imap)->flags |= MU_IMAP_XSCRIPT_MASK (n);	\
38   while (0)
39 #define MU_IMAP_CLR_XSCRIPT_MASK(imap,n)	\
40   do						\
41     (imap)->flags &= ~MU_IMAP_XSCRIPT_MASK (n);	\
42   while (0)
43 #define MU_IMAP_IS_XSCRIPT_MASK(imap,n)         \
44   ((imap)->flags & MU_IMAP_XSCRIPT_MASK (n))
45 
46 enum mu_imap_client_state
47   {
48     MU_IMAP_CLIENT_READY,
49     MU_IMAP_CLIENT_ERROR,
50     MU_IMAP_CLIENT_CONNECT_RX,
51     MU_IMAP_CLIENT_GREETINGS,
52     MU_IMAP_CLIENT_CAPABILITY_RX,
53     MU_IMAP_CLIENT_LOGIN_RX,
54     MU_IMAP_CLIENT_LOGOUT_RX,
55     MU_IMAP_CLIENT_ID_RX,
56     MU_IMAP_CLIENT_SELECT_RX,
57     MU_IMAP_CLIENT_STATUS_RX,
58     MU_IMAP_CLIENT_NOOP_RX,
59     MU_IMAP_CLIENT_FETCH_RX,
60     MU_IMAP_CLIENT_STORE_RX,
61     MU_IMAP_CLIENT_DELETE_RX,
62     MU_IMAP_CLIENT_RENAME_RX,
63     MU_IMAP_CLIENT_CLOSE_RX,
64     MU_IMAP_CLIENT_UNSELECT_RX,
65     MU_IMAP_CLIENT_CHECK_RX,
66     MU_IMAP_CLIENT_COPY_RX,
67     MU_IMAP_CLIENT_EXPUNGE_RX,
68     MU_IMAP_CLIENT_APPEND_RX,
69     MU_IMAP_CLIENT_LIST_RX,
70     MU_IMAP_CLIENT_SUBSCRIBE_RX,
71     MU_IMAP_CLIENT_UNSUBSCRIBE_RX,
72     MU_IMAP_CLIENT_LSUB_RX,
73     MU_IMAP_CLIENT_STARTTLS_RX,
74     MU_IMAP_CLIENT_SEARCH_RX,
75     MU_IMAP_CLIENT_CLOSING
76   };
77 
78 enum mu_imap_response
79   {
80     MU_IMAP_OK,
81     MU_IMAP_NO,
82     MU_IMAP_BAD
83   };
84 
85 struct _mu_imap
86   {
87     int flags;
88 
89     /* Holds the recent response */
90     enum mu_imap_response response;
91     /* The recent response code */
92     int response_code;
93 
94     /* Error string (if any) */
95     char *errstr;
96     size_t errsize;
97 
98     enum mu_imap_client_state client_state;
99     enum mu_imap_session_state session_state;
100 
101     /* Tag */
102     size_t tag_len;  /* Length of the command tag */
103     int *tag_buf;    /* Tag number (BCD) */
104     char *tag_str;   /* String representation (tag_len + 1 bytes, asciiz) */
105 
106     mu_list_t capa;
107     mu_imapio_t io;
108 
109     char *mbox_name;  /* Name of the currently opened mailbox */
110     int mbox_writable:1; /* Is it open read/write? */
111     struct mu_imap_stat mbox_stat;  /* Stats obtained from it */
112 
113     /* Folder data */
114     int separator;     /* Separator character */
115     size_t prefix_len; /* Path prefix length */
116 
117     /* Callbacks */
118     struct
119     {
120       mu_imap_callback_t action;
121       void *data;
122     } callback[_MU_IMAP_CB_MAX];
123 };
124 
125 enum imap_eltype
126   {
127     imap_eltype_string,
128     imap_eltype_list
129   };
130 
131 struct imap_list_element
132 {
133   enum imap_eltype type;
134   union
135   {
136     mu_list_t list;
137     char *string;
138   } v;
139 };
140 
141 #define MU_IMAP_FSET(p,f) ((p)->flags |= (f))
142 #define MU_IMAP_FISSET(p,f) ((p)->flags & (f))
143 #define MU_IMAP_FCLR(p,f) ((p)->flags &= ~(f))
144 
145 int _mu_imap_init (mu_imap_t imap);
146 int _mu_imap_trace_enable (mu_imap_t imap);
147 int _mu_imap_trace_disable (mu_imap_t imap);
148 int _mu_imap_xscript_level (mu_imap_t imap, int xlev);
149 
150 typedef void (*mu_imap_response_action_t) (mu_imap_t imap, mu_list_t resp,
151 					   void *data);
152 
153 struct imap_command
154 {
155   int session_state;
156   char *capa;
157   int rx_state;
158   int argc;
159   char const **argv;
160   char const *extra;
161   mu_msgset_t msgset;
162   void (*tagged_handler) (mu_imap_t);
163   mu_imap_response_action_t untagged_handler;
164   void *untagged_handler_data;
165 };
166 
167 int mu_imap_gencom (mu_imap_t imap, struct imap_command *cmd);
168 
169 /* If status indicates an error, return.
170   */
171 #define MU_IMAP_CHECK_ERROR(imap, status)			\
172   do								\
173     {								\
174       if (status != 0)						\
175 	{							\
176 	  imap->client_state = MU_IMAP_CLIENT_ERROR;		\
177 	  return status;					\
178 	}							\
179     }								\
180   while (0)
181 
182 /* Check if status indicates an error.
183    If the error is recoverable just return the status.
184    Otherwise, set the error state and return the status
185  */
186 #define MU_IMAP_CHECK_EAGAIN(imap, status)		\
187   do							\
188     {							\
189       switch (status)					\
190 	{						\
191 	case 0:						\
192 	  break;					\
193 	case EAGAIN:					\
194 	case EINPROGRESS:				\
195 	case EINTR:					\
196 	  return status;				\
197 	case MU_ERR_REPLY:				\
198 	case MU_ERR_BADREPLY:				\
199 	  imap->client_state = MU_IMAP_CLIENT_READY;	\
200 	  return status;				\
201 	default:					\
202 	  imap->client_state = MU_IMAP_CLIENT_ERROR;	\
203 	  return status;				\
204 	}						\
205     }							\
206   while (0)
207 
208 int _mu_imap_seterrstr (mu_imap_t imap, const char *str, size_t len);
209 int _mu_imap_seterrstrz (mu_imap_t imap, const char *str);
210 void _mu_imap_clrerrstr (mu_imap_t imap);
211 
212 int _mu_imap_tag_next (mu_imap_t imap);
213 int _mu_imap_tag_clr (mu_imap_t imap);
214 
215 
216 int _mu_imap_untagged_response_to_list (mu_imap_t imap, mu_list_t *plist);
217 int _mu_imap_process_untagged_response (mu_imap_t imap, mu_list_t list,
218 					mu_imap_response_action_t fun,
219 					void *data);
220 int _mu_imap_process_tagged_response (mu_imap_t imap, mu_list_t resp);
221 
222 int _mu_imap_response (mu_imap_t imap, mu_imap_response_action_t fun,
223 		       void *data);
224 
225 int _mu_imap_list_element_is_string (struct imap_list_element *elt,
226 				     const char *str);
227 int _mu_imap_list_element_is_nil (struct imap_list_element *elt);
228 
229 int _mu_imap_list_nth_element_is_string (mu_list_t list, size_t n,
230 					 const char *str);
231 
232 int _mu_imap_collect_flags (struct imap_list_element *arg, int *res);
233 
234 struct imap_list_element *_mu_imap_list_at (mu_list_t list, int idx);
235 
236 int _mu_imap_parse_fetch_response (mu_list_t resp, mu_list_t *result_list);
237 
238 void _mu_close_handler (mu_imap_t imap);
239 
240 /* ----------------------------- */
241 /* URL Auxiliaries               */
242 /* ----------------------------- */
243 int _mu_imap_url_init (mu_url_t url);
244 int _mu_imaps_url_init (mu_url_t url);
245 
246 /* ----------------------------- */
247 /* Mailbox interface             */
248 /* ----------------------------- */
249 
250 int _mu_imap_mailbox_init (mu_mailbox_t mailbox);
251 
252 #define _MU_IMAP_MSG_SCANNED   0x01 /* Message has already been scanned */
253 #define _MU_IMAP_MSG_CACHED    0x02 /* Message is cached */
254 #define _MU_IMAP_MSG_LINES     0x04 /* Number of lines is computed */
255 #define _MU_IMAP_MSG_ATTRCHG   0x08 /* Message attributes has changed */
256 
257 struct _mu_imap_message
258 {
259   int flags;
260   size_t msgno;             /* Message sequence number */
261   size_t uid;               /* Message UID */
262   int attr_flags;           /* Attributes */
263   mu_off_t offset;          /* Offset in the message cache stream */
264   mu_off_t body_start;      /* Start of message, relative to offset */
265   mu_off_t body_end;        /* End of message, relative to offset */
266   size_t header_lines;      /* Number of lines in the header */
267   size_t body_lines;        /* Number of lines in the body */
268   size_t message_size;      /* Message size */
269   size_t message_lines;     /* Number of lines in the message */
270   struct mu_imapenvelope *env; /* IMAP envelope */
271   mu_stream_t header_stream;   /* Memory stream with message headers */
272   mu_message_t message;     /* Pointer to the message structure */
273   struct _mu_imap_mailbox *imbx; /* Back pointer.  */
274 };
275 
276 #define _MU_IMAP_MBX_UPTODATE  0x01
277 
278 struct _mu_imap_mailbox
279 {
280   int flags;
281   struct mu_imap_stat stats;     /* Mailbox statistics */
282   struct _mu_imap_message **msgs; /* Array of messages */
283   size_t msgs_cnt;               /* Number of used slots in msgs */
284   size_t msgs_max;               /* Number of slots in msgs */
285   mu_stream_t cache;          /* Message cache stream */
286   int last_error;             /* Last error code */
287   mu_mailbox_t mbox;
288 };
289 
290 # ifdef __cplusplus
291 }
292 # endif
293 
294 #endif /* _MAILUTILS_SYS_IMAP_H */
295