/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 *
 * Copyright (C) 2019 KylinSoft  Co., Ltd.
 *
 * 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 St, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */
#include "sysdbusregister.h"

#include <QDebug>
#include <QSharedPointer>
#include <QRegularExpression>
#include <QProcess>
#include <stdlib.h>
#include <QDir>

#include <QDBusInterface>
#include <QDBusReply>
#include <QCryptographicHash>
#include <polkit-qt6-1/polkitqt1-authority.h>

#include <kysdk/kysdk-system/libkysysinfo.h>

/* qt会将glib里的signals成员识别为宏，所以取消该宏
 * 后面如果用到signals时，使用Q_SIGNALS代替即可
 **/
#ifdef signals
#undef signals
#endif

#include <glib.h>
#include <gio/gio.h>

#include <QtConcurrent/QtConcurrent>
#include <QDBusMessage>

QStringList ddcProIdList;

SysdbusRegister::SysdbusRegister()
    : UKUI::ServiceObject(nullptr), QDBusContext()
{
    QString aptSettingFile = "/etc/ukui-control-center/apt.conf";
    aptSettings = new QSettings(aptSettingFile, QSettings::IniFormat, this);

    mHibernateFile = "/etc/systemd/sleep.conf";
    mHibernateSet = new QSettings(mHibernateFile, QSettings::IniFormat, this);
    exitFlag = false;
    if (getCpuInfo().contains("D2000", Qt::CaseInsensitive)) {
        toGetDisplayInfo = false;
    } else {
        toGetDisplayInfo = true;
    }

    if (getCpuInfo() == QString("11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz")) {
        forceI2c = true;
    } else {
        forceI2c = false;
    }


    _getDisplayInfoThread();

    _id = 0;

    const char *sessionType = kdk_system_get_production_line();
    if (!QString(sessionType).compare("wayland", Qt::CaseInsensitive)) {
        m_isWayland = true;
    }
    m_diskInfo.clear();
    getDiskInfofromDbus();
}

void SysdbusRegister::getDiskInfofromDbus() {
    QDBusInterface ifc("com.kylin-os-manager",
                       "/driverinfo",
                       "driverinfo.tool",
                       QDBusConnection::systemBus());
    QDBusReply<QString> obj_reply = ifc.call("getDiskInfo");
    if (!obj_reply.isValid()) {
        qDebug() << Q_FUNC_INFO << "getDiskInfo return invalid";
        return;
    }
    QString diskStr = obj_reply.value();
    qDebug() << Q_FUNC_INFO << "getDiskInfo value" << diskStr;
    if (diskStr.isEmpty()) {
        qDebug() << Q_FUNC_INFO << "getDiskInfo value is empty";
        return;
    }
    QByteArray jsonData = diskStr.toUtf8();
    QJsonDocument doc = QJsonDocument::fromJson(jsonData);
    if (doc.isNull()) {
        qDebug() << Q_FUNC_INFO << "diskStr to QJsonDocument is null";
        return;
    }

    if (!doc.isArray()) {
        qDebug() << Q_FUNC_INFO << "diskStr to QJsonDocument is not array";
        return;
    }

    QJsonArray devices = doc.array();
    for (int idx = 0; idx < devices.size(); ++idx) {
        if (!devices[idx].isObject()) {
            qDebug() << Q_FUNC_INFO << "index" << idx << "is not Object";
            continue;
        }
        QJsonObject device = devices[idx].toObject();
        if (device.contains("size")) {
            m_diskInfo = device.value("size").toString();
            qDebug() << Q_FUNC_INFO << "disk size" << m_diskInfo;
            break;
        }
    }
    if (m_diskInfo.isEmpty()) {
        qDebug() << Q_FUNC_INFO << "disk size is empty" << m_diskInfo;
        return;
    }
    qDebug() << Q_FUNC_INFO << "disk size" << m_diskInfo;
}

QString SysdbusRegister::getDiskInfo() {
    return m_diskInfo;
}

SysdbusRegister::~SysdbusRegister()
{
    exitFlag = true;

}

void SysdbusRegister::exitService()
{
    exitFlag = true;
    this->emitUkuiServiceObjectFinished();
}

int SysdbusRegister::setPid(qint64 id)
{
    //密码校验
    QDBusConnection conn = connection();
    QDBusMessage msg = message();

    if (!authoriySetPid(conn.interface()->servicePid(msg.service()).value())){
       return 0;
    }

    _id = id;

    return 1;
}

bool SysdbusRegister::isSudoGroupNumber(QString uname)
{
    QString cmd = QString("cat /etc/group | grep sudo | awk -F: '{ print $NF}'");
    QString output;

    FILE   *stream;
    char buf[256];

    if ((stream = popen(cmd.toLatin1().data(), "r" )) == NULL){
        return false;
    }

    while(fgets(buf, 256, stream) != NULL){
        output = QString(buf).simplified();
    }

    pclose(stream);

    QStringList users = output.split(",");

    if (users.contains(uname)){
        return true;
    } else {
        return false;
    }
}

QString SysdbusRegister::GetComputerInfo() {
    QByteArray ba;
    FILE * fp = NULL;
    char cmd[128];
    char buf[1024];
    snprintf(cmd, 128, "dmidecode -t system");

    if ((fp = popen(cmd, "r")) != NULL){
        rewind(fp);
        while (!feof(fp)) {
            fgets(buf, sizeof (buf), fp);
            ba.append(buf);
        }
        pclose(fp);
        fp = NULL;
    }
    return QString(ba);
}

//获取免密登录状态
QString SysdbusRegister::getNoPwdLoginStatus(){
    QByteArray ba;
    FILE * fp = NULL;
    char cmd[128];
    char buf[1024];
    snprintf(cmd, 128, "cat /etc/group |grep nopasswdlogin");
    if ((fp = popen(cmd, "r")) != NULL){
        rewind(fp);
        fgets(buf, sizeof (buf), fp);
        ba.append(buf);
        pclose(fp);
        fp = NULL;
    }else{
        qDebug()<<"popen文件打开失败";
    }
    return QString(ba);
}

