"Fossies" - the Fresh Open Source Software Archive

Member "mikrolock-1.2.1/src/gui/qt-widgets/mlock-gui/mlockmainwindow.cpp" (2 Sep 2019, 24903 Bytes) of package /linux/privat/mikrolock-1.2.1.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mlockmainwindow.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.2_vs_1.2.1.

    1 /*
    2 mikrolock reads and writes encrypted files in the minilock format
    3 
    4 Copyright (C) 2015 Andre Simon
    5 
    6 This program is free software: you can redistribute it and/or modify
    7 it under the terms of the GNU General Public License as published by
    8 the Free Software Foundation, either version 3 of the License, or
    9 (at your option) any later version.
   10 
   11 This program is distributed in the hope that it will be useful,
   12 but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 GNU General Public License for more details.
   15 
   16 You should have received a copy of the GNU General Public License
   17 along with this program.  If not, see <http://www.gnu.org/licenses/>.
   18 */
   19 
   20 #include <QClipboard>
   21 #include <QMessageBox>
   22 #include <QFileDialog>
   23 #include <QPixmap>
   24 #include <QDesktopWidget>
   25 #include <QDesktopServices>
   26 #include <QSettings>
   27 #include <QFileInfo>
   28 #include <QSysInfo>
   29 #include <QStyle>
   30 
   31 #include "mlockmainwindow.h"
   32 #include "ui_mlockmainwindow.h"
   33 
   34 #include "showmanualdialog.h"
   35 
   36 // static data items shared with threads
   37 
   38 struct rcpt_list* MlockMainWindow::id_list=NULL;
   39 uint8_t MlockMainWindow::b_my_sk[KEY_LEN] = {0};
   40 uint8_t MlockMainWindow::b_my_pk[KEY_LEN + 1]= {0};
   41 uint8_t MlockMainWindow::c_minilock_id[KEY_LEN * 2]= {0};
   42 struct output_options MlockMainWindow::out_opts;
   43 bool MlockMainWindow::forceThreadStop=false;
   44 
   45 
   46 MlockMainWindow::MlockMainWindow(QWidget *parent) :
   47     QMainWindow(parent),
   48     ui(new Ui::MlockMainWindow),
   49     startedWithFilArg(false)
   50 {
   51     ui->setupUi(this);
   52 
   53     ui->stackedWidget->setCurrentIndex(0);
   54     ui->lblCurrentAction->setVisible(false);
   55     ui->progressBar->setVisible(false);
   56     ui->btnBrowseDestDir->setVisible(false);
   57 
   58     memset(out_opts.c_final_out_name, 0, sizeof out_opts.c_final_out_name);
   59     memset(out_opts.c_override_out_name, 0, sizeof out_opts.c_override_out_name);
   60     out_opts.override_out_name_as_dir=1;
   61     out_opts.task_mode=0;
   62     out_opts.crypto_progress=0.0;
   63     out_opts.hash_progress=0.0;
   64     out_opts.silent_mode=1;
   65     out_opts.random_outname=0;
   66     out_opts.exclude_my_id=0;
   67 
   68     QWidget *central = new QWidget();
   69 
   70     scrollAreaLayout = new QVBoxLayout(central);
   71     ui->scrollRcptList->setWidget(central);
   72     ui->scrollRcptList->setWidgetResizable(true);
   73 
   74     for(int i=0;i<5;i++){
   75            addIDInputSlot();
   76     }
   77 
   78     mailRE.setPattern("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?");
   79     mailRE.setPatternSyntax(QRegExp::RegExp);
   80 
   81     sodium_mlock( b_my_sk, sizeof b_my_sk);
   82 
   83     this->setGeometry( QStyle::alignedRect(Qt::LeftToRight,Qt::AlignCenter, this->size(),
   84                                            qApp->desktop()->availableGeometry() ));
   85 #ifdef Q_OS_WIN32
   86     taskBarButton=NULL;
   87     taskBarProgress=NULL;
   88 #endif
   89 
   90     readSettings();
   91 }
   92 
   93 void MlockMainWindow::setInitialInputFile(QString file){
   94     inputFilename = file;
   95     startedWithFilArg=true;
   96     statusBar()->showMessage(tr("Input file %1").arg(inputFilename));
   97 }
   98 
   99 void MlockMainWindow::on_txtPassPhrase_textChanged(){
  100     QString pp = ui->txtPassPhrase->text();
  101 
  102     ui->lblSecIcon->setEnabled(!pp.isEmpty());
  103 
  104     if (pp.length() < 20){
  105         ui->lblSecIcon->setPixmap(QPixmap (":/Status-security-low-icon.png"));
  106         ui->lblSecIcon->setToolTip(tr("The passphrase is too short (minimum: 20 characters)."));
  107         ui->btnUnlock->setEnabled(false);
  108         return;
  109     }
  110     if (pp.length() > 40){
  111         ui->lblSecIcon->setPixmap(QPixmap (":/Status-security-high-icon.png"));
  112         ui->lblSecIcon->setToolTip(tr("The passphrase is strong."));
  113         ui->btnUnlock->setEnabled(!ui->txtMail->text().isEmpty() );
  114         return;
  115     }
  116 
  117     ui->lblSecIcon->setPixmap(QPixmap (":/Status-security-medium-icon.png"));
  118 
  119     ui->lblSecIcon->setToolTip(tr("The passphrase must consist of at least five random words. It may be declined by the original miniLock Chrome extension."));
  120 
  121     pp=pp.trimmed();
  122     int wordCount=0;
  123     for (int i=1;i<pp.length();i++){
  124         if (pp[i]==' ' && pp[i-1]!=' ')
  125             wordCount++;
  126     }
  127 
  128     ui->btnUnlock->setEnabled(!ui->txtMail->text().isEmpty()
  129                               && wordCount> 3 );
  130  //   ui->btnUnlock->setAutoExclusive(true);
  131 }
  132 
  133 void MlockMainWindow::on_txtMail_textChanged()
  134 {
  135     ui->txtPassPhrase->clear();
  136     QString mail = ui->txtMail->text();
  137     bool possiblyMailAddress = mail.contains('@');
  138     ui->lblMailIcon->setEnabled(possiblyMailAddress);
  139     ui->lblMailIcon->setPixmap(QPixmap (":/Status-mail-unread-icon.png"));
  140     ui->lblMailIcon->setToolTip(tr("You do not need to enter an email address here unless you intend to use the Chrome miniLock extension."));
  141     if (possiblyMailAddress){
  142         if (mailRE.exactMatch(mail)){
  143             ui->lblMailIcon->setToolTip(tr("This mail address appears to be valid."));
  144         } else {
  145             ui->lblMailIcon->setPixmap(QPixmap (":/Status-mail-unread-new-icon.png"));
  146             ui->lblMailIcon->setToolTip(tr("This mail address appears to be invalid."));
  147         }
  148      }
  149 }
  150 
  151 void MlockMainWindow::on_btnUnlock_clicked(){
  152 
  153     this->setCursor(Qt::WaitCursor);
  154     ui->txtPassPhrase->setEchoMode(QLineEdit::Password);
  155     ui->cbShowPass->setChecked(false);
  156     QByteArray passphrase = ui->txtPassPhrase->text().toUtf8();
  157     QByteArray salt  = ui->txtMail->text().toUtf8();
  158 
  159     uint8_t b_cs[1];
  160     uint8_t b_passphrase_blake2[KEY_LEN] = {0};
  161 
  162     sodium_mlock( b_passphrase_blake2, sizeof b_passphrase_blake2);
  163 
  164     blake_2s_array((uint8_t*)passphrase.data(), passphrase.length(),
  165                    b_passphrase_blake2, KEY_LEN);
  166 
  167     int kdf_retval = 1;
  168 
  169     if (ui->rbArgon2->isChecked()){
  170         unsigned char salt_hash[crypto_pwhash_SALTBYTES];
  171         crypto_generichash(salt_hash, sizeof salt_hash,
  172                            (uint8_t*)salt.data(), salt.length(),
  173                            NULL, 0);
  174         kdf_retval= crypto_pwhash(b_my_sk, sizeof b_my_sk,
  175                                   (char*)b_passphrase_blake2, sizeof b_passphrase_blake2, salt_hash,
  176                                   crypto_pwhash_OPSLIMIT_SENSITIVE, crypto_pwhash_MEMLIMIT_SENSITIVE,
  177                                   crypto_pwhash_ALG_DEFAULT);
  178     } else {
  179         // parameters used by MiniLock
  180         kdf_retval= crypto_pwhash_scryptsalsa208sha256_ll(b_passphrase_blake2, sizeof b_passphrase_blake2,
  181                                                           (uint8_t*)salt.data(), salt.length(),
  182                                                           131072, 8, 1,
  183                                                           b_my_sk, sizeof b_my_sk);
  184     }
  185 
  186     sodium_munlock( b_passphrase_blake2, sizeof b_passphrase_blake2);
  187 
  188     if (kdf_retval) {
  189         QMessageBox::critical(this, ui->rbArgon2->isChecked() ? tr("Argon2 error"): tr("Scrypt error"), tr("Key derivation failed"));
  190         return;
  191     }
  192 
  193     crypto_scalarmult_base(b_my_pk, b_my_sk);
  194 
  195     blake_2s_array(b_my_pk, KEY_LEN , b_cs, sizeof b_cs);
  196     b_my_pk[KEY_LEN] = b_cs[0];
  197 
  198     base58_encode((unsigned char *)c_minilock_id, b_my_pk, KEY_LEN + 1);
  199 
  200     ui->lblMyId->setText( QString((const char*)c_minilock_id));
  201     ui->btnCopyId->setEnabled(true);
  202     ui->stackedWidget->setCurrentIndex(1);
  203     ui->lbGoPreviousScreen->setEnabled(true);
  204     this->setCursor(Qt::ArrowCursor);
  205 }
  206 
  207 void MlockMainWindow::on_btnCopyId_clicked(){
  208     QClipboard *clipboard = QApplication::clipboard();
  209     if (clipboard) {
  210         clipboard->setText(ui->lblMyId->text());
  211     }
  212 }
  213 
  214 void MlockMainWindow::initProgressDisplay(bool isEncryptMode)
  215 {
  216     statusBar()->showMessage(tr("%1 file %2...").arg(
  217                                  (ui->stackedWidget->currentIndex()==1)?
  218                                      tr("Decrypting"): tr("Encrypting")).arg(inputFilename));
  219     this->setCursor(Qt::WaitCursor);
  220     timer.restart();
  221     QPixmap actionPix( isEncryptMode ? ":/Actions-document-encrypt-icon.png": ":/Actions-document-decrypt-icon.png");
  222     ui->lblCurrentAction->setPixmap(actionPix);
  223     ui->lblCurrentAction->setVisible(true);
  224     ui->progressBar->setValue(0);
  225     ui->progressBar->setVisible(true);
  226     ui->btnBrowseDestDir->setVisible(true);
  227     ui->btnEncrypt->setEnabled(false);
  228     ui->btnSelectDestDir->setEnabled(false);
  229     ui->btnSelInputFile->setEnabled(false);
  230 
  231     out_opts.crypto_progress=0.0;
  232     out_opts.hash_progress=0.0;
  233 
  234 #ifdef Q_OS_WIN32
  235     if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
  236       if (taskBarButton==NULL){
  237          taskBarButton = new QWinTaskbarButton(this);
  238          taskBarButton->setWindow(this->windowHandle());
  239          taskBarProgress = taskBarButton->progress();
  240       }
  241       taskBarButton->setOverlayIcon(QIcon(actionPix));
  242     }
  243 #endif
  244 }
  245 
  246 void MlockMainWindow::decrypt(){
  247 
  248     initProgressDisplay(false);
  249 
  250     UpdateProgressBarThread *progressUpdateThread = new UpdateProgressBarThread();
  251     connect(progressUpdateThread, &UpdateProgressBarThread::finished, progressUpdateThread, &QObject::deleteLater);
  252     connect(progressUpdateThread, &UpdateProgressBarThread::progress, this, &MlockMainWindow::updateProgress);
  253     progressUpdateThread->start();
  254 
  255     DecryptThread *workerThread = new DecryptThread(inputFilename);
  256     connect(workerThread, &DecryptThread::resultReady, this, &MlockMainWindow::handleResults);
  257     connect(workerThread, &DecryptThread::finished, workerThread, &QObject::deleteLater);
  258     workerThread->start();
  259 }
  260 
  261 void MlockMainWindow::encrypt() {
  262 
  263     if (!ui->cbOmitId->isChecked()){
  264         rcpt_list_add(&id_list, (char*)c_minilock_id);
  265     }
  266 
  267     QString rcptId;
  268     QLineEdit *leCurrentId;
  269     for (int i=0; i<scrollAreaLayout->count(); i++){
  270         leCurrentId = dynamic_cast<QLineEdit*>(scrollAreaLayout->itemAt(i)->widget());
  271         rcptId = leCurrentId->text().trimmed();
  272 
  273         if (!rcptId.isEmpty() ){
  274 
  275             if (!rcpt_list_add(&id_list, (char*)rcptId.toStdString().c_str())){
  276                 QMessageBox::critical(this, tr("Bad Lock-ID"), tr("The ID %1 is invalid.").arg(rcptId));
  277                 leCurrentId->selectAll();
  278                 leCurrentId->setFocus();
  279                 return;
  280             }
  281         }
  282     }
  283 
  284     initProgressDisplay(true);
  285 
  286     out_opts.random_outname =  ui->cbRandomFileName->isChecked();
  287     out_opts.exclude_my_id = ui->cbOmitId->isChecked();
  288 
  289     UpdateProgressBarThread *progressUpdateThread = new UpdateProgressBarThread();
  290     connect(progressUpdateThread, &UpdateProgressBarThread::finished, progressUpdateThread, &QObject::deleteLater);
  291     connect(progressUpdateThread, &UpdateProgressBarThread::progress, this, &MlockMainWindow::updateProgress);
  292     progressUpdateThread->start();
  293 
  294     EncryptThread *workerThread = new EncryptThread(inputFilename);
  295     connect(workerThread, &EncryptThread::resultReady, this, &MlockMainWindow::handleResults);
  296     connect(workerThread, &EncryptThread::finished, workerThread, &QObject::deleteLater);
  297 
  298     workerThread->start();
  299 }
  300 
  301 void MlockMainWindow::handleResults(int result){
  302 
  303     if (result==0){
  304         statusBar()->showMessage(tr("%1 file %2 in %3s").arg(
  305                                      (ui->stackedWidget->currentIndex()==1) ?
  306                                          tr("Decrypted"): tr("Encrypted")).arg(inputFilename).arg(1 + timer.elapsed()/1000));
  307         QPixmap actionPix(":/Actions-dialog-ok-apply-icon.png");
  308         ui->lblCurrentAction->setPixmap(actionPix);
  309         ui->btnSelInputFile->setEnabled(true);
  310     } else {
  311         forceThreadStop=true;
  312 
  313         QPixmap actionPix(":/Actions-process-stop-icon.png");
  314         ui->lblCurrentAction->setPixmap(actionPix);
  315 
  316         switch((enum error_code)result){
  317 
  318         case err_failed:
  319             QMessageBox::critical(this, tr("Error") , tr("Unknown error."));
  320             break;
  321 
  322         case err_open:
  323             QMessageBox::critical(this, tr("Error") , tr("Could not decrypt the file."));
  324             break;
  325 
  326         case err_box:
  327             QMessageBox::critical(this, tr("Error") , tr("Could not encrypt the file."));
  328             break;
  329 
  330         case err_file_open:
  331             QMessageBox::critical(this, tr("Error") , tr("Could not open the file."));
  332             break;
  333 
  334         case err_file_read:
  335             QMessageBox::critical(this, tr("Error") , tr("Could not read the file."));
  336             break;
  337 
  338         case err_file_write:
  339             QMessageBox::critical(this, tr("Error") , tr("Could not write the file."));
  340             break;
  341 
  342         case err_hash:
  343             QMessageBox::critical(this, tr("Error") , tr("Could not calculate the hash of the file."));
  344             break;
  345 
  346         case err_format:
  347             QMessageBox::critical(this, tr("Error") , tr("Illegal minilock file format."));
  348             break;
  349 
  350         case err_no_rcpt:
  351             QMessageBox::critical(this, tr("Error") , tr("No recipients defined."));
  352             break;
  353 
  354         case err_not_allowed:
  355             QMessageBox::critical(this, tr("Error") , tr("You are not allowed to decrypt the file."));
  356             break;
  357 
  358         case err_file_empty:
  359             QMessageBox::critical(this, tr("Error") , tr("Empty input file."));
  360             break;
  361 
  362         case err_file_exists:
  363             QMessageBox::critical(this, tr("Error") , tr("Output file exists:\n%1").
  364                                   arg(QString((const char *)out_opts.c_final_out_name)).toLocal8Bit());
  365             break;
  366 
  367         default:
  368             QMessageBox::critical(this, tr("Error") , tr("Undefined error."));
  369             break;
  370         }
  371 
  372     }
  373     this->setCursor(Qt::ArrowCursor);
  374     ui->btnEncrypt->setEnabled(true);
  375     ui->btnSelectDestDir->setEnabled(true);
  376     ui->btnSelInputFile->setEnabled(true);
  377 
  378 }
  379 
  380 void MlockMainWindow::updateProgress(int p){
  381     ui->progressBar->setValue(p);
  382 #ifdef Q_OS_WIN32
  383     if (taskBarProgress!=NULL){
  384         taskBarProgress->setValue(p);
  385         taskBarProgress->setVisible(p && p!= 100);
  386         if (p==100) taskBarButton->clearOverlayIcon();
  387     }
  388 #endif
  389 }
  390 
  391 void MlockMainWindow::on_lbGoPreviousScreen_clicked(){
  392 
  393     if (ui->stackedWidget->currentIndex()>0)
  394         ui->stackedWidget->setCurrentIndex(ui->stackedWidget->currentIndex()-1);
  395 
  396     ui->lbGoPreviousScreen->setEnabled(ui->stackedWidget->currentIndex()>0);
  397 }
  398 
  399 void MlockMainWindow::on_btnSelectDestDir_clicked()
  400 {
  401     QFileDialog dialog(this, tr("Select destination directory"), "");
  402     dialog.setFileMode(QFileDialog::Directory);
  403     if (dialog.exec() && !dialog.selectedFiles().empty()) {
  404       ui->txtDestDir->setText(QDir::toNativeSeparators(dialog.selectedFiles().at(0)));
  405     }
  406 }
  407 
  408 void MlockMainWindow::on_btnSelInputFile_clicked()
  409 {
  410     inputFilename = QFileDialog::getOpenFileName(this, tr("Select the input file"), "", "*");
  411     startFileProcessing();
  412 }
  413 
  414 
  415 void MlockMainWindow::startFileProcessing(bool promptAction)
  416 {
  417     if (!inputFilename.isEmpty()) {
  418         if (    promptAction
  419             &&  QMessageBox::question(this,
  420                                       tr("Process given file"),
  421                                       tr("%1 %2\ninto %3 ?").arg(inputFilename.endsWith(".minilock") ?
  422                                       tr("Decrypt") :
  423                                       tr("Encrypt")).arg(QFileInfo(inputFilename).fileName()).arg(ui->txtDestDir->text()),
  424                                       QMessageBox::Yes|QMessageBox::No)== QMessageBox::No)
  425             return;
  426 
  427         if (inputFilename.endsWith("minilock"))
  428             decrypt();
  429         else
  430             ui->stackedWidget->setCurrentIndex(2);
  431     }
  432 }
  433 
  434 void MlockMainWindow::dropEvent(QDropEvent* event)
  435 {
  436 
  437     ui->lblDrop->setEnabled(false);
  438     if (ui->txtDestDir->text().isEmpty()) return;
  439 
  440     QList<QUrl> urls = event->mimeData()->urls();
  441     if (urls.isEmpty())
  442        return;
  443 
  444     QString fileName = urls.first().toLocalFile();
  445     if (!fileName.isEmpty())
  446        inputFilename=fileName;
  447 
  448     statusBar()->showMessage(tr("Input file %1").arg(inputFilename));
  449     startFileProcessing();
  450 }
  451 
  452 void MlockMainWindow::on_btnAddRcpt_clicked()
  453 {
  454     addIDInputSlot();
  455 }
  456 
  457 void MlockMainWindow::on_btnEncrypt_clicked()
  458 {
  459     encrypt();
  460 }
  461 
  462 void MlockMainWindow::on_txtDestDir_textChanged()
  463 {
  464     if (!ui->txtDestDir->text().endsWith(QDir::separator())) {
  465        ui->txtDestDir->setText(ui->txtDestDir->text() +  QDir::separator());
  466     }
  467 
  468     ui->btnSelInputFile->setEnabled(!ui->txtDestDir->text().isEmpty());
  469 
  470     strncpy((char*)out_opts.c_override_out_name,
  471             ui->txtDestDir->text().toLocal8Bit().data(),
  472             sizeof out_opts.c_override_out_name-1);
  473 }
  474 
  475 void MlockMainWindow::on_actionAbout_mlock_triggered()
  476 {
  477     QMessageBox::about( this, "About MikroLock",
  478                         QString("MikroLock reads and writes encrypted minilock files.\n\n"
  479                         "MikroLock %1\n"
  480                         "(C) 2015-2018 Andre Simon <andre.simon1 at gmx.de>\n\n"
  481                         "Minilock file format specification:\n"
  482                         "https://minilock.io\n\n"
  483                         "Built with Qt version %2\n\n"
  484                         "Icons are based on the KDE Oxygen icon theme\n\n"
  485                         "Released under the terms of the GNU GPL license.\n\n"
  486                         ).arg(MIKROLOCK_VERSION).arg(QString(qVersion ())) );
  487 }
  488 
  489 void MlockMainWindow::on_action_Translation_hints_triggered()
  490 {
  491     QMessageBox::information(this, tr("About providing translations"),
  492                              tr("This GUI was developed using the Qt toolkit, and "
  493                                 "translations may be provided using the tools Qt Linguist and lrelease.\n"
  494                                 "The ts files for Linguist reside in the src/gui/qt-widgets subdirectory.\n"
  495                                 "The qm file generated by lrelease has to be saved in l10n.\n\n"
  496                                 "Please send a note to as (at) andre-simon (dot) de if you have issues while translating "
  497                                 "or if you have finished or updated a translation."));
  498 }
  499 
  500 void MlockMainWindow::on_action_Manual_triggered(){
  501 
  502      ShowManualDialog dialog;
  503      QString l10nManualUri  = ":/manual/manual_"+QLocale::system().name()+".html";
  504 
  505      if (QFileInfo::exists(l10nManualUri))
  506          dialog.setHTMLSource(l10nManualUri);
  507     else
  508          dialog.setHTMLSource(":/manual/manual_en_EN.html");
  509 
  510      dialog.exec();
  511 }
  512 
  513 void MlockMainWindow::on_btnClearRecipients_clicked()
  514 {
  515     QLineEdit *leCurrentId;
  516     for (int i=0; i<scrollAreaLayout->count(); i++){
  517         leCurrentId = dynamic_cast<QLineEdit*>(scrollAreaLayout->itemAt(i)->widget());
  518         leCurrentId->setText("");
  519     }
  520 }
  521 
  522 void MlockMainWindow::on_btnOpenFileList_clicked()
  523 {
  524     QString listFilename = QFileDialog::getOpenFileName(this, tr("Select the recipient list file"), "", "*");
  525 
  526     if (!listFilename.isEmpty()){
  527         QFile f(listFilename);
  528 
  529         if (f.open(QIODevice::ReadOnly))
  530         {
  531             on_btnClearRecipients_clicked();
  532 
  533             QString data = f.readAll();
  534             QStringList vals = data.split('\n');
  535 
  536             vals.removeDuplicates();
  537 
  538             QRegExp delimRE("[\\,\\;\\|\\-\\/]");
  539 
  540             for (int i=0; i<vals.count(); i++){
  541 
  542                 if (i> scrollAreaLayout->count()-1){
  543                     addIDInputSlot();
  544                 }
  545                 QLineEdit *leCurrentId = dynamic_cast<QLineEdit*>(scrollAreaLayout->itemAt(i)->widget());
  546                 QString line(vals[i]);
  547                 int delimPos = line.indexOf(delimRE);
  548                 if (delimPos<0){
  549                     leCurrentId->setText(line.trimmed());
  550                 } else {
  551                     leCurrentId->setText(line.mid(0,delimPos).trimmed());
  552                     leCurrentId->setToolTip(line.mid(delimPos+1).replace(delimRE, ""));
  553                 }
  554             }
  555             f.close();
  556         }
  557     }
  558 }
  559 
  560 void MlockMainWindow::on_btnBrowseDestDir_clicked()
  561 {
  562   //  QDesktopServices::openUrl(QUrl("file:///"+ui->txtDestDir->text(), QUrl::TolerantMode));
  563     QDesktopServices::openUrl(QUrl::fromLocalFile(ui->txtDestDir->text()));
  564 }
  565 
  566 void MlockMainWindow::on_rbScrypt_clicked(){
  567     ui->rbArgon2->setChecked(false);
  568 }
  569 
  570 void MlockMainWindow::on_rbArgon2_clicked(){
  571     ui->rbScrypt->setChecked(false);
  572 }
  573 
  574 void MlockMainWindow::on_cbShowPass_clicked()
  575 {
  576     ui->txtPassPhrase->setEchoMode( ui->cbShowPass->isChecked() ? QLineEdit::Normal : QLineEdit::Password );
  577 }
  578 
  579 void MlockMainWindow::on_stackedWidget_currentChanged(int idx)
  580 {
  581     ui->progressBar->setVisible(false);
  582     ui->lblCurrentAction->setVisible(false);
  583     ui->btnBrowseDestDir->setVisible(false);
  584 
  585     switch(idx){
  586     case 0:
  587         statusBar()->showMessage(tr("Enter your mail adress and passphrase"));
  588         break;
  589 
  590     case 1:
  591         if (startedWithFilArg){
  592             statusBar()->showMessage(tr("Input file %1").arg(inputFilename));
  593 
  594             if (!inputFilename.isEmpty()) {
  595                 startFileProcessing(true);
  596                 startedWithFilArg=false;
  597             }
  598         } else {
  599             statusBar()->showMessage(tr("Set input and output parameters"));
  600         }
  601         break;
  602 
  603     case 2:
  604         statusBar()->showMessage(tr("Set encryption options for %1").arg(inputFilename));
  605         break;
  606 
  607     default:
  608         statusBar()->showMessage("");
  609         break;
  610     }
  611     this->setAcceptDrops(idx==1);
  612 }
  613 
  614 void MlockMainWindow::dragEnterEvent(QDragEnterEvent *event)
  615 {
  616     if (!ui->txtDestDir->text().isEmpty()
  617             && event->mimeData()->hasFormat("text/uri-list")
  618             && event->mimeData()->urls().count()==1
  619             ){
  620         event->acceptProposedAction();
  621         ui->lblDrop->setEnabled(true);
  622      }
  623 }
  624 
  625 void MlockMainWindow::dragLeaveEvent(QDragLeaveEvent* event)
  626 {
  627       ui->lblDrop->setEnabled(false);
  628 }
  629 
  630 void MlockMainWindow::addIDInputSlot()
  631 {
  632     QLineEdit* le =  new QLineEdit();
  633 #ifdef Q_OS_WIN32
  634     le->setFont(QFont("Courier New"));
  635 #else
  636     le->setFont(QFont("Monospace"));
  637 #endif
  638     scrollAreaLayout->addWidget(le);
  639 }
  640 
  641 void MlockMainWindow::writeSettings()
  642  {
  643      QSettings settings(QSettings::IniFormat, QSettings::UserScope,
  644                         "andre-simon.de", "mlock-gui");
  645 
  646      settings.beginGroup("MainWindow");
  647      settings.setValue("geometry", saveGeometry());
  648      settings.setValue("windowState", saveState());
  649      settings.endGroup();
  650 
  651      settings.beginGroup("input");
  652 
  653      settings.setValue("txtDestDir", ui->txtDestDir->text());
  654      settings.setValue("cbOmitId", ui->cbOmitId->isChecked());
  655      settings.setValue("cbRandomFileName", ui->cbRandomFileName->isChecked());
  656      settings.setValue("rbScrypt", ui->rbScrypt->isChecked());
  657      settings.setValue("rbArgon2", ui->rbArgon2->isChecked());
  658      settings.endGroup();
  659  }
  660 
  661  void MlockMainWindow::readSettings()
  662  {
  663      QSettings settings(QSettings::IniFormat, QSettings::UserScope,
  664                         "andre-simon.de", "mlock-gui");
  665 
  666      //QMessageBox::information(this, "path", settings.fileName());
  667      if (!QFile(settings.fileName()).exists()) return;
  668 
  669      settings.beginGroup("MainWindow");
  670 
  671      restoreGeometry(settings.value("geometry").toByteArray());
  672      restoreState(settings.value("windowState").toByteArray());
  673 
  674      settings.endGroup();
  675 
  676      settings.beginGroup("input");
  677 
  678      ui->txtDestDir->setText(settings.value("txtDestDir").toString());
  679      ui->cbOmitId->setChecked(settings.value("cbOmitId").toBool());
  680      ui->cbRandomFileName->setChecked(settings.value("cbRandomFileName").toBool());
  681      ui->rbScrypt->setChecked(settings.value("rbScrypt").toBool());
  682      ui->rbArgon2->setChecked(settings.value("rbArgon2").toBool());
  683 
  684      settings.endGroup();
  685  }
  686 
  687 
  688 MlockMainWindow::~MlockMainWindow()
  689 {
  690     sodium_munlock( b_my_sk, sizeof b_my_sk);
  691     writeSettings();
  692     delete ui;
  693 }
  694 
  695 /// Threads
  696 
  697 void DecryptThread::run() {
  698     int result= minilock_decode((uint8_t*) inFileName.toLocal8Bit().data(),
  699                                 MlockMainWindow::b_my_sk, MlockMainWindow::b_my_pk,
  700                                 &MlockMainWindow::out_opts);
  701     emit resultReady(result);
  702 }
  703 
  704 void EncryptThread::run()  {
  705     int result= minilock_encode((uint8_t*) inFileName.toLocal8Bit().data(),
  706                                 MlockMainWindow::c_minilock_id,
  707                                 MlockMainWindow::b_my_sk,
  708                                 &MlockMainWindow::id_list,
  709                                 &MlockMainWindow::out_opts);
  710     rcpt_list_free(&MlockMainWindow::id_list);
  711     emit resultReady(result);
  712 }
  713 
  714 void UpdateProgressBarThread::run() {
  715 
  716    int percentage=0;
  717    MlockMainWindow::forceThreadStop=false;
  718 
  719    while (percentage<100 &&!MlockMainWindow::forceThreadStop){
  720        QThread::msleep(150);
  721        percentage = (int)MlockMainWindow::out_opts.crypto_progress/2 + MlockMainWindow::out_opts.hash_progress/2;
  722        emit progress(percentage);
  723    }
  724    if (MlockMainWindow::forceThreadStop)
  725        emit progress(0);
  726 }
  727