mutt stable branch with some hacks
1/*
2 * Copyright (C) 2000-2007 Brendan Cully <brendan@kublai.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program 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
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19/* remote host account manipulation (POP/IMAP) */
20
21#if HAVE_CONFIG_H
22# include "config.h"
23#endif
24
25#include "mutt.h"
26#include "account.h"
27#include "url.h"
28
29/* mutt_account_match: compare account info (host/port/user) */
30int mutt_account_match (const ACCOUNT* a1, const ACCOUNT* a2)
31{
32 const char* user = NONULL (Username);
33
34 if (a1->type != a2->type)
35 return 0;
36 if (ascii_strcasecmp (a1->host, a2->host))
37 return 0;
38 if (a1->port != a2->port)
39 return 0;
40
41#ifdef USE_IMAP
42 if (a1->type == MUTT_ACCT_TYPE_IMAP)
43 {
44 if (ImapUser)
45 user = ImapUser;
46 }
47#endif
48
49#ifdef USE_POP
50 if (a1->type == MUTT_ACCT_TYPE_POP && PopUser)
51 user = PopUser;
52#endif
53
54 if (a1->flags & a2->flags & MUTT_ACCT_USER)
55 return (!strcmp (a1->user, a2->user));
56 if (a1->flags & MUTT_ACCT_USER)
57 return (!strcmp (a1->user, user));
58 if (a2->flags & MUTT_ACCT_USER)
59 return (!strcmp (a2->user, user));
60
61 return 1;
62}
63
64/* mutt_account_fromurl: fill account with information from url. */
65int mutt_account_fromurl (ACCOUNT* account, ciss_url_t* url)
66{
67 /* must be present */
68 if (url->host)
69 strfcpy (account->host, url->host, sizeof (account->host));
70 else
71 return -1;
72
73 if (url->user)
74 {
75 strfcpy (account->user, url->user, sizeof (account->user));
76 account->flags |= MUTT_ACCT_USER;
77 }
78 if (url->pass)
79 {
80 strfcpy (account->pass, url->pass, sizeof (account->pass));
81 account->flags |= MUTT_ACCT_PASS;
82 }
83 if (url->port)
84 {
85 account->port = url->port;
86 account->flags |= MUTT_ACCT_PORT;
87 }
88
89 return 0;
90}
91
92/* mutt_account_tourl: fill URL with info from account. The URL information
93 * is a set of pointers into account - don't free or edit account until
94 * you've finished with url (make a copy of account if you need it for
95 * a while). */
96void mutt_account_tourl (ACCOUNT* account, ciss_url_t* url)
97{
98 url->scheme = U_UNKNOWN;
99 url->user = NULL;
100 url->pass = NULL;
101 url->port = 0;
102
103#ifdef USE_IMAP
104 if (account->type == MUTT_ACCT_TYPE_IMAP)
105 {
106 if (account->flags & MUTT_ACCT_SSL)
107 url->scheme = U_IMAPS;
108 else
109 url->scheme = U_IMAP;
110 }
111#endif
112
113#ifdef USE_POP
114 if (account->type == MUTT_ACCT_TYPE_POP)
115 {
116 if (account->flags & MUTT_ACCT_SSL)
117 url->scheme = U_POPS;
118 else
119 url->scheme = U_POP;
120 }
121#endif
122
123#ifdef USE_SMTP
124 if (account->type == MUTT_ACCT_TYPE_SMTP)
125 {
126 if (account->flags & MUTT_ACCT_SSL)
127 url->scheme = U_SMTPS;
128 else
129 url->scheme = U_SMTP;
130 }
131#endif
132
133 url->host = account->host;
134 if (account->flags & MUTT_ACCT_PORT)
135 url->port = account->port;
136 if (account->flags & MUTT_ACCT_USER)
137 url->user = account->user;
138 if (account->flags & MUTT_ACCT_PASS)
139 url->pass = account->pass;
140}
141
142/* mutt_account_getuser: retrieve username into ACCOUNT, if necessary */
143int mutt_account_getuser (ACCOUNT* account)
144{
145 char prompt[SHORT_STRING];
146
147 /* already set */
148 if (account->flags & MUTT_ACCT_USER)
149 return 0;
150#ifdef USE_IMAP
151 else if ((account->type == MUTT_ACCT_TYPE_IMAP) && ImapUser)
152 strfcpy (account->user, ImapUser, sizeof (account->user));
153#endif
154#ifdef USE_POP
155 else if ((account->type == MUTT_ACCT_TYPE_POP) && PopUser)
156 strfcpy (account->user, PopUser, sizeof (account->user));
157#endif
158 else if (option (OPTNOCURSES))
159 return -1;
160 /* prompt (defaults to unix username), copy into account->user */
161 else
162 {
163 snprintf (prompt, sizeof (prompt), _("Username at %s: "), account->host);
164 strfcpy (account->user, NONULL (Username), sizeof (account->user));
165 if (mutt_get_field_unbuffered (prompt, account->user, sizeof (account->user), 0))
166 return -1;
167 }
168
169 account->flags |= MUTT_ACCT_USER;
170
171 return 0;
172}
173
174int mutt_account_getlogin (ACCOUNT* account)
175{
176 /* already set */
177 if (account->flags & MUTT_ACCT_LOGIN)
178 return 0;
179#ifdef USE_IMAP
180 else if (account->type == MUTT_ACCT_TYPE_IMAP)
181 {
182 if (ImapLogin)
183 {
184 strfcpy (account->login, ImapLogin, sizeof (account->login));
185 account->flags |= MUTT_ACCT_LOGIN;
186 }
187 }
188#endif
189
190 if (!(account->flags & MUTT_ACCT_LOGIN))
191 {
192 mutt_account_getuser (account);
193 strfcpy (account->login, account->user, sizeof (account->login));
194 }
195
196 account->flags |= MUTT_ACCT_LOGIN;
197
198 return 0;
199}
200
201/* mutt_account_getpass: fetch password into ACCOUNT, if necessary */
202int mutt_account_getpass (ACCOUNT* account)
203{
204 char prompt[SHORT_STRING];
205
206 if (account->flags & MUTT_ACCT_PASS)
207 return 0;
208#ifdef USE_IMAP
209 else if ((account->type == MUTT_ACCT_TYPE_IMAP) && ImapPass)
210 strfcpy (account->pass, ImapPass, sizeof (account->pass));
211#endif
212#ifdef USE_POP
213 else if ((account->type == MUTT_ACCT_TYPE_POP) && PopPass)
214 strfcpy (account->pass, PopPass, sizeof (account->pass));
215#endif
216#ifdef USE_SMTP
217 else if ((account->type == MUTT_ACCT_TYPE_SMTP) && SmtpPass)
218 strfcpy (account->pass, SmtpPass, sizeof (account->pass));
219#endif
220 else if (option (OPTNOCURSES))
221 return -1;
222 else
223 {
224 snprintf (prompt, sizeof (prompt), _("Password for %s@%s: "),
225 account->flags & MUTT_ACCT_LOGIN ? account->login : account->user,
226 account->host);
227 account->pass[0] = '\0';
228 if (mutt_get_password (prompt, account->pass, sizeof (account->pass)))
229 return -1;
230 }
231
232 account->flags |= MUTT_ACCT_PASS;
233
234 return 0;
235}
236
237void mutt_account_unsetpass (ACCOUNT* account)
238{
239 account->flags &= ~MUTT_ACCT_PASS;
240}
241
242/* mutt_account_getoauthbearer: call external command to generate the
243 * oauth refresh token for this ACCOUNT, then create and encode the
244 * OAUTHBEARER token based on RFC 7628. Returns NULL on failure.
245 * Resulting token is dynamically allocated and should be FREE'd by the
246 * caller.
247 */
248char* mutt_account_getoauthbearer (ACCOUNT* account)
249{
250 FILE *fp;
251 char *cmd = NULL;
252 char *token = NULL;
253 size_t token_size = 0;
254 char *oauthbearer = NULL;
255 size_t oalen;
256 char *encoded_token = NULL;
257 size_t encoded_len;
258 pid_t pid;
259
260 /* The oauthbearer token includes the login */
261 if (mutt_account_getlogin (account))
262 return NULL;
263
264#ifdef USE_IMAP
265 if ((account->type == MUTT_ACCT_TYPE_IMAP) && ImapOauthRefreshCmd)
266 cmd = ImapOauthRefreshCmd;
267#endif
268#ifdef USE_POP
269 else if ((account->type == MUTT_ACCT_TYPE_POP) && PopOauthRefreshCmd)
270 cmd = PopOauthRefreshCmd;
271#endif
272#ifdef USE_SMTP
273 else if ((account->type == MUTT_ACCT_TYPE_SMTP) && SmtpOauthRefreshCmd)
274 cmd = SmtpOauthRefreshCmd;
275#endif
276
277 if (cmd == NULL)
278 {
279 /* L10N: You will see this error message if (1) you have "oauthbearer" in
280 one of your $*_authenticators and (2) you do not have the corresponding
281 $*_oauth_refresh_command defined. So the message does not mean "None of
282 your $*_oauth_refresh_command's are defined."
283 */
284 mutt_error (_("mutt_account_getoauthbearer: No OAUTH refresh command defined"));
285 return NULL;
286 }
287
288 if ((pid = mutt_create_filter (cmd, NULL, &fp, NULL)) < 0)
289 {
290 mutt_perror _("mutt_account_getoauthbearer: Unable to run refresh command");
291 return NULL;
292 }
293
294 /* read line */
295 token = mutt_read_line (NULL, &token_size, fp, NULL, 0);
296 safe_fclose (&fp);
297 mutt_wait_filter (pid);
298
299 if (token == NULL || *token == '\0')
300 {
301 mutt_error (_("mutt_account_getoauthbearer: Command returned empty string"));
302 FREE (&token);
303 return NULL;
304 }
305
306 /* Determine the length of the keyed message digest, add 50 for
307 * overhead.
308 */
309 oalen = strlen (account->login) + strlen (account->host) + strlen (token) + 50;
310 oauthbearer = safe_malloc (oalen);
311
312 snprintf (oauthbearer, oalen,
313 "n,a=%s,\001host=%s\001port=%d\001auth=Bearer %s\001\001",
314 account->login, account->host, account->port, token);
315
316 FREE (&token);
317
318 encoded_len = strlen (oauthbearer) * 4 / 3 + 10;
319 encoded_token = safe_malloc (encoded_len);
320 mutt_to_base64 ((unsigned char*) encoded_token,
321 (unsigned char*) oauthbearer, strlen (oauthbearer),
322 encoded_len);
323 FREE (&oauthbearer);
324 return encoded_token;
325}