Commit 7e78c6af 7e78c6af4aa397ff422db07489850d40a9360a8c by Sergey Poznyakoff

Imap client: implement list.

* libmailutils/stdstream/basestr.c (mu_strout): Bugfix: initialize
destroy function.
* include/mailutils/imap.h (imap_command)
(mu_imap_gencom): Move to sys/imap.h
(mu_imap_list,mu_imap_list_new): New protos.
* include/mailutils/sys/imap.h (imap_command): New struct (from ../imap.h).
<handler>: Rename to tagged_handler.
(untagged_handler,untagged_handler_data): New members. All uses changed.
(mu_imap_gencom): New proto.

* libproto/imap/list.c: New file.
* libproto/imap/Makefile.am: Add list.c
* libproto/imap/gencom.c: Use supplied untagged_handler to
analize untagged response.

* mu/imap.c: Implement list command.
1 parent 85c5f9a8
...@@ -44,19 +44,6 @@ enum mu_imap_session_state ...@@ -44,19 +44,6 @@ enum mu_imap_session_state
44 int mu_imap_create (mu_imap_t *pimap); 44 int mu_imap_create (mu_imap_t *pimap);
45 void mu_imap_destroy (mu_imap_t *pimap); 45 void mu_imap_destroy (mu_imap_t *pimap);
46 46
47 struct imap_command
48 {
49 int session_state;
50 char *capa;
51 int rx_state;
52 int uid;
53 int argc;
54 char const **argv;
55 void (*handler) (mu_imap_t);
56 };
57
58 int mu_imap_gencom (mu_imap_t imap, struct imap_command *cmd);
59
60 int mu_imap_connect (mu_imap_t imap); 47 int mu_imap_connect (mu_imap_t imap);
61 int mu_imap_disconnect (mu_imap_t imap); 48 int mu_imap_disconnect (mu_imap_t imap);
62 49
...@@ -100,6 +87,11 @@ int mu_imap_append_message (mu_imap_t imap, const char *mailbox, int flags, ...@@ -100,6 +87,11 @@ int mu_imap_append_message (mu_imap_t imap, const char *mailbox, int flags,
100 struct tm *tm, struct mu_timezone *tz, 87 struct tm *tm, struct mu_timezone *tz,
101 mu_message_t msg); 88 mu_message_t msg);
102 89
90 int mu_imap_list (mu_imap_t imap, const char *refname, const char *mboxname,
91 mu_list_t retlist);
92 int mu_imap_list_new (mu_imap_t imap, const char *refname, const char *mboxname,
93 mu_list_t *plist);
94
103 int mu_imap_set_carrier (mu_imap_t imap, mu_stream_t carrier); 95 int mu_imap_set_carrier (mu_imap_t imap, mu_stream_t carrier);
104 int mu_imap_get_carrier (mu_imap_t imap, mu_stream_t *pcarrier); 96 int mu_imap_get_carrier (mu_imap_t imap, mu_stream_t *pcarrier);
105 97
......
...@@ -66,6 +66,7 @@ enum mu_imap_client_state ...@@ -66,6 +66,7 @@ enum mu_imap_client_state
66 MU_IMAP_CLIENT_COPY_RX, 66 MU_IMAP_CLIENT_COPY_RX,
67 MU_IMAP_CLIENT_EXPUNGE_RX, 67 MU_IMAP_CLIENT_EXPUNGE_RX,
68 MU_IMAP_CLIENT_APPEND_RX, 68 MU_IMAP_CLIENT_APPEND_RX,
69 MU_IMAP_CLIENT_LIST_RX,
69 MU_IMAP_CLIENT_CLOSING 70 MU_IMAP_CLIENT_CLOSING
70 }; 71 };
71 72
...@@ -135,6 +136,24 @@ int _mu_imap_trace_enable (mu_imap_t imap); ...@@ -135,6 +136,24 @@ int _mu_imap_trace_enable (mu_imap_t imap);
135 int _mu_imap_trace_disable (mu_imap_t imap); 136 int _mu_imap_trace_disable (mu_imap_t imap);
136 int _mu_imap_xscript_level (mu_imap_t imap, int xlev); 137 int _mu_imap_xscript_level (mu_imap_t imap, int xlev);
137 138
139 typedef void (*mu_imap_response_action_t) (mu_imap_t imap, mu_list_t resp,
140 void *data);
141
142 struct imap_command
143 {
144 int session_state;
145 char *capa;
146 int rx_state;
147 int uid;
148 int argc;
149 char const **argv;
150 void (*tagged_handler) (mu_imap_t);
151 mu_imap_response_action_t untagged_handler;
152 void *untagged_handler_data;
153 };
154
155 int mu_imap_gencom (mu_imap_t imap, struct imap_command *cmd);
156
138 /* If status indicates an error, return. 157 /* If status indicates an error, return.
139 */ 158 */
140 #define MU_IMAP_CHECK_ERROR(imap, status) \ 159 #define MU_IMAP_CHECK_ERROR(imap, status) \
...@@ -182,9 +201,6 @@ int _mu_imap_tag_next (mu_imap_t imap); ...@@ -182,9 +201,6 @@ int _mu_imap_tag_next (mu_imap_t imap);
182 int _mu_imap_tag_clr (mu_imap_t imap); 201 int _mu_imap_tag_clr (mu_imap_t imap);
183 202
184 203
185 typedef void (*mu_imap_response_action_t) (mu_imap_t imap, mu_list_t resp,
186 void *data);
187
188 int _mu_imap_untagged_response_to_list (mu_imap_t imap, mu_list_t *plist); 204 int _mu_imap_untagged_response_to_list (mu_imap_t imap, mu_list_t *plist);
189 int _mu_imap_process_untagged_response (mu_imap_t imap, mu_list_t list, 205 int _mu_imap_process_untagged_response (mu_imap_t imap, mu_list_t list,
190 mu_imap_response_action_t fun, 206 mu_imap_response_action_t fun,
......
...@@ -128,6 +128,7 @@ static struct _mu_file_stream stdstream[2] = { ...@@ -128,6 +128,7 @@ static struct _mu_file_stream stdstream[2] = {
128 { { ref_count: 1, 128 { { ref_count: 1,
129 buftype: mu_buffer_none, 129 buftype: mu_buffer_none,
130 flags: MU_STREAM_WRITE, 130 flags: MU_STREAM_WRITE,
131 destroy: bootstrap_destroy,
131 event_cb: std_bootstrap, 132 event_cb: std_bootstrap,
132 event_mask: _MU_STR_EVMASK (_MU_STR_EVENT_BOOTSTRAP) 133 event_mask: _MU_STR_EVMASK (_MU_STR_EVENT_BOOTSTRAP)
133 }, fd: MU_STDOUT_FD, filename: "<stdout>", 134 }, fd: MU_STDOUT_FD, filename: "<stdout>",
......
...@@ -48,6 +48,7 @@ libmu_imap_la_SOURCES = \ ...@@ -48,6 +48,7 @@ libmu_imap_la_SOURCES = \
48 err.c\ 48 err.c\
49 expunge.c\ 49 expunge.c\
50 id.c\ 50 id.c\
51 list.c\
51 login.c\ 52 login.c\
52 logout.c\ 53 logout.c\
53 mbcreate.c\ 54 mbcreate.c\
......
...@@ -39,7 +39,8 @@ mu_imap_copy (mu_imap_t imap, int uid, const char *msgset, const char *mailbox) ...@@ -39,7 +39,8 @@ mu_imap_copy (mu_imap_t imap, int uid, const char *msgset, const char *mailbox)
39 com.uid = 0; 39 com.uid = 0;
40 com.argc = 3; 40 com.argc = 3;
41 com.argv = argv; 41 com.argv = argv;
42 com.handler = NULL; 42 com.tagged_handler = NULL;
43 com.untagged_handler = NULL;
43 44
44 return mu_imap_gencom (imap, &com); 45 return mu_imap_gencom (imap, &com);
45 } 46 }
......
...@@ -40,7 +40,8 @@ mu_imap_delete (mu_imap_t imap, const char *mailbox) ...@@ -40,7 +40,8 @@ mu_imap_delete (mu_imap_t imap, const char *mailbox)
40 com.uid = 0; 40 com.uid = 0;
41 com.argc = 2; 41 com.argc = 2;
42 com.argv = argv; 42 com.argv = argv;
43 com.handler = NULL; 43 com.tagged_handler = NULL;
44 com.untagged_handler = NULL;
44 45
45 return mu_imap_gencom (imap, &com); 46 return mu_imap_gencom (imap, &com);
46 } 47 }
......
...@@ -44,7 +44,8 @@ mu_imap_fetch (mu_imap_t imap, int uid, const char *msgset, const char *items) ...@@ -44,7 +44,8 @@ mu_imap_fetch (mu_imap_t imap, int uid, const char *msgset, const char *items)
44 com.uid = uid; 44 com.uid = uid;
45 com.argc = 3; 45 com.argc = 3;
46 com.argv = argv; 46 com.argv = argv;
47 com.handler = NULL; 47 com.tagged_handler = NULL;
48 com.untagged_handler = NULL;
48 49
49 return mu_imap_gencom (imap, &com); 50 return mu_imap_gencom (imap, &com);
50 } 51 }
......
...@@ -74,10 +74,11 @@ mu_imap_gencom (mu_imap_t imap, struct imap_command *cmd) ...@@ -74,10 +74,11 @@ mu_imap_gencom (mu_imap_t imap, struct imap_command *cmd)
74 74
75 if (imap->client_state == cmd->rx_state) 75 if (imap->client_state == cmd->rx_state)
76 { 76 {
77 status = _mu_imap_response (imap, NULL, NULL); 77 status = _mu_imap_response (imap, cmd->untagged_handler,
78 cmd->untagged_handler_data);
78 MU_IMAP_CHECK_EAGAIN (imap, status); 79 MU_IMAP_CHECK_EAGAIN (imap, status);
79 if (cmd->handler) 80 if (cmd->tagged_handler)
80 cmd->handler (imap); 81 cmd->tagged_handler (imap);
81 switch (imap->resp_code) 82 switch (imap->resp_code)
82 { 83 {
83 case MU_IMAP_OK: 84 case MU_IMAP_OK:
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 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/address.h>
26 #include <mailutils/cstr.h>
27 #include <mailutils/cctype.h>
28 #include <mailutils/list.h>
29 #include <mailutils/imap.h>
30 #include <mailutils/sys/imap.h>
31
32 struct list_closure
33 {
34 int error_code;
35 mu_list_t retlist;
36 };
37
38 static int
39 count_level (const char *name, int delim)
40 {
41 int level = 0;
42
43 while (*name)
44 if (*name++ == delim)
45 level++;
46 return level;
47 }
48
49 static int
50 list_attr_conv (void *item, void *data)
51 {
52 struct imap_list_element *elt = item;
53 struct mu_list_response *rp = data;
54
55 if (elt->type != imap_eltype_string)
56 return 0;
57 if (mu_c_strcasecmp (elt->v.string, "\\Noinferiors"))
58 rp->type |= MU_FOLDER_ATTRIBUTE_DIRECTORY;
59 if (mu_c_strcasecmp (elt->v.string, "\\Noselect"))
60 rp->type |= MU_FOLDER_ATTRIBUTE_FILE;
61 /* FIXME: \Marked nad \Unmarked have no correspondence in flags. */
62 return 0;
63 }
64
65 static void
66 list_untagged_handler (mu_imap_t imap, mu_list_t resp, void *data)
67 {
68 struct list_closure *clos = data;
69 struct imap_list_element *elt;
70 size_t count;
71
72 if (clos->error_code)
73 return;
74
75 mu_list_count (resp, &count);
76 if (count == 4 &&
77 _mu_imap_list_nth_element_is_string (resp, 0, "LIST"))
78 {
79 struct mu_list_response *rp;
80
81 rp = calloc (1, sizeof (*rp));
82 if (!rp)
83 {
84 clos->error_code = ENOMEM;
85 return;
86 }
87
88 elt = _mu_imap_list_at (resp, 1);
89 if (!(elt && elt->type == imap_eltype_list))
90 return;
91 rp->type = 0;
92 mu_list_foreach (elt->v.list, list_attr_conv, rp);
93
94 elt = _mu_imap_list_at (resp, 3);
95 if (!(elt && elt->type == imap_eltype_string))
96 return;
97 rp->name = strdup (elt->v.string);
98 if (!rp->name)
99 {
100 free (rp);
101 clos->error_code = ENOMEM;
102 return;
103 }
104
105 elt = _mu_imap_list_at (resp, 2);
106 if (!(elt && elt->type == imap_eltype_string))
107 return;
108 if (mu_c_strcasecmp (elt->v.string, "NIL") == 0)
109 {
110 rp->separator = 0;
111 rp->level = 0;
112 }
113 else
114 {
115 rp->separator = elt->v.string[0];
116 rp->level = count_level (rp->name, rp->separator);
117 }
118 if ((clos->error_code = mu_list_append (clos->retlist, rp)))
119 mu_list_response_free (rp);
120 }
121 }
122
123 int
124 mu_imap_list (mu_imap_t imap, const char *refname, const char *mboxname,
125 mu_list_t retlist)
126 {
127 char const *argv[3];
128 static struct imap_command com;
129 struct list_closure clos;
130 int rc;
131
132 argv[0] = "LIST";
133 argv[1] = refname;
134 argv[2] = mboxname;
135
136 clos.error_code = 0;
137 clos.retlist = retlist;
138
139 com.session_state = MU_IMAP_SESSION_AUTH;
140 com.capa = NULL;
141 com.rx_state = MU_IMAP_CLIENT_LIST_RX;
142 com.uid = 0;
143 com.argc = 3;
144 com.argv = argv;
145 com.tagged_handler = NULL;
146 com.untagged_handler = list_untagged_handler;
147 com.untagged_handler_data = &clos;
148
149 rc = mu_imap_gencom (imap, &com);
150 if (rc == 0)
151 rc = clos.error_code;
152
153 return rc;
154 }
155
156 int
157 mu_imap_list_new (mu_imap_t imap, const char *refname, const char *mboxname,
158 mu_list_t *plist)
159 {
160 mu_list_t list;
161 int rc = mu_list_create (&list);
162 if (rc == 0)
163 {
164 mu_list_set_destroy_item (list, mu_list_response_free);
165 rc = mu_imap_list (imap, refname, mboxname, list);
166 if (rc)
167 mu_list_destroy (&list);
168 else
169 *plist = list;
170 }
171 return rc;
172 }
...@@ -40,7 +40,8 @@ mu_imap_mailbox_create (mu_imap_t imap, const char *mailbox) ...@@ -40,7 +40,8 @@ mu_imap_mailbox_create (mu_imap_t imap, const char *mailbox)
40 com.uid = 0; 40 com.uid = 0;
41 com.argc = 2; 41 com.argc = 2;
42 com.argv = argv; 42 com.argv = argv;
43 com.handler = NULL; 43 com.tagged_handler = NULL;
44 com.untagged_handler = NULL;
44 45
45 return mu_imap_gencom (imap, &com); 46 return mu_imap_gencom (imap, &com);
46 } 47 }
......
...@@ -39,7 +39,8 @@ mu_imap_rename (mu_imap_t imap, const char *mailbox, const char *new_mailbox) ...@@ -39,7 +39,8 @@ mu_imap_rename (mu_imap_t imap, const char *mailbox, const char *new_mailbox)
39 com.uid = 0; 39 com.uid = 0;
40 com.argc = 3; 40 com.argc = 3;
41 com.argv = argv; 41 com.argv = argv;
42 com.handler = NULL; 42 com.tagged_handler = NULL;
43 com.untagged_handler = NULL;
43 44
44 return mu_imap_gencom (imap, &com); 45 return mu_imap_gencom (imap, &com);
45 } 46 }
......
...@@ -41,7 +41,8 @@ mu_imap_store (mu_imap_t imap, int uid, const char *msgset, const char *items) ...@@ -41,7 +41,8 @@ mu_imap_store (mu_imap_t imap, int uid, const char *msgset, const char *items)
41 com.uid = uid; 41 com.uid = uid;
42 com.argc = 3; 42 com.argc = 3;
43 com.argv = argv; 43 com.argv = argv;
44 com.handler = NULL; 44 com.tagged_handler = NULL;
45 com.untagged_handler = NULL;
45 46
46 return mu_imap_gencom (imap, &com); 47 return mu_imap_gencom (imap, &com);
47 } 48 }
......
...@@ -895,6 +895,43 @@ com_append (int argc, char **argv) ...@@ -895,6 +895,43 @@ com_append (int argc, char **argv)
895 return 0; 895 return 0;
896 } 896 }
897 897
898 static int
899 print_list_item (void *item, void *data)
900 {
901 struct mu_list_response *resp = item;
902 mu_stream_t out = data;
903
904 mu_stream_printf (out,
905 "%c%c %c %4d %s\n",
906 (resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY) ? 'd' : '-',
907 (resp->type & MU_FOLDER_ATTRIBUTE_FILE) ? 'f' : '-',
908 resp->separator,
909 resp->level,
910 resp->name);
911 return 0;
912 }
913
914 static int
915 com_list (int argc, char **argv)
916 {
917 mu_list_t list;
918 int rc;
919 mu_stream_t out;
920
921 rc = mu_imap_list_new (imap, argv[1], argv[2], &list);
922 if (rc)
923 {
924 report_failure ("list", rc);
925 return 0;
926 }
927
928 out = mutool_open_pager ();
929 mu_list_foreach (list, print_list_item, out);
930 mu_stream_unref (out);
931 return 0;
932 }
933
934
898 struct mutool_command imap_comtab[] = { 935 struct mutool_command imap_comtab[] = {
899 { "capability", 1, -1, 0, 936 { "capability", 1, -1, 0,
900 com_capability, 937 com_capability,
...@@ -982,6 +1019,10 @@ struct mutool_command imap_comtab[] = { ...@@ -982,6 +1019,10 @@ struct mutool_command imap_comtab[] = {
982 com_append, 1019 com_append,
983 N_("[-time DATETIME] [-flag FLAG] MAILBOX FILE"), 1020 N_("[-time DATETIME] [-flag FLAG] MAILBOX FILE"),
984 N_("append message text from FILE to MAILBOX") }, 1021 N_("append message text from FILE to MAILBOX") },
1022 { "list", 3, 3, 0,
1023 com_list,
1024 N_("REF MBOX"),
1025 N_("List matching mailboxes") },
985 { "quit", 1, 1, 0, 1026 { "quit", 1, 1, 0,
986 com_logout, 1027 com_logout,
987 NULL, 1028 NULL,
......