account.c 8.58 KB
Newer Older
1
/*
2
 * Copyright (C) 2000-2007 Brendan Cully <brendan@kublai.com>
3
 *
4 5 6 7
 *     This program is free software; you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation; either version 2 of the License, or
 *     (at your option) any later version.
8
 *
9 10 11 12
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
13
 *
14 15
 *     You should have received a copy of the GNU General Public License
 *     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 20

/* remote host account manipulation (POP/IMAP) */

21 22 23 24
#if HAVE_CONFIG_H
# include "config.h"
#endif

25
#include "mutt.h"
26 27
#include "account.h"
#include "url.h"
28

29
/* mutt_account_match: compare account info (host/port/user) */
30 31 32 33 34 35
int mutt_account_match (const ACCOUNT* a1, const ACCOUNT* a2)
{
  const char* user = NONULL (Username);

  if (a1->type != a2->type)
    return 0;
36
  if (ascii_strcasecmp (a1->host, a2->host))
37 38 39 40 41
    return 0;
  if (a1->port != a2->port)
    return 0;

#ifdef USE_IMAP
42
  if (a1->type == MUTT_ACCT_TYPE_IMAP)
43 44 45 46
  {
    if (ImapUser)
      user = ImapUser;
  }
47 48 49
#endif

#ifdef USE_POP
50
  if (a1->type == MUTT_ACCT_TYPE_POP && PopUser)
51 52
    user = PopUser;
#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 60 61 62
    return (!strcmp (a2->user, user));

  return 1;
}
63

64 65 66 67 68 69 70 71 72 73 74 75
/* mutt_account_fromurl: fill account with information from url. */
int mutt_account_fromurl (ACCOUNT* account, ciss_url_t* url)
{
  /* must be present */
  if (url->host)
    strfcpy (account->host, url->host, sizeof (account->host));
  else
    return -1;

  if (url->user)
  {
    strfcpy (account->user, url->user, sizeof (account->user));
76
    account->flags |= MUTT_ACCT_USER;
77 78 79 80
  }
  if (url->pass)
  {
    strfcpy (account->pass, url->pass, sizeof (account->pass));
81
    account->flags |= MUTT_ACCT_PASS;
82 83 84 85
  }
  if (url->port)
  {
    account->port = url->port;
86
    account->flags |= MUTT_ACCT_PORT;
87 88 89 90 91
  }

  return 0;
}

Thomas Roessler's avatar
Thomas Roessler committed
92 93 94 95 96 97 98 99 100 101 102 103
/* mutt_account_tourl: fill URL with info from account. The URL information
 *   is a set of pointers into account - don't free or edit account until
 *   you've finished with url (make a copy of account if you need it for
 *   a while). */
void mutt_account_tourl (ACCOUNT* account, ciss_url_t* url)
{
  url->scheme = U_UNKNOWN;
  url->user = NULL;
  url->pass = NULL;
  url->port = 0;

#ifdef USE_IMAP
104
  if (account->type == MUTT_ACCT_TYPE_IMAP)
Thomas Roessler's avatar
Thomas Roessler committed
105
  {
106
    if (account->flags & MUTT_ACCT_SSL)
Thomas Roessler's avatar
Thomas Roessler committed
107 108 109 110 111 112 113
      url->scheme = U_IMAPS;
    else
      url->scheme = U_IMAP;
  }
#endif

#ifdef USE_POP
114
  if (account->type == MUTT_ACCT_TYPE_POP)
Thomas Roessler's avatar
Thomas Roessler committed
115
  {
116
    if (account->flags & MUTT_ACCT_SSL)
Thomas Roessler's avatar
Thomas Roessler committed
117 118 119 120 121 122
      url->scheme = U_POPS;
    else
      url->scheme = U_POP;
  }
#endif

123
#ifdef USE_SMTP
124
  if (account->type == MUTT_ACCT_TYPE_SMTP)
125
  {
126
    if (account->flags & MUTT_ACCT_SSL)
127 128 129 130 131 132
      url->scheme = U_SMTPS;
    else
      url->scheme = U_SMTP;
  }
#endif

Thomas Roessler's avatar
Thomas Roessler committed
133
  url->host = account->host;
134
  if (account->flags & MUTT_ACCT_PORT)
Thomas Roessler's avatar
Thomas Roessler committed
135
    url->port = account->port;
136
  if (account->flags & MUTT_ACCT_USER)
Thomas Roessler's avatar
Thomas Roessler committed
137
    url->user = account->user;
138
  if (account->flags & MUTT_ACCT_PASS)
Thomas Roessler's avatar
Thomas Roessler committed
139 140 141
    url->pass = account->pass;
}

142
/* mutt_account_getuser: retrieve username into ACCOUNT, if necessary */
143 144
int mutt_account_getuser (ACCOUNT* account)
{
145 146
  char prompt[SHORT_STRING];

147
  /* already set */
148
  if (account->flags & MUTT_ACCT_USER)
149 150
    return 0;
#ifdef USE_IMAP
151
  else if ((account->type == MUTT_ACCT_TYPE_IMAP) && ImapUser)
152 153 154
    strfcpy (account->user, ImapUser, sizeof (account->user));
#endif
#ifdef USE_POP
155
  else if ((account->type == MUTT_ACCT_TYPE_POP) && PopUser)
156 157
    strfcpy (account->user, PopUser, sizeof (account->user));
#endif
158 159
  else if (option (OPTNOCURSES))
    return -1;
160 161 162
  /* prompt (defaults to unix username), copy into account->user */
  else
  {
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 167 168
      return -1;
  }

169
  account->flags |= MUTT_ACCT_USER;
170 171 172 173

  return 0;
}