void SysdbusRegister::notifyPropertyChanged( const QString& interface,
                            const QString& propertyName)
{
    QDBusMessage signal = QDBusMessage::createSignal(
        "/",
        "org.freedesktop.DBus.Properties",
        "PropertiesChanged");
    signal << interface;
    QVariantMap changedProps;
    changedProps.insert(propertyName, property(propertyName.toLatin1().data()));
    signal << changedProps;
    signal << QStringList();
    QDBusConnection::systemBus().send(signal);
}

bool SysdbusRegister::NoPwdLoginStatus() const
{
    return NoPwdLogin;
}
//设置免密登录状态
bool SysdbusRegister::setNoPwdLoginStatus(bool status,QString username)
{
    //密码校验
    QDBusConnection conn = connection();
    QDBusMessage msg = message();

    if (!checkAuthorization(conn.interface()->servicePid(msg.service()).value())){
        return false;
    }

    if (username == nullptr) {
        if (status == false) {
            QString noPwdLoginUser = getNoPwdLoginStatus();
            qDebug() << "noPwdLoginUser:" << noPwdLoginUser;
            QStringList tmp = noPwdLoginUser.split(":", Qt::SkipEmptyParts);

            QString noPasswdUsers = tmp.at(tmp.count()-1);
            QStringList noPasswdUsersList = noPasswdUsers.split(",", Qt::SkipEmptyParts);
            foreach (QString noPasswdUser, noPasswdUsersList) {
                noPasswdUser.remove(QChar('\n'), Qt::CaseInsensitive);
                qDebug() << "nopasswduser:" << noPasswdUser;
                QString cmd = QString("gpasswd  -d %1 nopasswdlogin").arg(noPasswdUser);;
                QProcess::execute(cmd);
            }
        }
    } else {
        QString cmd;
        if(true == status){
             cmd = QString("gpasswd  -a %1 nopasswdlogin").arg(username);
        } else{
            cmd = QString("gpasswd  -d %1 nopasswdlogin").arg(username);
        }
        QProcess::execute(cmd);
    }

    NoPwdLogin = status;
    notifyPropertyChanged("com.control.center.qt.systemdbus", "NoPwdLoginStatus");
    return true;
}

// 设置自动登录状态
int SysdbusRegister::setAutoLoginStatus(QString username) {
    //密码校验
    QDBusConnection conn = connection();
    QDBusMessage msg = message();

    if (!authoriyAutoLogin(conn.interface()->servicePid(msg.service()).value())){
        return 0;
    }
    QString filename = "/etc/lightdm/lightdm.conf";
    QSharedPointer<QSettings>  autoSettings = QSharedPointer<QSettings>(new QSettings(filename, QSettings::IniFormat));
    autoSettings->beginGroup("SeatDefaults");

    autoSettings->setValue("autologin-user", username);

    autoSettings->endGroup();
    autoSettings->sync();

    return 1;
}

QString SysdbusRegister::getSuspendThenHibernate() {
    mHibernateSet->beginGroup("Sleep");

    QString time = mHibernateSet->value("HibernateDelaySec").toString();

    mHibernateSet->endGroup();
    mHibernateSet->sync();

    return time;
}

void SysdbusRegister::setSuspendThenHibernate(QString time) {
    mHibernateSet->beginGroup("Sleep");

    mHibernateSet->setValue("HibernateDelaySec", time);

    mHibernateSet->endGroup();
    mHibernateSet->sync();
}

int SysdbusRegister::setPasswdAging(int days, QString username) {
    //密码校验
    QDBusConnection conn = connection();
    QDBusMessage msg = message();

    if (!authoriyPasswdAging(conn.interface()->servicePid(msg.service()).value())){
        return 0;
    }

    QString cmd;

    cmd = QString("chage -M %1 %2").arg(days).arg(username);
    QProcess::execute(cmd);

    return 1;
}

int SysdbusRegister::_changeOtherUserPasswd(QString username, QString pwd){

    std::string str1 = username.toStdString();
    const char * user_name = str1.c_str();

    QString output;
    QString newPwd = pwd;
    int i = 0;
    for (i = 0; i < newPwd.count(); i++){
        if (!(int(newPwd.at(i).toLatin1() >= 48 && int(newPwd.at(i).toLatin1()) <= 57) ||
            int(newPwd.at(i).toLatin1() >= 65 && int(newPwd.at(i).toLatin1()) <= 90) ||
            int(newPwd.at(i).toLatin1() >= 97 && int(newPwd.at(i).toLatin1()) <= 122))){

                newPwd = newPwd.insert(i, QString("\\"));
                i++;
        }
    }

    std::string str2 = newPwd.toStdString();
    const char * passwd = str2.c_str();

    char * cmd = g_strdup_printf("/usr/bin/changeotheruserpwd '%s' %s", user_name, passwd);

    FILE   *stream;
    char buf[256];

    if ((stream = popen(cmd, "r" )) == NULL){
        return -1;
    }

    while(fgets(buf, 256, stream) != NULL){
        output = QString(buf).simplified();
    }

    pclose(stream);

    return 1;
}

int SysdbusRegister::changeOtherUserPasswd(QString username, QString pwd){

    //密码校验
    QDBusConnection conn = connection();
    QDBusMessage msg = message();
    if (!checkAuthorization(conn.interface()->servicePid(msg.service()).value())){
        return 0;
    }

    int _changeRet = _changeOtherUserPasswd(username, pwd);

    return _changeRet;

}

