undefined reference to vtable for DownloadManager - c++

I am trying to integrate the working code into my program, but I receive the error displayed on the title while compiling. Here is the code:
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the examples of the Qt Toolkit.
**
****************************************************************************/
#include <QCoreApplication>
#include <QFile>
#include <QFileInfo>
#include <QList>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QSslError>
#include <QStringList>
#include <QTimer>
#include <QUrl>
#include <stdio.h>
QT_BEGIN_NAMESPACE
class QSslError;
QT_END_NAMESPACE
QT_USE_NAMESPACE
class DownloadManager: public QObject
{
Q_OBJECT
QNetworkAccessManager manager;
QList<QNetworkReply *> currentDownloads;
public:
DownloadManager();
~DownloadManager() = 0;
void doDownload(const QUrl &url);
QString saveFileName(const QUrl &url);
bool saveToDisk(const QString &filename, QIODevice *data);
public slots:
void execute();
void downloadFinished(QNetworkReply *reply);
void sslErrors(const QList<QSslError> &errors);
};
DownloadManager::DownloadManager()
{
connect(&manager, SIGNAL(finished(QNetworkReply*)),
SLOT(downloadFinished(QNetworkReply*)));
}
DownloadManager::~DownloadManager()
{}
void DownloadManager::doDownload(const QUrl &url)
{
QNetworkRequest request(url);
QNetworkReply *reply = manager.get(request);
#ifndef QT_NO_SSL
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(sslErrors(QList<QSslError>)));
#endif
currentDownloads.append(reply);
}
QString DownloadManager::saveFileName(const QUrl &url)
{
QString path = url.path();
QString basename = QFileInfo(path).fileName();
if (basename.isEmpty())
basename = "download";
if (QFile::exists(basename)) {
// already exists, don't overwrite
int i = 0;
basename += '.';
while (QFile::exists(basename + QString::number(i)))
++i;
basename += QString::number(i);
}
return basename;
}
bool DownloadManager::saveToDisk(const QString &filename, QIODevice *data)
{
QFile file(filename);
if (!file.open(QIODevice::WriteOnly)) {
fprintf(stderr, "Could not open %s for writing: %s\n",
qPrintable(filename),
qPrintable(file.errorString()));
return false;
}
file.write(data->readAll());
file.close();
return true;
}
void DownloadManager::execute()
{
QStringList args = QCoreApplication::instance()->arguments();
args.takeFirst(); // skip the first argument, which is the program's name
if (args.isEmpty()) {
printf("Qt Download example - downloads all URLs in parallel\n"
"Usage: download url1 [url2... urlN]\n"
"\n"
"Downloads the URLs passed in the command-line to the local directory\n"
"If the target file already exists, a .0, .1, .2, etc. is appended to\n"
"differentiate.\n");
QCoreApplication::instance()->quit();
return;
}
foreach (QString arg, args) {
QUrl url = QUrl::fromEncoded(arg.toLocal8Bit());
doDownload(url);
}
}
void DownloadManager::sslErrors(const QList<QSslError> &sslErrors)
{
#ifndef QT_NO_SSL
foreach (const QSslError &error, sslErrors)
fprintf(stderr, "SSL error: %s\n", qPrintable(error.errorString()));
#else
Q_UNUSED(sslErrors);
#endif
}
void DownloadManager::downloadFinished(QNetworkReply *reply)
{
QUrl url = reply->url();
if (reply->error()) {
fprintf(stderr, "Download of %s failed: %s\n",
url.toEncoded().constData(),
qPrintable(reply->errorString()));
} else {
QString filename = saveFileName(url);
if (saveToDisk(filename, reply))
printf("Download of %s succeeded (saved to %s)\n",
url.toEncoded().constData(), qPrintable(filename));
}
currentDownloads.removeAll(reply);
reply->deleteLater();
if (currentDownloads.isEmpty())
// all downloads finished
QCoreApplication::instance()->quit();
}
//int main(int argc, char **argv)
//{
// QCoreApplication app(argc, argv);
// DownloadManager manager;
// QTimer::singleShot(0, &manager, SLOT(execute()));
// app.exec();
//}
//#include "main.moc"
In the code above, I removed main() (i will just use the class) and include "main.moc" (this gives a not found error). I also added destructor just in case.
And here is the project file in QtCreator:
QT += widgets core network
CONFIG += console
CONFIG -= app_bundle
SOURCES = main.cpp \
gos.cpp \
download.cpp
HEADERS = gos.h
QMAKE_PROJECT_NAME = GoS
# install
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/tutorials/addressbook/part7
INSTALLS += target
simulator: warning(This example might not fully work on Simulator platform)
What am I missing?

