summaryrefslogtreecommitdiff
path: root/alpine
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2020-06-26 12:19:56 -0600
committerEduardo Chappa <chappa@washington.edu>2020-06-26 12:19:56 -0600
commit354674406ed866dffbcab71455f796275a63df36 (patch)
tree6cb79243d5c72f569a9a7c944558251ea4af6464 /alpine
parent9a21decd8d4528c36870a86f631c754b0b63411f (diff)
downloadalpine-354674406ed866dffbcab71455f796275a63df36.tar.xz
* Expansion of the configuration screen for XOAUTH2 to include
username, and tenant. * If a user has more than one client-id for a service, Alpine tries to asks the user which client-id to use and associates that client-id to the credentials in the XOAUTH2 configuration screen.
Diffstat (limited to 'alpine')
-rw-r--r--alpine/arg.c65
-rw-r--r--alpine/confscroll.c23
-rw-r--r--alpine/conftype.h4
-rw-r--r--alpine/imap.c12
-rw-r--r--alpine/keymenu.c70
-rw-r--r--alpine/keymenu.h7
-rw-r--r--alpine/xoauth2.h8
-rw-r--r--alpine/xoauth2conf.c976
-rw-r--r--alpine/xoauth2conf.h8
9 files changed, 928 insertions, 245 deletions
diff --git a/alpine/arg.c b/alpine/arg.c
index 1971e80..25419b3 100644
--- a/alpine/arg.c
+++ b/alpine/arg.c
@@ -83,7 +83,9 @@ static char args_err_missing_copyabook[] = N_("missing argument for option \"-co
static char args_err_missing_server_name[] = N_("missing server name. Example: -xoauth2-server Gmail");
static char args_err_missing_client_id[] = N_("missing client-id name. Example: -xoauth2-client-id 760.someserver.com");
static char args_err_missing_client_secret[] = N_("missing client-secret name. Example: -xoauth2-client-secret V56i0fa_");
-static char args_err_missing_xoauth_option[] = N_("at least one of the arguments -xoauth2-server, or -xoauth2-client-id, or -xoauth2-client-secret is missing.");
+static char args_err_missing_tenant[] = N_("missing tenant value. Example: -xoauth2-tenant common");
+static char args_err_missing_user[] = N_("missing username value. Example: -xoauth2-user user@example.com");
+static char args_err_missing_xoauth_option[] = N_("at least one of the arguments -xoauth2-server, or -xoauth2-client-id, xoauth2-tenant, or -xoauth2-client-secret is missing.");
static char *args_pine_args[] = {
N_("Possible Starting Arguments for Alpine program:"),
@@ -217,9 +219,7 @@ pine_args(struct pine *pine_state, int argc, char **argv, ARGDATA_S *args)
char *sort = NULL;
char *pinerc_file = NULL;
char *lc = NULL;
- char *xoauth2_server = NULL;
- char *xoauth2_client_id = NULL;
- char *xoauth2_client_secret = NULL;
+ XOAUTH2_INFO_S x;
int do_help = 0;
int do_conf = 0;
int usage = 0;
@@ -232,6 +232,7 @@ pine_args(struct pine *pine_state, int argc, char **argv, ARGDATA_S *args)
av = argv;
memset(args, 0, sizeof(ARGDATA_S));
args->action = aaFolder;
+ memset((void *) &x, 0, sizeof(XOAUTH2_INFO_S));
pine_state->pine_name = (lc = last_cmpnt(argv[0])) ? lc : (lc = argv[0]);
#ifdef DOS
@@ -556,9 +557,9 @@ Loop: while(--ac > 0)
else if(strcmp(*av, "xoauth2-server") == 0){
if(--ac){
if((str = *++av) != NULL){
- if(xoauth2_server)
- fs_give((void **) &xoauth2_server);
- xoauth2_server = cpystr(str);
+ if(x.name)
+ fs_give((void **) &x.name);
+ x.name = cpystr(str);
}
}
else{
@@ -570,9 +571,9 @@ Loop: while(--ac > 0)
else if(strcmp(*av, "xoauth2-client-id") == 0){
if(--ac){
if((str = *++av) != NULL){
- if(xoauth2_client_id)
- fs_give((void **) &xoauth2_client_id);
- xoauth2_client_id = cpystr(str);
+ if(x.client_id)
+ fs_give((void **) &x.client_id);
+ x.client_id = cpystr(str);
}
}
else{
@@ -584,9 +585,9 @@ Loop: while(--ac > 0)
else if(strcmp(*av, "xoauth2-client-secret") == 0){
if(--ac){
if((str = *++av) != NULL){
- if(xoauth2_client_secret)
- fs_give((void **) &xoauth2_client_secret);
- xoauth2_client_secret = cpystr(str);
+ if(x.client_secret)
+ fs_give((void **) &x.client_secret);
+ x.client_secret = cpystr(str);
}
}
else{
@@ -595,6 +596,34 @@ Loop: while(--ac > 0)
}
goto Loop;
}
+ else if(strcmp(*av, "xoauth2-tenant") == 0){
+ if(--ac){
+ if((str = *++av) != NULL){
+ if(x.tenant)
+ fs_give((void **) &x.tenant);
+ x.tenant = cpystr(str);
+ }
+ }
+ else{
+ display_args_err(_(args_err_missing_tenant), NULL, 1);
+ ++usage;
+ }
+ goto Loop;
+ }
+ else if(strcmp(*av, "xoauth2-user") == 0){
+ if(--ac){
+ if((str = *++av) != NULL){
+ if(x.users)
+ fs_give((void **) &x.users);
+ x.users = cpystr(str);
+ }
+ }
+ else{
+ display_args_err(_(args_err_missing_user), NULL, 1);
+ ++usage;
+ }
+ goto Loop;
+ }
#ifdef _WINDOWS
else if(strcmp(*av, "install") == 0){
pine_state->install_flag = 1;
@@ -942,21 +971,15 @@ Loop: while(--ac > 0)
exit(-1);
}
- if((xoauth2_server || xoauth2_client_id || xoauth2_client_secret)
- && !(xoauth2_server && xoauth2_client_id && xoauth2_client_secret)){
- display_args_err(_(args_err_missing_xoauth_option), NULL, 1);
- ++usage;
- }
-
if(do_help || usage)
args_help();
if(usage)
exit(-1);
- if(xoauth2_server){
+ if(x.name){
char *tmp1, *tmp2;
- tmp2 = xoauth_config_line(xoauth2_server, xoauth2_client_id, xoauth2_client_secret);
+ tmp2 = xoauth_config_line(&x);
if(tmp2){
tmp1 = fs_get((strlen(ps_global->vars[V_XOAUTH2_INFO].name) + strlen(tmp2) + 2)*sizeof(char));
if(tmp1){
diff --git a/alpine/confscroll.c b/alpine/confscroll.c
index ee182b2..db7d2cf 100644
--- a/alpine/confscroll.c
+++ b/alpine/confscroll.c
@@ -33,6 +33,7 @@ static char rcsid[] = "$Id: confscroll.c 1169 2008-08-27 06:42:06Z hubert@u.wash
#include "talk.h"
#include "setup.h"
#include "smime.h"
+#include "xoauth2conf.h"
#include "../pith/state.h"
#include "../pith/flag.h"
#include "../pith/list.h"
@@ -1318,6 +1319,28 @@ no_down:
q_status_message(SM_ORDER,0,3, _("Moved to bottom"));
break;
+ case MC_XSHELP: /* help! */
+ if(FOOTER_ROWS(ps) == 1 && km_popped == 0){
+ km_popped = 2;
+ ps->mangled_footer = 1;
+ break;
+ }
+
+ prev_redrawer = ps_global->redrawer;
+ helper(h_xoauth2_config_screen, "XOAUTH2 CONFIGURATION SCREEN", HLPD_SIMPLE);
+ ps_global->redrawer = prev_redrawer;
+ ps->mangled_screen = 1;
+ break;
+
+ case MC_XSDELETE: /* Send caller to delete XOAUTH2 info */
+ case MC_XSADD: /* Send caller to add XOAUTH2 info */
+ if(pos){
+ *pos = get_confline_number(screen->current);
+ done++;
+ retval = cmd == MC_XSADD ? 4 : 5;
+ }
+ break;
+
case MC_REPAINT: /* redraw the display */
case MC_RESIZE:
ClearScreen();
diff --git a/alpine/conftype.h b/alpine/conftype.h
index dac07b7..9c25ad6 100644
--- a/alpine/conftype.h
+++ b/alpine/conftype.h
@@ -100,6 +100,10 @@ typedef struct conf_line {
char *exportval;
ScreenMode *listmode;
} t;
+ struct xoauth2_conf {
+ XOAUTH2_INFO_S *pat;
+ XOAUTH2_INFO_S **selected;
+ } x;
} d;
} CONF_S;
diff --git a/alpine/imap.c b/alpine/imap.c
index 7886172..d081228 100644
--- a/alpine/imap.c
+++ b/alpine/imap.c
@@ -145,7 +145,8 @@ OAUTH2_S alpine_oauth2_list[] =
{"imap.gmail.com", "smtp.gmail.com", NULL, NULL},
{{"client_id", NULL},
{"client_secret", NULL},
- {"code", NULL}, /* not used */
+ {"tenant", NULL}, /* not used */
+ {"code", NULL}, /* access code from the authorization process */
{"refresh_token", NULL},
{"scope", "https://mail.google.com/"},
{"redirect_uri", "urn:ietf:wg:oauth:2.0:oob"},
@@ -173,6 +174,7 @@ OAUTH2_S alpine_oauth2_list[] =
{"outlook.office365.com", "smtp.office365.com", NULL, NULL},
{{"client_id", NULL},
{"client_secret", NULL}, /* not used, but needed */
+ {"tenant", NULL}, /* used */
{"code", NULL}, /* not used, not needed */
{"refresh_token", NULL},
{"scope", "offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send"},
@@ -184,11 +186,11 @@ OAUTH2_S alpine_oauth2_list[] =
{"device_code", NULL} /* only used for frst time set up */
},
{{NULL, NULL, {OA2_End, OA2_End, OA2_End, OA2_End, OA2_End, OA2_End, OA2_End}}, /* Get Access Code, Not used */
- {"POST", "https://login.microsoftonline.com/common/oauth2/v2.0/devicecode", /* first time use and get device code information */
+ {"POST", "https://login.microsoftonline.com/\001/oauth2/v2.0/devicecode", /* first time use and get device code information */
{OA2_Id, OA2_Scope, OA2_End, OA2_End, OA2_End, OA2_End, OA2_End}},
- {"POST", "https://login.microsoftonline.com/common/oauth2/v2.0/token", /* Get first Refresh Token and Access token */
- {OA2_Id, OA2_Redirect, OA2_DeviceCode, OA2_End, OA2_End, OA2_End}},
- {"POST", "https://login.microsoftonline.com/common/oauth2/v2.0/token", /* Get access token from refresh token */
+ {"POST", "https://login.microsoftonline.com/\001/oauth2/v2.0/token", /* Get first Refresh Token and Access token */
+ {OA2_Id, OA2_Redirect, OA2_DeviceCode, OA2_End, OA2_End, OA2_End, 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_End, OA2_End, OA2_End}}
},
{NULL, NULL, NULL, 0, 0, NULL}, /* device_code information */
diff --git a/alpine/keymenu.c b/alpine/keymenu.c
index 69ca92d..8d94e87 100644
--- a/alpine/keymenu.c
+++ b/alpine/keymenu.c
@@ -1433,6 +1433,34 @@ struct key config_text_keys[] =
ENDKEY_MENU};
INST_KEY_MENU(config_text_keymenu, config_text_keys);
+struct key config_xoauth2_text_keys[] =
+ {HELP_MENU,
+ OTHER_MENU,
+ EXIT_SETUP_MENU,
+ {"C", "[" N_("Change Val") "]", {MC_EDIT,3,{'c',ctrl('M'),ctrl('J')}}, KS_NONE},
+ PREV_MENU,
+ NEXT_MENU,
+ PREVPAGE_MENU,
+ NEXTPAGE_MENU,
+ {"A", N_("Add Value"), {MC_ADD,1,{'a'}}, KS_NONE},
+ {"D", N_("Delete Val"), {MC_DELETE,1,{'d'}}, KS_NONE},
+ PRYNTTXT_MENU,
+ WHEREIS_MENU,
+
+ HELP_MENU,
+ OTHER_MENU,
+ {"^A", N_("Add Server"), {MC_XSADD,1,{ctrl('A')}}, KS_NONE},
+ {"^D", N_("Del Server"), {MC_XSDELETE,1,{ctrl('d')}}, KS_NONE},
+ NULL_MENU,
+ {"^H", N_("Conf Help"), {MC_XSHELP,1,{ctrl('h')}}, KS_NONE},
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ HOMEKEY_MENU,
+ ENDKEY_MENU};
+INST_KEY_MENU(config_xoauth2_text_keymenu, config_xoauth2_text_keys);
+
struct key config_text_to_charsets_keys[] =
{HELP_MENU,
@@ -1769,6 +1797,21 @@ struct key role_select_keys[] =
WHEREIS_MENU};
INST_KEY_MENU(role_select_km, role_select_keys);
+struct key xoauth2_id_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_("PrevID"), {MC_PREVITEM, 1, {'p'}}, KS_NONE},
+ {"N", N_("NextID"), {MC_NEXTITEM, 2, {'n', TAB}}, KS_NONE},
+ PREVPAGE_MENU,
+ NEXTPAGE_MENU,
+ HOMEKEY_MENU,
+ ENDKEY_MENU,
+ NULL_MENU,
+ WHEREIS_MENU};
+INST_KEY_MENU(xoauth2_id_select_km, xoauth2_id_select_keys);
+
struct key role_config_keys[] =
{HELP_MENU,
@@ -1829,6 +1872,33 @@ struct key config_text_wshuf_keys[] =
ENDKEY_MENU};
INST_KEY_MENU(config_text_wshuf_keymenu, config_text_wshuf_keys);
+struct key config_xoauth2_wshuf_keys[] =
+ {HELP_MENU,
+ OTHER_MENU,
+ EXIT_SETUP_MENU,
+ {"C", "[" N_("Change Val") "]", {MC_EDIT,3,{'c',ctrl('M'),ctrl('J')}}, KS_NONE},
+ PREV_MENU,
+ NEXT_MENU,
+ PREVPAGE_MENU,
+ NEXTPAGE_MENU,
+ {"A", N_("Add Value"), {MC_ADD,1,{'a'}}, KS_NONE},
+ {"D", N_("Delete Val"), {MC_DELETE,1,{'d'}}, KS_NONE},
+ PRYNTTXT_MENU,
+ WHEREIS_MENU,
+
+ HELP_MENU,
+ OTHER_MENU,
+ {"^A", N_("Add Server"), {MC_XSADD,1,{ctrl('A')}}, KS_NONE},
+ {"^D", N_("Del Server"), {MC_XSDELETE,1,{ctrl('d')}}, KS_NONE},
+ {"$", N_("Shuffle"), {MC_SHUFFLE,1,{'$'}}, KS_NONE},
+ {"^H", N_("Conf Help"), {MC_XSHELP,1,{ctrl('h')}}, KS_NONE},
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ HOMEKEY_MENU,
+ ENDKEY_MENU};
+INST_KEY_MENU(config_xoauth2_wshuf_keymenu, config_xoauth2_wshuf_keys);
struct key config_text_wshufandfldr_keys[] =
{HELP_MENU,
diff --git a/alpine/keymenu.h b/alpine/keymenu.h
index 87d1151..3cf4e2c 100644
--- a/alpine/keymenu.h
+++ b/alpine/keymenu.h
@@ -217,7 +217,9 @@ struct key_menu {
#define MC_ADDHEADER 804
#define MC_XOAUTH2 805
#define MC_EXTERNAL 806
-
+#define MC_XSADD 807
+#define MC_XSDELETE 808
+#define MC_XSHELP 809
/* Commands for S/MIME screens */
#define MC_TRUST 900
@@ -629,6 +631,7 @@ extern struct key_menu cancel_keymenu,
role_select_km,
role_conf_km,
config_text_wshuf_keymenu,
+ config_xoauth2_wshuf_keymenu,
config_text_wshufandfldr_keymenu,
config_role_file_keymenu,
config_role_file_res_keymenu,
@@ -647,6 +650,8 @@ extern struct key_menu cancel_keymenu,
config_role_afrom_keymenu,
config_checkbox_keymenu,
config_text_keymenu,
+ xoauth2_id_select_km,
+ config_xoauth2_text_keymenu,
config_text_to_charsets_keymenu,
config_radiobutton_keymenu,
config_yesno_keymenu,
diff --git a/alpine/xoauth2.h b/alpine/xoauth2.h
index f3896e8..a50a1e8 100644
--- a/alpine/xoauth2.h
+++ b/alpine/xoauth2.h
@@ -15,18 +15,14 @@
#ifndef ALPINE_XOAUTH2_INCLUDED
#define ALPINE_XOAUTH2_INCLUDED
-typedef struct xoauth_default_s {
- unsigned char *name;
- char *client_id;
- char *client_secret;
-} XOAUTH2_INFO_S;
-
#define GMAIL_NAME "Gmail"
#define GMAIL_ID "624395471329-0qee3goofj7kbl7hsukou3rqq0igntv1.apps.googleusercontent.com"
#define GMAIL_SECRET "vwnqVJQrJZpR6JilCfAN5nY7"
+#define GMAIL_TENANT NULL
#define OUTLOOK_NAME "Outlook"
#define OUTLOOK_ID "f21dcaf2-8020-469b-8135-343bfc35d046"
#define OUTLOOK_SECRET NULL
+#define OUTLOOK_TENANT "common"
#endif /* ALPINE_XOAUTH2_INCLUDED */
diff --git a/alpine/xoauth2conf.c b/alpine/xoauth2conf.c
index 0e89806..9a6b246 100644
--- a/alpine/xoauth2conf.c
+++ b/alpine/xoauth2conf.c
@@ -14,96 +14,356 @@
#include "headers.h"
#include "xoauth2conf.h"
-#include "xoauth2.h"
#include "keymenu.h"
#include "status.h"
#include "confscroll.h"
+#include "init.h"
#include "../pith/state.h"
#include "../pith/conf.h"
#include "../pith/list.h"
+#include "../pith/mailcmd.h"
extern OAUTH2_S alpine_oauth2_list[];
XOAUTH2_INFO_S xoauth_default[] = {
- { GMAIL_NAME, GMAIL_ID, GMAIL_SECRET},
- { OUTLOOK_NAME, OUTLOOK_ID, OUTLOOK_SECRET},
- { NULL, NULL, NULL}
+ { GMAIL_NAME, GMAIL_ID, GMAIL_SECRET, GMAIL_TENANT, NULL},
+ { OUTLOOK_NAME, OUTLOOK_ID, OUTLOOK_SECRET, OUTLOOK_TENANT, NULL},
+ { NULL, NULL, NULL, NULL, NULL}
};
+typedef enum {Xname = 0, Xid, Xsecret, Xtenant, Xuser, Xend} XTYPES;
+
+typedef struct xoauh2_info_val_s {
+ char *screen_name;
+ char *pinerc_name;
+} XOAUTH2_INFO_VAL_S;
+
+/* the order here must match the order in XTYPES above */
+XOAUTH2_INFO_VAL_S x_default[] = {
+ {NULL, "/NAME="},
+ {"Client-Id", "/ID="},
+ {"Client-Secret", "/SECRET="},
+ {"Tenant", "/TENANT="},
+ {"Username", "/USER="},
+ {NULL, NULL}
+};
+
+#define XNAME x_default[Xname].pinerc_name
+#define XID x_default[Xid].pinerc_name
+#define XSECRET x_default[Xsecret].pinerc_name
+#define XTENANT x_default[Xtenant].pinerc_name
+#define XUSER x_default[Xuser].pinerc_name
-#define NXSERVERS (sizeof(xoauth_default)/sizeof(xoauth_default[0])-1)
-#define XOAUTH2_CLIENT_ID _("Client-Id")
-#define XOAUTH2_CLIENT_SECRET _("Client-Secret")
-#define XNAME "/NAME="
-#define XID "/ID="
-#define XSECRET "/SECRET="
+#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
+char *list_to_array(char **);
+char **array_to_list(char *);
void write_xoauth_configuration(struct variable *, struct variable **, EditWhich);
+char **xoauth2_conf_dedup_and_merge(char ***);
+int same_xoauth2_info(XOAUTH2_INFO_S, XOAUTH2_INFO_S);
+XOAUTH2_INFO_S *xoauth_info_choice(XOAUTH2_INFO_S **, char *);
+int xoauth2_info_tool(struct pine *, int, CONF_S **, unsigned int);
+
+int
+same_xoauth2_info(XOAUTH2_INFO_S x, XOAUTH2_INFO_S y)
+{
+ int rv = 0;
+ if(x.name && y.name && !strcmp(x.name, y.name)
+ && x.client_id && y.client_id && !strcmp(x.client_id, y.client_id)
+ && ((!x.client_secret && !y.client_secret)
+ || (x.client_secret && y.client_secret && !strcmp(x.client_secret, y.client_secret)))
+ && ((!x.tenant && !y.tenant) || (x.tenant && y.tenant && !strcmp(x.tenant, y.tenant))))
+ rv = 1;
+ return rv;
+}
+
+char *
+list_to_array(char **list)
+{
+ char *rv;
+ int i;
+ size_t n;
+
+ if(list == NULL || *list == NULL) return NULL;
+
+ for(i = 0, n = 0; list[i] != NULL; i++)
+ n += strlen(list[i]) + 1;
+
+ rv = fs_get(n*sizeof(char));
+ *rv = '\0';
+ for(i = 0; list[i] != NULL; i++){
+ strcat(rv, list[i]);
+ if(list[i+1] != NULL) strcat(rv, ",");
+ }
+ return rv;
+}
+
+
+char **array_to_list(char *array)
+{
+ int i;
+ char *u;
+
+ if(array == NULL || *array == '\0') return NULL;
+
+ for(u = array, i = 0; u && *u; u++)
+ if(*u == ',') i++;
+
+ return parse_list(array, i+1, 0,NULL);
+}
char *
-xoauth_config_line(char *server, char *id, char *secret)
+xoauth_config_line(XOAUTH2_INFO_S *x)
{
size_t n;
char *rv;
+ int i;
- n = strlen(XNAME) + strlen(XID) + strlen(XSECRET)
- + strlen(server) + strlen(id) + strlen(secret) + 9;
+ if(x == NULL) return NULL;
+
+ n = strlen(XNAME) + strlen(x->name) + strlen(XID) + strlen(x->client_id)
+ + 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;
rv = fs_get(n*sizeof(char));
- sprintf(rv, "%s\"%s\" %s\"%s\" %s\"%s\"", XNAME, server, XID, id,
- XSECRET, secret);
+ sprintf(rv, "%s\"%s\" %s\"%s\"", XNAME, x->name, XID, x->client_id);
+ if(x->client_secret)
+ sprintf(rv + strlen(rv), " %s\"%s\"", XSECRET, x->client_secret);
+ if(x->tenant)
+ sprintf(rv + strlen(rv), " %s\"%s\"", XTENANT, x->tenant);
+ sprintf(rv + strlen(rv), " %s\"%s\"", XUSER, x->users ? x->users : "");
return rv;
}
-/* call this function when id and secret are unknown.
- * precedence is as follows:
- * If the user has configured something, return that;
- * else if we are already using a value, return that;
- * else return default values.
- */
-void
-oauth2_get_client_info(unsigned char *name, char **id, char **secret)
+int
+xoauth2_info_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
{
- int i;
- char **lval, *name_lval, *idp, *secretp;
+ int rv = 0;
+
+ switch(cmd){
+ case MC_CHOICE:
+ *((*cl)->d.x.selected) = (*cl)->d.x.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;
- *id = *secret = NULL;
+ return rv;
+}
+
+XOAUTH2_INFO_S *
+xoauth_info_choice(XOAUTH2_INFO_S **xinfo, char *user)
+{
+ int i, n, rv;
+ if(!ps_global->ttyo){
+ char *s;
+ char prompt[1024];
+ char reply[1024];
+ int sel;
+ for(i = n = 0; xinfo[i] != NULL; i++)
+ n += strlen(xinfo[i]->client_id); + 5; /* number, parenthesis, space */
+ n += strlen(xinfo[0]->name) + strlen(user);
+ n += 1024; /* large enough to display to lines of 80 characters in UTF-8 */
+ s = fs_get(n*sizeof(char));
+ sprintf(s, _("Alpine cannot determine which client-id to use for the username <%s> for your %s account. "), user, xinfo[0]->name);
+ sprintf(s + strlen(s), _("Please select the client-id to use from the following list.\n\n"));
+ for(i = 0; xinfo[i]; i++)
+ sprintf(s + strlen(s), " %d) %.70s\n", i+1, xinfo[i]->client_id);
+ sprintf(s + strlen(s), "%s", "\n\n");
+
+ 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) - 1;
+ rv = (sel >= 0 && sel < i) ? 0 : -1;
+ } while (rv != 0);
+ return copy_xoauth2_info(xinfo[rv]);
+ }
+ else{
+ CONF_S *ctmp = NULL, *first_line = NULL;
+ XOAUTH2_INFO_S *x_sel = NULL;
+ OPT_SCREEN_S screen;
+ char tmp[1024];
+
+ dprint((9, "xoauth2 select client-id screen"));
+ 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(_("Select a Client-ID to use with this account"));
+
+ new_confline(&ctmp);
+ ctmp->flags |= CF_NOSELECT;
+ ctmp->value = cpystr(tmp);
+
+ new_confline(&ctmp);
+ ctmp->flags |= CF_NOSELECT | CF_B_LINE;
+
+ sprintf(tmp, _("Alpine cannot determine which client-id to use for the username <%s>"), user);
+ new_confline(&ctmp);
+ ctmp->flags |= CF_NOSELECT;
+ ctmp->value = cpystr(tmp);
+
+ sprintf(tmp, _("for your %s account. Please select the client-id to use from the following list.\n\n"), xinfo[0]->name);
+ new_confline(&ctmp);
+ ctmp->flags |= CF_NOSELECT;
+ ctmp->value = cpystr(tmp);
+
+ new_confline(&ctmp);
+ ctmp->flags |= CF_NOSELECT | CF_B_LINE;
+
+ for(i = 0; xinfo[i] != NULL; i++){
+ new_confline(&ctmp);
+ if(!first_line)
+ first_line = ctmp;
+
+ ctmp->value = cpystr(xinfo[i]->client_id);
+ ctmp->d.x.selected = &x_sel;
+ ctmp->d.x.pat = copy_xoauth2_info(xinfo[i]);
+ ctmp->keymenu = &xoauth2_id_select_km;
+ ctmp->help = NO_HELP;
+ ctmp->help_title = NULL;
+ ctmp->tool = xoauth2_info_tool;
+ ctmp->flags = CF_STARTITEM;
+ ctmp->valoffset = 4;
+ }
+ (void)conf_scroll_screen(ps_global, &screen, first_line, _("SELECT CLIENT_ID"),
+ _("xoauth2"), 0, NULL);
+ return x_sel;
+ }
+ return NULL;
+}
+
+/* Get the client-id, etc. for server "name" associated to user "user" */
+XOAUTH2_INFO_S *
+oauth2_get_client_info(unsigned char *name, char *user)
+{
+ int i, j, matches;
+ char ***alval, **lval;
+ XOAUTH2_INFO_S *x, **xinfo;
- /* first check the value configured by the user */
+ if(name == NULL || *name == '\0' || user == NULL || *user == '\0')
+ return NULL;
+
+ matches = 0;
+ /* first count how many servers */
lval = ps_global->vars[V_XOAUTH2_INFO].current_val.l;
for(i = 0; lval && lval[i]; i++){
- xoauth_parse_client_info(lval[i], &name_lval, &idp, &secretp);
- if(name_lval && !strcmp(name_lval, name)){
- *id = idp ? cpystr(idp) : NULL;
- *secret = secretp ? cpystr(secretp) : NULL;
- }
- if(name_lval) fs_give((void **) &name_lval);
- if(idp) fs_give((void **) &idp);
- if(secretp) fs_give((void **) &secretp);
- break;
+ x = xoauth_parse_client_info(lval[i]);
+ if(x && x->name && name && !strcmp(x->name, name))
+ matches++;
+ free_xoauth2_info(&x);
}
- if(*id && **id && *secret && **secret) return;
+ /* if nothing, use the default value */
+ for(i = 0; xoauth_default[i].name != NULL && strcmp(xoauth_default[i].name, name); i++);
+ if(xoauth_default[i].name) matches++;
+
+ if(matches == 0) return NULL;
+ if(matches == 1) return copy_xoauth2_info(&xoauth_default[i]);
- /* if not, now see if we already have a value set, and use that */
- for(i = 0; alpine_oauth2_list[i].name != NULL; i++){
- if(!strcmp(alpine_oauth2_list[i].name, name)){
- *id = alpine_oauth2_list[i].param[OA2_Id].value
- ? cpystr(alpine_oauth2_list[i].param[OA2_Id].value) : NULL;
- *secret = alpine_oauth2_list[i].param[OA2_Secret].value
- ? cpystr(alpine_oauth2_list[i].param[OA2_Secret].value) : NULL;
- break;
+ /* more than one match, see if it is a duplicate client-id entry */
+ xinfo = fs_get((matches + 1)*sizeof(XOAUTH2_INFO_S *));
+ memset((void *)xinfo, 0, (matches + 1)*sizeof(XOAUTH2_INFO_S *));
+ matches = 0; /* restart the recount, it might go lower! */
+ for(i = 0; lval && lval[i]; i++){
+ x = xoauth_parse_client_info(lval[i]);
+ if(x && x->name && name && !strcmp(x->name, name)){
+ for(j = 0; xinfo && xinfo[j] && !same_xoauth2_info(*x, *xinfo[j]); j++);
+ if(!xinfo[j]) xinfo[matches++] = copy_xoauth2_info(x);
}
+ free_xoauth2_info(&x);
+ }
+ for(i = 0; xoauth_default[i].name != NULL && strcmp(xoauth_default[i].name, name); i++){
+ for(j = 0; xinfo && xinfo[j] && !same_xoauth2_info(xoauth_default[i], *xinfo[j]); j++);
+ if(xoauth_default[i].name && !xinfo[j]) xinfo[matches++] = copy_xoauth2_info(&xoauth_default[i]);
}
- if(*id && **id && *secret && **secret) return;
+ /* if after removing the duplicate entries, we only have one, use it */
+ if(matches == 1){
+ x = copy_xoauth2_info(xinfo[0]);
+ free_xoauth2_info(&xinfo[0]);
+ fs_give((void **) xinfo);
+ return x;
+ }
- /* if nothing, use the default value */
- for(i = 0; xoauth_default[i].name != NULL; i++)
- if(!strcmp(xoauth_default[i].name, name)){
- *id = cpystr(xoauth_default[i].client_id);
- *secret = cpystr(xoauth_default[i].client_secret);
- break;
- }
+ /* we have more than one match, now check if any of them matches the given user */
+ matches = 0;
+ for(i = 0; xinfo && xinfo[i]; i++){
+ lval = array_to_list(xinfo[i]->users);
+ for(j = 0; lval && lval[j] && strucmp(lval[j], user); j++);
+ if(lval && lval[j]){
+ matches++;
+ free_xoauth2_info(&x);
+ x = copy_xoauth2_info(xinfo[i]);
+ }
+ if(lval) free_list_array(&lval);
+ }
+
+ /* only one server matches the username */
+ if(matches == 1){
+ for(i = 0; xinfo[i] != NULL; i++)
+ free_xoauth2_info(&xinfo[i]);
+ fs_give((void **) xinfo);
+ return x;
+ }
+
+ free_xoauth2_info(&x);
+ /* We either have no matches, or have more than one match!
+ * in either case, let the user pick what they want */
+ x = xoauth_info_choice(xinfo, user);
+ for(i = 0; xinfo[i] != NULL; i++)
+ free_xoauth2_info(&xinfo[i]);
+ fs_give((void **) xinfo);
+
+ /* Once the user chose a client-id, save it so we do not ask again */
+ if(x != NULL){
+ int n = x->users ? strlen(x->users) + 1 : 0;
+ char ***alval, **l;
+
+ fs_resize((void **) &x->users, (n + strlen(user) + 1)*sizeof(char));
+ x->users[n > 0 ? n - 1 : 0] = '\0';
+ if(n > 0) strcat(x->users, ",");
+ strcat(x->users, user);
+ alval = ALVAL(&ps_global->vars[V_XOAUTH2_INFO], Main);
+ lval = *alval;
+
+ for(n = 0; lval && lval[n]; n++);
+ fs_resize((void **) &lval, (n+2)*sizeof(char *));
+ lval[n] = xoauth_config_line(x);
+ lval[n+1] = NULL;
+ *alval = xoauth2_conf_dedup_and_merge(&lval);
+ set_current_val(&ps_global->vars[V_XOAUTH2_INFO], FALSE, FALSE);
+ write_pinerc(ps_global, Main, WRP_NONE);
+ }
+
+ return x;
}
/* write vlist to v
@@ -113,30 +373,69 @@ oauth2_get_client_info(unsigned char *name, char **id, char **secret)
void
write_xoauth_configuration(struct variable *v, struct variable **vlist, EditWhich ew)
{
- int i, j, k;
- size_t n;
- char ***alval, **lval, *p, *q, *l;
+ int i, j, k, m, n;
+ XOAUTH2_INFO_S *x = NULL, *y;
+ char ***alval, **lval, **l;
+ char *p;
+
+ for (i = 0, n = 0; vlist[i] != NULL; i++) /* count number of lines we need */
+ if(!strcmp(vlist[i]->name, XOAUTH2_USERS))
+ n++;
+ lval = fs_get((n+1)*sizeof(char *));
+ memset((void *) lval, 0, (n+1)*sizeof(char *));
alval = ALVAL(v, ew);
- for (i = 0, k = 0; vlist[i] != NULL;){
- if(PVAL(vlist[i], ew)){
- j = i/2; /* this is the location in the alpine_oauth2_list array */
- i = 2*j; /* reset i */
- p = PVAL(vlist[i], ew);
- if(p == NULL) p = vlist[i]->current_val.p;
- q = PVAL(vlist[i+1], ew);
- if(q == NULL) q = vlist[i+1]->current_val.p;
- if(k == 0) lval = fs_get((NXSERVERS +1)*sizeof(char *));
- lval[k++] = xoauth_config_line(alpine_oauth2_list[j].name, p, q);
- if(alpine_oauth2_list[j].param[OA2_Id].value)
- fs_give((void **) &alpine_oauth2_list[j].param[OA2_Id].value);
- if(alpine_oauth2_list[j].param[OA2_Secret].value)
- fs_give((void **) &alpine_oauth2_list[j].param[OA2_Secret].value);
- alpine_oauth2_list[j].param[OA2_Id].value = cpystr(p);
- alpine_oauth2_list[j].param[OA2_Secret].value = cpystr(q);
- i += 2;
+ for (i = 0, k = 0; vlist[i] != NULL; i++){
+ if(x == NULL){
+ x = new_xoauth2_info();
+ x->name = cpystr(vlist[i]->descrip); /* hack! but makes life so much easier! */
+ for(m = 0; xoauth_default[m].name != NULL
+ && strcmp(xoauth_default[m].name, x->name); m++);
+ }
+ if (x->client_id == NULL && !strcmp(vlist[i]->name, XOAUTH2_CLIENT_ID)){
+ p = PVAL(vlist[i], ew);
+ if (p == NULL) p = vlist[i]->current_val.p;
+ if(p != NULL)
+ x->client_id = cpystr(p);
+ continue;
}
- else i++;
+ if (x->client_secret == NULL
+ && m >= 0
+ && xoauth_default[m].client_secret
+ && !strcmp(vlist[i]->name, XOAUTH2_CLIENT_SECRET)){
+ p = PVAL(vlist[i], ew);
+ if (p == NULL) p = vlist[i]->current_val.p;
+ if(p != NULL)
+ x->client_secret = cpystr(p);
+ continue;
+ }
+ if (x->tenant == NULL
+ && m >= 0
+ && xoauth_default[m].tenant
+ && !strcmp(vlist[i]->name, XOAUTH2_TENANT)){
+ p = PVAL(vlist[i], ew);
+ if (p == NULL) p = vlist[i]->current_val.p;
+ if(p != NULL)
+ x->tenant = cpystr(p);
+ continue;
+ }
+ if (x->users == NULL && !strcmp(vlist[i]->name, XOAUTH2_USERS)){
+ l = LVAL(vlist[i], ew);
+ x->users = list_to_array(l);
+ }
+ /* don't let it get to here until we are done! */
+ lval[k++] = xoauth_config_line(x);
+ if(alpine_oauth2_list[j].param[OA2_Id].value)
+ fs_give((void **) &alpine_oauth2_list[j].param[OA2_Id].value);
+ if(alpine_oauth2_list[j].param[OA2_Secret].value)
+ fs_give((void **) &alpine_oauth2_list[j].param[OA2_Secret].value);
+ if(alpine_oauth2_list[j].param[OA2_Tenant].value)
+ fs_give((void **) &alpine_oauth2_list[j].param[OA2_Tenant].value);
+ alpine_oauth2_list[j].param[OA2_Id].value = cpystr(x->client_id);
+ alpine_oauth2_list[j].param[OA2_Secret].value = x->client_secret ? cpystr(x->client_secret) : NULL;
+ alpine_oauth2_list[j].param[OA2_Tenant].value = x->tenant ? cpystr(x->tenant) : NULL;
+ /* get ready for next run */
+ free_xoauth2_info(&x);
}
if(k > 0){
lval[k] = NULL;
@@ -150,25 +449,26 @@ write_xoauth_configuration(struct variable *v, struct variable **vlist, EditWhi
/* parse line of the form
- /NAME="text" /ID="text" /SECRET="text"
+ /NAME="text" /ID="text" /TENANT="text" /SECRET="text" /USER="text"
*/
-void
-xoauth_parse_client_info(char *lvalp, char **namep, char **idp, char **secretp)
+XOAUTH2_INFO_S *
+xoauth_parse_client_info(char *lvalp)
{
char *s, *t, c;
- *namep = *idp = *secretp = NULL;
+ XOAUTH2_INFO_S *x;
- if (lvalp == NULL) return;
+ if (lvalp == NULL) return NULL;
+ x = new_xoauth2_info();
if((s = strstr(lvalp, XNAME)) != NULL){
s += strlen(XNAME);
if(*s == '"') s++;
for(t = s; *t && *t != '"' && *t != ' '; t++);
c = *t;
*t = '\0';
- *namep = cpystr(s);
+ if (*s) x->name = cpystr(s);
*t = c;
- }
+ } else x->name = NULL;
if((s = strstr(lvalp, XID)) != NULL){
s += strlen(XID);
@@ -176,9 +476,19 @@ xoauth_parse_client_info(char *lvalp, char **namep, char **idp, char **secretp)
for(t = s; *t && *t != '"' && *t != ' '; t++);
c = *t;
*t = '\0';
- *idp = cpystr(s);
+ if (*s) x->client_id = cpystr(s);
*t = c;
- }
+ } else x->client_id = NULL;
+
+ if((s = strstr(lvalp, XTENANT)) != NULL){
+ s += strlen(XTENANT);
+ if(*s == '"') s++;
+ for(t = s; *t && *t != '"' && *t != ' '; t++);
+ c = *t;
+ *t = '\0';
+ if (*s) x->tenant = cpystr(s);
+ *t = c;
+ } else x->tenant = NULL;
if((s = strstr(lvalp, XSECRET)) != NULL){
s += strlen(XSECRET);
@@ -186,11 +496,247 @@ xoauth_parse_client_info(char *lvalp, char **namep, char **idp, char **secretp)
for(t = s; *t && *t != '"' && *t != ' '; t++);
c = *t;
*t = '\0';
- *secretp = cpystr(s);
+ if (*s) x->client_secret = cpystr(s);
*t = c;
- }
+ } else x->client_secret = NULL;
+
+ if((s = strstr(lvalp, XUSER)) != NULL){
+ s += strlen(XUSER);
+ if(*s == '"') s++;
+ for(t = s; *t && *t != '"' && *t != ' '; t++);
+ c = *t;
+ *t = '\0';
+ if(*s) x->users = cpystr(s);
+ *t = c;
+ } else x->users = NULL;
+
+ return x;
}
+char **
+xoauth2_conf_dedup_and_merge(char ***alval)
+{
+ int i, j, k, l, n, m;
+ char **lval, **rv;
+ XOAUTH2_INFO_S *x, *y;
+
+ if(alval == NULL || *alval == NULL || **alval == NULL)
+ return NULL;
+
+ lval = *alval;
+ for(i = 0; lval[i] != NULL; i++); /* count how many entries */
+
+ rv = fs_get((i+1)*sizeof(char *));
+ memset((void *)rv, 0, (i+1)*sizeof(char *));
+
+ for (i = 0; lval[i] != NULL; i++){
+ x = xoauth_parse_client_info(lval[i]);
+ for (j = 0; rv[j] != NULL; j++){
+ y = xoauth_parse_client_info(rv[j]);
+ /* check if this is the same data. If so, merge the users into one and discard the old data */
+ if(same_xoauth2_info(*x, *y)){
+ char **l1, **l2, **l3;
+ int k, n;
+ /* merge user1 with user2, save in x->users */
+ l1 = array_to_list(x->users);
+ l2 = array_to_list(y->users);
+
+ for(n = 0; l1 && l1[n]; n++);
+ for(m = 0; l2 && l2[m]; m++, n++);
+ l3 = fs_get((n+1)*sizeof(char*));
+ memset((void *) l3, 0, (n+1)*sizeof(char *));
+
+ for(l = 0, n = 0; l1 && l1[l]; l++){
+ for(k = 0; l1 && l1[j] && l3[k] && strucmp(l1[l], l3[k]); k++);
+ if(l3[k] == NULL && l1 && l1[l] != NULL)
+ l3[n++] = cpystr(l1[l]);
+ }
+ for(l = 0; l2 && l2[l]; l++){
+ for(k = 0; l2 && l2[l] && l3[k] && strucmp(l2[l], l3[k]); k++);
+ if(l3[k] == NULL && l2 && l2[l] != NULL)
+ l3[n++] = cpystr(l2[l]);
+ }
+ l3[n++] = NULL;
+ if(x->users) fs_give((void **) &x->users);
+ x->users = list_to_array(l3);
+ fs_give((void **) &rv[j]);
+ rv[j] = xoauth_config_line(x);
+
+ if(l1) free_list_array(&l1);
+ if(l2) free_list_array(&l2);
+ if(l3) free_list_array(&l3);
+ free_xoauth2_info(&y);
+ break;
+ }
+ free_xoauth2_info(&y);
+ }
+ if(rv[j] == NULL) rv[j] = cpystr(lval[i]);
+ }
+ return rv;
+}
+
+/*
+ * X = new value, Y = default configuration
+ */
+void
+write_xoauth_conf_entry(XOAUTH2_INFO_S *x, XOAUTH2_INFO_S *y, CONF_S **cl, CONF_S **clb, CONF_S **fline,
+ struct variable ***varlistp, int *pp, int ln, int key)
+{
+ CONF_S *ctmpb = *clb;
+ struct variable **varlist;
+ int i, p = *pp;
+ char tmp[1024], tmp2[16];
+
+ i = 2; /* client_id and users always appear */
+ if(x->client_secret) i++;
+ if(x->tenant) i++;
+
+ sprintf(tmp2, "%d", key);
+ fs_resize((void **) varlistp, (p + i + 1)*sizeof(struct variable **));
+ memset((void *) *varlistp + p*sizeof(struct variable *), 0, (i + 1)*sizeof(struct variable *));
+ varlist = *varlistp;
+
+ new_confline(cl)->var = NULL;
+ if(fline && !*fline) *fline = *cl;
+ (*cl)->flags |= CF_NOSELECT;
+ (*cl)->help = NO_HELP;
+ (*cl)->valoffset = 1;
+ (*cl)->value = cpystr(x->name);
+ (*cl)->varname = NULL;
+ (*cl)->varnamep = ctmpb = *cl;
+
+ /* Setup client-id variable */
+ varlist[p] = fs_get(sizeof(struct variable));
+ memset((void *) varlist[p], 0, sizeof(struct variable));
+ varlist[p]->name = cpystr(XOAUTH2_CLIENT_ID);
+ varlist[p]->is_used = 1;
+ varlist[p]->is_user = 1;
+ varlist[p]->main_user_val.p = x->client_id && y->client_id
+ && strcmp(x->client_id, y->client_id) ? cpystr(x->client_id) : NULL;
+ varlist[p]->global_val.p = y->client_id ? cpystr(y->client_id) : NULL;
+ 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-id variable */
+ new_confline(cl)->var = varlist[p];
+ utf8_snprintf(tmp, sizeof(tmp), " %-*.100w =", ln, XOAUTH2_CLIENT_ID);
+ 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_client_id;
+ (*cl)->tool = text_tool;
+ (*cl)->varnamep = ctmpb;
+
+ /* Set up client-secret variable */
+ if(x->client_secret){
+ varlist[p] = fs_get(sizeof(struct variable));
+ memset((void *) varlist[p], 0, sizeof(struct variable));
+ varlist[p]->name = cpystr(XOAUTH2_CLIENT_SECRET);
+ varlist[p]->is_used = 1;
+ varlist[p]->is_user = 1;
+ varlist[p]->main_user_val.p = y->client_secret
+ && strcmp(x->client_secret, y->client_secret)
+ ? cpystr(x->client_secret) : NULL;
+ varlist[p]->global_val.p = y->client_secret ? cpystr(y->client_secret) : NULL;
+ 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_CLIENT_SECRET);
+ 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_client_secret;
+ (*cl)->tool = text_tool;
+ (*cl)->varnamep = ctmpb;
+ }
+
+ /* Set up tenant variable */
+ if(x->tenant){
+ varlist[p] = fs_get(sizeof(struct variable));
+ memset((void *) varlist[p], 0, sizeof(struct variable));
+ varlist[p]->name = cpystr(XOAUTH2_TENANT);
+ varlist[p]->is_used = 1;
+ varlist[p]->is_user = 1;
+ varlist[p]->main_user_val.p = y->tenant && strcmp(x->tenant, y->tenant)
+ ? cpystr(x->tenant) : NULL;
+ varlist[p]->global_val.p = y->tenant ? cpystr(y->tenant) : NULL;
+ 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_TENANT);
+ 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_tenant;
+ (*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));
+ varlist[p]->name = cpystr(XOAUTH2_USERS);
+ varlist[p]->is_used = 1;
+ varlist[p]->is_user = 1;
+ varlist[p]->is_list = 1;
+ varlist[p]->main_user_val.l = x->users ? array_to_list(x->users) : NULL;
+ 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 user variable */
+ new_confline(cl)->var = varlist[p];
+ utf8_snprintf(tmp, sizeof(tmp), " %-*.100w =", ln, XOAUTH2_USERS);
+ tmp[sizeof(tmp)-1] = '\0';
+ (*cl)->varname = cpystr(tmp);
+ (*cl)->valoffset = ln + 3 + 3;
+ (*cl)->keymenu = &config_xoauth2_wshuf_keymenu;
+ (*cl)->help = h_config_xoauth2_username;
+ if(x->users){
+ int z;
+ for(z = 0; varlist[p]->main_user_val.l[z]; z++){
+ if(z) new_confline(cl);
+ (*cl)->var = varlist[p];
+ (*cl)->varmem = z;
+ (*cl)->valoffset = ln + 3 + 3;
+ (*cl)->value = pretty_value(ps_global, *cl);
+ (*cl)->keymenu = &config_xoauth2_wshuf_keymenu;
+ (*cl)->tool = text_tool;
+ (*cl)->varnamep = ctmpb = *cl;
+ }
+ }
+ else {
+ (*cl)->varmem = 0;
+ (*cl)->value = pretty_value(ps_global, *cl);
+ (*cl)->keymenu = &config_xoauth2_wshuf_keymenu;
+ (*cl)->tool = text_tool;
+ (*cl)->varnamep = ctmpb = *cl;
+ }
+ p++;
+ *pp = p;
+ *varlistp = varlist;
+ *clb = ctmpb;
+
+ /* Separate servers with a blank line */
+ new_confline(cl);
+ (*cl)->flags |= CF_NOSELECT | CF_B_LINE;
+}
/*----------------------------------------------------------------------
Screen to add client_id and client_secret for a service
@@ -199,19 +745,20 @@ xoauth_parse_client_info(char *lvalp, char **namep, char **idp, char **secretp)
void
alpine_xoauth2_configuration(struct pine *ps, int edit_exceptions)
{
- struct variable gmail_client_id_var, gmail_client_secret_var;
- struct variable outlook_client_id_var, outlook_client_secret_var;
- struct variable *varlist[2*NXSERVERS + 1];
- char tmp[MAXPATH+1], *pval, **lval;
- char *id, *secret;
- char *name_lval, *id_lval, *id_conf, *id_def, *secret_lval, *secret_conf, *secret_def;
- int i, j, k, l, ln = 0, readonly_warning = 0, pos;
- CONF_S *ctmpa = NULL, *ctmpb, *first_line = NULL;
+ struct variable **varlist = NULL;
+ char tmp[MAXPATH+1], *pval, **lval, ***alval;
+ char *s, *extraname = NULL;
+ char *name, *id, *tenant, *secret, **user;
+ 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;
+ CONF_S *ctmpa = NULL, *ctmpb, *first_line;
FEATURE_S *feature;
PINERC_S *prc = NULL;
OPT_SCREEN_S screen;
int expose_hidden_config, add_hidden_vars_title = 0;
SAVED_CONFIG_S *vsave;
+ XOAUTH2_INFO_S x, *y;
dprint((3, "-- alpine_xoauth2_configuration --\n"));
@@ -239,127 +786,49 @@ alpine_xoauth2_configuration(struct pine *ps, int edit_exceptions)
mailcap_free(); /* free resources we won't be using for a while */
- varlist[0] = &gmail_client_id_var;
- varlist[1] = &gmail_client_secret_var;
- varlist[2] = &outlook_client_id_var;
- varlist[3] = &outlook_client_secret_var;
- varlist[2*NXSERVERS] = NULL;
-
- for(i = 0; i < 2*NXSERVERS; i++)
- memset((void *) varlist[i], 0, sizeof(struct variable));
-
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;
+
+ alval = ALVAL(&ps->vars[V_XOAUTH2_INFO], ew);
+ lval = *alval = xoauth2_conf_dedup_and_merge(alval);
+ set_current_val(&ps_global->vars[V_XOAUTH2_INFO], FALSE, FALSE);
+ write_pinerc(ps_global, ew, WRP_NONE);
+
do {
ctmpa = first_line = NULL;
- ln = strlen(XOAUTH2_CLIENT_ID);
- i = strlen(XOAUTH2_CLIENT_SECRET);
- if(ln < i) ln = i;
-
- lval = LVAL(&ps->vars[V_XOAUTH2_INFO], ew);
-
- for(i = 0, l = 0; alpine_oauth2_list[i].name != NULL; i++){
- id_conf = id_def = secret_conf = secret_def = NULL;
- name_lval = id_lval = secret_lval = NULL;
-
- id_conf = alpine_oauth2_list[i].param[OA2_Id].value;
- secret_conf = alpine_oauth2_list[i].param[OA2_Secret].value;
-
- for(j = 0; xoauth_default[j].name != NULL; j++)
- if(!strcmp(alpine_oauth2_list[i].name, xoauth_default[j].name))
- break;
-
- if(xoauth_default[j].name != NULL){
- id_def = xoauth_default[j].client_id;
- secret_def = xoauth_default[j].client_secret;
+ for(i = 0, p = 0; xoauth_default[i].name != NULL; i++){
+ /* always start with the default configuration */
+ for(k = 0, q = 0; lval && lval[k]; k++){
+ y = xoauth_parse_client_info(lval[k]);
+ if(same_xoauth2_info(xoauth_default[i], *y))
+ break;
+ free_xoauth2_info(&y);
}
-
- /* fix this: the purpose is to search for the name in lval */
- for(k = 0; lval && lval[k]; k++){
- xoauth_parse_client_info(lval[k], &name_lval, &id_lval, &secret_lval);
- if(name_lval && !strcmp(name_lval, alpine_oauth2_list[i].name))
- break;
- if (name_lval) fs_give((void **) &name_lval);
- if (id_lval) fs_give((void **) &id_lval);
- if (secret_lval) fs_give((void **) &secret_lval);
- }
-
- /* Here we have three values. The one being used by c-client in
- * id_conf, secret_conf. The default value in Alpine, obtained
- * by the programmer by registering Alpine, and the value
- * configured in Alpine by the user in id_lval, and secret_lval.
- *
- * The rules are:
- * 1. If id_lval && secret_lval are not null, we use those.
- * 2. else we use the default values.
- */
- id = id_lval ? id_lval : id_def;
- secret = secret_lval ? secret_lval : secret_def;
-
- new_confline(&ctmpa)->var = NULL;
- if(!first_line) first_line = ctmpa;
-
- /* Write Name of provider first */
- ctmpa->flags |= CF_NOSELECT;
- ctmpa->help = NO_HELP;
- ctmpa->valoffset = 1;
- ctmpa->value = cpystr(alpine_oauth2_list[i].name);
- ctmpa->varname = NULL;
- ctmpa->varnamep = ctmpb = ctmpa;
-
-
- /* Setup client-id variable */
- varlist[l]->name = cpystr(XOAUTH2_CLIENT_ID);
- varlist[l]->is_used = 1;
- varlist[l]->is_user = 1;
- varlist[l]->main_user_val.p = strcmp(id, id_def)? cpystr(id) : NULL;
- varlist[l]->global_val.p = cpystr(id_def);
- set_current_val(varlist[l], FALSE, FALSE);
-
- /* Write client-id variable */
- new_confline(&ctmpa)->var = varlist[l];
- utf8_snprintf(tmp, sizeof(tmp), " %-*.100w =", ln, XOAUTH2_CLIENT_ID);
- tmp[sizeof(tmp)-1] = '\0';
- ctmpa->varname = cpystr(tmp);
- ctmpa->varmem = l++;
- ctmpa->valoffset = ln + 3 + 3;
- ctmpa->value = pretty_value(ps, ctmpa);
- ctmpa->keymenu = &config_text_keymenu;
- ctmpa->help = h_config_xoauth2_client_id;
- ctmpa->tool = text_tool;
- ctmpa->varnamep = ctmpb;
-
- /* Set up client-secret variable */
- varlist[l]->name = cpystr(XOAUTH2_CLIENT_SECRET);
- varlist[l]->is_used = 1;
- varlist[l]->is_user = 1;
- varlist[l]->main_user_val.p = secret && secret_def && strcmp(secret, secret_def) ? cpystr(secret) : NULL;
- varlist[l]->global_val.p = secret_def ? cpystr(secret_def) : NULL;
- set_current_val(varlist[l], FALSE, FALSE);
-
- /* Write client-secret variable */
- if(secret){
- new_confline(&ctmpa)->var = varlist[l];
- utf8_snprintf(tmp, sizeof(tmp), " %-*.100w =", ln, XOAUTH2_CLIENT_SECRET);
- tmp[sizeof(tmp)-1] = '\0';
- ctmpa->varname = cpystr(tmp);
- ctmpa->varmem = l++;
- ctmpa->valoffset = ln + 3 + 3;
- ctmpa->value = pretty_value(ps, ctmpa);
- ctmpa->keymenu = &config_text_keymenu;
- ctmpa->help = h_config_xoauth2_client_secret;
- ctmpa->tool = text_tool;
- ctmpa->varnamep = ctmpb;
+ if(lval == NULL || lval[k] == NULL)
+ write_xoauth_conf_entry(&xoauth_default[i], &xoauth_default[i], &ctmpa, &ctmpb,
+ &first_line, &varlist, &p, ln, -i-1);
+ for(k = 0, q = 0; lval && lval[k]; k++){
+ y = xoauth_parse_client_info(lval[k]);
+ if(y && (!y->name || strcmp(y->name, xoauth_default[i].name))){
+ free_xoauth2_info(&y);
+ continue;
+ }
+ if(y->client_id == NULL)
+ y->client_id = cpystr(xoauth_default[i].client_id);
+ if(y->client_secret == NULL && xoauth_default[i].client_secret != NULL)
+ 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);
+ write_xoauth_conf_entry(y, &xoauth_default[i], &ctmpa, &ctmpb, &first_line, &varlist, &p, ln, k);
+ free_xoauth2_info(&y);
}
-
- /* Separate servers with a blank line */
- new_confline(&ctmpa);
- ctmpa->flags |= CF_NOSELECT | CF_B_LINE;
-
- /* clean up the house */
- if(id_lval) fs_give((void **) &id_lval);
- if(secret_lval) fs_give((void **) &secret_lval);
- if(name_lval) fs_give((void **) &name_lval);
}
vsave = save_config_vars(ps, expose_hidden_config);
@@ -379,6 +848,88 @@ alpine_xoauth2_configuration(struct pine *ps, int edit_exceptions)
write_pinerc(ps, ew, WRP_NONE);
break;
+ case 4: /* add a service */
+ {char service[MAILTMPLEN+1];
+ char prompt[MAILTMPLEN+1];
+ int flags = OE_DISALLOW_HELP;
+ strncpy(prompt, _("Enter service name: "), sizeof(prompt));
+ prompt[sizeof(prompt) - 1] = '\0';
+ service[0] = '\0';
+ if(optionally_enter(service,
+ -(ps_global->ttyo ? FOOTER_ROWS(ps_global) : 3),
+ 0, sizeof(service), prompt, NULL, NO_HELP, &flags) == 0){
+ for(i = 0; xoauth_default[i].name != NULL && strucmp(xoauth_default[i].name, service); i++);
+ if(xoauth_default[i].name == NULL)
+ q_status_message1(SM_ORDER, 3, 3, _("Service %s not known"), service);
+ else{
+ char **list;
+ ClearScreen();
+ ps_global->mangled_screen = 1;
+ for(j = 0; lval && lval[j]; j++);
+ list = fs_get((j+2)*sizeof(char *));
+ memset((void *)list, 0, (j+2)*sizeof(char *));
+ list[0] = xoauth_config_line(&xoauth_default[i]);
+ for(i = 0; lval && lval[i]; i++)
+ list[i+1] = cpystr(lval[i]);
+ if(lval) free_list_array(&lval);
+ *alval = lval = list;
+ for(i = 0; varlist && varlist[i]; i++){
+ free_variable_values(varlist[i]);
+ if(varlist[i]->descrip) fs_give((void **) &varlist[i]->descrip);
+ if(varlist[i]->dname) fs_give((void **) &varlist[i]->dname);
+ fs_give((void **) &varlist[i]);
+ }
+ if(varlist) fs_give((void **) varlist);
+ }
+ }
+ }
+ break;
+
+ case 5: /* delete a service */
+ { int m, key;
+ XOAUTH2_INFO_S *x;
+ char question[MAILTMPLEN];
+
+ for(i = 0, m = 1, j = 0; varlist[i] && m < pos;)
+ if(!varlist[i]->is_list){
+ i++; m++;
+ } else {
+ if(varlist[i]->current_val.l[j++]) m++;
+ else{
+ j = 0; m += 2; i++;
+ }
+ }
+ key = atoi(varlist[i]->dname); /* this hack avoids we rebuild varlist again */
+ if(key >= 0){
+ x = xoauth_parse_client_info(lval[key]);
+ snprintf(question, sizeof(question), _("Delete this configuration for %s "), x->name);
+ free_xoauth2_info(&x);
+ if(want_to(question, 'n', 'n', NO_HELP, WT_NORM) != 'y')
+ break;
+ for(i = key; lval && lval[i] && lval[i+1]; i++){
+ fs_give((void **) &lval[i]);
+ lval[i] = cpystr(lval[i+1]);
+ }
+ fs_give((void **) &lval[i]);
+ }
+ else {
+ q_status_message(SM_ORDER, 3, 3, _("Cannot delete default configuration"));
+ break;
+ }
+ if(lval && lval[0] == NULL)
+ free_list_array(&lval);
+ *alval = lval;
+ pos = 1; /* reset at the top */
+ for(i = 0; varlist && varlist[i]; i++){
+ free_variable_values(varlist[i]);
+ if(varlist[i]->descrip) fs_give((void **) &varlist[i]->descrip);
+ if(varlist[i]->dname) fs_give((void **) &varlist[i]->dname);
+ fs_give((void **) &varlist[i]);
+ }
+ if(varlist) fs_give((void **) varlist);
+ }
+ break;
+
case 10:
revert_to_saved_config(ps, vsave, expose_hidden_config);
if(prc)
@@ -392,8 +943,15 @@ alpine_xoauth2_configuration(struct pine *ps, int edit_exceptions)
}
} while (pos >= 0);
+ for(i = 0; varlist && varlist[i]; i++){
+ free_variable_values(varlist[i]);
+ if(varlist[i]->descrip) fs_give((void **) &varlist[i]->descrip);
+ if(varlist[i]->dname) fs_give((void **) &varlist[i]->dname);
+ fs_give((void **) &varlist[i]);
+ }
+ if(varlist) fs_give((void **) varlist);
+
#ifdef _WINDOWS
mswin_set_quit_confirm (F_OFF(F_QUIT_WO_CONFIRM, ps_global));
#endif
}
-
diff --git a/alpine/xoauth2conf.h b/alpine/xoauth2conf.h
index c1de413..41a5645 100644
--- a/alpine/xoauth2conf.h
+++ b/alpine/xoauth2conf.h
@@ -16,12 +16,14 @@
#define XOAUTH2_CONFIG
#include "confscroll.h"
+#include "xoauth2.h"
#include "../pith/state.h"
/* exported prototypes */
void alpine_xoauth2_configuration(struct pine *, int);
-void xoauth_parse_client_info(char *, char **, char **, char **);
-void oauth2_get_client_info(unsigned char *, char **, char **);
-char *xoauth_config_line(char *, char *, char *);
+XOAUTH2_INFO_S *xoauth_parse_client_info(char *);
+XOAUTH2_INFO_S *oauth2_get_client_info(unsigned char *, char *);
+char *xoauth_config_line(XOAUTH2_INFO_S *);
+void write_xoauth_conf_entry(XOAUTH2_INFO_S *, XOAUTH2_INFO_S *, CONF_S **, CONF_S **, CONF_S **, struct variable ***, int *, int, int);
#endif /* XOAUTH2_CONFIG */