int SysdbusRegister::createUser(QString name, QString fullname, int accounttype, QString faceicon, QString pwd){

    //密码校验
    QDBusConnection conn = connection();
    QDBusMessage msg = message();
    if (!checkAuthorization(conn.interface()->servicePid(msg.service()).value())){
        return 0;
    }

    QDBusInterface iface("org.freedesktop.Accounts",
                         "/org/freedesktop/Accounts",
                         "org.freedesktop.Accounts",
                         QDBusConnection::systemBus());

    QDBusReply<QDBusObjectPath> reply = iface.call("CreateUser", name, fullname, accounttype);

    if (reply.isValid()){
        QString op = reply.value().path();
        if (!op.isEmpty()){

            QDBusInterface ifaceUser("org.freedesktop.Accounts",
                                     op,
                                     "org.freedesktop.Accounts.User",
                                     QDBusConnection::systemBus());
            // 设置头像
            ifaceUser.call("SetIconFile", faceicon);

            // 设置密码
            _changeOtherUserPasswd(name, pwd);


        }
    }

    return 1;

}

bool SysdbusRegister::checkAuthorization(qint64 id){

    _id = id;

    if (_id == 0)
        return false;

    PolkitQt1::Authority::Result result;

    result = PolkitQt1::Authority::instance()->checkAuthorizationSync(
                "org.control.center.qt.systemdbus.action",
                PolkitQt1::UnixProcessSubject(_id),
                PolkitQt1::Authority::AllowUserInteraction);

    if (result == PolkitQt1::Authority::Yes){
        _id = 0;
        return true;
    } else {
        _id = 0;
        return false;
    }
}

bool SysdbusRegister::authoriySetPid(qint64 id)
{
    _id = id;

    if (_id == 0)
        return false;

    PolkitQt1::Authority::Result result;

    result = PolkitQt1::Authority::instance()->checkAuthorizationSync(
                "org.control.center.qt.systemdbus.action.pid",
                PolkitQt1::UnixProcessSubject(_id),
                PolkitQt1::Authority::AllowUserInteraction);

    if (result == PolkitQt1::Authority::Yes){
        _id = 0;
        return true;
    } else {
        _id = 0;
        return false;
    }
}

bool SysdbusRegister::authoriyGrub(qint64 id)
{
    _id = id;

    if (_id == 0)
        return false;

    PolkitQt1::Authority::Result result;

    result = PolkitQt1::Authority::instance()->checkAuthorizationSync(
                "org.control.center.qt.systemdbus.action.grub",
                PolkitQt1::UnixProcessSubject(_id),
                PolkitQt1::Authority::AllowUserInteraction);

    if (result == PolkitQt1::Authority::Yes){
        _id = 0;
        return true;
    } else {
        _id = 0;
        return false;
    }
}

bool SysdbusRegister::authoriyAutoLogin(qint64 id)
{
    _id = id;

    if (_id == 0)
        return false;

    PolkitQt1::Authority::Result result;

    result = PolkitQt1::Authority::instance()->checkAuthorizationSync(
                "org.control.center.qt.systemdbus.action.autologin",
                PolkitQt1::UnixProcessSubject(_id),
                PolkitQt1::Authority::AllowUserInteraction);

    if (result == PolkitQt1::Authority::Yes){
        _id = 0;
        return true;
    } else {
        _id = 0;
        return false;
    }
}

bool SysdbusRegister::authoriyPasswdAging(qint64 id)
{
    _id = id;

    if (_id == 0)
        return false;

    PolkitQt1::Authority::Result result;

    result = PolkitQt1::Authority::instance()->checkAuthorizationSync(
                "org.control.center.qt.systemdbus.action.passwdaging",
                PolkitQt1::UnixProcessSubject(_id),
                PolkitQt1::Authority::AllowUserInteraction);

    qDebug() << "result = " << result;
    if (result == PolkitQt1::Authority::Yes){
        _id = 0;
        return true;
    } else {
        _id = 0;
        return false;
    }
}

bool SysdbusRegister::authoriySetHostName(qint64 id)
{
    _id = id;

    if (_id == 0)
        return false;

    PolkitQt1::Authority::Result result;

    result = PolkitQt1::Authority::instance()->checkAuthorizationSync(
                "org.control.center.qt.systemdbus.action.hostname",
                PolkitQt1::UnixProcessSubject(_id),
                PolkitQt1::Authority::AllowUserInteraction);

    qDebug() << "result = " << result;
    if (result == PolkitQt1::Authority::Yes){
        _id = 0;
        return true;
    } else {
        _id = 0;
        return false;
    }
}

void SysdbusRegister::_setI2CBrightness(QString brightness, QString type) {
    QString program = "/usr/sbin/i2ctransfer";
    QStringList arg;
    int br=brightness.toInt();
    QString light = "0x" + QString::number(br,16);
    QString c = "0x" + QString::number(168^br,16);
    arg << "-f" << "-y" << type << "w7@0x37" << "0x51" << "0x84" << "0x03"
        << "0x10" << "0x00" << light << c;
    QProcess *vcpPro = new QProcess(this);
    vcpPro->startDetached(program, arg);
}

int SysdbusRegister::_getI2CBrightness(QString type) {
    QString program = "/usr/sbin/i2ctransfer";
    QStringList arg;
    QProcess vcpPro;
    int bright[2] = {-1,-1}; //部分显示器不能调节亮度但是返回值 > 0,所以获取两次判断是否一致
    bool ok;
    for (int i = 0; i < 2; i++) {
        arg.clear();
        arg<<"-f"<<"-y"<<type<<"w5@0x37"<<"0x51"<<"0x82"<<"0x01"<<"0x10"<<"0xac";
        vcpPro.start(program, arg);
        vcpPro.waitForStarted();
        vcpPro.waitForFinished();
        arg.clear();
        arg<<"-f"<<"-y"<<type<<"r16@0x37";
        usleep(40000);
        vcpPro.start(program, arg);
        vcpPro.waitForStarted();
        vcpPro.waitForFinished();
        QString result = vcpPro.readAllStandardOutput().trimmed();
        if (result == "")
            return -1;

        QString bri=result.split(" ").at(9);
        bright[i] = bri.toInt(&ok,16);
    }
    if (bright[0] != bright[1]) {
        return -1;
    }
    if(ok && bright[0] >= 0 && bright[0] <= 100)
        return bright[0];

    return -1;
}