Is the code in a header file (.h) or in a source file (.cpp)? When subclassing from QObject, moc depends on the class definition being in a header.
So split the class definition from download.cpp into download.h and add it to the HEADERS variable. Remember to make distclean and then call qmake again to get a clean build.

Since the main.cpp file contains Q_OBJECT macro, you'll need to generate main.moc file and #include "main.moc" it at the end of the source file.
Actually, qmake should handle this itself, but you need to re-run qmake for your project after adding the new #include line and then re-build.

Related

How to create files with root privileges using C++/Qt and PolKit-Qt-1

I apologize for the somewhat lengthy discussion. Also, this is my first submission to StackOverflow, so please forgive my unfamiliarity.
I usually use C++/Qt Widget or C++/QML with Linux. This time, I need to create or write files with root privileges, and I am using the following URL (PolKit-Qt-1) to create and test my own C++/Qt Widget software.
https://api.kde.org/polkit-qt-1/html/
I am using polkit-qt-gui-1 to create software (C++/Qt) to create and write files with root privileges when a button is pressed.
However, a permission error occurs because the file cannot be created or written as root, but has been created or written as the executing user.
Perhaps there is a mistake in some configuration file, or there is a missing or incorrect part of the source code.
I want to create or write a file with root privileges when a button is pressed. How do I create or write files with root privileges using C++/Qt and PolKit-Qt-1?
Thank you for your cooperation.
My own source code is shown below. The action file for polkit-1 is also shown below.
main.cpp:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
PolkitQt1::Gui::ActionButton *bt = new PolkitQt1::Gui::ActionButton(ui->pushButton, "org.qt.policykit.examples.write", this);
bt->setText("Run with administrative privileges");
bt->setVisible(true, PolkitQt1::Gui::Action::No | PolkitQt1::Gui::Action::Auth | PolkitQt1::Gui::Action::Yes);
bt->setEnabled(true, PolkitQt1::Gui::Action::No | PolkitQt1::Gui::Action::Auth | PolkitQt1::Gui::Action::Yes);
connect(bt, SIGNAL(triggered(bool)), this, SLOT(activateAction()));
connect(bt, SIGNAL(clicked(QAbstractButton*,bool)), bt, SLOT(activate()));
connect(bt, SIGNAL(authorized()), this, SLOT(onBtnClicked()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::activateAction()
{
PolkitQt1::Gui::Action *action = qobject_cast<PolkitQt1::Gui::Action *>(sender());
action->activate();
}
void MainWindow::onBtnClicked()
{
PolkitQt1::Gui::Action *action = qobject_cast<PolkitQt1::Gui::Action *>(sender());
qDebug() << "pretending to be the mechanism for action:" << action->actionId();
PolkitQt1::UnixProcessSubject subject(static_cast<uint>(QCoreApplication::applicationPid()));
PolkitQt1::Authority::Result result = PolkitQt1::Authority::instance()->checkAuthorizationSync(action->actionId(), subject, PolkitQt1::Authority::AllowUserInteraction);
if (result == PolkitQt1::Authority::Yes)
{
// Write /opt/sample.txt file with root privilege.
writeTextFile("/opt/sample.txt", "foo bar");
}
else
{
return;
}
return;
}
void MainWindow::writeTextFile(QString FileName, QString strOutputData)
{
QFileInfo FileInfo(FileName);
QFile File(FileName);
if(!File.open(QIODevice::WriteOnly))
{
QString strErrMsg = "File(" + FileInfo.fileName() + ") Open Error: " + File.errorString();
qDebug() << strErrMsg;
return;
}
QTextStream OutStream(&File);
OutStream << strOutputData;
File.close();
return;
}
mainwindow.h:
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtWidgets>
#include <QDBusContext>
#include <QDBusMessage>
#include <QDBusConnection>
#include <polkit-qt5-1/polkitqt1-gui-action.h>
#include <polkit-qt5-1/polkitqt1-gui-actionbutton.h>
#include <polkit-qt5-1/polkitqt1-gui-actionbuttons.h>
#include <polkit-qt5-1/polkitqt1-authority.h>
#include <dbus/dbus.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow, protected QDBusContext
{
Q_OBJECT
private:
void writeTextFile(QString FileName, QString strOutputData);
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
private Q_SLOTS:
void activateAction();
void onBtnClicked();
};
#endif // MAINWINDOW_H
/usr/share/polkit-1/actions/org.qt.policykit.examples.policy:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE policyconfig PUBLIC '-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN' 'http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd'>
<policyconfig>
<vendor>KDE</vendor>
<vendor_url>http://www.kde.org</vendor_url>
<action id="org.qt.policykit.examples.write">
<description>Write</description>
<message>Prevents PolKit-Qt-1 example from writing</message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
</action>
</policyconfig>
Sorry for the long wait.
After much trial and error, the following source code allows the program to run with administrative privilege (root) only when a specific button is pressed.
Please forgive the somewhat lengthy post.
Main executable
Main executable is GUI software that sends D-Bus messages by pressing a button.
main.cpp:
main.cpp has the same source code as above.
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::onAuthBtnClicked()
{
QDBusConnection bus = QDBusConnection::systemBus();
if (!bus.isConnected())
{
QMessageBox(QMessageBox::Critical, tr("D-Bus error"), tr("Cannot connect to the D-Bus session bus."), QMessageBox::Close, this).exec();
}
// this is our Special Action that after allowed will call the helper
QDBusMessage message;
message = QDBusMessage::createMethodCall("org.qt.policykit.examples", "/", "org.qt.policykit.examples", QLatin1String("write"));
// If a method in a helper file has arguments, enter the arguments.
//QList<QVariant> ArgsToHelper;
//ArgsToHelper << QVariant::fromValue("foo") << QVariant::fromValue("bar");
//message.setArguments(ArgsToHelper);
// Send a message to DBus. (Execute the helper file.)
QDBusMessage reply = QDBusConnection::systemBus().call(message);
// Receive the return value (including arguments) from the helper file.
// The methods in the helper file have two arguments, so check them.
if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().size() == 2)
{
// the reply can be anything, here we receive a bool
if (reply.arguments().at(0).toInt() == 0)
{ // If the helper file method completes successfully after successful authentication
QMessageBox(QMessageBox::NoIcon, tr("Successed"), tr("The file was written successfully."), QMessageBox::Close, this).exec();
}
else if (reply.arguments().at(0).toInt() == -1)
{ // If the helper file method fails after successful authentication
QString strErrMsg = reply.arguments().at(1).toString();
QMessageBox(QMessageBox::Critical, tr("Failed"), tr("Failed to write file.\n") + strErrMsg, QMessageBox::Close, this).exec();
}
else
{ // If the authentication is canceled
QMessageBox(QMessageBox::NoIcon, tr("Cancelled"), tr("Writing of the file was canceled."), QMessageBox::Close, this).exec();
}
}
else if (reply.type() == QDBusMessage::MethodCallMessage)
{
QMessageBox(QMessageBox::Warning, tr("Time out"), tr("Message did not receive a reply (timeout by message bus)."), QMessageBox::Close, this).exec();
}
else if (reply.type() == QDBusMessage::ErrorMessage)
{
QMessageBox(QMessageBox::Critical, tr("D-Bus error"), tr("Could not send message to D-Bus."), QMessageBox::Close, this).exec();
}
return;
}
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtWidgets>
#include <QtGui>
#include <QDBusContext>
#include <QDBusMessage>
#include <QDBusConnection>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public: // Public Functions
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private: // Private Variables
Ui::MainWindow *ui;
private Q_SLOTS:
void onAuthBtnClicked();
};
#endif // MAINWINDOW_H
Helper executable
Helper executable is software that receives messages from D-Bus and creates files with root privileges.
main.cpp:
#include <QCoreApplication>
#include "SampleHelper.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
SampleHelper sample(argc, argv);
return a.exec();
}
SampleHelper.cpp:
#include <QTimer>
#include <QFile>
#include <QTextStream>
#include <QDateTime>
#include "SampleHelper.h"
#include "SampleAdaptor.h"
#define MINUTE 30000
SampleHelper::SampleHelper(int &argc, char **argv) : QCoreApplication(argc, argv)
{
(void) new SampleAdaptor(this);
// Register the DBus service
if (!QDBusConnection::systemBus().registerService("org.qt.policykit.examples"))
{
QTextStream ErrStream(stderr);
ErrStream << QDBusConnection::systemBus().lastError().message();
QTimer::singleShot(0, this, SLOT(quit()));
return;
}
if (!QDBusConnection::systemBus().registerObject("/", this))
{
QTextStream ErrStream(stderr);
ErrStream << "unable to register service interface to dbus";
QTimer::singleShot(0, this, SLOT(quit()));
return;
}
// Normally you will set a timeout so your application can
// free some resources of the poor client machine ;)
QTimer::singleShot(MINUTE, this, SLOT(quit()));
}
SampleHelper::~SampleHelper()
{
}
int SampleHelper::write(QString &strErrMsg)
{
// message().service() is the service name of the caller
// We can check if the caller is authorized to the following action
PolkitQt1::Authority::Result result;
PolkitQt1::SystemBusNameSubject subject(message().service());
result = PolkitQt1::Authority::instance()->checkAuthorizationSync("org.qt.policykit.examples.write", subject , PolkitQt1::Authority::AllowUserInteraction);
if (result == PolkitQt1::Authority::Yes)
{ // Caller is authorized so we can perform the action
return writeValue(strErrMsg);
}
else
{ // Caller is not authorized so the action can't be performed
return 1;
}
}
int SampleHelper::writeValue(QString &strErrMsg)
{
// This action must be authorized first. It will set the implicit
// authorization for the Shout action by editing the .policy file
try
{
QFileInfo FileInfo("/opt/sample.txt");
QFile File("/opt/sample.txt");
if(!File.open(QIODevice::WriteOnly))
{
strErrMsg = "File(" + FileInfo.fileName() + ") Open Error: " + File.errorString();
return -1;
}
QDateTime current_date_time =QDateTime::currentDateTime();
QString current_date = current_date_time.toString("yyyy.MM.dd hh:mm:ss.zzz ddd");
QTextStream OutStream(&File);
OutStream << current_date;
File.close();
}
catch (QException &err)
{
strErrMsg = err.what();
}
return 0;
}
SampleHelper.h:
#ifndef SAMPLE_HELPER_H
#define SAMPLE_HELPER_H
#include <QDBusConnection>
#include <QDBusContext>
#include <QDBusMessage>
#include <QCoreApplication>
#include <polkit-qt5-1/polkitqt1-authority.h>
class SampleHelper : public QCoreApplication, protected QDBusContext
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.qt.policykit.examples")
private:
int writeValue(QString &strErrMsg);
public:
SampleHelper(int &argc, char **argv);
~SampleHelper() override;
public Q_SLOTS:
int write(QString &strErrMsg);
};
#endif
Execute the qdbusxml2cpp command (using the D-Bus interface file at this time) to generate the adapter source code file and header files for the helper.
qdbusxml2cpp -a SampleAdaptor -c SampleAdaptor -i SampleHelper.h -l SampleHelper org.qt.policykit.examples.xml
In this example, SampleAdaptor.cpp and SampleAdaptor.h are generated.
Add this file to the helper executable's project.
If this is done automatically :
Qt .pro file, the following commands were written.
system(qdbusxml2cpp -a SampleAdaptor -c SampleAdaptor -i SampleHelper.h -l SampleHelper org.qt.policykit.examples.xml)
CMake file, the following commands were written.
qt_add_dbus_adaptor(
SampleAdaptor_SRC
org.qt.policykit.examples.xml
SampleHelper.h
SampleHelper
SampleAdaptor
SampleAdaptor
)
Create Polkit policy file
/usr/share/polkit-1/actions/org.qt.policykit.examples.policy:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE policyconfig PUBLIC '-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN' 'http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd'>
<policyconfig>
<vendor>presire</vendor>
<vendor_url></vendor_url>
<action id="org.qt.policykit.examples.write">
<description>Write</description>
<message>Prevents PolKit-Qt-1 example from writing</message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
</action>
</policyconfig>
Create D-Bus configuration files
/usr/share/dbus-1/interfaces/org.qt.policykit.examples.xml:
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.qt.policykit.examples">
<method name="write" >
<!-- OUT: whether the user gained the authorization -->
<arg direction="out" type="i" name="code" />
<arg direction="out" type="s" name="msg" />
</method>
</interface>
</node>
/usr/share/dbus-1/system-services/org.qt.policykit.examples.service:
[D-BUS Service]
Name=org.qt.policykit.examples
Exec=/<Path>/<to>/<Helper executable file>
User=root
/etc/dbus-1/system-local.conf:
or
/etc/dbus-1/system.d/org.qt.policykit.examples.conf:
or
/usr/share/dbus-1/system.d/org.qt.policykit.examples.conf:
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<!-- This configuration file specifies the required security policies
for the PolicyKit examples to work. -->
<!-- Only user root can own the PackageKit service -->
<policy user="root">
<allow own="org.qt.policykit.examples"/>
</policy>
<!-- Allow anyone to call into the service - we'll reject callers using PolicyKit -->
<policy context="default">
<allow send_destination="org.qt.policykit.examples"/>
</policy>
</busconfig>

