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(xoauth_default
[i
].name
&& !xinfo
[j
]) xinfo
[matches
++] = copy_xoauth2_info(&xoauth_default
[i
]);
308 /* if after removing the duplicate entries, we only have one, use it */
310 x
= copy_xoauth2_info(xinfo
[0]);
311 free_xoauth2_info(&xinfo
[0]);
312 fs_give((void **) xinfo
);
316 /* we have more than one match, now check if any of them matches the given user */
318 for(i
= 0; xinfo
&& xinfo
[i
]; i
++){
319 lval
= array_to_list(xinfo
[i
]->users
);
320 for(j
= 0; lval
&& lval
[j
] && strucmp(lval
[j
], user
); j
++);
323 free_xoauth2_info(&x
);
324 x
= copy_xoauth2_info(xinfo
[i
]);
326 if(lval
) free_list_array(&lval
);
329 /* only one server matches the username */
331 for(i
= 0; xinfo
[i
] != NULL
; i
++)
332 free_xoauth2_info(&xinfo
[i
]);
333 fs_give((void **) xinfo
);
337 free_xoauth2_info(&x
);
338 /* We either have no matches, or have more than one match!
339 * in either case, let the user pick what they want */
340 x
= xoauth_info_choice(xinfo
, user
);
341 for(i
= 0; xinfo
[i
] != NULL
; i
++)
342 free_xoauth2_info(&xinfo
[i
]);
343 fs_give((void **) xinfo
);
345 /* Once the user chose a client-id, save it so we do not ask again */
347 int n
= x
->users
? strlen(x
->users
) + 1 : 0;
350 fs_resize((void **) &x
->users
, (n
+ strlen(user
) + 1)*sizeof(char));
351 x
->users
[n
> 0 ? n
- 1 : 0] = '\0';
352 if(n
> 0) strcat(x
->users
, ",");
353 strcat(x
->users
, user
);
354 alval
= ALVAL(&ps_global
->vars
[V_XOAUTH2_INFO
], Main
);
357 for(n
= 0; lval
&& lval
[n
]; n
++);
358 fs_resize((void **) &lval
, (n
+2)*sizeof(char *));
359 lval
[n
] = xoauth_config_line(x
);
361 *alval
= xoauth2_conf_dedup_and_merge(&lval
);
362 set_current_val(&ps_global
->vars
[V_XOAUTH2_INFO
], FALSE
, FALSE
);
363 write_pinerc(ps_global
, Main
, WRP_NONE
);
370 * Each vlist member is of type "p", while "v" is of type "l", so we
371 * each entry in "l" by using each of the "p" entries.
374 write_xoauth_configuration(struct variable
*v
, struct variable
**vlist
, EditWhich ew
)
377 XOAUTH2_INFO_S
*x
= NULL
, *y
;
378 char ***alval
, **lval
, **l
;
381 for (i
= 0, n
= 0; vlist
[i
] != NULL
; i
++) /* count number of lines we need */
382 if(!strcmp(vlist
[i
]->name
, XOAUTH2_USERS
))
384 lval
= fs_get((n
+1)*sizeof(char *));
385 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 if(alpine_oauth2_list
[j
].param
[OA2_Id
].value
)
429 fs_give((void **) &alpine_oauth2_list
[j
].param
[OA2_Id
].value
);
430 if(alpine_oauth2_list
[j
].param
[OA2_Secret
].value
)
431 fs_give((void **) &alpine_oauth2_list
[j
].param
[OA2_Secret
].value
);
432 if(alpine_oauth2_list
[j
].param
[OA2_Tenant
].value
)
433 fs_give((void **) &alpine_oauth2_list
[j
].param
[OA2_Tenant
].value
);
434 alpine_oauth2_list
[j
].param
[OA2_Id
].value
= cpystr(x
->client_id
);
435 alpine_oauth2_list
[j
].param
[OA2_Secret
].value
= x
->client_secret
? cpystr(x
->client_secret
) : NULL
;
436 alpine_oauth2_list
[j
].param
[OA2_Tenant
].value
= x
->tenant
? cpystr(x
->tenant
) : NULL
;
437 /* get ready for next run */
438 free_xoauth2_info(&x
);
442 if(*alval
) free_list_array(alval
);
447 set_current_val(&ps_global
->vars
[V_XOAUTH2_INFO
], FALSE
, FALSE
);
451 /* parse line of the form
452 /NAME="text" /ID="text" /TENANT="text" /SECRET="text" /USER="text"
455 xoauth_parse_client_info(char *lvalp
)
460 if (lvalp
== NULL
) return NULL
;
462 x
= new_xoauth2_info();
463 if((s
= strstr(lvalp
, XNAME
)) != NULL
){
466 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
469 if (*s
) x
->name
= cpystr(s
);
471 } else x
->name
= NULL
;
473 if((s
= strstr(lvalp
, XID
)) != NULL
){
476 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
479 if (*s
) x
->client_id
= cpystr(s
);
481 } else x
->client_id
= NULL
;
483 if((s
= strstr(lvalp
, XTENANT
)) != NULL
){
484 s
+= strlen(XTENANT
);
486 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
489 if (*s
) x
->tenant
= cpystr(s
);
491 } else x
->tenant
= NULL
;
493 if((s
= strstr(lvalp
, XSECRET
)) != NULL
){
494 s
+= strlen(XSECRET
);
496 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
499 if (*s
) x
->client_secret
= cpystr(s
);
501 } else x
->client_secret
= NULL
;
503 if((s
= strstr(lvalp
, XUSER
)) != NULL
){
506 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
509 if(*s
) x
->users
= cpystr(s
);
511 } else x
->users
= NULL
;
517 xoauth2_conf_dedup_and_merge(char ***alval
)
519 int i
, j
, k
, l
, n
, m
;
521 XOAUTH2_INFO_S
*x
, *y
;
523 if(alval
== NULL
|| *alval
== NULL
|| **alval
== NULL
)
527 for(i
= 0; lval
[i
] != NULL
; i
++); /* count how many entries */
529 rv
= fs_get((i
+1)*sizeof(char *));
530 memset((void *)rv
, 0, (i
+1)*sizeof(char *));
532 for (i
= 0; lval
[i
] != NULL
; i
++){
533 x
= xoauth_parse_client_info(lval
[i
]);
534 for (j
= 0; rv
[j
] != NULL
; j
++){
535 y
= xoauth_parse_client_info(rv
[j
]);
536 /* check if this is the same data. If so, merge the users into one and discard the old data */
537 if(same_xoauth2_info(*x
, *y
)){
538 char **l1
, **l2
, **l3
;
540 /* merge user1 with user2, save in x->users */
541 l1
= array_to_list(x
->users
);
542 l2
= array_to_list(y
->users
);
544 for(n
= 0; l1
&& l1
[n
]; n
++);
545 for(m
= 0; l2
&& l2
[m
]; m
++, n
++);
546 l3
= fs_get((n
+1)*sizeof(char*));
547 memset((void *) l3
, 0, (n
+1)*sizeof(char *));
549 for(l
= 0, n
= 0; l1
&& l1
[l
]; l
++){
550 for(k
= 0; l1
&& l1
[j
] && l3
[k
] && strucmp(l1
[l
], l3
[k
]); k
++);
551 if(l3
[k
] == NULL
&& l1
&& l1
[l
] != NULL
)
552 l3
[n
++] = cpystr(l1
[l
]);
554 for(l
= 0; l2
&& l2
[l
]; l
++){
555 for(k
= 0; l2
&& l2
[l
] && l3
[k
] && strucmp(l2
[l
], l3
[k
]); k
++);
556 if(l3
[k
] == NULL
&& l2
&& l2
[l
] != NULL
)
557 l3
[n
++] = cpystr(l2
[l
]);
560 if(x
->users
) fs_give((void **) &x
->users
);
561 x
->users
= list_to_array(l3
);
562 fs_give((void **) &rv
[j
]);
563 rv
[j
] = xoauth_config_line(x
);
565 if(l1
) free_list_array(&l1
);
566 if(l2
) free_list_array(&l2
);
567 if(l3
) free_list_array(&l3
);
568 free_xoauth2_info(&y
);
571 free_xoauth2_info(&y
);
573 if(rv
[j
] == NULL
) rv
[j
] = cpystr(lval
[i
]);
579 * X = new value, Y = default configuration
582 write_xoauth_conf_entry(XOAUTH2_INFO_S
*x
, XOAUTH2_INFO_S
*y
, CONF_S
**cl
, CONF_S
**clb
, CONF_S
**fline
,
583 struct variable
***varlistp
, int *pp
, int ln
, int key
)
585 CONF_S
*ctmpb
= *clb
;
586 struct variable
**varlist
;
588 char tmp
[1024], tmp2
[16];
590 i
= 2; /* client_id and users always appear */
591 if(x
->client_secret
) i
++;
594 sprintf(tmp2
, "%d", key
);
595 fs_resize((void **) varlistp
, (p
+ i
+ 1)*sizeof(struct variable
**));
596 memset((void *) (*varlistp
+ p
*sizeof(struct variable
*)), 0, (i
+ 1)*sizeof(struct variable
*));
599 new_confline(cl
)->var
= NULL
;
600 if(fline
&& !*fline
) *fline
= *cl
;
601 (*cl
)->flags
|= CF_NOSELECT
;
602 (*cl
)->help
= NO_HELP
;
603 (*cl
)->valoffset
= 1;
604 (*cl
)->value
= cpystr(x
->name
);
605 (*cl
)->varname
= NULL
;
606 (*cl
)->varnamep
= ctmpb
= *cl
;
608 /* Setup client-id variable */
609 varlist
[p
] = fs_get(sizeof(struct variable
));
610 memset((void *) varlist
[p
], 0, sizeof(struct variable
));
611 varlist
[p
]->name
= cpystr(XOAUTH2_CLIENT_ID
);
612 varlist
[p
]->is_used
= 1;
613 varlist
[p
]->is_user
= 1;
614 varlist
[p
]->main_user_val
.p
= x
->client_id
&& y
->client_id
615 && strcmp(x
->client_id
, y
->client_id
) ? cpystr(x
->client_id
) : NULL
;
616 varlist
[p
]->global_val
.p
= y
->client_id
? cpystr(y
->client_id
) : NULL
;
617 varlist
[p
]->dname
= cpystr(tmp2
); /* hack, but makes life easier! */
618 varlist
[p
]->descrip
= cpystr(x
->name
); /* hack, but makes life easier! */
619 set_current_val(varlist
[p
], FALSE
, FALSE
);
621 /* Write client-id variable */
622 new_confline(cl
)->var
= varlist
[p
];
623 utf8_snprintf(tmp
, sizeof(tmp
), " %-*.100w =", ln
, XOAUTH2_CLIENT_ID
);
624 tmp
[sizeof(tmp
)-1] = '\0';
625 (*cl
)->varname
= cpystr(tmp
);
627 (*cl
)->valoffset
= ln
+ 3 + 3;
628 (*cl
)->value
= pretty_value(ps_global
, *cl
);
629 (*cl
)->keymenu
= &config_xoauth2_text_keymenu
;
630 (*cl
)->help
= h_config_xoauth2_client_id
;
631 (*cl
)->tool
= text_tool
;
632 (*cl
)->varnamep
= ctmpb
;
634 /* Set up client-secret variable */
635 if(x
->client_secret
){
636 varlist
[p
] = fs_get(sizeof(struct variable
));
637 memset((void *) varlist
[p
], 0, sizeof(struct variable
));
638 varlist
[p
]->name
= cpystr(XOAUTH2_CLIENT_SECRET
);
639 varlist
[p
]->is_used
= 1;
640 varlist
[p
]->is_user
= 1;
641 varlist
[p
]->main_user_val
.p
= y
->client_secret
642 && strcmp(x
->client_secret
, y
->client_secret
)
643 ? cpystr(x
->client_secret
) : NULL
;
644 varlist
[p
]->global_val
.p
= y
->client_secret
? cpystr(y
->client_secret
) : NULL
;
645 varlist
[p
]->dname
= cpystr(tmp2
); /* hack, but makes life easier! */
646 varlist
[p
]->descrip
= cpystr(x
->name
); /* hack, but makes life easier! */
647 set_current_val(varlist
[p
], FALSE
, FALSE
);
649 /* Write client-secret variable */
650 new_confline(cl
)->var
= varlist
[p
];
651 utf8_snprintf(tmp
, sizeof(tmp
), " %-*.100w =", ln
, XOAUTH2_CLIENT_SECRET
);
652 tmp
[sizeof(tmp
)-1] = '\0';
653 (*cl
)->varname
= cpystr(tmp
);
655 (*cl
)->valoffset
= ln
+ 3 + 3;
656 (*cl
)->value
= pretty_value(ps_global
, *cl
);
657 (*cl
)->keymenu
= &config_xoauth2_text_keymenu
;
658 (*cl
)->help
= h_config_xoauth2_client_secret
;
659 (*cl
)->tool
= text_tool
;
660 (*cl
)->varnamep
= ctmpb
;
663 /* Set up tenant variable */
665 varlist
[p
] = fs_get(sizeof(struct variable
));
666 memset((void *) varlist
[p
], 0, sizeof(struct variable
));
667 varlist
[p
]->name
= cpystr(XOAUTH2_TENANT
);
668 varlist
[p
]->is_used
= 1;
669 varlist
[p
]->is_user
= 1;
670 varlist
[p
]->main_user_val
.p
= y
->tenant
&& strcmp(x
->tenant
, y
->tenant
)
671 ? cpystr(x
->tenant
) : NULL
;
672 varlist
[p
]->global_val
.p
= y
->tenant
? cpystr(y
->tenant
) : NULL
;
673 varlist
[p
]->dname
= cpystr(tmp2
); /* hack, but makes life easier! */
674 varlist
[p
]->descrip
= cpystr(x
->name
); /* hack, but makes life easier! */
675 set_current_val(varlist
[p
], FALSE
, FALSE
);
677 /* Write client-secret variable */
678 new_confline(cl
)->var
= varlist
[p
];
679 utf8_snprintf(tmp
, sizeof(tmp
), " %-*.100w =", ln
, XOAUTH2_TENANT
);
680 tmp
[sizeof(tmp
)-1] = '\0';
681 (*cl
)->varname
= cpystr(tmp
);
683 (*cl
)->valoffset
= ln
+ 3 + 3;
684 (*cl
)->value
= pretty_value(ps_global
, *cl
);
685 (*cl
)->keymenu
= &config_xoauth2_text_keymenu
;
686 (*cl
)->help
= h_config_xoauth2_tenant
;
687 (*cl
)->tool
= text_tool
;
688 (*cl
)->varnamep
= ctmpb
;
691 /* Setup users variable */
692 varlist
[p
] = fs_get(sizeof(struct variable
));
693 memset((void *) varlist
[p
], 0, sizeof(struct variable
));
694 varlist
[p
]->name
= cpystr(XOAUTH2_USERS
);
695 varlist
[p
]->is_used
= 1;
696 varlist
[p
]->is_user
= 1;
697 varlist
[p
]->is_list
= 1;
698 varlist
[p
]->main_user_val
.l
= x
->users
? array_to_list(x
->users
) : NULL
;
699 varlist
[p
]->dname
= cpystr(tmp2
); /* hack, but makes life easier! */
700 varlist
[p
]->descrip
= cpystr(x
->name
); /* hack, but makes life easier! */
701 set_current_val(varlist
[p
], FALSE
, FALSE
);
703 /* Write user variable */
704 new_confline(cl
)->var
= varlist
[p
];
705 utf8_snprintf(tmp
, sizeof(tmp
), " %-*.100w =", ln
, XOAUTH2_USERS
);
706 tmp
[sizeof(tmp
)-1] = '\0';
707 (*cl
)->varname
= cpystr(tmp
);
708 (*cl
)->valoffset
= ln
+ 3 + 3;
709 (*cl
)->keymenu
= &config_xoauth2_wshuf_keymenu
;
710 (*cl
)->help
= h_config_xoauth2_username
;
713 for(z
= 0; varlist
[p
]->main_user_val
.l
[z
]; z
++){
714 if(z
) new_confline(cl
);
715 (*cl
)->var
= varlist
[p
];
717 (*cl
)->valoffset
= ln
+ 3 + 3;
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
;
726 (*cl
)->value
= pretty_value(ps_global
, *cl
);
727 (*cl
)->keymenu
= &config_xoauth2_wshuf_keymenu
;
728 (*cl
)->tool
= text_tool
;
729 (*cl
)->varnamep
= ctmpb
= *cl
;
736 /* Separate servers with a blank line */
738 (*cl
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
741 /*----------------------------------------------------------------------
742 Screen to add client_id and client_secret for a service
746 alpine_xoauth2_configuration(struct pine
*ps
, int edit_exceptions
)
748 struct variable
**varlist
= NULL
;
749 char tmp
[MAXPATH
+1], *pval
, **lval
, ***alval
;
750 char *s
, *extraname
= NULL
;
751 char *name
, *id
, *tenant
, *secret
, **user
;
752 char *name_lval
, *id_lval
, *tenant_lval
, *secret_lval
, *user_lval
,
753 *id_def
, *tenant_def
, *secret_def
;
754 int i
, j
, k
, l
, p
, q
, ln
= 0, readonly_warning
= 0, pos
;
755 CONF_S
*ctmpa
= NULL
, *ctmpb
, *first_line
;
757 PINERC_S
*prc
= NULL
;
759 int expose_hidden_config
, add_hidden_vars_title
= 0;
760 SAVED_CONFIG_S
*vsave
;
761 XOAUTH2_INFO_S x
, *y
;
763 dprint((3, "-- alpine_xoauth2_configuration --\n"));
765 expose_hidden_config
= F_ON(F_EXPOSE_HIDDEN_CONFIG
, ps_global
);
766 ew
= edit_exceptions
? ps_global
->ew_for_except_vars
: Main
;
769 readonly_warning
= 1;
782 readonly_warning
= prc
? prc
->readonly
: 1;
785 ps
->next_screen
= SCREEN_FUN_NULL
;
787 mailcap_free(); /* free resources we won't be using for a while */
790 ln
= strlen(XOAUTH2_CLIENT_ID
);
791 i
= strlen(XOAUTH2_CLIENT_SECRET
);
793 i
= strlen(XOAUTH2_TENANT
);
795 i
= strlen(XOAUTH2_USERS
);
798 alval
= ALVAL(&ps
->vars
[V_XOAUTH2_INFO
], ew
);
799 lval
= *alval
= xoauth2_conf_dedup_and_merge(alval
);
800 set_current_val(&ps_global
->vars
[V_XOAUTH2_INFO
], FALSE
, FALSE
);
801 write_pinerc(ps_global
, ew
, WRP_NONE
);
804 ctmpa
= first_line
= NULL
;
806 for(i
= 0, p
= 0; xoauth_default
[i
].name
!= NULL
; i
++){
807 /* always start with the default configuration */
808 for(k
= 0, q
= 0; lval
&& lval
[k
]; k
++){
809 y
= xoauth_parse_client_info(lval
[k
]);
810 if(same_xoauth2_info(xoauth_default
[i
], *y
))
812 free_xoauth2_info(&y
);
814 if(lval
== NULL
|| lval
[k
] == NULL
)
815 write_xoauth_conf_entry(&xoauth_default
[i
], &xoauth_default
[i
], &ctmpa
, &ctmpb
,
816 &first_line
, &varlist
, &p
, ln
, -i
-1);
817 for(k
= 0, q
= 0; lval
&& lval
[k
]; k
++){
818 y
= xoauth_parse_client_info(lval
[k
]);
819 if(y
&& (!y
->name
|| strcmp(y
->name
, xoauth_default
[i
].name
))){
820 free_xoauth2_info(&y
);
823 if(y
->client_id
== NULL
)
824 y
->client_id
= cpystr(xoauth_default
[i
].client_id
);
825 if(y
->client_secret
== NULL
&& xoauth_default
[i
].client_secret
!= NULL
)
826 y
->client_secret
= cpystr(xoauth_default
[i
].client_secret
);
827 if(y
->tenant
== NULL
&& xoauth_default
[i
].tenant
!= NULL
)
828 y
->tenant
= cpystr(xoauth_default
[i
].tenant
);
829 write_xoauth_conf_entry(y
, &xoauth_default
[i
], &ctmpa
, &ctmpb
, &first_line
, &varlist
, &p
, ln
, k
);
830 free_xoauth2_info(&y
);
834 vsave
= save_config_vars(ps
, expose_hidden_config
);
835 first_line
= pos
< 0 ? first_sel_confline(first_line
) : set_confline_number(first_line
, pos
);
837 memset(&screen
, 0, sizeof(screen
));
838 screen
.ro_warning
= readonly_warning
;
839 /* TRANSLATORS: Print something1 using something2.
840 "configuration" is something1 */
841 switch(conf_scroll_screen(ps
, &screen
, first_line
, "XOAUTH2 Alpine Info",
842 _("configuration"), 0, &pos
)){
847 write_xoauth_configuration(&ps
->vars
[V_XOAUTH2_INFO
], varlist
, ew
);
848 write_pinerc(ps
, ew
, WRP_NONE
);
851 case 4: /* add a service */
852 {char service
[MAILTMPLEN
+1];
853 char prompt
[MAILTMPLEN
+1];
854 int flags
= OE_DISALLOW_HELP
;
855 strncpy(prompt
, _("Enter service name: "), sizeof(prompt
));
856 prompt
[sizeof(prompt
) - 1] = '\0';
858 if(optionally_enter(service
,
859 -(ps_global
->ttyo
? FOOTER_ROWS(ps_global
) : 3),
860 0, sizeof(service
), prompt
, NULL
, NO_HELP
, &flags
) == 0){
861 for(i
= 0; xoauth_default
[i
].name
!= NULL
&& strucmp(xoauth_default
[i
].name
, service
); i
++);
862 if(xoauth_default
[i
].name
== NULL
)
863 q_status_message1(SM_ORDER
, 3, 3, _("Service %s not known"), service
);
867 ps_global
->mangled_screen
= 1;
868 for(j
= 0; lval
&& lval
[j
]; j
++);
869 list
= fs_get((j
+2)*sizeof(char *));
870 memset((void *)list
, 0, (j
+2)*sizeof(char *));
871 list
[0] = xoauth_config_line(&xoauth_default
[i
]);
872 for(i
= 0; lval
&& lval
[i
]; i
++)
873 list
[i
+1] = cpystr(lval
[i
]);
874 if(lval
) free_list_array(&lval
);
875 *alval
= lval
= list
;
876 for(i
= 0; varlist
&& varlist
[i
]; i
++){
877 free_variable_values(varlist
[i
]);
878 if(varlist
[i
]->descrip
) fs_give((void **) &varlist
[i
]->descrip
);
879 if(varlist
[i
]->dname
) fs_give((void **) &varlist
[i
]->dname
);
880 fs_give((void **) &varlist
[i
]);
882 if(varlist
) fs_give((void **) varlist
);
888 case 5: /* delete a service */
891 char question
[MAILTMPLEN
];
893 for(i
= 0, m
= 1, j
= 0; varlist
[i
] && m
< pos
;)
894 if(!varlist
[i
]->is_list
){
897 if(varlist
[i
]->current_val
.l
[j
++]) m
++;
902 key
= atoi(varlist
[i
]->dname
); /* this hack avoids we rebuild varlist again */
904 x
= xoauth_parse_client_info(lval
[key
]);
905 snprintf(question
, sizeof(question
), _("Delete this configuration for %s "), x
->name
);
906 free_xoauth2_info(&x
);
907 if(want_to(question
, 'n', 'n', NO_HELP
, WT_NORM
) != 'y')
909 for(i
= key
; lval
&& lval
[i
] && lval
[i
+1]; i
++){
910 fs_give((void **) &lval
[i
]);
911 lval
[i
] = cpystr(lval
[i
+1]);
913 fs_give((void **) &lval
[i
]);
916 q_status_message(SM_ORDER
, 3, 3, _("Cannot delete default configuration"));
919 if(lval
&& lval
[0] == NULL
)
920 free_list_array(&lval
);
922 pos
= 1; /* reset at the top */
923 for(i
= 0; varlist
&& varlist
[i
]; i
++){
924 free_variable_values(varlist
[i
]);
925 if(varlist
[i
]->descrip
) fs_give((void **) &varlist
[i
]->descrip
);
926 if(varlist
[i
]->dname
) fs_give((void **) &varlist
[i
]->dname
);
927 fs_give((void **) &varlist
[i
]);
929 if(varlist
) fs_give((void **) varlist
);
934 revert_to_saved_config(ps
, vsave
, expose_hidden_config
);
936 prc
->outstanding_pinerc_changes
= 0;
940 q_status_message(SM_ORDER
,7,10,
941 "conf_scroll_screen bad ret, not supposed to happen");
946 for(i
= 0; varlist
&& varlist
[i
]; i
++){
947 free_variable_values(varlist
[i
]);
948 if(varlist
[i
]->descrip
) fs_give((void **) &varlist
[i
]->descrip
);
949 if(varlist
[i
]->dname
) fs_give((void **) &varlist
[i
]->dname
);
950 fs_give((void **) &varlist
[i
]);
952 if(varlist
) fs_give((void **) varlist
);
955 mswin_set_quit_confirm (F_OFF(F_QUIT_WO_CONFIRM
, ps_global
));