QString SysdbusRegister::getCpuInfo()
{
    QFile file("/proc/cpuinfo");

    if (file.open(QIODevice::ReadOnly)) {
        QString buffer = file.readAll();
        QStringList modelLine = buffer.split('\n').filter(QRegularExpression("^model name"));
        QStringList modelLineWayland = buffer.split('\n').filter(QRegularExpression("^Hardware"));
        QStringList lines = buffer.split('\n');

        if (modelLine.isEmpty()) {
            if (modelLineWayland.isEmpty()) {
                return "Unknown";
            }
            modelLine = modelLineWayland;
        }


        int count = lines.filter(QRegularExpression("^processor")).count();

        QString result;
        result.append(modelLine.first().split(':').at(1));
        result = result.trimmed();

        return result;
    }

    return QString();
}


int SysdbusRegister::changeRTC() {
    QString cmd = "hwclock -w";
    return system(cmd.toLatin1().data());
}

bool SysdbusRegister::setNtpSerAddress(QString serverAddress)
{
    if (serverAddress == "default") {
        system("rm -rf /etc/systemd/timesyncd.conf.d/");
        system("timedatectl set-ntp false");
        system("timedatectl set-ntp true");
        return true;
    }

    QString dirName  = "/etc/systemd/timesyncd.conf.d/";
    QString fileName = "/etc/systemd/timesyncd.conf.d/kylin.conf";

    QDir  dir(dirName);
    QFile file(fileName);
    if (!dir.exists()) {
        if (dir.mkdir(dirName) == false) {
            return false;
        }
    }
    if (file.open(QIODevice::WriteOnly) == false) {
        return false;
    }
    file.write("[Time]\n");
    file.write("NTP = ");
    file.write(serverAddress.toLatin1().data());
    file.write("\n");
    file.close();
    system("timedatectl set-ntp false");
    system("timedatectl set-ntp true");
    return true;

}

bool SysdbusRegister::setaptproxy(QString ip, QString port, bool open)
{
    QStringList keys = aptSettings->childGroups();
    aptSettings->beginGroup("Info");
    aptSettings->setValue("open", open);
    aptSettings->setValue("ip", ip);
    aptSettings->setValue("port", port);
    aptSettings->endGroup();
    QString content_http = QString("%1%2%3%4%5%6").arg("Acquire::http::Proxy ").arg("\"http://").arg(ip).arg(":").arg(port).arg("\";\n");
    QString content_https = QString("%1%2%3%4%5%6").arg("Acquire::https::Proxy ").arg("\"https://").arg(ip).arg(":").arg(port).arg("\";\n");
    QString profile_http = QString("%1%2%3%4%5").arg("export http_proxy=\"http://").arg(ip).arg(":").arg(port).arg("\"\n");
    QString profile_https = QString("%1%2%3%4%5").arg("export https_proxy=\"https://").arg(ip).arg(":").arg(port).arg("\"\n");

    QString dirName  = "/etc/apt/apt.conf.d/";
    QString fileName = "/etc/apt/apt.conf.d/80apt-proxy";
    QString dirName_1  = "/etc/profile.d/";
    QString fileName_1 = "/etc/profile.d/80apt-proxy.sh";
    QDir AptDir(dirName);
    QDir ProDir(dirName_1);
    QFile AptProxyFile(fileName);
    QFile AptProxyProFile(fileName_1);

    if (AptDir.exists() && ProDir.exists()) {
        if (open) {    //开关开启则创建对应文件，未开启则删掉对应文件
            if (AptProxyFile.exists() && AptProxyProFile.exists()) {
               AptProxyFile.remove();
               AptProxyProFile.remove();
            }
            AptProxyFile.open(QIODevice::ReadWrite | QIODevice::Text);
            AptProxyProFile.open(QIODevice::ReadWrite | QIODevice::Text);
            //写入内容,这里需要转码，否则报错
            QByteArray str = content_http.toUtf8();
            QByteArray str_1 = content_https.toUtf8();
            QByteArray str_2 = profile_http.toUtf8();
            QByteArray str_3 = profile_https.toUtf8();
            //写入QByteArray格式字符串
            AptProxyFile.write(str);
            AptProxyFile.write(str_1);
            AptProxyProFile.write(str_2);
            AptProxyProFile.write(str_3);
        } else {
            if (AptProxyFile.exists() && AptProxyProFile.exists()) {
               AptProxyFile.remove();
               AptProxyProFile.remove();
            }
        }
    }else {
           return false;
    }
    return true;
}

QHash<QString, QVariant> SysdbusRegister::getaptproxy()
{
    QHash<QString, QVariant> mAptInfo;
    aptSettings->beginGroup("Info");
    mAptInfo.insert("open" ,  aptSettings->value("open").toBool());
    mAptInfo.insert("ip" ,  aptSettings->value("ip").toString());
    mAptInfo.insert("port" ,  aptSettings->value("port").toString());
    aptSettings->endGroup();
    return mAptInfo;
}

