2010-03-20 22:09:27 +03:00
/*
2015-04-19 18:17:47 +03:00
* Bittorrent Client using Qt and libtorrent .
2018-04-14 22:53:45 +03:00
* Copyright ( C ) 2006 Christophe Dumez < chris @ qbittorrent . org >
2010-03-20 22:09:27 +03:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*
* In addition , as a special exception , the copyright holders give permission to
* link this program with the OpenSSL project ' s " OpenSSL " library ( or with
* modified versions of it that use the same license as the " OpenSSL " library ) ,
* and distribute the linked executables . You must obey the GNU General Public
* License in all respects for all of the code used other than " OpenSSL " . If you
* modify file ( s ) , you may extend this exception to your version of the file ( s ) ,
* but you are not obligated to do so . If you do not wish to do so , delete this
* exception statement from your version .
*/
2018-04-07 09:35:00 +03:00
# include "misc.h"
2016-02-27 03:27:56 +03:00
# include <boost/version.hpp>
2016-02-27 03:38:52 +03:00
# include <libtorrent/version.hpp>
2010-03-20 22:09:27 +03:00
2013-09-21 11:59:58 +04:00
# ifdef Q_OS_WIN
2010-06-09 13:48:14 +04:00
# include <windows.h>
2016-07-23 06:54:07 +03:00
# include <Shlobj.h>
2010-06-09 13:48:14 +04:00
# else
# include <sys/types.h>
2018-04-07 09:35:00 +03:00
# include <unistd.h>
2010-03-20 22:09:27 +03:00
# endif
2013-09-21 11:59:58 +04:00
# ifdef Q_OS_MAC
2010-03-20 22:09:27 +03:00
# include <CoreServices/CoreServices.h>
2010-08-17 14:50:14 +04:00
# include <Carbon/Carbon.h>
2010-03-20 22:09:27 +03:00
# endif
2018-04-07 09:35:00 +03:00
# include <QByteArray>
# include <QDebug>
# include <QFileInfo>
# include <QProcess>
# include <QRegularExpression>
# include <QSysInfo>
# include <QUrl>
# ifdef DISABLE_GUI
# include <QCoreApplication>
# else
# include <QApplication>
# include <QDesktopServices>
# include <QDesktopWidget>
# include <QStyle>
2013-09-21 11:59:58 +04:00
# if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) && defined(QT_DBUS_LIB)
2010-08-16 21:35:32 +04:00
# include <QDBusInterface>
# include <QDBusMessage>
2018-05-24 16:39:28 +03:00
# endif
# if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
2018-05-15 22:03:12 +03:00
# include "base/utils/version.h"
2010-08-16 21:35:32 +04:00
# endif
2015-06-28 21:58:39 +03:00
# endif
2015-09-25 11:10:05 +03:00
# include "base/logger.h"
2018-04-14 22:53:45 +03:00
# include "base/unicodestrings.h"
# include "base/utils/string.h"
2015-06-28 21:58:39 +03:00
# include "fs.h"
2010-11-23 00:55:32 +03:00
2018-04-07 09:35:00 +03:00
namespace
{
const struct { const char * source ; const char * comment ; } units [ ] = {
QT_TRANSLATE_NOOP3 ( " misc " , " B " , " bytes " ) ,
QT_TRANSLATE_NOOP3 ( " misc " , " KiB " , " kibibytes (1024 bytes) " ) ,
QT_TRANSLATE_NOOP3 ( " misc " , " MiB " , " mebibytes (1024 kibibytes) " ) ,
QT_TRANSLATE_NOOP3 ( " misc " , " GiB " , " gibibytes (1024 mibibytes) " ) ,
QT_TRANSLATE_NOOP3 ( " misc " , " TiB " , " tebibytes (1024 gibibytes) " ) ,
QT_TRANSLATE_NOOP3 ( " misc " , " PiB " , " pebibytes (1024 tebibytes) " ) ,
QT_TRANSLATE_NOOP3 ( " misc " , " EiB " , " exbibytes (1024 pebibytes) " )
} ;
}
2010-12-02 21:21:45 +03:00
2016-04-12 21:33:17 +03:00
void Utils : : Misc : : shutdownComputer ( const ShutdownDialogAction & action )
2014-11-26 00:10:32 +03:00
{
2016-12-27 15:19:20 +03:00
# if defined(Q_OS_WIN)
HANDLE hToken ; // handle to process token
TOKEN_PRIVILEGES tkp ; // pointer to token structure
if ( ! OpenProcessToken ( GetCurrentProcess ( ) , TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY , & hToken ) )
return ;
// Get the LUID for shutdown privilege.
LookupPrivilegeValue ( NULL , SE_SHUTDOWN_NAME ,
& tkp . Privileges [ 0 ] . Luid ) ;
tkp . PrivilegeCount = 1 ; // one privilege to set
tkp . Privileges [ 0 ] . Attributes = SE_PRIVILEGE_ENABLED ;
// Get shutdown privilege for this process.
AdjustTokenPrivileges ( hToken , FALSE , & tkp , 0 ,
( PTOKEN_PRIVILEGES ) NULL , 0 ) ;
// Cannot test the return value of AdjustTokenPrivileges.
if ( GetLastError ( ) ! = ERROR_SUCCESS )
return ;
2018-04-07 10:56:09 +03:00
using PSETSUSPENDSTATE = BOOLEAN ( WINAPI * ) ( BOOLEAN , BOOLEAN , BOOLEAN ) ;
const auto setSuspendState = Utils : : Misc : : loadWinAPI < PSETSUSPENDSTATE > ( " PowrProf.dll " , " SetSuspendState " ) ;
if ( action = = ShutdownDialogAction : : Suspend ) {
if ( setSuspendState )
setSuspendState ( false , false , false ) ;
}
else if ( action = = ShutdownDialogAction : : Hibernate ) {
if ( setSuspendState )
setSuspendState ( true , false , false ) ;
}
else {
2018-04-08 11:13:28 +03:00
const QString msg = QCoreApplication : : translate ( " misc " , " qBittorrent will shutdown the computer now because all downloads are complete. " ) ;
std : : unique_ptr < wchar_t [ ] > msgWchar ( new wchar_t [ msg . length ( ) + 1 ] { } ) ;
msg . toWCharArray ( msgWchar . get ( ) ) ;
: : InitiateSystemShutdownW ( nullptr , msgWchar . get ( ) , 10 , true , false ) ;
2018-04-07 10:56:09 +03:00
}
2016-12-27 15:19:20 +03:00
// Disable shutdown privilege.
tkp . Privileges [ 0 ] . Attributes = 0 ;
AdjustTokenPrivileges ( hToken , FALSE , & tkp , 0 , ( PTOKEN_PRIVILEGES ) NULL , 0 ) ;
# elif defined(Q_OS_MAC)
AEEventID EventToSend ;
if ( action ! = ShutdownDialogAction : : Shutdown )
EventToSend = kAESleep ;
else
EventToSend = kAEShutDown ;
AEAddressDesc targetDesc ;
2018-07-23 07:49:32 +03:00
const ProcessSerialNumber kPSNOfSystemProcess = { 0 , kSystemProcess } ;
2016-12-27 15:19:20 +03:00
AppleEvent eventReply = { typeNull , NULL } ;
AppleEvent appleEventToSend = { typeNull , NULL } ;
OSStatus error = AECreateDesc ( typeProcessSerialNumber , & kPSNOfSystemProcess ,
sizeof ( kPSNOfSystemProcess ) , & targetDesc ) ;
if ( error ! = noErr )
return ;
error = AECreateAppleEvent ( kCoreEventClass , EventToSend , & targetDesc ,
kAutoGenerateReturnID , kAnyTransactionID , & appleEventToSend ) ;
AEDisposeDesc ( & targetDesc ) ;
if ( error ! = noErr )
return ;
error = AESend ( & appleEventToSend , & eventReply , kAENoReply ,
kAENormalPriority , kAEDefaultTimeout , NULL , NULL ) ;
AEDisposeDesc ( & appleEventToSend ) ;
if ( error ! = noErr )
return ;
AEDisposeDesc ( & eventReply ) ;
# elif (defined(Q_OS_UNIX) && defined(QT_DBUS_LIB))
2014-11-26 00:10:32 +03:00
// Use dbus to power off / suspend the system
2016-04-12 21:33:17 +03:00
if ( action ! = ShutdownDialogAction : : Shutdown ) {
2014-11-26 00:10:32 +03:00
// Some recent systems use systemd's logind
QDBusInterface login1Iface ( " org.freedesktop.login1 " , " /org/freedesktop/login1 " ,
" org.freedesktop.login1.Manager " , QDBusConnection : : systemBus ( ) ) ;
if ( login1Iface . isValid ( ) ) {
2016-04-12 21:33:17 +03:00
if ( action = = ShutdownDialogAction : : Suspend )
2014-11-26 00:10:32 +03:00
login1Iface . call ( " Suspend " , false ) ;
else
login1Iface . call ( " Hibernate " , false ) ;
return ;
}
// Else, other recent systems use UPower
QDBusInterface upowerIface ( " org.freedesktop.UPower " , " /org/freedesktop/UPower " ,
" org.freedesktop.UPower " , QDBusConnection : : systemBus ( ) ) ;
if ( upowerIface . isValid ( ) ) {
2016-04-12 21:33:17 +03:00
if ( action = = ShutdownDialogAction : : Suspend )
2014-11-26 00:10:32 +03:00
upowerIface . call ( " Suspend " ) ;
else
upowerIface . call ( " Hibernate " ) ;
return ;
}
// HAL (older systems)
QDBusInterface halIface ( " org.freedesktop.Hal " , " /org/freedesktop/Hal/devices/computer " ,
" org.freedesktop.Hal.Device.SystemPowerManagement " ,
QDBusConnection : : systemBus ( ) ) ;
2016-04-12 21:33:17 +03:00
if ( action = = ShutdownDialogAction : : Suspend )
2014-11-26 00:10:32 +03:00
halIface . call ( " Suspend " , 5 ) ;
else
halIface . call ( " Hibernate " ) ;
2013-12-23 15:41:07 +04:00
}
2014-11-26 00:10:32 +03:00
else {
// Some recent systems use systemd's logind
QDBusInterface login1Iface ( " org.freedesktop.login1 " , " /org/freedesktop/login1 " ,
" org.freedesktop.login1.Manager " , QDBusConnection : : systemBus ( ) ) ;
if ( login1Iface . isValid ( ) ) {
login1Iface . call ( " PowerOff " , false ) ;
return ;
}
// Else, other recent systems use ConsoleKit
QDBusInterface consolekitIface ( " org.freedesktop.ConsoleKit " , " /org/freedesktop/ConsoleKit/Manager " ,
" org.freedesktop.ConsoleKit.Manager " , QDBusConnection : : systemBus ( ) ) ;
if ( consolekitIface . isValid ( ) ) {
consolekitIface . call ( " Stop " ) ;
return ;
}
// HAL (older systems)
QDBusInterface halIface ( " org.freedesktop.Hal " , " /org/freedesktop/Hal/devices/computer " ,
" org.freedesktop.Hal.Device.SystemPowerManagement " ,
QDBusConnection : : systemBus ( ) ) ;
halIface . call ( " Shutdown " ) ;
2011-04-05 20:41:54 +04:00
}
2014-11-26 00:10:32 +03:00
2016-12-27 15:19:20 +03:00
# else
Q_UNUSED ( action ) ;
2010-08-16 21:57:15 +04:00
# endif
2010-08-16 21:35:32 +04:00
}
2010-03-20 22:09:27 +03:00
# ifndef DISABLE_GUI
2015-09-25 07:52:39 +03:00
QPoint Utils : : Misc : : screenCenter ( const QWidget * w )
2014-11-26 00:10:32 +03:00
{
2015-09-25 07:52:39 +03:00
// Returns the QPoint which the widget will be placed center on screen (where parent resides)
2014-11-26 00:10:32 +03:00
2015-09-25 07:52:39 +03:00
QWidget * parent = w - > parentWidget ( ) ;
QDesktopWidget * desktop = QApplication : : desktop ( ) ;
int scrn = desktop - > screenNumber ( parent ) ; // fallback to `primaryScreen` when parent is invalid
QRect r = desktop - > availableGeometry ( scrn ) ;
return QPoint ( r . x ( ) + ( r . width ( ) - w - > frameSize ( ) . width ( ) ) / 2 , r . y ( ) + ( r . height ( ) - w - > frameSize ( ) . height ( ) ) / 2 ) ;
2010-03-20 22:09:27 +03:00
}
2015-02-27 16:00:00 +03:00
# endif
2015-07-21 01:11:05 +03:00
2015-09-23 23:20:22 +03:00
QString Utils : : Misc : : unitString ( Utils : : Misc : : SizeUnit unit )
{
return QCoreApplication : : translate ( " misc " ,
2016-07-23 06:23:16 +03:00
units [ static_cast < int > ( unit ) ] . source , units [ static_cast < int > ( unit ) ] . comment ) ;
2015-09-23 23:20:22 +03:00
}
// return best userfriendly storage unit (B, KiB, MiB, GiB, TiB, ...)
2010-03-20 22:09:27 +03:00
// use Binary prefix standards from IEC 60027-2
// see http://en.wikipedia.org/wiki/Kilobyte
// value must be given in bytes
2014-08-08 03:46:54 +04:00
// to send numbers instead of strings with suffixes
2015-09-23 23:20:22 +03:00
bool Utils : : Misc : : friendlyUnit ( qint64 sizeInBytes , qreal & val , Utils : : Misc : : SizeUnit & unit )
2014-11-26 00:10:32 +03:00
{
2015-09-23 23:20:22 +03:00
if ( sizeInBytes < 0 ) return false ;
2014-11-26 00:10:32 +03:00
int i = 0 ;
2015-09-23 23:20:22 +03:00
qreal rawVal = static_cast < qreal > ( sizeInBytes ) ;
while ( ( rawVal > = 1024. ) & & ( i < = static_cast < int > ( SizeUnit : : ExbiByte ) ) ) {
rawVal / = 1024. ;
2015-06-17 03:03:51 +03:00
+ + i ;
}
2015-09-23 23:20:22 +03:00
val = rawVal ;
unit = static_cast < SizeUnit > ( i ) ;
return true ;
}
QString Utils : : Misc : : friendlyUnit ( qint64 bytesValue , bool isSpeed )
{
SizeUnit unit ;
qreal friendlyVal ;
2016-07-23 06:23:16 +03:00
if ( ! friendlyUnit ( bytesValue , friendlyVal , unit ) )
2015-09-23 23:20:22 +03:00
return QCoreApplication : : translate ( " misc " , " Unknown " , " Unknown (size) " ) ;
2014-11-26 00:10:32 +03:00
QString ret ;
2015-09-23 23:20:22 +03:00
if ( unit = = SizeUnit : : Byte )
2016-10-19 16:29:09 +03:00
ret = QString : : number ( bytesValue ) + QString : : fromUtf8 ( C_NON_BREAKING_SPACE ) + unitString ( unit ) ;
2014-11-26 00:10:32 +03:00
else
2016-10-19 16:29:09 +03:00
ret = Utils : : String : : fromDouble ( friendlyVal , friendlyUnitPrecision ( unit ) ) + QString : : fromUtf8 ( C_NON_BREAKING_SPACE ) + unitString ( unit ) ;
2015-09-23 23:20:22 +03:00
if ( isSpeed )
2014-11-26 00:10:32 +03:00
ret + = QCoreApplication : : translate ( " misc " , " /s " , " per second " ) ;
return ret ;
2010-03-20 22:09:27 +03:00
}
2016-09-26 13:26:25 +03:00
int Utils : : Misc : : friendlyUnitPrecision ( SizeUnit unit )
{
// friendlyUnit's number of digits after the decimal point
if ( unit < = SizeUnit : : MebiByte ) return 1 ;
else if ( unit = = SizeUnit : : GibiByte ) return 2 ;
else return 3 ;
}
2015-09-23 23:20:22 +03:00
qlonglong Utils : : Misc : : sizeInBytes ( qreal size , Utils : : Misc : : SizeUnit unit )
{
2016-07-23 06:23:16 +03:00
for ( int i = 0 ; i < static_cast < int > ( unit ) ; + + i )
2015-09-23 23:20:22 +03:00
size * = 1024 ;
return size ;
}
2016-07-23 06:23:16 +03:00
bool Utils : : Misc : : isPreviewable ( const QString & extension )
2014-11-26 00:10:32 +03:00
{
2018-06-14 14:46:50 +03:00
static const QSet < QString > multimediaExtensions = {
" 3GP " ,
" AAC " ,
" AC3 " ,
" AIF " ,
" AIFC " ,
" AIFF " ,
" ASF " ,
" AU " ,
" AVI " ,
" FLAC " ,
" FLV " ,
" M3U " ,
" M4A " ,
" M4P " ,
" M4V " ,
" MID " ,
" MKV " ,
" MOV " ,
" MP2 " ,
" MP3 " ,
" MP4 " ,
" MPC " ,
" MPE " ,
" MPEG " ,
" MPG " ,
" MPP " ,
" OGG " ,
" OGM " ,
" OGV " ,
" QT " ,
" RA " ,
" RAM " ,
" RM " ,
" RMV " ,
" RMVB " ,
" SWA " ,
" SWF " ,
" VOB " ,
" WAV " ,
" WMA " ,
" WMV "
} ;
return multimediaExtensions . contains ( extension . toUpper ( ) ) ;
2010-03-20 22:09:27 +03:00
}
// Take a number of seconds and return an user-friendly
// time duration like "1d 2h 10m".
2015-05-06 14:53:27 +03:00
QString Utils : : Misc : : userFriendlyDuration ( qlonglong seconds )
2014-11-26 00:10:32 +03:00
{
2016-07-23 06:23:16 +03:00
if ( ( seconds < 0 ) | | ( seconds > = MAX_ETA ) )
2015-06-15 12:36:14 +03:00
return QString : : fromUtf8 ( C_INFINITY ) ;
2017-02-08 08:11:36 +03:00
2014-11-26 00:10:32 +03:00
if ( seconds = = 0 )
return " 0 " ;
2017-02-08 08:11:36 +03:00
2014-11-26 00:10:32 +03:00
if ( seconds < 60 )
return QCoreApplication : : translate ( " misc " , " < 1m " , " < 1 minute " ) ;
2017-02-08 08:11:36 +03:00
qlonglong minutes = seconds / 60 ;
2014-11-26 00:10:32 +03:00
if ( minutes < 60 )
2016-07-23 06:23:16 +03:00
return QCoreApplication : : translate ( " misc " , " %1m " , " e.g: 10minutes " ) . arg ( QString : : number ( minutes ) ) ;
2017-02-08 08:11:36 +03:00
qlonglong hours = minutes / 60 ;
minutes - = hours * 60 ;
2014-11-26 00:10:32 +03:00
if ( hours < 24 )
2018-03-06 18:49:12 +03:00
return QCoreApplication : : translate ( " misc " , " %1h %2m " , " e.g: 3hours 5minutes " ) . arg ( QString : : number ( hours ) , QString : : number ( minutes ) ) ;
2017-02-08 08:11:36 +03:00
qlonglong days = hours / 24 ;
hours - = days * 24 ;
2014-11-26 00:10:32 +03:00
if ( days < 100 )
2018-03-06 18:49:12 +03:00
return QCoreApplication : : translate ( " misc " , " %1d %2h " , " e.g: 2days 10hours " ) . arg ( QString : : number ( days ) , QString : : number ( hours ) ) ;
2017-02-08 08:11:36 +03:00
2015-06-15 12:36:14 +03:00
return QString : : fromUtf8 ( C_INFINITY ) ;
2010-03-20 22:09:27 +03:00
}
2010-06-05 22:59:05 +04:00
2015-05-06 14:53:27 +03:00
QString Utils : : Misc : : getUserIDString ( )
2014-11-26 00:10:32 +03:00
{
QString uid = " 0 " ;
2013-09-21 11:59:58 +04:00
# ifdef Q_OS_WIN
2018-04-07 09:35:00 +03:00
const int UNLEN = 256 ;
2015-01-20 17:54:41 +03:00
WCHAR buffer [ UNLEN + 1 ] = { 0 } ;
2016-07-23 06:23:16 +03:00
DWORD buffer_len = sizeof ( buffer ) / sizeof ( * buffer ) ;
2015-01-20 17:54:41 +03:00
if ( GetUserNameW ( buffer , & buffer_len ) )
uid = QString : : fromWCharArray ( buffer ) ;
2010-06-09 13:48:14 +04:00
# else
2014-11-26 00:10:32 +03:00
uid = QString : : number ( getuid ( ) ) ;
2010-06-09 13:48:14 +04:00
# endif
2014-11-26 00:10:32 +03:00
return uid ;
2010-06-09 13:48:14 +04:00
}
2015-05-06 14:53:27 +03:00
QStringList Utils : : Misc : : toStringList ( const QList < bool > & l )
2014-11-26 00:10:32 +03:00
{
QStringList ret ;
foreach ( const bool & b , l )
ret < < ( b ? " 1 " : " 0 " ) ;
return ret ;
2010-06-05 22:59:05 +04:00
}
2015-05-06 14:53:27 +03:00
QList < int > Utils : : Misc : : intListfromStringList ( const QStringList & l )
2014-11-26 00:10:32 +03:00
{
QList < int > ret ;
foreach ( const QString & s , l )
ret < < s . toInt ( ) ;
return ret ;
2010-06-05 22:59:05 +04:00
}
2015-05-06 14:53:27 +03:00
QList < bool > Utils : : Misc : : boolListfromStringList ( const QStringList & l )
2014-11-26 00:10:32 +03:00
{
QList < bool > ret ;
foreach ( const QString & s , l )
2015-12-05 17:48:57 +03:00
ret < < ( s = = " 1 " ) ;
2014-11-26 00:10:32 +03:00
return ret ;
2010-06-05 22:59:05 +04:00
}
2010-10-25 23:34:42 +04:00
2015-05-06 14:53:27 +03:00
bool Utils : : Misc : : isUrl ( const QString & s )
2010-12-30 22:12:03 +03:00
{
2017-03-07 16:10:42 +03:00
static const QRegularExpression reURLScheme (
" http[s]?|ftp " , QRegularExpression : : CaseInsensitiveOption ) ;
return reURLScheme . match ( QUrl ( s ) . scheme ( ) ) . hasMatch ( ) ;
2010-12-30 22:12:03 +03:00
}
2018-04-14 22:53:45 +03:00
QString Utils : : Misc : : parseHtmlLinks ( const QString & rawText )
2011-04-04 21:16:34 +04:00
{
2018-04-14 22:53:45 +03:00
QString result = rawText ;
2018-05-24 18:41:03 +03:00
static const QRegularExpression reURL (
2016-07-23 06:23:16 +03:00
" ( \\ s|^) " // start with whitespace or beginning of line
2014-11-26 00:10:32 +03:00
" ( "
2016-07-23 06:23:16 +03:00
" ( " // case 1 -- URL with scheme
" (http(s?)) \\ :// " // start with scheme
2014-11-26 00:10:32 +03:00
" ([a-zA-Z0-9_-]+ \\ .)+ " // domainpart. at least one of these must exist
" ([a-zA-Z0-9 \\ ?%=&/_ \\ .:#;-]+) " // everything to 1st non-URI char, must be at least one char after the previous dot (cannot use ".*" because it can be too greedy)
" ) "
" | "
2016-07-23 06:23:16 +03:00
" ( " // case 2a -- no scheme, contains common TLD example.com
2014-11-26 00:10:32 +03:00
" ([a-zA-Z0-9_-]+ \\ .)+ " // domainpart. at least one of these must exist
" (?= " // must be followed by TLD
2016-07-23 06:23:16 +03:00
" AERO|aero| " // N.B. assertions are non-capturing
2014-11-26 00:10:32 +03:00
" ARPA|arpa| "
" ASIA|asia| "
" BIZ|biz| "
" CAT|cat| "
" COM|com| "
" COOP|coop| "
" EDU|edu| "
" GOV|gov| "
" INFO|info| "
" INT|int| "
" JOBS|jobs| "
" MIL|mil| "
" MOBI|mobi| "
" MUSEUM|museum| "
" NAME|name| "
" NET|net| "
" ORG|org| "
" PRO|pro| "
" RO|ro| "
" RU|ru| "
" TEL|tel| "
" TRAVEL|travel "
" ) "
" ([a-zA-Z0-9 \\ ?%=&/_ \\ .:#;-]+) " // everything to 1st non-URI char, must be at least one char after the previous dot (cannot use ".*" because it can be too greedy)
" ) "
" | "
2015-05-04 02:09:30 +03:00
" ( " // case 2b no scheme, no TLD, must have at least 2 alphanum strings plus uncommon TLD string --> del.icio.us
2016-07-23 06:23:16 +03:00
" ([a-zA-Z0-9_-]+ \\ .) {2,} " // 2 or more domainpart. --> del.icio.
" [a-zA-Z]{2,} " // one ab (2 char or longer) --> us
2014-11-26 00:10:32 +03:00
" ([a-zA-Z0-9 \\ ?%=&/_ \\ .:#;-]*) " // everything to 1st non-URI char, maybe nothing in case of del.icio.us/path
" ) "
" ) "
) ;
// Capture links
result . replace ( reURL , " \\ 1<a href= \" \\ 2 \" > \\ 2</a> " ) ;
// Capture links without scheme
2018-05-24 18:41:03 +03:00
static const QRegularExpression reNoScheme ( " <a \\ s+href= \" (?!https?) ( [ a - zA - Z0 - 9 \ \ ? % = & / _ \ \ . - : # ] + ) \ \ s * \ " > " ) ;
2014-11-26 00:10:32 +03:00
result . replace ( reNoScheme , " <a href= \" http:// \\ 1 \" > " ) ;
2015-06-24 13:49:31 +03:00
// to preserve plain text formatting
result = " <p style= \" white-space: pre-wrap; \" > " + result + " </p> " ;
2014-11-26 00:10:32 +03:00
return result ;
2011-04-04 21:16:34 +04:00
}
2012-05-15 20:57:31 +04:00
2015-06-28 21:58:39 +03:00
# ifndef DISABLE_GUI
// Open the given path with an appropriate application
2016-07-23 06:23:16 +03:00
void Utils : : Misc : : openPath ( const QString & absolutePath )
2015-06-28 21:58:39 +03:00
{
const QString path = Utils : : Fs : : fromNativePath ( absolutePath ) ;
// Hack to access samba shares with QDesktopServices::openUrl
if ( path . startsWith ( " // " ) )
QDesktopServices : : openUrl ( Utils : : Fs : : toNativePath ( " file: " + path ) ) ;
else
QDesktopServices : : openUrl ( QUrl : : fromLocalFile ( path ) ) ;
}
// Open the parent directory of the given path with a file manager and select
// (if possible) the item at the given path
2016-07-23 06:23:16 +03:00
void Utils : : Misc : : openFolderSelect ( const QString & absolutePath )
2015-06-28 21:58:39 +03:00
{
const QString path = Utils : : Fs : : fromNativePath ( absolutePath ) ;
2016-07-23 06:24:58 +03:00
// If the item to select doesn't exist, try to open its parent
2018-03-08 20:04:57 +03:00
if ( ! QFileInfo : : exists ( path ) ) {
2018-07-21 08:28:13 +03:00
openPath ( path . left ( path . lastIndexOf ( ' / ' ) ) ) ;
2016-07-23 06:24:58 +03:00
return ;
2015-06-28 21:58:39 +03:00
}
2016-07-23 06:24:58 +03:00
# ifdef Q_OS_WIN
2016-07-23 06:54:07 +03:00
HRESULT hresult = : : CoInitializeEx ( nullptr , COINIT_MULTITHREADED ) ;
2016-12-01 10:52:49 +03:00
PIDLIST_ABSOLUTE pidl = : : ILCreateFromPathW ( reinterpret_cast < PCTSTR > ( Utils : : Fs : : toNativePath ( path ) . utf16 ( ) ) ) ;
2016-07-23 06:54:07 +03:00
if ( pidl ) {
: : SHOpenFolderAndSelectItems ( pidl , 0 , nullptr , 0 ) ;
: : ILFree ( pidl ) ;
2015-06-28 21:58:39 +03:00
}
2016-07-23 06:54:07 +03:00
if ( ( hresult = = S_OK ) | | ( hresult = = S_FALSE ) )
: : CoUninitialize ( ) ;
2016-07-23 06:24:58 +03:00
# elif defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
QProcess proc ;
2018-05-15 22:03:12 +03:00
proc . start ( " xdg-mime " , { " query " , " default " , " inode/directory " } ) ;
2016-07-23 06:24:58 +03:00
proc . waitForFinished ( ) ;
QString output = proc . readLine ( ) . simplified ( ) ;
2018-05-15 22:03:12 +03:00
if ( ( output = = " dolphin.desktop " ) | | ( output = = " org.kde.dolphin.desktop " ) ) {
proc . startDetached ( " dolphin " , { " --select " , Utils : : Fs : : toNativePath ( path ) } ) ;
}
2016-07-23 06:24:58 +03:00
else if ( ( output = = " nautilus.desktop " ) | | ( output = = " org.gnome.Nautilus.desktop " )
2018-05-15 22:03:12 +03:00
| | ( output = = " nautilus-folder-handler.desktop " ) ) {
proc . start ( " nautilus " , { " --version " } ) ;
proc . waitForFinished ( ) ;
2018-05-24 18:41:03 +03:00
const QString nautilusVerStr = QString ( proc . readLine ( ) ) . remove ( QRegularExpression ( " [^0-9.] " ) ) ;
2018-05-15 22:03:12 +03:00
using NautilusVersion = Utils : : Version < int , 3 > ;
if ( NautilusVersion : : tryParse ( nautilusVerStr , { 1 , 0 , 0 } ) > NautilusVersion { 3 , 28 } )
proc . startDetached ( " nautilus " , { Utils : : Fs : : toNativePath ( path ) } ) ;
else
proc . startDetached ( " nautilus " , { " --no-desktop " , Utils : : Fs : : toNativePath ( path ) } ) ;
}
else if ( output = = " nemo.desktop " ) {
proc . startDetached ( " nemo " , { " --no-desktop " , Utils : : Fs : : toNativePath ( path ) } ) ;
}
else if ( ( output = = " konqueror.desktop " ) | | ( output = = " kfmclient_dir.desktop " ) ) {
proc . startDetached ( " konqueror " , { " --select " , Utils : : Fs : : toNativePath ( path ) } ) ;
}
else {
2016-07-23 06:24:58 +03:00
// "caja" manager can't pinpoint the file, see: https://github.com/qbittorrent/qBittorrent/issues/5003
2018-07-21 08:28:13 +03:00
openPath ( path . left ( path . lastIndexOf ( ' / ' ) ) ) ;
2018-05-15 22:03:12 +03:00
}
2015-06-28 21:58:39 +03:00
# else
2018-07-21 08:28:13 +03:00
openPath ( path . left ( path . lastIndexOf ( ' / ' ) ) ) ;
2015-06-28 21:58:39 +03:00
# endif
}
2016-07-23 06:23:16 +03:00
2015-06-28 21:58:39 +03:00
# endif // DISABLE_GUI
2016-02-27 00:48:53 +03:00
QString Utils : : Misc : : osName ( )
{
// static initialization for usage in signal handler
static const QString name =
2016-07-23 06:23:16 +03:00
QString ( " %1 %2 %3 " )
2018-03-06 18:49:12 +03:00
. arg ( QSysInfo : : prettyProductName ( )
, QSysInfo : : kernelVersion ( )
, QSysInfo : : currentCpuArchitecture ( ) ) ;
2016-02-27 00:48:53 +03:00
return name ;
}
2016-02-27 03:27:56 +03:00
QString Utils : : Misc : : boostVersionString ( )
{
// static initialization for usage in signal handler
static const QString ver = QString ( " %1.%2.%3 " )
2016-07-23 06:23:16 +03:00
. arg ( BOOST_VERSION / 100000 )
. arg ( ( BOOST_VERSION / 100 ) % 1000 )
. arg ( BOOST_VERSION % 100 ) ;
2016-02-27 03:27:56 +03:00
return ver ;
}
2016-02-27 03:38:52 +03:00
QString Utils : : Misc : : libtorrentVersionString ( )
{
// static initialization for usage in signal handler
static const QString ver = LIBTORRENT_VERSION ;
return ver ;
}
2016-07-23 08:19:26 +03:00
# ifdef Q_OS_WIN
QString Utils : : Misc : : windowsSystemPath ( )
{
static const QString path = [ ] ( ) - > QString {
2018-09-21 12:26:17 +03:00
WCHAR systemPath [ MAX_PATH ] = { 0 } ;
2016-07-23 08:19:26 +03:00
GetSystemDirectoryW ( systemPath , sizeof ( systemPath ) / sizeof ( WCHAR ) ) ;
return QString : : fromWCharArray ( systemPath ) ;
} ( ) ;
return path ;
}
# endif