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"
20 #include "confscroll.h"
21 #include "../pith/state.h"
22 #include "../pith/conf.h"
23 #include "../pith/list.h"
25 extern OAUTH2_S alpine_oauth2_list
[];
27 XOAUTH2_INFO_S xoauth_default
[] = {
28 { GMAIL_NAME
, GMAIL_ID
, GMAIL_SECRET
},
30 { OUTLOOK_NAME
, OUTLOOK_ID
, OUTLOOK_SECRET
},
36 #define NXSERVERS (sizeof(xoauth_default)/sizeof(xoauth_default[0])-1)
37 #define XOAUTH2_CLIENT_ID _("Client-Id")
38 #define XOAUTH2_CLIENT_SECRET _("Client-Secret")
39 #define XNAME "/NAME="
41 #define XSECRET "/SECRET="
43 void write_xoauth_configuration(struct variable
*, struct variable
**, EditWhich
);
46 xoauth_config_line(char *server
, char *id
, char *secret
)
51 n
= strlen(XNAME
) + strlen(XID
) + strlen(XSECRET
)
52 + strlen(server
) + strlen(id
) + strlen(secret
) + 9;
53 rv
= fs_get(n
*sizeof(char));
54 sprintf(rv
, "%s\"%s\" %s\"%s\" %s\"%s\"", XNAME
, server
, XID
, id
,
59 /* call this function when id and secret are unknown.
60 * precedence is as follows:
61 * If the user has configured something, return that;
62 * else if we are already using a value, return that;
63 * else return default values.
66 oauth2_get_client_info(unsigned char *name
, char **id
, char **secret
)
69 char **lval
, *name_lval
, *idp
, *secretp
;
73 /* first check the value configured by the user */
74 lval
= ps_global
->vars
[V_XOAUTH2_INFO
].current_val
.l
;
75 for(i
= 0; lval
&& lval
[i
]; i
++){
76 xoauth_parse_client_info(lval
[i
], &name_lval
, &idp
, &secretp
);
77 if(name_lval
&& !strcmp(name_lval
, name
)){
78 *id
= idp
? cpystr(idp
) : NULL
;
79 *secret
= secretp
? cpystr(secretp
) : NULL
;
81 if(name_lval
) fs_give((void **) &name_lval
);
82 if(idp
) fs_give((void **) &idp
);
83 if(secretp
) fs_give((void **) &secretp
);
87 if(*id
&& **id
&& *secret
&& **secret
) return;
89 /* if not, now see if we already have a value set, and use that */
90 for(i
= 0; alpine_oauth2_list
[i
].name
!= NULL
; i
++){
91 if(!strcmp(alpine_oauth2_list
[i
].name
, name
)){
92 *id
= alpine_oauth2_list
[i
].param
[OA2_Id
].value
93 ? cpystr(alpine_oauth2_list
[i
].param
[OA2_Id
].value
) : NULL
;
94 *secret
= alpine_oauth2_list
[i
].param
[OA2_Secret
].value
95 ? cpystr(alpine_oauth2_list
[i
].param
[OA2_Secret
].value
) : NULL
;
100 if(*id
&& **id
&& *secret
&& **secret
) return;
102 /* if nothing, use the default value */
103 for(i
= 0; xoauth_default
[i
].name
!= NULL
; i
++)
104 if(!strcmp(xoauth_default
[i
].name
, name
)){
105 *id
= cpystr(xoauth_default
[i
].client_id
);
106 *secret
= cpystr(xoauth_default
[i
].client_secret
);
112 * Each vlist member is of type "p", while "v" is of type "l", so we
113 * each entry in "l" by using each of the "p" entries.
116 write_xoauth_configuration(struct variable
*v
, struct variable
**vlist
, EditWhich ew
)
120 char ***alval
, **lval
, *p
, *q
, *l
;
122 alval
= ALVAL(v
, ew
);
123 for (i
= 0, k
= 0; vlist
[i
] != NULL
;){
124 if(PVAL(vlist
[i
], ew
)){
125 j
= i
/2; /* this is the location in the alpine_oauth2_list array */
126 i
= 2*j
; /* reset i */
127 p
= PVAL(vlist
[i
], ew
);
128 if(p
== NULL
) p
= vlist
[i
]->current_val
.p
;
129 q
= PVAL(vlist
[i
+1], ew
);
130 if(q
== NULL
) q
= vlist
[i
+1]->current_val
.p
;
131 if(k
== 0) lval
= fs_get((NXSERVERS
+1)*sizeof(char *));
132 lval
[k
++] = xoauth_config_line(alpine_oauth2_list
[j
].name
, p
, q
);
133 if(alpine_oauth2_list
[j
].param
[OA2_Id
].value
)
134 fs_give((void **) &alpine_oauth2_list
[j
].param
[OA2_Id
].value
);
135 if(alpine_oauth2_list
[j
].param
[OA2_Secret
].value
)
136 fs_give((void **) &alpine_oauth2_list
[j
].param
[OA2_Secret
].value
);
137 alpine_oauth2_list
[j
].param
[OA2_Id
].value
= cpystr(p
);
138 alpine_oauth2_list
[j
].param
[OA2_Secret
].value
= cpystr(q
);
145 if(*alval
) free_list_array(alval
);
150 set_current_val(&ps_global
->vars
[V_XOAUTH2_INFO
], FALSE
, FALSE
);
154 /* parse line of the form
155 /NAME="text" /ID="text" /SECRET="text"
158 xoauth_parse_client_info(char *lvalp
, char **namep
, char **idp
, char **secretp
)
161 *namep
= *idp
= *secretp
= NULL
;
163 if (lvalp
== NULL
) return;
165 if((s
= strstr(lvalp
, XNAME
)) != NULL
){
168 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
175 if((s
= strstr(lvalp
, XID
)) != NULL
){
178 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
185 if((s
= strstr(lvalp
, XSECRET
)) != NULL
){
186 s
+= strlen(XSECRET
);
188 for(t
= s
; *t
&& *t
!= '"' && *t
!= ' '; t
++);
191 *secretp
= cpystr(s
);
197 /*----------------------------------------------------------------------
198 Screen to add client_id and client_secret for a service
202 alpine_xoauth2_configuration(struct pine
*ps
, int edit_exceptions
)
204 struct variable gmail_client_id_var
, gmail_client_secret_var
;
206 struct variable outlook_client_id_var
, outlook_client_secret_var
;
208 struct variable
*varlist
[2*NXSERVERS
+ 1];
209 char tmp
[MAXPATH
+1], *pval
, **lval
;
211 char *name_lval
, *id_lval
, *id_conf
, *id_def
, *secret_lval
, *secret_conf
, *secret_def
;
212 int i
, j
, k
, l
, ln
= 0, readonly_warning
= 0, pos
;
213 CONF_S
*ctmpa
= NULL
, *ctmpb
, *first_line
= NULL
;
215 PINERC_S
*prc
= NULL
;
217 int expose_hidden_config
, add_hidden_vars_title
= 0;
218 SAVED_CONFIG_S
*vsave
;
220 dprint((3, "-- alpine_xoauth2_configuration --\n"));
222 expose_hidden_config
= F_ON(F_EXPOSE_HIDDEN_CONFIG
, ps_global
);
223 ew
= edit_exceptions
? ps_global
->ew_for_except_vars
: Main
;
226 readonly_warning
= 1;
239 readonly_warning
= prc
? prc
->readonly
: 1;
242 ps
->next_screen
= SCREEN_FUN_NULL
;
244 mailcap_free(); /* free resources we won't be using for a while */
246 varlist
[0] = &gmail_client_id_var
;
247 varlist
[1] = &gmail_client_secret_var
;
249 varlist
[2] = &outlook_client_id_var
;
250 varlist
[3] = &outlook_client_secret_var
;
252 varlist
[2*NXSERVERS
] = NULL
;
254 for(i
= 0; i
< 2*NXSERVERS
; i
++)
255 memset((void *) varlist
[i
], 0, sizeof(struct variable
));
259 ctmpa
= first_line
= NULL
;
261 ln
= strlen(XOAUTH2_CLIENT_ID
);
262 i
= strlen(XOAUTH2_CLIENT_SECRET
);
265 lval
= LVAL(&ps
->vars
[V_XOAUTH2_INFO
], ew
);
267 for(i
= 0, l
= 0; alpine_oauth2_list
[i
].name
!= NULL
; i
++){
268 id_conf
= id_def
= secret_conf
= secret_def
= NULL
;
269 name_lval
= id_lval
= secret_lval
= NULL
;
271 id_conf
= alpine_oauth2_list
[i
].param
[OA2_Id
].value
;
272 secret_conf
= alpine_oauth2_list
[i
].param
[OA2_Secret
].value
;
274 for(j
= 0; xoauth_default
[j
].name
!= NULL
; j
++)
275 if(!strcmp(alpine_oauth2_list
[i
].name
, xoauth_default
[j
].name
))
278 if(xoauth_default
[j
].name
!= NULL
){
279 id_def
= xoauth_default
[j
].client_id
;
280 secret_def
= xoauth_default
[j
].client_secret
;
283 /* fix this: the purpose is to search for the name in lval */
284 for(k
= 0; lval
&& lval
[k
]; k
++){
285 xoauth_parse_client_info(lval
[k
], &name_lval
, &id_lval
, &secret_lval
);
286 if(name_lval
&& !strcmp(name_lval
, alpine_oauth2_list
[i
].name
))
288 if (name_lval
) fs_give((void **) &name_lval
);
289 if (id_lval
) fs_give((void **) &id_lval
);
290 if (secret_lval
) fs_give((void **) &secret_lval
);
293 /* Here we have three values. The one being used by c-client in
294 * id_conf, secret_conf. The default value in Alpine, obtained
295 * by the programmer by registering Alpine, and the value
296 * configured in Alpine by the user in id_lval, and secret_lval.
299 * 1. If id_lval && secret_lval are not null, we use those.
300 * 2. else we use the default values.
302 id
= id_lval
? id_lval
: id_def
;
303 secret
= secret_lval
? secret_lval
: secret_def
;
305 new_confline(&ctmpa
)->var
= NULL
;
306 if(!first_line
) first_line
= ctmpa
;
308 /* Write Name of provider first */
309 ctmpa
->flags
|= CF_NOSELECT
;
310 ctmpa
->help
= NO_HELP
;
311 ctmpa
->valoffset
= 1;
312 ctmpa
->value
= cpystr(alpine_oauth2_list
[i
].name
);
313 ctmpa
->varname
= NULL
;
314 ctmpa
->varnamep
= ctmpb
= ctmpa
;
317 /* Setup client-id variable */
318 varlist
[l
]->name
= cpystr(XOAUTH2_CLIENT_ID
);
319 varlist
[l
]->is_used
= 1;
320 varlist
[l
]->is_user
= 1;
321 varlist
[l
]->main_user_val
.p
= strcmp(id
, id_def
)? cpystr(id
) : NULL
;
322 varlist
[l
]->global_val
.p
= cpystr(id_def
);
323 set_current_val(varlist
[l
], FALSE
, FALSE
);
325 /* Write client-id variable */
326 new_confline(&ctmpa
)->var
= varlist
[l
];
327 utf8_snprintf(tmp
, sizeof(tmp
), " %-*.100w =", ln
, XOAUTH2_CLIENT_ID
);
328 tmp
[sizeof(tmp
)-1] = '\0';
329 ctmpa
->varname
= cpystr(tmp
);
331 ctmpa
->valoffset
= ln
+ 3 + 3;
332 ctmpa
->value
= pretty_value(ps
, ctmpa
);
333 ctmpa
->keymenu
= &config_text_keymenu
;
334 ctmpa
->help
= h_config_xoauth2_client_id
;
335 ctmpa
->tool
= text_tool
;
336 ctmpa
->varnamep
= ctmpb
;
338 /* Set up client-secret variable */
339 varlist
[l
]->name
= cpystr(XOAUTH2_CLIENT_SECRET
);
340 varlist
[l
]->is_used
= 1;
341 varlist
[l
]->is_user
= 1;
342 varlist
[l
]->main_user_val
.p
= strcmp(secret
, secret_def
) ? cpystr(secret
) : NULL
;
343 varlist
[l
]->global_val
.p
= cpystr(secret_def
);
344 set_current_val(varlist
[l
], FALSE
, FALSE
);
346 /* Write client-secret variable */
347 new_confline(&ctmpa
)->var
= varlist
[l
];
348 utf8_snprintf(tmp
, sizeof(tmp
), " %-*.100w =", ln
, XOAUTH2_CLIENT_SECRET
);
349 tmp
[sizeof(tmp
)-1] = '\0';
350 ctmpa
->varname
= cpystr(tmp
);
352 ctmpa
->valoffset
= ln
+ 3 + 3;
353 ctmpa
->value
= pretty_value(ps
, ctmpa
);
354 ctmpa
->keymenu
= &config_text_keymenu
;
355 ctmpa
->help
= h_config_xoauth2_client_secret
;
356 ctmpa
->tool
= text_tool
;
357 ctmpa
->varnamep
= ctmpb
;
359 /* Separate servers with a blank line */
360 new_confline(&ctmpa
);
361 ctmpa
->flags
|= CF_NOSELECT
| CF_B_LINE
;
363 /* clean up the house */
364 if(id_lval
) fs_give((void **) &id_lval
);
365 if(secret_lval
) fs_give((void **) &secret_lval
);
366 if(name_lval
) fs_give((void **) &name_lval
);
369 vsave
= save_config_vars(ps
, expose_hidden_config
);
370 first_line
= pos
< 0 ? first_sel_confline(first_line
) : set_confline_number(first_line
, pos
);
372 memset(&screen
, 0, sizeof(screen
));
373 screen
.ro_warning
= readonly_warning
;
374 /* TRANSLATORS: Print something1 using something2.
375 "configuration" is something1 */
376 switch(conf_scroll_screen(ps
, &screen
, first_line
, "XOAUTH2 Alpine Info",
377 _("configuration"), 0, &pos
)){
382 write_xoauth_configuration(&ps
->vars
[V_XOAUTH2_INFO
], varlist
, ew
);
383 write_pinerc(ps
, ew
, WRP_NONE
);
387 revert_to_saved_config(ps
, vsave
, expose_hidden_config
);
389 prc
->outstanding_pinerc_changes
= 0;
393 q_status_message(SM_ORDER
,7,10,
394 "conf_scroll_screen bad ret, not supposed to happen");
400 mswin_set_quit_confirm (F_OFF(F_QUIT_WO_CONFIRM
, ps_global
));