bool SysdbusRegister::sethostname(QString hostname)
{
    //密码校验
    QDBusConnection conn = connection();
    QDBusMessage msg = message();

    if (!authoriySetHostName(conn.interface()->servicePid(msg.service()).value())){
        return false;
    }

    QString fileName = "/etc/hosts";
    QString strAll;
    QFile readFile(fileName);
    if(readFile.open(QIODevice::ReadWrite | QIODevice::Text))
    {
        QTextStream stream_1(&readFile);
        int count = 0;
        while(!stream_1.atEnd())
        {
            if (count != 0)
                strAll.append("\n");
            count++;
            QString oneLine = stream_1.readLine();  //读取一行
            if(oneLine.contains("127.0.1.1")) {
                QString tempStr = QString("%1%2").arg("127.0.1.1       ").arg(hostname);
                strAll.append(tempStr);
                continue;
            }
            strAll.append(oneLine);
        }
    }
    readFile.close();
    QFile writeFile(fileName);
    if(writeFile.open(QIODevice::WriteOnly | QIODevice::Text))
    {
            QTextStream stream_2(&writeFile);
            stream_2<<strAll;
    }
    writeFile.close();

    return true;
}

QString SysdbusRegister::getMemory()
{
    float memorysize(0.0);
    // 设置系统环境变量
    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    env.insert("LANG","en_US");
    QProcess *process = new QProcess;
    process->setProcessEnvironment(env);
    process->start("bash" , QStringList() << "-c" << "dmidecode -t memory | grep Size ");
    process->waitForFinished();
    QByteArray ba = process->readAllStandardOutput();
    delete process;

    QString sizeinfo = QString(ba.data());
    QStringList size_list = sizeinfo.split('\n');
    for (QString str : size_list) {
        str.remove(QRegularExpression("\\s"));
        if (str.split(':').at(0) == "Size") {
            QString res = str.split(':').at(1);
            QRegularExpression rx("^\\d");
            QRegularExpressionMatch match = rx.match(res);
            if (match.hasMatch()){
                QRegularExpression rx_1("^(.*)MB$");
                QRegularExpression rx_2("^(.*)GB$");
                QRegularExpressionMatch match_1 = rx_1.match(res);
                QRegularExpressionMatch match_2 = rx_2.match(res);
                if (match_1.hasMatch()) {
                    qDebug()<<match_1.captured(1);
                    memorysize +=  ceil(match_1.captured(1).toFloat()/1024);
                }
                if (match_2.hasMatch()) {
                    qDebug()<<match_2.captured(1);
                    memorysize +=  match_2.captured(1).toFloat();
                }
            }
        }
    }
    qDebug()<<"memory : "<<memorysize;
    return QString::number(memorysize);
}

void SysdbusRegister::getDisplayInfo()
{
    toGetDisplayInfo = true;
    return;
}

void SysdbusRegister::_getDisplayInfoThread()
{
    QtConcurrent::run([=] {  //运行独立线程去获取ddc信息，不能每次重新运行run，会导致获取的信息不对
        while (true) {
            if (exitFlag)
                return;
            if (!toGetDisplayInfo || forceI2c) {
                sleep(1);
                continue;
            }
            bool include_invalid_displays = true;
            DDCA_Display_Info_List*  dlist_loc = nullptr;
            ddca_get_display_info_list2(include_invalid_displays, &dlist_loc);
            for(int i = 0; i < dlist_loc->ct; i++) {
                QCryptographicHash Hash(QCryptographicHash::Md5);
                Hash.reset();
                Hash.addData(reinterpret_cast<const char *>(dlist_loc->info[i].edid_bytes), 128);
                QByteArray md5 = Hash.result().toHex();
                QString edidHash = QString(md5);

                if (dlist_loc->info[i].dispno < 0) {  //this display is invalid for DDC.
                    bool edidExist = false;
                    for (int j = 0; j < displayInfo_V.size(); j++) {
                        if (edidHash == displayInfo_V[j].edidHash) {
                            if (false == displayInfo_V[j]._DDC) {
                                edidExist = true;
                                for (int i = 0; i < 3; i++) {
                                    displayInfo_V[j].I2C_brightness = _getI2CBrightness(displayInfo_V[j].I2C_busType); //重新获取亮度
                                    if (displayInfo_V[j].I2C_brightness > 0) {
                                        break;
                                    }
                                    sleep(1);
                                }
                            } else { //有的显示器刚开始是valid
                                displayInfo_V.remove(j);
                                edidExist = false;
                            }
                            break;
                        }
                    }
                    if (false == edidExist) {
                        struct displayInfo display;
                        display.edidHash = edidHash;
                        display._DDC = false;
                        display.I2C_busType = QString::number(dlist_loc->info[i].path.path.i2c_busno);
                        for (int i = 0; i < 3; i++) {
                            display.I2C_brightness = _getI2CBrightness(display.I2C_busType);
                            if (display.I2C_brightness > 0) {
                                break;
                            }
                            sleep(1);
                        }
                        displayInfo_V.append(display);
                    }
                } else {  //this display is valid for DDC.
                    bool edidExist = false;
                    for (int j = 0; j < displayInfo_V.size(); j++) {
                        if (edidHash == displayInfo_V[j].edidHash) {
                            if (true == displayInfo_V[j]._DDC) {
                                edidExist = true;
                            } else { //有的显示器刚开始是invalid
                                displayInfo_V.remove(j);
                                edidExist = false;
                            }
                            break;
                        }
                    }
                    if (!edidExist) {
                        struct displayInfo display;
                        DDCA_Display_Identifier did;
                        DDCA_Display_Ref ddca_dref;
                        display._DDC = true;
                        display.edidHash = edidHash;
                        display.I2C_busType = QString::number(dlist_loc->info[i].path.path.i2c_busno);
                        ddca_create_edid_display_identifier(dlist_loc->info[i].edid_bytes,&did);
                        ddca_create_display_ref(did,&ddca_dref);
                        ddca_open_display2(ddca_dref,false,&display.ddca_dh_loc);
                        displayInfo_V.append(display);
                    }
                }
            }
            ddca_free_display_info_list(dlist_loc);
            toGetDisplayInfo = false;
        }
    });
}

