You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

622 lines
18 KiB

/* pinentry-efl.c
Copyright (C) 2017 Obsidian-Studios, Inc.
Author William L. Thomson Jr. <wlt@o-sinc.com>
Based on pinentry-gtk2.c
Copyright (C) 1999 Robert Bihlmeyer <robbe@orcus.priv.at>
Copyright (C) 2001, 2002, 2007, 2015 g10 Code GmbH
Copyright (C) 2004 by Albrecht Dreß <albrecht.dress@arcor.de>
pinentry-efl is a pinentry application for the EFL widget set.
It tries to follow the Gnome Human Interface Guide as close as
possible.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <Elementary.h>
#include <Ecore_X.h>
#include <gpg-error.h>
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#endif
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
#pragma GCC diagnostic pop
#endif
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#else
#include "getopt.h"
#endif /* HAVE_GETOPT_H */
#include "pinentry.h"
#ifdef FALLBACK_CURSES
#include "pinentry-curses.h"
#endif
#define PGMNAME "pinentry-efl"
#ifndef VERSION
#define VERSION
#endif
#define ENTRY_HIDE "Hide entry"
#define ENTRY_SHOW "Show entry"
typedef enum { CONFIRM_CANCEL, CONFIRM_OK, CONFIRM_NOTOK } confirm_value_t;
static const int WIDTH = 480;
static const int BUTTON_HEIGHT = 27;
static const int BUTTON_WIDTH = 70;
static const int BUTTON_ICON_SIZE = 13;
static const int PADDING = 5;
static Eina_Bool got_input;
static Ecore_Timer *timer;
static Evas_Object *check_label;
static Evas_Object *error_label;
static Evas_Object *entry;
static Evas_Object *repeat_entry;
static Evas_Object *qualitybar;
static Evas_Object *win;
static char **pargv;
static int grab_failed;
static int passphrase_ok;
static int confirm_mode;
static int pargc;
static confirm_value_t confirm_value;
static pinentry_t pinentry;
pinentry_cmd_handler_t pinentry_cmd_handler;
static void
quit (void)
{
evas_object_del(win);
elm_exit();
ecore_main_loop_quit ();
}
static void
delete_event (void *data EINA_UNUSED,
Evas_Object *obj EINA_UNUSED,
void *event EINA_UNUSED)
{
pinentry->close_button = 1;
quit ();
}
static void
changed_text_handler (void *data EINA_UNUSED,
Evas_Object *obj,
void *event EINA_UNUSED)
{
const char *s;
int length;
int percent;
got_input = EINA_TRUE;
if (pinentry->repeat_passphrase && repeat_entry)
{
elm_object_text_set (repeat_entry, "");
elm_object_text_set (error_label, "");
}
if (!qualitybar || !pinentry->quality_bar)
return;
s = elm_object_text_get (obj);
if (!s)
s = "";
length = strlen (s);
percent = length? pinentry_inq_quality (pinentry, s, length) : 0;
evas_object_color_set(qualitybar,
255 - ( 2.55 * percent ),
2.55 * percent, 0, 255);
elm_progressbar_value_set (qualitybar, (double) percent / 100.0);
}
static void
on_check (void *data EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED)
{
if(elm_check_state_get(obj))
{
elm_entry_password_set(entry, EINA_FALSE);
elm_object_text_set(check_label,ENTRY_HIDE);
}
else
{
elm_entry_password_set(entry, EINA_TRUE);
elm_object_text_set(check_label,ENTRY_SHOW);
}
evas_object_size_hint_min_set(check_label,
ELM_SCALE_SIZE(BUTTON_WIDTH),
ELM_SCALE_SIZE(BUTTON_HEIGHT));
evas_object_size_hint_align_set(check_label, 0, 1);
}
static void
on_click (void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
{
if (confirm_mode)
{
confirm_value = (confirm_value_t) data;
quit ();
return;
}
if (data)
{
const char *s;
const char *s2;
s = elm_entry_entry_get (entry);
if (!s)
s = "";
if (pinentry->repeat_passphrase && repeat_entry)
{
s2 = elm_entry_entry_get (repeat_entry);
if (!s2)
s2 = "";
if (strcmp (s, s2))
{
elm_object_text_set(error_label,
pinentry->repeat_error_string?
pinentry->repeat_error_string:
"not correctly repeated");
elm_object_focus_set(entry,EINA_TRUE);
return;
}
pinentry->repeat_okay = 1;
}
passphrase_ok = 1;
pinentry_setbufferlen (pinentry, strlen (s) + 1);
if (pinentry->pin)
strncpy (pinentry->pin, s, strlen(s) + 1);
}
quit ();
}
static void
enter_callback (void *data, Evas_Object * obj, void *event_info EINA_UNUSED)
{
if (data)
elm_object_focus_set (data, 1);
else
on_click ((void *) CONFIRM_OK, obj, NULL);
}
static Eina_Bool
timeout_cb (const void * data)
{
pinentry_t pe = (pinentry_t)data;
if (!got_input)
{
ecore_main_loop_quit();
if (pe)
pe->specific_err = gpg_error (GPG_ERR_TIMEOUT);
}
timer = NULL;
return ECORE_CALLBACK_DONE;
}
static void
create_window (void)
{
char *txt;
Evas_Object *icon;
Evas_Object *obj;
Evas_Object *table;
int btn_txt_len = 0;
int row = 0;
int ok_len = 0;
win = elm_win_util_dialog_add(NULL,"pinentry","enter pin");
elm_win_autodel_set(win, EINA_TRUE);
elm_win_center(win,EINA_TRUE,EINA_TRUE);
evas_object_smart_callback_add(win, "delete,request", delete_event, NULL);
table = elm_table_add(win);
elm_table_padding_set(table,ELM_SCALE_SIZE(PADDING),0);
evas_object_size_hint_padding_set (table,
ELM_SCALE_SIZE(PADDING),
ELM_SCALE_SIZE(PADDING),
ELM_SCALE_SIZE(PADDING),
ELM_SCALE_SIZE(PADDING));
evas_object_show(table);
if (pinentry->title)
{
txt = elm_entry_utf8_to_markup(pinentry->title);
elm_win_title_set ( win, txt );
free (txt);
}
/* Description Label */
if (pinentry->description)
{
char* aligned;
int len;
obj = elm_label_add(table);
elm_label_line_wrap_set (obj, ELM_WRAP_WORD);
txt = elm_entry_utf8_to_markup(pinentry->description);
len = strlen(txt)+20; // 20 chars for align tag
aligned = calloc(len+1,sizeof(char));
if(aligned)
{
snprintf(aligned,len, "<align=left>%s</align>",txt);
elm_object_text_set(obj,aligned);
free (aligned);
} else
elm_object_text_set(obj,txt);
free (txt);
evas_object_size_hint_weight_set(obj, EVAS_HINT_EXPAND, 0);
evas_object_size_hint_align_set(obj, EVAS_HINT_FILL, 0);
elm_table_pack(table, obj, 1, row, 5, 1);
evas_object_show(obj);
row++;
}
if (!confirm_mode && (pinentry->error || pinentry->repeat_passphrase))
{
/* Error Label */
if (pinentry->error)
txt = elm_entry_utf8_to_markup(pinentry->error);
else
txt = "";
obj = elm_label_add(table);
evas_object_color_set(obj, 255, 0, 0, 255);
elm_object_text_set(obj,txt);
elm_object_style_set(obj,"slide_bounce");
elm_label_slide_duration_set(obj, 10);
elm_label_slide_mode_set(obj, ELM_LABEL_SLIDE_MODE_ALWAYS);
elm_label_slide_go(obj);
evas_object_size_hint_weight_set(obj, EVAS_HINT_EXPAND, 0);
evas_object_size_hint_align_set(obj, EVAS_HINT_FILL, 0);
elm_table_pack(table, obj, 1, row, 5, 1);
evas_object_show(obj);
if (pinentry->error)
free (txt);
row++;
}
qualitybar = NULL;
if (!confirm_mode)
{
if (pinentry->prompt)
{
/* Entry/Prompt Label */
obj = elm_label_add(table);
txt = elm_entry_utf8_to_markup(pinentry->prompt);
elm_object_text_set(obj,txt);
free (txt);
evas_object_size_hint_weight_set(obj, 0, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(obj, 1, EVAS_HINT_FILL);
elm_table_pack(table, obj, 1, row, 1, 1);
evas_object_show(obj);
}
entry = elm_entry_add(table);
elm_entry_scrollable_set(entry, EINA_TRUE);
elm_scroller_policy_set(entry,
ELM_SCROLLER_POLICY_OFF,
ELM_SCROLLER_POLICY_OFF);
elm_entry_password_set(entry, EINA_TRUE);
elm_entry_single_line_set(entry, EINA_TRUE);
evas_object_size_hint_weight_set(entry, 0, 0);
evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, 0);
elm_table_pack(table, entry, 2, row, 4, 1);
evas_object_smart_callback_add(entry,
"changed",
changed_text_handler,
NULL);
evas_object_show(entry);
row++;
/* Check box */
obj = elm_check_add(table);
evas_object_size_hint_align_set(obj, 1, EVAS_HINT_FILL);
elm_table_pack(table, obj, 1, row, 1, 1);
evas_object_smart_callback_add(obj, "changed", on_check, NULL);
evas_object_show(obj);
/* Check Label */
check_label = elm_label_add(table);
on_check((void *)NULL, obj, (void *)NULL);
elm_table_pack(table, check_label, 2, row, 4, 1);
evas_object_show(check_label);
row++;
if (pinentry->quality_bar)
{
/* Quality Bar Label */
obj = elm_label_add(table);
txt = elm_entry_utf8_to_markup(pinentry->quality_bar);
elm_object_text_set(obj,txt);
free (txt);
evas_object_size_hint_weight_set(obj, 0, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(obj, 1, EVAS_HINT_FILL);
elm_table_pack(table, obj, 1, row, 1, 1);
evas_object_show(obj);
qualitybar = elm_progressbar_add(table);
evas_object_color_set(qualitybar, 255, 0, 0, 255);
evas_object_show(qualitybar);
if (pinentry->quality_bar_tt)
elm_object_tooltip_text_set (qualitybar,
pinentry->quality_bar_tt);
evas_object_size_hint_weight_set(qualitybar, EVAS_HINT_EXPAND, 0);
evas_object_size_hint_align_set(qualitybar, EVAS_HINT_FILL, 0);
elm_table_pack(table, qualitybar, 2, row, 4, 1);
row++;
}
if (pinentry->repeat_passphrase)
{
/* Repeat Label */
obj = elm_label_add(table);
txt = elm_entry_utf8_to_markup(pinentry->repeat_passphrase);
elm_object_text_set(obj,txt);
free (txt);
evas_object_size_hint_weight_set(obj, 0, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(obj, 1, EVAS_HINT_FILL);
elm_table_pack(table, obj, 1, row, 1, 1);
evas_object_show(obj);
repeat_entry = elm_entry_add(table);
elm_entry_scrollable_set(repeat_entry, EINA_TRUE);
elm_scroller_policy_set(repeat_entry,
ELM_SCROLLER_POLICY_OFF,
ELM_SCROLLER_POLICY_OFF);
elm_entry_password_set(repeat_entry, EINA_TRUE);
elm_entry_single_line_set(repeat_entry, EINA_TRUE);
evas_object_size_hint_weight_set(repeat_entry, 0, 0);
evas_object_size_hint_align_set(repeat_entry, EVAS_HINT_FILL, 0);
elm_table_pack(table, repeat_entry, 2, row, 4, 1);
evas_object_smart_callback_add (repeat_entry, "activated",
enter_callback, NULL);
evas_object_show(repeat_entry);
evas_object_smart_callback_add (entry,
"activated",
enter_callback,
repeat_entry);
evas_object_smart_callback_add(repeat_entry,
"activated",
on_click,
(void *) CONFIRM_OK);
row++;
}
else
evas_object_smart_callback_add(entry,
"activated",
on_click,
(void *) CONFIRM_OK);
}
/* Cancel Button */
if (!pinentry->one_button)
{
obj = elm_button_add(table);
icon = elm_icon_add (table);
evas_object_size_hint_aspect_set (icon, EVAS_ASPECT_CONTROL_BOTH, 1, 1);
if (elm_icon_standard_set (icon, "dialog-cancel") ||
elm_icon_standard_set (icon, "window-close"))
{
evas_object_size_hint_min_set(icon,
ELM_SCALE_SIZE(BUTTON_ICON_SIZE),
ELM_SCALE_SIZE(BUTTON_ICON_SIZE));
elm_object_part_content_set(obj, "icon", icon);
evas_object_show (icon);
}
else
evas_object_del(icon);
if (pinentry->cancel || pinentry->default_cancel)
{
if(pinentry->cancel)
txt = elm_entry_utf8_to_markup(pinentry->cancel);
else
txt = elm_entry_utf8_to_markup(pinentry->default_cancel);
if(txt[0]=='_')
elm_object_text_set(obj,txt+1);
else
elm_object_text_set(obj,txt);
btn_txt_len = ELM_SCALE_SIZE(strlen(txt) * (PADDING * 1.5));
free (txt);
}
else
elm_object_text_set(obj, "Cancel"); //STOCK_CANCEL
evas_object_size_hint_align_set(obj, 0, 0);
if(btn_txt_len>ELM_SCALE_SIZE(BUTTON_WIDTH))
evas_object_size_hint_min_set(obj,
btn_txt_len,
ELM_SCALE_SIZE(BUTTON_HEIGHT));
else
evas_object_size_hint_min_set(obj,
ELM_SCALE_SIZE(BUTTON_WIDTH),
ELM_SCALE_SIZE(BUTTON_HEIGHT));
elm_table_pack(table, obj, 4, row, 1, 1);
evas_object_smart_callback_add(obj,
"clicked",
on_click,
(void *) CONFIRM_CANCEL);
evas_object_show(obj);
}
/* OK Button */
obj = elm_button_add(table);
icon = elm_icon_add (table);
evas_object_size_hint_aspect_set (icon, EVAS_ASPECT_CONTROL_BOTH, 1, 1);
if (elm_icon_standard_set (icon, "dialog-ok") ||
elm_icon_standard_set (icon, "list-add"))
{
evas_object_size_hint_min_set(icon,
ELM_SCALE_SIZE(BUTTON_ICON_SIZE),
ELM_SCALE_SIZE(BUTTON_ICON_SIZE));
elm_object_part_content_set(obj, "icon", icon);
evas_object_show (icon);
}
else
evas_object_del(icon);
if (pinentry->ok || pinentry->default_ok)
{
if(pinentry->ok)
txt = elm_entry_utf8_to_markup(pinentry->ok);
else
txt = elm_entry_utf8_to_markup(pinentry->default_ok);
if(txt[0]=='_')
elm_object_text_set(obj,txt+1);
else
elm_object_text_set(obj,txt);
ok_len = ELM_SCALE_SIZE(strlen(txt) * (PADDING * 1.5));
if(ok_len>btn_txt_len)
btn_txt_len = ok_len;
free (txt);
}
else
elm_object_text_set(obj,"OK"); //STOCK_OK
evas_object_size_hint_align_set(obj, 0, 0);
if(btn_txt_len>ELM_SCALE_SIZE(BUTTON_WIDTH))
evas_object_size_hint_min_set(obj,
btn_txt_len,
ELM_SCALE_SIZE(BUTTON_HEIGHT));
else
evas_object_size_hint_min_set(obj,
ELM_SCALE_SIZE(BUTTON_WIDTH),
ELM_SCALE_SIZE(BUTTON_HEIGHT));
elm_table_pack(table, obj, 5, row, 1, 1);
evas_object_smart_callback_add(obj, "clicked", on_click, (void *) CONFIRM_OK);
evas_object_show(obj);
/* Key/Lock Icon */
obj = elm_icon_add (win);
evas_object_size_hint_aspect_set (obj, EVAS_ASPECT_CONTROL_BOTH, 1, 1);
if (elm_icon_standard_set (obj, "dialog-password"))
{
double ic_size = WIDTH/5;
if(row==0)
ic_size = ic_size/3.5;
else if(row<4)
ic_size = ic_size - ic_size/row;
evas_object_size_hint_min_set(obj,
ELM_SCALE_SIZE(ic_size),
ELM_SCALE_SIZE(ic_size));
evas_object_size_hint_weight_set(obj, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(obj, EVAS_HINT_FILL, 0.5);
elm_table_pack(table, obj, 0, 0, 1, row? row:1);
evas_object_show (obj);
}
else
evas_object_del(obj);
/* Box for padding */
obj = elm_box_add (win);
elm_box_pack_end (obj, table);
evas_object_show (obj);
elm_win_resize_object_add(win,obj);
if(entry)
elm_object_focus_set (entry, EINA_TRUE);
evas_object_show(win);
elm_win_activate(win);
if (pinentry->timeout > 0)
timer = ecore_timer_add (pinentry->timeout,
(Ecore_Task_Cb)timeout_cb,
pinentry);
}
static int
efl_cmd_handler (pinentry_t pe)
{
int want_pass = !!pe->pin;
got_input = EINA_FALSE;
pinentry = pe;
confirm_value = CONFIRM_CANCEL;
passphrase_ok = 0;
confirm_mode = want_pass ? 0 : 1;
/* init ecore-x explicitly using DISPLAY since this can launch
* from console
*/
if (pe->display)
ecore_x_init (pe->display);
elm_init (pargc, pargv);
create_window ();
ecore_main_loop_begin ();
if (timer)
{
ecore_timer_del (timer);
timer = NULL;
}
if (confirm_value == CONFIRM_CANCEL || grab_failed)
pe->canceled = 1;
pinentry = NULL;
if (want_pass)
{
if (passphrase_ok && pe->pin)
return strlen (pe->pin);
else
return -1;
}
else
return (confirm_value == CONFIRM_OK) ? 1 : 0;
}
int
main (int argc, char *argv[])
{
pinentry_init (PGMNAME);
#ifdef FALLBACK_CURSES
if (pinentry_have_display (argc, argv))
{
#endif
pinentry_cmd_handler = efl_cmd_handler;
pargc = argc;
pargv = argv;
#ifdef FALLBACK_CURSES
}
else
{
pinentry_cmd_handler = curses_cmd_handler;
}
#endif
pinentry_parse_opts (argc, argv);
if (pinentry_loop ())
return 1;
return 0;
}