QT c++ multiple definition and first defined here error

I added a part in the main.cpp file that asks for a password before the window opens. It gets what it needs from the help.h and cnstnt.h files. Then I created a dialog named settings and tried to change the password here. It was working fine in my previous test project, but when I used the same things in this project, I encountered a first defined here error. I checked, I did run qmake and rebuild but nothing changed. How can I fix this problem? I'm new to C++ and QT.
here is my codes
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QMessageBox>
#include "cnstnt.h"
#include "help.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyle("fusion");
a.setQuitOnLastWindowClosed(false);
MainWindow w;
QString login = QInputDialog::getText(NULL, "Login","username",QLineEdit::Normal);
if (login == cnstnt::username)
{
QString getPassword = QInputDialog::getText(NULL, "Login","password",QLineEdit::Password);
QString hashpassword = hlpr::hashPassword(getPassword.toUtf8());
if(hashpassword == hlpr::getTxtPassword()){
w.show();
}else{
QMessageBox::warning(nullptr, "error!", "wrong password!");
}
}
else
{
QMessageBox::warning(nullptr, "error!", "wrong username!");
}
return a.exec();
}
cnstnt.h
#ifndef CNSTNT_H
#define CNSTNT_H
#include <QtWidgets>
namespace cnstnt {
QString TEXT_DIR = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/test/password.txt";
QString username = "admin";
}
#endif // CNSTNT_H
help.h
#ifndef HELP_H
#define HELP_H
#include <QCryptographicHash>
#include "cnstnt.h"
namespace hlpr {
// login actions
QString hashPassword(QByteArray str){
QByteArray step1 = QCryptographicHash::hash((str),QCryptographicHash::Md5).toHex();
QString lastHash = QString(QCryptographicHash::hash((step1),QCryptographicHash::Sha512).toHex());
return lastHash;
}
QString getTxtPassword(){
QString currentPassword;
QFile file(cnstnt::TEXT_DIR);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)){
QTextStream in(&file);
currentPassword = in.readLine();
file.close();
}
return currentPassword;
}
bool setTxtPassword(QString newPass){
QFile file(cnstnt::TEXT_DIR);
if(file.open(QIODevice::WriteOnly | QIODevice::Truncate)){
QTextStream stream(&file);
QByteArray newPassType = newPass.toUtf8();
stream << hashPassword(newPassType);
file.close();
return true;
}
return false;
}
}
#endif // HELP_H
settingdialog.h
#ifndef SETTINGDIALOG_H
#define SETTINGDIALOG_H
#include <QDialog>
#include <QMessageBox>
#include "help.h"
namespace Ui {
class settingDialog;
}
class settingDialog : public QDialog
{
Q_OBJECT
public:
explicit settingDialog(QWidget *parent = nullptr);
~settingDialog();
private slots:
void on_pushButton_8_clicked();
private:
Ui::settingDialog *ui;
};
#endif // SETTINGDIALOG_H
settingdialog.cpp
#include "settingdialog.h"
#include "ui_settingdialog.h"
settingDialog::settingDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::settingDialog)
{
ui->setupUi(this);
}
settingDialog::~settingDialog()
{
delete ui;
}
void settingDialog::on_pushButton_8_clicked()
{
QString TEXT_DIR = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/test/password.txt";
QString savedPassword = hlpr::getTxtPassword();
QString curPassword = ui->oldPassBox->text();
QString newPass = ui->newPassBox->text();
QString confirmPass = ui->confirmPass->text();
QByteArray curHash = curPassword.toUtf8();
if(newPass != confirmPass) {
QMessageBox::information(this, "Bilgi", "Yeni şifreniz ile tekrarı eşleşmiyor!");
}else if(newPass == curPassword){
QMessageBox::information(this, "Bilgi", "Mevcut şifreniz ile yeni şifreniz ile aynı olamaz!");
}else if(savedPassword != hlpr::hashPassword(curHash)) {
QMessageBox::information(this, "Bilgi", "Mevcut şifreniz hatalı!");
}else{
bool status = hlpr::setTxtPassword(newPass);
if(status){
ui->oldPassBox->clear();
ui->newPassBox->clear();
ui->confirmPass->clear();
QMessageBox::information(this, "Başarılı", "Şifreniz başarıyla güncellendi.");
}else{
QMessageBox::warning(this, "Hata!", "Şifreniz güncellenirken hata oluştu!");
}
}
}
errors
X:\DataLoggerQT\QtSerialMonitor-master\src\help.h:11: error:
multiple definition of hlpr::passwordHash(QByteArray)' debug/mainwindow.o: In function ZSt19__iterator_categoryIPK7QStringENSt15iterator_traitsIT_E17iterator_categoryERKS4_':
X:\DataLoggerQT\QtSerialMonitor-master\build-QtSerialMonitor-Desktop_Qt_5_15_2_MinGW_32_bit-Debug/../src/help.h:11:
multiple definition of `hlpr::passwordHash(QByteArray)'
X:\DataLoggerQT\QtSerialMonitor-master\src\help.h:11: first defined
here
X:\DataLoggerQT\QtSerialMonitor-master\src\help.h:28: error: multiple definition of hlpr::setTxtPassword(QString)' debug/moc_mainwindow.o: In function ZN4hlpr14setTxtPasswordE7QString':
X:\DataLoggerQT\QtSerialMonitor-master\build-QtSerialMonitor-Desktop_Qt_5_15_2_MinGW_32_bit-Debug/debug/../../src/help.h:28: multiple definition of `hlpr::setTxtPassword(QString)'
You have included helper.h in two header files - settingdialog.h and main.cpp, mainwindow.h is included in main.cpp and, I suppose, includes settingdialog.h itself. Or, maybe, it's included through any other included header. So you've got multiple definition error, one per include.
To avoid such kind of errors, functions in helper.h file should be declared with extern keyword and their implementation should be moved to helper.cpp file. It would prevent you from any potential problems in future. And you should always declare functions in this way.
And at last, you do not need to include helper.h in settingdialog.h as you use it's functions in cpp. Move include to settingdialog.cpp. Keep it in mind to include files only there, where they are really used, it would minimize compilation time.