void SysdbusRegister::setDisplayBrightness(QString brightness, QString edidHash, QString i2cBus)
{
    //内核有i2c号，直接使用i2c协议
    if (i2cBus != "-1") {
        for (int j = 0; j < i2c_displayInfo_V.size(); j++) {
            if (i2c_displayInfo_V[j].m_I2C_busType == i2cBus) {
                i2c_displayInfo_V[j].m_I2C_brightness = brightness.toInt();
                _setI2CBrightness(brightness, i2cBus);
                return;
            }
        }
        //还未存在
        struct I2CdisplayInfo display;
        display.m_I2C_busType = i2cBus;
        display.m_I2C_brightness = -1;
        i2c_displayInfo_V.append(display);
        QtConcurrent::run([=, i2cBus] {
            for (int num = 0; num < i2c_displayInfo_V.size(); num++) {
                if (i2c_displayInfo_V[num].m_I2C_busType == i2cBus) {
                    for (int i = 0; i < 3; i++) {
                        i2c_displayInfo_V[num].m_I2C_brightness = _getI2CBrightness(display.m_I2C_busType);
                        if (i2c_displayInfo_V[num].m_I2C_brightness > 0) {
                            break;
                        }
                        sleep(1);
                    }
                    return;
                }
            }
        });
    } else {
        bool edidExist = false;
        for (int j = 0; j < displayInfo_V.size(); j++) {
            if (displayInfo_V[j].edidHash == edidHash) {
                edidExist = true;
                if (true == displayInfo_V[j]._DDC) {
                    uint8_t new_sh = brightness.toUInt() >> 8;
                    uint8_t new_sl = brightness.toUInt() & 0xff;
                    ddca_set_non_table_vcp_value(displayInfo_V[j].ddca_dh_loc,0x10,new_sh,new_sl);
                } else {
                    _setI2CBrightness(brightness, displayInfo_V[j].I2C_busType);
                    displayInfo_V[j].I2C_brightness = brightness.toInt();
                }
            }
        }
        if (!edidExist) {
            getDisplayInfo();
        }
    }
    return;
}

int SysdbusRegister::getDisplayBrightness(QString edidHash, QString i2cBus)
{
    //内核有i2c号，直接使用i2c协议
    if (i2cBus != "-1") {
        for (int j = 0; j < i2c_displayInfo_V.size(); j++) {
            if (i2c_displayInfo_V[j].m_I2C_busType == i2cBus) {
                if (i2c_displayInfo_V[j].m_I2C_brightness < 0) {
                    QtConcurrent::run([=, j] {
                        i2c_displayInfo_V[j].m_I2C_brightness = _getI2CBrightness(i2c_displayInfo_V[j].m_I2C_busType);
                    });
                }
                return i2c_displayInfo_V[j].m_I2C_brightness;
            }
        }
        //还未存在
        struct I2CdisplayInfo display;
        display.m_I2C_busType = i2cBus;
        display.m_I2C_brightness = -1;
        i2c_displayInfo_V.append(display);
        QtConcurrent::run([=, i2cBus] {
            for (int num = 0; num < i2c_displayInfo_V.size(); num++) {
                if (i2c_displayInfo_V[num].m_I2C_busType == i2cBus) {
                    for (int i = 0; i < 3; i++) {
                        i2c_displayInfo_V[num].m_I2C_brightness = _getI2CBrightness(display.m_I2C_busType);
                        if (i2c_displayInfo_V[num].m_I2C_brightness > 0) {
                            break;
                        }
                        sleep(1);
                    }
                    return;
                }
            }
        });
    } else {
        bool edidExist = false;
        for (int j = 0; j < displayInfo_V.size(); j++) {
            if (displayInfo_V[j].edidHash == edidHash) {
                edidExist = true;
                if (true == displayInfo_V[j]._DDC) {
                    DDCA_Non_Table_Vcp_Value  valrec;
                    if (ddca_get_non_table_vcp_value(displayInfo_V[j].ddca_dh_loc,0x10,&valrec) == 0) {
        //                uint16_t max_val = valrec.mh << 8 | valrec.ml; 暂未使用
                        uint16_t cur_val = valrec.sh << 8 | valrec.sl;
                        return cur_val;
                    } else {
                        getDisplayInfo();
                        return -2;
                    }
                } else {
                    if (displayInfo_V[j].I2C_brightness >=0 && displayInfo_V[j].I2C_brightness <= 100) {
                        return displayInfo_V[j].I2C_brightness;
                    } else {
                        getDisplayInfo();
                        return -2;
                    }
                }
            }
        }
        if (!edidExist) {
            getDisplayInfo();
        }
    }
    return -2;
}

QString SysdbusRegister::showDisplayInfo()
{
    QString retString = "";
    for (int i = 0; i < i2c_displayInfo_V.size(); i++) {
        retString = retString + "<I2C-drm>" + " bus=" + i2c_displayInfo_V[i].m_I2C_busType + "("+QString::number(i2c_displayInfo_V[i].m_I2C_brightness)+")" + "\r\n";
    }

    for (int j = 0; j < displayInfo_V.size(); j++) {
        if (true == displayInfo_V[j]._DDC) {
            retString = retString + "<DDC>" + " bus=" + displayInfo_V[j].I2C_busType;
        } else {
            retString = retString + "<I2C>" + " bus=" + displayInfo_V[j].I2C_busType + "("+QString::number(displayInfo_V[j].I2C_brightness)+")";
        }
        retString = retString + " edidHash=" + displayInfo_V[j].edidHash + "\r\n";
    }
    return retString;
}

QString SysdbusRegister::getDmidecodeType()
{
    QString retString = "";
    QProcess process;
    QString cmd = "dmidecode --type 3 | grep Type:";
    process.start("bash", QStringList() <<"-c" << cmd);
    process.waitForFinished();
    QString strResult = process.readAllStandardOutput()+process.readAllStandardError();
    if (strResult.contains("Desktop", Qt::CaseInsensitive)) {
        retString = "desktop";
    } else if (strResult.contains("All In One", Qt::CaseInsensitive)) {
        retString = "all in one";
    } else if (strResult.contains("Notebook", Qt::CaseInsensitive)) {
        retString = "notebook";
    } else {
        retString = "unknown";
    }

    return retString;
}

