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/stream.h>
26 #include <mailutils/tls.h>
27 #include <mailutils/imap.h>
28 #include <mailutils/sys/imap.h>
29 
30 int
mu_imap_starttls(mu_imap_t imap)31 mu_imap_starttls (mu_imap_t imap)
32 {
33 #ifdef WITH_TLS
34   int status;
35   mu_stream_t tlsstream, streams[2];
36 
37   if (imap == NULL)
38     return EINVAL;
39   if (!imap->io)
40     return MU_ERR_NO_TRANSPORT;
41   if (imap->session_state == MU_IMAP_SESSION_INIT)
42     return MU_ERR_SEQ;
43 
44   status = mu_imap_capability_test (imap, "STARTTLS", NULL);
45   if (status == MU_ERR_NOENT)
46     return ENOSYS;
47   else if (status)
48     return status;
49 
50   switch (imap->client_state)
51     {
52     case MU_IMAP_CLIENT_READY:
53       status = _mu_imap_tag_next (imap);
54       MU_IMAP_CHECK_EAGAIN (imap, status);
55       status = mu_imapio_printf (imap->io, "%s STARTTLS\r\n", imap->tag_str);
56       MU_IMAP_CHECK_ERROR (imap, status);
57       MU_IMAP_FCLR (imap, MU_IMAP_RESP);
58       imap->client_state = MU_IMAP_CLIENT_STARTTLS_RX;
59 
60     case MU_IMAP_CLIENT_STARTTLS_RX:
61       status = _mu_imap_response (imap, NULL, NULL);
62       MU_IMAP_CHECK_EAGAIN (imap, status);
63       switch (imap->response)
64 	{
65 	case MU_IMAP_OK:
66 	  status = mu_imapio_get_streams (imap->io, streams);
67 	  MU_IMAP_CHECK_EAGAIN (imap, status);
68 	  status = mu_tls_client_stream_create (&tlsstream,
69 						streams[0], streams[1], 0);
70 	  mu_stream_unref (streams[0]);
71 	  mu_stream_unref (streams[1]);
72 	  MU_IMAP_CHECK_EAGAIN (imap, status);
73 	  streams[0] = streams[1] = tlsstream;
74 	  status = mu_imapio_set_streams (imap->io, streams);
75 	  mu_stream_unref (streams[0]);
76 	  mu_stream_unref (streams[1]);
77 	  MU_IMAP_CHECK_EAGAIN (imap, status);
78 	  /* Invalidate the capability list */
79 	  mu_list_destroy (&imap->capa);
80 	  status = 0;
81 	  break;
82 
83 	case MU_IMAP_NO:
84 	  status = MU_ERR_FAILURE;
85 	  break;
86 
87 	case MU_IMAP_BAD:
88 	  status = MU_ERR_BADREPLY;
89 	  break;
90 	}
91 
92       imap->client_state = MU_IMAP_CLIENT_READY;
93       break;
94 
95     default:
96       status = EINPROGRESS;
97     }
98   return status;
99 #else
100   return ENOSYS;
101 #endif
102 }
103 
104