_popen() returns nothing

This is a Qt program. I am trying to run gcc command and get the result using _popen(on Windows). However, I get no output.
After debugging, I find that gcc command runs ok.
void editor::on_action_Compile_triggered()
{
QString str = "gcc \""+curFile+"\" -o \""+outputFile+"\" 2>&1"; //compile curFile
FILE *fp = _popen(str.toStdString().data(),"r");
if (!fp)
{
ui->Log->setText("Error."); //Log is a text browser
}
else
{
QString tmpStr = "";
char tmp[1024] = { 0 };
while (fgets(tmp, 1024, fp) != NULL) //read fp
tmpStr += (QString)tmp;
ui->Log->setText(tmpStr); //print to screen
}
_pclose(fp);
}
According to me, you are not having a problem. Your above code is working for me (as long as I declare a correct curfile and outputFile). You are not having an ouput because gcc has successfully compiled the file. You may want to verify if the file called outputFile has been produced. Indeed, when gcc succeeds, it does not ouput anything.
Otherwise, you might be having a problem with your signal/slot connexion which does not trigger the slot on_action_Compile_triggered(then please read on the complete code provided below)
To test it try to modify your curFile to point to an inexisting file and you will get an ouput error typical of gcc.
To check this, as for me, I created a QmainWindow with a QPushButton button (called pushbutton) and a QtextEdit (called Log). I provide my complete code below.
When I have an error (for instance the compiled file is not found. to emulate this, rename your curFile into a wrong file), I obtain this (using your code above).
When I do not have any error, I obtain nothing in the QTextEditcontrol but the outputFile executable file is produced by gcc in the directory:
Here is my code:
// QMainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void compile();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
// QMainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QObject::connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::compile);
}
MainWindow::~MainWindow()
{
QObject::disconnect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::compile);
delete ui;
}
void MainWindow::compile()
{
QString curFile("..\\..\\T0180694\\test.c");
QString outputFile("..\\..\\T0180694\\test.exe");
//copied all from your code
QString str = "gcc \""+curFile+"\" -o \""+outputFile+"\" 2>&1"; //compile curFile
FILE *fp = _popen(str.toStdString().data(),"r");
if (!fp)
{
ui->Log->setText("Error."); //Log is a text browser
}
else
{
QString tmpStr = "";
char tmp[1024] = { 0 };
while (fgets(tmp, 1024, fp) != NULL) //read fp
tmpStr += (QString)tmp;
ui->Log->setText(tmpStr); //print to screen
}
_pclose(fp);
//until here
}
//main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