QString SysdbusRegister::getDmiDecodeRes(QString args)
{
    QString program = "/usr/sbin/dmidecode " + args;

    QProcess *vcpPro = new QProcess(this);
    vcpPro->start(program);
    vcpPro->waitForFinished();
    QByteArray ba = vcpPro->readAllStandardOutput();
    vcpPro->deleteLater();
    return QString::fromStdString(ba.toStdString());
}

QString SysdbusRegister::getShowTimezone()
{
    QFile file("/etc/.kytimezone");
    QString mTimezone = "";
    if(file.exists()) {
        if(file.open(QIODevice::ReadOnly | QIODevice::Text)) {
            QTextStream textStream(&file);
            mTimezone = textStream.readLine();
            file.close();
        }
    }
    return mTimezone;
}

void SysdbusRegister::setShowTimezone(QString timezone)
{
    QFile file("/etc/.kytimezone");
    if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate |
                QIODevice::Text)) {
        qDebug() << "setshowtimezone faild" << timezone;
        return;
    }
    file.write(timezone.toStdString().c_str());

    Q_EMIT changed("timezone");
    return;
}

bool SysdbusRegister::setGrupPasswd(QString username, QString passwd, QString lang, bool status)
{
    //密码校验
    QDBusConnection conn = connection();
    QDBusMessage msg = message();
    if (!callerPathCompare("/usr/bin/ukui-session-service")) {
        if (!authoriyGrub(conn.interface()->servicePid(msg.service()).value())){
            Q_EMIT this->updateFinished(false);
            return false;
        }
    }

    QString cmd;
    if(true == status){
        cmd = QString("grub-password -u %1 '%2' && export LANG=%3 && update-grub").arg(username).arg(passwd).arg(lang);
    } else{
        cmd = QString("grub-password -d && export LANG=%1 && update-grub").arg(lang);
    }

    qDebug() << "cmd= " << cmd;
    auto *watcher  = new QFutureWatcher<int>();
    connect(watcher, &QFutureWatcher<int>::finished, this, [this, watcher](){
        int ret = watcher->result();
        Q_EMIT this->updateFinished(ret == -1 ? false : true);
        watcher->deleteLater();
    });

    // Start the computation.
    QFuture<int> future = QtConcurrent::run([=, cmd] {
        int ret = system(cmd.toLatin1().data());
        return ret;
    });
    watcher->setFuture(future);

    return true;
}

bool SysdbusRegister::getGrupPasswdStatus()
{
    QByteArray ba = "";
    FILE * fp = NULL;
    char cmd[128];
    char buf[1024];
    snprintf(cmd, 128, "cat /etc/grub.d/00_header |grep password_pbkdf2");
    if ((fp = popen(cmd, "r")) != NULL){
        rewind(fp);
        fgets(buf, sizeof (buf), fp);
        ba.append(buf);
        pclose(fp);
        fp = NULL;
    }else{
        qDebug()<<"popen文件打开失败";
    }

    if (!ba.contains("password_pbkdf2")) {
        return false;
    }

    return true;
}

bool SysdbusRegister::callerPathCompare(QString path)
{
    QString clientService = message().service();
    QDBusConnectionInterface *intf = connection().interface();
    unsigned int  pid = intf->servicePid(clientService).value();
    /*check caller white list*/
    QFileInfo file(QString("/proc/%1/exe").arg(pid));
    QString execPath = "";
    if (file.exists()) {
        execPath= file.canonicalFilePath();
    }
    if (execPath != path) {
        return false;
    }

    return true;
}

bool SysdbusRegister::setGrupBootTime(int time, QString lang)
{
    //密码校验
    QDBusConnection conn = connection();
    QDBusMessage msg = message();
    if (!callerPathCompare("/usr/bin/ukui-session-service")) {
        if (!authoriyGrub(conn.interface()->servicePid(msg.service()).value())){
            Q_EMIT this->updateFinished(false);
            return false;
        }
    }

    QString filePath = "/etc/default/grub";
    QString keyword = "GRUB_TIMEOUT=";
    QString replaceContent = QString::number(time);
    QFile fileRead(filePath);       //先读取文件信息，QIODevice::Text能将换行转为\n
    QString arryRead;
    if (fileRead.open(QIODevice::ReadOnly|QIODevice::Text)) {
        arryRead = fileRead.readAll();
    }
    fileRead.close();

    //存储每一段信息
    QStringList arryListWrite = arryRead.split("\n");

    QFile fileWrite(filePath);
    if (fileWrite.open(QIODevice::WriteOnly|QIODevice::Text)) {        //文件流写文件
        QTextStream streamWrite(&fileWrite);      //通过文本流控制文件写操作

        //这里到arryListWrite.size()-1是因为arryListWrite数组按照\n分 段时，最后一行尾部有个\n，所以数组最后一个值为空，需要将它去掉
        for (int i = 0 ; i < arryListWrite.size() - 1; i++) {
            QString contentWrite= arryListWrite.at(i);
            if (contentWrite.contains(keyword)) {
                int indexBefore = contentWrite.indexOf(keyword);
                contentWrite.replace(indexBefore + keyword.length(), contentWrite.size() - indexBefore - keyword.length(), replaceContent);
                streamWrite << contentWrite << "\n";
            } else {
                streamWrite << arryListWrite.at(i) << "\n";
            }
        }

        fileWrite.close();

        QString cmd = QString("grub-install && export LANG=%1 && update-grub").arg(lang);
        if (m_isWayland) {
            cmd = QString("mount -o remount,rw /boot/ && mount -o remount,rw /boot/efi && export LANG=%1"
                          " && update-grub && mount -o remount,ro /boot/ && mount -o remount,ro /boot/efi").arg(lang);
        }
        qDebug() << "cmd= " << cmd;
        // Instantiate the objects and connect to the finished signal.

        auto *watcher  = new QFutureWatcher<int>();
        connect(watcher, &QFutureWatcher<int>::finished, this, [this, watcher](){
            int ret = watcher->result();
            Q_EMIT this->updateFinished(ret == -1 ? false : true);
            watcher->deleteLater();
        });

        // Start the computation.
        QFuture<int> future = QtConcurrent::run([=, cmd] {
            int ret = system(cmd.toLatin1().data());
            return ret;
        });
        watcher->setFuture(future);
    } else {
        qDebug() << filePath << "open failed";
        Q_EMIT this->updateFinished(false);
        return false;
    }

    return true;
}

