2 * ========================================================================
3 * Copyright 2006-2008 University of Washington
4 * Copyright 2013-2020 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"
26 extern OAUTH2_S alpine_oauth2_list
[];
28 XOAUTH2_INFO_S xoauth_default
[] = {
29 { GMAIL_NAME
, GMAIL_ID
, GMAIL_SECRET
, GMAIL_TENANT
, NULL
},
30 { OUTLOOK_NAME
, OUTLOOK_ID
, OUTLOOK_SECRET
, OUTLOOK_TENANT
, NULL
},
31 { NULL
, NULL
, NULL
, NULL
, NULL
}
34 typedef enum {Xname
= 0, Xid
, Xsecret
, Xtenant
, Xuser
, Xend
} XTYPES
;
36 typedef struct xoauh2_info_val_s
{
41 /* the order here must match the order in XTYPES above */
42 XOAUTH2_INFO_VAL_S x_default
[] = {
44 {"Client-Id", "/ID="},
45 {"Client-Secret", "/SECRET="},
46 {"Tenant", "/TENANT="},
47 {"Username", "/USER="},
51 #define XNAME x_default[Xname].pinerc_name
52 #define XID x_default[Xid].pinerc_name
53 #define XSECRET x_default[Xsecret].pinerc_name
54 #define XTENANT x_default[Xtenant].pinerc_name
55 #define XUSER x_default[Xuser].pinerc_name
57 #define XOAUTH2_CLIENT_ID x_default[Xid].screen_name
58 #define XOAUTH2_CLIENT_SECRET x_default[Xsecret].screen_name
59 #define XOAUTH2_TENANT x_default[Xtenant].screen_name
60 #define XOAUTH2_USERS x_default[Xuser].screen_name
62 char *list_to_array(char **);
63 char **array_to_list(char *);
64 void write_xoauth_configuration(struct variable
*, struct variable
**, EditWhich
);
65 char **xoauth2_conf_dedup_and_merge(char ***);
66 int same_xoauth2_info(XOAUTH2_INFO_S
, XOAUTH2_INFO_S
);
67 XOAUTH2_INFO_S
*xoauth_info_choice(XOAUTH2_INFO_S
**, char *);
68 int xoauth2_info_tool(struct pine
*, int, CONF_S
**, unsigned int);
71 same_xoauth2_info(XOAUTH2_INFO_S x
, XOAUTH2_INFO_S y
)
74 if(x
.name
&& y
.name
&& !strcmp(x
.name
, y
.name
)
75 && x
.client_id
&& y
.client_id
&& !strcmp(x
.client_id
, y
.client_id
)
76 && ((!x
.client_secret
&& !y
.client_secret
)
77 || (x
.client_secret
&& y
.client_secret
&& !strcmp(x
.client_secret
, y
.client_secret
)))
78 && ((!x
.tenant
&& !y
.tenant
) || (x
.tenant
&& y
.tenant
&& !strcmp(x
.tenant
, y
.tenant
))))
84 list_to_array(char **list
)
90 if(list
== NULL
|| *list
== NULL
) return NULL
;
92 for(i
= 0, n
= 0; list
[i
] != NULL
; i
++)
93 n
+= strlen(list
[i
]) + 1;
95 rv
= fs_get(n
*sizeof(char));
97 for(i
= 0; list
[i
] != NULL
; i
++){
99 if(list
[i
+1] != NULL
) strcat(rv
, ",");
105 char **array_to_list(char *array
)
110 if(array
== NULL
|| *array
== '\0') return NULL
;
112 for(u
= array
, i
= 0; u
&& *u
; u
++)
115 return parse_list(array
, i
+1, 0,NULL
);
119 xoauth_config_line(XOAUTH2_INFO_S
*x
)
125 if(x
== NULL
) return NULL
;
127 n
= strlen(XNAME
) + strlen(x
->name
) + strlen(XID
) + strlen(x
->client_id
)
128 + strlen(x
->client_secret
? XSECRET
: "") + strlen(x
->client_secret
? x
->client_secret
: "")
129 + strlen(x
->tenant
? XTENANT
: "") + strlen(x
->tenant
? x
->tenant
: "")
130 + strlen(XUSER
) + strlen(x
->users
? x
->users
: "")
131 + 2 + 3 + (x
->client_secret
? 3 : 0) + (x
->tenant
? 3 : 0) + 3 + 1;
132 rv
= fs_get(n
*sizeof(char));
133 sprintf(rv
, "%s\"%s\" %s\"%s\"", XNAME
, x
->name
, XID
, x
->client_id
);
135 sprintf(rv
+ strlen(rv
), " %s\"%s\"", XSECRET
, x
->client_secret
);
137 sprintf(rv
+ strlen(rv
), " %s\"%s\"", XTENANT
, x
->tenant
);
138 sprintf(rv
+ strlen(rv
), " %s\"%s\"", XUSER
, x
->users
? x
->users
: "");
143 xoauth2_info_tool(struct pine
*ps
, int cmd
, CONF_S
**cl
, unsigned int flags
)
149 *((*cl
)->d
.x
.selected
) = (*cl
)->d
.x
.pat
;
150 rv
= simple_exit_cmd(flags
);
153 rv
= simple_exit_cmd(flags
);
161 ps
->mangled_body
= 1;
167 xoauth_info_choice(XOAUTH2_INFO_S
**xinfo
, char *user
)
170 if(!ps_global
->ttyo
){
175 for(i
= n
= 0; xinfo
[i
] != NULL
; i
++)
176 n
+= strlen(xinfo
[i
]->client_id
); + 5; /* number, parenthesis, space */
177 n
+= strlen(xinfo
[0]->name
) + strlen(user
);
178 n
+= 1024; /* large enough to display to lines of 80 characters in UTF-8 */
179 s
= fs_get(n
*sizeof(char));
180 sprintf(s
, _("Alpine cannot determine which client-id to use for the username <%s> for your %s account. "), user
, xinfo
[0]->name
);
181 sprintf(s
+ strlen(s
), _("Please select the client-id to use from the following list.\n\n"));
182 for(i
= 0; xinfo
[i
]; i
++)
183 sprintf(s
+ strlen(s
), " %d) %.70s\n", i
+1, xinfo
[i
]->client_id
);
184 sprintf(s
+ strlen(s
), "%s", "\n\n");
186 display_init_err(s
, 0);
188 strncpy(prompt
, _("Enter your selection number: "), sizeof(prompt
));
189 prompt
[sizeof(prompt
)-1] = '\0';
192 rv
= optionally_enter(reply
, 0, 0, sizeof(reply
), prompt
, NULL
, NO_HELP
, 0);
193 sel
= atoi(reply
) - 1;
194 rv
= (sel
>= 0 && sel
< i
) ? 0 : -1;
196 return copy_xoauth2_info(xinfo
[rv
]);
199 CONF_S
*ctmp
= NULL
, *first_line
= NULL
;
200 XOAUTH2_INFO_S
*x_sel
= NULL
;
204 dprint((9, "xoauth2 select client-id screen"));
205 ps_global
->next_screen
= SCREEN_FUN_NULL
;
207 memset(&screen
, 0, sizeof(screen
));
209 for(i
= 0; i
< sizeof(tmp
) && i
< ps_global
->ttyo
->screen_cols
; i
++)
214 ctmp
->flags
|= CF_NOSELECT
;
215 ctmp
->value
= cpystr(tmp
);
218 ctmp
->flags
|= CF_NOSELECT
;
219 ctmp
->value
= cpystr(_("Select a Client-ID to use with this account"));
222 ctmp
->flags
|= CF_NOSELECT
;
223 ctmp
->value
= cpystr(tmp
);
226 ctmp
->flags
|= CF_NOSELECT
| CF_B_LINE
;
228 sprintf(tmp
, _("Alpine cannot determine which client-id to use for the username <%s>"), user
);
230 ctmp
->flags
|= CF_NOSELECT
;
231 ctmp
->value
= cpystr(tmp
);
233 sprintf(tmp
, _("for your %s account. Please select the client-id to use from the following list.\n\n"), xinfo
[0]->name
);
235 ctmp
->flags
|= CF_NOSELECT
;
236 ctmp
->value
= cpystr(tmp
);
239 ctmp
->flags
|= CF_NOSELECT
| CF_B_LINE
;
241 for(i
= 0; xinfo
[i
] != NULL
; i
++){
246 ctmp
->value
= cpystr(xinfo
[i
]->client_id
);
247 ctmp
->d
.x
.selected
= &x_sel
;
248 ctmp
->d
.x
.pat
= copy_xoauth2_info(xinfo
[i
]);
249 ctmp
->keymenu
= &xoauth2_id_select_km
;
250 ctmp
->help
= NO_HELP
;
251 ctmp
->help_title
= NULL
;
252 ctmp
->tool
= xoauth2_info_tool
;
253 ctmp
->flags
= CF_STARTITEM
;
256 (void)conf_scroll_screen(ps_global
, &screen
, first_line
, _("SELECT CLIENT_ID"),
257 _("xoauth2"), 0, NULL
);
263 /* Get the client-id, etc. for server "name" associated to user "user" */
265 oauth2_get_client_info(unsigned char *name
, char *user
)
268 char ***alval
, **lval
;
269 XOAUTH2_INFO_S
*x
, **xinfo
;
271 if(name
== NULL
|| *name
== '\0' || user
== NULL
|| *user
== '\0')
275 /* first count how many servers */
276 lval
= ps_global
->vars
[V_XOAUTH2_INFO
].current_val
.l
;
277 for(i
= 0; lval
&& lval
[i
]; i
++){
278 x
= xoauth_parse_client_info(lval
[i
]);
279 if(x
&& x
->name
&& name
&& !strcmp(x
->name
, name
))
281 free_xoauth2_info(&x
);
284 /* if nothing, use the default value */
285 for(i
= 0; xoauth_default
[i
].name
!= NULL
&& strcmp(xoauth_default
[i
].name
, name
); i
++);
286 if(xoauth_default
[i
].name
) matches
++;
288 if(matches
== 0) return NULL
;
289 if(matches
== 1) return copy_xoauth2_info(&xoauth_default
[i
]);
291 /* more than one match, see if it is a duplicate client-id entry */
292 xinfo
= fs_get((matches
+ 1)*sizeof(XOAUTH2_INFO_S
*));
293 memset((void *)xinfo
, 0, (matches
+ 1)*sizeof(XOAUTH2_INFO_S
*));
294 matches
= 0; /* restart the recount, it might go lower! */
295 for(i
= 0; lval
&& lval
[i
]; i
++){
296 x
= xoauth_parse_client_info(lval
[i
]);
297 if(x
&& x
->name
&& name
&& !strcmp(x
->name
, name
)){
298 for(j
= 0; xinfo
&& xinfo
[j
] && !same_xoauth2_info(*x
, *xinfo
[j
]); j
++);
299 if(!xinfo
[j
]) xinfo
[matches
++] = copy_xoauth2_info(x
);
301 free_xoauth2_info(&x
);
303 for(i
= 0; xoauth_default
[i
].name
!= NULL
&& strcmp(xoauth_default
[i
].name
, name
); i
++);
304 for(j
= 0; xinfo
&& xinfo
[j
] && !same_xoauth2_info(xoauth_default
[i
], *xinfo
[j
]); j
++);
305 if(!xinfo
[j
]) xinfo
[matches
++] = copy_xoauth2_info(&xoauth_default
[i
]);
307 /* if after removing the duplicate entries, we only have one, use it */
309 x
= copy_xoauth2_info(xinfo
[0]);
310 free_xoauth2_info(&xinfo
[0]);
311 fs_give((void **) xinfo
);
315 /* we have more than one match, now check if any of them matches the given user */
317 for(i
= 0; xinfo
&& xinfo
[i
]; i
++){
318 lval
= array_to_list(xinfo
[i
]->users
);
319 for(j
= 0; lval
&& lval
[j
] && strucmp(lval
[j
], user
); j
++);
322 free_xoauth2_info(&x
);
323 x
= copy_xoauth2_info(xinfo
[i
]);
325 if(lval
) free_list_array(&lval
);
328 /* only one server matches the username */
330 for(i
= 0; xinfo
[i
] != NULL
; i
++)
331 free_xoauth2_info(&xinfo
[i
]);
332 fs_give((void **) xinfo
);
336 free_xoauth2_info(&x
);
337 /* We either have no matches, or have more than one match!
338 * in either case, let the user pick what they want */
339 x
= xoauth_info_choice(xinfo
, user
);
340 for(i
= 0; xinfo
[i
] != NULL
; i
++)
341 free_xoauth2_info(&xinfo
[i
]);
342 fs_give((void **) xinfo
);
344 /* Once the user chose a client-id, save it so we do not ask again */
346 int n
= x
->users
? strlen(x
->users
) + 1 : 0;
349 fs_resize((void **) &x
->users
, (n
+ strlen(user
) + 1)*sizeof(char));
350 x
->users
[n
> 0 ? n
- 1 : 0] = '\0';
351 if(n
> 0) strcat(x
->users
, ",");
352 strcat(x
->users
, user
);
353 alval
= ALVAL(&ps_global
->vars
[V_XOAUTH2_INFO
], Main
);
356 for(n
= 0; lval
&& lval
[n
]; n
++);
357 fs_resize((void **) &lval
, (n
+2)*sizeof(char *));
358 lval
[n
] = xoauth_config_line(x
);
360 *alval
= xoauth2_conf_dedup_and_merge(&lval
);
361 set_current_val(&ps_global
->vars
[V_XOAUTH2_INFO
], FALSE
, FALSE
);
362 write_pinerc(ps_global
, Main
, WRP_NONE
);
369 * Each vlist member is of type "p", while "v" is of type "l", so we
370 * each entry in "l" by using each of the "p" entries.
373 write_xoauth_configuration(struct variable
*v
, struct variable
**vlist
, EditWhich ew
)
376 XOAUTH2_INFO_S
*x
= NULL
, *y
;
377 char ***alval
, **lval
, **l
;
380 for (i
= 0, n
= 0; vlist
[i
] != NULL
; i
++) /* count number of lines we need */
381 if(!strcmp(vlist
[i
]->name
, XOAUTH2_USERS
))
383 lval
= fs_get((n
+1)*sizeof(char *));
384 memset((void *) lval
, 0, (n
+1)*sizeof(char *));
387 alval
= ALVAL(v
, ew
);
388 for (i
= 0, k
= 0; vlist
[i
] != NULL
; i
++){
390 x
= new_xoauth2_info();
391 x
->name
= cpystr(vlist
[i
]->descrip
); /* hack! but makes life so much easier! */
392 for(m
= 0; xoauth_default
[m
].name
!= NULL
393 && strcmp(xoauth_default
[m
].name
, x
->name
); m
++);
395 if (x
->client_id
== NULL
&& !strcmp(vlist
[i
]->name
, XOAUTH2_CLIENT_ID
)){
396 p
= PVAL(vlist
[i
], ew
);
397 if (p
== NULL
) p
= vlist
[i
]->current_val
.p
;
399 x
->client_id
= cpystr(p
);
402 if (x
->client_secret
== NULL
404 && xoauth_default
[m
].client_secret
405 && !strcmp(vlist
[i
]->name
, XOAUTH2_CLIENT_SECRET
)){
406 p
= PVAL(vlist
[i
], ew
);
407 if (p
== NULL
) p
= vlist
[i
]->current_val
.p
;
409 x
->client_secret
= cpystr(p
);
412 if (x
->tenant
== NULL
414 && xoauth_default
[m
].tenant
415 && !strcmp(vlist
[i
]->name
, XOAUTH2_TENANT
)){
416 p
= PVAL(vlist
[i
], ew
);
417 if (p
== NULL
) p
= vlist
[i
]->current_val
.p
;
419 x
->tenant
= cpystr(p
);
422 if (x
->users
== NULL
&& !strcmp(vlist
[i
]->name
, XOAUTH2_USERS
)){
423 l
= LVAL(vlist
[i
], ew
);
424 x
->users
= list_to_array(l
);
426 /* don't let it get to here until we are done! */
427 lval
[k
++] = xoauth_config_line(x
);
428 /* get ready for next run */
429 free_xoauth2_info(&x
);
434 if(*alval
) free_list_array(alval
);
439 set_current_val(&ps_global
->vars
[V_XOAUTH2_INFO
], FALSE
, FALSE
);
443 /* parse line of the form
444 /NAME="text" /ID="text" /TENANT="text" /SECRET="text" /USER="text"
447 xoauth_parse_client_info(char *lvalp
)
452 if (lvalp
== NULL
) return NULL
;
454 x
= new_xoauth2_info();
455 if((s
= strstr(lvalp
, XNAME
)) != NULL
){
458 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
461 if (*s
) x
->name
= cpystr(s
);
463 } else x
->name
= NULL
;
465 if((s
= strstr(lvalp
, XID
)) != NULL
){
468 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
471 if (*s
) x
->client_id
= cpystr(s
);
473 } else x
->client_id
= NULL
;
475 if((s
= strstr(lvalp
, XTENANT
)) != NULL
){
476 s
+= strlen(XTENANT
);
478 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
481 if (*s
) x
->tenant
= cpystr(s
);
483 } else x
->tenant
= NULL
;
485 if((s
= strstr(lvalp
, XSECRET
)) != NULL
){
486 s
+= strlen(XSECRET
);
488 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
491 if (*s
) x
->client_secret
= cpystr(s
);
493 } else x
->client_secret
= NULL
;
495 if((s
= strstr(lvalp
, XUSER
)) != NULL
){
498 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
501 if(*s
) x
->users
= cpystr(s
);
503 } else x
->users
= NULL
;
509 xoauth2_conf_dedup_and_merge(char ***alval
)
511 int i
, j
, k
, l
, n
, m
;
513 XOAUTH2_INFO_S
*x
, *y
;
515 if(alval
== NULL
|| *alval
== NULL
|| **alval
== NULL
)
519 for(i
= 0; lval
[i
] != NULL
; i
++); /* count how many entries */
521 rv
= fs_get((i
+1)*sizeof(char *));
522 memset((void *)rv
, 0, (i
+1)*sizeof(char *));
524 for (i
= 0; lval
[i
] != NULL
; i
++){
525 x
= xoauth_parse_client_info(lval
[i
]);
526 for (j
= 0; rv
[j
] != NULL
; j
++){
527 y
= xoauth_parse_client_info(rv
[j
]);
528 /* check if this is the same data. If so, merge the users into one and discard the old data */
529 if(same_xoauth2_info(*x
, *y
)){
530 char **l1
, **l2
, **l3
;
532 /* merge user1 with user2, save in x->users */
533 l1
= array_to_list(x
->users
);
534 l2
= array_to_list(y
->users
);
536 for(n
= 0; l1
&& l1
[n
]; n
++);
537 for(m
= 0; l2
&& l2
[m
]; m
++, n
++);
538 l3
= fs_get((n
+1)*sizeof(char*));
539 memset((void *) l3
, 0, (n
+1)*sizeof(char *));
541 for(l
= 0, n
= 0; l1
&& l1
[l
]; l
++){
542 for(k
= 0; l1
&& l1
[j
] && l3
[k
] && strucmp(l1
[l
], l3
[k
]); k
++);
543 if(l3
[k
] == NULL
&& l1
&& l1
[l
] != NULL
)
544 l3
[n
++] = cpystr(l1
[l
]);
546 for(l
= 0; l2
&& l2
[l
]; l
++){
547 for(k
= 0; l2
&& l2
[l
] && l3
[k
] && strucmp(l2
[l
], l3
[k
]); k
++);
548 if(l3
[k
] == NULL
&& l2
&& l2
[l
] != NULL
)
549 l3
[n
++] = cpystr(l2
[l
]);
552 if(x
->users
) fs_give((void **) &x
->users
);
553 x
->users
= list_to_array(l3
);
554 fs_give((void **) &rv
[j
]);
555 rv
[j
] = xoauth_config_line(x
);
557 if(l1
) free_list_array(&l1
);
558 if(l2
) free_list_array(&l2
);
559 if(l3
) free_list_array(&l3
);
560 free_xoauth2_info(&y
);
563 free_xoauth2_info(&y
);
565 if(rv
[j
] == NULL
) rv
[j
] = cpystr(lval
[i
]);
571 * X = new value, Y = default configuration
574 write_xoauth_conf_entry(XOAUTH2_INFO_S
*x
, XOAUTH2_INFO_S
*y
, CONF_S
**cl
, CONF_S
**clb
, CONF_S
**fline
,
575 struct variable
***varlistp
, int *pp
, int ln
, int key
)
577 CONF_S
*ctmpb
= *clb
;
578 struct variable
**varlist
;
580 char tmp
[1024], tmp2
[16];
582 i
= 2; /* client_id and users always appear */
583 if(x
->client_secret
) i
++;
586 sprintf(tmp2
, "%d", key
);
587 fs_resize((void **) varlistp
, (p
+ i
+ 1)*sizeof(struct variable
**));
588 memset((void *) (*varlistp
+ p
*sizeof(struct variable
*)), 0, (i
+ 1)*sizeof(struct variable
*));
591 new_confline(cl
)->var
= NULL
;
592 if(fline
&& !*fline
) *fline
= *cl
;
593 (*cl
)->flags
|= CF_NOSELECT
;
594 (*cl
)->help
= NO_HELP
;
595 (*cl
)->valoffset
= 1;
596 (*cl
)->value
= cpystr(x
->name
);
597 (*cl
)->varname
= NULL
;
598 (*cl
)->varnamep
= ctmpb
= *cl
;
600 /* Setup client-id variable */
601 varlist
[p
] = fs_get(sizeof(struct variable
));
602 memset((void *) varlist
[p
], 0, sizeof(struct variable
));
603 varlist
[p
]->name
= cpystr(XOAUTH2_CLIENT_ID
);
604 varlist
[p
]->is_used
= 1;
605 varlist
[p
]->is_user
= 1;
606 varlist
[p
]->main_user_val
.p
= x
->client_id
&& y
->client_id
607 && strcmp(x
->client_id
, y
->client_id
) ? cpystr(x
->client_id
) : NULL
;
608 varlist
[p
]->global_val
.p
= y
->client_id
? cpystr(y
->client_id
) : NULL
;
609 varlist
[p
]->dname
= cpystr(tmp2
); /* hack, but makes life easier! */
610 varlist
[p
]->descrip
= cpystr(x
->name
); /* hack, but makes life easier! */
611 set_current_val(varlist
[p
], FALSE
, FALSE
);
613 /* Write client-id variable */
614 new_confline(cl
)->var
= varlist
[p
];
615 utf8_snprintf(tmp
, sizeof(tmp
), " %-*.100w =", ln
, XOAUTH2_CLIENT_ID
);
616 tmp
[sizeof(tmp
)-1] = '\0';
617 (*cl
)->varname
= cpystr(tmp
);
619 (*cl
)->valoffset
= ln
+ 3 + 3;
620 (*cl
)->value
= pretty_value(ps_global
, *cl
);
621 (*cl
)->keymenu
= &config_xoauth2_text_keymenu
;
622 (*cl
)->help
= h_config_xoauth2_client_id
;
623 (*cl
)->tool
= text_tool
;
624 (*cl
)->varnamep
= ctmpb
;
626 /* Set up client-secret variable */
627 if(x
->client_secret
){
628 varlist
[p
] = fs_get(sizeof(struct variable
));
629 memset((void *) varlist
[p
], 0, sizeof(struct variable
));
630 varlist
[p
]->name
= cpystr(XOAUTH2_CLIENT_SECRET
);
631 varlist
[p
]->is_used
= 1;
632 varlist
[p
]->is_user
= 1;
633 varlist
[p
]->main_user_val
.p
= y
->client_secret
634 && strcmp(x
->client_secret
, y
->client_secret
)
635 ? cpystr(x
->client_secret
) : NULL
;
636 varlist
[p
]->global_val
.p
= y
->client_secret
? cpystr(y
->client_secret
) : NULL
;
637 varlist
[p
]->dname
= cpystr(tmp2
); /* hack, but makes life easier! */
638 varlist
[p
]->descrip
= cpystr(x
->name
); /* hack, but makes life easier! */
639 set_current_val(varlist
[p
], FALSE
, FALSE
);
641 /* Write client-secret variable */
642 new_confline(cl
)->var
= varlist
[p
];
643 utf8_snprintf(tmp
, sizeof(tmp
), " %-*.100w =", ln
, XOAUTH2_CLIENT_SECRET
);
644 tmp
[sizeof(tmp
)-1] = '\0';
645 (*cl
)->varname
= cpystr(tmp
);
647 (*cl
)->valoffset
= ln
+ 3 + 3;
648 (*cl
)->value
= pretty_value(ps_global
, *cl
);
649 (*cl
)->keymenu
= &config_xoauth2_text_keymenu
;
650 (*cl
)->help
= h_config_xoauth2_client_secret
;
651 (*cl
)->tool
= text_tool
;
652 (*cl
)->varnamep
= ctmpb
;
655 /* Set up tenant variable */
657 varlist
[p
] = fs_get(sizeof(struct variable
));
658 memset((void *) varlist
[p
], 0, sizeof(struct variable
));
659 varlist
[p
]->name
= cpystr(XOAUTH2_TENANT
);
660 varlist
[p
]->is_used
= 1;
661 varlist
[p
]->is_user
= 1;
662 varlist
[p
]->main_user_val
.p
= y
->tenant
&& strcmp(x
->tenant
, y
->tenant
)
663 ? cpystr(x
->tenant
) : NULL
;
664 varlist
[p
]->global_val
.p
= y
->tenant
? cpystr(y
->tenant
) : NULL
;
665 varlist
[p
]->dname
= cpystr(tmp2
); /* hack, but makes life easier! */
666 varlist
[p
]->descrip
= cpystr(x
->name
); /* hack, but makes life easier! */
667 set_current_val(varlist
[p
], FALSE
, FALSE
);
669 /* Write client-secret variable */
670 new_confline(cl
)->var
= varlist
[p
];
671 utf8_snprintf(tmp
, sizeof(tmp
), " %-*.100w =", ln
, XOAUTH2_TENANT
);
672 tmp
[sizeof(tmp
)-1] = '\0';
673 (*cl
)->varname
= cpystr(tmp
);
675 (*cl
)->valoffset
= ln
+ 3 + 3;
676 (*cl
)->value
= pretty_value(ps_global
, *cl
);
677 (*cl
)->keymenu
= &config_xoauth2_text_keymenu
;
678 (*cl
)->help
= h_config_xoauth2_tenant
;
679 (*cl
)->tool
= text_tool
;
680 (*cl
)->varnamep
= ctmpb
;
683 /* Setup users variable */
684 varlist
[p
] = fs_get(sizeof(struct variable
));
685 memset((void *) varlist
[p
], 0, sizeof(struct variable
));
686 varlist
[p
]->name
= cpystr(XOAUTH2_USERS
);
687 varlist
[p
]->is_used
= 1;
688 varlist
[p
]->is_user
= 1;
689 varlist
[p
]->is_list
= 1;
690 varlist
[p
]->main_user_val
.l
= x
->users
? array_to_list(x
->users
) : NULL
;
691 varlist
[p
]->dname
= cpystr(tmp2
); /* hack, but makes life easier! */
692 varlist
[p
]->descrip
= cpystr(x
->name
); /* hack, but makes life easier! */
693 set_current_val(varlist
[p
], FALSE
, FALSE
);
695 /* Write user variable */
696 new_confline(cl
)->var
= varlist
[p
];
697 utf8_snprintf(tmp
, sizeof(tmp
), " %-*.100w =", ln
, XOAUTH2_USERS
);
698 tmp
[sizeof(tmp
)-1] = '\0';
699 (*cl
)->varname
= cpystr(tmp
);
700 (*cl
)->valoffset
= ln
+ 3 + 3;
701 (*cl
)->keymenu
= &config_xoauth2_wshuf_keymenu
;
702 (*cl
)->help
= h_config_xoauth2_username
;
705 for(z
= 0; varlist
[p
]->main_user_val
.l
[z
]; z
++){
706 if(z
) new_confline(cl
);
707 (*cl
)->var
= varlist
[p
];
709 (*cl
)->valoffset
= ln
+ 3 + 3;
710 (*cl
)->value
= pretty_value(ps_global
, *cl
);
711 (*cl
)->keymenu
= &config_xoauth2_wshuf_keymenu
;
712 (*cl
)->tool
= text_tool
;
713 (*cl
)->varnamep
= ctmpb
= *cl
;
718 (*cl
)->value
= pretty_value(ps_global
, *cl
);
719 (*cl
)->keymenu
= &config_xoauth2_wshuf_keymenu
;
720 (*cl
)->tool
= text_tool
;
721 (*cl
)->varnamep
= ctmpb
= *cl
;
728 /* Separate servers with a blank line */
730 (*cl
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
733 /*----------------------------------------------------------------------
734 Screen to add client_id and client_secret for a service
738 alpine_xoauth2_configuration(struct pine
*ps
, int edit_exceptions
)
740 struct variable
**varlist
= NULL
;
741 char tmp
[MAXPATH
+1], *pval
, **lval
, ***alval
;
742 char *s
, *extraname
= NULL
;
743 char *name
, *id
, *tenant
, *secret
, **user
;
744 char *name_lval
, *id_lval
, *tenant_lval
, *secret_lval
, *user_lval
,
745 *id_def
, *tenant_def
, *secret_def
;
746 int i
, j
, k
, l
, p
, q
, ln
= 0, readonly_warning
= 0, pos
;
747 CONF_S
*ctmpa
= NULL
, *ctmpb
, *first_line
;
749 PINERC_S
*prc
= NULL
;
751 int expose_hidden_config
, add_hidden_vars_title
= 0;
752 SAVED_CONFIG_S
*vsave
;
753 XOAUTH2_INFO_S x
, *y
;
755 dprint((3, "-- alpine_xoauth2_configuration --\n"));
757 expose_hidden_config
= F_ON(F_EXPOSE_HIDDEN_CONFIG
, ps_global
);
758 ew
= edit_exceptions
? ps_global
->ew_for_except_vars
: Main
;
761 readonly_warning
= 1;
774 readonly_warning
= prc
? prc
->readonly
: 1;
777 ps
->next_screen
= SCREEN_FUN_NULL
;
779 mailcap_free(); /* free resources we won't be using for a while */
782 ln
= strlen(XOAUTH2_CLIENT_ID
);
783 i
= strlen(XOAUTH2_CLIENT_SECRET
);
785 i
= strlen(XOAUTH2_TENANT
);
787 i
= strlen(XOAUTH2_USERS
);
790 alval
= ALVAL(&ps
->vars
[V_XOAUTH2_INFO
], ew
);
791 lval
= *alval
= xoauth2_conf_dedup_and_merge(alval
);
792 set_current_val(&ps_global
->vars
[V_XOAUTH2_INFO
], FALSE
, FALSE
);
793 write_pinerc(ps_global
, ew
, WRP_NONE
);
796 ctmpa
= first_line
= NULL
;
798 for(i
= 0, p
= 0; xoauth_default
[i
].name
!= NULL
; i
++){
799 /* always start with the default configuration */
800 for(k
= 0, q
= 0; lval
&& lval
[k
]; k
++){
801 y
= xoauth_parse_client_info(lval
[k
]);
802 if(same_xoauth2_info(xoauth_default
[i
], *y
))
804 free_xoauth2_info(&y
);
806 if(lval
== NULL
|| lval
[k
] == NULL
)
807 write_xoauth_conf_entry(&xoauth_default
[i
], &xoauth_default
[i
], &ctmpa
, &ctmpb
,
808 &first_line
, &varlist
, &p
, ln
, -i
-1);
809 for(k
= 0, q
= 0; lval
&& lval
[k
]; k
++){
810 y
= xoauth_parse_client_info(lval
[k
]);
811 if(y
&& (!y
->name
|| strcmp(y
->name
, xoauth_default
[i
].name
))){
812 free_xoauth2_info(&y
);
815 if(y
->client_id
== NULL
)
816 y
->client_id
= cpystr(xoauth_default
[i
].client_id
);
817 if(y
->client_secret
== NULL
&& xoauth_default
[i
].client_secret
!= NULL
)
818 y
->client_secret
= cpystr(xoauth_default
[i
].client_secret
);
819 if(y
->tenant
== NULL
&& xoauth_default
[i
].tenant
!= NULL
)
820 y
->tenant
= cpystr(xoauth_default
[i
].tenant
);
821 write_xoauth_conf_entry(y
, &xoauth_default
[i
], &ctmpa
, &ctmpb
, &first_line
, &varlist
, &p
, ln
, k
);
822 free_xoauth2_info(&y
);
826 vsave
= save_config_vars(ps
, expose_hidden_config
);
827 first_line
= pos
< 0 ? first_sel_confline(first_line
) : set_confline_number(first_line
, pos
);
829 memset(&screen
, 0, sizeof(screen
));
830 screen
.ro_warning
= readonly_warning
;
831 /* TRANSLATORS: Print something1 using something2.
832 "configuration" is something1 */
833 switch(conf_scroll_screen(ps
, &screen
, first_line
, "XOAUTH2 Alpine Info",
834 _("configuration"), 0, &pos
)){
839 write_xoauth_configuration(&ps
->vars
[V_XOAUTH2_INFO
], varlist
, ew
);
840 write_pinerc(ps
, ew
, WRP_NONE
);
843 case 4: /* add a service */
844 {char service
[MAILTMPLEN
+1];
845 char prompt
[MAILTMPLEN
+1];
846 int flags
= OE_DISALLOW_HELP
;
847 strncpy(prompt
, _("Enter service name: "), sizeof(prompt
));
848 prompt
[sizeof(prompt
) - 1] = '\0';
850 if(optionally_enter(service
,
851 -(ps_global
->ttyo
? FOOTER_ROWS(ps_global
) : 3),
852 0, sizeof(service
), prompt
, NULL
, NO_HELP
, &flags
) == 0){
853 for(i
= 0; xoauth_default
[i
].name
!= NULL
&& strucmp(xoauth_default
[i
].name
, service
); i
++);
854 if(xoauth_default
[i
].name
== NULL
)
855 q_status_message1(SM_ORDER
, 3, 3, _("Service %s not known"), service
);
859 ps_global
->mangled_screen
= 1;
860 for(j
= 0; lval
&& lval
[j
]; j
++);
861 list
= fs_get((j
+2)*sizeof(char *));
862 memset((void *)list
, 0, (j
+2)*sizeof(char *));
863 list
[0] = xoauth_config_line(&xoauth_default
[i
]);
864 for(i
= 0; lval
&& lval
[i
]; i
++)
865 list
[i
+1] = cpystr(lval
[i
]);
866 if(lval
) free_list_array(&lval
);
867 *alval
= lval
= list
;
868 for(i
= 0; varlist
&& varlist
[i
]; i
++){
869 free_variable_values(varlist
[i
]);
870 if(varlist
[i
]->descrip
) fs_give((void **) &varlist
[i
]->descrip
);
871 if(varlist
[i
]->dname
) fs_give((void **) &varlist
[i
]->dname
);
872 fs_give((void **) &varlist
[i
]);
874 if(varlist
) fs_give((void **) varlist
);
880 case 5: /* delete a service */
883 char question
[MAILTMPLEN
];
885 for(i
= 0, m
= 1, j
= 0; varlist
[i
] && m
< pos
;)
886 if(!varlist
[i
]->is_list
){
889 if(varlist
[i
]->current_val
.l
[j
++]) m
++;
894 key
= atoi(varlist
[i
]->dname
); /* this hack avoids we rebuild varlist again */
896 x
= xoauth_parse_client_info(lval
[key
]);
897 snprintf(question
, sizeof(question
), _("Delete this configuration for %s "), x
->name
);
898 free_xoauth2_info(&x
);
899 if(want_to(question
, 'n', 'n', NO_HELP
, WT_NORM
) != 'y')
901 for(i
= key
; lval
&& lval
[i
] && lval
[i
+1]; i
++){
902 fs_give((void **) &lval
[i
]);
903 lval
[i
] = cpystr(lval
[i
+1]);
905 fs_give((void **) &lval
[i
]);
908 q_status_message(SM_ORDER
, 3, 3, _("Cannot delete default configuration"));
911 if(lval
&& lval
[0] == NULL
)
912 free_list_array(&lval
);
914 pos
= 1; /* reset at the top */
915 for(i
= 0; varlist
&& varlist
[i
]; i
++){
916 free_variable_values(varlist
[i
]);
917 if(varlist
[i
]->descrip
) fs_give((void **) &varlist
[i
]->descrip
);
918 if(varlist
[i
]->dname
) fs_give((void **) &varlist
[i
]->dname
);
919 fs_give((void **) &varlist
[i
]);
921 if(varlist
) fs_give((void **) varlist
);
926 revert_to_saved_config(ps
, vsave
, expose_hidden_config
);
928 prc
->outstanding_pinerc_changes
= 0;
932 q_status_message(SM_ORDER
,7,10,
933 "conf_scroll_screen bad ret, not supposed to happen");
938 for(i
= 0; varlist
&& varlist
[i
]; i
++){
939 free_variable_values(varlist
[i
]);
940 if(varlist
[i
]->descrip
) fs_give((void **) &varlist
[i
]->descrip
);
941 if(varlist
[i
]->dname
) fs_give((void **) &varlist
[i
]->dname
);
942 fs_give((void **) &varlist
[i
]);
944 if(varlist
) fs_give((void **) varlist
);
947 mswin_set_quit_confirm (F_OFF(F_QUIT_WO_CONFIRM
, ps_global
));