{"error":"invalid_client"} from Spotify Web Api when trying to refresh token

I'm a newbie in terms both on Qt and C++ but i was trying to play a bit with a spotify web api for uni project. Unfortunately I got stuck on posting my refresh token to api to get new access token. Every time i do that, i'm getting response {"error":"invalid_client"}. I've made sure both my client id and client secret are correct. I think there is an mistake somewhere in my header but i've tried few things and it didn't do much.
Here's my code:
void MainWindow::on_pushButton_2_clicked(){
QNetworkAccessManager * manager = new QNetworkAccessManager(this);
QUrl url("https://accounts.spotify.com/api/token");
QNetworkRequest request(url);
QString header = "my_client_id:my_client_secret";
QByteArray ba;
ba.append(header);
ui->teOutput->appendPlainText(ba.toBase64());
QString full_header= "Authorization: Basic " + ba.toBase64();
//ui->teOutput->appendPlainText(full_header);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
request.setHeader(QNetworkRequest::ContentDispositionHeader, full_header);
QUrlQuery params;
params.addQueryItem("grant_type", "refresh_token");
params.addQueryItem("refresh_token", "here_is_my_refresh_token");
connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onFinish(QNetworkReply *)));
manager->post(request, params.query().toUtf8());
//ui->teOutput->appendPlainText(params.query().toUtf8());
}
void MainWindow::onFinish(QNetworkReply *rep)
{
QString data = rep->readAll();
ui->teOutput->appendPlainText(data);
}
And here's how my request should look like (as suggested i've checked that using cUrl)
curl -X "POST" -H "Authorization: Basic xxxxxxxxxxx" -d grant_type=refresh_token -d refresh_token=xxxxxxxxxxxxx https://accounts.spotify.com/api/token
The command -H "Authorization: Basic xxxxxxxxxxx" is equivalent to:
request.setRawHeader("Authorization", "Basic xxxxxxxxxxx");
So you should use instead of request.setHeader(QNetworkRequest::ContentDispositionHeader, full_header);.
Although it is not necessary to implement all the logic since the Spotify API uses OAuth2 that Qt implements in the Qt Network Authorization module.
Only the QNetworkRequest header should be modified when requesting or refreshing the token since that is not part of the Oauth2 standard.
constants.h
#ifndef CONSTANTS_H
#define CONSTANTS_H
#include <QByteArray>
#include <QUrl>
namespace Constants {
const QByteArray SPOTIFY_CLIENT_ID = "xxxxxxxx";
const QByteArray SPOTIFY_CLIENT_SECRET = "yyyyyyyy";
const QUrl SPOTIFY_AUTHORIZATION_URL = QUrl("https://accounts.spotify.com/authorize");
const QUrl SPOTIFY_ACCESSTOKEN_URL = QUrl("https://accounts.spotify.com/api/token");
}
#endif // CONSTANTS_H
networkaccessmanager.h
#ifndef NETWORKACCESSMANAGER_H
#define NETWORKACCESSMANAGER_H
#include <QNetworkAccessManager>
class NetworkAccessManager : public QNetworkAccessManager
{
public:
using QNetworkAccessManager::QNetworkAccessManager;
protected:
QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData);
};
#endif // NETWORKACCESSMANAGER_H
networkaccessmanager.cpp
#include "networkaccessmanager.h"
#include "constants.h"
#include <QtGlobal>
QNetworkReply *NetworkAccessManager::createRequest(QNetworkAccessManager::Operation op,
const QNetworkRequest &request,
QIODevice *outgoingData)
{
QNetworkRequest r(request);
if(r.url() == Constants::SPOTIFY_ACCESSTOKEN_URL)
r.setRawHeader("Authorization",
"Basic " +
QByteArray(Constants::SPOTIFY_CLIENT_ID + ":" + Constants::SPOTIFY_CLIENT_SECRET).toBase64());
return QNetworkAccessManager::createRequest(op, r, outgoingData);
}
spotifywrapper.h
#ifndef SPOTIFYWRAPPER_H
#define SPOTIFYWRAPPER_H
#include <QOAuth2AuthorizationCodeFlow>
#include <QObject>
class SpotifyWrapper : public QObject
{
Q_OBJECT
public:
explicit SpotifyWrapper(QObject *parent = nullptr);
QNetworkReply *me();
public Q_SLOTS:
void grant();
Q_SIGNALS:
void authenticated();
private:
QOAuth2AuthorizationCodeFlow oauth2;
};
#endif // SPOTIFYWRAPPER_H
spotifywrapper.cpp
#include "spotifywrapper.h"
#include "networkaccessmanager.h"
#include "constants.h"
#include <QDesktopServices>
#include <QOAuthHttpServerReplyHandler>
#include <QUrlQuery>
SpotifyWrapper::SpotifyWrapper(QObject *parent) : QObject(parent)
{
QOAuthHttpServerReplyHandler * replyHandler = new QOAuthHttpServerReplyHandler(1337, this);
replyHandler->setCallbackPath("callback");
oauth2.setNetworkAccessManager(new NetworkAccessManager(this));
oauth2.setReplyHandler(replyHandler);
oauth2.setAuthorizationUrl(Constants::SPOTIFY_AUTHORIZATION_URL);
oauth2.setAccessTokenUrl(Constants::SPOTIFY_ACCESSTOKEN_URL);
oauth2.setClientIdentifier(Constants::SPOTIFY_CLIENT_ID);
oauth2.setScope("user-read-private user-read-email");
oauth2.setState("34fFs29kd09");
connect(&oauth2, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser,
&QDesktopServices::openUrl);
connect(&oauth2, &QOAuth2AuthorizationCodeFlow::statusChanged, [=](
QAbstractOAuth::Status status) {
if (status == QAbstractOAuth::Status::Granted){
emit authenticated();
}
});
}
void SpotifyWrapper::grant()
{
oauth2.grant();
}
QNetworkReply *SpotifyWrapper::me()
{
return oauth2.get(QUrl("https://api.spotify.com/v1/me"));
}
main.cpp
#include "spotifywrapper.h"
#include <QNetworkReply>
#include <QGuiApplication>
#include <QTimer>
int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);
SpotifyWrapper wrapper;
wrapper.grant();
QObject::connect(&wrapper, &SpotifyWrapper::authenticated, [&wrapper](){
qDebug() << "authenticated";
QNetworkReply *reply = wrapper.me();
QObject::connect(reply, &QNetworkReply::finished, [=]() {
reply->deleteLater();
if (reply->error() != QNetworkReply::NoError) {
qDebug() << reply->errorString();
return;
}
qDebug() << reply->readAll();
QTimer::singleShot(1000, &QCoreApplication::quit);
});
});
return a.exec();
}
You must also set as Redirect URIs in the SETTINGS of your application to "http://127.0.0.1:1337/callback":
The full example can be found here

