* Addition of a link to the Apache License 2.0. This is available from
[alpine.git] / alpine / xoauth2conf.c
blobf21697c28af15a1420393eaae2c900ff871adde2
1 /*
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 * ========================================================================
15 #include "headers.h"
16 #include "xoauth2conf.h"
17 #include "keymenu.h"
18 #include "status.h"
19 #include "confscroll.h"
20 #include "init.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 {
37 char *screen_name;
38 char *pinerc_name;
39 } XOAUTH2_INFO_VAL_S;
41 /* the order here must match the order in XTYPES above */
42 XOAUTH2_INFO_VAL_S x_default[] = {
43 {NULL, "/NAME="},
44 {"Client-Id", "/ID="},
45 {"Client-Secret", "/SECRET="},
46 {"Tenant", "/TENANT="},
47 {"Username", "/USER="},
48 {NULL, NULL}
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);
70 int
71 same_xoauth2_info(XOAUTH2_INFO_S x, XOAUTH2_INFO_S y)
73 int rv = 0;
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))))
79 rv = 1;
80 return rv;
83 char *
84 list_to_array(char **list)
86 char *rv;
87 int i;
88 size_t n;
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));
96 *rv = '\0';
97 for(i = 0; list[i] != NULL; i++){
98 strcat(rv, list[i]);
99 if(list[i+1] != NULL) strcat(rv, ",");
101 return rv;
105 char **array_to_list(char *array)
107 int i;
108 char *u;
110 if(array == NULL || *array == '\0') return NULL;
112 for(u = array, i = 0; u && *u; u++)
113 if(*u == ',') i++;
115 return parse_list(array, i+1, 0,NULL);
118 char *
119 xoauth_config_line(XOAUTH2_INFO_S *x)
121 size_t n;
122 char *rv;
123 int i;
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);
134 if(x->client_secret)
135 sprintf(rv + strlen(rv), " %s\"%s\"", XSECRET, x->client_secret);
136 if(x->tenant)
137 sprintf(rv + strlen(rv), " %s\"%s\"", XTENANT, x->tenant);
138 sprintf(rv + strlen(rv), " %s\"%s\"", XUSER, x->users ? x->users : "");
139 return rv;
143 xoauth2_info_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
145 int rv = 0;
147 switch(cmd){
148 case MC_CHOICE:
149 *((*cl)->d.x.selected) = (*cl)->d.x.pat;
150 rv = simple_exit_cmd(flags);
152 case MC_EXIT:
153 rv = simple_exit_cmd(flags);
154 break;
156 default:
157 rv = -1;
160 if(rv > 0)
161 ps->mangled_body = 1;
163 return rv;
166 XOAUTH2_INFO_S *
167 xoauth_info_choice(XOAUTH2_INFO_S **xinfo, char *user)
169 int i, n, rv;
170 if(!ps_global->ttyo){
171 char *s;
172 char prompt[1024];
173 char reply[1024];
174 int sel;
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;
195 } while (rv != 0);
196 return copy_xoauth2_info(xinfo[rv]);
198 else{
199 CONF_S *ctmp = NULL, *first_line = NULL;
200 XOAUTH2_INFO_S *x_sel = NULL;
201 OPT_SCREEN_S screen;
202 char tmp[1024];
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++)
210 tmp[i] = '-';
211 tmp[i] = '\0';
213 new_confline(&ctmp);
214 ctmp->flags |= CF_NOSELECT;
215 ctmp->value = cpystr(tmp);
217 new_confline(&ctmp);
218 ctmp->flags |= CF_NOSELECT;
219 ctmp->value = cpystr(_("Select a Client-ID to use with this account"));
221 new_confline(&ctmp);
222 ctmp->flags |= CF_NOSELECT;
223 ctmp->value = cpystr(tmp);
225 new_confline(&ctmp);
226 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
228 sprintf(tmp, _("Alpine cannot determine which client-id to use for the username <%s>"), user);
229 new_confline(&ctmp);
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);
234 new_confline(&ctmp);
235 ctmp->flags |= CF_NOSELECT;
236 ctmp->value = cpystr(tmp);
238 new_confline(&ctmp);
239 ctmp->flags |= CF_NOSELECT | CF_B_LINE;
241 for(i = 0; xinfo[i] != NULL; i++){
242 new_confline(&ctmp);
243 if(!first_line)
244 first_line = ctmp;
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;
254 ctmp->valoffset = 4;
256 (void)conf_scroll_screen(ps_global, &screen, first_line, _("SELECT CLIENT_ID"),
257 _("xoauth2"), 0, NULL);
258 return x_sel;
260 return NULL;
263 /* Get the client-id, etc. for server "name" associated to user "user" */
264 XOAUTH2_INFO_S *
265 oauth2_get_client_info(unsigned char *name, char *user)
267 int i, j, matches;
268 char ***alval, **lval;
269 XOAUTH2_INFO_S *x, **xinfo;
271 if(name == NULL || *name == '\0' || user == NULL || *user == '\0')
272 return NULL;
274 matches = 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))
280 matches++;
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 */
309 if(matches == 1){
310 x = copy_xoauth2_info(xinfo[0]);
311 free_xoauth2_info(&xinfo[0]);
312 fs_give((void **) xinfo);
313 return x;
316 /* we have more than one match, now check if any of them matches the given user */
317 matches = 0;
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++);
321 if(lval && lval[j]){
322 matches++;
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 */
330 if(matches == 1){
331 for(i = 0; xinfo[i] != NULL; i++)
332 free_xoauth2_info(&xinfo[i]);
333 fs_give((void **) xinfo);
334 return x;
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 */
346 if(x != NULL){
347 int n = x->users ? strlen(x->users) + 1 : 0;
348 char ***alval, **l;
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);
355 lval = *alval;
357 for(n = 0; lval && lval[n]; n++);
358 fs_resize((void **) &lval, (n+2)*sizeof(char *));
359 lval[n] = xoauth_config_line(x);
360 lval[n+1] = NULL;
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);
366 return x;
369 /* write vlist to v
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.
373 void
374 write_xoauth_configuration(struct variable *v, struct variable **vlist, EditWhich ew)
376 int i, j, k, m, n;
377 XOAUTH2_INFO_S *x = NULL, *y;
378 char ***alval, **lval, **l;
379 char *p;
381 for (i = 0, n = 0; vlist[i] != NULL; i++) /* count number of lines we need */
382 if(!strcmp(vlist[i]->name, XOAUTH2_USERS))
383 n++;
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++){
389 if(x == NULL){
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;
398 if(p != NULL)
399 x->client_id = cpystr(p);
400 continue;
402 if (x->client_secret == NULL
403 && m >= 0
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;
408 if(p != NULL)
409 x->client_secret = cpystr(p);
410 continue;
412 if (x->tenant == NULL
413 && m >= 0
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;
418 if(p != NULL)
419 x->tenant = cpystr(p);
420 continue;
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);
440 if(k > 0){
441 lval[k] = NULL;
442 if(*alval) free_list_array(alval);
443 *alval = lval;
445 else
446 *alval = NULL;
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"
454 XOAUTH2_INFO_S *
455 xoauth_parse_client_info(char *lvalp)
457 char *s, *t, c;
458 XOAUTH2_INFO_S *x;
460 if (lvalp == NULL) return NULL;
462 x = new_xoauth2_info();
463 if((s = strstr(lvalp, XNAME)) != NULL){
464 s += strlen(XNAME);
465 if(*s == '"') s++;
466 for(t = s; *t && *t != '"' && *t != ' '; t++);
467 c = *t;
468 *t = '\0';
469 if (*s) x->name = cpystr(s);
470 *t = c;
471 } else x->name = NULL;
473 if((s = strstr(lvalp, XID)) != NULL){
474 s += strlen(XID);
475 if(*s == '"') s++;
476 for(t = s; *t && *t != '"' && *t != ' '; t++);
477 c = *t;
478 *t = '\0';
479 if (*s) x->client_id = cpystr(s);
480 *t = c;
481 } else x->client_id = NULL;
483 if((s = strstr(lvalp, XTENANT)) != NULL){
484 s += strlen(XTENANT);
485 if(*s == '"') s++;
486 for(t = s; *t && *t != '"' && *t != ' '; t++);
487 c = *t;
488 *t = '\0';
489 if (*s) x->tenant = cpystr(s);
490 *t = c;
491 } else x->tenant = NULL;
493 if((s = strstr(lvalp, XSECRET)) != NULL){
494 s += strlen(XSECRET);
495 if(*s == '"') s++;
496 for(t = s; *t && *t != '"' && *t != ' '; t++);
497 c = *t;
498 *t = '\0';
499 if (*s) x->client_secret = cpystr(s);
500 *t = c;
501 } else x->client_secret = NULL;
503 if((s = strstr(lvalp, XUSER)) != NULL){
504 s += strlen(XUSER);
505 if(*s == '"') s++;
506 for(t = s; *t && *t != '"' && *t != ' '; t++);
507 c = *t;
508 *t = '\0';
509 if(*s) x->users = cpystr(s);
510 *t = c;
511 } else x->users = NULL;
513 return x;
516 char **
517 xoauth2_conf_dedup_and_merge(char ***alval)
519 int i, j, k, l, n, m;
520 char **lval, **rv;
521 XOAUTH2_INFO_S *x, *y;
523 if(alval == NULL || *alval == NULL || **alval == NULL)
524 return NULL;
526 lval = *alval;
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;
539 int k, n;
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]);
559 l3[n++] = NULL;
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);
569 break;
571 free_xoauth2_info(&y);
573 if(rv[j] == NULL) rv[j] = cpystr(lval[i]);
575 return rv;
579 * X = new value, Y = default configuration
581 void
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;
587 int i, p = *pp;
588 char tmp[1024], tmp2[16];
590 i = 2; /* client_id and users always appear */
591 if(x->client_secret) i++;
592 if(x->tenant) 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 *));
597 varlist = *varlistp;
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);
626 (*cl)->varmem = p++;
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);
654 (*cl)->varmem = p++;
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 */
664 if(x->tenant){
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);
682 (*cl)->varmem = p++;
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;
711 if(x->users){
712 int z;
713 for(z = 0; varlist[p]->main_user_val.l[z]; z++){
714 if(z) new_confline(cl);
715 (*cl)->var = varlist[p];
716 (*cl)->varmem = z;
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;
724 else {
725 (*cl)->varmem = 0;
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;
731 p++;
732 *pp = p;
733 *varlistp = varlist;
734 *clb = ctmpb;
736 /* Separate servers with a blank line */
737 new_confline(cl);
738 (*cl)->flags |= CF_NOSELECT | CF_B_LINE;
741 /*----------------------------------------------------------------------
742 Screen to add client_id and client_secret for a service
744 ---*/
745 void
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;
756 FEATURE_S *feature;
757 PINERC_S *prc = NULL;
758 OPT_SCREEN_S screen;
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;
768 if(ps->restricted)
769 readonly_warning = 1;
770 else{
771 switch(ew){
772 case Main:
773 prc = ps->prc;
774 break;
775 case Post:
776 prc = ps->post_prc;
777 break;
778 default:
779 break;
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 */
789 pos = -1;
790 ln = strlen(XOAUTH2_CLIENT_ID);
791 i = strlen(XOAUTH2_CLIENT_SECRET);
792 if(ln < i) ln = i;
793 i = strlen(XOAUTH2_TENANT);
794 if(ln < i) ln = i;
795 i = strlen(XOAUTH2_USERS);
796 if(ln < i) ln = i;
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);
803 do {
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))
811 break;
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);
821 continue;
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);
836 pos = -1;
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)){
843 case 0:
844 break;
846 case 1:
847 write_xoauth_configuration(&ps->vars[V_XOAUTH2_INFO], varlist, ew);
848 write_pinerc(ps, ew, WRP_NONE);
849 break;
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';
857 service[0] = '\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);
864 else{
865 char **list;
866 ClearScreen();
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);
886 break;
888 case 5: /* delete a service */
889 { int m, key;
890 XOAUTH2_INFO_S *x;
891 char question[MAILTMPLEN];
893 for(i = 0, m = 1, j = 0; varlist[i] && m < pos;)
894 if(!varlist[i]->is_list){
895 i++; m++;
896 } else {
897 if(varlist[i]->current_val.l[j++]) m++;
898 else{
899 j = 0; m += 2; i++;
902 key = atoi(varlist[i]->dname); /* this hack avoids we rebuild varlist again */
903 if(key >= 0){
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')
908 break;
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]);
915 else {
916 q_status_message(SM_ORDER, 3, 3, _("Cannot delete default configuration"));
917 break;
919 if(lval && lval[0] == NULL)
920 free_list_array(&lval);
921 *alval = 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);
931 break;
933 case 10:
934 revert_to_saved_config(ps, vsave, expose_hidden_config);
935 if(prc)
936 prc->outstanding_pinerc_changes = 0;
937 break;
939 default:
940 q_status_message(SM_ORDER,7,10,
941 "conf_scroll_screen bad ret, not supposed to happen");
942 break;
944 } while (pos >= 0);
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);
954 #ifdef _WINDOWS
955 mswin_set_quit_confirm (F_OFF(F_QUIT_WO_CONFIRM, ps_global));
956 #endif