Commit 439f8c1a 439f8c1a9f99409087694f95c82f40c12e286371 by Sergey Poznyakoff

imap client: implement login and id commands.

* libproto/imap/id.c: New file.
* libproto/imap/login.c: New file.
* libproto/imap/Makefile.am: Add new files.
* libproto/imap/capability.c (mu_imap_capability): Clear
MU_IMAP_RESP before reading response.
Add MU_WRDSF_QUOTE to mu_wordsplit flags.
* libproto/imap/err.c (_mu_imap_seterrstr): Bugfix: initialize
imap->errstr.
* libproto/imap/logout.c (mu_imap_logout): Clear
MU_IMAP_RESP before reading response.
* libproto/imap/response.c (_mu_imap_response): Set error string.
* mu/imap.c (com_login, com_id): New functions.
(imap_comtab) <login, id>: New keywords.
1 parent 96cfdb5e
...@@ -49,8 +49,11 @@ int mu_imap_disconnect (mu_imap_t imap); ...@@ -49,8 +49,11 @@ int mu_imap_disconnect (mu_imap_t imap);
49 int mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter); 49 int mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter);
50 int mu_imap_capability_test (mu_imap_t imap, const char *name, 50 int mu_imap_capability_test (mu_imap_t imap, const char *name,
51 const char **pret); 51 const char **pret);
52 52
53 int mu_imap_login (mu_imap_t imap, const char *user, const char *pass);
53 int mu_imap_logout (mu_imap_t imap); 54 int mu_imap_logout (mu_imap_t imap);
55
56 int mu_imap_id (mu_imap_t imap, char **idenv, mu_list_t *plist);
54 57
55 int mu_imap_set_carrier (mu_imap_t imap, mu_stream_t carrier); 58 int mu_imap_set_carrier (mu_imap_t imap, mu_stream_t carrier);
56 int mu_imap_get_carrier (mu_imap_t imap, mu_stream_t *pcarrier); 59 int mu_imap_get_carrier (mu_imap_t imap, mu_stream_t *pcarrier);
......
...@@ -40,7 +40,9 @@ enum mu_imap_client_state ...@@ -40,7 +40,9 @@ enum mu_imap_client_state
40 MU_IMAP_GREETINGS, 40 MU_IMAP_GREETINGS,
41 MU_IMAP_CONNECTED, 41 MU_IMAP_CONNECTED,
42 MU_IMAP_CAPABILITY_RX, 42 MU_IMAP_CAPABILITY_RX,
43 MU_IMAP_LOGIN_RX,
43 MU_IMAP_LOGOUT_RX, 44 MU_IMAP_LOGOUT_RX,
45 MU_IMAP_ID_RX,
44 }; 46 };
45 47
46 enum mu_imap_response 48 enum mu_imap_response
......
...@@ -33,6 +33,7 @@ struct mu_kwd bool_keytab[] = { ...@@ -33,6 +33,7 @@ struct mu_kwd bool_keytab[] = {
33 /*{ "reuse", MU_WRDSF_REUSE },*/ 33 /*{ "reuse", MU_WRDSF_REUSE },*/
34 { "undef", MU_WRDSF_UNDEF }, 34 { "undef", MU_WRDSF_UNDEF },
35 { "novar", MU_WRDSF_NOVAR }, 35 { "novar", MU_WRDSF_NOVAR },
36 { "nocmd", MU_WRDSF_NOCMD },
36 { "ws", MU_WRDSF_WS }, 37 { "ws", MU_WRDSF_WS },
37 { "quote", MU_WRDSF_QUOTE }, 38 { "quote", MU_WRDSF_QUOTE },
38 { "squeeze_delims", MU_WRDSF_SQUEEZE_DELIMS }, 39 { "squeeze_delims", MU_WRDSF_SQUEEZE_DELIMS },
...@@ -205,7 +206,7 @@ main (int argc, char **argv) ...@@ -205,7 +206,7 @@ main (int argc, char **argv)
205 plaintext_option = !negate; 206 plaintext_option = !negate;
206 continue; 207 continue;
207 } 208 }
208 209
209 if (mu_kwd_xlat_name (bool_keytab, opt, &flag) == 0) 210 if (mu_kwd_xlat_name (bool_keytab, opt, &flag) == 0)
210 { 211 {
211 if (negate) 212 if (negate)
......
...@@ -36,6 +36,8 @@ libmu_imap_la_SOURCES = \ ...@@ -36,6 +36,8 @@ libmu_imap_la_SOURCES = \
36 destroy.c\ 36 destroy.c\
37 disconnect.c\ 37 disconnect.c\
38 err.c\ 38 err.c\
39 id.c\
40 login.c\
39 logout.c\ 41 logout.c\
40 response.c\ 42 response.c\
41 state.c\ 43 state.c\
......
...@@ -81,6 +81,7 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter) ...@@ -81,6 +81,7 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter)
81 status = mu_stream_printf (imap->carrier, "%s CAPABILITY\r\n", 81 status = mu_stream_printf (imap->carrier, "%s CAPABILITY\r\n",
82 imap->tag_str); 82 imap->tag_str);
83 MU_IMAP_CHECK_EAGAIN (imap, status); 83 MU_IMAP_CHECK_EAGAIN (imap, status);
84 MU_IMAP_FCLR (imap, MU_IMAP_RESP);
84 imap->state = MU_IMAP_CAPABILITY_RX; 85 imap->state = MU_IMAP_CAPABILITY_RX;
85 86
86 case MU_IMAP_CAPABILITY_RX: 87 case MU_IMAP_CAPABILITY_RX:
...@@ -103,7 +104,7 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter) ...@@ -103,7 +104,7 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter)
103 104
104 if (mu_wordsplit (str, &ws, 105 if (mu_wordsplit (str, &ws,
105 MU_WRDSF_NOVAR | MU_WRDSF_NOCMD | 106 MU_WRDSF_NOVAR | MU_WRDSF_NOCMD |
106 MU_WRDSF_SQUEEZE_DELIMS)) 107 MU_WRDSF_QUOTE | MU_WRDSF_SQUEEZE_DELIMS))
107 { 108 {
108 int ec = errno; 109 int ec = errno;
109 mu_error ("mu_imap_capability: cannot split line: %s", 110 mu_error ("mu_imap_capability: cannot split line: %s",
......
...@@ -32,6 +32,7 @@ _mu_imap_seterrstr (mu_imap_t imap, const char *str, size_t len) ...@@ -32,6 +32,7 @@ _mu_imap_seterrstr (mu_imap_t imap, const char *str, size_t len)
32 if (!p) 32 if (!p)
33 return ENOMEM; 33 return ENOMEM;
34 imap->errsize = len + 1; 34 imap->errsize = len + 1;
35 imap->errstr = p;
35 } 36 }
36 memcpy (imap->errstr, str, len); 37 memcpy (imap->errstr, str, len);
37 imap->errstr[len] = 0; 38 imap->errstr[len] = 0;
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2010 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/cstr.h>
26 #include <mailutils/wordsplit.h>
27 #include <mailutils/stream.h>
28 #include <mailutils/sys/imap.h>
29
30 static int
31 id_comp (const void *item, const void *value)
32 {
33 const char *id = item;
34 const char *needle = value;
35 return mu_c_strcasecmp (id, needle);
36 }
37
38 static int
39 parse_id_reply (mu_imap_t imap, mu_list_t *plist)
40 {
41 mu_list_t list;
42 int rc;
43 const char *response;
44 struct mu_wordsplit ws;
45 size_t i;
46
47 rc = mu_list_create (&list);
48 if (rc)
49 return rc;
50 mu_list_set_comparator (list, id_comp);
51 mu_list_set_destroy_item (list, mu_list_free_item);
52
53 rc = mu_list_get (imap->untagged_resp, 0, (void*) &response);
54 if (rc == MU_ERR_NOENT)
55 {
56 *plist = list;
57 return 0;
58 }
59 else if (rc)
60 {
61 mu_list_destroy (&list);
62 return rc;
63 }
64
65 ws.ws_delim = "() \t";
66 if (mu_wordsplit (response, &ws,
67 MU_WRDSF_NOVAR | MU_WRDSF_NOCMD |
68 MU_WRDSF_QUOTE | MU_WRDSF_DELIM |
69 MU_WRDSF_SQUEEZE_DELIMS |
70 MU_WRDSF_WS))
71 {
72 int ec = errno;
73 mu_error ("mu_imap_id: cannot split line: %s",
74 mu_wordsplit_strerror (&ws));
75 mu_list_destroy (&list);
76 return ec;
77 }
78
79 for (i = 1; i < ws.ws_wordc; i += 2)
80 {
81 size_t len, l1, l2;
82 char *elt;
83
84 if (i + 1 == ws.ws_wordc)
85 break;
86 l1 = strlen (ws.ws_wordv[i]);
87 l2 = strlen (ws.ws_wordv[i+1]);
88 len = l1 + l2 + 1;
89 elt = malloc (len + 1);
90 if (!elt)
91 break;
92
93 memcpy (elt, ws.ws_wordv[i], l1);
94 elt[l1] = 0;
95 memcpy (elt + l1 + 1, ws.ws_wordv[i+1], l2);
96 elt[len] = 0;
97 mu_list_append (list, elt);
98 }
99 mu_wordsplit_free (&ws);
100 *plist = list;
101 return 0;
102 }
103
104 int
105 mu_imap_id (mu_imap_t imap, char **idenv, mu_list_t *plist)
106 {
107 int status;
108
109 if (imap == NULL)
110 return EINVAL;
111 if (!imap->carrier)
112 return MU_ERR_NO_TRANSPORT;
113 if (imap->state != MU_IMAP_CONNECTED)
114 return MU_ERR_SEQ;
115
116 switch (imap->state)
117 {
118 case MU_IMAP_CONNECTED:
119 status = _mu_imap_tag_next (imap);
120 MU_IMAP_CHECK_EAGAIN (imap, status);
121 status = mu_stream_printf (imap->carrier, "%s ID ",
122 imap->tag_str);
123 MU_IMAP_CHECK_ERROR (imap, status);
124 if (!idenv)
125 status = mu_stream_printf (imap->carrier, "NIL");
126 else
127 {
128 if (idenv[0])
129 {
130 int i;
131 char *delim = "(";
132 for (i = 0; idenv[i]; i++)
133 {
134 status = mu_stream_printf (imap->carrier, "%s\"%s\"",
135 delim, idenv[i]);
136 MU_IMAP_CHECK_ERROR (imap, status);
137
138 delim = " ";
139 if (status)
140 break;
141 }
142 status = mu_stream_printf (imap->carrier, ")");
143 }
144 else
145 status = mu_stream_printf (imap->carrier, "()");
146 }
147 MU_IMAP_CHECK_ERROR (imap, status);
148 status = mu_stream_printf (imap->carrier, "\r\n");
149 MU_IMAP_CHECK_ERROR (imap, status);
150 MU_IMAP_FCLR (imap, MU_IMAP_RESP);
151 imap->state = MU_IMAP_ID_RX;
152
153 case MU_IMAP_ID_RX:
154 status = _mu_imap_response (imap);
155 MU_IMAP_CHECK_EAGAIN (imap, status);
156 switch (imap->resp_code)
157 {
158 case MU_IMAP_OK:
159 imap->imap_state = MU_IMAP_STATE_AUTH;
160 if (plist)
161 status = parse_id_reply (imap, plist);
162 break;
163
164 case MU_IMAP_NO:
165 status = EACCES;
166 break;
167
168 case MU_IMAP_BAD:
169 status = MU_ERR_BADREPLY;
170 break;
171 }
172 imap->state = MU_IMAP_CONNECTED;
173 break;
174
175 default:
176 status = EINPROGRESS;
177 }
178 return status;
179 }
180
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2010 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 <mailutils/errno.h>
23 #include <mailutils/stream.h>
24 #include <mailutils/sys/imap.h>
25
26 int
27 mu_imap_login (mu_imap_t imap, const char *user, const char *pass)
28 {
29 int status;
30
31 if (imap == NULL)
32 return EINVAL;
33 if (!imap->carrier)
34 return MU_ERR_NO_TRANSPORT;
35 if (imap->state != MU_IMAP_CONNECTED)
36 return MU_ERR_SEQ;
37 if (imap->imap_state != MU_IMAP_STATE_NONAUTH)
38 return MU_ERR_SEQ;
39
40 switch (imap->state)
41 {
42 case MU_IMAP_CONNECTED:
43 if (mu_imap_trace_mask (imap, MU_IMAP_TRACE_QRY, MU_XSCRIPT_SECURE))
44 _mu_imap_xscript_level (imap, MU_XSCRIPT_SECURE);
45 status = _mu_imap_tag_next (imap);
46 MU_IMAP_CHECK_EAGAIN (imap, status);
47 status = mu_stream_printf (imap->carrier, "%s LOGIN \"%s\" \"%s\"\r\n",
48 imap->tag_str, user, pass);
49 _mu_imap_xscript_level (imap, MU_XSCRIPT_NORMAL);
50 /* FIXME: how to obscure the passwd in the stream buffer? */
51 MU_IMAP_CHECK_EAGAIN (imap, status);
52 MU_IMAP_FCLR (imap, MU_IMAP_RESP);
53 imap->state = MU_IMAP_LOGIN_RX;
54
55 case MU_IMAP_LOGIN_RX:
56 status = _mu_imap_response (imap);
57 MU_IMAP_CHECK_EAGAIN (imap, status);
58 switch (imap->resp_code)
59 {
60 case MU_IMAP_OK:
61 imap->imap_state = MU_IMAP_STATE_AUTH;
62 break;
63
64 case MU_IMAP_NO:
65 status = EACCES;
66 break;
67
68 case MU_IMAP_BAD:
69 status = MU_ERR_BADREPLY;
70 break;
71 }
72 imap->state = MU_IMAP_CONNECTED;
73 break;
74
75 default:
76 status = EINPROGRESS;
77 }
78 return status;
79 }
80
...@@ -43,6 +43,7 @@ mu_imap_logout (mu_imap_t imap) ...@@ -43,6 +43,7 @@ mu_imap_logout (mu_imap_t imap)
43 status = mu_stream_printf (imap->carrier, "%s LOGOUT\r\n", 43 status = mu_stream_printf (imap->carrier, "%s LOGOUT\r\n",
44 imap->tag_str); 44 imap->tag_str);
45 MU_IMAP_CHECK_EAGAIN (imap, status); 45 MU_IMAP_CHECK_EAGAIN (imap, status);
46 MU_IMAP_FCLR (imap, MU_IMAP_RESP);
46 imap->state = MU_IMAP_LOGOUT_RX; 47 imap->state = MU_IMAP_LOGOUT_RX;
47 48
48 case MU_IMAP_LOGOUT_RX: 49 case MU_IMAP_LOGOUT_RX:
......
...@@ -85,12 +85,24 @@ _mu_imap_response (mu_imap_t imap) ...@@ -85,12 +85,24 @@ _mu_imap_response (mu_imap_t imap)
85 imap->tagbuf = np; 85 imap->tagbuf = np;
86 } 86 }
87 strcpy (imap->tagbuf, p); 87 strcpy (imap->tagbuf, p);
88 if (IS_PREFIX(p, len, "OK")) 88 if (IS_PREFIX (p, len, "OK"))
89 imap->resp_code = MU_IMAP_OK; 89 {
90 else if (IS_PREFIX(p, len, "NO")) 90 imap->resp_code = MU_IMAP_OK;
91 imap->resp_code = MU_IMAP_NO; 91 p = mu_str_skip_cset (p + 2, " ");
92 else if (IS_PREFIX(p, len, "BAD")) 92 _mu_imap_seterrstr (imap, p, strlen (p));
93 imap->resp_code = MU_IMAP_BAD; 93 }
94 else if (IS_PREFIX (p, len, "NO"))
95 {
96 imap->resp_code = MU_IMAP_NO;
97 p = mu_str_skip_cset (p + 2, " ");
98 _mu_imap_seterrstr (imap, p, strlen (p));
99 }
100 else if (IS_PREFIX (p, len, "BAD"))
101 {
102 imap->resp_code = MU_IMAP_BAD;
103 p = mu_str_skip_cset (p + 2, " ");
104 _mu_imap_seterrstr (imap, p, strlen (p));
105 }
94 else 106 else
95 status = MU_ERR_BADREPLY; 107 status = MU_ERR_BADREPLY;
96 MU_IMAP_FSET (imap, MU_IMAP_RESP); 108 MU_IMAP_FSET (imap, MU_IMAP_RESP);
......
...@@ -358,6 +358,102 @@ com_capability (int argc, char **argv) ...@@ -358,6 +358,102 @@ com_capability (int argc, char **argv)
358 return status; 358 return status;
359 } 359 }
360 360
361 static int
362 com_login (int argc, char **argv)
363 {
364 int status;
365 char *pwd, *passbuf = NULL;
366
367 if (argc == 2)
368 {
369 if (!mutool_shell_interactive)
370 {
371 mu_error (_("login: password required"));
372 return 1;
373 }
374 status = mu_getpass (mustrin, mustrout, "Password:", &passbuf);
375 if (status)
376 return status;
377 pwd = passbuf;
378 }
379 else
380 pwd = argv[2];
381
382 status = mu_imap_login (imap, argv[1], pwd);
383 memset (pwd, 0, strlen (pwd));
384 free (passbuf);
385 if (status == 0)
386 imap_prompt_env ();
387 else
388 {
389 const char *str;
390
391 mu_error ("authentication failed: %s", mu_strerror (status));
392 if (mu_imap_strerror (imap, &str) == 0)
393 mu_error ("server reply: %s", str);
394 }
395 return 0;
396 }
397
398
399 static int
400 _print_id (void *item, void *data)
401 {
402 const char *id = item;
403 mu_stream_printf (mustrout, "ID: %s %s\n", id, id + strlen (id) + 1);
404 return 0;
405 }
406
407 static int
408 com_id (int argc, char **argv)
409 {
410 mu_list_t list;
411 char *test = NULL;
412 int status;
413
414 argv++;
415 if (argv[0] && strcmp (argv[0], "-test") == 0)
416 {
417 argv++;
418 if (argv[0] == NULL)
419 {
420 mu_error ("id -test requires an argument");
421 return 0;
422 }
423 test = argv[0];
424 argv++;
425 }
426
427 status = mu_imap_id (imap, argv + 1, &list);
428 if (status == 0)
429 {
430 if (test)
431 {
432 const char *res;
433 int rc = mu_list_locate (list, test, (void*)&res);
434
435 switch (rc)
436 {
437 case 0:
438 mu_stream_printf (mustrout, "%s: %s\n", test,
439 res + strlen (res) + 1);
440 break;
441
442 case MU_ERR_NOENT:
443 mu_stream_printf (mustrout, "%s is not set\n", test);
444 break;
445
446 default:
447 return rc;
448 }
449 }
450 else
451 mu_list_do (list, _print_id, NULL);
452 mu_list_destroy (&list);
453 }
454 return status;
455 }
456
361 457
362 struct mutool_command imap_comtab[] = { 458 struct mutool_command imap_comtab[] = {
363 { "capability", 1, -1, com_capability, 459 { "capability", 1, -1, com_capability,
...@@ -375,9 +471,15 @@ struct mutool_command imap_comtab[] = { ...@@ -375,9 +471,15 @@ struct mutool_command imap_comtab[] = {
375 com_disconnect, 471 com_disconnect,
376 NULL, 472 NULL,
377 N_("close connection") }, 473 N_("close connection") },
474 { "login", 2, 3, com_login,
475 N_("USER [PASS]"),
476 N_("login to the server") },
378 { "logout", 1, 1, com_logout, 477 { "logout", 1, 1, com_logout,
379 NULL, 478 NULL,
380 N_("quit imap session") }, 479 N_("quit imap session") },
480 { "id", 1, -1, com_id,
481 N_("[-test KW] [ARG [ARG...]]"),
482 N_("send ID command") },
381 { "quit", 1, 1, com_logout, 483 { "quit", 1, 1, com_logout,
382 NULL, 484 NULL,
383 N_("same as `logout'") }, 485 N_("same as `logout'") },
......