2 * ========================================================================
3 * Copyright 2006-2008 University of Washington
4 * Copyright 2013-2022 Eduardo Chappa
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
16 #include "xoauth2conf.h"
19 #include "confscroll.h"
21 #include "../pith/state.h"
22 #include "../pith/conf.h"
23 #include "../pith/list.h"
24 #include "../pith/mailcmd.h"
25 #include "xoauth2info.c"
27 typedef enum {Xname
= 0, Xid
, Xsecret
, Xtenant
, Xuser
, XFlow
, Xend
} XTYPES
;
29 typedef struct xoauh2_info_val_s
{
34 /* the order here must match the order in XTYPES above */
35 XOAUTH2_INFO_VAL_S x_default
[] = {
37 {XOAUTH2_CLIENT_ID
, XID
},
38 {XOAUTH2_CLIENT_SECRET
, XSECRET
},
39 {XOAUTH2_TENANT
, XTENANT
},
40 {XOAUTH2_USERS
, XUSER
},
41 {XOAUTH2_FLOW
, XFLOW
},
45 char *list_to_array(char **);
46 char **array_to_list(char *);
47 void write_xoauth_configuration(struct variable
*, struct variable
**, EditWhich
);
48 char **xoauth2_conf_dedup_and_merge(char ***);
49 XOAUTH2_INFO_S
*xoauth_info_choice(XOAUTH2_INFO_S
**, char *);
50 int xoauth2_info_tool(struct pine
*, int, CONF_S
**, unsigned int);
51 char *xoauth2_extra_text(XOAUTH2_INFO_S
**, int);
52 XOAUTH2_INFO_S
**xoauth2_configured_servers(void);
53 XOAUTH2_INFO_S
**parse_xoauth2_info_list(char **lval
, int *totalp
);
56 list_to_array(char **list
)
62 if(list
== NULL
|| *list
== NULL
) return NULL
;
64 for(i
= 0, n
= 0; list
[i
] != NULL
; i
++)
65 n
+= strlen(list
[i
]) + 1;
67 rv
= fs_get(n
*sizeof(char));
69 for(i
= 0; list
[i
] != NULL
; i
++){
71 if(list
[i
+1] != NULL
) strcat(rv
, ",");
77 char **array_to_list(char *array
)
82 if(array
== NULL
|| *array
== '\0') return NULL
;
84 for(u
= array
, i
= 0; u
&& *u
; u
++)
87 return parse_list(array
, i
+1, 0,NULL
);
91 xoauth_config_line(XOAUTH2_INFO_S
*x
)
96 if(x
== NULL
) return NULL
;
98 n
= strlen(XNAME
) + strlen((char *) x
->name
) + strlen(XID
) + strlen(x
->client_id
)
99 + strlen(x
->client_secret
? XSECRET
: "") + strlen(x
->client_secret
? x
->client_secret
: "")
100 + strlen(x
->tenant
? XTENANT
: "") + strlen(x
->tenant
? x
->tenant
: "")
101 + strlen(XUSER
) + strlen(x
->users
? x
->users
: "")
102 + strlen(XFLOW
) + strlen(x
->flow
? x
->flow
: "")
103 + 2 + 3 + (x
->client_secret
? 3 : 0) + (x
->tenant
? 3 : 0)
104 + 3 + (x
->flow
? 3 : 0) + 1;
105 rv
= fs_get(n
*sizeof(char));
106 sprintf(rv
, "%s\"%s\" %s\"%s\"", XNAME
, x
->name
, XID
, x
->client_id
);
108 sprintf(rv
+ strlen(rv
), " %s\"%s\"", XSECRET
, x
->client_secret
);
110 sprintf(rv
+ strlen(rv
), " %s\"%s\"", XTENANT
, x
->tenant
);
111 sprintf(rv
+ strlen(rv
), " %s\"%s\"", XUSER
, x
->users
? x
->users
: "");
113 sprintf(rv
+ strlen(rv
), " %s\"%s\"", XFLOW
, x
->flow
? x
->flow
: "");
118 xoauth2_info_tool(struct pine
*ps
, int cmd
, CONF_S
**cl
, unsigned int flags
)
124 *((*cl
)->d
.x
.selected
) = (*cl
)->d
.x
.pat
;
125 rv
= simple_exit_cmd(flags
);
128 rv
= simple_exit_cmd(flags
);
136 ps
->mangled_body
= 1;
142 xoauth2_extra_text(XOAUTH2_INFO_S
**xinfo
, int i
)
152 for(j
= 0; xinfo
[j
] != NULL
; j
++);
153 if(i
< 0 || i
>= j
) return NULL
;
157 for(methodcount
= 1, j
= 0; xinfo
[j
] != NULL
; j
++)
158 if(j
!= i
&& xinfo
[j
]->flow
&& !strucmp(xinfo
[j
]->flow
, x
->flow
))
160 if(methodcount
== 1) return cpystr(x
->flow
);
163 /* we either do not have flow, or have more than one flow, use user */
165 char **lval
= array_to_list(xinfo
[i
]->users
);
166 if(lval
&& lval
[0]){ /* use the first one */
167 rv
= cpystr(lval
[0]);
168 free_list_array(&lval
);
172 if(rv
== NULL
) rv
= cpystr(_("client-id unused"));
177 xoauth_info_choice(XOAUTH2_INFO_S
**xinfo
, char *user
)
182 dprint((9, "xoauth_info_choice()"));
184 for(i
= 0; xinfo
&& xinfo
[i
]; i
++);
185 if(i
== 0) return NULL
;
187 if(strucmp((char *) xinfo
[0]->name
, (char *) GMAIL_NAME
) == 0){
188 for(i
= 0; xinfo
&& xinfo
[i
] && strcmp(xinfo
[i
]->client_id
, (char *) GMAIL_ID
) != 0; i
++);
189 if(!xinfo
|| xinfo
[i
] != NULL
){
193 for(j
= 0; xinfo
[j
] != NULL
; j
++){
198 x
= xinfo
[j
] ? copy_xoauth2_info(xinfo
[j
]) : NULL
;
199 free_xoauth2_info(&xinfo
[j
- offset
]);
200 xinfo
[j
- offset
] = x
;
202 xinfo
[j
- offset
] = NULL
;
203 for(i
= 0; xinfo
&& xinfo
[i
]; i
++);
207 if(i
== 1) return copy_xoauth2_info(xinfo
[0]);
209 if(!ps_global
->ttyo
){
214 for(i
= n
= 0; xinfo
[i
] != NULL
; i
++)
215 n
+= strlen(xinfo
[i
]->client_id
) + strlen(xinfo
[i
]->flow
? xinfo
[i
]->flow
: "")
216 + strlen(xinfo
[i
]->users
? xinfo
[i
]->users
: "") + 8; /* number, parenthesis, space */
217 n
+= strlen((char *) xinfo
[0]->name
) + strlen(user
);
218 n
+= 1024; /* large enough to display lines of 80 characters in UTF-8 */
219 s
= fs_get(n
*sizeof(char));
220 sprintf(s
, _("Alpine cannot determine which client-id to use for the username <%s> for your %s account. "), user
, xinfo
[0]->name
);
221 sprintf(s
+ strlen(s
), _("Please select the client-id to use from the following list.\n\n"));
222 for(i
= 0; xinfo
[i
]; i
++){
223 extra
= xoauth2_extra_text(xinfo
, i
);
224 sprintf(s
+ strlen(s
), " %d) %.70s%s%s\n", i
+1, xinfo
[i
]->client_id
,
225 extra
? " - " : "", extra
? extra
: "");
226 if(extra
) fs_give((void **) &extra
);
228 sprintf(s
+ strlen(s
), "%s", "\n\n");
230 display_init_err(s
, 0);
232 strncpy(prompt
, _("Enter your selection number: "), sizeof(prompt
));
233 prompt
[sizeof(prompt
)-1] = '\0';
236 rv
= optionally_enter(reply
, 0, 0, sizeof(reply
), prompt
, NULL
, NO_HELP
, 0);
237 sel
= atoi(reply
) - 1;
238 rv
= (sel
>= 0 && sel
< i
) ? 0 : -1;
240 return copy_xoauth2_info(xinfo
[sel
]);
243 CONF_S
*ctmp
= NULL
, *first_line
= NULL
;
244 XOAUTH2_INFO_S
*x_sel
= NULL
;
248 ps_global
->next_screen
= SCREEN_FUN_NULL
;
250 memset(&screen
, 0, sizeof(screen
));
252 for(i
= 0; i
< sizeof(tmp
) && i
< ps_global
->ttyo
->screen_cols
; i
++)
257 ctmp
->flags
|= CF_NOSELECT
;
258 ctmp
->value
= cpystr(tmp
);
261 ctmp
->flags
|= CF_NOSELECT
;
262 ctmp
->value
= cpystr(_("Select a Client-ID to use with this account"));
265 ctmp
->flags
|= CF_NOSELECT
;
266 ctmp
->value
= cpystr(tmp
);
269 ctmp
->flags
|= CF_NOSELECT
| CF_B_LINE
;
271 sprintf(tmp
, _("Alpine cannot determine which client-id to use for the username <%s>"), user
);
273 ctmp
->flags
|= CF_NOSELECT
;
274 ctmp
->value
= cpystr(tmp
);
276 sprintf(tmp
, _("for your %s account. Please select the client-id to use from the following list.\n\n"), xinfo
[0]->name
);
278 ctmp
->flags
|= CF_NOSELECT
;
279 ctmp
->value
= cpystr(tmp
);
281 for(i
= 0; xinfo
[i
] != NULL
; i
++){
283 ctmp
->flags
|= CF_NOSELECT
| CF_B_LINE
;
285 if((extra
= xoauth2_extra_text(xinfo
, i
)) != NULL
){
287 ctmp
->flags
|= CF_NOSELECT
;
288 ctmp
->value
= cpystr(extra
);
296 ctmp
->value
= cpystr(xinfo
[i
]->client_id
);
297 ctmp
->d
.x
.selected
= &x_sel
;
298 ctmp
->d
.x
.pat
= copy_xoauth2_info(xinfo
[i
]);
299 ctmp
->keymenu
= &xoauth2_id_select_km
;
300 ctmp
->help
= NO_HELP
;
301 ctmp
->help_title
= NULL
;
302 ctmp
->tool
= xoauth2_info_tool
;
303 ctmp
->flags
= CF_STARTITEM
;
304 ctmp
->valoffset
= 4 + (extra
? 3 : 0);
305 if(extra
) fs_give((void **) &extra
);
307 (void)conf_scroll_screen(ps_global
, &screen
, first_line
, _("SELECT CLIENT_ID"),
308 _("xoauth2"), 0, NULL
);
315 parse_xoauth2_info_list(char **lval
, int *totalp
)
318 XOAUTH2_INFO_S
**rv
= NULL
;
320 for(total
= 0; lval
&& lval
[total
]; total
++);
322 rv
= fs_get((total
+ 1)*sizeof(XOAUTH2_INFO_S
*));
323 for(i
= 0; i
< total
; i
++)
324 rv
[i
] = xoauth_parse_client_info(lval
[i
]);
333 xoauth2_configured_servers(void)
335 XOAUTH2_INFO_S
**cv
, **muv
, **rv
= NULL
;
336 int cvt
, muvt
, rvt
, i
, j
, total
= 0;
338 cv
= parse_xoauth2_info_list(ps_global
->vars
[V_XOAUTH2_INFO
].current_val
.l
, &cvt
);
339 muv
= parse_xoauth2_info_list(ps_global
->vars
[V_XOAUTH2_INFO
].main_user_val
.l
, &muvt
);
343 rv
= fs_get((rvt
+ 1)*sizeof(XOAUTH2_INFO_S
*));
344 memset((void *) rv
, 0, (rvt
+ 1)*sizeof(XOAUTH2_INFO_S
*));
346 for(i
= 0; cv
&& cv
[i
]; i
++){
347 for(j
= 0; rv
[j
] && !same_xoauth2_info(*cv
[i
], *rv
[j
]); j
++);
348 if(!rv
[j
]) rv
[total
++] = copy_xoauth2_info(cv
[i
]);
350 free_xoauth2_info_list(&cv
);
352 for(i
= 0; muv
&& muv
[i
]; i
++){
353 for(j
= 0; rv
[j
] && !same_xoauth2_info(*muv
[i
], *rv
[j
]); j
++);
354 if(!rv
[j
]) rv
[total
++] = copy_xoauth2_info(muv
[i
]);
356 free_xoauth2_info_list(&muv
);
361 /* Get the client-id, etc. for server "name" associated to user "user" */
363 oauth2_get_client_info(unsigned char *name
, char *user
)
365 int i
, j
, matches
, len
;
366 XOAUTH2_INFO_S
*x
, **xinfo
, **lval
;
368 if(name
== NULL
|| *name
== '\0' || user
== NULL
|| *user
== '\0')
372 /* first count how many servers */
373 lval
= xoauth2_configured_servers();
374 for(i
= 0; lval
&& lval
[i
]; i
++){
376 if(x
&& x
->name
&& name
&& !strcmp((char *) x
->name
, (char *) name
))
380 /* if nothing, use the default value */
381 for(i
= 0; xoauth_default
[i
].name
!= NULL
&& strcmp((char *) xoauth_default
[i
].name
, (char *) name
); i
++);
382 if(xoauth_default
[i
].name
) matches
++;
385 free_xoauth2_info_list(&lval
);
386 return matches
== 1 ? copy_xoauth2_info(&xoauth_default
[i
]) : NULL
;
389 /* more than one match, see if it is a duplicate client-id entry */
390 xinfo
= fs_get((matches
+ 1)*sizeof(XOAUTH2_INFO_S
*));
391 memset((void *)xinfo
, 0, (matches
+ 1)*sizeof(XOAUTH2_INFO_S
*));
392 matches
= 0; /* restart the recount, it might go lower! */
393 for(i
= 0; lval
&& lval
[i
]; i
++){
395 if(x
&& x
->name
&& name
&& !strcmp((char *) x
->name
, (char *) name
)){
396 for(j
= 0; xinfo
&& xinfo
[j
] && !same_xoauth2_info(*x
, *xinfo
[j
]); j
++);
397 if(!xinfo
[j
]) xinfo
[matches
++] = copy_xoauth2_info(x
);
400 for(i
= 0; xoauth_default
[i
].name
!= NULL
&& strcmp((char *) xoauth_default
[i
].name
, (char *) name
); i
++);
401 for(j
= 0; xinfo
&& xinfo
[j
] && !same_xoauth2_info(xoauth_default
[i
], *xinfo
[j
]); j
++);
402 if(!xinfo
[j
]) xinfo
[matches
++] = copy_xoauth2_info(&xoauth_default
[i
]);
404 /* if after removing the duplicate entries, we only have one, use it */
406 x
= copy_xoauth2_info(xinfo
[0]);
407 free_xoauth2_info_list(&lval
);
408 free_xoauth2_info_list(&xinfo
);
412 x
= NULL
; /* reset x to null so it will not be double freed */
413 /* we have more than one match, now check if any of them matches the given user */
415 for(i
= 0; xinfo
&& xinfo
[i
]; i
++){
416 char **alval
= array_to_list(xinfo
[i
]->users
);
417 for(j
= 0; alval
&& alval
[j
] && strucmp(alval
[j
], user
); j
++);
418 if(alval
&& alval
[j
]){
420 free_xoauth2_info(&x
);
421 x
= copy_xoauth2_info(xinfo
[i
]);
423 if(alval
) free_list_array(&alval
);
426 /* only one server matches the username */
428 free_xoauth2_info_list(&xinfo
);
429 free_xoauth2_info_list(&lval
);
433 free_xoauth2_info(&x
);
435 /* We either have no matches, or have more than one match!
436 * in either case, let the user pick what they want */
437 x
= xoauth_info_choice(xinfo
, user
);
438 free_xoauth2_info_list(&xinfo
);
439 free_xoauth2_info_list(&lval
);
441 /* Once the user chose a client-id, save it so we do not ask again */
443 int n
= x
->users
? strlen(x
->users
) + 1 : 0;
444 char ***alval
, **lvalp
;
446 fs_resize((void **) &x
->users
, (n
+ strlen(user
) + 1)*sizeof(char));
447 x
->users
[n
> 0 ? n
- 1 : 0] = '\0';
448 if(n
> 0) strcat(x
->users
, ",");
449 strcat(x
->users
, user
);
450 alval
= ALVAL(&ps_global
->vars
[V_XOAUTH2_INFO
], Main
);
453 for(n
= 0; lvalp
&& lvalp
[n
]; n
++);
454 fs_resize((void **) &lvalp
, (n
+2)*sizeof(char *));
455 lvalp
[n
] = xoauth_config_line(x
);
457 *alval
= xoauth2_conf_dedup_and_merge(&lvalp
);
458 set_current_val(&ps_global
->vars
[V_XOAUTH2_INFO
], FALSE
, FALSE
);
459 write_pinerc(ps_global
, Main
, WRP_NONE
);
466 * Each vlist member is of type "p", while "v" is of type "l", so we
467 * each entry in "l" by using each of the "p" entries.
470 write_xoauth_configuration(struct variable
*v
, struct variable
**vlist
, EditWhich ew
)
473 XOAUTH2_INFO_S
*x
= NULL
;
474 char ***alval
, **lval
, **l
;
477 for (i
= 0, n
= 0; vlist
[i
] != NULL
; i
++) /* count number of lines we need */
478 if(!strcmp(vlist
[i
]->name
, XOAUTH2_USERS
))
480 lval
= fs_get((n
+1)*sizeof(char *));
481 memset((void *) lval
, 0, (n
+1)*sizeof(char *));
484 alval
= ALVAL(v
, ew
);
485 for (i
= 0, k
= 0; vlist
[i
] != NULL
; i
++){
487 x
= new_xoauth2_info();
488 x
->name
= (unsigned char *) cpystr(vlist
[i
]->descrip
); /* hack! but makes life so much easier! */
489 for(m
= 0; xoauth_default
[m
].name
!= NULL
490 && strcmp((char *) xoauth_default
[m
].name
, (char *) x
->name
); m
++);
492 if (x
->client_id
== NULL
&& !strcmp(vlist
[i
]->name
, XOAUTH2_CLIENT_ID
)){
493 p
= PVAL(vlist
[i
], ew
);
494 if (p
== NULL
) p
= vlist
[i
]->current_val
.p
;
496 x
->client_id
= cpystr(p
);
499 if (x
->client_secret
== NULL
501 && xoauth_default
[m
].client_secret
502 && !strcmp(vlist
[i
]->name
, XOAUTH2_CLIENT_SECRET
)){
503 p
= PVAL(vlist
[i
], ew
);
504 if (p
== NULL
) p
= vlist
[i
]->current_val
.p
;
506 x
->client_secret
= cpystr(p
);
509 if (x
->tenant
== NULL
511 && xoauth_default
[m
].tenant
512 && !strcmp(vlist
[i
]->name
, XOAUTH2_TENANT
)){
513 p
= PVAL(vlist
[i
], ew
);
514 if (p
== NULL
) p
= vlist
[i
]->current_val
.p
;
516 x
->tenant
= cpystr(p
);
519 if (x
->flow
== NULL
&& !strcmp(vlist
[i
]->name
, XOAUTH2_FLOW
)){
520 p
= PVAL(vlist
[i
], ew
);
521 if (p
== NULL
) p
= vlist
[i
]->current_val
.p
;
526 if (x
->users
== NULL
&& !strcmp(vlist
[i
]->name
, XOAUTH2_USERS
)){
527 l
= LVAL(vlist
[i
], ew
);
528 x
->users
= list_to_array(l
);
530 /* don't let it get to here until we are done! */
531 lval
[k
++] = xoauth_config_line(x
);
532 /* get ready for next run */
533 free_xoauth2_info(&x
);
538 if(*alval
) free_list_array(alval
);
543 set_current_val(&ps_global
->vars
[V_XOAUTH2_INFO
], FALSE
, FALSE
);
547 /* parse line of the form
548 /NAME="text" /ID="text" /TENANT="text" /SECRET="text" /USER="text"
551 xoauth_parse_client_info(char *lvalp
)
556 if (lvalp
== NULL
) return NULL
;
558 x
= new_xoauth2_info();
559 if((s
= strstr(lvalp
, XNAME
)) != NULL
){
562 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
565 if (*s
) x
->name
= (unsigned char *) cpystr(s
);
567 } else x
->name
= NULL
;
569 if((s
= strstr(lvalp
, XID
)) != NULL
){
572 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
575 if (*s
) x
->client_id
= cpystr(s
);
577 } else x
->client_id
= NULL
;
579 if((s
= strstr(lvalp
, XTENANT
)) != NULL
){
580 s
+= strlen(XTENANT
);
582 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
585 if (*s
) x
->tenant
= cpystr(s
);
587 } else x
->tenant
= NULL
;
589 if((s
= strstr(lvalp
, XSECRET
)) != NULL
){
590 s
+= strlen(XSECRET
);
592 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
595 if (*s
) x
->client_secret
= cpystr(s
);
597 } else x
->client_secret
= NULL
;
599 if((s
= strstr(lvalp
, XFLOW
)) != NULL
){
602 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
605 if(*s
) x
->flow
= cpystr(s
);
607 } else x
->flow
= NULL
;
609 if((s
= strstr(lvalp
, XUSER
)) != NULL
){
612 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
615 if(*s
) x
->users
= cpystr(s
);
617 } else x
->users
= NULL
;
623 xoauth2_conf_dedup_and_merge(char ***alval
)
627 XOAUTH2_INFO_S
*x
, *y
;
629 if(alval
== NULL
|| *alval
== NULL
|| **alval
== NULL
)
633 for(i
= 0; lval
[i
] != NULL
; i
++); /* count how many entries */
635 rv
= fs_get((i
+1)*sizeof(char *));
636 memset((void *)rv
, 0, (i
+1)*sizeof(char *));
638 for (i
= 0; lval
[i
] != NULL
; i
++){
639 x
= xoauth_parse_client_info(lval
[i
]);
640 for (j
= 0; rv
[j
] != NULL
; j
++){
641 y
= xoauth_parse_client_info(rv
[j
]);
642 /* check if this is the same data. If so, merge the users into one and discard the old data */
643 if(same_xoauth2_info(*x
, *y
)){
644 char **l1
, **l2
, **l3
;
646 /* merge user1 with user2, save in x->users */
647 l1
= array_to_list(x
->users
);
648 l2
= array_to_list(y
->users
);
650 for(n
= 0; l1
&& l1
[n
]; n
++);
651 for(m
= 0; l2
&& l2
[m
]; m
++, n
++);
652 l3
= fs_get((n
+1)*sizeof(char*));
653 memset((void *) l3
, 0, (n
+1)*sizeof(char *));
655 for(l
= 0, n
= 0; l1
&& l1
[l
]; l
++){
656 for(k
= 0; l1
&& l1
[j
] && l3
[k
] && strucmp(l1
[l
], l3
[k
]); k
++);
657 if(l3
[k
] == NULL
&& l1
&& l1
[l
] != NULL
)
658 l3
[n
++] = cpystr(l1
[l
]);
660 for(l
= 0; l2
&& l2
[l
]; l
++){
661 for(k
= 0; l2
&& l2
[l
] && l3
[k
] && strucmp(l2
[l
], l3
[k
]); k
++);
662 if(l3
[k
] == NULL
&& l2
&& l2
[l
] != NULL
)
663 l3
[n
++] = cpystr(l2
[l
]);
666 if(x
->users
) fs_give((void **) &x
->users
);
667 x
->users
= list_to_array(l3
);
668 fs_give((void **) &rv
[j
]);
669 rv
[j
] = xoauth_config_line(x
);
671 if(l1
) free_list_array(&l1
);
672 if(l2
) free_list_array(&l2
);
673 if(l3
) free_list_array(&l3
);
674 free_xoauth2_info(&y
);
677 free_xoauth2_info(&y
);
679 if(rv
[j
] == NULL
) rv
[j
] = cpystr(lval
[i
]);
685 * X = new value, Y = default configuration
688 write_xoauth_conf_entry(XOAUTH2_INFO_S
*x
, XOAUTH2_INFO_S
*y
, CONF_S
**cl
, CONF_S
**clb
, CONF_S
**fline
,
689 struct variable
***varlistp
, int *pp
, int ln
, int key
)
691 CONF_S
*ctmpb
= *clb
;
692 struct variable
**varlist
;
694 char tmp
[1024], tmp2
[16];
696 sprintf(tmp2
, "%d", key
);
699 new_confline(cl
)->var
= NULL
;
700 if(fline
&& !*fline
) *fline
= *cl
;
701 (*cl
)->flags
|= CF_NOSELECT
;
702 (*cl
)->help
= NO_HELP
;
703 (*cl
)->valoffset
= 1;
704 (*cl
)->value
= cpystr((char *) x
->name
);
705 (*cl
)->varname
= NULL
;
706 (*cl
)->varnamep
= ctmpb
= *cl
;
708 /* Setup client-id variable */
709 varlist
[p
] = fs_get(sizeof(struct variable
));
710 memset((void *) varlist
[p
], 0, sizeof(struct variable
));
711 varlist
[p
]->name
= cpystr(XOAUTH2_CLIENT_ID
);
712 varlist
[p
]->is_used
= 1;
713 varlist
[p
]->is_user
= 1;
714 varlist
[p
]->main_user_val
.p
= x
->client_id
&& y
->client_id
715 && strcmp(x
->client_id
, y
->client_id
) ? cpystr(x
->client_id
) : NULL
;
716 varlist
[p
]->global_val
.p
= y
->client_id
? cpystr(y
->client_id
) : NULL
;
717 varlist
[p
]->dname
= cpystr(tmp2
); /* hack, but makes life easier! */
718 varlist
[p
]->descrip
= cpystr((char *) x
->name
); /* hack, but makes life easier! */
719 set_current_val(varlist
[p
], FALSE
, FALSE
);
721 /* Write client-id variable */
722 new_confline(cl
)->var
= varlist
[p
];
723 utf8_snprintf(tmp
, sizeof(tmp
), " %-*.100w =", ln
, XOAUTH2_CLIENT_ID
);
724 tmp
[sizeof(tmp
)-1] = '\0';
725 (*cl
)->varname
= cpystr(tmp
);
727 (*cl
)->valoffset
= ln
+ 3 + 3;
728 (*cl
)->value
= pretty_value(ps_global
, *cl
);
729 (*cl
)->keymenu
= &config_xoauth2_text_keymenu
;
730 (*cl
)->help
= h_config_xoauth2_client_id
;
731 (*cl
)->tool
= text_tool
;
732 (*cl
)->varnamep
= ctmpb
;
734 /* Set up client-secret variable */
735 if(x
->client_secret
){
736 varlist
[p
] = fs_get(sizeof(struct variable
));
737 memset((void *) varlist
[p
], 0, sizeof(struct variable
));
738 varlist
[p
]->name
= cpystr(XOAUTH2_CLIENT_SECRET
);
739 varlist
[p
]->is_used
= 1;
740 varlist
[p
]->is_user
= 1;
741 varlist
[p
]->main_user_val
.p
= y
->client_secret
742 && strcmp(x
->client_secret
, y
->client_secret
)
743 ? cpystr(x
->client_secret
) : NULL
;
744 varlist
[p
]->global_val
.p
= y
->client_secret
? cpystr(y
->client_secret
) : NULL
;
745 varlist
[p
]->dname
= cpystr(tmp2
); /* hack, but makes life easier! */
746 varlist
[p
]->descrip
= cpystr((char *) x
->name
); /* hack, but makes life easier! */
747 set_current_val(varlist
[p
], FALSE
, FALSE
);
749 /* Write client-secret variable */
750 new_confline(cl
)->var
= varlist
[p
];
751 utf8_snprintf(tmp
, sizeof(tmp
), " %-*.100w =", ln
, XOAUTH2_CLIENT_SECRET
);
752 tmp
[sizeof(tmp
)-1] = '\0';
753 (*cl
)->varname
= cpystr(tmp
);
755 (*cl
)->valoffset
= ln
+ 3 + 3;
756 (*cl
)->value
= pretty_value(ps_global
, *cl
);
757 (*cl
)->keymenu
= &config_xoauth2_text_keymenu
;
758 (*cl
)->help
= h_config_xoauth2_client_secret
;
759 (*cl
)->tool
= text_tool
;
760 (*cl
)->varnamep
= ctmpb
;
763 /* Set up tenant variable */
765 varlist
[p
] = fs_get(sizeof(struct variable
));
766 memset((void *) varlist
[p
], 0, sizeof(struct variable
));
767 varlist
[p
]->name
= cpystr(XOAUTH2_TENANT
);
768 varlist
[p
]->is_used
= 1;
769 varlist
[p
]->is_user
= 1;
770 varlist
[p
]->main_user_val
.p
= y
->tenant
&& strcmp(x
->tenant
, y
->tenant
)
771 ? cpystr(x
->tenant
) : NULL
;
772 varlist
[p
]->global_val
.p
= y
->tenant
? cpystr(y
->tenant
) : NULL
;
773 varlist
[p
]->dname
= cpystr(tmp2
); /* hack, but makes life easier! */
774 varlist
[p
]->descrip
= cpystr((char *) x
->name
); /* hack, but makes life easier! */
775 set_current_val(varlist
[p
], FALSE
, FALSE
);
777 /* Write client-secret variable */
778 new_confline(cl
)->var
= varlist
[p
];
779 utf8_snprintf(tmp
, sizeof(tmp
), " %-*.100w =", ln
, XOAUTH2_TENANT
);
780 tmp
[sizeof(tmp
)-1] = '\0';
781 (*cl
)->varname
= cpystr(tmp
);
783 (*cl
)->valoffset
= ln
+ 3 + 3;
784 (*cl
)->value
= pretty_value(ps_global
, *cl
);
785 (*cl
)->keymenu
= &config_xoauth2_text_keymenu
;
786 (*cl
)->help
= h_config_xoauth2_tenant
;
787 (*cl
)->tool
= text_tool
;
788 (*cl
)->varnamep
= ctmpb
;
791 /* Set up flow variable */
793 varlist
[p
] = fs_get(sizeof(struct variable
));
794 memset((void *) varlist
[p
], 0, sizeof(struct variable
));
795 varlist
[p
]->name
= cpystr(XOAUTH2_FLOW
);
796 varlist
[p
]->is_used
= 1;
797 varlist
[p
]->is_user
= 1;
798 varlist
[p
]->main_user_val
.p
= cpystr(x
->flow
);
799 varlist
[p
]->global_val
.p
= cpystr(x
->flow
);
800 varlist
[p
]->dname
= cpystr(tmp2
); /* hack, but makes life easier! */
801 varlist
[p
]->descrip
= cpystr((char *) x
->name
); /* hack, but makes life easier! */
802 set_current_val(varlist
[p
], FALSE
, FALSE
);
804 /* Write client-secret variable */
805 new_confline(cl
)->var
= varlist
[p
];
806 utf8_snprintf(tmp
, sizeof(tmp
), " %-*.100w =", ln
, XOAUTH2_FLOW
);
807 tmp
[sizeof(tmp
)-1] = '\0';
808 (*cl
)->varname
= cpystr(tmp
);
810 (*cl
)->valoffset
= ln
+ 3 + 3;
811 (*cl
)->value
= pretty_value(ps_global
, *cl
);
812 (*cl
)->keymenu
= &config_xoauth2_text_keymenu
;
813 (*cl
)->help
= h_config_xoauth2_flow
;
814 (*cl
)->tool
= text_tool
;
815 (*cl
)->varnamep
= ctmpb
;
818 /* Setup users variable */
819 varlist
[p
] = fs_get(sizeof(struct variable
));
820 memset((void *) varlist
[p
], 0, sizeof(struct variable
));
821 varlist
[p
]->name
= cpystr(XOAUTH2_USERS
);
822 varlist
[p
]->is_used
= 1;
823 varlist
[p
]->is_user
= 1;
824 varlist
[p
]->is_list
= 1;
825 varlist
[p
]->main_user_val
.l
= x
->users
? array_to_list(x
->users
) : NULL
;
826 varlist
[p
]->dname
= cpystr(tmp2
); /* hack, but makes life easier! */
827 varlist
[p
]->descrip
= cpystr((char *) x
->name
); /* hack, but makes life easier! */
828 set_current_val(varlist
[p
], FALSE
, FALSE
);
830 /* Write user variable */
831 new_confline(cl
)->var
= varlist
[p
];
832 utf8_snprintf(tmp
, sizeof(tmp
), " %-*.100w =", ln
, XOAUTH2_USERS
);
833 tmp
[sizeof(tmp
)-1] = '\0';
834 (*cl
)->varname
= cpystr(tmp
);
835 (*cl
)->valoffset
= ln
+ 3 + 3;
836 (*cl
)->keymenu
= &config_xoauth2_wshuf_keymenu
;
837 (*cl
)->help
= h_config_xoauth2_username
;
840 for(z
= 0; varlist
[p
]->main_user_val
.l
[z
]; z
++){
841 if(z
) new_confline(cl
);
842 (*cl
)->var
= varlist
[p
];
844 (*cl
)->valoffset
= ln
+ 3 + 3;
845 (*cl
)->value
= pretty_value(ps_global
, *cl
);
846 (*cl
)->keymenu
= &config_xoauth2_wshuf_keymenu
;
847 (*cl
)->tool
= text_tool
;
848 (*cl
)->varnamep
= ctmpb
= *cl
;
853 (*cl
)->value
= pretty_value(ps_global
, *cl
);
854 (*cl
)->keymenu
= &config_xoauth2_wshuf_keymenu
;
855 (*cl
)->tool
= text_tool
;
856 (*cl
)->varnamep
= ctmpb
= *cl
;
863 /* Separate servers with a blank line */
865 (*cl
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
868 /*----------------------------------------------------------------------
869 Screen to add client_id and client_secret for a service
873 alpine_xoauth2_configuration(struct pine
*ps
, int edit_exceptions
)
875 struct variable
**varlist
= NULL
;
876 char **lval
, ***alval
;
877 int i
, j
, k
, p
, ln
= 0, readonly_warning
= 0, pos
, count_vars
;
879 CONF_S
*ctmpa
= NULL
, *ctmpb
, *first_line
;
880 PINERC_S
*prc
= NULL
;
882 int expose_hidden_config
;
883 SAVED_CONFIG_S
*vsave
;
886 dprint((3, "-- alpine_xoauth2_configuration --\n"));
888 expose_hidden_config
= F_ON(F_EXPOSE_HIDDEN_CONFIG
, ps_global
);
889 ew
= edit_exceptions
? ps_global
->ew_for_except_vars
: Main
;
892 readonly_warning
= 1;
905 readonly_warning
= prc
? prc
->readonly
: 1;
908 ps
->next_screen
= SCREEN_FUN_NULL
;
910 mailcap_free(); /* free resources we won't be using for a while */
913 for(ln
= 0, m
= Xid
; m
< Xend
; m
++){
914 i
= strlen(x_default
[m
].screen_name
);
918 alval
= ALVAL(&ps
->vars
[V_XOAUTH2_INFO
], ew
);
919 lval
= *alval
= xoauth2_conf_dedup_and_merge(alval
);
920 set_current_val(&ps_global
->vars
[V_XOAUTH2_INFO
], FALSE
, FALSE
);
921 write_pinerc(ps_global
, ew
, WRP_NONE
);
924 ctmpa
= first_line
= NULL
;
926 for(i
= 0, count_vars
= 0; xoauth_default
[i
].name
!= NULL
; i
++){
927 /* always start with the default configuration */
928 for(k
= 0; lval
&& lval
[k
]; k
++){
929 y
= xoauth_parse_client_info(lval
[k
]);
930 if(same_xoauth2_info(xoauth_default
[i
], *y
))
932 free_xoauth2_info(&y
);
934 if(lval
== NULL
|| lval
[k
] == NULL
){
936 if(xoauth_default
[i
].client_secret
) count_vars
++;
937 if(xoauth_default
[i
].tenant
) count_vars
++;
939 for(k
= 0; lval
&& lval
[k
]; k
++){
940 y
= xoauth_parse_client_info(lval
[k
]);
941 if(y
&& (!y
->name
|| strcmp((char *) y
->name
, (char *) xoauth_default
[i
].name
))){
942 free_xoauth2_info(&y
);
946 if(xoauth_default
[i
].client_secret
!= NULL
) count_vars
++;
947 if(xoauth_default
[i
].tenant
!= NULL
) count_vars
++;
948 free_xoauth2_info(&y
);
952 for(i
= 0; varlist
&& varlist
[i
]; i
++){
953 free_variable_values(varlist
[i
]);
954 if(varlist
[i
]->descrip
) fs_give((void **) &varlist
[i
]->descrip
);
955 if(varlist
[i
]->dname
) fs_give((void **) &varlist
[i
]->dname
);
956 fs_give((void **) &varlist
[i
]);
958 if(varlist
) fs_give((void **) varlist
);
960 varlist
= fs_get((count_vars
+ 1)*sizeof(struct variable
*));
961 memset((void *) varlist
, 0, (count_vars
+1)*sizeof(struct variable
*));
963 for(i
= 0, p
= 0; xoauth_default
[i
].name
!= NULL
; i
++){
964 /* always start with the default configuration */
965 for(k
= 0; lval
&& lval
[k
]; k
++){
966 y
= xoauth_parse_client_info(lval
[k
]);
967 if(same_xoauth2_info(xoauth_default
[i
], *y
))
969 free_xoauth2_info(&y
);
971 if(lval
== NULL
|| lval
[k
] == NULL
){
973 for(oa2list
= alpine_oauth2_list
; oa2list
&& oa2list
->name
; oa2list
++){
974 if(oa2list
->hide
) continue;
975 if(!strcmp((char *) oa2list
->name
, (char *) xoauth_default
[i
].name
)){
976 xoauth_default
[i
].flow
= cpystr(oa2list
->server_mthd
[0].name
? "Authorize"
977 : (oa2list
->server_mthd
[1].name
? "Device" : "Unknown"));
978 write_xoauth_conf_entry(&xoauth_default
[i
], &xoauth_default
[i
], &ctmpa
, &ctmpb
,
979 &first_line
, &varlist
, &p
, ln
, -i
-1);
980 fs_give((void **) &xoauth_default
[i
].flow
);
981 break; /* just one entry, set the default to the first entry */
985 for(k
= 0; lval
&& lval
[k
]; k
++){
986 OAUTH2_S
*oa2list
, *oa2
;
988 y
= xoauth_parse_client_info(lval
[k
]);
989 if(y
&& (!y
->name
|| strcmp((char *) y
->name
, (char *) xoauth_default
[i
].name
))){
990 free_xoauth2_info(&y
);
993 if(y
->client_id
== NULL
)
994 y
->client_id
= cpystr(xoauth_default
[i
].client_id
);
995 if(y
->client_secret
== NULL
&& xoauth_default
[i
].client_secret
!= NULL
)
996 y
->client_secret
= cpystr(xoauth_default
[i
].client_secret
);
997 if(y
->tenant
== NULL
&& xoauth_default
[i
].tenant
!= NULL
)
998 y
->tenant
= cpystr(xoauth_default
[i
].tenant
);
999 for(oa2
= NULL
, oa2list
= alpine_oauth2_list
; oa2
== NULL
&& oa2list
; oa2list
++)
1000 if(!strcmp((char *) oa2list
->name
, (char *) y
->name
)) oa2
= oa2list
;
1001 if(oa2
&& y
->flow
== NULL
)
1002 y
->flow
= cpystr(oa2
->server_mthd
[0].name
? "Authorize"
1003 : (oa2
->server_mthd
[1].name
? "Device" : "Unknown"));
1004 if(oa2
&& !oa2
->hide
)
1005 write_xoauth_conf_entry(y
, &xoauth_default
[i
], &ctmpa
, &ctmpb
, &first_line
, &varlist
, &p
, ln
, k
);
1006 free_xoauth2_info(&y
);
1010 vsave
= save_config_vars(ps
, expose_hidden_config
);
1011 first_line
= pos
< 0 ? first_sel_confline(first_line
) : set_confline_number(first_line
, pos
);
1013 memset(&screen
, 0, sizeof(screen
));
1014 screen
.ro_warning
= readonly_warning
;
1015 /* TRANSLATORS: Print something1 using something2.
1016 "configuration" is something1 */
1017 switch(conf_scroll_screen(ps
, &screen
, first_line
, "XOAUTH2 Alpine Info",
1018 _("configuration"), 0, &pos
)){
1023 write_xoauth_configuration(&ps
->vars
[V_XOAUTH2_INFO
], varlist
, ew
);
1024 write_pinerc(ps
, ew
, WRP_NONE
);
1027 case 4: /* add a service */
1028 {char service
[MAILTMPLEN
+1];
1029 char prompt
[MAILTMPLEN
+1];
1030 int flags
= OE_DISALLOW_HELP
;
1031 strncpy(prompt
, _("Enter service name: "), sizeof(prompt
));
1032 prompt
[sizeof(prompt
) - 1] = '\0';
1034 if(optionally_enter(service
,
1035 -(ps_global
->ttyo
? FOOTER_ROWS(ps_global
) : 3),
1036 0, sizeof(service
), prompt
, NULL
, NO_HELP
, &flags
) == 0){
1037 for(i
= 0; xoauth_default
[i
].name
!= NULL
&& strucmp((char *) xoauth_default
[i
].name
, service
); i
++);
1038 if(xoauth_default
[i
].name
== NULL
)
1039 q_status_message1(SM_ORDER
, 3, 3, _("Service %s not known"), service
);
1043 ps_global
->mangled_screen
= 1;
1044 for(j
= 0; lval
&& lval
[j
]; j
++);
1045 list
= fs_get((j
+2)*sizeof(char *));
1046 memset((void *)list
, 0, (j
+2)*sizeof(char *));
1047 list
[0] = xoauth_config_line(&xoauth_default
[i
]);
1048 for(i
= 0; lval
&& lval
[i
]; i
++)
1049 list
[i
+1] = cpystr(lval
[i
]);
1050 if(lval
) free_list_array(&lval
);
1051 *alval
= lval
= list
;
1052 for(i
= 0; varlist
&& varlist
[i
]; i
++){
1053 free_variable_values(varlist
[i
]);
1054 if(varlist
[i
]->descrip
) fs_give((void **) &varlist
[i
]->descrip
);
1055 if(varlist
[i
]->dname
) fs_give((void **) &varlist
[i
]->dname
);
1056 fs_give((void **) &varlist
[i
]);
1058 if(varlist
) fs_give((void **) varlist
);
1064 case 5: /* delete a service */
1067 char question
[MAILTMPLEN
];
1069 for(i
= 0, m
= 1, j
= 0; varlist
[i
] && m
< pos
;)
1070 if(!varlist
[i
]->is_list
){
1074 && varlist
[i
]->current_val
.l
1075 && varlist
[i
]->current_val
.l
[j
++])
1081 key
= atoi(varlist
[i
]->dname
); /* this hack avoids we rebuild varlist again */
1083 x
= xoauth_parse_client_info(lval
[key
]);
1084 snprintf(question
, sizeof(question
), _("Delete this configuration for %s "), x
->name
);
1085 free_xoauth2_info(&x
);
1086 if(want_to(question
, 'n', 'n', NO_HELP
, WT_NORM
) != 'y')
1088 for(i
= key
; lval
&& lval
[i
] && lval
[i
+1]; i
++){
1089 fs_give((void **) &lval
[i
]);
1090 lval
[i
] = cpystr(lval
[i
+1]);
1092 fs_give((void **) &lval
[i
]);
1095 q_status_message(SM_ORDER
, 3, 3, _("Cannot delete default configuration"));
1098 if(lval
&& lval
[0] == NULL
)
1099 free_list_array(&lval
);
1101 pos
= 1; /* reset at the top */
1102 for(i
= 0; varlist
&& varlist
[i
]; i
++){
1103 free_variable_values(varlist
[i
]);
1104 if(varlist
[i
]->descrip
) fs_give((void **) &varlist
[i
]->descrip
);
1105 if(varlist
[i
]->dname
) fs_give((void **) &varlist
[i
]->dname
);
1106 fs_give((void **) &varlist
[i
]);
1108 if(varlist
) fs_give((void **) varlist
);
1113 revert_to_saved_config(ps
, vsave
, expose_hidden_config
);
1115 prc
->outstanding_pinerc_changes
= 0;
1119 q_status_message(SM_ORDER
,7,10,
1120 "conf_scroll_screen bad ret, not supposed to happen");
1126 mswin_set_quit_confirm (F_OFF(F_QUIT_WO_CONFIRM
, ps_global
));