int SysdbusRegister::getGrubBootTime()
{
    QByteArray ba = "";
    FILE * fp = NULL;
    char cmd[128];
    char buf[1024];
    snprintf(cmd, 128, "cat /etc/default/grub | grep GRUB_TIMEOUT | cut -d '=' -f 2");
    if ((fp = popen(cmd, "r")) != NULL){
        rewind(fp);
        fgets(buf, sizeof (buf), fp);
        ba.append(buf);
        pclose(fp);
        fp = NULL;
    } else {
        qDebug()<<"popen文件打开失败";
    }

    if (ba.isEmpty()) {
        return -1;
    }

    qDebug() << "GRUB_TIMEOUT = " << ba.toInt();

    return ba.toInt();
}

bool SysdbusRegister::setDefaultBootItem(int index, QString lang)
{
    //密码校验
    QDBusConnection conn = connection();
    QDBusMessage msg = message();
    if (!callerPathCompare("/usr/bin/ukui-session-service")) {
        if (!authoriyGrub(conn.interface()->servicePid(msg.service()).value())){
            Q_EMIT this->updateFinished(false);
            return false;
        }
    }

    QString filePath = "/etc/default/grub";
    QString keyword = "GRUB_DEFAULT=";
    QString replaceContent = QString::number(index);
    QFile fileRead(filePath);       //先读取文件信息，QIODevice::Text能将换行转为\n
    QString arryRead;
    if (fileRead.open(QIODevice::ReadOnly|QIODevice::Text)) {
        arryRead = fileRead.readAll();
    }
    fileRead.close();
    qDebug() << "arryRead" << arryRead;

    //存储每一段信息
    QStringList arryListWrite = arryRead.split("\n");
    qDebug() << "arryListWrite:";
    for(int i = 0; i < arryListWrite.size(); i++){
        qDebug() << arryListWrite.at(i);
    }

    QFile fileWrite(filePath);
    if (fileWrite.open(QIODevice::WriteOnly|QIODevice::Text)) {        //文件流写文件
        QTextStream streamWrite(&fileWrite);      //通过文本流控制文件写操作

        //这里到arryListWrite.size()-1是因为arryListWrite数组按照\n分 段时，最后一行尾部有个\n，所以数组最后一个值为空，需要将它去掉
        for (int i = 0 ; i < arryListWrite.size() - 1; i++) {
            QString contentWrite= arryListWrite.at(i);
            if (contentWrite.contains(keyword)) {
                int indexBefore = contentWrite.indexOf(keyword);
                contentWrite.replace(indexBefore + keyword.length(), contentWrite.size() - indexBefore - keyword.length(), replaceContent);
                streamWrite << contentWrite << "\n";
            } else {
                streamWrite << arryListWrite.at(i) << "\n";
            }
        }

        fileWrite.close();

        QString cmd = QString("grub-install && export LANG=%1 && update-grub").arg(lang);
        qDebug() << "cmd= " << cmd;
        auto *watcher  = new QFutureWatcher<int>();
        connect(watcher, &QFutureWatcher<int>::finished, this, [this, watcher](){
            int ret = watcher->result();
            Q_EMIT this->updateFinished(ret == -1 ? false : true);
            watcher->deleteLater();
        });

        // Start the computation.
        QFuture<int> future = QtConcurrent::run([=, cmd] {
            int ret = system(cmd.toLatin1().data());
            return ret;
        });
        watcher->setFuture(future);
    } else {
        qDebug() << filePath << "open failed";
        Q_EMIT this->updateFinished(false);
        return false;
    }

    return true;
}

int SysdbusRegister::getDefaultBootItem()
{
    QByteArray ba = "";
    FILE * fp = NULL;
    char cmd[128];
    char buf[1024];
    snprintf(cmd, 128, "cat /etc/default/grub | grep GRUB_DEFAULT | cut -d '=' -f 2");
    if ((fp = popen(cmd, "r")) != NULL){
        rewind(fp);
        fgets(buf, sizeof (buf), fp);
        ba.append(buf);
        pclose(fp);
        fp = NULL;
    } else {
        qDebug()<<"popen文件打开失败";
    }

    if (ba.isEmpty()) {
        return -1;
    }

    qDebug() << "GRUB_TIMEOUT = " << ba.toInt();

    return ba.toInt();
}

QString SysdbusRegister::getSysInstallTime(const QString &part)
{
    QProcess process;

    QString cmd = QString("/usr/sbin/tune2fs -l /dev/%1 |grep create").arg(part);
    process.start(cmd);
    process.waitForFinished();
    QString info = process.readAllStandardOutput();
    if (!info.isEmpty()) {
        if (info.contains("Filesystem created")) {
            info.replace(QRegularExpression("[\\s]+"), " ");
            return info.mid(20);
        }
    }
    return QString();
}

void SysdbusRegister::setXrdpService(bool status)
{
    QString cmd = QString("systemctl %1 xrdp.service").arg(status ? "start" : "stop");
    system(cmd.toUtf8().data());
    return;
}