174 175 176
int mutt_account_getlogin (ACCOUNT* account)
{
  /* already set */
177
  if (account->flags & MUTT_ACCT_LOGIN)
178 179
    return 0;
#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 189
  }
#endif

190
  if (!(account->flags & MUTT_ACCT_LOGIN))
191 192 193 194 195
  {
    mutt_account_getuser (account);
    strfcpy (account->login, account->user, sizeof (account->login));
  }

196
  account->flags |= MUTT_ACCT_LOGIN;
197 198 199 200 201

  return 0;
}

/* mutt_account_getpass: fetch password into ACCOUNT, if necessary */
202 203
int mutt_account_getpass (ACCOUNT* account)
{
204 205
  char prompt[SHORT_STRING];

206
  if (account->flags & MUTT_ACCT_PASS)
207 208
    return 0;
#ifdef USE_IMAP
209
  else if ((account->type == MUTT_ACCT_TYPE_IMAP) && ImapPass)
210 211 212
    strfcpy (account->pass, ImapPass, sizeof (account->pass));
#endif
#ifdef USE_POP
213
  else if ((account->type == MUTT_ACCT_TYPE_POP) && PopPass)
214
    strfcpy (account->pass, PopPass, sizeof (account->pass));
215 216
#endif
#ifdef USE_SMTP
217
  else if ((account->type == MUTT_ACCT_TYPE_SMTP) && SmtpPass)
218
    strfcpy (account->pass, SmtpPass, sizeof (account->pass));
219
#endif
220 221
  else if (option (OPTNOCURSES))
    return -1;
222 223
  else
  {
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 230 231
      return -1;
  }

232
  account->flags |= MUTT_ACCT_PASS;
233 234 235

  return 0;
}
236 237 238

void mutt_account_unsetpass (ACCOUNT* account)
{
239
  account->flags &= ~MUTT_ACCT_PASS;
240
}
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278

/* mutt_account_getoauthbearer: call external command to generate the
 * oauth refresh token for this ACCOUNT, then create and encode the
 * OAUTHBEARER token based on RFC 7628.  Returns NULL on failure.
 * Resulting token is dynamically allocated and should be FREE'd by the
 * caller.
 */
char* mutt_account_getoauthbearer (ACCOUNT* account)
{
  FILE	*fp;
  char *cmd = NULL;
  char *token = NULL;
  size_t token_size = 0;
  char *oauthbearer = NULL;
  size_t oalen;
  char *encoded_token = NULL;
  size_t encoded_len;
  pid_t	pid;

  /* The oauthbearer token includes the login */
  if (mutt_account_getlogin (account))
    return NULL;

#ifdef USE_IMAP
  if ((account->type == MUTT_ACCT_TYPE_IMAP) && ImapOauthRefreshCmd)
    cmd = ImapOauthRefreshCmd;
#endif
#ifdef USE_POP
  else if ((account->type == MUTT_ACCT_TYPE_POP) && PopOauthRefreshCmd)
    cmd = PopOauthRefreshCmd;
#endif
#ifdef USE_SMTP
  else if ((account->type == MUTT_ACCT_TYPE_SMTP) && SmtpOauthRefreshCmd)
    cmd = SmtpOauthRefreshCmd;
#endif

  if (cmd == NULL)
  {
279 280 281 282
    /* L10N: You will see this error message if (1) you have "oauthbearer" in
       one of your $*_authenticators and (2) you do not have the corresponding
       $*_oauth_refresh_command defined. So the message does not mean "None of
       your $*_oauth_refresh_command's are defined."
283
    */
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
    mutt_error (_("mutt_account_getoauthbearer: No OAUTH refresh command defined"));
    return NULL;
  }

  if ((pid = mutt_create_filter (cmd, NULL, &fp, NULL)) < 0)
  {
    mutt_perror _("mutt_account_getoauthbearer: Unable to run refresh command");
    return NULL;
  }

  /* read line */
  token = mutt_read_line (NULL, &token_size, fp, NULL, 0);
  safe_fclose (&fp);
  mutt_wait_filter (pid);

  if (token == NULL || *token == '\0')
  {
    mutt_error (_("mutt_account_getoauthbearer: Command returned empty string"));
    FREE (&token);
    return NULL;
  }

  /* Determine the length of the keyed message digest, add 50 for
   * overhead.
   */
309
  oalen = strlen (account->login) + strlen (account->host) + strlen (token) + 50;
310 311 312
  oauthbearer = safe_malloc (oalen);

  snprintf (oauthbearer, oalen,
313 314
            "n,a=%s,\001host=%s\001port=%d\001auth=Bearer %s\001\001",
            account->login, account->host, account->port, token);
315 316 317 318 319 320 321 322 323 324 325

  FREE (&token);

  encoded_len = strlen (oauthbearer) * 4 / 3 + 10;
  encoded_token = safe_malloc (encoded_len);
  mutt_to_base64 ((unsigned char*) encoded_token,
                  (unsigned char*) oauthbearer, strlen (oauthbearer),
		  encoded_len);
  FREE (&oauthbearer);
  return encoded_token;
}