Qt QNetworkAccessManager always return empty data and the status code is 0

I met a strange problem and I have searched for several hours but cannot find solution.
I am using Qt to write a Windows desktop application and I want to download a file from the Internet so I use QNetworkAccessManager. Following is my test code, which is in the MainWindow's constructor:
QNetworkRequest request;
request.setUrl(QUrl("www.example.org"));
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
if(manager->networkAccessible() == QNetworkAccessManager::Accessible){
qDebug() << "Network accessible";
}
else{
qDebug() << "Network is not accessible";
}
manager->get(request);
connect(manager, manager->finished, this, connFinished);
And next is connFinished function:
void MainWindow::connFinished(QNetworkReply *r){
int statusCode = r->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug() << statusCode;
}
After running the code, the output is:
Network accessible
0
I'm sure that the www.example.org can be accessed in my machine and there is no redirection. The HTTP status code is 0 even my PC has disconnected from the Internet. The problem still happens in a new project so it's not only this project's problem.
My Qt version: Qt 5.5.1 (MSVC 2013, 32 bit)
Compiler: gcc version 5.1.0 (tdm-1)
Is there anyone knows why this happened? Thanks!
Project files and code:
test.pro
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = test
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QUrl>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void connFinished(QNetworkReply *r);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QNetworkRequest request;
request.setUrl(QUrl("www.example.org"));
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
if(manager->networkAccessible() == QNetworkAccessManager::Accessible){
qDebug() << "Network accessible";
}
else{
qDebug() << "Network is not accessible";
}
manager->get(request);
connect(manager, manager->finished, this, connFinished);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::connFinished(QNetworkReply *r){
int statusCode = r->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug() << statusCode;
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Before call QNetworkAccessManager::get() function you have to connects it signals to slot.
QNetworkRequest request;
request.setUrl(QUrl("www.example.org"));
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),this,SLOT(connFinished(QNetworkReply*)));
manager->get(request);
Okay, I have found where the problem is. I have to use http://www.exmaple.org rather than www.example.org, otherwise the QNAM will report a ProtocolUnknownError error. I assumed that the QNAM will guess the protocol type. But sadly it won't.
If using https protocol in your URL, you should add the following dll files beside your executable file.
libeay32.dll
ssleay32.dll