"Fossies" - the Fresh Open Source Software Archive

Member "zuluCrypt-5.7.1/zuluCrypt-gui/utility.cpp" (31 Jan 2020, 61419 Bytes) of package /linux/misc/zuluCrypt-5.7.1.tar.xz:


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 "utility.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.7.0_vs_5.7.1.

    1 /*
    2  *
    3  *  Copyright ( c ) 2011-2015
    4  *  name : Francis Banyikwa
    5  *  email: mhogomchungu@gmail.com
    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 2 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 <iostream>
   21 #include <sys/stat.h>
   22 #include <sys/types.h>
   23 #include <fcntl.h>
   24 #include <unistd.h>
   25 #include <string.h>
   26 #include <stdio.h>
   27 #include <QObject>
   28 #include <QDir>
   29 #include <pwd.h>
   30 #include <grp.h>
   31 #include <termios.h>
   32 
   33 #include <memory>
   34 
   35 #include <QTranslator>
   36 #include <QEventLoop>
   37 #include <QDebug>
   38 #include <QCoreApplication>
   39 #include <blkid/blkid.h>
   40 #include <QByteArray>
   41 #include <QProcess>
   42 #include <QFile>
   43 #include <QDir>
   44 #include <QTableWidget>
   45 #include <QMessageBox>
   46 #include <QTableWidgetItem>
   47 #include <QProcessEnvironment>
   48 #include <unistd.h>
   49 #include <pwd.h>
   50 #include <QApplication>
   51 #include <QEvent>
   52 #include <QKeyEvent>
   53 #include <QMetaObject>
   54 #include <QtNetwork/QLocalSocket>
   55 #include "../zuluCrypt-cli/constants.h"
   56 #include "../zuluCrypt-cli/bin/bash_special_chars.h"
   57 #include "version.h"
   58 #include "locale_path.h"
   59 #include "mount_prefix_path.h"
   60 #include "dialogmsg.h"
   61 #include "support_whirlpool.h"
   62 #include "readonlywarning.h"
   63 #include "../plugins/plugins.h"
   64 #include "plugin.h"
   65 #include "install_prefix.h"
   66 #include "utility.h"
   67 #include "executablesearchpaths.h"
   68 #include "network_access_manager.hpp"
   69 #include "zuluPolkit.h"
   70 
   71 #include <sys/types.h>
   72 #include <sys/stat.h>
   73 #include <fcntl.h>
   74 #include <unistd.h>
   75 
   76 #include <gcrypt.h>
   77 
   78 #include "../zuluCrypt-cli/pluginManager/libzuluCryptPluginManager.h"
   79 
   80 #include "../zuluCrypt-cli/utility/process/process.h"
   81 
   82 #include "plugin_path.h"
   83 
   84 #include "../zuluCrypt-cli/utility/process/process.h"
   85 
   86 #include "reuse_mount_point.h"
   87 #include "share_mount_prefix_path.h"
   88 
   89 #include "zuluPolkit.h"
   90 
   91 #include "json.h"
   92 
   93 struct jsonResult
   94 {
   95     bool finished ;
   96     int exitCode ;
   97     int exitStatus ;
   98     QByteArray stdError ;
   99     QByteArray stdOut ;
  100 };
  101 
  102 static std::function< void() > _failed_to_connect_to_zulupolkit ;
  103 
  104 static QSettings * _settings ;
  105 
  106 static debugWindow * _debugWindow ;
  107 
  108 static QWidget * _mainWindow ;
  109 
  110 static void _post_backend_cmd( const QString& b )
  111 {
  112     QString a = "***************************\n" ;
  113     QString c = "\n***************************" ;
  114 
  115     _debugWindow->UpdateOutPut( a + b + c,true ) ;
  116 }
  117 
  118 void utility::setDebugWindow( debugWindow * w )
  119 {
  120     _debugWindow = w ;
  121 }
  122 
  123 void utility::mainWindowWidget( QWidget * e )
  124 {
  125     _mainWindow = e ;
  126 }
  127 
  128 QWidget * utility::mainWindowWidget()
  129 {
  130     return _mainWindow ;
  131 }
  132 
  133 
  134 std::unique_ptr< utility::RandomDataSource > utility::RandomDataSource::get( utility::RandomDataSource::types type )
  135 {
  136     if( type == utility::RandomDataSource::types::urandom ){
  137 
  138         return std::make_unique< utility::UrandomDataSource >() ;
  139     }else{
  140         return std::make_unique< utility::CRandDataSource >() ;
  141     }
  142 }
  143 
  144 utility::RandomDataSource::~RandomDataSource()
  145 {
  146 }
  147 
  148 static QByteArray _json_command( const QByteArray& cookie,
  149                  const QByteArray& password,
  150                  const QString& exe,
  151                  const QString& path = QString(),
  152                  const QByteArray& data = QByteArray() )
  153 {
  154     nlohmann::json json ;
  155 
  156     json[ "cookie" ]   = cookie.constData() ;
  157     json[ "password" ] = password.constData() ;
  158     json[ "command" ]  = exe.toLatin1().constData() ;
  159     json[ "path" ]     = path.toLatin1().constData() ;
  160     json[ "data" ]     = data.constData() ;
  161 
  162     return json.dump().c_str() ;
  163 }
  164 
  165 static jsonResult _json_result( const QByteArray& e )
  166 {
  167     try{
  168         if( !e.isEmpty() ){
  169 
  170             auto json = nlohmann::json::parse( e.constData() ) ;
  171 
  172             return { json[ "finished" ].get< bool >(),
  173                  json[ "exitCode" ].get< int >(),
  174                  json[ "exitStatus" ].get< int >(),
  175                  json[ "stdError" ].get< std::string >().c_str(),
  176                  json[ "stdOut" ].get< std::string >().c_str() } ;
  177         }
  178 
  179     }catch( ... ){}
  180 
  181     return { false,255,255,"","" } ;
  182 }
  183 
  184 static bool _connected( QLocalSocket& s )
  185 {
  186     s.connectToServer( utility::helperSocketPath() ) ;
  187 
  188     for( int i = 0 ; ; i++ ){
  189 
  190         if( s.waitForConnected() ){
  191 
  192             return true ;
  193 
  194         }else if( i == 2 ){
  195 
  196             utility::debug() << "ERROR: Failed To Connect To zuluPolkit" ;
  197             break ;
  198         }else{
  199             utility::debug() << s.errorString() ;
  200 
  201             utility::Task::suspendForOneSecond() ;
  202         }
  203     }
  204 
  205     return false ;
  206 }
  207 
  208 static QByteArray _cookie ;
  209 static bool _run_through_polkit ;
  210 
  211 ::Task::future< utility::Task >& utility::Task::run( const QString& exe,USEPOLKIT e )
  212 {
  213     return utility::Task::run( exe,-1,e ) ;
  214 }
  215 
  216 ::Task::future< utility::Task >& utility::Task::run( const QString& exe,int s,USEPOLKIT e )
  217 {
  218     return ::Task::run( [ = ](){
  219 
  220         auto env = QProcessEnvironment::systemEnvironment() ;
  221 
  222         return utility::Task( exe,s,env,_cookie,[](){ umask( 0 ) ; },e ) ;
  223     } ) ;
  224 }
  225 
  226 void utility::polkitFailedWarning( std::function< void() > e )
  227 {
  228     _failed_to_connect_to_zulupolkit = std::move( e ) ;
  229 }
  230 
  231 void utility::Task::execute( const QString& exe,int waitTime,
  232                  const QProcessEnvironment& env,
  233                  const QByteArray& password,
  234                  std::function< void() > f,
  235                  USEPOLKIT polkit )
  236 {
  237     if( polkit == USEPOLKIT::True && utility::useZuluPolkit() ){
  238 
  239         QLocalSocket s ;
  240 
  241         if( _connected( s ) ){
  242 
  243             _post_backend_cmd( exe ) ;
  244 
  245             s.write( _json_command( _cookie,password,exe ) ) ;
  246 
  247             s.waitForBytesWritten() ;
  248 
  249             s.waitForReadyRead( -1 ) ;
  250 
  251             auto e = _json_result( s.readAll() ) ;
  252 
  253             m_finished   = e.finished ;
  254             m_exitCode   = e.exitCode ;
  255             m_exitStatus = e.exitStatus ;
  256             m_stdError   = e.stdError ;
  257             m_stdOut     = e.stdOut ;
  258         }else{
  259             _failed_to_connect_to_zulupolkit() ;
  260 
  261             m_finished   = false ;
  262             m_exitCode   = -1 ;
  263             m_exitStatus = -1 ;
  264             m_stdError   = "" ;
  265             m_stdOut     = QObject::tr( "zuluCrypt: Failed To Establish Connection With zuluPolkit" ).toLatin1() ;
  266         }
  267     }else{
  268         _post_backend_cmd( exe ) ;
  269 
  270         auto p = ::Task::process::run( exe,{},waitTime,password,env,std::move( f ) ).get() ;
  271 
  272         m_finished   = p.finished() ;
  273         m_exitCode   = p.exit_code() ;
  274         m_exitStatus = p.exit_status() ;
  275         m_stdOut     = p.std_out() ;
  276         m_stdError   = p.std_error() ;
  277     }
  278 }
  279 
  280 void utility::setDefaultEnvironment()
  281 {
  282 }
  283 
  284 QString utility::passwordSocketPath()
  285 {
  286     return "/tmp/zuluCrypt-" + QString::number( getuid() ) ;
  287 }
  288 
  289 #if QT_VERSION > QT_VERSION_CHECK( 5,0,0 )
  290     #include <QStandardPaths>
  291     QString utility::socketPath()
  292     {
  293         return QStandardPaths::writableLocation( QStandardPaths::RuntimeLocation ) ;
  294     }
  295 #else
  296     #include <QDesktopServices>
  297     QString utility::socketPath()
  298     {
  299         return QDesktopServices::storageLocation( QDesktopServices::DataLocation ) ;
  300     }
  301 #endif
  302 
  303 void utility::setSettingsObject( QSettings * e )
  304 {
  305     _settings = e ;
  306 }
  307 
  308 QSettings& utility::settingsObject()
  309 {
  310     return *_settings ;
  311 }
  312 
  313 static QString zuluPolkitExe()
  314 {
  315     auto exe = utility::executableFullPath( "pkexec" ) ;
  316 
  317     if( exe.isEmpty() ){
  318 
  319         return QString() ;
  320     }else{
  321         return QString( "%1 %2 %3 fork" ).arg( exe,zuluPolkitPath,utility::helperSocketPath() ) ;
  322     }
  323 }
  324 
  325 static ::Task::future< utility::Task >& _start_zulupolkit( const QString& e )
  326 {
  327     utility::UrandomDataSource randSource ;
  328 
  329     if( randSource.open() ){
  330 
  331         _cookie = randSource.getData( 16 ).toHex() ;
  332     }else{
  333         _cookie = utility::CRandDataSource().getData( 16 ).toHex() ;
  334     }
  335 
  336     return ::Task::run( [ = ]{
  337 
  338         return utility::Task( e,
  339                       -1,
  340                       utility::systemEnvironment(),
  341                       _cookie,
  342                       [](){},
  343                       utility::Task::USEPOLKIT::False ) ;
  344     } ) ;
  345 }
  346 
  347 static bool _enable_polkit_support( const QString& m )
  348 {
  349     struct stat st ;
  350 
  351     if( m == "zuluCrypt" ){
  352 
  353         stat( ZULUCRYPTzuluCrypt,&st ) ;
  354     }else{
  355         stat( zuluMountPath,&st ) ;
  356     }
  357 
  358     bool s = st.st_mode & S_ISUID ;
  359 
  360     return !s ;
  361 }
  362 
  363 void utility::startHelperExecutable( QObject * obj,const QString& arg,const QString& exe,
  364                      const char * slot,const char * slot1 )
  365 {
  366     if( _enable_polkit_support( exe ) ){
  367 
  368         auto exe = zuluPolkitExe() ;
  369 
  370         if( !exe.isEmpty() ){
  371 
  372             _start_zulupolkit( exe ).then( [ = ]( const utility::Task& e ){
  373 
  374                 _run_through_polkit = e.success() ;
  375 
  376                 QMetaObject::invokeMethod( obj,
  377                                slot,
  378                                Q_ARG( bool,e.success() ),
  379                                Q_ARG( QString,arg ) ) ;
  380             } ) ;
  381         }else{
  382             DialogMsg().ShowUIOK( QObject::tr( "ERROR" ),
  383                           QObject::tr( "Failed to locate pkexec executable" ) ) ;
  384 
  385             QMetaObject::invokeMethod( obj,slot1 ) ;
  386         }
  387     }else{
  388         QMetaObject::invokeMethod( obj,slot,Q_ARG( bool,true ),Q_ARG( QString,arg ) ) ;
  389     }
  390 }
  391 
  392 QString utility::helperSocketPath()
  393 {
  394     auto a = QString::number( getuid() ) ;
  395     auto b = QCoreApplication::applicationName() ;
  396 
  397     return QString( "/tmp/zuluCrypt-%1/%2.polkit.socket" ).arg( a,b ) ;
  398 }
  399 
  400 bool utility::useZuluPolkit()
  401 {
  402     return _run_through_polkit ;
  403 }
  404 
  405 bool utility::requireSystemPermissions( const QString& e,utility::background_thread thread )
  406 {
  407     const char * exe ;
  408     const char * group ;
  409 
  410     if( QCoreApplication::applicationName() == "zuluCrypt" ){
  411 
  412         exe = ZULUCRYPTzuluCrypt" -S" ;
  413         group = "zulucrypt" ;
  414     }else{
  415         exe = zuluMountPath" -S" ;
  416         group = "zulumount" ;
  417     }
  418 
  419     auto s = [ & ](){
  420 
  421         if( thread == utility::background_thread::True ){
  422 
  423             return utility::Task::run( exe ).get().stdOut() ;
  424         }else{
  425             return utility::Task::run( exe ).await().stdOut() ;
  426         }
  427     }() ;
  428 
  429     if( utility::split( s ).contains( e ) ){
  430 
  431         if( utility::userBelongsToGroup( group ) ){
  432 
  433             return false ;
  434         }else{
  435             return true ;
  436         }
  437     }else{
  438         return false ;
  439     }
  440 }
  441 
  442 bool utility::enablePolkit( utility::background_thread thread )
  443 {
  444     if( _run_through_polkit ){
  445 
  446         return true ;
  447     }
  448 
  449     auto exe = zuluPolkitExe() ;
  450 
  451     if( !exe.isEmpty() ){
  452 
  453         auto socketPath = utility::helperSocketPath() ;
  454 
  455         if( thread == utility::background_thread::True ){
  456 
  457             if( _start_zulupolkit( exe ).get().success() ){
  458 
  459                 _run_through_polkit = true ;
  460 
  461                 while( !utility::pathExists( socketPath ) ){
  462 
  463                     utility::Task::waitForOneSecond() ;
  464                 }
  465             }
  466         }else{
  467             if( _start_zulupolkit( exe ).await().success() ){
  468 
  469                 _run_through_polkit = true ;
  470 
  471                 while( !utility::pathExists( socketPath ) ){
  472 
  473                     utility::Task::suspendForOneSecond() ;
  474                 }
  475             }
  476         }
  477     }
  478 
  479     return _run_through_polkit ;
  480 }
  481 
  482 void utility::quitHelper()
  483 {
  484     auto e = utility::helperSocketPath() ;
  485 
  486     if( utility::pathExists( e ) ){
  487 
  488         QLocalSocket s ;
  489 
  490         s.connectToServer( e ) ;
  491 
  492         if( s.waitForConnected() ){
  493 
  494             s.write( _json_command( _cookie,"","exit" ) ) ;
  495 
  496             s.waitForBytesWritten() ;
  497         }
  498     }
  499 }
  500 
  501 std::pair< bool,QByteArray > utility::privilegedReadConfigFile( const QString& path )
  502 {
  503     if( utility::enablePolkit( utility::background_thread::False ) ){
  504 
  505         QLocalSocket s ;
  506 
  507         if( _connected( s ) ){
  508 
  509             s.write( _json_command( _cookie,QByteArray(),"Read",path ) ) ;
  510 
  511             s.waitForBytesWritten() ;
  512 
  513             s.waitForReadyRead() ;
  514 
  515             return { true,_json_result( s.readAll() ).stdOut } ;
  516         }
  517     }
  518 
  519     return { false,QByteArray() } ;
  520 }
  521 
  522 void utility::privilegedWriteConfigFile( const QByteArray& data,const QString& path )
  523 {
  524     if( utility::enablePolkit( utility::background_thread::False ) ){
  525 
  526         QLocalSocket s ;
  527 
  528         if( _connected( s ) ){
  529 
  530             s.write( _json_command( _cookie,QByteArray(),"Write",path,data ) ) ;
  531 
  532             s.waitForBytesWritten() ;
  533         }
  534     }
  535 }
  536 
  537 bool utility::reUseMountPointPath()
  538 {
  539     return REUSE_MOUNT_POINT ;
  540 }
  541 
  542 bool utility::reUseMountPoint()
  543 {
  544     return utility::reUseMountPointPath() ;
  545 }
  546 
  547 int utility::getUID()
  548 {
  549     return static_cast< int >( getuid() ) ;
  550 }
  551 
  552 int utility::getUserID()
  553 {
  554     return utility::getUID() ;
  555 }
  556 
  557 int utility::getGUID( int uid )
  558 {
  559     auto e = getpwuid( static_cast< uid_t >( uid ) ) ;
  560 
  561     if( e ){
  562 
  563         return static_cast< int >( e->pw_gid ) ;
  564     }else{
  565         return uid ;
  566     }
  567 }
  568 
  569 QString utility::getStringUserID()
  570 {
  571     return QString::number( utility::getUserID() ) ;
  572 }
  573 
  574 QString utility::appendUserUID( const QString& e )
  575 {
  576     if( utility::useZuluPolkit() ){
  577 
  578         return e + " -K " + utility::getStringUserID() ;
  579     }else{
  580         return e ;
  581     }
  582 }
  583 
  584 static passwd * _getPassWd()
  585 {
  586     return getpwuid( static_cast< uid_t >( utility::getUserID() ) ) ;
  587 }
  588 
  589 QString utility::userName()
  590 {
  591     return _getPassWd()->pw_name ;
  592 }
  593 
  594 QString utility::homePath()
  595 {
  596     return getpwuid( static_cast< uid_t >( utility::getUserID() ) )->pw_dir ;
  597 }
  598 
  599 static int _help()
  600 {
  601     std::cout << "\n" << VERSION_STRING << std::endl ;
  602 
  603     QString helpMsg = QObject::tr( "\n\
  604 options:\n\
  605     -d   path to where a volume to be auto unlocked/mounted is located\n\
  606     -m   tool to use to open a default file manager(default tool is xdg-open)\n\
  607     -e   start the application without showing the GUI\n" ) ;
  608 
  609     std::cout << helpMsg.toLatin1().constData() << std::endl ;
  610 
  611     return 0 ;
  612 }
  613 
  614 static bool _printHelpOrVersionInfo()
  615 {
  616     QStringList q = QCoreApplication::arguments() ;
  617     return q.contains( "-h" )        ||
  618            q.contains( "-help" )     ||
  619            q.contains( "--help" )    ||
  620            q.contains( "-v" )        ||
  621            q.contains(  "-version" ) ||
  622            q.contains( "--version" ) ;
  623 }
  624 
  625 int utility::startApplication( const char * appName,std::function<int()> start )
  626 {
  627     QCoreApplication::setApplicationName( appName ) ;
  628 
  629     if( _printHelpOrVersionInfo() ){
  630 
  631         return _help() ;
  632     }else{
  633         return start() ;
  634     }
  635 }
  636 
  637 void utility::startApplication( QObject * s,const char * e )
  638 {
  639     QMetaObject::invokeMethod( s,e,Qt::QueuedConnection ) ;
  640 }
  641 
  642 void utility::keySend( const QString& path,const QByteArray& key )
  643 {
  644     ::Task::exec( [ path,key ](){
  645 
  646         auto handle = ::zuluCryptPluginManagerOpenConnection( path.toLatin1().constData() ) ;
  647 
  648         if( handle ){
  649 
  650             size_t size = static_cast< size_t >( key.size() ) ;
  651 
  652             /*
  653              * ZULUCRYPT_KEYFILE_MAX_SIZE is defined in ../zuluCrypt-cli/constants.h
  654              * The variable holds the maximum keyfile size
  655              */
  656 
  657             if( size > ZULUCRYPT_KEYFILE_MAX_SIZE ){
  658 
  659                 size = ZULUCRYPT_KEYFILE_MAX_SIZE ;
  660             }
  661 
  662             ::zuluCryptPluginManagerSendKey( handle,key.constData(),size ) ;
  663             ::zuluCryptPluginManagerCloseConnection( handle ) ;
  664         }
  665     } ) ;
  666 }
  667 
  668 void utility::keySend( const QString& keyPath,const QString& key )
  669 {
  670     utility::keySend( keyPath,key.toLatin1() ) ;
  671 }
  672 
  673 void utility::createPlugInMenu( QMenu * menu,const QString& a,const QString& b,const QString& c,bool addPlugIns )
  674 {
  675     QStringList l ;
  676     QStringList e ;
  677 
  678     l.append( a ) ;
  679 
  680     if( LXQt::Wallet::backEndIsSupported( LXQt::Wallet::BackEnd::libsecret ) ){
  681 
  682         l.append( b ) ;
  683     }
  684     if( LXQt::Wallet::backEndIsSupported( LXQt::Wallet::BackEnd::kwallet ) ){
  685 
  686         l.append( c ) ;
  687     }
  688 
  689     if( addPlugIns ){
  690 
  691         QDir dir( ZULUCRYPTpluginPath ) ;
  692 
  693         if( dir.exists() ){
  694 
  695             e = dir.entryList() ;
  696 
  697             e.removeOne( "zuluCrypt-testKey" ) ;
  698             e.removeOne( "." ) ;
  699             e.removeOne( ".." ) ;
  700             e.removeOne( "keyring" ) ;
  701             e.removeOne( "kwallet" ) ;
  702         }
  703 
  704         //e.append( "network" ) ;
  705     }
  706 
  707     menu->clear() ;
  708 
  709     auto _add_actions = [ menu ]( const QStringList& r ){
  710 
  711         for( const auto& it : r ){
  712 
  713             menu->addAction( it ) ;
  714         }
  715     } ;
  716 
  717     _add_actions( l ) ;
  718     _add_actions( e ) ;
  719 }
  720 
  721 ::Task::future<int>& utility::exec( const QString& exe )
  722 {
  723     return ::Task::run( [ exe ](){ return utility::Task( exe ).exitCode() ; } ) ;
  724 }
  725 
  726 ::Task::future<QStringList>& utility::luksEmptySlots( const QString& volumePath )
  727 {
  728     return ::Task::run( [ volumePath ](){
  729 
  730         auto e = utility::appendUserUID( "%1 -b -d \"%2\"" ) ;
  731 
  732         auto r = utility::Task( e.arg( ZULUCRYPTzuluCrypt,volumePath ) ) ;
  733 
  734         if( r.success() ){
  735 
  736             const auto& s = r.stdOut() ;
  737 
  738             int i = 0 ;
  739 
  740             for( const auto& it : s ){
  741 
  742                 if( it == '1' || it == '3' ){
  743 
  744                     i++ ;
  745                 }
  746             }
  747 
  748             return QStringList{ QString::number( i ),QString::number( s.size() - 1 ) } ;
  749         }
  750 
  751         return QStringList() ;
  752     } ) ;
  753 }
  754 
  755 ::Task::future<QString>& utility::getUUIDFromPath( const QString& dev )
  756 {
  757     return ::Task::run( [ dev ](){
  758 
  759         auto device = dev ;
  760         device = device.replace( "\"", "\"\"\"" ) ;
  761         auto exe = utility::appendUserUID( "%1 -U -d \"%2\"" ).arg( ZULUCRYPTzuluCrypt,device ) ;
  762 
  763         auto r = utility::Task( exe ) ;
  764 
  765         if( r.success() ){
  766 
  767             QString uuid = r.stdOut() ;
  768             uuid.remove( "\n" ) ;
  769 
  770             if( uuid == "UUID=\"\"" ){
  771 
  772                 return QString() ;
  773             }else{
  774                 return uuid ;
  775             }
  776         }else{
  777             return QString() ;
  778         }
  779     } ) ;
  780 }
  781 
  782 ::Task::future<bool>& utility::openPath( const QString& path,const QString& opener )
  783 {
  784     return ::Task::run( [ = ](){
  785 
  786         auto e = opener + " " + utility::Task::makePath( path ) ;
  787 
  788         return utility::Task::run( e,utility::Task::USEPOLKIT::False ).get().failed() ;
  789     } ) ;
  790 }
  791 
  792 void utility::openPath( const QString& path,const QString& opener,
  793             QWidget * obj,const QString& title,const QString& msg )
  794 {
  795     openPath( path,opener ).then( [ title,msg,obj ]( bool failed ){
  796 
  797         if( failed && obj ){
  798 
  799             DialogMsg m( obj ) ;
  800             m.ShowUIOK( title,msg ) ;
  801         }
  802     } ) ;
  803 }
  804 
  805 static ::Task::future<QString>& _getKey( LXQt::Wallet::Wallet& wallet,const QString& volumeID )
  806 {
  807     return ::Task::run( [ & ]()->QString{
  808 
  809         decltype( wallet.readValue( volumeID ) ) key ;
  810 
  811         if( volumeID.startsWith( "UUID=" ) ){
  812 
  813             key = wallet.readValue( volumeID ) ;
  814         }else{
  815             auto uuid = utility::getUUIDFromPath( volumeID ).get() ;
  816 
  817             if( uuid.isEmpty() ){
  818 
  819                 key = wallet.readValue( utility::getVolumeID( volumeID ) ) ;
  820             }else{
  821                 key = wallet.readValue( uuid ) ;
  822 
  823                 if( key.isEmpty() ){
  824 
  825                     key = wallet.readValue( volumeID ) ;
  826                 }
  827             }
  828         }
  829 
  830         return key ;
  831     } ) ;
  832 }
  833 
  834 utility::wallet utility::getKey( LXQt::Wallet::Wallet& wallet,const QString& keyID,const QString& app )
  835 {
  836     utility::wallet w{ false,false,"" } ;
  837 
  838     auto s = wallet.backEnd() ;
  839 
  840     if( s == LXQt::Wallet::BackEnd::kwallet || s == LXQt::Wallet::BackEnd::libsecret ){
  841 
  842         if( s == LXQt::Wallet::BackEnd::kwallet ){
  843 
  844             w.opened = wallet.open( "default",utility::applicationName() ) ;
  845         }else{
  846             w.opened = wallet.open( utility::walletName(),utility::applicationName() ) ;
  847         }
  848 
  849         if( w.opened ){
  850 
  851             w.key = _getKey( wallet,keyID ).await() ;
  852         }
  853 
  854     }else if( s == LXQt::Wallet::BackEnd::internal ){
  855 
  856         auto walletName = utility::walletName() ;
  857         auto appName    = utility::applicationName() ;
  858 
  859         if( LXQt::Wallet::walletExists( s,walletName,appName ) ){
  860 
  861             wallet.setImage( utility::getIcon( app ) ) ;
  862 
  863             if( wallet.opened() ){
  864 
  865                 w.opened = true ;
  866             }else{
  867                 w.opened = wallet.open( walletName,appName ) ;
  868             }
  869 
  870             if( w.opened ){
  871 
  872                 w.key = _getKey( wallet,keyID ).await() ;
  873                 w.notConfigured = false ;
  874             }
  875         }else{
  876             w.notConfigured = true ;
  877         }
  878     }
  879 
  880     return w ;
  881 }
  882 
  883 static quint64 _volumeSize( const QString& e,size_t size )
  884 {
  885     utility::fileHandle h ;
  886 
  887     if( size == 0 ){
  888 
  889         if( h.open( e ) ){
  890 
  891             return h.size() ;
  892         }else{
  893             return 0 ;
  894         }
  895     }else{
  896         return size ;
  897     }
  898 }
  899 
  900 static int _openVolume( const QString& e )
  901 {
  902     return open( e.toLatin1().constData(),O_RDWR ) ;
  903 }
  904 
  905 static std::function< void( int ) > _closeFunction( const QString& e )
  906 {
  907     return [ & ]( int fd ){
  908 
  909         if( fd != -1 ){
  910 
  911             for( int i = 0 ; i < 5 ; i++ ){
  912 
  913                 if( close( fd ) == 0 ){
  914 
  915                     utility::Task( utility::appendUserUID( "%1 -q -d \"%2\"" ).arg( ZULUCRYPTzuluCrypt,e ) ) ;
  916 
  917                     break ;
  918                 }
  919             }
  920         }
  921     } ;
  922 }
  923 
  924 static bool _writeToVolume( int fd,std::array< char,1024 >& buffer )
  925 {
  926     return write( fd,buffer.data(),buffer.size() ) != -1 ;
  927 }
  928 
  929 ::Task::future< int >& utility::clearVolume( const QString& volume,
  930                          std::atomic_bool * exit,
  931                          size_t volumeSize,
  932                          std::function< void( quint64 size,quint64 offset ) > function )
  933 {
  934     return ::Task::run( [ volume,exit,volumeSize,function ](){
  935 
  936         auto volumePath = volume ;
  937 
  938         volumePath.replace( "\"","\"\"\"" ) ;
  939 
  940         auto a = utility::appendUserUID( "%1 -k -J -d \"%2\"" ).arg( ZULUCRYPTzuluCrypt,volumePath ) ;
  941 
  942         int r = utility::Task( a ).exitCode() ;
  943 
  944         if( r != 0 ){
  945 
  946             return r ;
  947         }else{
  948             auto volumeMapperPath = utility::mapperPath( volume ) ;
  949 
  950             utility::fileHandle f( _openVolume( volumeMapperPath ),_closeFunction( volumePath ) ) ;
  951 
  952             int fd = f.handle() ;
  953 
  954             if( fd == -1 ){
  955 
  956                 return 1 ;
  957             }else{
  958                 std::array< char,1024 > buffer ;
  959 
  960                 quint64 size         = _volumeSize( volumeMapperPath,volumeSize ) ;
  961                 quint64 size_written = 0 ;
  962 
  963                 if( size == 0 ){
  964 
  965                     return 0 ;
  966                 }
  967 
  968                 while( _writeToVolume( fd,buffer ) ){
  969 
  970                     if( *exit ){
  971                         /*
  972                          * erasedevice::taskResult() has info on why we return 5 here.
  973                          */
  974                         return 5 ;
  975                     }else{
  976                         size_written += buffer.size() ;
  977 
  978                         function( size,size_written ) ;
  979 
  980                         if( size_written >= size ){
  981 
  982                             break ;
  983                         }
  984                     }
  985                 }
  986             }
  987 
  988             return 0 ;
  989         }
  990     } ) ;
  991 }
  992 
  993 QString utility::cryptMapperPath()
  994 {
  995     //return QString( crypt_get_dir() )
  996     return "/dev/mapper/" ;
  997 }
  998 
  999 bool utility::userIsRoot()
 1000 {
 1001     return getuid() == 0 ;
 1002 }
 1003 
 1004 QString utility::shareMountPointToolTip()
 1005 {
 1006     QString x ;
 1007 #if USE_HOME_PATH_AS_MOUNT_PREFIX
 1008     x = QDir::homePath() + "/" ;
 1009 #else
 1010     x = "/run/media/private/" ;
 1011 #endif
 1012     return QObject::tr( "\
 1013 If the option is checked,a primary private mount point will be created in \"%1\"\n\
 1014 and a secondary publicly accessible \"mirror\" mount point will be created in \"%2\"" ).arg( x,SHARE_MOUNT_PREFIX "/" ) ;
 1015 }
 1016 
 1017 QString utility::shareMountPointToolTip( const QString& path )
 1018 {
 1019     auto s = QString( SHARE_MOUNT_PREFIX "/" ) + path.split( "/" ).last() ;
 1020 
 1021     if( QFile::exists( s ) ){
 1022 
 1023         return QObject::tr( "public mount point: " ) + s ;
 1024     }else{
 1025         return QString() ;
 1026     }
 1027 }
 1028 
 1029 QString utility::sharedMountPointPath( const QString& path )
 1030 {
 1031     if( path == "/" ){
 1032 
 1033         return QString() ;
 1034     }else{
 1035         auto s = SHARE_MOUNT_PREFIX "/" + path.split( "/" ).last() ;
 1036 
 1037         if( QFile::exists( s ) ){
 1038 
 1039             return s ;
 1040         }else{
 1041             return QString() ;
 1042         }
 1043     }
 1044 }
 1045 
 1046 bool utility::pathPointsToAFile( const QString& path )
 1047 {
 1048     utility::fileHandle h ;
 1049 
 1050     if( h.open( path ) ){
 1051 
 1052         return h.isFile() ;
 1053     }else{
 1054         return false ;
 1055     }
 1056 }
 1057 
 1058 bool utility::pathPointsToAFolder( const QString& path )
 1059 {
 1060     utility::fileHandle h ;
 1061 
 1062     if( h.open( path ) ){
 1063 
 1064         return h.isFolder() ;
 1065     }else{
 1066         return false ;
 1067     }
 1068 }
 1069 
 1070 bool utility::useDmCryptForRandomData()
 1071 {
 1072     if( !_settings->contains( "UseDmCryptForRandomData" ) ){
 1073 
 1074         _settings->setValue( "UseDmCryptForRandomData",false ) ;
 1075     }
 1076 
 1077     return _settings->value( "UseDmCryptForRandomData" ).toBool() ;
 1078 }
 1079 
 1080 QString utility::localizationLanguage( const QString& program )
 1081 {
 1082     Q_UNUSED( program )
 1083 
 1084     if( _settings->contains( "LocalizationLanguage" ) ){
 1085 
 1086         return _settings->value( "LocalizationLanguage" ).toString() ;
 1087     }else{
 1088         _settings->setValue( "LocalizationLanguage","en_US" ) ;
 1089 
 1090         return "en_US" ;
 1091     }
 1092 }
 1093 
 1094 void utility::setLocalizationLanguage( const QString& program,const QString& language )
 1095 {
 1096     Q_UNUSED( program )
 1097     _settings->setValue( "LocalizationLanguage",language ) ;
 1098 }
 1099 
 1100 QString utility::localizationLanguagePath( const QString& program )
 1101 {
 1102     return QString( TRANSLATION_PATH ) + program ;
 1103 }
 1104 
 1105 
 1106 QString utility::walletName()
 1107 {
 1108     return "zuluCrypt" ;
 1109 }
 1110 
 1111 QString utility::applicationName()
 1112 {
 1113     return "zuluCrypt" ;
 1114 }
 1115 
 1116 bool utility::pathIsReadable( const QString& path,bool isFolder )
 1117 {
 1118     QFileInfo s( path ) ;
 1119 
 1120     if( isFolder ){
 1121 
 1122         return s.isReadable() && s.isDir() ;
 1123     }else{
 1124         return s.isReadable() && s.isFile() ;
 1125     }
 1126 }
 1127 
 1128 bool utility::pathIsWritable( const QString& path,bool isFolder )
 1129 {
 1130     QFileInfo s( path ) ;
 1131 
 1132     if( isFolder ){
 1133 
 1134         return s.isWritable() && s.isDir() ;
 1135     }else{
 1136         return s.isWritable() && s.isFile() ;
 1137     }
 1138 }
 1139 
 1140 bool utility::configDirectoriesAreNotWritable( QWidget * w )
 1141 {
 1142     auto a = utility::socketPath() ;
 1143     auto b = utility::passwordSocketPath() ;
 1144 
 1145     QDir().mkpath( b ) ;
 1146 
 1147     utility::changePathOwner( b ) ;
 1148     utility::changePathPermissions( b,0700 ) ;
 1149 
 1150     if( utility::pathIsWritable( a ) && utility::pathIsWritable( b ) ){
 1151 
 1152         return false ;
 1153     }else{
 1154         auto e = QObject::tr( "\"%1\" and \"%2\" Folders Must Be Writable." ).arg( a,b ) ;
 1155         DialogMsg( w ).ShowUIOK( QObject::tr( "ERROR" ),e ) ;
 1156         return true ;
 1157     }
 1158 }
 1159 
 1160 bool utility::setOpenVolumeReadOnly( QWidget * parent,bool checked,const QString& app )
 1161 {
 1162     return readOnlyWarning::showWarning( parent,checked,app ) ;
 1163 }
 1164 
 1165 bool utility::getOpenVolumeReadOnlyOption( const QString& app )
 1166 {
 1167     return readOnlyWarning::getOpenVolumeReadOnlyOption( app ) ;
 1168 }
 1169 
 1170 QString utility::keyPath()
 1171 {
 1172     utility::UrandomDataSource randomSource ;
 1173 
 1174     QByteArray data ;
 1175 
 1176     if( randomSource.open() ){
 1177 
 1178         data = randomSource.getData( 64 ) ;
 1179     }else{
 1180         data = utility::CRandDataSource().getData( 64 ) ;
 1181     }
 1182 
 1183     QString a = utility::passwordSocketPath() ;
 1184 
 1185     return QString( "%1/%2" ).arg( a,utility::hashPath( data ).mid( 1 ) ) ;
 1186 }
 1187 
 1188 bool utility::eventFilter( QObject * gui,QObject * watched,QEvent * event,std::function< void() > function )
 1189 {
 1190     if( watched == gui ){
 1191 
 1192         if( event->type() == QEvent::KeyPress ){
 1193 
 1194             auto keyEvent = static_cast< QKeyEvent* >( event ) ;
 1195 
 1196             if( keyEvent->key() == Qt::Key_Escape ){
 1197 
 1198                 function() ;
 1199 
 1200                 return true ;
 1201             }
 1202         }
 1203     }
 1204 
 1205     return false ;
 1206 }
 1207 
 1208 QStringList utility::split( const QString& str,char token )
 1209 {
 1210     if( str.isEmpty() ){
 1211 
 1212         return {} ;
 1213     }
 1214 
 1215     return str.split( token,QString::SkipEmptyParts ) ;
 1216 }
 1217 
 1218 QStringList utility::split( const QByteArray& str,char token )
 1219 {
 1220     return  utility::split( QString( str ),token ) ;
 1221 }
 1222 
 1223 bool utility::mapperPathExists( const QString& path )
 1224 {
 1225     return utility::pathExists( utility::mapperPath( path ) ) ;
 1226 }
 1227 
 1228 QString utility::mountPath( const QString& path )
 1229 {
 1230     auto pass = _getPassWd() ;
 1231 
 1232 #if USE_HOME_PATH_AS_MOUNT_PREFIX
 1233     return QString( "%1/%2" ).arg( QString( pass->pw_dir ) ).arg( path ) ;
 1234 #else
 1235     return QString( "/run/media/private/%1/%2" ).arg( QString( pass->pw_dir ).split( "/" ).last(),path ) ;
 1236 #endif
 1237 }
 1238 
 1239 QString utility::homeMountPath( const QString& path )
 1240 {
 1241     return QString( "%1/%2" ).arg( _getPassWd()->pw_dir,path ) ;
 1242 }
 1243 
 1244 QString utility::mountPathPostFix( const QString& path )
 1245 {
 1246     if( path.isEmpty() ){
 1247 
 1248         return path ;
 1249     }else{
 1250         auto _usable_mount_point = []( const QString& e ){
 1251 
 1252             if( utility::reUseMountPointPath() ){
 1253 
 1254                 if( utility::pathExists( e ) ){
 1255 
 1256                     return utility::pathPointsToAFolder( e ) ;
 1257                 }else{
 1258                     return true ;
 1259                 }
 1260 
 1261             }else{
 1262                 return !utility::pathExists( e ) ;
 1263             }
 1264         } ;
 1265 
 1266         auto e = utility::mountPath( path ) ;
 1267 
 1268         if( _usable_mount_point( e ) ){
 1269 
 1270             return path ;
 1271         }else{
 1272             QString z ;
 1273 
 1274             for( int i = 1 ; i < 1000 ; i++ ){
 1275 
 1276                 z = QString::number( i ) ;
 1277 
 1278                 if( _usable_mount_point( QString( "%1_%2" ).arg( e,z ) ) ){
 1279 
 1280                     return QString( "%1_%2" ).arg( path,z ) ;
 1281                 }
 1282             }
 1283 
 1284             return path ;
 1285         }
 1286     }
 1287 }
 1288 
 1289 QString utility::mapperPath( const QString& r,const QString& component )
 1290 {
 1291     auto rpath = r ;
 1292 
 1293     auto path = utility::cryptMapperPath() + "zuluCrypt-" + utility::getStringUserID() ;
 1294 
 1295     if( rpath.startsWith( "UUID=" ) ){
 1296 
 1297         rpath.remove( '\"' ) ;
 1298 
 1299         rpath.replace( "UUID=","UUID-" ) ;
 1300 
 1301         path += "-" + rpath + utility::hashPath( rpath.toLatin1() ) ;
 1302     }else{
 1303         if( component.isEmpty() ){
 1304 
 1305             path += "-NAAN-" + rpath.split( "/" ).last() + utility::hashPath( rpath.toLatin1() ) ;
 1306         }else{
 1307             path += component + rpath.split( "/" ).last() + utility::hashPath( rpath.toLatin1() ) ;
 1308         }
 1309     }
 1310 
 1311     for( const auto& it : BASH_SPECIAL_CHARS ){
 1312 
 1313         path.replace( it,'_' ) ;
 1314     }
 1315     return path ;
 1316 }
 1317 
 1318 QString utility::hashPath( const QByteArray& p )
 1319 {
 1320     int l = p.size() ;
 1321 
 1322     uint32_t hash = 0 ;
 1323 
 1324     auto key = p.constData() ;
 1325 
 1326     for( int i = 0 ; i < l ; i++ ){
 1327 
 1328         hash += static_cast< unsigned int >( *( key + i ) ) ;
 1329 
 1330         hash += ( hash << 10 ) ;
 1331 
 1332         hash ^= ( hash >> 6 ) ;
 1333     }
 1334 
 1335     hash += ( hash << 3 ) ;
 1336 
 1337     hash ^= ( hash >> 11 ) ;
 1338 
 1339     hash += ( hash << 15 ) ;
 1340 
 1341     return "-" + QString::number( hash ) ;
 1342 }
 1343 
 1344 bool utility::pathExists( const QString& path )
 1345 {
 1346     return QFile::exists( path ) ;
 1347 }
 1348 
 1349 bool utility::canCreateFile( const QString& path )
 1350 {
 1351     auto s = path ;
 1352 
 1353     auto e = s.lastIndexOf( '/' ) ;
 1354 
 1355     if( e != -1 ){
 1356 
 1357         s.truncate( e ) ;
 1358     }
 1359 
 1360     return utility::pathIsWritable( s ) ;
 1361 }
 1362 
 1363 QString utility::resolvePath( const QString& path )
 1364 {
 1365     if( path.size() == 1 && path.at( 0 ) == QChar( '~' ) ){
 1366 
 1367         return utility::homePath() + "/" ;
 1368 
 1369     }else if( path.startsWith( "~/" ) ){
 1370 
 1371         return utility::homePath() + "/" + path.mid( 2 ) ;
 1372 
 1373     }else if( path.startsWith( "UUID= ") ){
 1374 
 1375         return path ;
 1376 
 1377     }else if( path.startsWith( "/dev/" ) ){
 1378 
 1379         return path ;
 1380 
 1381     }else if( path.startsWith( "file://" ) ){
 1382 
 1383         return path.mid( 7 ) ;
 1384     }else{
 1385         QDir r( path ) ;
 1386 
 1387         auto rp = r.canonicalPath() ;
 1388 
 1389         if( rp.isEmpty() ) {
 1390 
 1391             return path ;
 1392         }else{
 1393             return rp ;
 1394         }
 1395     }
 1396 }
 1397 
 1398 QString utility::executableFullPath( const QString& f )
 1399 {
 1400     QString e = f ;
 1401 
 1402     if( e.startsWith( "/" ) ){
 1403 
 1404         auto s =  QDir( f ).canonicalPath() ;
 1405 
 1406         for( const auto& it : utility::executableSearchPaths() ){
 1407 
 1408             if( s.startsWith( it ) ){
 1409 
 1410                 return s ;
 1411             }
 1412         }
 1413 
 1414         return QString() ;
 1415     }
 1416 
 1417     if( e == "ecryptfs" ){
 1418 
 1419         e = "ecryptfs-simple" ;
 1420     }
 1421 
 1422     QString exe ;
 1423 
 1424     for( const auto& it : utility::executableSearchPaths() ){
 1425 
 1426         exe = it + e ;
 1427 
 1428         if( utility::pathExists( exe ) ){
 1429 
 1430             return exe ;
 1431         }
 1432     }
 1433 
 1434     return QString() ;
 1435 }
 1436 
 1437 
 1438 static QString _absolute_exe_path( const QString& exe )
 1439 {
 1440     auto e = utility::executableFullPath( exe ) ;
 1441 
 1442     if( e.isEmpty() ){
 1443 
 1444         return exe ;
 1445     }else{
 1446         return e ;
 1447     }
 1448 }
 1449 
 1450 QString utility::cmdArgumentValue( const QStringList& l,const QString& arg,const QString& defaulT )
 1451 {
 1452     int j = l.size() ;
 1453 
 1454     for( int i = 0 ; i < j ; i++ ){
 1455 
 1456         if( l.at( i ) == arg ){
 1457 
 1458             auto e = [ & ](){
 1459 
 1460                 if( i + 1 < j ){
 1461 
 1462                     return l.at( i + 1 ) ;
 1463                 }else{
 1464                     return defaulT ;
 1465                 }
 1466             } ;
 1467 
 1468             if( arg == "-m" ){
 1469 
 1470                 return _absolute_exe_path( e() ) ;
 1471             }else{
 1472                 return e() ;
 1473             }
 1474         }
 1475     }
 1476 
 1477     return defaulT ;
 1478 }
 1479 
 1480 static QString _device_id_to_partition_id( const QString& id )
 1481 {
 1482     if( id.startsWith( "/dev/disk/by-id" ) ){
 1483 
 1484         auto l = id.split( '\t' ) ;
 1485 
 1486         if( l.size() > 1 ){
 1487 
 1488             QDir d( l.first() ) ;
 1489 
 1490             auto e = d.canonicalPath() ;
 1491 
 1492             if( e.isEmpty() ){
 1493 
 1494                 return l.first() + '\t' + l.at( 1 ) ;
 1495             }else{
 1496                 return e + '\t' + l.at( 1 ) ;
 1497             }
 1498         }else{
 1499             return id ;
 1500         }
 1501     }else{
 1502         return id ;
 1503     }
 1504 }
 1505 
 1506 static QString _partition_id_to_device_id( const QString& id,bool expand )
 1507 {
 1508     if( id.startsWith( "/dev/" ) ){
 1509 
 1510         auto l = utility::directoryList( "/dev/disk/by-id" ) ;
 1511 
 1512         QDir r ;
 1513 
 1514         for( const auto& it : l ){
 1515 
 1516             const auto& e = it ;
 1517 
 1518             if( !e.startsWith( "dm" ) ){
 1519 
 1520                 auto q = QString( "/dev/disk/by-id/%1" ).arg( e ) ;
 1521 
 1522                 r.setPath( q ) ;
 1523 
 1524                 if( r.canonicalPath() == id ){
 1525 
 1526                     if( expand ){
 1527 
 1528                         return q ;
 1529                     }else{
 1530                         return e ;
 1531                     }
 1532                 }
 1533             }
 1534         }
 1535         return id ;
 1536     }else{
 1537         return id ;
 1538     }
 1539 }
 1540 
 1541 QString utility::getVolumeID( const QString& id,bool expand )
 1542 {
 1543     return _partition_id_to_device_id( id,expand ) ;
 1544 }
 1545 
 1546 
 1547 bool utility::showWarningOnExtendingCoverFile()
 1548 {
 1549     if( !_settings->contains( "ShowWarningOnExtendingCoverFile" ) ){
 1550 
 1551          utility::showWarningOnExtendingCoverFile( true ) ;
 1552     }
 1553 
 1554     return _settings->value( "ShowWarningOnExtendingCoverFile" ).toBool() ;
 1555 }
 1556 
 1557 void utility::showWarningOnExtendingCoverFile( bool e )
 1558 {
 1559     _settings->setValue( "ShowWarningOnExtendingCoverFile",e ) ;
 1560 }
 1561 
 1562 void utility::addToFavorite( const QString& dev,const QString& m_point )
 1563 {
 1564     if( !( dev.isEmpty() || m_point.isEmpty() ) ){
 1565 
 1566         QStringList s ;
 1567 
 1568         if( _settings->contains( "Favotites" ) ){
 1569 
 1570              s = _settings->value( "Favotites" ).toStringList() ;
 1571         }
 1572 
 1573         auto e = QString( "%1\t%2" ).arg( _partition_id_to_device_id( dev,true ),m_point ) ;
 1574 
 1575         s.append( e ) ;
 1576 
 1577         _settings->setValue( "Favotites",s ) ;
 1578     }
 1579 }
 1580 
 1581 QStringList utility::readFavorites()
 1582 {
 1583     if( _settings->contains( "Favotites" ) ){
 1584 
 1585          QStringList l ;
 1586 
 1587          for( const auto& it : _settings->value( "Favotites" ).toStringList() ){
 1588 
 1589              if( it.startsWith( "/dev/disk/by-id" ) ){
 1590 
 1591                  l.append( _device_id_to_partition_id( it ) ) ;
 1592              }else{
 1593                  l.append( it ) ;
 1594              }
 1595          }
 1596 
 1597          return l ;
 1598     }else{
 1599         return QStringList() ;
 1600     }
 1601 }
 1602 
 1603 bool utility::unMountVolumesOnLogout()
 1604 {
 1605     if( !_settings->contains( "unMountVolumesOnLogout" ) ){
 1606 
 1607         _settings->setValue( "unMountVolumesOnLogout",false ) ;
 1608     }
 1609 
 1610     return _settings->value( "unMountVolumesOnLogout" ).toBool() ;
 1611 }
 1612 
 1613 void utility::removeFavoriteEntry( const QString& e )
 1614 {
 1615     auto s = utility::readFavorites() ;
 1616 
 1617     s.removeOne( e ) ;
 1618 
 1619     _settings->setValue( "Favotites",s );
 1620 }
 1621 
 1622 void utility::readFavorites( QMenu * m,bool truncate,bool showFolders )
 1623 {
 1624     m->clear() ;
 1625 
 1626     auto _add_action = [ m,truncate ]( const QString& e ){
 1627 
 1628         auto ac = new QAction( m ) ;
 1629 
 1630         if( truncate ){
 1631 
 1632             auto l = utility::split( e,'\t' ) ;
 1633 
 1634             if( l.size() > 0 ){
 1635 
 1636                 ac->setText( l.first() ) ;
 1637             }
 1638         }else{
 1639             ac->setText( e ) ;
 1640         }
 1641 
 1642         ac->setEnabled( !e.startsWith( "/dev/disk/by-id" ) ) ;
 1643 
 1644         return ac ;
 1645     } ;
 1646 
 1647     m->addAction( new QAction( QObject::tr( "Manage Favorites" ),m ) ) ;
 1648 
 1649     m->addAction( new QAction( QObject::tr( "Mount All" ),m ) ) ;
 1650 
 1651     m->addSeparator() ;
 1652 
 1653     for( const auto& it : utility::readFavorites() ){
 1654 
 1655         if( showFolders ){
 1656 
 1657             m->addAction( _add_action( it ) ) ;
 1658         }else{
 1659             auto e = utility::split( it,'\t' ).first() ;
 1660 
 1661             if( utility::pathExists( e ) ){
 1662 
 1663                 if( !utility::pathPointsToAFolder( e ) ){
 1664 
 1665                     m->addAction( _add_action( it ) ) ;
 1666                 }
 1667             }
 1668         }
 1669     }
 1670 }
 1671 
 1672 int utility::favoriteClickedOption( const QString& opt )
 1673 {
 1674     if( opt == QObject::tr( "Manage Favorites" ) ){
 1675 
 1676         return 1 ;
 1677 
 1678     }else if( opt == QObject::tr( "Mount All" ) ){
 1679 
 1680         return 2 ;
 1681     }else{
 1682         return 3 ;
 1683     }
 1684 }
 1685 
 1686 bool utility::userHasGoodVersionOfWhirlpool()
 1687 {
 1688 #ifdef GCRYPT_VERSION_NUMBER
 1689     return GCRYPT_VERSION_NUMBER >= 0x010601 && SUPPORT_WHIRLPOOL ;
 1690 #else
 1691     return SUPPORT_WHIRLPOOL ;
 1692 #endif
 1693 }
 1694 
 1695 void utility::licenseInfo( QWidget * parent )
 1696 {
 1697     QString s = "\nGpg key fingerprint: E3AF84691424AD00E099003502FC64E8DEBF43A8" ;
 1698 
 1699     QString license = QString( "%1\n\n\
 1700 This program is free software: you can redistribute it and/or modify \
 1701 it under the terms of the GNU General Public License as published by \
 1702 the Free Software Foundation, either version 2 of the License, or \
 1703 ( at your option ) any later version.\n\
 1704 \n\
 1705 This program is distributed in the hope that it will be useful,\
 1706 but WITHOUT ANY WARRANTY; without even the implied warranty of \
 1707 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the \
 1708 GNU General Public License for more details." ).arg( VERSION_STRING + s ) ;
 1709 
 1710 
 1711     DialogMsg m( parent ) ;
 1712     m.ShowUIInfo( QObject::tr( "about zuluCrypt" ),false,license ) ;
 1713 }
 1714 
 1715 static utility::array_t _default_dimensions( const char * defaults )
 1716 {
 1717     auto l = QString( defaults ).split( ' ' ) ;
 1718 
 1719     utility::array_t e ;
 1720 
 1721     auto f = e.data() ;
 1722 
 1723     auto j = l.size() ;
 1724 
 1725     for( int i = 0 ; i < j ; i++ ){
 1726 
 1727         *( f + i ) = l.at( i ).toInt() ;
 1728     }
 1729 
 1730     return e ;
 1731 }
 1732 
 1733 static utility::array_t _dimensions( const char * defaults,int size )
 1734 {
 1735     if( _settings->contains( "Dimensions" ) ){
 1736 
 1737         auto l = _settings->value( "Dimensions" ).toStringList() ;
 1738 
 1739         utility::array_t p ;
 1740 
 1741         if( l.size() != size || size > int( p.size() ) ){
 1742 
 1743             utility::debug() << "Failed to parse config file" ;
 1744             return _default_dimensions( defaults ) ;
 1745         }
 1746 
 1747         auto f = p.data() ;
 1748 
 1749         auto j = l.size() ;
 1750 
 1751         for( int i = 0 ; i < j ; i++ ){
 1752 
 1753             bool ok ;
 1754 
 1755             int e = l.at( i ).toInt( &ok ) ;
 1756 
 1757             if( ok ){
 1758 
 1759                 *( f + i ) = e ;
 1760             }else{
 1761                 qDebug() << "failed to parse config file option" ;
 1762                 return _default_dimensions( defaults ) ;
 1763             }
 1764         }
 1765 
 1766         return p ;
 1767     }else{
 1768         return _default_dimensions( defaults ) ;
 1769     }
 1770 }
 1771 
 1772 utility::array_t utility::getWindowDimensions( const QString& application )
 1773 {
 1774     if( application == "zuluCrypt" ){
 1775 
 1776         return _dimensions( "297 189 782 419 298 336 100",7 ) ;
 1777     }else{
 1778         return _dimensions( "205 149 910 477 220 320 145 87 87",9 ) ;
 1779     }
 1780 }
 1781 
 1782 void utility::setWindowDimensions( const QString& application,const std::initializer_list<int>& e )
 1783 {
 1784     Q_UNUSED( application )
 1785 
 1786     QStringList s ;
 1787 
 1788     for( const auto& it : e ){
 1789 
 1790         s.append( QString::number( it ) ) ;
 1791     }
 1792 
 1793     _settings->setValue( "Dimensions",s ) ;
 1794 }
 1795 
 1796 QFont utility::getFont( QWidget * widget )
 1797 {
 1798     if( !_settings->contains( "Font") ){
 1799 
 1800         return widget->font() ;
 1801     }else{
 1802         auto l = _settings->value( "Font" ).toStringList() ;
 1803 
 1804         if( l.size() >= 4 ){
 1805 
 1806             QFont F ;
 1807 
 1808             const QString& fontFamily = l.at( 0 ) ;
 1809             const QString& fontSize   = l.at( 1 ) ;
 1810             const QString& fontStyle  = l.at( 2 ) ;
 1811             const QString& fontWeight = l.at( 3 ) ;
 1812 
 1813             F.setFamily( fontFamily ) ;
 1814 
 1815             F.setPointSize( fontSize.toInt() ) ;
 1816 
 1817             if( fontStyle == "normal" ){
 1818 
 1819                 F.setStyle( QFont::StyleNormal ) ;
 1820 
 1821             }else if( fontStyle == "italic" ){
 1822 
 1823                 F.setStyle( QFont::StyleItalic ) ;
 1824             }else{
 1825                 F.setStyle( QFont::StyleOblique ) ;
 1826             }
 1827 
 1828             if( fontWeight == "normal" ){
 1829 
 1830                 F.setWeight( QFont::Normal ) ;
 1831             }else{
 1832                 F.setWeight( QFont::Bold ) ;
 1833             }
 1834 
 1835             return F ;
 1836         }else{
 1837             return widget->font() ;
 1838         }
 1839     }
 1840 }
 1841 
 1842 void utility::saveFont( const QFont& Font )
 1843 {
 1844     auto s = QString( "%1\n%2\n" ).arg( Font.family(),QString::number( Font.pointSize() ) ) ;
 1845 
 1846     if( Font.style() == QFont::StyleNormal ){
 1847 
 1848         s = s + "normal\n" ;
 1849 
 1850     }else if( Font.style() == QFont::StyleItalic ){
 1851 
 1852         s = s + "italic\n" ;
 1853     }else{
 1854         s = s + "oblique\n" ;
 1855     }
 1856 
 1857     if( Font.weight() == QFont::Normal ){
 1858 
 1859         s = s + "normal\n" ;
 1860     }else{
 1861         s = s + "bold" ;
 1862     }
 1863 
 1864     _settings->setValue( "Font",utility::split( s,'\n' ) ) ;
 1865 }
 1866 
 1867 bool utility::runningInMixedMode()
 1868 {
 1869     return utility::useZuluPolkit() ;
 1870 }
 1871 
 1872 bool utility::notRunningInMixedMode()
 1873 {
 1874     return !utility::runningInMixedMode() ;
 1875 }
 1876 
 1877 bool utility::userBelongsToGroup( const char * groupname )
 1878 {
 1879     auto user = getpwuid( static_cast< gid_t >( utility::getUserID() ) ) ;
 1880 
 1881     if( user != nullptr ){
 1882 
 1883         auto grp = getgrnam( groupname ) ;
 1884 
 1885         if( grp != nullptr ){
 1886 
 1887             auto name  = user->pw_name ;
 1888 
 1889             for( auto e = grp->gr_mem ; *e ; e++ ){
 1890 
 1891                 if( strcmp( *e,name ) == 0 ){
 1892 
 1893                     return true ;
 1894                 }
 1895             }
 1896         }
 1897     }
 1898 
 1899     return false ;
 1900 }
 1901 
 1902 int utility::pluginKey( QWidget * w,QByteArray * key,const QString& p )
 1903 {
 1904     plugins::plugin pluginType ;
 1905     QString pluginString ;
 1906     QVector<QString> exe ;
 1907 
 1908     if( p == "hmac" ){
 1909 
 1910         pluginType   = plugins::plugin::hmac_key ;
 1911         pluginString = QObject::tr( "hmac plugin.\n\nThis plugin generates a key using below formular:\n\nkey = hmac(sha256,passphrase,keyfile contents)" ) ;
 1912 
 1913     }else if( p == "keykeyfile" ){
 1914 
 1915         pluginType   = plugins::plugin::keyKeyFile ;
 1916         pluginString = QObject::tr( "keykeyfile plugin.\n\nThis plugin generates a key using below formular:\n\nkey = passphrase + keyfile contents" ) ;
 1917 
 1918     }else if( p == "gpg" ){
 1919 
 1920         pluginType   = plugins::plugin::gpg ;
 1921         pluginString = QObject::tr( "gpg plugin.\n\nThis plugin retrives a key locked in a gpg file with a symmetric key" ) ;
 1922 
 1923         if( utility::pathExists( "/usr/bin/gpg" ) ){
 1924 
 1925             exe.append( "/usr/bin/gpg" ) ;
 1926 
 1927         }else if( utility::pathExists( "/usr/local/bin/gpg" ) ){
 1928 
 1929             exe.append( "/usr/local/bin/gpg" ) ;
 1930 
 1931         }else if( utility::pathExists( "/usr/sbin/gpg" ) ){
 1932 
 1933             exe.append( "/usr/sbin/gpg" ) ;
 1934 
 1935         }else{
 1936 
 1937             DialogMsg msg( w ) ;
 1938 
 1939             msg.ShowUIOK( QObject::tr( "ERROR" ),QObject::tr( "Could not find \"gpg\" executable in \"/usr/local/bin\",\"/usr/bin\" and \"/usr/sbin\"" ) ) ;
 1940 
 1941             return 1 ;
 1942         }
 1943 
 1944     }else{
 1945         return 1 ;
 1946     }
 1947 
 1948     QEventLoop l ;
 1949 
 1950     plugin::instance( w,pluginType,[ & ]( const QByteArray& e ){
 1951 
 1952         *key = e ;
 1953 
 1954         if( e.isEmpty() ){
 1955 
 1956             l.exit( 1 ) ;
 1957         }else{
 1958             l.exit( 0 ) ;
 1959         }
 1960 
 1961     },pluginString,exe ) ;
 1962 
 1963     return l.exec() ;
 1964 }
 1965 
 1966 void utility::showTrayIcon( QAction * ac,QObject * obj,bool show )
 1967 {
 1968     bool opt_show = true ;
 1969 
 1970     if( ac ){
 1971 
 1972         if( !_settings->contains( "ShowTrayIcon" ) ){
 1973 
 1974             _settings->setValue( "ShowTrayIcon",true ) ;
 1975         }
 1976 
 1977         ac->setCheckable( true ) ;
 1978 
 1979         if( _settings->value( "ShowTrayIcon" ).toBool() ){
 1980 
 1981             ac->setChecked( true ) ;
 1982             opt_show = true ;
 1983         }else{
 1984             ac->setChecked( false ) ;
 1985             opt_show = false ;
 1986         }
 1987     }
 1988 
 1989     auto _show_tray = [ & ]{
 1990 
 1991         QMetaObject::invokeMethod( obj,"showTrayIcon",Qt::QueuedConnection,
 1992                        Q_ARG( bool,show ? show : opt_show ) ) ;
 1993     } ;
 1994 
 1995     for( int i = 0 ; i < 10 ; i++ ){
 1996 
 1997         if( QSystemTrayIcon::isSystemTrayAvailable() ){
 1998 
 1999             return _show_tray() ;
 2000         }else{
 2001             utility::Task::suspendForOneSecond() ;
 2002         }
 2003     }
 2004 
 2005     /*
 2006      * The tray doesnt seem to be ready yet but we cant wait any longer,just display it and
 2007      * hope for the best.
 2008      */
 2009     _show_tray() ;
 2010 }
 2011 
 2012 void utility::trayProperty( QSystemTrayIcon * trayIcon,bool zuluCrypt )
 2013 {
 2014     Q_UNUSED( zuluCrypt )
 2015 
 2016     if( _settings->contains( "ShowTrayIcon" ) ){
 2017 
 2018         if( _settings->value( "ShowTrayIcon" ).toBool() ){
 2019 
 2020             _settings->setValue( "ShowTrayIcon",false ) ;
 2021             trayIcon->hide() ;
 2022         }else{
 2023             _settings->setValue( "ShowTrayIcon",true ) ;
 2024             trayIcon->show() ;
 2025         }
 2026     }
 2027 }
 2028 
 2029 class translator
 2030 {
 2031 public:
 2032     void set( const QString& app,const QByteArray& r,int s )
 2033     {
 2034         QCoreApplication::installTranslator( [ & ](){
 2035 
 2036             auto f = m_translator.data() ;
 2037             auto e = *( f + s ) ;
 2038 
 2039             if( e ){
 2040 
 2041                 QCoreApplication::removeTranslator( e ) ;
 2042 
 2043                 delete e ;
 2044             }
 2045 
 2046             e = new QTranslator() ;
 2047 
 2048             e->load( r.constData(),utility::localizationLanguagePath( app ) ) ;
 2049 
 2050             *( f + s ) = e ;
 2051 
 2052             return e ;
 2053         }() ) ;
 2054     }
 2055     ~translator()
 2056     {
 2057         for( auto e : m_translator ){
 2058 
 2059             if( e ){
 2060 
 2061                 /*
 2062                  * QApplication appear to already be gone by the time we get here.
 2063                  */
 2064                 //QCoreApplication::removeTranslator( e ) ;
 2065 
 2066                 delete e ;
 2067             }
 2068         }
 2069     }
 2070 
 2071 private:
 2072     std::array< QTranslator *,2 > m_translator = { { nullptr,nullptr } } ;
 2073 } static _translator ;
 2074 
 2075 static void _selectOption( QMenu * m,const QString& opt )
 2076 {
 2077     utility::selectMenuOption s( m,false ) ;
 2078     s.selectOption( opt ) ;
 2079 }
 2080 
 2081 void utility::setLocalizationLanguage( bool translate,QMenu * m,const QString& app )
 2082 {
 2083     auto r = utility::localizationLanguage( app ).toLatin1() ;
 2084 
 2085     if( translate ){
 2086 
 2087         _translator.set( app,r,0 ) ;
 2088 
 2089         if( app == "zuluMount-gui" ){
 2090 
 2091             /*
 2092              * We are loading zuluCrypt-gui translation file to get translations for
 2093              * lxqtwallet strings.
 2094              */
 2095             _translator.set( "zuluCrypt-gui",r,1 ) ;
 2096         }
 2097     }else{
 2098         QDir d( utility::localizationLanguagePath( app ) ) ;
 2099 
 2100         auto t = d.entryList() ;
 2101 
 2102         if( !t.isEmpty() ){
 2103 
 2104             t.removeOne( "." ) ;
 2105             t.removeOne( ".." ) ;
 2106 
 2107             for( auto& it : t ){
 2108 
 2109                 m->addAction( it.remove( ".qm" ) )->setCheckable( true ) ;
 2110             }
 2111         }
 2112 
 2113         _selectOption( m,r ) ;
 2114     }
 2115 }
 2116 
 2117 void utility::languageMenu( QWidget * w,QMenu * m,QAction * ac,const char * app )
 2118 {
 2119     Q_UNUSED( w )
 2120 
 2121     auto e = ac->text() ;
 2122 
 2123     e.remove( "&" ) ;
 2124 
 2125     utility::setLocalizationLanguage( app,e ) ;
 2126 
 2127     utility::setLocalizationLanguage( true,m,app ) ;
 2128 
 2129     _selectOption( m,e ) ;
 2130 
 2131     return ;
 2132 }
 2133 
 2134 QStringList utility::directoryList( const QString& e )
 2135 {
 2136     QDir d( e ) ;
 2137 
 2138     auto l = d.entryList() ;
 2139 
 2140     l.removeOne( "." ) ;
 2141     l.removeOne( ".." ) ;
 2142 
 2143     return l ;
 2144 }
 2145 
 2146 void utility::setIconMenu( const QString& app,QAction * ac,QWidget * w,
 2147                std::function< void( const QString& ) >&& function )
 2148 {
 2149     ac->setMenu( [ & ](){
 2150 
 2151         auto m = new QMenu( w ) ;
 2152 
 2153         auto n = new utility::selectMenuOption( m,true,std::move( function ) ) ;
 2154 
 2155         w->connect( m,SIGNAL( triggered( QAction * ) ),n,SLOT( selectOption( QAction * ) ) ) ;
 2156 
 2157         if( !_settings->contains( "IconName" ) ){
 2158 
 2159             _settings->setValue( "IconName",app ) ;
 2160         }
 2161 
 2162         QString s = _settings->value( "IconName" ).toString() ;
 2163 
 2164         QDir d( INSTALL_PREFIX "/share/icons/hicolor/48x48/apps/" ) ;
 2165 
 2166         d.setNameFilters( { "zuluCrypt.*","zuluMount.*" } ) ;
 2167 
 2168         for( auto& it : d.entryList() ){
 2169 
 2170             if( it.startsWith( app ) ){
 2171 
 2172                 if( it != "zuluCrypt.png" && it != "zuluMount.png" ){
 2173 
 2174                     it.remove( app + "." ) ;
 2175                 }
 2176 
 2177                 it.remove( ".png" ) ;
 2178 
 2179                 auto ac = m->addAction( it ) ;
 2180 
 2181                 ac->setCheckable( true ) ;
 2182 
 2183                 ac->setChecked( it == s ) ;
 2184             }
 2185         }
 2186 
 2187         return m ;
 2188     }() ) ;
 2189 }
 2190 
 2191 void utility::setIcons( const QString& app,const QString& iconName )
 2192 {
 2193     Q_UNUSED( app )
 2194     _settings->setValue( "IconName",iconName ) ;
 2195 }
 2196 
 2197 QIcon utility::getIcon( const QString& app )
 2198 {
 2199     if( !_settings->contains( "IconName" ) ){
 2200 
 2201         _settings->setValue( "IconName",app ) ;
 2202     }
 2203 
 2204     QString e = _settings->value( "IconName" ).toString() ;
 2205 
 2206     if( e == "zuluCrypt" || e == "zuluMount" ){
 2207 
 2208         QIcon icon( INSTALL_PREFIX "/share/icons/hicolor/48x48/apps/" + e + ".png" ) ;
 2209         return QIcon::fromTheme( app,icon ) ;
 2210     }else{
 2211         return QIcon( INSTALL_PREFIX "/share/icons/hicolor/48x48/apps/" + app + "." + e + ".png" ) ;
 2212     }
 2213 }
 2214 
 2215 bool utility::autoSetVolumeAsVeraCrypt( const QString& app )
 2216 {
 2217     Q_UNUSED( app )
 2218 
 2219     if( _settings->contains( "AutoSetVolumeAsVeraCrypt" ) ){
 2220 
 2221         return _settings->value( "AutoSetVolumeAsVeraCrypt" ).toBool() ;
 2222     }else{
 2223         _settings->setValue( "AutoOpenFolderOnMount",false ) ;
 2224 
 2225         return false ;
 2226     }
 2227 }
 2228 
 2229 void utility::autoSetVolumeAsVeraCrypt( const QString& app,bool set )
 2230 {
 2231     Q_UNUSED( app )
 2232     _settings->setValue( "AutoSetVolumeAsVeraCrypt",set ) ;
 2233 }
 2234 
 2235 int utility::defaultUnlockingVolumeType()
 2236 {
 2237     if( !_settings->contains( "DefaultUnlockingVolumeType" ) ){
 2238 
 2239         _settings->setValue( "DefaultUnlockingVolumeType",0 ) ;
 2240     }
 2241 
 2242     return _settings->value( "DefaultUnlockingVolumeType" ).toInt() ;
 2243 }
 2244 
 2245 void utility::defaultUnlockingVolumeType( int e )
 2246 {
 2247     _settings->setValue( "DefaultUnlockingVolumeType",e ) ;
 2248 
 2249 }
 2250 
 2251 void utility::autoOpenFolderOnMount( const QString& app,bool e )
 2252 {
 2253     Q_UNUSED( app )
 2254     _settings->setValue( "AutoOpenFolderOnMount",e ) ;
 2255 }
 2256 
 2257 bool utility::autoOpenFolderOnMount( const QString& app )
 2258 {
 2259     Q_UNUSED( app )
 2260 
 2261     if( _settings->contains( "AutoOpenFolderOnMount" ) ){
 2262 
 2263         return _settings->value( "AutoOpenFolderOnMount" ).toBool() ;
 2264     }else{
 2265         _settings->setValue( "AutoOpenFolderOnMount",true ) ;
 2266 
 2267         return true ;
 2268     }
 2269 }
 2270 
 2271 QString utility::powerOffCommand()
 2272 {
 2273     if( _settings->contains( "PowerOffCommand" ) ){
 2274 
 2275         return _settings->value( "PowerOffCommand" ).toString() ;
 2276     }else{
 2277         _settings->setValue( "PowerOffCommand","" ) ;
 2278 
 2279         return QString() ;
 2280     }
 2281 }
 2282 
 2283 void utility::setDoNotMinimizeToTray( bool e )
 2284 {
 2285     _settings->setValue( "doNotMinimizeToTray",e ) ;
 2286 }
 2287 
 2288 bool utility::doNotMinimizeToTray()
 2289 {
 2290     if( !_settings->contains( "doNotMinimizeToTray" ) ){
 2291 
 2292         _settings->setValue( "doNotMinimizeToTray",false ) ;
 2293     }
 2294 
 2295     return _settings->value( "doNotMinimizeToTray" ).toBool() ;
 2296 }
 2297 
 2298 void utility::mountWithSharedMountPoint( bool e )
 2299 {
 2300     _settings->setValue( "mountWithSharedMountPoint",e ) ;
 2301 }
 2302 
 2303 bool utility::mountWithSharedMountPoint()
 2304 {
 2305     if( !_settings->contains( "mountWithSharedMountPoint" ) ){
 2306 
 2307         _settings->setValue( "mountWithSharedMountPoint",false ) ;
 2308     }
 2309 
 2310     return _settings->value( "mountWithSharedMountPoint" ).toBool() ;
 2311 }
 2312 
 2313 QString utility::prettyfySpaceUsage( quint64 s )
 2314 {
 2315     auto _convert = [ & ]( const char * p,double q ){
 2316 
 2317         auto e = QString::number( double( s ) / q,'f',2 ) ;
 2318 
 2319         e.remove( ".00" ) ;
 2320 
 2321         return QString( "%1 %2" ).arg( e,p ) ;
 2322     } ;
 2323 
 2324     switch( QString::number( s ).size() ){
 2325 
 2326         case 0 :
 2327         case 1 : case 2 : case 3 :
 2328 
 2329             return QString( "%1 B" ).arg( QString::number( s ) ) ;
 2330 
 2331         case 4 : case 5 : case 6 :
 2332 
 2333             return _convert( "KB",1024 ) ;
 2334 
 2335         case 7 : case 8 : case 9 :
 2336 
 2337             return _convert( "MB",1048576 ) ;
 2338 
 2339         case 10: case 11 : case 12 :
 2340 
 2341             return _convert( "GB",1073741824 ) ;
 2342 
 2343         default:
 2344             return _convert( "TB",1024.0 * 1073741824 ) ;
 2345     }
 2346 }
 2347 
 2348 QStringList utility::plainDmCryptOptions()
 2349 {
 2350     if( _settings->contains( "PlainDmCryptOptions" ) ){
 2351 
 2352         return _settings->value( "PlainDmCryptOptions" ).toStringList() ;
 2353     }else{
 2354         QStringList s = {
 2355 
 2356             { "aes.cbc-essiv:sha256.256.sha256" },
 2357             { "aes.cbc-essiv:sha256.256.sha512" },
 2358             { "aes.cbc-essiv:sha256.256.sha1" },
 2359             { "aes.cbc-essiv:sha256.256.ripemd160" },
 2360             { "aes.cbc-essiv:sha256.512.sha256" },
 2361             { "aes.cbc-essiv:sha256.512.sha512" },
 2362             { "aes.cbc-essiv:sha256.512.sha1" },
 2363             { "aes.cbc-essiv:sha256.512.ripemd160" },
 2364             { "aes.xts-plain64.256.sha256" },
 2365             { "aes.xts-plain64.256.sha512" },
 2366             { "aes.xts-plain64.256.sha1" },
 2367             { "aes.xts-plain64.256.ripemd160" },
 2368             { "aes.xts-plain64.512.sha256" },
 2369             { "aes.xts-plain64.512.sha512" },
 2370             { "aes.xts-plain64.512.sha1" },
 2371             { "aes.xts-plain64.512.ripemd160" },
 2372         };
 2373 
 2374         _settings->setValue( "PlainDmCryptOptions",s ) ;
 2375 
 2376         return s ;
 2377     }
 2378 }
 2379 
 2380 QStringList utility::supportedFileSystems()
 2381 {
 2382     if( _settings->contains( "SupportedFileSystems" ) ){
 2383 
 2384         return _settings->value( "SupportedFileSystems" ).toStringList() ;
 2385     }else{
 2386         QStringList s{ "ext4","vfat","ntfs","ext2","ext3","exfat","ntfs","btrfs" } ;
 2387 
 2388         _settings->setValue( "SupportedFileSystems",s ) ;
 2389 
 2390         return s ;
 2391     }
 2392 }
 2393 
 2394 std::pair< bool,QByteArray > utility::getKeyFromNetwork( const QString& e )
 2395 {
 2396     Q_UNUSED( e )
 2397 
 2398     return { false,QByteArray() } ;
 2399 #if 0
 2400     if( !_settings->contains( "NetworkAddress" ) ){
 2401 
 2402         return _settings->setValue( "NetworkAddress","127.0.0.1" ) ;
 2403     }
 2404 
 2405     QFile f( utility::homePath() + "/.zuluCrypt/network" ) ;
 2406 
 2407     if( !f.open( QIODevice::ReadOnly ) ){
 2408 
 2409         return { false,"" } ;
 2410     }
 2411 
 2412     QUrl url ;
 2413 
 2414     QByteArray data = "device=" + utility::split( e,' ' ).last().toLatin1() ;
 2415 
 2416     QByteArray host ;
 2417 
 2418     for( const auto& it : utility::split( f.readAll() ) ){
 2419 
 2420         if( it.startsWith( "url=" ) ){
 2421 
 2422             url.setUrl( it.toLatin1().constData() + 4 ) ;
 2423 
 2424         }else if( it.startsWith( "host=" ) ){
 2425 
 2426             host = it.toLatin1().constData() + 5 ;
 2427         }else{
 2428             data += "&" + it ;
 2429         }
 2430     }
 2431 
 2432     QNetworkRequest n( url ) ;
 2433 
 2434     n.setRawHeader( "Host",host ) ;
 2435     n.setRawHeader( "Content-Type","application/x-www-form-urlencoded" ) ;
 2436 
 2437     NetworkAccessManager m ;
 2438 
 2439     auto s = m.post( n,data ) ;
 2440 
 2441     if( s->error() == QNetworkReply::NoError ){
 2442 
 2443         return { true,s->readAll() } ;
 2444     }else{
 2445         return { false,"" } ;
 2446     }
 2447 #endif
 2448 }
 2449 
 2450 void utility::setHDPI( const QString& e )
 2451 {
 2452     Q_UNUSED( e )
 2453 
 2454 #if QT_VERSION >= 0x050600
 2455 
 2456     QApplication::setAttribute( Qt::AA_EnableHighDpiScaling ) ;
 2457 
 2458     if( !_settings->contains( "ScaleFactor" ) ){
 2459 
 2460         _settings->setValue( "ScaleFactor","1" ) ;
 2461     }
 2462 
 2463     qputenv( "QT_SCALE_FACTOR",_settings->value( "ScaleFactor" ).toString().toLatin1() ) ;
 2464 #endif
 2465 }
 2466 
 2467 bool utility::platformIsLinux()
 2468 {
 2469     return true ;
 2470 }
 2471 
 2472 bool utility::platformIsOSX()
 2473 {
 2474     return false ;
 2475 }
 2476 
 2477 QStringList utility::executableSearchPaths()
 2478 {
 2479     return ::executableSearchPaths::values() ;
 2480 }
 2481 
 2482 QString utility::executableSearchPaths( const QString& e )
 2483 {
 2484     if( e.isEmpty() ){
 2485 
 2486         return utility::executableSearchPaths().join( ":" ) ;
 2487     }else{
 2488         return e + ":" + utility::executableSearchPaths().join( ":" ) ;
 2489     }
 2490 }
 2491 
 2492 static inline bool _terminalEchoOff( struct termios * old,struct termios * current )
 2493 {
 2494     if( tcgetattr( 1,old ) != 0 ){
 2495 
 2496         return false ;
 2497     }
 2498 
 2499     *current = *old;
 2500     current->c_lflag &= static_cast< unsigned int >( ~ECHO ) ;
 2501 
 2502     if( tcsetattr( 1,TCSAFLUSH,current ) != 0 ){
 2503 
 2504         return false ;
 2505     }else{
 2506         return true ;
 2507     }
 2508 }
 2509 
 2510 QString utility::readPassword( bool addNewLine )
 2511 {
 2512     std::cout << "Password: " << std::flush ;
 2513 
 2514     struct termios old ;
 2515     struct termios current ;
 2516 
 2517     _terminalEchoOff( &old,&current ) ;
 2518 
 2519     QString s ;
 2520     int e ;
 2521 
 2522     int m = 1024 ;
 2523 
 2524     for( int i = 0 ; i < m ; i++ ){
 2525 
 2526         e = std::getchar() ;
 2527 
 2528         if( e == '\n' || e == -1 ){
 2529 
 2530             break ;
 2531         }else{
 2532             s += static_cast< char >( e ) ;
 2533         }
 2534     }
 2535 
 2536     tcsetattr( 1,TCSAFLUSH,&old ) ;
 2537 
 2538     if( addNewLine ){
 2539 
 2540         std::cout << std::endl ;
 2541     }
 2542 
 2543     return s ;
 2544 }
 2545 
 2546 QString utility::fileManager()
 2547 {
 2548     if( _settings->contains( "FileManager" ) ){
 2549 
 2550         return _settings->value( "FileManager" ).toString() ;
 2551     }else{
 2552         _settings->setValue( "FileManager","xdg-open" ) ;
 2553 
 2554         return "xdg-open" ;
 2555     }
 2556 }
 2557 
 2558 void utility::setFileManager( const QString& e )
 2559 {
 2560     if( e.isEmpty() ){
 2561 
 2562         _settings->setValue( "FileManager","xdg-open" ) ;
 2563     }else{
 2564         _settings->setValue( "FileManager",e ) ;
 2565     }
 2566 }
 2567 
 2568 QProcessEnvironment utility::systemEnvironment()
 2569 {
 2570     auto e = QProcessEnvironment::systemEnvironment() ;
 2571 
 2572     e.insert( "zuluCryptRuntimePath",utility::passwordSocketPath() + "/" ) ;
 2573 
 2574     e.insert( "CRYFS_NO_UPDATE_CHECK","TRUE" ) ;
 2575     e.insert( "CRYFS_FRONTEND","noninteractive" ) ;
 2576 
 2577     e.insert( "LANG","C" ) ;
 2578 
 2579     e.insert( "PATH",utility::executableSearchPaths( e.value( "PATH" ) ) ) ;
 2580 
 2581     return e ;
 2582 }
 2583 
 2584 bool utility::clearPassword()
 2585 {
 2586     if( _settings->contains( "ClearPassword" ) ){
 2587 
 2588         return _settings->value( "ClearPassword" ).toBool() ;
 2589     }else{
 2590         _settings->setValue( "ClearPassword",true ) ;
 2591 
 2592         return true ;
 2593     }
 2594 }
 2595 
 2596 bool utility::readOnlyOption()
 2597 {
 2598     if( _settings->contains( "ReadOnly" ) ){
 2599 
 2600         return _settings->value( "ReadOnly" ).toBool() ;
 2601     }else{
 2602         _settings->setValue( "ReadOnly",false ) ;
 2603 
 2604         return false ;
 2605     }
 2606 }
 2607 
 2608 void utility::readOnlyOption( bool e )
 2609 {
 2610     _settings->setValue( "ReadOnly",e ) ;
 2611 }
 2612 
 2613 bool utility::readOnlyWarning()
 2614 {
 2615     if( _settings->contains( "ReadOnlyWarning" ) ){
 2616 
 2617         return _settings->value( "ReadOnlyWarning" ).toBool() ;
 2618     }else{
 2619         _settings->setValue( "ReadOnlyWarning",true ) ;
 2620 
 2621         return true ;
 2622     }
 2623 }
 2624 
 2625 void utility::readOnlyWarning( bool e )
 2626 {
 2627     _settings->setValue( "ReadOnlyWarning",e ) ;
 2628 }
 2629 
 2630 QString utility::failedToStartzuluPolkit()
 2631 {
 2632     return QObject::tr( "Failed To Start Helper Application.\n\n\"org.zulucrypt.zulupolkit.policy\" polkit file is misconfigured,\nzuluPolkit executable could not be found\n or pkexec failed to start zuluPolkit." ) ;
 2633 }
 2634 
 2635 static utility::result< int > _convert_string_to_version( const QString& e )
 2636 {
 2637     auto _convert = []( const QString& e )->utility::result< int >{
 2638 
 2639         bool ok ;
 2640 
 2641         auto s = e.toInt( &ok ) ;
 2642 
 2643         if( ok ){
 2644 
 2645             return s  ;
 2646         }else{
 2647             return {} ;
 2648         }
 2649     } ;
 2650 
 2651     auto s = utility::split( e,'.' ) ;
 2652 
 2653     auto components = s.size() ;
 2654 
 2655     int major = 1000000 ;
 2656     int minor = 1000 ;
 2657     int patch = 1 ;
 2658 
 2659     if( components == 1 ){
 2660 
 2661         auto a = _convert( s.first() ) ;
 2662 
 2663         if( a ){
 2664 
 2665             return major * a.value() ;
 2666         }
 2667 
 2668     }else if( components == 2 ){
 2669 
 2670         auto a = _convert( s.at( 0 ) ) ;
 2671         auto b = _convert( s.at( 1 ) ) ;
 2672 
 2673         if( a && b ){
 2674 
 2675             return major * a.value() + minor * b.value() ;
 2676         }
 2677 
 2678     }else if( components == 3 ){
 2679 
 2680         auto a = _convert( s.at( 0 ) ) ;
 2681         auto b = _convert( s.at( 1 ) ) ;
 2682         auto c = _convert( s.at( 2 ) ) ;
 2683 
 2684         if( a && b && c ){
 2685 
 2686             return major * a.value() + minor * b.value() + patch * c.value() ;
 2687         }
 2688     }
 2689 
 2690     return {} ;
 2691 }
 2692 
 2693 static utility::result< QString > _installed_version( const QString& backend )
 2694 {
 2695     auto _remove_junk = []( QString e ){
 2696 
 2697         e.replace( "v","" ).replace( ";","" ) ;
 2698 
 2699         QString m ;
 2700 
 2701         for( int s = 0 ; s < e.size() ; s++ ){
 2702 
 2703             auto n = e.at( s ) ;
 2704 
 2705             if( n == '.' || ( n >= '0' && n <= '9' ) ){
 2706 
 2707                 m += n ;
 2708             }else{
 2709                 break ;
 2710             }
 2711         }
 2712 
 2713         return m ;
 2714     } ;
 2715 
 2716     auto exe = utility::executableFullPath( backend ) ;
 2717 
 2718     if( exe.isEmpty() ){
 2719 
 2720         return {} ;
 2721     }
 2722 
 2723     auto cmd = [ & ](){
 2724 
 2725         if( backend == "securefs" ){
 2726 
 2727             return backend + " version" ;
 2728         }else{
 2729             return backend + " --version" ;
 2730         }
 2731     }() ;
 2732 
 2733     auto s = utility::systemEnvironment() ;
 2734 
 2735     auto r = [ & ](){
 2736 
 2737         if( backend == "encfs" ){
 2738 
 2739             return QString( ::Task::process::run( cmd,{},-1,{},s ).get().std_error() ) ;
 2740         }else{
 2741             return QString( ::Task::process::run( cmd,{},-1,{},s ).get().std_out() ) ;
 2742         }
 2743     }() ;
 2744 
 2745     if( r.isEmpty() ){
 2746 
 2747         return {} ;
 2748     }
 2749 
 2750     auto m = utility::split( utility::split( r,'\n' ).first(),' ' ) ;
 2751 
 2752     if( utility::equalsAtleastOne( backend,"cryfs","encfs","sshfs" ) ){
 2753 
 2754         if( m.size() >= 3 ){
 2755 
 2756             return _remove_junk( m.at( 2 ) ) ;
 2757         }
 2758 
 2759     }else if( utility::equalsAtleastOne( backend,"gocryptfs","securefs","ecryptfs-simple" ) ){
 2760 
 2761         if( m.size() >= 2 ){
 2762 
 2763             return _remove_junk( m.at( 1 ) ) ;
 2764         }
 2765     }
 2766 
 2767     return {} ;
 2768 }
 2769 
 2770 ::Task::future< utility::result< QString > >& utility::backEndInstalledVersion( const QString& backend )
 2771 {
 2772     return ::Task::run( _installed_version,backend ) ;
 2773 }
 2774 
 2775 static utility::result< int > _installedVersion( const QString& backend )
 2776 {
 2777     auto s = utility::backEndInstalledVersion( backend ).get() ;
 2778 
 2779     if( s && !s.value().isEmpty() ){
 2780 
 2781         return _convert_string_to_version( s.value() ) ;
 2782     }else{
 2783         return {} ;
 2784     }
 2785 }
 2786 
 2787 template< typename Function >
 2788 ::Task::future< utility::result< bool > >& _compare_versions( const QString& backend,
 2789                                  const QString& version,
 2790                                  Function compare )
 2791 {
 2792     return ::Task::run( [ = ]()->utility::result< bool >{
 2793 
 2794         auto installed = _installedVersion( backend ) ;
 2795         auto guard_version = _convert_string_to_version( version ) ;
 2796 
 2797         if( installed && guard_version ){
 2798 
 2799             return compare( installed.value(),guard_version.value() ) ;
 2800         }else{
 2801             return {} ;
 2802         }
 2803     } ) ;
 2804 }
 2805 
 2806 ::Task::future< utility::result< bool > >& utility::backendIsGreaterOrEqualTo( const QString& backend,
 2807                                            const QString& version )
 2808 {
 2809     return _compare_versions( backend,version,std::greater_equal<int>() ) ;
 2810 }
 2811 
 2812 ::Task::future< utility::result< bool > >& utility::backendIsLessThan( const QString& backend,
 2813                                        const QString& version )
 2814 {
 2815     return _compare_versions( backend,version,std::less<int>() ) ;
 2816 }
 2817 
 2818 utility::UrandomDataSource::UrandomDataSource() :
 2819     m_file( "/dev/urandom" )
 2820 {
 2821 }
 2822 
 2823 bool utility::UrandomDataSource::open()
 2824 {
 2825     m_file.open( QIODevice::ReadOnly ) ;
 2826 
 2827     return m_file.isOpen() ;
 2828 }
 2829 
 2830 qint64 utility::UrandomDataSource::getData( char * data,qint64 size )
 2831 {
 2832     return m_file.read( data,size ) ;
 2833 }
 2834 
 2835 QByteArray utility::UrandomDataSource::getData( qint64 size )
 2836 {
 2837     return m_file.read( size ) ;
 2838 }
 2839 
 2840 utility::CRandDataSource::CRandDataSource()
 2841 {
 2842 }
 2843 
 2844 bool utility::CRandDataSource::open()
 2845 {
 2846     return true ;
 2847 }
 2848 
 2849 qint64 utility::CRandDataSource::getData( char * data,qint64 size )
 2850 {
 2851     time_t t ;
 2852 
 2853     srand( static_cast< unsigned int >( time( &t ) ) ) ;
 2854 
 2855     for( int i = 0 ; i < size ; i++ ){
 2856 
 2857        *( data + i ) = static_cast< char >( rand() ) ;
 2858     }
 2859 
 2860     return size ;
 2861 }
 2862 
 2863 QByteArray utility::CRandDataSource::getData( qint64 size )
 2864 {
 2865     QByteArray data ;
 2866 
 2867     data.resize( static_cast< int >( size ) ) ;
 2868 
 2869     utility::CRandDataSource().getData( data.data(),size ) ;
 2870 
 2871     return data ;
 2872 }
 2873 
 2874 QString utility::loopDevicePath( const QString& e )
 2875 {
 2876     const auto s = QDir( "/sys/block" ).entryList() ;
 2877 
 2878     QFile file ;
 2879 
 2880     for( const auto& it : s ){
 2881 
 2882         if( it.startsWith( "loop" ) ){
 2883 
 2884             QString m = "/sys/block/" + it + "/loop/backing_file" ;
 2885 
 2886             if( utility::pathExists( m ) ){
 2887 
 2888                 file.setFileName( m ) ;
 2889 
 2890                 file.open( QIODevice::ReadOnly ) ;
 2891 
 2892                 QString s = file.readAll() ;
 2893 
 2894                 file.close() ;
 2895 
 2896                 if( s.startsWith( e ) ){
 2897 
 2898                     return "/dev/" + it ;
 2899                 }
 2900             }
 2901         }
 2902     }
 2903 
 2904     return QString() ;
 2905 }
 2906 
 2907 static bool _removeYkchalrespNewLineCharacter()
 2908 {
 2909     if( !_settings->contains( "RemoveYkchalrespNewLineCharacter" ) ){
 2910 
 2911         _settings->setValue( "RemoveYkchalrespNewLineCharacter",true ) ;
 2912     }
 2913 
 2914     return _settings->value( "RemoveYkchalrespNewLineCharacter" ).toBool() ;
 2915 }
 2916 
 2917 static QString _ykchalrespArguments()
 2918 {
 2919     if( !_settings->contains( "YkchalrespArguments" ) ){
 2920 
 2921         _settings->setValue( "YkchalrespArguments","-2 -i -" ) ;
 2922     }
 2923 
 2924     return _settings->value( "YkchalrespArguments" ).toString() ;
 2925 }
 2926 
 2927 static QString _ykchalresp_path()
 2928 {
 2929     static QString m = utility::executableFullPath( "ykchalresp" ) ;
 2930     return m ;
 2931 }
 2932 
 2933 
 2934 utility::result<QByteArray> utility::yubiKey( const QString& challenge )
 2935 {
 2936     QString exe = _ykchalresp_path() ;
 2937 
 2938     if( !exe.isEmpty() ){
 2939 
 2940         exe = exe + " " + _ykchalrespArguments() ;
 2941 
 2942         //_post_backend_cmd( exe ) ;
 2943 
 2944         auto s = ::Task::process::run( exe,challenge.toLatin1() ).await() ;
 2945 
 2946         if( s.success() ){
 2947 
 2948             auto m = s.std_out() ;
 2949 
 2950             if( _removeYkchalrespNewLineCharacter() ){
 2951 
 2952                 m.replace( "\n","" ) ;
 2953             }
 2954 
 2955             return m ;
 2956         }else{
 2957             std::cout << "Failed to get a responce from ykchalresp" << std::endl ;
 2958             std::cout << "StdOUt:" << s.std_out().constData() << std::endl ;
 2959             std::cout << "StdError:" << s.std_error().constData() << std::endl ;
 2960         }
 2961     }
 2962 
 2963     return {} ;
 2964 }
 2965 
 2966 utility::progress::progress( int s,std::function< void( const utility::progress::result& )> function ) :
 2967     m_offset_last( 0 ),
 2968     m_total_time( 0 ),
 2969     m_function( std::move( function ) ),
 2970     m_duration( s ),
 2971     m_time( m_duration.timer() ),
 2972     m_previousTime( m_time.currentMSecsSinceEpoch() )
 2973 {
 2974 }
 2975 
 2976 void utility::progress::update_progress( quint64 size,quint64 offset )
 2977 {
 2978     int i = int( ( offset * 100 / size ) ) ;
 2979 
 2980     auto time_expired = m_duration.passed() ;
 2981 
 2982     if( !time_expired ){
 2983 
 2984         m_duration.reset() ;
 2985     }
 2986 
 2987     if( i > m_progress || time_expired ){
 2988 
 2989         m_progress = i ;
 2990 
 2991         double currentTime = m_time.currentMSecsSinceEpoch() ;
 2992 
 2993         double time_diff = ( currentTime - m_previousTime ) / 1000 ;
 2994         double offset_diff = offset - m_offset_last ;
 2995 
 2996         m_total_time = m_total_time + time_diff ;
 2997 
 2998         QString current_speed = this->speed( offset_diff,time_diff ) ;
 2999 
 3000         QString average_speed = this->speed( offset,m_total_time ) ;
 3001 
 3002         double avg_speed = offset / m_total_time ;
 3003 
 3004         double remaining_data = size - offset ;
 3005 
 3006         QString eta = this->time( remaining_data / avg_speed ) ;
 3007 
 3008         m_function( { current_speed,
 3009                   average_speed,
 3010                   eta,
 3011                   this->time( m_total_time ),
 3012                   i } ) ;
 3013 
 3014         m_offset_last = offset ;
 3015         m_previousTime = currentTime ;
 3016     }
 3017 }
 3018 
 3019 std::function< void( quint64 size,quint64 offset ) > utility::progress::updater_quint()
 3020 {
 3021     return [ this ]( quint64 size,quint64 offset ){
 3022 
 3023         this->update_progress( size,offset ) ;
 3024     } ;
 3025 }
 3026 
 3027 std::function< void( qint64 size,qint64 offset ) > utility::progress::updater_qint()
 3028 {
 3029     return [ this ]( qint64 size,qint64 offset ){
 3030 
 3031         this->update_progress( quint64( size ),quint64( offset ) ) ;
 3032     } ;
 3033 }
 3034 
 3035 QString utility::progress::time( double s )
 3036 {
 3037     int milliseconds = int( s ) * 1000 ;
 3038     int seconds      = milliseconds / 1000;
 3039     milliseconds     = milliseconds % 1000;
 3040     int minutes      = seconds / 60 ;
 3041     seconds          = seconds % 60 ;
 3042     int hours        = minutes / 60 ;
 3043     minutes          = minutes % 60 ;
 3044 
 3045     QTime time ;
 3046     time.setHMS( hours,minutes,seconds,milliseconds ) ;
 3047     return time.toString( "hh:mm:ss" ) ;
 3048 }
 3049 
 3050 QString utility::progress::speed( double size,double time )
 3051 {
 3052     QString s ;
 3053 
 3054     if( size < 1024 ){
 3055 
 3056         s = "B" ;
 3057 
 3058     }else if( size <= 1024 * 1024 ){
 3059 
 3060         s = "KB" ;
 3061         size = size / 1024 ;
 3062 
 3063     }else if( size <= 1024 * 1024 * 1024 ){
 3064 
 3065         s = "MB" ;
 3066         size = size / ( 1024 * 1024 ) ;
 3067 
 3068     }else if( size <= 1024 * 1024 * 1024 * 1024ll ){
 3069 
 3070         s = "GB" ;
 3071         size = size / ( 1024 * 1024 * 1024 ) ;
 3072     }else{
 3073         s = "B" ;
 3074     }
 3075 
 3076     size = size / time ;
 3077 
 3078     return QString::number( size,'f',2 ) + " " + s + "/s" ;
 3079 }
 3080 
 3081 utility::duration::duration( long miliseconds ) : m_milliseconds( miliseconds )
 3082 {
 3083     this->reset() ;
 3084 }
 3085 
 3086 bool utility::duration::passed()
 3087 {
 3088     auto now = m_time.currentMSecsSinceEpoch() ;
 3089 
 3090     if( now - m_start_time >= m_milliseconds ){
 3091 
 3092         this->reset() ;
 3093 
 3094         return true ;
 3095     }else{
 3096         return false ;
 3097     }
 3098 }
 3099 
 3100 void utility::duration::reset()
 3101 {
 3102     m_start_time = m_time.currentMSecsSinceEpoch() ;
 3103 }
 3104 
 3105 QDateTime& utility::duration::timer()
 3106 {
 3107     return m_time ;
 3108 }