/* main.cpp - A Fltk based dialog for PIN entry. Copyright (C) 2016 Anatoly madRat L. Berenblit Written by Anatoly madRat L. Berenblit . 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. SPDX-License-Identifier: GPL-2.0+ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #define PGMNAME (PACKAGE_NAME"-fltk") #include #include #include #include #include #include #include "memory.h" #include #include #ifdef FALLBACK_CURSES #include #endif #include #include #include #include #include #include #include "pinwindow.h" #include "passwindow.h" #include "qualitypasswindow.h" #define CONFIRM_STRING "Confirm" #define REPEAT_ERROR_STRING "Texts do not match" #define OK_STRING "OK" #define CANCEL_STRING "Cancel" char *application = NULL; static std::string escape_accel_utf8(const char *s) { std::string result; if (NULL != s) { result.reserve(strlen(s)); for (const char *p = s; *p; ++p) { if ('&' == *p) result.push_back(*p); result.push_back(*p); } } return result; } class cancel_exception { }; static int get_quality(const char *passwd, void *ptr) { if (NULL == passwd || 0 == *passwd) return 0; pinentry_t* pe = reinterpret_cast(ptr); return pinentry_inq_quality(*pe, passwd, strlen(passwd)); } bool is_short(const char *str) { return fl_utf_nb_char(reinterpret_cast(str), strlen(str)) < 16; } bool is_empty(const char *str) { return (NULL == str) || (0 == *str); } static int fltk_cmd_handler(pinentry_t pe) { int ret = -1; try { // TODO: Add parent window to pinentry-fltk window //if (pe->parent_wid){} std::string title = !is_empty(pe->title)?pe->title:PGMNAME; std::string ok = escape_accel_utf8(pe->ok?pe->ok:(pe->default_ok?pe->default_ok:OK_STRING)); std::string cancel = escape_accel_utf8(pe->cancel?pe->cancel:(pe->default_cancel?pe->default_cancel:CANCEL_STRING)); if (!!pe->pin) // password (or confirmation) { std::unique_ptr window; bool isSimple = (NULL == pe->quality_bar) && // pinenty.h: If this is not NULL ... is_empty(pe->error) && is_empty(pe->description) && is_short(pe->prompt); if (isSimple) { assert(NULL == pe->description); window.reset(PinWindow::create()); window->prompt(pe->prompt); } else { PassWindow *pass = NULL; if (pe->quality_bar) // pinenty.h: If this is not NULL ... { QualityPassWindow *p = QualityPassWindow::create(get_quality, &pe); window.reset(p); pass = p; p->quality(pe->quality_bar); } else { pass = PassWindow::create(); window.reset(pass); } if (NULL == pe->description) { pass->description(pe->prompt); pass->prompt(" "); } else { pass->description(pe->description); pass->prompt(escape_accel_utf8(pe->prompt).c_str()); } pass->description(pe->description); pass->prompt(escape_accel_utf8(pe->prompt).c_str()); if (NULL != pe->error) pass->error(pe->error); } window->ok(ok.c_str()); window->cancel(cancel.c_str()); window->title(title.c_str()); window->showModal((NULL != application)?1:0, &application); if (NULL == window->passwd()) throw cancel_exception(); const std::string password = window->passwd(); window.reset(); if (pe->repeat_passphrase) { const char *dont_match = NULL; do { if (NULL == dont_match && is_short(pe->repeat_passphrase)) { window.reset(PinWindow::create()); window->prompt(escape_accel_utf8(pe->repeat_passphrase).c_str()); } else { PassWindow *pass = PassWindow::create(); window.reset(pass); pass->description(pe->repeat_passphrase); pass->prompt(" "); pass->error(dont_match); } window->ok(ok.c_str()); window->cancel(cancel.c_str()); window->title(title.c_str()); window->showModal(); if (NULL == window->passwd()) throw cancel_exception(); if (password == window->passwd()) { pe->repeat_okay = 1; ret = 1; break; } else { dont_match = (NULL!=pe->repeat_error_string)? pe->repeat_error_string:REPEAT_ERROR_STRING; } } while (true); } else ret = 1; pinentry_setbufferlen(pe, password.size()+1); if (pe->pin) { memcpy(pe->pin, password.c_str(), password.size()+1); pe->result = password.size(); ret = password.size(); } } else { // Confirmation or Message Dialog title, desc Fl_Window dummy(0,0, 1,1); dummy.border(0); dummy.show((NULL != application)?1:0, &application); dummy.hide(); fl_message_title(title.c_str()); int result = -1; const char *message = (NULL != pe->description)?pe->description:CONFIRM_STRING; if (pe->one_button) { fl_ok = ok.c_str(); fl_message(message); result = 1; // OK } else if (pe->notok) { switch (fl_choice(message, ok.c_str(), cancel.c_str(), pe->notok)) { case 0: result = 1; break; case 2: result = 0; break; default: case 1: result = -1;break; } } else { switch (fl_choice(message, ok.c_str(), cancel.c_str(), NULL)) { case 0: result = 1; break; default: case 1: result = -1;break; } } // cancel -> pe->canceled = true, 0 // ok/y -> 1 // no -> 0 if (-1 == result) pe->canceled = true; ret = (1 == result); } Fl::check(); } catch (const cancel_exception&) { ret = -1; } catch (...) { ret = -1; } // do_touch_file(pe); only for NCURSES? return ret; } pinentry_cmd_handler_t pinentry_cmd_handler = fltk_cmd_handler; int main(int argc, char *argv[]) { application = *argv; pinentry_init(PGMNAME); #ifdef FALLBACK_CURSES if (!pinentry_have_display(argc, argv)) pinentry_cmd_handler = curses_cmd_handler; else #endif { //FLTK understood only -D (--display) // and should be converted into -di[splay] const static struct option long_options[] = { {"display", required_argument, 0, 'D' }, {NULL, no_argument, 0, 0 } }; for (int i = 0; i < argc-1; ++i) { switch (getopt_long(argc-i, argv+i, "D:", long_options, NULL)) { case 'D': { char* emul[] = {application, (char*)"-display", optarg}; Fl::args(3, emul); i = argc; break; } default: break; } } } pinentry_parse_opts(argc, argv); return pinentry_loop() ?EXIT_FAILURE:EXIT_SUCCESS; }