summaryrefslogtreecommitdiff
path: root/alpine
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2020-07-09 00:16:36 -0600
committerEduardo Chappa <chappa@washington.edu>2020-07-09 00:16:36 -0600
commit0f89ad88df81df9d2ca7eafa276fecf8206fb598 (patch)
treeb8c24c61a7b9959241c5bfc0d95b7fe2f595c323 /alpine
parent560dd4993146181912c3bb98f6b26f7ed7f4de5d (diff)
downloadalpine-0f89ad88df81df9d2ca7eafa276fecf8206fb598.tar.xz
* Add choice of Authorization flow to Alpine. Alpine supports two ways to get
authorization to read email. One is called "Authorize" and the other "Device". Some servers support both, some only one. For servers that support both, Alpine will ask if it does not know which method to choose. Inspired by a conversation with Pieter Jacques.
Diffstat (limited to 'alpine')
-rw-r--r--alpine/conftype.h4
-rw-r--r--alpine/imap.c227
-rw-r--r--alpine/keymenu.c15
-rw-r--r--alpine/keymenu.h1
-rw-r--r--alpine/xoauth2.h2
-rw-r--r--alpine/xoauth2conf.c98
6 files changed, 314 insertions, 33 deletions
diff --git a/alpine/conftype.h b/alpine/conftype.h
index 9c25ad6..21c7e45 100644
--- a/alpine/conftype.h
+++ b/alpine/conftype.h
@@ -104,6 +104,10 @@ typedef struct conf_line {
XOAUTH2_INFO_S *pat;
XOAUTH2_INFO_S **selected;
} x;
+ struct xoauth2_flow {
+ OAUTH2_S *pat;
+ OAUTH2_S **selected; /* of type XOAUTH2_S */
+ } xf;
} d;
} CONF_S;
diff --git a/alpine/imap.c b/alpine/imap.c
index 0368570..fe4fdce 100644
--- a/alpine/imap.c
+++ b/alpine/imap.c
@@ -40,6 +40,8 @@ static char rcsid[] = "$Id: imap.c 1266 2009-07-14 18:39:12Z hubert@u.washington
#include "busy.h"
#include "titlebar.h"
#include "xoauth2.h"
+#include "xoauth2conf.h"
+#include "confscroll.h"
#include "init.h"
#include "../pith/state.h"
#include "../pith/conf.h"
@@ -103,6 +105,8 @@ void mm_login_alt_cue(NETMBX *);
long pine_tcptimeout_noscreen(long, long, char *);
int answer_cert_failure(int, MSGNO_S *, SCROLL_S *);
int oauth2_auth_answer(int, MSGNO_S *, SCROLL_S *);
+OAUTH2_S *oauth2_select_flow(char *);
+int xoauth2_flow_tool(struct pine *, int, CONF_S **, unsigned int);
#ifdef LOCAL_PASSWD_CACHE
int read_passfile(char *, MMLOGIN_S **);
@@ -199,9 +203,159 @@ OAUTH2_S alpine_oauth2_list[] =
0, /* first time indicator */
0 /* client secret required */
},
+ {"Outlook",
+ {"outlook.office365.com", "smtp.office365.com", NULL, NULL},
+ {{"client_id", NULL},
+ {"client_secret", NULL}, /* not used, but needed */
+ {"tenant", NULL}, /* used */
+ {"code", NULL}, /* used during authorization */
+ {"refresh_token", NULL},
+ {"scope", "offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send"},
+ {"redirect_uri", "http://localhost"},
+ {"grant_type", "authorization_code"},
+ {"grant_type", "refresh_token"},
+ {"response_type", "code"},
+ {"state", NULL}, /* not used */
+ {"device_code", NULL} /* not used */
+ },
+ {{"GET", "https://login.microsoftonline.com/\001/oauth2/v2.0/authorize", /* Get Access Code */
+ {OA2_Id, OA2_Scope, OA2_Redirect, OA2_Response, OA2_End, OA2_End, OA2_End}},
+ {NULL, NULL, {OA2_End, OA2_End, OA2_End, OA2_End, OA2_End, OA2_End, OA2_End}}, /* device code, not used */
+ {"POST", "https://login.microsoftonline.com/\001/oauth2/v2.0/token", /* Get first Refresh Token and Access token */
+ {OA2_Id, OA2_Redirect, OA2_Scope, OA2_GrantTypeforAccessToken, OA2_Secret, OA2_Code, OA2_End}},
+ {"POST", "https://login.microsoftonline.com/\001/oauth2/v2.0/token", /* Get access token from refresh token */
+ {OA2_Id, OA2_RefreshToken, OA2_Scope, OA2_GrantTypefromRefreshToken, OA2_Secret, OA2_End, OA2_End}}
+ },
+ {NULL, NULL, NULL, 0, 0, NULL}, /* device_code information, not used */
+ NULL, /* access token */
+ 0, /* expiration time */
+ 0, /* first time indicator */
+ 1 /* client secret required */
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0},
};
+int
+xoauth2_flow_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
+{
+ int rv = 0;
+
+ switch(cmd){
+ case MC_CHOICE:
+ *((*cl)->d.xf.selected) = (*cl)->d.xf.pat;
+ rv = simple_exit_cmd(flags);
+
+ case MC_EXIT:
+ rv = simple_exit_cmd(flags);
+ break;
+
+ default:
+ rv = -1;
+ }
+
+ if(rv > 0)
+ ps->mangled_body = 1;
+
+ return rv;
+}
+
+OAUTH2_S *
+oauth2_select_flow(char *host)
+{
+ OAUTH2_S *oa2list, *oa2;
+ int i, n, rv;
+ char *method;
+
+ if(ps_global->ttyo){
+ CONF_S *ctmp = NULL, *first_line = NULL;
+ OAUTH2_S *x_sel = NULL;
+ OPT_SCREEN_S screen;
+ char tmp[1024];
+
+ dprint((9, "xoauth2 select flow"));
+ ps_global->next_screen = SCREEN_FUN_NULL;
+
+ memset(&screen, 0, sizeof(screen));
+
+ for(i = 0; i < sizeof(tmp) && i < ps_global->ttyo->screen_cols; i++)
+ tmp[i] = '-';
+ tmp[i] = '\0';
+
+ new_confline(&ctmp);
+ ctmp->flags |= CF_NOSELECT;
+ ctmp->value = cpystr(tmp);
+
+ new_confline(&ctmp);
+ ctmp->flags |= CF_NOSELECT;
+ ctmp->value = cpystr(_("Please select below the authorization flow you would like to follow:"));
+
+ new_confline(&ctmp);
+ ctmp->flags |= CF_NOSELECT;
+ ctmp->value = cpystr(tmp);
+
+ for(oa2list = alpine_oauth2_list; oa2list && oa2list->name ;oa2list++){
+ for(i = 0; oa2list && oa2list->host && oa2list->host[i] && strucmp(oa2list->host[i], host); i++);
+ if(oa2list && oa2list->host && i < OAUTH2_TOT_EQUIV && oa2list->host[i]){
+ new_confline(&ctmp);
+ if(!first_line)
+ first_line = ctmp;
+ method = oa2list->server_mthd[0].name ? "Authorize"
+ : (oa2list->server_mthd[1].name ? "Device" : "Unknown");
+ sprintf(tmp, "%s (%s)", oa2list->name, method);
+ ctmp->value = cpystr(tmp);
+ ctmp->d.xf.selected = &x_sel;
+ ctmp->d.xf.pat = oa2list;
+ ctmp->keymenu = &xoauth2_id_select_km;
+ ctmp->help = NO_HELP;
+ ctmp->help_title = NULL;
+ ctmp->tool = xoauth2_flow_tool;
+ ctmp->flags = CF_STARTITEM;
+ ctmp->valoffset = 4;
+ }
+ }
+ (void)conf_scroll_screen(ps_global, &screen, first_line, _("SELECT AUTHORIZATION FLOW"),
+ _("xoauth2"), 0, NULL);
+ oa2 = x_sel;
+ }
+ else{
+ char *s;
+ char prompt[1024];
+ char reply[1024];
+ int sel, j;
+
+ for(oa2list = alpine_oauth2_list; oa2list && oa2list->name ;oa2list++)
+ n += strlen(oa2list->name); + 5; /* number, parenthesis, space */
+ n += 1024; /* large enough to display to lines of 80 characters in UTF-8 */
+ s = fs_get(n*sizeof(char));
+ strcpy(s, _("Please select below the authorization flow you would like to follow:"));
+ sprintf(s + strlen(s), _("Please select the client-id to use from the following list.\n\n"));
+ for(j = 1, oa2list = alpine_oauth2_list; oa2list && oa2list->name ;oa2list++){
+ for(i = 0; oa2list && oa2list->host && oa2list->host[i] && strucmp(oa2list->host[i], host); i++);
+ if(oa2list && oa2list->host && i < OAUTH2_TOT_EQUIV && oa2list->host[i])
+ sprintf(s + strlen(s), " %d) %.70s\n", j++, oa2list->name);
+ }
+ display_init_err(s, 0);
+
+ strncpy(prompt, _("Enter your selection number: "), sizeof(prompt));
+ prompt[sizeof(prompt)-1] = '\0';
+ do{
+ rv = optionally_enter(reply, 0, 0, sizeof(reply), prompt, NULL, NO_HELP, 0);
+ sel = atoi(reply);
+ rv = (sel >= 0 && sel < i) ? 0 : -1;
+ } while (rv != 0);
+
+ for(j = 1, oa2list = alpine_oauth2_list; oa2list && oa2list->name ;oa2list++){
+ for(i = 0; oa2list && oa2list->host && oa2list->host[i] && strucmp(oa2list->host[i], host); i++);
+ if(oa2list && oa2list->host && i < OAUTH2_TOT_EQUIV && oa2list->host[i]){
+ if(j == sel) break;
+ else j++;
+ }
+ }
+ oa2 = oa2list;
+ }
+ return oa2;
+}
+
typedef struct auth_code_s {
char *code;
int answer;
@@ -512,7 +666,8 @@ oauth2_get_access_code(unsigned char *url, char *method, OAUTH2_S *oauth2, int *
ps_global->painted_footer_on_startup = 0;
} while (user_input.answer != 'e');
- if(!struncmp(user_input.code, "https://", 8)){
+ if(!struncmp(user_input.code, "http://", 7)
+ || !struncmp(user_input.code, "https://", 8)){
char *s, *t;
s = strstr(user_input.code, "code=");
if(s != NULL){
@@ -594,7 +749,8 @@ try_wantto:
rc = optionally_enter(token, q_line, 0, MAILTMPLEN,
prompt, NULL, NO_HELP, &flags);
} while (rc != 0 && rc != 1);
- if(!struncmp(token, "https://", 8)){
+ if(!struncmp(token, "http://", 7)
+ || !struncmp(token, "https://", 8)){
char *s, *t;
s = strstr(token, "code=");
if(s != NULL){
@@ -680,7 +836,9 @@ mm_login_oauth2(NETMBX *mb, char *user, char *method,
int save_in_init;
int registered;
int ChangeAccessToken, ChangeRefreshToken, ChangeExpirationTime;
- OAUTH2_S *oa2list;
+ OAUTH2_S *oa2list, *oa2;
+ XOAUTH2_INFO_S *x;
+
unsigned long OldExpirationTime, NewExpirationTime, SaveExpirationTime;
#if defined(_WINDOWS) || defined(LOCAL_PASSWD_CACHE)
int preserve_password = -1;
@@ -723,13 +881,25 @@ mm_login_oauth2(NETMBX *mb, char *user, char *method,
}
}
+ if(trial == 0L && !altuserforcache){
+ if(*mb->user != '\0')
+ strncpy(user, mb->user, NETMAXUSER);
+ else{
+ flags = OE_APPEND_CURRENT;
+ sprintf(prompt, "%s: %s - %s: ", hostlabel, mb->orighost, userlabel);
+ rc = optionally_enter(user, q_line, 0, NETMAXUSER,
+ prompt, NULL, NO_HELP, &flags);
+ }
+ user[NETMAXUSER-1] = '\0';
+ }
+
/*
* We check to see if the server we are going to log in to is already
* registered. This gives us a list of servers with the same
* credentials, so we use the same credentials for all of them.
*/
- for(registered = 0, oa2list = alpine_oauth2_list;
+ for(registered = 0, oa2list = alpine_oauth2_list;
oa2list && oa2list->host != NULL && oa2list->host[0] != NULL;
oa2list++){
for(i = 0; i < OAUTH2_TOT_EQUIV
@@ -742,6 +912,25 @@ mm_login_oauth2(NETMBX *mb, char *user, char *method,
}
if(registered){
+ x = oauth2_get_client_info(oa2list->name, user);
+ if(x && x->flow){
+ for(oa2list = alpine_oauth2_list;
+ oa2list && oa2list->host != NULL && oa2list->host[0] != NULL;
+ oa2list++){
+ for(i = 0; i < OAUTH2_TOT_EQUIV
+ && oa2list->host[i] != NULL
+ && strucmp(oa2list->host[i], mb->orighost) != 0; i++);
+ if(i < OAUTH2_TOT_EQUIV && oa2list->host[i] != NULL){
+ char *flow = oa2list->server_mthd[0].name ? "Authorize"
+ : (oa2list->server_mthd[1].name ? "Device" : "Unknown");
+ if(!strucmp(x->flow, flow)) break; /* found it */
+ }
+ }
+ }
+ /* else use the one we found earlier, the user has to configure this better */
+ }
+
+ if(registered){
hostlist2[i = 0].name = mb->host;
if(mb->orighost && mb->orighost[0] && strucmp(mb->host, mb->orighost))
hostlist2[++i].name = mb->orighost;
@@ -766,18 +955,6 @@ mm_login_oauth2(NETMBX *mb, char *user, char *method,
* and use the access token.
*/
if(trial == 0L && !altuserforcache){
- int code;
-
- if(*mb->user != '\0')
- strncpy(user, mb->user, NETMAXUSER);
- else{
- flags = OE_APPEND_CURRENT;
- sprintf(prompt, "%s: %s - %s: ", hostlabel, mb->orighost, userlabel);
- rc = optionally_enter(user, q_line, 0, NETMAXUSER,
- prompt, NULL, NO_HELP, &flags);
- }
- user[NETMAXUSER-1] = '\0';
-
/* Search for a refresh token that is already loaded ... */
if(imap_get_passwd_auth(mm_login_list, &token, user,
registered ? hostlist2 : hostlist,
@@ -845,6 +1022,24 @@ mm_login_oauth2(NETMBX *mb, char *user, char *method,
}
else login->first_time++;
+ if(login->first_time){ /* count how many authorization methods we support */
+ int nmethods, i, j;
+
+ for(nmethods = 0, oa2 = alpine_oauth2_list; oa2 && oa2->name ; oa2++){
+ for(j = 0; j < OAUTH2_TOT_EQUIV
+ && oa2
+ && oa2->host[j] != NULL
+ && strucmp(oa2->host[j], mb->orighost) != 0; j++);
+ if(oa2 && oa2->host && j < OAUTH2_TOT_EQUIV && oa2->host[j])
+ nmethods++;
+ }
+
+ if(nmethods > 1)
+ oa2list = oauth2_select_flow(mb->orighost);
+
+ if(!oa2list) registered = 0;
+ }
+
/* Default to saving what we already had saved */
SaveRefreshToken = NewRefreshToken;
diff --git a/alpine/keymenu.c b/alpine/keymenu.c
index 8d94e87..47350d6 100644
--- a/alpine/keymenu.c
+++ b/alpine/keymenu.c
@@ -1797,6 +1797,21 @@ struct key role_select_keys[] =
WHEREIS_MENU};
INST_KEY_MENU(role_select_km, role_select_keys);
+struct key xoauth2_flow_select_keys[] =
+ {HELP_MENU,
+ NULL_MENU,
+ {"E", N_("Exit"), {MC_EXIT,1,{'e'}}, KS_EXITMODE},
+ {"S", "[" N_("Select") "]", {MC_CHOICE,3,{'s',ctrl('M'),ctrl('J')}}, KS_NONE},
+ {"P", N_("PrevFlow"), {MC_PREVITEM, 1, {'p'}}, KS_NONE},
+ {"N", N_("NextFlow"), {MC_NEXTITEM, 2, {'n', TAB}}, KS_NONE},
+ PREVPAGE_MENU,
+ NEXTPAGE_MENU,
+ HOMEKEY_MENU,
+ ENDKEY_MENU,
+ NULL_MENU,
+ WHEREIS_MENU};
+INST_KEY_MENU(xoauth2_flow_select_km, xoauth2_flow_select_keys);
+
struct key xoauth2_id_select_keys[] =
{HELP_MENU,
NULL_MENU,
diff --git a/alpine/keymenu.h b/alpine/keymenu.h
index 3cf4e2c..4664ed9 100644
--- a/alpine/keymenu.h
+++ b/alpine/keymenu.h
@@ -651,6 +651,7 @@ extern struct key_menu cancel_keymenu,
config_checkbox_keymenu,
config_text_keymenu,
xoauth2_id_select_km,
+ xoauth2_flow_select_km,
config_xoauth2_text_keymenu,
config_text_to_charsets_keymenu,
config_radiobutton_keymenu,
diff --git a/alpine/xoauth2.h b/alpine/xoauth2.h
index a50a1e8..739a3b7 100644
--- a/alpine/xoauth2.h
+++ b/alpine/xoauth2.h
@@ -22,7 +22,7 @@
#define OUTLOOK_NAME "Outlook"
#define OUTLOOK_ID "f21dcaf2-8020-469b-8135-343bfc35d046"
-#define OUTLOOK_SECRET NULL
+#define OUTLOOK_SECRET "Tk-DAcEi13-FeSsY_Ja4Y.-MyL66I.wIPt"
#define OUTLOOK_TENANT "common"
#endif /* ALPINE_XOAUTH2_INCLUDED */
diff --git a/alpine/xoauth2conf.c b/alpine/xoauth2conf.c
index 7af3679..f930be6 100644
--- a/alpine/xoauth2conf.c
+++ b/alpine/xoauth2conf.c
@@ -26,12 +26,12 @@
extern OAUTH2_S alpine_oauth2_list[];
XOAUTH2_INFO_S xoauth_default[] = {
- { GMAIL_NAME, GMAIL_ID, GMAIL_SECRET, GMAIL_TENANT, NULL},
- { OUTLOOK_NAME, OUTLOOK_ID, OUTLOOK_SECRET, OUTLOOK_TENANT, NULL},
- { NULL, NULL, NULL, NULL, NULL}
+ { GMAIL_NAME, GMAIL_ID, GMAIL_SECRET, GMAIL_TENANT, NULL, NULL},
+ { OUTLOOK_NAME, OUTLOOK_ID, OUTLOOK_SECRET, OUTLOOK_TENANT, NULL, NULL},
+ { NULL, NULL, NULL, NULL, NULL, NULL}
};
-typedef enum {Xname = 0, Xid, Xsecret, Xtenant, Xuser, Xend} XTYPES;
+typedef enum {Xname = 0, Xid, Xsecret, Xtenant, Xuser, XFlow, Xend} XTYPES;
typedef struct xoauh2_info_val_s {
char *screen_name;
@@ -45,6 +45,7 @@ XOAUTH2_INFO_VAL_S x_default[] = {
{"Client-Secret", "/SECRET="},
{"Tenant", "/TENANT="},
{"Username", "/USER="},
+ {"Auth Flow", "/Flow="},
{NULL, NULL}
};
@@ -53,11 +54,13 @@ XOAUTH2_INFO_VAL_S x_default[] = {
#define XSECRET x_default[Xsecret].pinerc_name
#define XTENANT x_default[Xtenant].pinerc_name
#define XUSER x_default[Xuser].pinerc_name
+#define XFLOW x_default[XFlow].pinerc_name
#define XOAUTH2_CLIENT_ID x_default[Xid].screen_name
#define XOAUTH2_CLIENT_SECRET x_default[Xsecret].screen_name
#define XOAUTH2_TENANT x_default[Xtenant].screen_name
#define XOAUTH2_USERS x_default[Xuser].screen_name
+#define XOAUTH2_FLOW x_default[XFlow].screen_name
char *list_to_array(char **);
char **array_to_list(char *);
@@ -128,7 +131,9 @@ xoauth_config_line(XOAUTH2_INFO_S *x)
+ strlen(x->client_secret ? XSECRET : "") + strlen(x->client_secret ? x->client_secret : "")
+ strlen(x->tenant ? XTENANT : "") + strlen(x->tenant ? x->tenant : "")
+ strlen(XUSER) + strlen(x->users ? x->users : "")
- + 2 + 3 + (x->client_secret ? 3 : 0) + (x->tenant ? 3 : 0) + 3 + 1;
+ + strlen(XFLOW) + strlen(x->flow ? x->flow : "")
+ + 2 + 3 + (x->client_secret ? 3 : 0) + (x->tenant ? 3 : 0)
+ + 3 + (x->flow ? 3 : 0) + 1;
rv = fs_get(n*sizeof(char));
sprintf(rv, "%s\"%s\" %s\"%s\"", XNAME, x->name, XID, x->client_id);
if(x->client_secret)
@@ -136,6 +141,8 @@ xoauth_config_line(XOAUTH2_INFO_S *x)
if(x->tenant)
sprintf(rv + strlen(rv), " %s\"%s\"", XTENANT, x->tenant);
sprintf(rv + strlen(rv), " %s\"%s\"", XUSER, x->users ? x->users : "");
+ if(x->flow)
+ sprintf(rv + strlen(rv), " %s\"%s\"", XFLOW, x->flow ? x->flow : "");
return rv;
}
@@ -419,6 +426,13 @@ write_xoauth_configuration(struct variable *v, struct variable **vlist, EditWhi
x->tenant = cpystr(p);
continue;
}
+ if (x->flow == NULL && !strcmp(vlist[i]->name, XOAUTH2_FLOW)){
+ p = PVAL(vlist[i], ew);
+ if (p == NULL) p = vlist[i]->current_val.p;
+ if(p != NULL)
+ x->flow = cpystr(p);
+ continue;
+ }
if (x->users == NULL && !strcmp(vlist[i]->name, XOAUTH2_USERS)){
l = LVAL(vlist[i], ew);
x->users = list_to_array(l);
@@ -492,6 +506,16 @@ xoauth_parse_client_info(char *lvalp)
*t = c;
} else x->client_secret = NULL;
+ if((s = strstr(lvalp, XFLOW)) != NULL){
+ s += strlen(XFLOW);
+ if(*s == '"') s++;
+ for(t = s; *t && *t != '"' && *t != ' '; t++);
+ c = *t;
+ *t = '\0';
+ if(*s) x->flow = cpystr(s);
+ *t = c;
+ } else x->flow = NULL;
+
if((s = strstr(lvalp, XUSER)) != NULL){
s += strlen(XUSER);
if(*s == '"') s++;
@@ -674,6 +698,33 @@ write_xoauth_conf_entry(XOAUTH2_INFO_S *x, XOAUTH2_INFO_S *y, CONF_S **cl, CONF_
(*cl)->varnamep = ctmpb;
}
+ /* Set up flow variable */
+ if(x->flow){
+ varlist[p] = fs_get(sizeof(struct variable));
+ memset((void *) varlist[p], 0, sizeof(struct variable));
+ varlist[p]->name = cpystr(XOAUTH2_FLOW);
+ varlist[p]->is_used = 1;
+ varlist[p]->is_user = 1;
+ varlist[p]->main_user_val.p = cpystr(x->flow);
+ varlist[p]->global_val.p = cpystr(x->flow);
+ varlist[p]->dname = cpystr(tmp2); /* hack, but makes life easier! */
+ varlist[p]->descrip = cpystr(x->name); /* hack, but makes life easier! */
+ set_current_val(varlist[p], FALSE, FALSE);
+
+ /* Write client-secret variable */
+ new_confline(cl)->var = varlist[p];
+ utf8_snprintf(tmp, sizeof(tmp), " %-*.100w =", ln, XOAUTH2_FLOW);
+ tmp[sizeof(tmp)-1] = '\0';
+ (*cl)->varname = cpystr(tmp);
+ (*cl)->varmem = p++;
+ (*cl)->valoffset = ln + 3 + 3;
+ (*cl)->value = pretty_value(ps_global, *cl);
+ (*cl)->keymenu = &config_xoauth2_text_keymenu;
+ (*cl)->help = h_config_xoauth2_flow;
+ (*cl)->tool = text_tool;
+ (*cl)->varnamep = ctmpb;
+ }
+
/* Setup users variable */
varlist[p] = fs_get(sizeof(struct variable));
memset((void *) varlist[p], 0, sizeof(struct variable));
@@ -738,6 +789,7 @@ alpine_xoauth2_configuration(struct pine *ps, int edit_exceptions)
char *name_lval, *id_lval, *tenant_lval, *secret_lval, *user_lval,
*id_def, *tenant_def, *secret_def;
int i, j, k, l, p, q, ln = 0, readonly_warning = 0, pos, count_vars;
+ XTYPES m;
CONF_S *ctmpa = NULL, *ctmpb, *first_line;
FEATURE_S *feature;
PINERC_S *prc = NULL;
@@ -773,13 +825,10 @@ alpine_xoauth2_configuration(struct pine *ps, int edit_exceptions)
mailcap_free(); /* free resources we won't be using for a while */
pos = -1;
- ln = strlen(XOAUTH2_CLIENT_ID);
- i = strlen(XOAUTH2_CLIENT_SECRET);
- if(ln < i) ln = i;
- i = strlen(XOAUTH2_TENANT);
- if(ln < i) ln = i;
- i = strlen(XOAUTH2_USERS);
- if(ln < i) ln = i;
+ for(ln = 0, m = Xid; m < Xend; m++){
+ i = strlen(x_default[m].screen_name);
+ if(ln < i) ln = i;
+ }
alval = ALVAL(&ps->vars[V_XOAUTH2_INFO], ew);
lval = *alval = xoauth2_conf_dedup_and_merge(alval);
@@ -798,7 +847,7 @@ alpine_xoauth2_configuration(struct pine *ps, int edit_exceptions)
free_xoauth2_info(&y);
}
if(lval == NULL || lval[k] == NULL){
- count_vars += 2;
+ count_vars += 3;
if(xoauth_default[i].client_secret) count_vars++;
if(xoauth_default[i].tenant) count_vars++;
}
@@ -808,7 +857,7 @@ alpine_xoauth2_configuration(struct pine *ps, int edit_exceptions)
free_xoauth2_info(&y);
continue;
}
- count_vars += 2;
+ count_vars += 3;
if(xoauth_default[i].client_secret != NULL) count_vars++;
if(xoauth_default[i].tenant != NULL) count_vars++;
free_xoauth2_info(&y);
@@ -834,10 +883,22 @@ alpine_xoauth2_configuration(struct pine *ps, int edit_exceptions)
break;
free_xoauth2_info(&y);
}
- if(lval == NULL || lval[k] == NULL)
- write_xoauth_conf_entry(&xoauth_default[i], &xoauth_default[i], &ctmpa, &ctmpb,
+ if(lval == NULL || lval[k] == NULL){
+ OAUTH2_S *oa2list;
+ for(oa2list = alpine_oauth2_list; oa2list; oa2list++){
+ if(!strcmp(oa2list->name,xoauth_default[i].name)){
+ xoauth_default[i].flow = cpystr(oa2list->server_mthd[0].name ? "Authorize"
+ : (oa2list->server_mthd[1].name ? "Device" : "Unknown"));
+ write_xoauth_conf_entry(&xoauth_default[i], &xoauth_default[i], &ctmpa, &ctmpb,
&first_line, &varlist, &p, ln, -i-1);
+ fs_give((void **) &xoauth_default[i].flow);
+ break; /* just one entry, set the default to the first entry */
+ }
+ }
+ }
for(k = 0, q = 0; lval && lval[k]; k++){
+ OAUTH2_S *oa2list, *oa2;
+
y = xoauth_parse_client_info(lval[k]);
if(y && (!y->name || strcmp(y->name, xoauth_default[i].name))){
free_xoauth2_info(&y);
@@ -849,6 +910,11 @@ alpine_xoauth2_configuration(struct pine *ps, int edit_exceptions)
y->client_secret = cpystr(xoauth_default[i].client_secret);
if(y->tenant == NULL && xoauth_default[i].tenant != NULL)
y->tenant = cpystr(xoauth_default[i].tenant);
+ for(oa2 = NULL, oa2list = alpine_oauth2_list; oa2 == NULL && oa2list; oa2list++)
+ if(!strcmp(oa2list->name, y->name)) oa2 = oa2list;
+ if(y->flow == NULL)
+ y->flow = cpystr(oa2->server_mthd[0].name ? "Authorize"
+ : (oa2->server_mthd[1].name ? "Device" : "Unknown"));
write_xoauth_conf_entry(y, &xoauth_default[i], &ctmpa, &ctmpb, &first_line, &varlist, &p, ln, k);
free_xoauth2_info(&y);
}