diff options
author | Nils Achtergarde <[email protected]> | 2018-01-04 21:39:25 +0000 |
---|---|---|
committer | Nils Achtergarde <[email protected]> | 2018-01-04 21:39:25 +0000 |
commit | b36dc4d79f446ae69aeb85137663a4e0ca23eba2 (patch) | |
tree | 23d0ae5e94e874064143735c249a2ad2cb95ad16 /src | |
parent | added .gitignore with mocfiles-dir and objectfiles-dir (diff) | |
download | gpg4usb-b36dc4d79f446ae69aeb85137663a4e0ca23eba2.tar.gz gpg4usb-b36dc4d79f446ae69aeb85137663a4e0ca23eba2.zip |
put *.h and *.cpp to src-subdirectory
Diffstat (limited to 'src')
51 files changed, 9794 insertions, 0 deletions
diff --git a/src/aboutdialog.cpp b/src/aboutdialog.cpp new file mode 100644 index 0000000..3362342 --- /dev/null +++ b/src/aboutdialog.cpp @@ -0,0 +1,92 @@ +/* + * aboutdialog.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "aboutdialog.h" + +AboutDialog::AboutDialog(QWidget *parent) + : QDialog(parent) +{ + this->setWindowTitle(tr("About ")+ qApp->applicationName()); + + QTabWidget *tabWidget = new QTabWidget; + InfoTab *infoTab = new InfoTab; + TranslatorsTab *translatorsTab = new TranslatorsTab; + + tabWidget->addTab(infoTab, tr("General")); + tabWidget->addTab(translatorsTab, tr("Translators")); + + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(close())); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(tabWidget); + mainLayout->addWidget(buttonBox); + setLayout(mainLayout); + + this->exec(); +} + +InfoTab::InfoTab(QWidget *parent) + : QWidget(parent) +{ + QPixmap *pixmap = new QPixmap(":gpg4usb-logo.png"); + QString *text = new QString("<center><h2>" + qApp->applicationName() + " " + + qApp->applicationVersion() + "</h2></center>" + + tr("<center>This application allows simple encryption <br>" + "and decryption of text messages or files.<br>" + "It's licensed under the GPL v3<br><br>" + "<b>Developer:</b><br>" + "Bene, Heimer, Juergen, Nils, Ubbo<br><br>" + "If you have any questions or suggestions have a look<br/>" + "at our <a href=\"http://gpg4usb.cpunk.de/contact.php\">" + "contact page</a> or send a mail to our<br/> mailing list at" + " <a href=\"mailto:[email protected]\">[email protected]</a>.") + tr("<br><br> Built with Qt ") + qVersion() + + tr(" and GPGME ") + GpgME::GpgContext::getGpgmeVersion() +"</center>"); + + QGridLayout *layout = new QGridLayout(); + QLabel *pixmapLabel = new QLabel(); + pixmapLabel->setPixmap(*pixmap); + layout->addWidget(pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter); + QLabel *aboutLabel = new QLabel(); + aboutLabel->setText(*text); + aboutLabel->setOpenExternalLinks(true); + layout->addWidget(aboutLabel, 1, 0, 1, -1); + layout->addItem(new QSpacerItem(20, 10, QSizePolicy::Minimum, + QSizePolicy::Fixed), 2, 1, 1, 1); + + setLayout(layout); +} + +TranslatorsTab::TranslatorsTab(QWidget *parent) + : QWidget(parent) +{ + QFile translatorsFile; + translatorsFile.setFileName(qApp->applicationDirPath()+"/TRANSLATORS"); + translatorsFile.open(QIODevice::ReadOnly); + QByteArray inBuffer = translatorsFile.readAll(); + + QLabel *label = new QLabel(inBuffer); + QVBoxLayout *mainLayout = new QVBoxLayout(this); + mainLayout->addWidget(label); + + setLayout(mainLayout); +} + diff --git a/src/aboutdialog.h b/src/aboutdialog.h new file mode 100644 index 0000000..295ee6f --- /dev/null +++ b/src/aboutdialog.h @@ -0,0 +1,73 @@ +/* + * aboutdialog.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __ABOUTDIALOG_H__ +#define __ABOUTDIALOG_H__ + +#include <QWidget> +#include <QtGui> + +#include "gpgcontext.h" + +QT_BEGIN_NAMESPACE +class QVBoxLayout; +class QLabel; +class QTabWidget; +QT_END_NAMESPACE + +/** + * @brief Class containing the main tab of about dialog + * + */ +class InfoTab : public QWidget + { + Q_OBJECT + + public: + InfoTab(QWidget *parent = 0); + }; + +/** + * @brief Class containing the translator tab of about dialog + * + */ +class TranslatorsTab : public QWidget + { + Q_OBJECT + + public: + TranslatorsTab(QWidget *parent = 0); + }; + + /** + * @brief Class for handling the about dialog + * + */ +class AboutDialog : public QDialog +{ + Q_OBJECT + +public: + AboutDialog(QWidget *parent = 0); +}; + +#endif // __ABOUTDIALOG_H__ + diff --git a/src/attachments.cpp b/src/attachments.cpp new file mode 100644 index 0000000..1110464 --- /dev/null +++ b/src/attachments.cpp @@ -0,0 +1,183 @@ +/* + * attachments.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +/* TODO: + * - check content encoding (base64 / quoted-printable) and apply appropriate opperation (maybe already in mime.cpp) + * - check memory usage, use less copy operations / more references + * - possibility to clear attachment-view , e.g. with decryption or encrypting a new message + * - save all: like in thunderbird, one folder, all files go there + */ + +/* + * - save, delete (clear) all + * - each line save & clear button + * - attached files to view-menu + * - also an open button, whichs should save file to tmp-folder, and open with correct app (via QDesktopServices) + */ + + +#include "attachments.h" + +Attachments::Attachments(QWidget *parent) + : QWidget(parent) +{ + table = new AttachmentTableModel(this); + + tableView = new QTableView; + tableView->setModel(table); + tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + // only one entry should be selected at time + tableView->setSelectionMode(QAbstractItemView::SingleSelection); + tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); + tableView->setFocusPolicy(Qt::NoFocus); + tableView->setAlternatingRowColors(true); + tableView->verticalHeader()->hide(); + tableView->setShowGrid(false); + tableView->setColumnWidth(0, 300); + tableView->horizontalHeader()->setStretchLastSection(true); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(tableView); + layout->setContentsMargins(0,0,0,0); + setLayout(layout); + createActions(); + +} + +void Attachments::contextMenuEvent(QContextMenuEvent *event) +{ + QMenu menu(this); + menu.addAction(saveFileAct); + // enable open with only if allowed by user + if(settings.value("mime/openAttachment").toBool()) + menu.addAction(openFileAct); + + menu.exec(event->globalPos()); +} + +void Attachments::createActions() +{ + saveFileAct = new QAction(tr("Save File"), this); + saveFileAct->setToolTip(tr("Save this file")); + saveFileAct->setIcon(QIcon(":filesave.png")); + connect(saveFileAct, SIGNAL(triggered()), this, SLOT(slotSaveFile())); + + openFileAct = new QAction(tr("Open File"), this); + openFileAct->setToolTip(tr("Open this file")); + openFileAct->setIcon(QIcon(":fileopen.png")); + connect(openFileAct, SIGNAL(triggered()), this, SLOT(slotOpenFile())); + +} + +void Attachments::slotSaveFile() +{ + + QModelIndexList indexes = tableView->selectionModel()->selection().indexes(); + + if (indexes.size() < 1) { + return; + } + + // only singe-selection possible now: TODO: foreach + MimePart mp = table->getMimePart(indexes.at(0).row()); + QString filename = mp.header.getParam("Content-Type", "name"); + // TODO: find out why filename is quoted + filename.chop(1); + filename.remove(0, 1); + // TODO: check if really base64 + saveByteArrayToFile(QByteArray::fromBase64(mp.body), filename); + +} + +void Attachments::saveByteArrayToFile(QByteArray outBuffer, QString filename) +{ + + //QString path=""; + QString path = filename; + QString outfileName = QFileDialog::getSaveFileName(this, tr("Save File"), path); + + if (outfileName.isEmpty()) return; + + QFile outfile(outfileName); + if (!outfile.open(QFile::WriteOnly)) { + QMessageBox::warning(this, tr("File"), + tr("Cannot write file %1:\n%2.") + .arg(outfileName) + .arg(outfile.errorString())); + return; + } + + QDataStream out(&outfile); + out.writeRawData(outBuffer.data(), outBuffer.length()); + outfile.close(); +} + +/** + * WIP: TODO: + * - create attachments dir if not existing + * - ask for cleanup of dir on exit + * - remove code-duplication with saveByteArrayToFile + */ +void Attachments::slotOpenFile() { + + // TODO: make attachmentdir constant or configurable + QString attachmentDir = qApp->applicationDirPath() + "/attachments/"; + //QDir p = QDir(qApp->applicationDirPath() + "/attachments/"); + if(!QDir(attachmentDir).exists()) { + QDir().mkpath(attachmentDir); + } + + QModelIndexList indexes = tableView->selectionModel()->selection().indexes(); + MimePart mp = table->getMimePart(indexes.at(0).row()); + +// qDebug() << "mime: " << mp.header.getValue("Content-Type"); + + QString filename = mp.header.getParam("Content-Type", "name"); + // TODO: find out why filename is quoted +// qDebug() << "file: " << filename; + filename.chop(1); + filename.remove(0, 1); + filename.prepend(attachmentDir); + + // qDebug() << "file: " << filename; + QByteArray outBuffer = QByteArray::fromBase64(mp.body); + + + QFile outfile(filename); + if (!outfile.open(QFile::WriteOnly)) { + QMessageBox::warning(this, tr("File"), + tr("Cannot write file %1:\n%2.") + .arg(filename) + .arg(outfile.errorString())); + return; + } + + QDataStream out(&outfile); + out.writeRawData(outBuffer.data(), outBuffer.length()); + outfile.close(); + QDesktopServices::openUrl(QUrl("file://"+filename, QUrl::TolerantMode)); +} + +void Attachments::addMimePart(MimePart *mp) +{ + table->add(*mp); +} + diff --git a/src/attachments.h b/src/attachments.h new file mode 100644 index 0000000..5d72d9e --- /dev/null +++ b/src/attachments.h @@ -0,0 +1,68 @@ +/* + * attachments.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __ATTACHMENTS_H__ +#define __ATTACHMENTS_H__ + +#include "attachmenttablemodel.h" +#include <QtGui> +#include <QWidget> + +QT_BEGIN_NAMESPACE +class QTableView; +class QHeaderView; +class QVBoxLayout; +class QMenu; +class QMessageBox; +class QContextMenuEvent; +class QFileDialog; +class QUrl; +class QDesktopServices; +class QSettings; +class QApplication; +QT_END_NAMESPACE + +class Attachments : public QWidget +{ + Q_OBJECT + +public slots: + void slotSaveFile(); + void slotOpenFile(); + +public: + Attachments(QWidget *parent = 0); + void addMimePart(MimePart *mp); + +private: + void createActions(); + void saveByteArrayToFile(QByteArray outBuffer, QString filename); + QAction *saveFileAct; + QAction *openFileAct; + AttachmentTableModel *table; + QTableView *tableView; + QSettings settings; + +protected: + void contextMenuEvent(QContextMenuEvent *event); +}; + +#endif // __ATTACHMENTS_H__ diff --git a/src/attachmenttablemodel.cpp b/src/attachmenttablemodel.cpp new file mode 100644 index 0000000..f0eadfc --- /dev/null +++ b/src/attachmenttablemodel.cpp @@ -0,0 +1,138 @@ +/* + * attachmenttablemodel.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "attachmenttablemodel.h" + +/** compare with http://doc.qt.nokia.com/4.6/itemviews-addressbook.html + */ + +AttachmentTableModel::AttachmentTableModel(QObject *parent) : + QAbstractTableModel(parent) +{ +} + +AttachmentTableModel::AttachmentTableModel(QList<MimePart> mimeparts, QObject *parent) : + QAbstractTableModel(parent) +{ + listOfMimeparts = mimeparts; +} + + +void AttachmentTableModel::add(MimePart mp) +{ + listOfMimeparts.append(mp); + //QModelIndex changedIndex0 = createIndex(listOfMimeparts.size(), 0); + //QModelIndex changedIndex1 = createIndex(listOfMimeparts.size(), 1); + + //emit(dataChanged(changedIndex0, changedIndex1)); + // TODO: check the data-changed signal + reset(); +} + +MimePart AttachmentTableModel::getSelectedMimePart(QModelIndex index) +{ + return listOfMimeparts.at(index.row()); +} + +MimePart AttachmentTableModel::getMimePart(int index) +{ + return listOfMimeparts.at(index); +} + +/*QList<MimePart> AttachmentTableModel::getSelectedMimeParts(QModelIndexList indexes){ + + foreach(QModelIndex index, indexes) { + qDebug() << "ir: "<< index.row(); + } + +}*/ + +int AttachmentTableModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return listOfMimeparts.size(); +} + +int AttachmentTableModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return 2; +} + +QVariant AttachmentTableModel::data(const QModelIndex &index, int role) const +{ + + //qDebug() << "called, index: " << index.column(); + + if (!index.isValid()) + return QVariant(); + + if (index.row() >= listOfMimeparts.size() || index.row() < 0) + return QVariant(); + + if (role == Qt::DisplayRole) { + MimePart mp = listOfMimeparts.at(index.row()); + + if (index.column() == 0) + return mp.header.getParam("Content-Type", "name"); + if (index.column() == 1) + return mp.header.getValue("Content-Type"); + + } + + // set icon + // TODO more generic matching, e.g. for audio + if (role == Qt::DecorationRole && index.column() == 0) { + MimePart mp = listOfMimeparts.at(index.row()); + QString icon; + if (mp.header.getValue("Content-Type").startsWith("image")) { + icon = ":mimetypes/image-x-generic.png"; + } else { + icon = mp.header.getValue("Content-Type").replace("/", "-"); + icon = ":mimetypes/" + icon + ".png"; + } + if (!QFile::exists(icon)) icon = ":mimetypes/unknown.png"; + return QIcon(icon); + } + + return QVariant(); +} + +QVariant AttachmentTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + //qDebug() << "called, section: " << section; + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) { + switch (section) { + case 0: + return tr("Filename"); + + case 1: + return tr("Contenttype"); + + default: + return QVariant(); + } + } + return QVariant(); +} diff --git a/src/attachmenttablemodel.h b/src/attachmenttablemodel.h new file mode 100644 index 0000000..bb019de --- /dev/null +++ b/src/attachmenttablemodel.h @@ -0,0 +1,56 @@ +/* + * attachmenttablemodel.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __ATTACHMENTTABLEMODEL_H__ +#define __ATTACHMENTTABLEMODEL_H__ + +#include "mime.h" +#include <QIcon> +#include <QFile> +#include <QAbstractTableModel> + +QT_BEGIN_NAMESPACE +class QStandardItem; +QT_END_NAMESPACE + +class AttachmentTableModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + AttachmentTableModel(QObject *parent = 0); + AttachmentTableModel(QList<MimePart> mimeparts, QObject *parent = 0); + + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + + void add(MimePart mp); + MimePart getSelectedMimePart(QModelIndex index); + MimePart getMimePart(int index); + //QList<MimePart> getSelectedMimeParts(QModelIndexList indexes); + +private: + QList<MimePart> listOfMimeparts; +}; + +#endif // __ATTACHMENTTABLEMODEL_H__ diff --git a/src/editorpage.cpp b/src/editorpage.cpp new file mode 100644 index 0000000..28926a9 --- /dev/null +++ b/src/editorpage.cpp @@ -0,0 +1,108 @@ +/* + * textpage.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "editorpage.h" + +EditorPage::EditorPage(const QString &filePath, QWidget *parent) : QWidget(parent), + fullFilePath(filePath) +{ + // Set the Textedit properties + textPage = new QTextEdit(); + textPage->setAcceptRichText(false); + + // Set the layout style + mainLayout = new QVBoxLayout(); + mainLayout->setSpacing(0); + mainLayout->addWidget(textPage); + mainLayout->setContentsMargins(0,0,0,0); + setLayout(mainLayout); + + setAttribute(Qt::WA_DeleteOnClose); + textPage->setFocus(); + + //connect(textPage, SIGNAL(textChanged()), this, SLOT(formatGpgHeader())); +} + +const QString& EditorPage::getFilePath() const +{ + return fullFilePath; +} + +QTextEdit* EditorPage::getTextPage() +{ + return textPage; +} + +void EditorPage::setFilePath(const QString &filePath) +{ + fullFilePath = filePath; +} + +void EditorPage::showNotificationWidget(QWidget *widget, const char *className) +{ + widget->setProperty(className,true); + mainLayout->addWidget(widget); +} + +void EditorPage::closeNoteByClass(const char *className) +{ + QList<QWidget *> widgets = findChildren<QWidget *>(); + foreach(QWidget * widget, widgets) + { + if (widget->property(className) == true) { + widget->close(); + } + } +} + +void EditorPage::slotFormatGpgHeader() { + + QString content = textPage->toPlainText(); + + // Get positions of the gpg-headers, if they exist + int start = content.indexOf(GpgConstants::PGP_SIGNED_BEGIN); + int startSig = content.indexOf(GpgConstants::PGP_SIGNATURE_BEGIN); + int endSig = content.indexOf(GpgConstants::PGP_SIGNATURE_END); + + if(start < 0 || startSig < 0 || endSig < 0 || signMarked) { + return; + } + + signMarked = true; + + // Set the fontstyle for the header + QTextCharFormat signFormat; + signFormat.setForeground(QBrush(QColor::fromRgb(80,80,80))); + signFormat.setFontPointSize(9); + + // set font style for the signature + QTextCursor cursor(textPage->document()); + cursor.setPosition(startSig, QTextCursor::MoveAnchor); + cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, endSig); + cursor.setCharFormat(signFormat); + + // set the font style for the header + int headEnd = content.indexOf("\n\n", start); + cursor.setPosition(start, QTextCursor::MoveAnchor); + cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, headEnd); + cursor.setCharFormat(signFormat); + +} diff --git a/src/editorpage.h b/src/editorpage.h new file mode 100644 index 0000000..d5222cf --- /dev/null +++ b/src/editorpage.h @@ -0,0 +1,101 @@ +/* + * textpage.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __EDITORPAGE_H__ +#define __EDITORPAGE_H__ + +#include "gpgconstants.h" +#include <QTextEdit> +#include <QtGui> + +QT_BEGIN_NAMESPACE +class QVBoxLayout; +class QHBoxLayout; +class QString; +class QLabel; +QT_END_NAMESPACE + +/** + * @brief Class for handling a single tab of the tabwidget + * + */ +class EditorPage : public QWidget +{ + Q_OBJECT + +public: + /** + * @details Add layout and add plaintextedit + * + * @param filePath Path of the file handled in this tab + * @param parent Pointer to the parent widget + */ + EditorPage(const QString &filePath = "", QWidget *parent = 0); + + /** + * @details Get the filepath of the currently activated tab. + */ + const QString& getFilePath() const; + + /** + * @details Set filepath of currently activated tab. + * + * @param filePath The path to be set + */ + void setFilePath(const QString &filePath); + + /** + * @details Return pointer tp the textedit of the currently activated tab. + */ + QTextEdit *getTextPage(); + + /** + * @details Show additional widget at buttom of currently active tab + * + * @param widget The widget to be added + * @param className The name to handle the added widget + */ + void showNotificationWidget(QWidget *widget, const char *className); + + /** + * @details Hide all widgets with the given className + * + * @param className The classname of the widgets to hide + */ + void closeNoteByClass(const char *className); + +private: + QTextEdit *textPage; /** The textedit of the tab */ + QVBoxLayout *mainLayout; /** The layout for the tab */ + QWidget *notificationWidget; /** The notification widget shown at the buttom of the tab */ + QMenu *verifyMenu; /** The menu in the notifiaction widget */ + QString fullFilePath; /** The path to the file handled in the tab */ + QLabel *verifyLabel; /** The label of the verify-notification widget */ + bool signMarked; /** true, if the signed header is marked, false if not */ + +private slots: + /** + * @details Format the gpg header in another font-style + */ + void slotFormatGpgHeader(); +}; + +#endif // __TEXTPAGE_H__ diff --git a/src/fileencryptiondialog.cpp b/src/fileencryptiondialog.cpp new file mode 100755 index 0000000..38b7de5 --- /dev/null +++ b/src/fileencryptiondialog.cpp @@ -0,0 +1,249 @@ +/* + * fileencryptiondialog.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "fileencryptiondialog.h" + +FileEncryptionDialog::FileEncryptionDialog(GpgME::GpgContext *ctx, QStringList keyList, DialogAction action, QWidget *parent) + : QDialog(parent) + +{ + mAction = action; + mCtx = ctx; + if (mAction == Decrypt) { + setWindowTitle(tr("Decrypt File")); + resize(500, 200); + } else if (mAction == Encrypt) { + setWindowTitle(tr("Encrypt File")); + resize(500, 400); + } else if (mAction == Sign) { + setWindowTitle(tr("Sign File")); + resize(500, 400); + } else if (mAction == Verify) { + setWindowTitle(tr("Verify File")); + resize(500, 200); + } + + setModal(true); + + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotExecuteAction())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + QGroupBox *groupBox1 = new QGroupBox(tr("File")); + + /* Setup input & Outputfileselection*/ + inputFileEdit = new QLineEdit(); + QPushButton *fb1 = new QPushButton("..."); + connect(fb1, SIGNAL(clicked()), this, SLOT(slotSelectInputFile())); + QLabel *fl1 = new QLabel(tr("Input")); + fl1->setBuddy(inputFileEdit); + + outputFileEdit = new QLineEdit(); + QPushButton *fb2 = new QPushButton("..."); + connect(fb2, SIGNAL(clicked()), this, SLOT(slotSelectOutputFile())); + QLabel *fl2 = new QLabel(tr("Output")); + fl2->setBuddy(outputFileEdit); + + QGridLayout *gLayout = new QGridLayout(); + gLayout->addWidget(fl1, 0, 0); + gLayout->addWidget(inputFileEdit, 0, 1); + gLayout->addWidget(fb1, 0, 2); + signFileEdit = new QLineEdit(); + // verify does not need outfile, but signature file + if(mAction != Verify) { + gLayout->addWidget(fl2, 1, 0); + gLayout->addWidget(outputFileEdit, 1, 1); + gLayout->addWidget(fb2, 1, 2); + } else { + QPushButton *sfb1 = new QPushButton("..."); + connect(sfb1, SIGNAL(clicked()), this, SLOT(slotSelectSignFile())); + QLabel *sfl1 = new QLabel(tr("Signature")); + sfl1->setBuddy(signFileEdit); + + gLayout->addWidget(sfl1, 1, 0); + gLayout->addWidget(signFileEdit, 1, 1); + gLayout->addWidget(sfb1, 1, 2); + } + groupBox1->setLayout(gLayout); + + /*Setup KeyList*/ + mKeyList = new KeyList(mCtx); + mKeyList->hide(); + mKeyList->setColumnWidth(2, 150); + mKeyList->setColumnWidth(3, 150); + mKeyList->setChecked(&keyList); + + statusLabel = new QLabel(); + statusLabel->setStyleSheet("QLabel {color: red;}"); + + QVBoxLayout *vbox2 = new QVBoxLayout(); + vbox2->addWidget(groupBox1); + vbox2->addWidget(mKeyList); + vbox2->addWidget(statusLabel); + vbox2->addWidget(buttonBox); + vbox2->addStretch(0); + setLayout(vbox2); + + if(action == Encrypt || action == Sign) { + slotShowKeyList(); + } + + exec(); +} + +void FileEncryptionDialog::slotSelectInputFile() +{ + QString path = ""; + if (inputFileEdit->text().size() > 0) { + path = QFileInfo(inputFileEdit->text()).absolutePath(); + } + +// QString infileName = QFileDialog::getOpenFileName(this, tr("Open File"), path, tr("Files") + tr("All Files (*)")); + QString infileName = QFileDialog::getOpenFileName(this, tr("Open File"), path); + inputFileEdit->setText(infileName); + + // try to find a matching output-filename, if not yet done + if (infileName > 0 + && outputFileEdit->text().size() == 0 + && signFileEdit->text().size() == 0) { + if (mAction == Encrypt) { + outputFileEdit->setText(infileName + ".asc"); + } else if (mAction == Sign) { + outputFileEdit->setText(infileName + ".sig"); + } else if (mAction == Verify) { + signFileEdit->setText(infileName + ".sig"); + } else { + if (infileName.endsWith(".asc", Qt::CaseInsensitive)) { + QString ofn = infileName; + ofn.chop(4); + outputFileEdit->setText(ofn); + } else { + outputFileEdit->setText(infileName + ".out"); + } + } + } +} + +void FileEncryptionDialog::slotSelectOutputFile() +{ + QString path = ""; + if (outputFileEdit->text().size() > 0) { + path = QFileInfo(outputFileEdit->text()).absolutePath(); + } + + QString outfileName = QFileDialog::getSaveFileName(this, tr("Save File"),path, NULL ,NULL ,QFileDialog::DontConfirmOverwrite); + outputFileEdit->setText(outfileName); + +} + +void FileEncryptionDialog::slotSelectSignFile() +{ + QString path = ""; + if (signFileEdit->text().size() > 0) { + path = QFileInfo(signFileEdit->text()).absolutePath(); + } + + QString signfileName = QFileDialog::getSaveFileName(this, tr("Open File"),path, NULL ,NULL ,QFileDialog::DontConfirmOverwrite); + signFileEdit->setText(signfileName); + + if (inputFileEdit->text().size() == 0 && signfileName.endsWith(".sig", Qt::CaseInsensitive)) { + QString sfn = signfileName; + sfn.chop(4); + inputFileEdit->setText(sfn); + } + +} + +void FileEncryptionDialog::slotExecuteAction() +{ + + QFile infile; + infile.setFileName(inputFileEdit->text()); + if (!infile.open(QIODevice::ReadOnly)) { + statusLabel->setText( tr("Couldn't open file")); + inputFileEdit->setStyleSheet("QLineEdit { background: yellow }"); + return; + } + + QByteArray inBuffer = infile.readAll(); + QByteArray *outBuffer = new QByteArray(); + infile.close(); + if ( mAction == Encrypt ) { + if (! mCtx->encrypt(mKeyList->getChecked(), inBuffer, outBuffer)) return; + } + + if ( mAction == Decrypt ) { + if (! mCtx->decrypt(inBuffer, outBuffer)) return; + } + + if( mAction == Sign ) { + if(! mCtx->sign(mKeyList->getChecked(), inBuffer, outBuffer, true)) return; + } + + if( mAction == Verify ) { + QFile signfile; + signfile.setFileName(signFileEdit->text()); + if (!signfile.open(QIODevice::ReadOnly)) { + statusLabel->setText( tr("Couldn't open file")); + signFileEdit->setStyleSheet("QLineEdit { background: yellow }"); + return; + } + QByteArray signBuffer = signfile.readAll(); + new VerifyDetailsDialog(this, mCtx, mKeyList, &inBuffer, &signBuffer); + return; + } + + QFile outfile(outputFileEdit->text()); + if (outfile.exists()){ + QMessageBox::StandardButton ret; + ret = QMessageBox::warning(this, tr("File"), + tr("File exists! Do you want to overwrite it?"), + QMessageBox::Ok|QMessageBox::Cancel); + if (ret == QMessageBox::Cancel){ + return; + } + } + + if (!outfile.open(QFile::WriteOnly)) { + QMessageBox::warning(this, tr("File"), + tr("Cannot write file %1:\n%2.") + .arg(outputFileEdit->text()) + .arg(outfile.errorString())); + return; + } + + QDataStream out(&outfile); + out.writeRawData(outBuffer->data(), outBuffer->length()); + outfile.close(); + QMessageBox::information(0, "Done", "Output saved to " + outputFileEdit->text()); + + accept(); +} + +void FileEncryptionDialog::slotShowKeyList() +{ + mKeyList->show(); +} + +void FileEncryptionDialog::slotHideKeyList() +{ + mKeyList->hide(); +} diff --git a/src/fileencryptiondialog.h b/src/fileencryptiondialog.h new file mode 100755 index 0000000..af6edff --- /dev/null +++ b/src/fileencryptiondialog.h @@ -0,0 +1,118 @@ +/* + * fileencryptiondialog.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __FILEENCRYPTIONDIALOG_H__ +#define __FILEENCRYPTIONDIALOG_H__ + +#include "gpgcontext.h" +#include "keylist.h" +#include "verifydetailsdialog.h" + +QT_BEGIN_NAMESPACE +class QDialog; +class QLineEdit; +class QWidget; +class QDialogButtonBox; +class QLabel; +class QPushButton; +class QHBoxLayout; +class QVBoxLayout; +class QDebug; +class QFileDialog; +QT_END_NAMESPACE + +/** + * @brief + * + * @class FileEncryptionDialog fileencryptiondialog.h "fileencryptiondialog.h" + */ +class FileEncryptionDialog : public QDialog +{ + Q_OBJECT + +public: + + enum DialogAction { + Encrypt, + Decrypt, + Sign, + Verify + }; + + /** + * @brief + * + * @fn FileEncryptionDialog + * @param ctx + * @param keyList + * @param parent + */ + FileEncryptionDialog(GpgME::GpgContext *ctx, QStringList keyList, DialogAction action, QWidget *parent = 0); +public slots: + /** + * @details + * + * @fn selectInputFile + */ + void slotSelectInputFile(); + /** + * @brief + * + * @fn selectOutputFile + */ + void slotSelectOutputFile(); + /** + * @brief + * + * @fn selectSignFile + */ + void slotSelectSignFile(); + /** + * @brief + * + * @fn executeAction + */ + void slotExecuteAction(); + /** + * @brief + * + * @fn hideKeyList + */ + void slotHideKeyList(); + /** + * @brief + * + * @fn showKeyList + */ + void slotShowKeyList(); + +private: + QLineEdit *outputFileEdit; /**< TODO */ + QLineEdit *inputFileEdit; /**< TODO */ + QLineEdit *signFileEdit; /**< TODO */ + DialogAction mAction; /**< TODO */ + QLabel *statusLabel; /**< TODO */ +protected: + GpgME::GpgContext *mCtx; /**< TODO */ + KeyList *mKeyList; /**< TODO */ + +}; +#endif // __FILEENCRYPTIONDIALOG_H__ diff --git a/src/findwidget.cpp b/src/findwidget.cpp new file mode 100644 index 0000000..ff8de5a --- /dev/null +++ b/src/findwidget.cpp @@ -0,0 +1,135 @@ + +#include "findwidget.h" + +FindWidget::FindWidget(QWidget *parent, QTextEdit *edit) : + QWidget(parent) +{ + mTextpage = edit; + findEdit = new QLineEdit(this); + QPushButton *closeButton= new QPushButton(this->style()->standardIcon(QStyle::SP_TitleBarCloseButton),"",this); + QPushButton *nextButton= new QPushButton(QIcon(":button_next.png"), ""); + QPushButton *previousButton= new QPushButton(QIcon(":button_previous.png"), ""); + + QHBoxLayout *notificationWidgetLayout = new QHBoxLayout(this); + notificationWidgetLayout->setContentsMargins(10,0,0,0); + notificationWidgetLayout->addWidget(new QLabel(tr("Find:"))); + notificationWidgetLayout->addWidget(findEdit,2); + notificationWidgetLayout->addWidget(nextButton); + notificationWidgetLayout->addWidget(previousButton); + notificationWidgetLayout->addWidget(closeButton); + + this->setLayout(notificationWidgetLayout); + connect(findEdit,SIGNAL(textEdited(QString)),this,SLOT(slotFind())); + connect(findEdit,SIGNAL(returnPressed()),this,SLOT(slotFindNext())); + connect(nextButton,SIGNAL(clicked()),this,SLOT(slotFindNext())); + connect(previousButton,SIGNAL(clicked()),this,SLOT(slotFindPrevious())); + connect(closeButton,SIGNAL(clicked()),this,SLOT(slotClose())); + + // The timer is necessary for setting the focus + QTimer::singleShot(0, findEdit, SLOT(setFocus())); +} + +void FindWidget::setBackground() +{ + QTextCursor cursor = mTextpage->textCursor(); + // if match is found set background of QLineEdit to white, otherwise to red + QPalette bgPalette( findEdit->palette() ); + + if (!findEdit->text().isEmpty() && mTextpage->document()->find(findEdit->text()).position() < 0 ) { + bgPalette.setColor( QPalette::Base, "#ececba"); + } else { + bgPalette.setColor( QPalette::Base, Qt::white); + } + findEdit->setPalette(bgPalette); +} + +void FindWidget::slotFindNext() +{ + QTextCursor cursor = mTextpage->textCursor(); + cursor = mTextpage->document()->find(findEdit->text(), cursor, QTextDocument::FindCaseSensitively); + + // if end of document is reached, restart search from beginning + if (cursor.position() == -1) { + cursor = mTextpage->document()->find(findEdit->text(), cursor, QTextDocument::FindCaseSensitively); + } + + // cursor should not stay at -1, otherwise text is not editable + // todo: check how gedit handles this + if(cursor.position() != -1) { + mTextpage->setTextCursor(cursor); + } + this->setBackground(); +} + +void FindWidget::slotFind() +{ + QTextCursor cursor = mTextpage->textCursor(); + + if (cursor.anchor() == -1) { + cursor = mTextpage->document()->find(findEdit->text(), cursor, QTextDocument::FindCaseSensitively); + } else { + cursor = mTextpage->document()->find(findEdit->text(), cursor.anchor(), QTextDocument::FindCaseSensitively); + } + + // if end of document is reached, restart search from beginning + if (cursor.position() == -1) { + cursor = mTextpage->document()->find(findEdit->text(), cursor, QTextDocument::FindCaseSensitively); + } + + // cursor should not stay at -1, otherwise text is not editable + // todo: check how gedit handles this + if(cursor.position() != -1) { + mTextpage->setTextCursor(cursor); + } + this->setBackground(); +} + +void FindWidget::slotFindPrevious() +{ + QTextDocument::FindFlags flags; + flags |= QTextDocument::FindBackward; + flags |= QTextDocument::FindCaseSensitively; + + QTextCursor cursor = mTextpage->textCursor(); + cursor = mTextpage->document()->find(findEdit->text(), cursor, flags); + + // if begin of document is reached, restart search from end + if (cursor.position() == -1) { + cursor = mTextpage->document()->find(findEdit->text(), QTextCursor::End, flags); + } + + // cursor should not stay at -1, otherwise text is not editable + // todo: check how gedit handles this + if(cursor.position() != -1) { + mTextpage->setTextCursor(cursor); + } + this->setBackground(); +} + +void FindWidget::keyPressEvent( QKeyEvent* e ) +{ + switch ( e->key() ) + { + case Qt::Key_Escape: + this->slotClose(); + break; + case Qt::Key_F3: + if (e->modifiers() & Qt::ShiftModifier) { + this->slotFindPrevious(); + } else { + this->slotFindNext(); + } + break; + } +} + +void FindWidget::slotClose() { + QTextCursor cursor = mTextpage->textCursor(); + + if ( cursor.position() == -1) { + cursor.setPosition(0); + mTextpage->setTextCursor(cursor); + } + mTextpage->setFocus(); + close(); +} diff --git a/src/findwidget.h b/src/findwidget.h new file mode 100644 index 0000000..4e69fa6 --- /dev/null +++ b/src/findwidget.h @@ -0,0 +1,42 @@ + +#ifndef FINDWIDGET_H +#define FINDWIDGET_H + +#include "editorpage.h" + +#include <QWidget> + +/** + * @brief Class for handling the find widget shown at buttom of a textedit-page + */ +class FindWidget : public QWidget +{ + Q_OBJECT + +public: + /** + * @brief + * + * @param parent The parent widget + */ + explicit FindWidget(QWidget *parent, QTextEdit *edit); + +private: + void keyPressEvent( QKeyEvent* e ); + /** + * @details Set background of findEdit to red, if no match is found (Documents textcursor position equals -1), + * otherwise set it to white. + */ + void setBackground(); + + QTextEdit *mTextpage; /** Textedit associated to the notification */ + QLineEdit *findEdit; /** Label holding the text shown in verifyNotification */ + QTextCharFormat cursorFormat; + +private slots: + void slotFindNext(); + void slotFindPrevious(); + void slotFind(); + void slotClose(); +}; +#endif // FINDWIDGET_H diff --git a/src/gpgconstants.cpp b/src/gpgconstants.cpp new file mode 100644 index 0000000..0d3306a --- /dev/null +++ b/src/gpgconstants.cpp @@ -0,0 +1,31 @@ +/* + * gpgconstants.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "gpgconstants.h" +#include <QString> + +const char* GpgConstants::PGP_CRYPT_BEGIN = "-----BEGIN PGP MESSAGE-----"; +const char* GpgConstants::PGP_CRYPT_END = "-----END PGP MESSAGE-----"; +const char* GpgConstants::PGP_SIGNED_BEGIN = "-----BEGIN PGP SIGNED MESSAGE-----"; +const char* GpgConstants::PGP_SIGNED_END = "-----END PGP SIGNATURE-----"; +const char* GpgConstants::PGP_SIGNATURE_BEGIN = "-----BEGIN PGP SIGNATURE-----"; +const char* GpgConstants::PGP_SIGNATURE_END = "-----END PGP SIGNATURE-----"; + diff --git a/src/gpgconstants.h b/src/gpgconstants.h new file mode 100644 index 0000000..e01083c --- /dev/null +++ b/src/gpgconstants.h @@ -0,0 +1,40 @@ +/* + * gpgconstants.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef GPGCONSTANTS_H +#define GPGCONSTANTS_H + +class QString; + +const int RESTART_CODE = 1000; + +class GpgConstants +{ +public: + static const char* PGP_CRYPT_BEGIN; + static const char* PGP_CRYPT_END; + static const char* PGP_SIGNED_BEGIN; + static const char* PGP_SIGNED_END; + static const char* PGP_SIGNATURE_BEGIN; + static const char* PGP_SIGNATURE_END; +}; + +#endif // GPGCONSTANTS_H diff --git a/src/gpgcontext.cpp b/src/gpgcontext.cpp new file mode 100644 index 0000000..45e053b --- /dev/null +++ b/src/gpgcontext.cpp @@ -0,0 +1,835 @@ +/* + * gpgcontext.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "gpgcontext.h" +#include <unistd.h> /* contains read/write */ +#ifdef _WIN32 +#include <windows.h> +#endif +namespace GpgME +{ + +/** Constructor + * Set up gpgme-context, set paths to app-run path + */ +GpgContext::GpgContext() +{ + /** get application path */ + QString appPath = qApp->applicationDirPath(); + + /** The function `gpgme_check_version' must be called before any other + * function in the library, because it initializes the thread support + * subsystem in GPGME. (from the info page) */ + gpgme_check_version(NULL); + + // TODO: Set gpgme_language to config + /*QSettings settings; + qDebug() << " - " << settings.value("int/lang").toLocale().name(); + qDebug() << " - " << QLocale(settings.value("int/lang").toString()).name();*/ + + // the locale set here is used for the other setlocale calls which have NULL + // -> NULL means use default, which is configured here + setlocale(LC_ALL, ""); + + /** set locale, because tests do also */ + gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL)); + //qDebug() << "Locale set to" << LC_CTYPE << " - " << setlocale(LC_CTYPE, NULL); +#ifndef _WIN32 + gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL)); +#endif + + err = gpgme_new(&mCtx); + + checkErr(err); + /** here come the settings, instead of /usr/bin/gpg + * a executable in the same path as app is used. + * also lin/win must be checked, for calling gpg.exe if needed + */ +#ifdef _WIN32 + gpgBin = appPath + "/bin/gpg.exe"; +#else + gpgBin = appPath + "/bin/gpg"; +#endif + + QSettings settings; + QString accKeydbPath = settings.value("gpgpaths/keydbpath").toString(); + QString gpgKeys = appPath + "/keydb/"+accKeydbPath; + + if (accKeydbPath != "") { + if (!QDir(gpgKeys).exists()) { + QMessageBox::critical(0,tr("keydb path"),tr("Didn't find keydb directory. Switching to gpg4usb's default keydb directory for this session.")); + gpgKeys = appPath + "/keydb"; + } + } + + /* err = gpgme_ctx_set_engine_info(mCtx, GPGME_PROTOCOL_OpenPGP, + gpgBin.toUtf8().constData(), + gpgKeys.toUtf8().constData());*/ +#ifndef GPG4USB_NON_PORTABLE + err = gpgme_ctx_set_engine_info(mCtx, GPGME_PROTOCOL_OpenPGP, + gpgBin.toLocal8Bit().constData(), + gpgKeys.toLocal8Bit().constData()); + checkErr(err); +#endif + + gpgme_engine_info_t engineInfo; + engineInfo = gpgme_ctx_get_engine_info(mCtx); + + + while (engineInfo !=NULL ) { + qDebug() << gpgme_get_protocol_name(engineInfo->protocol); + engineInfo=engineInfo->next; + } + + /** Setting the output type must be done at the beginning */ + /** think this means ascii-armor --> ? */ + gpgme_set_armor(mCtx, 1); + /** passphrase-callback */ + gpgme_set_passphrase_cb(mCtx, passphraseCb, this); + + /** check if app is called with -d from command line */ + if (qApp->arguments().contains("-d")) { + qDebug() << "gpgme_data_t debug on"; + debug = true; + } else { + debug = false; + } + + connect(this,SIGNAL(signalKeyDBChanged()),this,SLOT(slotRefreshKeyList())); + slotRefreshKeyList(); +} + +/** Destructor + * Release gpgme-context + */ +GpgContext::~GpgContext() +{ + if (mCtx) gpgme_release(mCtx); + mCtx = 0; +} + +/** Import Key from QByteArray + * + */ +GpgImportInformation GpgContext::importKey(QByteArray inBuffer) +{ + GpgImportInformation *importInformation = new GpgImportInformation(); + err = gpgme_data_new_from_mem(&in, inBuffer.data(), inBuffer.size(), 1); + checkErr(err); + err = gpgme_op_import(mCtx, in); + gpgme_import_result_t result; + + result = gpgme_op_import_result(mCtx); + if (result->unchanged){ + importInformation->unchanged = result->unchanged; + } + if (result->considered){ + importInformation->considered = result->considered; + } + if (result->no_user_id){ + importInformation->no_user_id = result->no_user_id; + } + if (result->imported){ + importInformation->imported = result->imported; + } + if (result->imported_rsa){ + importInformation->imported_rsa = result->imported_rsa; + } + if (result->unchanged){ + importInformation->unchanged = result->unchanged; + } + if (result->new_user_ids){ + importInformation->new_user_ids = result->new_user_ids; + } + if (result->new_sub_keys){ + importInformation->new_sub_keys = result->new_sub_keys; + } + if (result->new_signatures){ + importInformation->new_signatures = result->new_signatures; + } + if (result->new_revocations){ + importInformation->new_revocations =result->new_revocations; + } + if (result->secret_read){ + importInformation->secret_read = result->secret_read; + } + if (result->secret_imported){ + importInformation->secret_imported = result->secret_imported; + } + if (result->secret_unchanged){ + importInformation->secret_unchanged = result->secret_unchanged; + } + if (result->not_imported){ + importInformation->not_imported = result->not_imported; + } + gpgme_import_status_t status = result->imports; + while (status != NULL) { + GpgImportedKey key; + key.importStatus = status->status; + key.fpr = status->fpr; + importInformation->importedKeys.append(key); + status=status->next; + } + checkErr(err); + emit signalKeyDBChanged(); + gpgme_data_release(in); + return *importInformation; +} + +/** Generate New Key with values params + * + */ +void GpgContext::generateKey(QString *params) +{ + err = gpgme_op_genkey(mCtx, params->toAscii().data(), NULL, NULL); + checkErr(err); + emit signalKeyDBChanged(); +} + +/** Export Key to QByteArray + * + */ +bool GpgContext::exportKeys(QStringList *uidList, QByteArray *outBuffer) +{ + size_t read_bytes; + gpgme_data_t out = 0; + outBuffer->resize(0); + + if (uidList->count() == 0) { + QMessageBox::critical(0, "Export Keys Error", "No Keys Selected"); + return false; + } + + for (int i = 0; i < uidList->count(); i++) { + err = gpgme_data_new(&out); + checkErr(err); + + err = gpgme_op_export(mCtx, uidList->at(i).toAscii().constData(), 0, out); + checkErr(err); + + read_bytes = gpgme_data_seek(out, 0, SEEK_END); + + err = readToBuffer(out, outBuffer); + checkErr(err); + gpgme_data_release(out); + } + return true; +} + +gpgme_key_t GpgContext::getKeyDetails(QString uid) +{ + gpgme_key_t key; + + // try secret + gpgme_get_key(mCtx, uid.toAscii().constData(), &key, 1); + // ok, its a public key + if (!key) { + gpgme_get_key(mCtx, uid.toAscii().constData(), &key, 0); + } + return key; +} + +/** List all availabe Keys (VERY much like kgpgme) + */ +GpgKeyList GpgContext::listKeys() +{ + gpgme_error_t err; + gpgme_key_t key; + + GpgKeyList keys; + //TODO dont run the loop more often than necessary + // list all keys ( the 0 is for all ) + err = gpgme_op_keylist_start(mCtx, NULL, 0); + checkErr(err); + while (!(err = gpgme_op_keylist_next(mCtx, &key))) { + GpgKey gpgkey; + + if (!key->subkeys) + continue; + + gpgkey.id = key->subkeys->keyid; + gpgkey.fpr = key->subkeys->fpr; + gpgkey.expired = (key->expired != 0); + gpgkey.revoked = (key->revoked != 0); + + if (key->uids) { + gpgkey.name = QString::fromUtf8(key->uids->name); + gpgkey.email = QString::fromUtf8(key->uids->email); + } + keys.append(gpgkey); + gpgme_key_unref(key); + } + gpgme_op_keylist_end(mCtx); + + // list only private keys ( the 1 does ) + gpgme_op_keylist_start(mCtx, NULL, 1); + while (!(err = gpgme_op_keylist_next(mCtx, &key))) { + if (!key->subkeys) + continue; + // iterate keys, mark privates + GpgKeyList::iterator it = keys.begin(); + while (it != keys.end()) { + if (key->subkeys->keyid == it->id.toStdString()) + it->privkey = true; + it++; + } + + gpgme_key_unref(key); + } + gpgme_op_keylist_end(mCtx); + + return keys; +} + +/** Delete keys + */ + +void GpgContext::deleteKeys(QStringList *uidList) +{ + QString tmp; + gpgme_key_t key; + + foreach(tmp, *uidList) { + gpgme_op_keylist_start(mCtx, tmp.toAscii().constData(), 0); + gpgme_op_keylist_next(mCtx, &key); + gpgme_op_keylist_end(mCtx); + gpgme_op_delete(mCtx, key, 1); + } + emit signalKeyDBChanged(); +} + +/** Encrypt inBuffer for reciepients-uids, write + * result to outBuffer + */ +bool GpgContext::encrypt(QStringList *uidList, const QByteArray &inBuffer, QByteArray *outBuffer) +{ + + gpgme_data_t in = 0, out = 0; + outBuffer->resize(0); + + if (uidList->count() == 0) { + QMessageBox::critical(0, tr("No Key Selected"), tr("No Key Selected")); + return false; + } + + //gpgme_encrypt_result_t e_result; + gpgme_key_t recipients[uidList->count()+1]; + + /* get key for user */ + for (int i = 0; i < uidList->count(); i++) { + // the last 0 is for public keys, 1 would return private keys + gpgme_op_keylist_start(mCtx, uidList->at(i).toAscii().constData(), 0); + gpgme_op_keylist_next(mCtx, &recipients[i]); + gpgme_op_keylist_end(mCtx); + } + //Last entry in array has to be NULL + recipients[uidList->count()] = NULL; + + //If the last parameter isnt 0, a private copy of data is made + if (mCtx) { + err = gpgme_data_new_from_mem(&in, inBuffer.data(), inBuffer.size(), 1); + checkErr(err); + if (!err) { + err = gpgme_data_new(&out); + checkErr(err); + if (!err) { + err = gpgme_op_encrypt(mCtx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, in, out); + checkErr(err); + if (!err) { + err = readToBuffer(out, outBuffer); + checkErr(err); + } + } + } + } + /* unref all keys */ + for (int i = 0; i <= uidList->count(); i++) { + gpgme_key_unref(recipients[i]); + } + if (in) { + gpgme_data_release(in); + } + if (out) { + gpgme_data_release(out); + } + return (err == GPG_ERR_NO_ERROR); +} + +/** Decrypt QByteAarray, return QByteArray + * mainly from http://basket.kde.org/ (kgpgme.cpp) + */ +bool GpgContext::decrypt(const QByteArray &inBuffer, QByteArray *outBuffer) +{ + gpgme_data_t in = 0, out = 0; + gpgme_decrypt_result_t result = 0; + QString errorString; + + outBuffer->resize(0); + if (mCtx) { + err = gpgme_data_new_from_mem(&in, inBuffer.data(), inBuffer.size(), 1); + checkErr(err); + if (!err) { + err = gpgme_data_new(&out); + checkErr(err); + if (!err) { + err = gpgme_op_decrypt(mCtx, in, out); + checkErr(err); + + if(gpg_err_code(err) == GPG_ERR_DECRYPT_FAILED) { + errorString.append(gpgErrString(err)).append("<br>"); + result = gpgme_op_decrypt_result(mCtx); + checkErr(result->recipients->status); + errorString.append(gpgErrString(result->recipients->status)).append("<br>"); + errorString.append(tr("<br>No private key with id %1 present in keyring").arg(result->recipients->keyid)); + } else { + errorString.append(gpgErrString(err)).append("<br>"); + } + + if (!err) { + result = gpgme_op_decrypt_result(mCtx); + if (result->unsupported_algorithm) { + QMessageBox::critical(0, tr("Unsupported algorithm"), result->unsupported_algorithm); + } else { + err = readToBuffer(out, outBuffer); + checkErr(err); + } + } + } + } + } + if (gpg_err_code(err) != GPG_ERR_NO_ERROR && gpg_err_code(err) != GPG_ERR_CANCELED) { + QMessageBox::critical(0, tr("Error decrypting:"), errorString); + return false; + } + + if (! settings.value("general/rememberPassword").toBool()) { + clearPasswordCache(); + } + + if (in) { + gpgme_data_release(in); + } + if (out) { + gpgme_data_release(out); + } + return (err == GPG_ERR_NO_ERROR); +} + +/** Read gpgme-Data to QByteArray + * mainly from http://basket.kde.org/ (kgpgme.cpp) + */ +#define BUF_SIZE (32 * 1024) +gpgme_error_t GpgContext::readToBuffer(gpgme_data_t in, QByteArray *outBuffer) +{ + int ret; + gpgme_error_t err = GPG_ERR_NO_ERROR; + + ret = gpgme_data_seek(in, 0, SEEK_SET); + if (ret) { + err = gpgme_err_code_from_errno(errno); + checkErr(err, "failed dataseek in readToBuffer"); + } else { + char *buf = new char[BUF_SIZE + 2]; + + if (buf) { + while ((ret = gpgme_data_read(in, buf, BUF_SIZE)) > 0) { + uint size = outBuffer->size(); + outBuffer->resize(size + ret); + memcpy(outBuffer->data() + size, buf, ret); + } + if (ret < 0) { + err = gpgme_err_code_from_errno(errno); + checkErr(err, "failed data_read in readToBuffer"); + } + delete[] buf; + } + } + return err; +} + +/** The Passphrase window, if not provided by env-Var GPG_AGENT_INFO + * originally copied from http://basket.kde.org/ (kgpgme.cpp), but modified + */ +gpgme_error_t GpgContext::passphraseCb(void *hook, const char *uid_hint, + const char *passphrase_info, + int last_was_bad, int fd) +{ + GpgContext *gpg = static_cast<GpgContext*>(hook); + return gpg->passphrase(uid_hint, passphrase_info, last_was_bad, fd); +} + +gpgme_error_t GpgContext::passphrase(const char *uid_hint, + const char * /*passphrase_info*/, + int last_was_bad, int fd) +{ + gpgme_error_t returnValue = GPG_ERR_CANCELED; + QString passwordDialogMessage; + QString gpgHint = QString::fromUtf8(uid_hint); + bool result; +#ifdef _WIN32 + DWORD written; + HANDLE hd = (HANDLE)fd; +#endif + + if (last_was_bad) { + passwordDialogMessage += "<i>"+tr("Wrong password")+".</i><br><br>\n\n"; + clearPasswordCache(); + } + + /** if uid provided */ + if (!gpgHint.isEmpty()) { + // remove UID, leave only username & email + gpgHint.remove(0, gpgHint.indexOf(" ")); + passwordDialogMessage += "<b>"+tr("Enter Password for")+"</b><br>" + gpgHint + "<br>"; + } + + if (mPasswordCache.isEmpty()) { + QString password = QInputDialog::getText(QApplication::activeWindow(), tr("Enter Password"), + passwordDialogMessage, QLineEdit::Password, + "", &result); + + if (result) mPasswordCache = password.toAscii(); + } else { + result = true; + } + + if (result) { + +#ifndef _WIN32 + if (write(fd, mPasswordCache.data(), mPasswordCache.length()) == -1) { + qDebug() << "something is terribly broken"; + } +#else + WriteFile(hd, mPasswordCache.data(), mPasswordCache.length(), &written, 0); +#endif + + returnValue = GPG_ERR_NO_ERROR; + } + +#ifndef _WIN32 + if (write(fd, "\n", 1) == -1) { + qDebug() << "something is terribly broken"; + } +#else + WriteFile(hd, "\n", 1, &written, 0); + + /* program will hang on cancel if hd not closed */ + if(!result) { + CloseHandle(hd); + } +#endif + + return returnValue; +} + +/** also from kgpgme.cpp, seems to clear password from mem */ +void GpgContext::clearPasswordCache() +{ + if (mPasswordCache.size() > 0) { + mPasswordCache.fill('\0'); + mPasswordCache.truncate(0); + } +} + +// error-handling +int GpgContext::checkErr(gpgme_error_t err, QString comment) const +{ + //if (err != GPG_ERR_NO_ERROR && err != GPG_ERR_CANCELED) { + if (err != GPG_ERR_NO_ERROR) { + qDebug() << "[Error " << comment << "] Source: " << gpgme_strsource(err) << " String: " << gpgErrString(err); + } + return err; +} + +int GpgContext::checkErr(gpgme_error_t err) const +{ + //if (err != GPG_ERR_NO_ERROR && err != GPG_ERR_CANCELED) { + if (err != GPG_ERR_NO_ERROR) { + qDebug() << "[Error] Source: " << gpgme_strsource(err) << " String: " << gpgErrString(err); + } + return err; +} + +QString GpgContext::gpgErrString(gpgme_error_t err) { + return QString::fromUtf8(gpgme_strerror(err)); +} + +/** export private key, TODO errohandling, e.g. like in seahorse (seahorse-gpg-op.c) **/ + +void GpgContext::exportSecretKey(QString uid, QByteArray *outBuffer) +{ + qDebug() << *outBuffer; + // export private key to outBuffer + QStringList arguments; + arguments << "--armor" << "--export-secret-key" << uid; + QByteArray *err = new QByteArray(); + executeGpgCommand(arguments, outBuffer, err); + + // append public key to outBuffer + QByteArray *pubKey = new QByteArray(); + QStringList keyList; + keyList.append(uid); + exportKeys(&keyList,pubKey); + outBuffer->append(*pubKey); +} + +/** return type should be gpgme_error_t*/ +void GpgContext::executeGpgCommand(QStringList arguments, QByteArray *stdOut, QByteArray *stdErr) +{ + QStringList args; + args << "--homedir" << gpgKeys << "--batch" << arguments; + + qDebug() << args; + QProcess gpg; + // qDebug() << "engine->file_name" << engine->file_name; + + gpg.start(gpgBin, args); + gpg.waitForFinished(); + + *stdOut = gpg.readAllStandardOutput(); + *stdErr = gpg.readAllStandardError(); + qDebug() << *stdOut; +} + +/*** + * if sigbuffer not set, the inbuffer should contain signed text + * + * TODO: return type should contain: + * -> list of sigs + * -> valid + * -> errors + */ +gpgme_signature_t GpgContext::verify(QByteArray *inBuffer, QByteArray *sigBuffer) { + + int error=0; + gpgme_data_t in; + gpgme_error_t err; + gpgme_signature_t sign; + gpgme_verify_result_t result; + + err = gpgme_data_new_from_mem(&in, inBuffer->data(), inBuffer->size(), 1); + checkErr(err); + + if (sigBuffer != NULL ) { + gpgme_data_t sigdata; + err = gpgme_data_new_from_mem(&sigdata, sigBuffer->data(), sigBuffer->size(), 1); + err = gpgme_op_verify (mCtx, sigdata, in, NULL); + } else { + err = gpgme_op_verify (mCtx, in, NULL, in); + } + error = checkErr(err); + + if (error != 0) { + return NULL; + } + + result = gpgme_op_verify_result (mCtx); + sign = result->signatures; + return sign; +} + +/*** + * return type should contain: + * -> list of sigs + * -> valid + * -> decrypted message + */ +//void GpgContext::decryptVerify(QByteArray in) { + +/* gpgme_error_t err; + gpgme_data_t in, out; + + gpgme_decrypt_result_t decrypt_result; + gpgme_verify_result_t verify_result; + + err = gpgme_op_decrypt_verify (mCtx, in, out); + decrypt_result = gpgme_op_decrypt_result (mCtx); + + verify_result = gpgme_op_verify_result (mCtx); + */ +//} + +bool GpgContext::sign(QStringList *uidList, const QByteArray &inBuffer, QByteArray *outBuffer, bool detached) { + + gpgme_error_t err; + gpgme_data_t in, out; + gpgme_sign_result_t result; + gpgme_sig_mode_t mode; + + if (uidList->count() == 0) { + QMessageBox::critical(0, tr("Key Selection"), tr("No Private Key Selected")); + return false; + } + + // at start or end? + gpgme_signers_clear(mCtx); + + //gpgme_encrypt_result_t e_result; + gpgme_key_t signers[uidList->count()+1]; + + + // TODO: do we really need array? adding one key in loop should be ok + for (int i = 0; i < uidList->count(); i++) { + // the last 0 is for public keys, 1 would return private keys + gpgme_op_keylist_start(mCtx, uidList->at(i).toAscii().constData(), 0); + gpgme_op_keylist_next(mCtx, &signers[i]); + gpgme_op_keylist_end(mCtx); + + err = gpgme_signers_add (mCtx, signers[i]); + checkErr(err); + } + + err = gpgme_data_new_from_mem(&in, inBuffer.data(), inBuffer.size(), 1); + checkErr(err); + err = gpgme_data_new (&out); + checkErr(err); + + /* + `GPGME_SIG_MODE_NORMAL' + A normal signature is made, the output includes the plaintext + and the signature. + + `GPGME_SIG_MODE_DETACH' + A detached signature is made. + + `GPGME_SIG_MODE_CLEAR' + A clear text signature is made. The ASCII armor and text + mode settings of the context are ignored. + */ + + if(detached) { + mode = GPGME_SIG_MODE_DETACH; + } else { + mode = GPGME_SIG_MODE_CLEAR; + } + + err = gpgme_op_sign (mCtx, in, out, mode); + checkErr (err); + + if (err == GPG_ERR_CANCELED) { + return false; + } + + if (err != GPG_ERR_NO_ERROR) { + QMessageBox::critical(0, tr("Error signing:"), QString::fromUtf8(gpgme_strerror(err))); + return false; + } + + result = gpgme_op_sign_result (mCtx); + err = readToBuffer(out, outBuffer); + checkErr (err); + + gpgme_data_release(in); + gpgme_data_release(out); + + if (! settings.value("general/rememberPassword").toBool()) { + clearPasswordCache(); + } + + return (err == GPG_ERR_NO_ERROR); +} + +/* + * if there is no '\n' before the PGP-Begin-Block, but for example a whitespace, + * GPGME doesn't recognise the Message as encrypted. This function adds '\n' + * before the PGP-Begin-Block, if missing. + */ +void GpgContext::preventNoDataErr(QByteArray *in) +{ + int block_start = in->indexOf(GpgConstants::PGP_CRYPT_BEGIN); + if (block_start > 0 && in->at(block_start - 1) != '\n') { + in->insert(block_start, '\n'); + } + block_start = in->indexOf(GpgConstants::PGP_SIGNED_BEGIN); + if (block_start > 0 && in->at(block_start - 1) != '\n') { + in->insert(block_start, '\n'); + } +} + +/* + * isSigned returns: + * - 0, if text isn't signed at all + * - 1, if text is partially signed + * - 2, if text is completly signed + */ +int GpgContext::textIsSigned(const QByteArray &text) { + if (text.trimmed().startsWith(GpgConstants::PGP_SIGNED_BEGIN) && text.trimmed().endsWith(GpgConstants::PGP_SIGNED_END)) { + return 2; + } + if (text.contains(GpgConstants::PGP_SIGNED_BEGIN) && text.contains(GpgConstants::PGP_SIGNED_END)) { + return 1; + } + return 0; +} + +QString GpgContext::beautifyFingerprint(QString fingerprint) +{ + uint len = fingerprint.length(); + if ((len > 0) && (len % 4 == 0)) + for (uint n = 0; 4 *(n + 1) < len; ++n) + fingerprint.insert(5 * n + 4, ' '); + return fingerprint; +} + +void GpgContext::slotRefreshKeyList() { + mKeyList = this->listKeys(); +} + +/** + * note: privkey status is not returned + */ +GpgKey GpgContext::getKeyByFpr(QString fpr) { + + //GpgKeyList list = this->listKeys(); + foreach (GpgKey key, mKeyList) { + if(key.fpr == fpr) { + return key; + } + } + + return GpgKey(); +} + +/** + * note: privkey status is not returned + */ +GpgKey GpgContext::getKeyById(QString id) { + + //GpgKeyList list = this->listKeys(); + foreach (GpgKey key, mKeyList) { + if(key.id == id) { + return key; + } + } + + return GpgKey(); +} + +QString GpgContext::getGpgmeVersion() { + return QString(gpgme_check_version(NULL)); +} + +} + + + + + diff --git a/src/gpgcontext.h b/src/gpgcontext.h new file mode 100644 index 0000000..5b8f93c --- /dev/null +++ b/src/gpgcontext.h @@ -0,0 +1,183 @@ +/* + * gpgcontext.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __SGPGMEPP_CONTEXT_H__ +#define __SGPGMEPP_CONTEXT_H__ + +#include "gpgconstants.h" +#include <locale.h> +#include <errno.h> +#include <gpgme.h> +#include <QLinkedList> +#include <QtGui> + +QT_BEGIN_NAMESPACE +class QMessageBox; +class sstream; +class QApplication; +class QByteArray; +class QString; +QT_END_NAMESPACE + +class GpgKey +{ +public: + GpgKey() { + privkey = false; + } + QString id; + QString name; + QString email; + QString fpr; + bool privkey; + bool expired; + bool revoked; +}; + +typedef QLinkedList< GpgKey > GpgKeyList; + +class GpgImportedKey +{ +public: + QString fpr; + int importStatus; +}; + +typedef QLinkedList< GpgImportedKey > GpgImportedKeyList; + +class GpgImportInformation +{ +public: + GpgImportInformation() { + considered = 0; + no_user_id = 0; + imported = 0; + imported_rsa = 0; + unchanged = 0; + new_user_ids = 0; + new_sub_keys = 0; + new_signatures = 0; + new_revocations = 0; + secret_read = 0; + secret_imported = 0; + secret_unchanged = 0; + not_imported = 0; + } + + int considered; + int no_user_id; + int imported; + int imported_rsa; + int unchanged; + int new_user_ids; + int new_sub_keys; + int new_signatures; + int new_revocations; + int secret_read; + int secret_imported; + int secret_unchanged; + int not_imported; + GpgImportedKeyList importedKeys; +}; + +namespace GpgME +{ + +class GpgContext : public QObject +{ + Q_OBJECT + +public: + GpgContext(); // Constructor + ~GpgContext(); // Destructor + GpgImportInformation importKey(QByteArray inBuffer); + bool exportKeys(QStringList *uidList, QByteArray *outBuffer); + void generateKey(QString *params); + GpgKeyList listKeys(); + void deleteKeys(QStringList *uidList); + bool encrypt(QStringList *uidList, const QByteArray &inBuffer, + QByteArray *outBuffer); + bool decrypt(const QByteArray &inBuffer, QByteArray *outBuffer); + void clearPasswordCache(); + void exportSecretKey(QString uid, QByteArray *outBuffer); + gpgme_key_t getKeyDetails(QString uid); + gpgme_signature_t verify(QByteArray *inBuffer, QByteArray *sigBuffer = NULL); +// void decryptVerify(QByteArray in); + bool sign(QStringList *uidList, const QByteArray &inBuffer, QByteArray *outBuffer, bool detached = false); + /** + * @details If text contains PGP-message, put a linebreak before the message, + * so that gpgme can decrypt correctly + * + * @param in Pointer to the QBytearray to check. + */ + void preventNoDataErr(QByteArray *in); + + GpgKey getKeyByFpr(QString fpr); + GpgKey getKeyById(QString id); + + static QString gpgErrString(gpgme_error_t err); + static QString getGpgmeVersion(); + + /** + * @brief + * + * @param text + * @return \li 2, if the text is completly signed, + * \li 1, if the text is partially signed, + * \li 0, if the text is not signed at all. + */ + int textIsSigned(const QByteArray &text); + QString beautifyFingerprint(QString fingerprint); + +signals: + void signalKeyDBChanged(); + +private slots: + void slotRefreshKeyList(); + +private: + gpgme_ctx_t mCtx; + gpgme_data_t in, out; + gpgme_error_t err; + gpgme_error_t readToBuffer(gpgme_data_t in, QByteArray *outBuffer); + QByteArray mPasswordCache; + QSettings settings; + bool debug; + GpgKeyList mKeyList; + int checkErr(gpgme_error_t err) const; + int checkErr(gpgme_error_t err, QString comment) const; + + static gpgme_error_t passphraseCb(void *hook, const char *uid_hint, + const char *passphrase_info, + int last_was_bad, int fd); + gpgme_error_t passphrase(const char *uid_hint, + const char *passphrase_info, + int last_was_bad, int fd); + + void executeGpgCommand(QStringList arguments, + QByteArray *stdOut, + QByteArray *stdErr); + QString gpgBin; + QString gpgKeys; +}; +} // namespace GpgME + +#endif // __SGPGMEPP_CONTEXT_H__ diff --git a/src/helppage.cpp b/src/helppage.cpp new file mode 100644 index 0000000..ace8c92 --- /dev/null +++ b/src/helppage.cpp @@ -0,0 +1,81 @@ +/* + * helppage.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "helppage.h" + +HelpPage::HelpPage(const QString path, QWidget *parent) : + QWidget(parent) +{ + + browser = new QTextBrowser(); + QVBoxLayout* mainLayout = new QVBoxLayout(); + mainLayout->setSpacing(0); + mainLayout->addWidget(browser); + mainLayout->setContentsMargins(0,0,0,0); + setLayout(mainLayout); + //setAttribute(Qt::WA_DeleteOnClose); + //browser->setSource(QUrl::fromLocalFile(path)); + + connect(browser, SIGNAL(anchorClicked(QUrl)), this, SLOT(slotOpenUrl(QUrl))); + browser->setOpenLinks(false); + browser->setSource(localizedHelp(QUrl(path))); + browser->setFocus(); + +} + +void HelpPage::slotOpenUrl(QUrl url) { + browser->setSource(localizedHelp(url)); +}; + +/** + * @brief HelpPage::localizedHelp + * check if the requested file is also available with the locale, + * e.g. return index.de.html if index.html was requested but the + * locale is de and index.de.html is available + * @param url + * @return + */ +QUrl HelpPage::localizedHelp(QUrl url) { + QString path = url.toLocalFile(); + QString filename = path.mid(path.lastIndexOf("/") + 1 ); + QString filepath = path.left(path.lastIndexOf("/") + 1 ); + QStringList fileparts = filename.split("."); + + //QSettings settings; + QString lang = QSettings().value("int/lang", QLocale::system().name()).toString(); + if (lang.isEmpty()) { + lang = QLocale::system().name(); + } + + fileparts.insert(1,lang); + QString langfile = filepath + fileparts.join("."); + + if(QFile(QUrl(langfile).toLocalFile()).exists()) { + return langfile; + } else { + return path; + } + +} + +QTextBrowser* HelpPage::getBrowser() { + return browser; +} diff --git a/src/helppage.h b/src/helppage.h new file mode 100644 index 0000000..22aa9b1 --- /dev/null +++ b/src/helppage.h @@ -0,0 +1,50 @@ +/* + * helppage.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef HELPPAGE_H +#define HELPPAGE_H + +#include <QWidget> +#include <QTextBrowser> +#include <QVBoxLayout> +#include <QSettings> +#include <QFile> +#include <QLocale> + +class HelpPage : public QWidget +{ + Q_OBJECT +public: + explicit HelpPage(const QString path, QWidget *parent = 0); + QTextBrowser *getBrowser(); + +signals: + +public slots: + void slotOpenUrl(QUrl url); + +private: + QTextBrowser *browser; /** The textbrowser of the tab */ + QUrl localizedHelp(QUrl path); + +}; + +#endif // HELPPAGE_H diff --git a/src/keydetailsdialog.cpp b/src/keydetailsdialog.cpp new file mode 100644 index 0000000..36f2e4a --- /dev/null +++ b/src/keydetailsdialog.cpp @@ -0,0 +1,225 @@ +/* + * keydetailsdialog.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "keydetailsdialog.h" + +KeyDetailsDialog::KeyDetailsDialog(GpgME::GpgContext* ctx, gpgme_key_t key, QWidget *parent) + : QDialog(parent) +{ + mCtx = ctx; + keyid = new QString(key->subkeys->keyid); + + ownerBox = new QGroupBox(tr("Owner details")); + keyBox = new QGroupBox(tr("Key details")); + fingerprintBox = new QGroupBox(tr("Fingerprint")); + additionalUidBox = new QGroupBox(tr("Additional Uids")); + buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); + + nameVarLabel = new QLabel(QString::fromUtf8(key->uids->name)); + nameVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + emailVarLabel = new QLabel(QString::fromUtf8(key->uids->email)); + emailVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + + commentVarLabel = new QLabel(QString::fromUtf8(key->uids->comment)); + commentVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + keyidVarLabel = new QLabel(key->subkeys->keyid); + keyidVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + + QString keySizeVal, keyExpireVal, keyCreatedVal, keyAlgoVal; + + if (key->subkeys->expires == 0) { + keyExpireVal = tr("Never"); + } else { + keyExpireVal = QDateTime::fromTime_t(key->subkeys->expires).toString("dd. MMM. yyyy"); + } + + keyAlgoVal = gpgme_pubkey_algo_name(key->subkeys->pubkey_algo); + keyCreatedVal = QDateTime::fromTime_t(key->subkeys->timestamp).toString("dd. MMM. yyyy"); + + // have el-gamal key? + if (key->subkeys->next) { + keySizeVal.sprintf("%d / %d", int(key->subkeys->length), int(key->subkeys->next->length)); + if (key->subkeys->next->expires == 0) { + keyExpireVal += tr(" / Never"); + } else { + keyExpireVal += " / " + QDateTime::fromTime_t(key->subkeys->next->expires).toString("dd. MMM. yyyy"); + } + keyAlgoVal.append(" / ").append(gpgme_pubkey_algo_name(key->subkeys->next->pubkey_algo)); + keyCreatedVal += " / " + QDateTime::fromTime_t(key->subkeys->next->timestamp).toString("dd. MMM. yyyy"); + } else { + keySizeVal.setNum(int(key->subkeys->length)); + } + + keySizeVarLabel = new QLabel(keySizeVal); + expireVarLabel = new QLabel(keyExpireVal); + createdVarLabel = new QLabel(keyCreatedVal); + algorithmVarLabel = new QLabel(keyAlgoVal); + + QVBoxLayout *mvbox = new QVBoxLayout(); + QGridLayout *vboxKD = new QGridLayout(); + QGridLayout *vboxOD = new QGridLayout(); + + vboxOD->addWidget(new QLabel(tr("Name:")), 0, 0); + vboxOD->addWidget(new QLabel(tr("E-Mailaddress:")), 1, 0); + vboxOD->addWidget(new QLabel(tr("Comment:")), 2, 0); + vboxOD->addWidget(nameVarLabel, 0, 1); + vboxOD->addWidget(emailVarLabel, 1, 1); + vboxOD->addWidget(commentVarLabel, 2, 1); + + vboxKD->addWidget(new QLabel(tr("Key size:")), 0, 0); + vboxKD->addWidget(new QLabel(tr("Expires on: ")), 1, 0); + vboxKD->addWidget(new QLabel(tr("Algorithm: ")), 3, 0); + vboxKD->addWidget(new QLabel(tr("Created on: ")), 4, 0); + vboxKD->addWidget(new QLabel(tr("Key ID: ")), 5, 0); + vboxKD->addWidget(keySizeVarLabel, 0, 1); + vboxKD->addWidget(expireVarLabel, 1, 1); + vboxKD->addWidget(algorithmVarLabel, 3, 1); + vboxKD->addWidget(createdVarLabel, 4, 1); + vboxKD->addWidget(keyidVarLabel, 5, 1); + + ownerBox->setLayout(vboxOD); + mvbox->addWidget(ownerBox); + + keyBox->setLayout(vboxKD); + mvbox->addWidget(keyBox); + + fingerPrintVarLabel = new QLabel(beautifyFingerprint(key->subkeys->fpr)); + fingerPrintVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + fingerPrintVarLabel->setStyleSheet("margin-left: 20; margin-right: 20;"); + QHBoxLayout *hboxFP = new QHBoxLayout(); + + hboxFP->addWidget(fingerPrintVarLabel); + QIcon ico(":button_copy.png"); + + QPushButton copyFingerprintButton(QIcon(ico.pixmap(12, 12)), ""); + //copyFingerprintButton.setStyleSheet("QPushButton {border: 0px; } QPushButton:Pressed {} "); + copyFingerprintButton.setFlat(true); + copyFingerprintButton.setToolTip(tr("copy fingerprint to clipboard")); + connect(©FingerprintButton, SIGNAL(clicked()), this, SLOT(slotCopyFingerprint())); + + hboxFP->addWidget(©FingerprintButton); + + fingerprintBox->setLayout(hboxFP); + mvbox->addWidget(fingerprintBox); + + // If key has more than primary uid, also show the other uids + gpgme_user_id_t addUserIds = key->uids->next; + if (addUserIds !=NULL) { + QVBoxLayout *vboxUID = new QVBoxLayout(); + while (addUserIds != NULL){ + addUserIdsVarLabel = new QLabel(QString::fromUtf8(addUserIds->name)+ QString(" <")+addUserIds->email+">"); + addUserIdsVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + vboxUID->addWidget(addUserIdsVarLabel); + addUserIds=addUserIds->next; + } + additionalUidBox->setLayout(vboxUID); + mvbox->addWidget(additionalUidBox); + } + + if (key->secret) { + QGroupBox *privKeyBox = new QGroupBox(tr("Private Key")); + QVBoxLayout *vboxPK = new QVBoxLayout(); + + QPushButton *exportButton = new QPushButton(tr("Export Private Key")); + vboxPK->addWidget(exportButton); + connect(exportButton, SIGNAL(clicked()), this, SLOT(slotExportPrivateKey())); + + privKeyBox->setLayout(vboxPK); + mvbox->addWidget(privKeyBox); + } + + if((key->expired) || (key->revoked)) { + QHBoxLayout *expBox = new QHBoxLayout(); + QIcon icon = QIcon::fromTheme("dialog-warning"); + QPixmap pixmap = icon.pixmap(QSize(32,32),QIcon::Normal,QIcon::On); + + QLabel *expLabel = new QLabel(); + QLabel *iconLabel = new QLabel(); + if (key->expired) { + expLabel->setText(tr("Warning: Key expired")); + } + if (key->revoked) { + expLabel->setText(tr("Warning: Key revoked")); + } + + iconLabel->setPixmap(pixmap); + QFont font = expLabel->font(); + font.setBold(true); + expLabel->setFont(font); + expBox->addWidget(iconLabel); + expBox->addWidget(expLabel); + mvbox->addLayout(expBox); + } + + mvbox->addWidget(buttonBox); + + this->setLayout(mvbox); + this->setWindowTitle(tr("Keydetails")); + this->setModal(true); + this->show(); + + exec(); +} + +void KeyDetailsDialog::slotExportPrivateKey() +{ + // Show a information box with explanation about private key + int ret = QMessageBox::information(this, tr("Exporting private Key"), + tr("You are about to export your private key.\n" + "This is NOT your public key, so don't give it away.\n" + "Make sure you keep it save." + "Do you really want to export your private key?"), + QMessageBox::Cancel | QMessageBox::Ok); + + // export key, if ok was clicked + if (ret == QMessageBox::Ok) { + QByteArray *keyArray = new QByteArray(); + mCtx->exportSecretKey(*keyid, keyArray); + gpgme_key_t key = mCtx->getKeyDetails(*keyid); + QString fileString = QString::fromUtf8(key->uids->name) + " " + QString::fromUtf8(key->uids->email) + "(" + QString(key->subkeys->keyid)+ ")_pub_sec.asc"; + QString fileName = QFileDialog::getSaveFileName(this, tr("Export Key To File"), fileString, tr("Key Files") + " (*.asc *.txt);;All Files (*)"); + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox::critical(0,tr("Export error"),tr("Couldn't open %1 for writing").arg(fileName)); + return; + } + QTextStream stream(&file); + stream << *keyArray; + file.close(); + delete keyArray; + } +} + +QString KeyDetailsDialog::beautifyFingerprint(QString fingerprint) +{ + uint len = fingerprint.length(); + if ((len > 0) && (len % 4 == 0)) + for (uint n = 0; 4 *(n + 1) < len; ++n) + fingerprint.insert(5 * n + 4, ' '); + return fingerprint; +} + +void KeyDetailsDialog::slotCopyFingerprint() { + QString fpr = fingerPrintVarLabel->text().trimmed().replace(" ", ""); + QClipboard *cb = QApplication::clipboard(); + cb->setText(fpr); +} diff --git a/src/keydetailsdialog.h b/src/keydetailsdialog.h new file mode 100644 index 0000000..2774fe2 --- /dev/null +++ b/src/keydetailsdialog.h @@ -0,0 +1,87 @@ +/* + * keydetailsdialog.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __KEYDETAILSDIALOG_H__ +#define __KEYDETAILSDIALOG_H__ + +#include "gpgcontext.h" +#include <gpgme.h> + +QT_BEGIN_NAMESPACE +class QDateTime; +class QVBoxLayout; +class QHBoxLayout; +class QDialogButtonBox; +class QDialog; +class QGroupBox; +class QLabel; +class QGridLayout; +class QPushButton; +QT_END_NAMESPACE + +class KeyDetailsDialog : public QDialog +{ + Q_OBJECT + +public: + KeyDetailsDialog(GpgME::GpgContext* ctx, gpgme_key_t key, QWidget *parent = 0); + + /** + * @details Return QString with a space inserted at every fourth character + * + * @param fingerprint The fingerprint to be beautified + */ + static QString beautifyFingerprint(QString fingerprint); + +private slots: + /** + * @details Export the key to a file, which is choosen in a file dialog + */ + void slotExportPrivateKey(); + + /** + * @details Copy the fingerprint to clipboard + */ + void slotCopyFingerprint(); + +private: + QString *keyid; /** The id of the key the details should be shown for */ + GpgME::GpgContext *mCtx; /** The current gpg-context */ + + QGroupBox *ownerBox; /** Groupbox containing owner information */ + QGroupBox *keyBox; /** Groupbox containing key information */ + QGroupBox *fingerprintBox; /** Groupbox containing fingerprint information */ + QGroupBox *additionalUidBox; /** Groupbox containing information about additional uids */ + QDialogButtonBox *buttonBox; /** Box containing the close button */ + + QLabel *nameVarLabel; /** Label containng the keys name */ + QLabel *emailVarLabel; /** Label containng the keys email */ + QLabel *commentVarLabel; /** Label containng the keys commment */ + QLabel *keySizeVarLabel; /** Label containng the keys keysize */ + QLabel *expireVarLabel; /** Label containng the keys expiration date */ + QLabel *createdVarLabel; /** Label containng the keys creation date */ + QLabel *algorithmVarLabel; /** Label containng the keys algorithm */ + QLabel *keyidVarLabel; /** Label containng the keys keyid */ + QLabel *fingerPrintVarLabel; /** Label containng the keys fingerprint */ + QLabel *addUserIdsVarLabel; /** Label containng info about keys additional uids */ +}; + +#endif // __KEYDETAILSDIALOG_H__ diff --git a/src/keygendialog.cpp b/src/keygendialog.cpp new file mode 100644 index 0000000..2aa5f81 --- /dev/null +++ b/src/keygendialog.cpp @@ -0,0 +1,255 @@ +/* + * + * keygendialog.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "keygendialog.h" + +KeyGenDialog::KeyGenDialog(GpgME::GpgContext *ctx, QWidget *parent) + : QDialog(parent) +{ + mCtx = ctx; + buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + + this->setWindowTitle(tr("Generate Key")); + this->setModal(true); + generateKeyDialog(); +} + +void KeyGenDialog::generateKeyDialog() +{ + errorLabel = new QLabel(tr("")); + nameEdit = new QLineEdit(this); + emailEdit = new QLineEdit(this); + commentEdit = new QLineEdit(this); + + keySizeSpinBox = new QSpinBox(this); + keySizeSpinBox->setRange(1024, 4096); + keySizeSpinBox->setValue(2048); + + keySizeSpinBox->setSingleStep(1024); + + keyTypeComboBox = new QComboBox(this); + keyTypeComboBox->addItem("RSA"); + keyTypeComboBox->addItem("DSA/Elgamal"); + keyTypeComboBox->setCurrentIndex(0); + dateEdit = new QDateEdit(QDate::currentDate().addYears(5), this); + dateEdit->setMinimumDate(QDate::currentDate()); + dateEdit->setDisplayFormat("dd/MM/yyyy"); + dateEdit->setCalendarPopup(true); + dateEdit->setEnabled(true); + + expireCheckBox = new QCheckBox(this); + expireCheckBox->setCheckState(Qt::Unchecked); + + passwordEdit = new QLineEdit(this); + repeatpwEdit = new QLineEdit(this); + + passwordEdit->setEchoMode(QLineEdit::Password); + repeatpwEdit->setEchoMode(QLineEdit::Password); + + pwStrengthSlider = new QSlider(this); + pwStrengthSlider->setOrientation(Qt::Horizontal); + pwStrengthSlider->setMaximum(6); + pwStrengthSlider->setDisabled(true); + pwStrengthSlider->setToolTip(tr("Password Strength")); + pwStrengthSlider->setTickPosition(QSlider::TicksBelow); + + QGridLayout *vbox1 = new QGridLayout; + + vbox1->addWidget(new QLabel(tr("Name:")), 0, 0); + vbox1->addWidget(new QLabel(tr("E-Mailaddress:")), 1, 0); + vbox1->addWidget(new QLabel(tr("Comment:")), 2, 0); + vbox1->addWidget(new QLabel(tr("Expiration Date:")), 3, 0); + vbox1->addWidget(new QLabel(tr("Never Expire")), 3, 3); + vbox1->addWidget(new QLabel(tr("KeySize (in Bit):")), 4, 0); + vbox1->addWidget(new QLabel(tr("Key Type:")), 5, 0); + vbox1->addWidget(new QLabel(tr("Password:")), 6, 0); + vbox1->addWidget(new QLabel(tr("Password: Strength\nWeak -> Strong")), 6, 3); + vbox1->addWidget(new QLabel(tr("Repeat Password:")), 7, 0); + + vbox1->addWidget(nameEdit, 0, 1); + vbox1->addWidget(emailEdit, 1, 1); + vbox1->addWidget(commentEdit, 2, 1); + vbox1->addWidget(dateEdit, 3, 1); + vbox1->addWidget(expireCheckBox, 3, 2); + vbox1->addWidget(keySizeSpinBox, 4, 1); + vbox1->addWidget(keyTypeComboBox,5, 1); + vbox1->addWidget(passwordEdit, 6, 1); + vbox1->addWidget(repeatpwEdit, 7, 1); + vbox1->addWidget(pwStrengthSlider, 7, 3); + + QWidget *nameList = new QWidget(this); + nameList->setLayout(vbox1); + + QVBoxLayout *vbox2 = new QVBoxLayout(); + vbox2->addWidget(nameList); + vbox2->addWidget(errorLabel); + vbox2->addWidget(buttonBox); + + connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotKeyGenAccept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + connect(expireCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotExpireBoxChanged())); + connect(passwordEdit, SIGNAL(textChanged(QString)), this, SLOT(slotPasswordEditChanged())); +// connect(keyTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotKeyTypeChanged())); +// connect(keySizeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotKeySizeChanged())); + this->setLayout(vbox2); +} + +void KeyGenDialog::slotKeyGenAccept() +{ + QString errorString = ""; + QString keyGenParams = ""; + /** + * check for errors in keygen dialog input + */ + if ((nameEdit->text()).size() < 5) { + errorString.append(tr(" Name must contain at least five characters. \n")); + } + if (passwordEdit->text() != repeatpwEdit->text()) { + errorString.append(tr(" Password and Repeat don't match. ")); + } + + if (errorString.isEmpty()) { + /** + * create the string for key generation + */ + + if(keyTypeComboBox->currentText() == "RSA") { + keyGenParams = "<GnupgKeyParms format=\"internal\">\n" + "Key-Type: RSA\n" + "Key-Usage: sign\n" + "Key-Length: " + keySizeSpinBox->cleanText() + "\n" + "Subkey-Type: RSA\n" + "Subkey-Length: " + keySizeSpinBox->cleanText() + "\n" + "Subkey-Usage: encrypt\n"; + } else { + keyGenParams = "<GnupgKeyParms format=\"internal\">\n" + "Key-Type: DSA\n" + "Key-Length: " + keySizeSpinBox->cleanText() + "\n" + "Subkey-Type: ELG-E\n" + "Subkey-Length: " + keySizeSpinBox->cleanText() + "\n"; + } + + keyGenParams += "Name-Real: " + nameEdit->text().toUtf8() + "\n"; + if (!(commentEdit->text().isEmpty())) { + keyGenParams += "Name-Comment: " + commentEdit->text().toUtf8() + "\n"; + } + if (!(emailEdit->text().isEmpty())) { + keyGenParams += "Name-Email: " + emailEdit->text().toUtf8() + "\n"; + } + if (expireCheckBox->checkState()) { + keyGenParams += "Expire-Date: 0\n"; + } else { + keyGenParams += "Expire-Date: " + dateEdit->sectionText(QDateTimeEdit::YearSection) + "-" + dateEdit->sectionText(QDateTimeEdit::MonthSection) + "-" + dateEdit->sectionText(QDateTimeEdit::DaySection) + "\n"; + } + if (!(passwordEdit->text().isEmpty())) { + keyGenParams += "Passphrase: " + passwordEdit->text() + "\n"; + } + keyGenParams += "</GnupgKeyParms>"; + + KeyGenThread *kg = new KeyGenThread(keyGenParams, mCtx); + kg->start(); + + this->accept(); + + QDialog *dialog = new QDialog(this, Qt::CustomizeWindowHint | Qt::WindowTitleHint); + dialog->setModal(true); + dialog->setWindowTitle(tr("Generating Key...")); + + QLabel *waitMessage = new QLabel(tr("Collecting random data for key generation.\n This may take a while.\n To speed up the process use your computer\n (e.g. browse the net, listen to music,...)")); + QProgressBar *pb = new QProgressBar(); + pb->setRange(0, 0); + + QVBoxLayout *layout = new QVBoxLayout(dialog); + layout->addWidget(waitMessage); + layout->addWidget(pb); + dialog->setLayout(layout); + + dialog->show(); + + while (kg->isRunning()) { + QCoreApplication::processEvents(); + } + + dialog->close(); + QMessageBox::information(0,tr("Success"),tr("New key created")); + } else { + /** + * create error message + */ + errorLabel->setAutoFillBackground(true); + QPalette error = errorLabel->palette(); + error.setColor(QPalette::Background, "#ff8080"); + errorLabel->setPalette(error); + errorLabel->setText(errorString); + + this->show(); + } +} + +void KeyGenDialog::slotExpireBoxChanged() +{ + if (expireCheckBox->checkState()) { + dateEdit->setEnabled(false); + } else { + dateEdit->setEnabled(true); + } +} + +void KeyGenDialog::slotPasswordEditChanged() +{ + pwStrengthSlider->setValue(checkPassWordStrength()); + update(); +} + +int KeyGenDialog::checkPassWordStrength() +{ + int strength = 0; + + // increase strength by two, if password has more than 7 characters + if ((passwordEdit->text()).length() > 7) { + strength = strength + 2; + } + + // increase strength by one, if password contains a digit + if ((passwordEdit->text()).contains(QRegExp("\\d"))) { + strength++; + } + + // increase strength by one, if password contains a lowercase character + if ((passwordEdit->text()).contains(QRegExp("[a-z]"))) { + strength++; + } + + // increase strength by one, if password contains an uppercase character + if ((passwordEdit->text()).contains(QRegExp("[A-Z]"))) { + strength++; + } + + // increase strength by one, if password contains a non-word character + if ((passwordEdit->text()).contains(QRegExp("\\W"))) { + strength++; + } + + return strength; +} + diff --git a/src/keygendialog.h b/src/keygendialog.h new file mode 100644 index 0000000..b3f4183 --- /dev/null +++ b/src/keygendialog.h @@ -0,0 +1,93 @@ +/* + * keygendialog.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __KEYGENDIALOG_H__ +#define __KEYGENDIALOG_H__ + +#include "keygenthread.h" +#include "gpgcontext.h" +#include <QtGui> + +QT_BEGIN_NAMESPACE +class QDateTime; +class QDialogButtonBox; +class QDialog; +class QGridLayout; +QT_END_NAMESPACE + +class KeyGenDialog : public QDialog +{ + Q_OBJECT + + /** + * @details Constructor of this class + * + * @param ctx The current GpgME context + * @param key The key to show details of + * @param parent The parent of this widget + */ + public: + KeyGenDialog(GpgME::GpgContext* ctx, QWidget *parent = 0); + +private: + void generateKeyDialog(); + + /** + * @details Check the password strength of the text in the passwordEdit member + * + * @return digit between 0 and 6, the higher the more secure is the password + */ + int checkPassWordStrength(); + + GpgME::GpgContext *mCtx; /** The current gpg context */ + KeyGenThread *keyGenThread; /** Thread for key generation */ + QStringList errorMessages; /** List of errors occuring when checking entries of lineedits */ + QDialogButtonBox *buttonBox; /** Box for standardbuttons */ + QLabel *errorLabel; /** Label containing error message */ + QLineEdit *nameEdit; /** Lineedit for the keys name */ + QLineEdit *emailEdit; /** Lineedit for the keys email */ + QLineEdit *commentEdit; /** Lineedit for the keys comment */ + QLineEdit *passwordEdit; /** Lineedit for the keys password */ + QLineEdit *repeatpwEdit; /** Lineedit for the repetition of the keys password */ + QSpinBox *keySizeSpinBox; /** Spinbox for the keys size (in bit) */ + QComboBox *keyTypeComboBox; /** Combobox for Keytpe */ + QDateTimeEdit *dateEdit; /** Dateedit for expiration date */ + QCheckBox *expireCheckBox; /** Checkbox, if key should expire */ + QSlider *pwStrengthSlider; /** Slider showing the password strength */ + +private slots: + /** + * @details when expirebox was checked/unchecked, enable/disable the expiration date box + */ + void slotExpireBoxChanged(); + + /** + * @details When passwordedit changed, set new value for password strength slider + */ + void slotPasswordEditChanged(); + + /** + * @details check all lineedits for false entries. Show error, when there is one, otherwise generate the key + */ + void slotKeyGenAccept(); + +}; +#endif // __KEYGENDIALOG_H__ diff --git a/src/keygenthread.cpp b/src/keygenthread.cpp new file mode 100644 index 0000000..c558877 --- /dev/null +++ b/src/keygenthread.cpp @@ -0,0 +1,34 @@ +/* + * keygenthread.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "keygenthread.h" + +KeyGenThread::KeyGenThread(QString keyGenParams, GpgME::GpgContext *ctx) +{ + this->keyGenParams = keyGenParams; + this->mCtx = ctx; + abort = false; +} + +void KeyGenThread::run() +{ + mCtx->generateKey(&keyGenParams); +} diff --git a/src/keygenthread.h b/src/keygenthread.h new file mode 100644 index 0000000..6fc61e9 --- /dev/null +++ b/src/keygenthread.h @@ -0,0 +1,56 @@ +/* + * keygenthread.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __KEYGENTHREAD_H__ +#define __KEYGENTHREAD_H__ + +#include "gpgcontext.h" +#include <qthread.h> +#include <iostream> +#include <string> +#include <cmath> +#include <QtGui> + +QT_BEGIN_NAMESPACE +class QMessageBox; +QT_END_NAMESPACE + +class KeyGenThread : public QThread +{ + Q_OBJECT + +public: + KeyGenThread(QString keyGenParams, GpgME::GpgContext *ctx); + +signals: + void signalKeyGenerated(); + +private: + QString keyGenParams; + GpgME::GpgContext *mCtx; + bool abort; + QMutex mutex; + +protected: + void run(); + +}; +#endif // __KEYGENTHREAD_H__ diff --git a/src/keyimportdetaildialog.cpp b/src/keyimportdetaildialog.cpp new file mode 100644 index 0000000..4448865 --- /dev/null +++ b/src/keyimportdetaildialog.cpp @@ -0,0 +1,160 @@ +/* + * keyimportdetailsdialog.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "keyimportdetaildialog.h" + +KeyImportDetailDialog::KeyImportDetailDialog(GpgME::GpgContext* ctx, GpgImportInformation result, QWidget *parent) + : QDialog(parent) +{ + mCtx = ctx; + mResult = result; + // If no key for import found, just show a message + if (mResult.considered == 0) { + QMessageBox::information(0, tr("Key import details"), tr("No keys found to import")); + return; + } + + QVBoxLayout *mvbox = new QVBoxLayout(); + + this->createGeneralInfoBox(); + mvbox->addWidget(generalInfoBox); + + this->createKeysTable(); + mvbox->addWidget(keysTable); + + this->createButtonBox(); + mvbox->addWidget(buttonBox); + + this->setLayout(mvbox); + this->setWindowTitle(tr("Key import details")); + this->resize(QSize(600,300)); + this->setModal(true); + this->exec(); +} + +void KeyImportDetailDialog::createGeneralInfoBox() +{ + // GridBox for general import information + generalInfoBox = new QGroupBox(tr("Genral key import info")); + QGridLayout *generalInfoBoxLayout = new QGridLayout(generalInfoBox); + + generalInfoBoxLayout->addWidget(new QLabel(tr("Considered:")),1,0); + generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.considered)),1,1); + int row=2; + if (mResult.unchanged != 0){ + generalInfoBoxLayout->addWidget(new QLabel(tr("Public unchanged:")),row,0); + generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.unchanged)),row,1); + row++; + } + if (mResult.imported != 0){ + generalInfoBoxLayout->addWidget(new QLabel(tr("Imported:")),row,0); + generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.imported)),row,1); + row++; + } + if (mResult.not_imported != 0){ + generalInfoBoxLayout->addWidget(new QLabel(tr("Not imported:")),row,0); + generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.not_imported)),row,1); + row++; + } + if (mResult.secret_read != 0){ + generalInfoBoxLayout->addWidget(new QLabel(tr("Private read:")),row,0); + generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.secret_read)),row,1); + row++; + } + if (mResult.secret_imported != 0){ + generalInfoBoxLayout->addWidget(new QLabel(tr("Private imported:")),row,0); + generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.secret_imported)),row,1); + row++; + } + if (mResult.secret_unchanged != 0){ + generalInfoBoxLayout->addWidget(new QLabel(tr("Private unchanged:")),row,0); + generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.secret_unchanged)),row,1); + row++; + } +} + +void KeyImportDetailDialog::createKeysTable() +{ + keysTable = new QTableWidget(this); + keysTable->setRowCount(0); + keysTable->setColumnCount(4); + keysTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + // Nothing is selectable + keysTable->setSelectionMode(QAbstractItemView::NoSelection); + + QStringList headerLabels; + headerLabels << tr("Name") << tr("Email") << tr("Status") << tr("Fingerprint"); + keysTable->verticalHeader()->hide(); + + keysTable->setHorizontalHeaderLabels(headerLabels); + int row = 0; + foreach (GpgImportedKey impKey, mResult.importedKeys) { + keysTable->setRowCount(row+1); + GpgKey key = mCtx->getKeyByFpr(impKey.fpr); + keysTable->setItem(row, 0, new QTableWidgetItem(key.name)); + keysTable->setItem(row, 1, new QTableWidgetItem(key.email)); + keysTable->setItem(row, 2 ,new QTableWidgetItem(getStatusString(impKey.importStatus))); + keysTable->setItem(row, 3, new QTableWidgetItem(impKey.fpr)); + row++; + } + keysTable->horizontalHeader()->setResizeMode(0, QHeaderView::ResizeToContents); + keysTable->horizontalHeader()->setStretchLastSection(true); + keysTable->resizeColumnsToContents(); +} + +QString KeyImportDetailDialog::getStatusString(int keyStatus) +{ + QString statusString; + // keystatus is greater than 15, if key is private + if (keyStatus > 15) { + statusString.append(tr("private")); + keyStatus=keyStatus-16; + } else { + statusString.append(tr("public")); + } + if (keyStatus == 0) { + statusString.append(", "+tr("unchanged")); + } else { + if (keyStatus == 1) { + statusString.append(", "+tr("new key")); + } else { + if (keyStatus > 7) { + statusString.append(", "+tr("new subkey")); + keyStatus=keyStatus-8; + } + if (keyStatus > 3) { + statusString.append(", "+tr("new signature")); + keyStatus=keyStatus-4; + } + if (keyStatus > 1) { + statusString.append(", "+tr("new uid")); + keyStatus=keyStatus-2; + } + } + } + return statusString; +} + +void KeyImportDetailDialog::createButtonBox() +{ + buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(close())); +} diff --git a/src/keyimportdetaildialog.h b/src/keyimportdetaildialog.h new file mode 100644 index 0000000..dde1f54 --- /dev/null +++ b/src/keyimportdetaildialog.h @@ -0,0 +1,55 @@ +/* + * keyimportdetailsdialog.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __KEYIMPORTDETAILSDIALOG_H__ +#define __KEYIMPORTDETAILSDIALOG_H__ + +#include "gpgcontext.h" +#include <gpgme.h> + +QT_BEGIN_NAMESPACE +class QGridLayout; +class QDialogButtonBox; +QT_END_NAMESPACE + +class KeyImportDetailDialog : public QDialog +{ + Q_OBJECT + +public: + KeyImportDetailDialog(GpgME::GpgContext* ctx, GpgImportInformation result, QWidget *parent = 0); + +private: + void createGeneralInfoBox(); + void createKeyInfoBox(); + void createKeysTable(); + void createButtonBox(); + QString getStatusString(int keyStatus); + + QTableWidget *keysTable; + GpgME::GpgContext *mCtx; + QGroupBox *generalInfoBox; + QGroupBox *keyInfoBox; + QDialogButtonBox *buttonBox; + GpgImportInformation mResult; +}; + +#endif // __KEYIMPORTDETAILSDIALOG_H__ diff --git a/src/keylist.cpp b/src/keylist.cpp new file mode 100644 index 0000000..cd01a2e --- /dev/null +++ b/src/keylist.cpp @@ -0,0 +1,321 @@ +/* + * keylist.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "keylist.h" + +KeyList::KeyList(GpgME::GpgContext *ctx, QWidget *parent) + : QWidget(parent) +{ + mCtx = ctx; + + mKeyList = new QTableWidget(this); + mKeyList->setColumnCount(6); + mKeyList->verticalHeader()->hide(); + mKeyList->setShowGrid(false); + mKeyList->setColumnWidth(0, 24); + mKeyList->setColumnWidth(1, 20); + mKeyList->sortByColumn(2, Qt::AscendingOrder); + mKeyList->setSelectionBehavior(QAbstractItemView::SelectRows); + // hide id and fingerprint of key + mKeyList->setColumnHidden(4, true); + mKeyList->setColumnHidden(5, true); + + // tableitems not editable + mKeyList->setEditTriggers(QAbstractItemView::NoEditTriggers); + // no focus (rectangle around tableitems) + // may be it should focus on whole row + mKeyList->setFocusPolicy(Qt::NoFocus); + + mKeyList->setAlternatingRowColors(true); + + QStringList labels; + labels << "" << "" << tr("Name") << tr("EMail") << "id" << "fpr"; + mKeyList->setHorizontalHeaderLabels(labels); + mKeyList->horizontalHeader()->setStretchLastSection(true); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(mKeyList); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(3); + setLayout(layout); + + popupMenu = new QMenu(this); + connect(mCtx, SIGNAL(signalKeyDBChanged()), this, SLOT(slotRefresh())); + setAcceptDrops(true); + slotRefresh(); +} + +void KeyList::slotRefresh() +{ + QStringList *keyList; + keyList = getChecked(); + // while filling the table, sort enabled causes errors + mKeyList->setSortingEnabled(false); + mKeyList->clearContents(); + + GpgKeyList keys = mCtx->listKeys(); + mKeyList->setRowCount(keys.size()); + + int row = 0; + GpgKeyList::iterator it = keys.begin(); + while (it != keys.end()) { + + QTableWidgetItem *tmp0 = new QTableWidgetItem(); + tmp0->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); + tmp0->setCheckState(Qt::Unchecked); + mKeyList->setItem(row, 0, tmp0); + + if (it->privkey) { + QTableWidgetItem *tmp1 = new QTableWidgetItem(QIcon(":kgpg_key2.png"), ""); + mKeyList->setItem(row, 1, tmp1); + } + QTableWidgetItem *tmp2 = new QTableWidgetItem(it->name); + tmp2->setToolTip(it->name); + mKeyList->setItem(row, 2, tmp2); + QTableWidgetItem *tmp3 = new QTableWidgetItem(it->email); + tmp3->setToolTip(it->email); + // strike out expired keys + if(it->expired || it->revoked) { + QFont strike = tmp2->font(); + strike.setStrikeOut(true); + tmp2->setFont(strike); + tmp3->setFont(strike); + } + mKeyList->setItem(row, 3, tmp3); + QTableWidgetItem *tmp4 = new QTableWidgetItem(it->id); + mKeyList->setItem(row, 4, tmp4); + QTableWidgetItem *tmp5 = new QTableWidgetItem(it->fpr); + mKeyList->setItem(row, 5, tmp5); + + + it++; + ++row; + } + mKeyList->setSortingEnabled(true); + setChecked(keyList); +} + +QStringList *KeyList::getChecked() +{ + QStringList *ret = new QStringList(); + for (int i = 0; i < mKeyList->rowCount(); i++) { + if (mKeyList->item(i, 0)->checkState() == Qt::Checked) { + *ret << mKeyList->item(i, 4)->text(); + } + } + return ret; +} + +QStringList *KeyList::getAllPrivateKeys() +{ + QStringList *ret = new QStringList(); + for (int i = 0; i < mKeyList->rowCount(); i++) { + if (mKeyList->item(i, 1)) { + *ret << mKeyList->item(i, 4)->text(); + } + } + return ret; +} + +QStringList *KeyList::getPrivateChecked() +{ + QStringList *ret = new QStringList(); + for (int i = 0; i < mKeyList->rowCount(); i++) { + if ((mKeyList->item(i, 0)->checkState() == Qt::Checked) && (mKeyList->item(i, 1))) { + *ret << mKeyList->item(i, 4)->text(); + } + } + return ret; +} + +void KeyList::setChecked(QStringList *keyIds) +{ + if (!keyIds->isEmpty()) { + for (int i = 0; i < mKeyList->rowCount(); i++) { + if (keyIds->contains(mKeyList->item(i, 4)->text())) { + mKeyList->item(i, 0)->setCheckState(Qt::Checked); + } + } + } +} + +QStringList *KeyList::getSelected() +{ + QStringList *ret = new QStringList(); + + for (int i = 0; i < mKeyList->rowCount(); i++) { + if (mKeyList->item(i, 0)->isSelected() == 1) { + *ret << mKeyList->item(i, 4)->text(); + } + } + return ret; +} + +bool KeyList::containsPrivateKeys() +{ + for (int i = 0; i < mKeyList->rowCount(); i++) { + if (mKeyList->item(i, 1)) { + return true; + } + } + return false; +} + +void KeyList::setColumnWidth(int row, int size) +{ + mKeyList->setColumnWidth(row, size); +} + +void KeyList::contextMenuEvent(QContextMenuEvent *event) +{ + popupMenu->exec(event->globalPos()); +} + +void KeyList::addMenuAction(QAction *act) +{ + popupMenu->addAction(act); +} + +void KeyList::dropEvent(QDropEvent* event) +{ +// importKeyDialog(); + QSettings settings; + + QDialog *dialog = new QDialog(); + + dialog->setWindowTitle(tr("Import Keys")); + QLabel *label; + label = new QLabel(tr("You've dropped something on the keylist.\n gpg4usb will now try to import key(s).")+"\n"); + + // "always import keys"-CheckBox + QCheckBox *checkBox = new QCheckBox(tr("Always import without bothering.")); + if (settings.value("general/confirmImportKeys").toBool()) checkBox->setCheckState(Qt::Unchecked); + + // Buttons for ok and cancel + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); + + QVBoxLayout *vbox = new QVBoxLayout(); + vbox->addWidget(label); + vbox->addWidget(checkBox); + vbox->addWidget(buttonBox); + + dialog->setLayout(vbox); + + if (settings.value("general/confirmImportKeys",Qt::Checked).toBool()) + { + dialog->exec(); + if (dialog->result() == QDialog::Rejected) { + return; + } + if (checkBox->isChecked()){ + settings.setValue("general/confirmImportKeys", false); + } else { + settings.setValue("general/confirmImportKeys", true); + + } + } + + if (event->mimeData()->hasUrls()) + { + foreach (QUrl tmp, event->mimeData()->urls()) + { + QFile file; + file.setFileName(tmp.toLocalFile()); + if (!file.open(QIODevice::ReadOnly)) { + qDebug() << tr("Couldn't Open File: ") + tmp.toString(); + } + QByteArray inBuffer = file.readAll(); + this->importKeys(inBuffer); + file.close(); + } + } else { + QByteArray inBuffer(event->mimeData()->text().toUtf8()); + this->importKeys(inBuffer); + } +} + +void KeyList::dragEnterEvent(QDragEnterEvent *event) +{ + event->acceptProposedAction(); +} + +/** set background color for Keys and put them to top + * + */ +void KeyList::markKeys(QStringList *keyIds) +{ + foreach(QString id, *keyIds) { + qDebug() << "marked: " << id; + } +} + +void KeyList::importKeys(QByteArray inBuffer) +{ + GpgImportInformation result = mCtx->importKey(inBuffer); + new KeyImportDetailDialog(mCtx, result, this); +} + +void KeyList::uploadKeyToServer(QByteArray *keys) +{ + QUrl reqUrl("http://localhost:11371/pks/add"); + qnam = new QNetworkAccessManager(this); + + QUrl params; + keys->replace("\n", "%0D%0A") + .replace("(", "%28") + .replace(")", "%29") + .replace("/", "%2F") + .replace(":", "%3A") + .replace("+","%2B") + .replace(' ', '+'); + + params.addEncodedQueryItem("keytext", *keys); + QNetworkRequest req(reqUrl); + + req.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded"); + + QNetworkReply *reply = qnam->post(req,params.encodedQuery()); + connect(reply, SIGNAL(finished()), + this, SLOT(uploadFinished())); + qDebug() << "REQURL: " << reqUrl; + qDebug() << "PARAMS.ENCODED: " << params.toEncoded(); +} + +void KeyList::uploadFinished() +{ + QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender()); + + QByteArray response = reply->readAll(); + qDebug() << "RESPNOSE: " << response.data(); + //reply->readAll(); + qDebug() << "ERROR: " << reply->error(); + if (reply->error()) { + qDebug() << "Error while contacting keyserver!"; + return; + } else { + qDebug() << "Success while contacting keyserver!"; + } + + reply->deleteLater(); + reply = 0; +} diff --git a/src/keylist.h b/src/keylist.h new file mode 100644 index 0000000..0909291 --- /dev/null +++ b/src/keylist.h @@ -0,0 +1,76 @@ +/* + * keylist.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __KEYLIST_H__ +#define __KEYLIST_H__ + +#include "gpgcontext.h" +#include "keyimportdetaildialog.h" +#include <QNetworkAccessManager> +#include <QtNetwork> + +QT_BEGIN_NAMESPACE +class QWidget; +class QVBoxLayout; +class QLabel; +class QTableWidget; +class QMenu; +QT_END_NAMESPACE + +class KeyList : public QWidget +{ + Q_OBJECT + +public: + KeyList(GpgME::GpgContext *ctx, QWidget *parent = 0); + void setColumnWidth(int row, int size); + void addMenuAction(QAction *act); + + QStringList *getChecked(); + QStringList *getPrivateChecked(); + QStringList *getAllPrivateKeys(); + + void setChecked(QStringList *keyIds); + //QStringList *getPrivateChecked(); + QStringList *getSelected(); + void markKeys(QStringList *keyIds); + bool containsPrivateKeys(); + +public slots: + void slotRefresh(); + void uploadKeyToServer(QByteArray *keys); + +private: + void importKeys(QByteArray inBuffer); + GpgME::GpgContext *mCtx; + QTableWidget *mKeyList; + QMenu *popupMenu; + QNetworkAccessManager *qnam; + +private slots: + void uploadFinished(); + +protected: + void contextMenuEvent(QContextMenuEvent *event); + void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent* event);}; + +#endif // __KEYLIST_H__ diff --git a/src/keymgmt.cpp b/src/keymgmt.cpp new file mode 100755 index 0000000..c17fd86 --- /dev/null +++ b/src/keymgmt.cpp @@ -0,0 +1,289 @@ +/* + * + * keymgmt.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "keymgmt.h" + +KeyMgmt::KeyMgmt(GpgME::GpgContext *ctx, QWidget *parent ) : QMainWindow(parent) +{ + mCtx = ctx; + + /* the list of Keys available*/ + mKeyList = new KeyList(mCtx); + mKeyList->setColumnWidth(2, 250); + mKeyList->setColumnWidth(3, 250); + setCentralWidget(mKeyList); + + createActions(); + createMenus(); + createToolBars(); + connect(this,SIGNAL(signalStatusBarChanged(QString)),this->parent(),SLOT(slotSetStatusBarText(QString))); + + /* Restore the iconstyle */ + QSettings settings; + settings.sync(); + QSize iconSize = settings.value("toolbar/iconsize", QSize(32, 32)).toSize(); + Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>(settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon).toUInt()); + this->setIconSize(iconSize); + this->setToolButtonStyle(buttonStyle); + + // state sets pos & size of dock-widgets + this->restoreState(settings.value("keymgmt/windowState").toByteArray()); + + // Restore window size & location + if (settings.value("window/windowSave").toBool()) { + QPoint pos = settings.value("keymgmt/pos", QPoint(100, 100)).toPoint(); + QSize size = settings.value("keymgmt/size", QSize(800, 450)).toSize(); + this->resize(size); + this->move(pos); + } else { + this->resize(QSize(800, 400)); + } + + setWindowTitle(tr("Keymanagement")); + mKeyList->addMenuAction(deleteSelectedKeysAct); + mKeyList->addMenuAction(showKeyDetailsAct); +} + +void KeyMgmt::createActions() +{ + closeAct = new QAction(tr("&Close Key Management"), this); + closeAct->setShortcut(tr("Ctrl+Q")); + closeAct->setIcon(QIcon(":exit.png")); + closeAct->setToolTip(tr("Close Key Management")); + connect(closeAct, SIGNAL(triggered()), this, SLOT(close())); + + importKeyFromFileAct = new QAction(tr("&File"), this); + importKeyFromFileAct->setIcon(QIcon(":import_key_from_file.png")); + importKeyFromFileAct->setToolTip(tr("Import New Key From File")); + connect(importKeyFromFileAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromFile())); + + importKeyFromClipboardAct = new QAction(tr("&Clipboard"), this); + importKeyFromClipboardAct->setIcon(QIcon(":import_key_from_clipboard.png")); + importKeyFromClipboardAct->setToolTip(tr("Import New Key From Clipboard")); + connect(importKeyFromClipboardAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromClipboard())); + + importKeyFromKeyServerAct = new QAction(tr("&Keyserver"), this); + importKeyFromKeyServerAct->setIcon(QIcon(":import_key_from_server.png")); + importKeyFromKeyServerAct->setToolTip(tr("Import New Key From Keyserver")); + connect(importKeyFromKeyServerAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromKeyServer())); + + exportKeyToClipboardAct = new QAction(tr("Export To &Clipboard"), this); + exportKeyToClipboardAct->setIcon(QIcon(":export_key_to_clipboard.png")); + exportKeyToClipboardAct->setToolTip(tr("Export Selected Key(s) To Clipboard")); + connect(exportKeyToClipboardAct, SIGNAL(triggered()), this, SLOT(slotExportKeyToClipboard())); + + exportKeyToFileAct = new QAction(tr("Export To &File"), this); + exportKeyToFileAct->setIcon(QIcon(":export_key_to_file.png")); + exportKeyToFileAct->setToolTip(tr("Export Selected Key(s) To File")); + connect(exportKeyToFileAct, SIGNAL(triggered()), this, SLOT(slotExportKeyToFile())); + + deleteSelectedKeysAct = new QAction(tr("Delete Selected Key(s)"), this); + deleteSelectedKeysAct->setToolTip(tr("Delete the Selected keys")); + connect(deleteSelectedKeysAct, SIGNAL(triggered()), this, SLOT(slotDeleteSelectedKeys())); + + deleteCheckedKeysAct = new QAction(tr("Delete Checked Key(s)"), this); + deleteCheckedKeysAct->setToolTip(tr("Delete the Checked keys")); + deleteCheckedKeysAct->setIcon(QIcon(":button_cancel.png")); + connect(deleteCheckedKeysAct, SIGNAL(triggered()), this, SLOT(slotDeleteCheckedKeys())); + + generateKeyDialogAct = new QAction(tr("Generate Key"), this); + generateKeyDialogAct->setToolTip(tr("Generate New Key")); + generateKeyDialogAct->setIcon(QIcon(":key_generate.png")); + connect(generateKeyDialogAct, SIGNAL(triggered()), this, SLOT(slotGenerateKeyDialog())); + + showKeyDetailsAct = new QAction(tr("Show Keydetails"), this); + showKeyDetailsAct->setToolTip(tr("Show Details for this Key")); + connect(showKeyDetailsAct, SIGNAL(triggered()), this, SLOT(slotShowKeyDetails())); +} + +void KeyMgmt::createMenus() +{ + fileMenu = menuBar()->addMenu(tr("&File")); + fileMenu->addAction(closeAct); + + keyMenu = menuBar()->addMenu(tr("&Key")); + importKeyMenu = keyMenu->addMenu(tr("&Import Key From...")); + importKeyMenu->addAction(importKeyFromFileAct); + importKeyMenu->addAction(importKeyFromClipboardAct); + importKeyMenu->addAction(importKeyFromKeyServerAct); + keyMenu->addAction(exportKeyToFileAct); + keyMenu->addAction(exportKeyToClipboardAct); + keyMenu->addSeparator(); + keyMenu->addAction(deleteCheckedKeysAct); + keyMenu->addAction(generateKeyDialogAct); +} + +void KeyMgmt::createToolBars() +{ + QToolBar *keyToolBar = addToolBar(tr("Key")); + keyToolBar->setObjectName("keytoolbar"); + + // add button with popup menu for import + QToolButton* toolButton = new QToolButton(this); + toolButton->setMenu(importKeyMenu); + toolButton->setPopupMode(QToolButton::InstantPopup); + toolButton->setIcon(QIcon(":key_import.png")); + toolButton->setToolTip(tr("Import key")); + toolButton->setText(tr("Import key from")); + toolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + keyToolBar->addWidget(toolButton); + + keyToolBar->addSeparator(); + keyToolBar->addAction(deleteCheckedKeysAct); + keyToolBar->addSeparator(); + keyToolBar->addAction(exportKeyToFileAct); + keyToolBar->addAction(exportKeyToClipboardAct); + +} + +void KeyMgmt::slotImportKeys(QByteArray inBuffer) +{ + GpgImportInformation result = mCtx->importKey(inBuffer); + new KeyImportDetailDialog(mCtx, result, this); + +} + +void KeyMgmt::slotImportKeyFromFile() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Open Key"), "", tr("Key Files") + " (*.asc *.txt);;"+tr("Keyring files")+" (*.gpg);;All Files (*)"); + if (! fileName.isNull()) { + QFile file; + file.setFileName(fileName); + if (!file.open(QIODevice::ReadOnly)) { + qDebug() << tr("Couldn't Open File: ") + fileName; + return; + } + QByteArray inBuffer = file.readAll(); + slotImportKeys(inBuffer); + file.close(); + } +} + +void KeyMgmt::slotImportKeyFromKeyServer() +{ + importDialog = new KeyServerImportDialog(mCtx, mKeyList, this); + importDialog->show(); +} + +void KeyMgmt::slotImportKeyFromClipboard() +{ + QClipboard *cb = QApplication::clipboard(); + slotImportKeys(cb->text(QClipboard::Clipboard).toAscii()); +} + +void KeyMgmt::slotDeleteSelectedKeys() +{ + deleteKeysWithWarning(mKeyList->getSelected()); +} + +void KeyMgmt::slotDeleteCheckedKeys() +{ + deleteKeysWithWarning(mKeyList->getChecked()); +} + +void KeyMgmt::deleteKeysWithWarning(QStringList *uidList) +{ + /** + * TODO: Different Messages for private/public key, check if + * more than one selected... compare to seahorse "delete-dialog" + */ + + if (uidList->isEmpty()) { + return; + } + QString keynames; + foreach (QString uid, *uidList) { + keynames.append(QString::fromUtf8(mCtx->getKeyDetails(uid)->uids->name)); + keynames.append("<i> <"); + keynames.append(QString::fromUtf8(mCtx->getKeyDetails(uid)->uids->email)); + keynames.append("> </i><br/>"); + } + + int ret = QMessageBox::warning(this, tr("Deleting Keys"), + "<b>"+tr("Are you sure that you want to delete the following keys?")+"</b><br/><br/>"+keynames+ + +"<br/>"+tr("The action can not be undone."), + QMessageBox::No | QMessageBox::Yes); + + if (ret == QMessageBox::Yes) { + mCtx->deleteKeys(uidList); + } +} + +void KeyMgmt::slotShowKeyDetails() +{ + if (mKeyList->getSelected()->isEmpty()) { + return; + } + + // TODO: first...? + gpgme_key_t key = mCtx->getKeyDetails(mKeyList->getSelected()->first()); + + new KeyDetailsDialog(mCtx, key); +} + +void KeyMgmt::slotExportKeyToFile() +{ + QByteArray *keyArray = new QByteArray(); + if (!mCtx->exportKeys(mKeyList->getChecked(), keyArray)) { + return; + } + gpgme_key_t key = mCtx->getKeyDetails(mKeyList->getChecked()->first()); + QString fileString = QString::fromUtf8(key->uids->name) + " " + QString::fromUtf8(key->uids->email) + "(" + QString(key->subkeys->keyid)+ ")_pub.asc"; + + QString fileName = QFileDialog::getSaveFileName(this, tr("Export Key To File"), fileString, tr("Key Files") + " (*.asc *.txt);;All Files (*)"); + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) + return; + QTextStream stream(&file); + stream << *keyArray; + file.close(); + delete keyArray; + emit signalStatusBarChanged(QString(tr("key(s) exported"))); +} + +void KeyMgmt::slotExportKeyToClipboard() +{ + QByteArray *keyArray = new QByteArray(); + QClipboard *cb = QApplication::clipboard(); + if (!mCtx->exportKeys(mKeyList->getChecked(), keyArray)) { + return; + } + cb->setText(*keyArray); + delete keyArray; +} + +void KeyMgmt::slotGenerateKeyDialog() +{ + KeyGenDialog *keyGenDialog = new KeyGenDialog(mCtx,this); + keyGenDialog->show(); +} + +void KeyMgmt::closeEvent(QCloseEvent *event) +{ + QSettings settings; + //settings.setValue("geometry", saveGeometry()); + settings.setValue("keymgmt/windowState", saveState()); + settings.setValue("keymgmt/pos", pos()); + settings.setValue("keymgmt/size", size()); + + QMainWindow::closeEvent(event); +} diff --git a/src/keymgmt.h b/src/keymgmt.h new file mode 100755 index 0000000..22a8b66 --- /dev/null +++ b/src/keymgmt.h @@ -0,0 +1,92 @@ +/* + * keymgmt.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __KEYMGMT_H__ +#define __KEYMGMT_H__ + +#include "keylist.h" +#include "keygenthread.h" +#include "keydetailsdialog.h" +#include "keyimportdetaildialog.h" +#include "keyserverimportdialog.h" +#include "keygendialog.h" +#include <QtGui> + +QT_BEGIN_NAMESPACE +class QMainWindow; +class iostream; +class QFileDialog; +class QIcon; +class QAction; +class QApplication; +QT_END_NAMESPACE + +class KeyMgmt : public QMainWindow +{ + Q_OBJECT + +public: + KeyMgmt(GpgME::GpgContext* ctx, QWidget *parent = 0); + QAction *importKeyFromClipboardAct; + QAction *importKeyFromFileAct; + QAction *importKeyFromKeyServerAct; + +public slots: + void slotImportKeyFromFile(); + void slotImportKeyFromClipboard(); + void slotImportKeyFromKeyServer(); + void slotImportKeys(QByteArray inBuffer); + void slotExportKeyToFile(); + void slotExportKeyToClipboard(); + void slotDeleteSelectedKeys(); + void slotDeleteCheckedKeys(); + void slotGenerateKeyDialog(); + void slotShowKeyDetails(); + +signals: + void signalStatusBarChanged(QString); + +private: + void createMenus(); + void createActions(); + void createToolBars(); + void deleteKeysWithWarning(QStringList *uidList); + + KeyList *mKeyList; + GpgME::GpgContext *mCtx; + QMenu *fileMenu; + QMenu *keyMenu; + QMenu *importKeyMenu; + QAction *exportKeyToFileAct; + QAction *exportKeyToClipboardAct; + QAction *deleteCheckedKeysAct; + QAction *deleteSelectedKeysAct; + QAction *generateKeyDialogAct; + QAction *closeAct; + QAction *showKeyDetailsAct; + QMessageBox msgbox; + KeyServerImportDialog *importDialog; + +protected: + void closeEvent(QCloseEvent *event); +}; + +#endif // __KEYMGMT_H__ diff --git a/src/keyserverimportdialog.cpp b/src/keyserverimportdialog.cpp new file mode 100644 index 0000000..819dfc0 --- /dev/null +++ b/src/keyserverimportdialog.cpp @@ -0,0 +1,313 @@ +/* + * + * keyserverimportdialog.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "keyserverimportdialog.h" + +KeyServerImportDialog::KeyServerImportDialog(GpgME::GpgContext *ctx, KeyList *keyList, QWidget *parent) + : QDialog(parent) +{ + mCtx = ctx; + mKeyList = keyList; + // Buttons + closeButton = createButton(tr("&Close"), SLOT(close())); + importButton = createButton(tr("&Import"), SLOT(slotImport())); + searchButton = createButton(tr("&Search"), SLOT(slotSearch())); + + // Line edit for search string + searchLabel = new QLabel(tr("Search string:")); + searchLineEdit = new QLineEdit(); + + // combobox for keyserverlist + keyServerLabel = new QLabel(tr("Keyserver:")); + keyServerComboBox = createComboBox(); + + // table containing the keys found + createKeysTable(); + message = new QLabel; + icon = new QLabel; + + // Layout for messagebox + QHBoxLayout *messageLayout= new QHBoxLayout; + messageLayout->addWidget(icon); + messageLayout->addWidget(message); + messageLayout->addStretch(); + + // Layout for import and close button + QHBoxLayout *buttonsLayout = new QHBoxLayout; + buttonsLayout->addStretch(); + buttonsLayout->addWidget(importButton); + buttonsLayout->addWidget(closeButton); + + QGridLayout *mainLayout = new QGridLayout; + mainLayout->addWidget(searchLabel, 1, 0); + mainLayout->addWidget(searchLineEdit, 1, 1); + mainLayout->addWidget(searchButton,1, 2); + mainLayout->addWidget(keyServerLabel, 2, 0); + mainLayout->addWidget(keyServerComboBox, 2, 1); + mainLayout->addWidget(keysTable, 3, 0, 1, 3); + mainLayout->addLayout(messageLayout, 4, 0, 1, 3); + mainLayout->addLayout(buttonsLayout, 5, 0, 1, 3); + + this->setLayout(mainLayout); + this->setWindowTitle(tr("Import Keys from Keyserver")); + this->resize(700, 300); + this->setModal(true); +} + +QPushButton *KeyServerImportDialog::createButton(const QString &text, const char *member) +{ + QPushButton *button = new QPushButton(text); + connect(button, SIGNAL(clicked()), this, member); + return button; +} + +QComboBox *KeyServerImportDialog::createComboBox() +{ + QComboBox *comboBox = new QComboBox; + comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + + // Read keylist from ini-file and fill it into combobox + QSettings settings; + comboBox->addItems(settings.value("keyserver/keyServerList").toStringList()); + + // set default keyserver in combobox + QString keyserver = settings.value("keyserver/defaultKeyServer").toString(); + comboBox->setCurrentIndex(comboBox->findText(keyserver)); + + return comboBox; +} + +void KeyServerImportDialog::createKeysTable() +{ + keysTable = new QTableWidget(); + keysTable->setColumnCount(4); + + // always a whole row is marked + keysTable->setSelectionBehavior(QAbstractItemView::SelectRows); + keysTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + + // Make just one row selectable + keysTable->setSelectionMode(QAbstractItemView::SingleSelection); + + QStringList labels; + labels << tr("UID") << tr("Creation date") << tr("KeyID") << tr("Tag"); + keysTable->horizontalHeader()->setResizeMode(0, QHeaderView::ResizeToContents); + keysTable->setHorizontalHeaderLabels(labels); + keysTable->verticalHeader()->hide(); + + connect(keysTable, SIGNAL(cellActivated(int,int)), + this, SLOT(slotImport())); +} + +void KeyServerImportDialog::setMessage(const QString &text, bool error) +{ + message->setText(text); + if (error) { + QIcon undoicon = QIcon::fromTheme("dialog-error"); + QPixmap pixmap = undoicon.pixmap(QSize(32,32),QIcon::Normal,QIcon::On); + icon->setPixmap(pixmap); + } else { + QIcon undoicon = QIcon::fromTheme("dialog-information"); + QPixmap pixmap = undoicon.pixmap(QSize(32,32),QIcon::Normal,QIcon::On); + icon->setPixmap(pixmap); + } +} + +void KeyServerImportDialog::slotSearch() +{ + QUrl url = keyServerComboBox->currentText()+":11371/pks/lookup?search="+searchLineEdit->text()+"&op=index&options=mr"; + qnam = new QNetworkAccessManager(this); + QNetworkReply* reply = qnam->get(QNetworkRequest(url)); + connect(reply, SIGNAL(finished()), + this, SLOT(slotSearchFinished())); +} + +void KeyServerImportDialog::slotSearchFinished() +{ + QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender()); + + keysTable->clearContents(); + keysTable->setRowCount(0); + QString firstLine = QString(reply->readLine(1024)); + + QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); + if (reply->error()) { + setMessage(tr("Couldn't contact keyserver!"),true); + //setMessage(reply->error()); + qDebug() << reply->error(); + } + if (firstLine.contains("Error")) + { + QString text= QString(reply->readLine(1024)); + if (text.contains("Too many responses")) { + setMessage(tr("Too many responses from keyserver!"),true); + } else if (text.contains("No keys found")) { + // if string looks like hex string, search again with 0x prepended + QRegExp rx("[0-9A-Fa-f]*"); + QString query = searchLineEdit->text(); + if (rx.exactMatch(query)) { + setMessage(tr("No keys found, input may be kexId, retrying search with 0x."),true); + searchLineEdit->setText(query.prepend("0x")); + this->slotSearch(); + } else { + setMessage(tr("No keys found containing the search string!"),true); + } + } else if (text.contains("Insufficiently specific words")) { + setMessage(tr("Insufficiently specific search string!"),true); + } else { + setMessage(text, true); + } + } else { + int row = 0; + char buff[1024]; + bool strikeout=false; + while (reply->readLine(buff,sizeof(buff)) !=-1) { + QString decoded = QString::fromUtf8(QByteArray::fromPercentEncoding(buff)); + QStringList line = decoded.split(":"); + + //TODO: have a look at two following pub lines + if (line[0] == "pub") { + strikeout=false; + + QString flags = line[line.size()-1]; + + keysTable->setRowCount(row+1); + + // flags can be "d" for disabled, "r" for revoked + // or "e" for expired + if (flags.contains("r") or flags.contains("d") or flags.contains("e")) { + strikeout=true; + if (flags.contains("e")) { + keysTable->setItem(row, 3, new QTableWidgetItem( QString("expired"))); + } + if (flags.contains("r")) { + keysTable->setItem(row, 3, new QTableWidgetItem( QString(tr("revoked")))); + } + if (flags.contains("d")) { + keysTable->setItem(row, 3, new QTableWidgetItem( QString(tr("disabled")))); + } + } + + QStringList line2 = QString(reply->readLine()).split(":"); + + QTableWidgetItem *uid = new QTableWidgetItem(); + if (line2.size() > 1) { + uid->setText(line2[1]); + keysTable->setItem(row, 0, uid); + } + QTableWidgetItem *creationdate = new QTableWidgetItem(QDateTime::fromTime_t(line[4].toInt()).toString("dd. MMM. yyyy")); + keysTable->setItem(row, 1, creationdate); + QTableWidgetItem *keyid = new QTableWidgetItem(line[1]); + keysTable->setItem(row, 2, keyid); + if (strikeout) { + QFont strike = uid->font(); + strike.setStrikeOut(true); + uid->setFont(strike); + creationdate->setFont(strike); + keyid->setFont(strike); + } + row++; + } else { + if (line[0] == "uid") { + QStringList l; + int height=keysTable->rowHeight(row-1); + keysTable->setRowHeight(row-1,height+16); + QString tmp=keysTable->item(row-1,0)->text(); + tmp.append(QString("\n")+line[1]); + QTableWidgetItem *tmp1 = new QTableWidgetItem(tmp); + keysTable->setItem(row-1,0,tmp1); + if (strikeout) { + QFont strike = tmp1->font(); + strike.setStrikeOut(true); + tmp1->setFont(strike); + } + } + } + setMessage(tr("%1 keys found. Doubleclick a key to import it.").arg(row),false); + } + keysTable->resizeColumnsToContents(); + } + reply->deleteLater(); + reply = 0; +} + +void KeyServerImportDialog::slotImport() +{ + if ( keysTable->currentRow() > -1 ) { + QString keyid = keysTable->item(keysTable->currentRow(),2)->text(); + QUrl url = keyServerComboBox->currentText(); + slotImport(QStringList(keyid), url); + } +} + +void KeyServerImportDialog::slotImport(QStringList keyIds) +{ + QSettings settings; + QString keyserver=settings.value("keyserver/defaultKeyServer").toString(); + QUrl url(keyserver); + slotImport(keyIds, url); +} + + +void KeyServerImportDialog::slotImport(QStringList keyIds, QUrl keyServerUrl) +{ + foreach(QString keyId, keyIds) { + QUrl reqUrl(keyServerUrl.scheme() + "://" + keyServerUrl.host() + ":11371/pks/lookup?op=get&search=0x"+keyId+"&options=mr"); + //qDebug() << "req to " << reqUrl; + qnam = new QNetworkAccessManager(this); + QNetworkReply *reply = qnam->get(QNetworkRequest(reqUrl)); + connect(reply, SIGNAL(finished()), + this, SLOT(slotImportFinished())); + } +} + +void KeyServerImportDialog::slotImportFinished() +{ + QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender()); + + QByteArray key = reply->readAll(); + + QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); + if (reply->error()) { + setMessage(tr("Error while contacting keyserver!"),true); + return; + } + this->importKeys(key.constData()); + setMessage(tr("Key imported"),false); + + // Add keyserver to list in config-file, if it isn't contained + QSettings settings; + QStringList keyServerList = settings.value("keyserver/keyServerList").toStringList(); + if (!keyServerList.contains(keyServerComboBox->currentText())) + { + keyServerList.append(keyServerComboBox->currentText()); + settings.setValue("keyserver/keyServerList", keyServerList); + } + reply->deleteLater(); + reply = 0; +} + +void KeyServerImportDialog::importKeys(QByteArray inBuffer) +{ + GpgImportInformation result = mCtx->importKey(inBuffer); + new KeyImportDetailDialog(mCtx, result, this); +} diff --git a/src/keyserverimportdialog.h b/src/keyserverimportdialog.h new file mode 100644 index 0000000..b33af57 --- /dev/null +++ b/src/keyserverimportdialog.h @@ -0,0 +1,89 @@ +/* + * + * keyserverimportdialog.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __KEYSERVERIMPORTDIALOG_H__ +#define __KEYSERVERIMPORTDIALOG_H__ + +#include "gpgcontext.h" +#include "keyimportdetaildialog.h" +#include "keylist.h" +#include <QNetworkAccessManager> +#include <QtNetwork> + +QT_BEGIN_NAMESPACE +class QDialog; +class QDir; +class QUrl; +class QtGui; +class QPixmap; +class QNetworkReply; +class QComboBox; +class QLabel; +class QPushButton; +class QTableWidget; +class QTableWidgetItem; +class QLineEdit; +class QPalette; +class QTreeWidget; +class QTreeWidgetItem; +QT_END_NAMESPACE + +class KeyServerImportDialog : public QDialog +{ + Q_OBJECT + +public: + KeyServerImportDialog(GpgME::GpgContext *ctx, KeyList *keyList, QWidget *parent = 0); + void slotImport(QStringList keyIds); + void slotImport(QStringList keyIds, QUrl keyserverUrl); + +private slots: + void slotImport(); + void slotSearchFinished(); + void slotImportFinished(); + void slotSearch(); + +private: + void createKeysTable(); + void setMessage(const QString &text, bool error); + void close(); + void importKeys(QByteArray inBuffer); + + QPushButton *createButton(const QString &text, const char *member); + QComboBox *createComboBox(); + GpgME::GpgContext *mCtx; + KeyList *mKeyList; + QLineEdit *searchLineEdit; + QComboBox *keyServerComboBox; + QLabel *searchLabel; + QLabel *keyServerLabel; + QLabel *message; + QLabel *icon; + QPushButton *closeButton; + QPushButton *importButton; + QPushButton *searchButton; + QTableWidget *keysTable; + QUrl url; + QNetworkAccessManager *qnam; + +}; +#endif // __KEYSERVERIMPORTDIALOG_H__ diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..019466b --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,121 @@ +/* + * main.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include <QApplication> +#include "mainwindow.h" +#include "gpgconstants.h" + +int main(int argc, char *argv[]) +{ + + Q_INIT_RESOURCE(gpg4usb); + + QApplication app(argc, argv); + + // get application path + QString appPath = qApp->applicationDirPath(); + + app.setApplicationVersion("0.3.3"); + app.setApplicationName("gpg4usb"); + + // dont show icons in menus + app.setAttribute(Qt::AA_DontShowIconsInMenus); + + // unicode in source + QTextCodec::setCodecForTr(QTextCodec::codecForName("utf-8")); + + // set environment variables + // TODO: + // - unsetenv on windows? + // - wputenv or wputenv_s on windows? http://msdn.microsoft.com/en-us/library/d6dtz42k(v=vs.80).aspx + #ifndef _WIN32 + // do not use GPG_AGENTS like seahorse, because they may save + // a password an pc's not owned by user + unsetenv("GPG_AGENT_INFO"); + #endif + +// qDebug() << getenv("GNUPGHOME"); + +#ifndef GPG4USB_NON_PORTABLE + // take care of gpg not creating directorys on harddisk + putenv(QString("GNUPGHOME=" + appPath + "/keydb").toAscii().data()); + + // this may help with newer gpgme versions on windows + //putenv(QString("GPGME_GPGPATH=" + appPath.replace("/", "\\") + "\\bin\\gpg.exe").toAscii().data()); + + // QSettings uses org-name for automatically setting path... + app.setOrganizationName("conf"); + + // specify default path & format for QSettings + QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, appPath); +#else + // in non portable conf should go to ~/.conf/gpg4usb + app.setOrganizationName("gpg4usb"); + qDebug() << "gpg4usb non portable build"; +#endif + + /*QLocale ql(lang); + foreach(QLocale l , QLocale::matchingLocales(ql.language(), ql.script(), ql.country())) { + qDebug() << "l: " << l.bcp47Name(); + }*/ + + // css + QFile file(qApp->applicationDirPath() + "/css/default.css"); + file.open(QFile::ReadOnly); + QString styleSheet = QLatin1String(file.readAll()); + qApp->setStyleSheet(styleSheet); + file.close(); + + /** + * internationalisation. loop to restart mainwindow + * with changed translation when settings change. + */ + QSettings::setDefaultFormat(QSettings::IniFormat); + QSettings settings; + QTranslator translator, translator2; + int return_from_event_loop_code; + + do { + app.removeTranslator(&translator); + app.removeTranslator(&translator2); + + QString lang = settings.value("int/lang", QLocale::system().name()).toString(); + if (lang.isEmpty()) { + lang = QLocale::system().name(); + } + + translator.load("ts/gpg4usb_" + lang, appPath); + app.installTranslator(&translator); + + // set qt translations + translator2.load("ts/qt_" + lang, appPath); + app.installTranslator(&translator2); + + MainWindow window; + return_from_event_loop_code = app.exec(); + + } while( return_from_event_loop_code == RESTART_CODE); + + return return_from_event_loop_code; +} + + + diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp new file mode 100644 index 0000000..6e00eb9 --- /dev/null +++ b/src/mainwindow.cpp @@ -0,0 +1,1043 @@ +/* + * mainwindow.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "mainwindow.h" + +MainWindow::MainWindow() +{ + mCtx = new GpgME::GpgContext(); + + /* get path were app was started */ + setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); + setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); + + edit = new TextEdit(); + setCentralWidget(edit); + + /* the list of Keys available*/ + mKeyList = new KeyList(mCtx); + + /* List of binary Attachments */ + attachmentDockCreated = false; + + /* Variable containing if restart is needed */ + this->slotSetRestartNeeded(false); + + keyMgmt = new KeyMgmt(mCtx, this); + keyMgmt->hide(); + /* test attachmentdir for files alll 15s */ + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(slotCheckAttachmentFolder())); + timer->start(5000); + + createActions(); + createMenus(); + createToolBars(); + createStatusBar(); + createDockWindows(); + + connect(edit->tabWidget,SIGNAL(currentChanged(int)),this,SLOT(slotDisableTabActions(int))); + + mKeyList->addMenuAction(appendSelectedKeysAct); + mKeyList->addMenuAction(copyMailAddressToClipboardAct); + mKeyList->addMenuAction(showKeyDetailsAct); + mKeyList->addMenuAction(refreshKeysFromKeyserverAct); + mKeyList->addMenuAction(uploadKeyToServerAct); + + restoreSettings(); + + // open filename if provided as first command line parameter + QStringList args = qApp->arguments(); + if (args.size() > 1) { + if (!args[1].startsWith("-")) { + if (QFile::exists(args[1])) + edit->loadFile(args[1]); + } + } + edit->curTextPage()->setFocus(); + this->setWindowTitle(qApp->applicationName()); + this->show(); + + // Show wizard, if the don't show wizard message box wasn't checked + // and keylist doesn't contain a private key + QSettings settings; + if (settings.value("wizard/showWizard",true).toBool() || !settings.value("wizard/nextPage").isNull()) { + slotStartWizard(); + } +} + +void MainWindow::restoreSettings() +{ + // state sets pos & size of dock-widgets + this->restoreState(settings.value("window/windowState").toByteArray()); + + // Restore window size & location + if (settings.value("window/windowSave").toBool()) { + QPoint pos = settings.value("window/pos", QPoint(100, 100)).toPoint(); + QSize size = settings.value("window/size", QSize(800, 450)).toSize(); + this->resize(size); + this->move(pos); + } else { + this->resize(QSize(800, 450)); + this->move(QPoint(100, 100)); + } + + // Iconsize + QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize(); + this->setIconSize(iconSize); + + importButton->setIconSize(iconSize); + fileEncButton->setIconSize(iconSize); + // set list of keyserver if not defined + QStringList *keyServerDefaultList; + keyServerDefaultList = new QStringList("http://pgp.mit.edu"); + keyServerDefaultList->append("http://pool.sks-keyservers.net"); + keyServerDefaultList->append("http://subkeys.pgp.net"); + + QStringList keyServerList = settings.value("keyserver/keyServerList", *keyServerDefaultList).toStringList(); + settings.setValue("keyserver/keyServerList", keyServerList); + + // set default keyserver, if it's not set + QString defaultKeyServer = settings.value("keyserver/defaultKeyServer", QString("http://pgp.mit.edu")).toString(); + settings.setValue("keyserver/defaultKeyServer", defaultKeyServer); + + // Iconstyle + Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>(settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon).toUInt()); + this->setToolButtonStyle(buttonStyle); + importButton->setToolButtonStyle(buttonStyle); + fileEncButton->setToolButtonStyle(buttonStyle); + + // Checked Keys + if (settings.value("keys/keySave").toBool()) { + QStringList keyIds = settings.value("keys/keyList").toStringList(); + mKeyList->setChecked(&keyIds); + } +} + +void MainWindow::saveSettings() +{ + // window position and size + settings.setValue("window/windowState", saveState()); + settings.setValue("window/pos", pos()); + settings.setValue("window/size", size()); + + // keyid-list of private checked keys + if (settings.value("keys/keySave").toBool()) { + QStringList *keyIds = mKeyList->getPrivateChecked(); + if (!keyIds->isEmpty()) { + settings.setValue("keys/keyList", *keyIds); + } else { + settings.setValue("keys/keyList", ""); + } + } else { + settings.remove("keys/keyList"); + } +} + +void MainWindow::createActions() +{ + /* Main Menu + */ + newTabAct = new QAction(tr("&New"), this); + newTabAct->setIcon(QIcon(":misc_doc.png")); + QList<QKeySequence> newTabActShortcutList; + newTabActShortcutList.append(QKeySequence (Qt::CTRL + Qt::Key_N)); + newTabActShortcutList.append(QKeySequence (Qt::CTRL + Qt::Key_T)); + newTabAct->setShortcuts(newTabActShortcutList); + newTabAct->setToolTip(tr("Open a new file")); + connect(newTabAct, SIGNAL(triggered()), edit, SLOT(slotNewTab())); + + openAct = new QAction(tr("&Open..."), this); + openAct->setIcon(QIcon(":fileopen.png")); + openAct->setShortcut(QKeySequence::Open); + openAct->setToolTip(tr("Open an existing file")); + connect(openAct, SIGNAL(triggered()), edit, SLOT(slotOpen())); + + saveAct = new QAction(tr("&Save"), this); + saveAct->setIcon(QIcon(":filesave.png")); + saveAct->setShortcut(QKeySequence::Save); + saveAct->setToolTip(tr("Save the current File")); + connect(saveAct, SIGNAL(triggered()), edit, SLOT(slotSave())); + + saveAsAct = new QAction(tr("Save &As")+"...", this); + saveAsAct->setIcon(QIcon(":filesaveas.png")); + saveAsAct->setShortcut(QKeySequence::SaveAs); + saveAsAct->setToolTip(tr("Save the current File as...")); + connect(saveAsAct, SIGNAL(triggered()), edit, SLOT(slotSaveAs())); + + printAct = new QAction(tr("&Print"), this); + printAct->setIcon(QIcon(":fileprint.png")); + printAct->setShortcut(QKeySequence::Print); + printAct->setToolTip(tr("Print Document")); + connect(printAct, SIGNAL(triggered()), edit, SLOT(slotPrint())); + + closeTabAct = new QAction(tr("&Close"), this); + closeTabAct->setShortcut(QKeySequence::Close); + closeTabAct->setToolTip(tr("Close file")); + connect(closeTabAct, SIGNAL(triggered()), edit, SLOT(slotCloseTab())); + + quitAct = new QAction(tr("&Quit"), this); + quitAct->setShortcut(QKeySequence::Quit); + quitAct->setIcon(QIcon(":exit.png")); + quitAct->setToolTip(tr("Quit Program")); + connect(quitAct, SIGNAL(triggered()), this, SLOT(close())); + + /* Edit Menu + */ + undoAct = new QAction(tr("&Undo"), this); + undoAct->setShortcut(QKeySequence::Undo); + undoAct->setToolTip(tr("Undo Last Edit Action")); + connect(undoAct, SIGNAL(triggered()), edit, SLOT(slotUndo())); + + redoAct = new QAction(tr("&Redo"), this); + redoAct->setShortcut(QKeySequence::Redo); + redoAct->setToolTip(tr("Redo Last Edit Action")); + connect(redoAct, SIGNAL(triggered()), edit, SLOT(slotRedo())); + + zoomInAct = new QAction(tr("Zoom In"), this); + zoomInAct->setShortcut(QKeySequence::ZoomIn); + connect(zoomInAct, SIGNAL(triggered()), edit, SLOT(slotZoomIn())); + + zoomOutAct = new QAction(tr("Zoom Out"), this); + zoomOutAct->setShortcut(QKeySequence::ZoomOut); + connect(zoomOutAct, SIGNAL(triggered()), edit, SLOT(slotZoomOut())); + + pasteAct = new QAction(tr("&Paste"), this); + pasteAct->setIcon(QIcon(":button_paste.png")); + pasteAct->setShortcut(QKeySequence::Paste); + pasteAct->setToolTip(tr("Paste Text From Clipboard")); + connect(pasteAct, SIGNAL(triggered()), edit, SLOT(slotPaste())); + + cutAct = new QAction(tr("Cu&t"), this); + cutAct->setIcon(QIcon(":button_cut.png")); + cutAct->setShortcut(QKeySequence::Cut); + cutAct->setToolTip(tr("Cut the current selection's contents to the " + "clipboard")); + connect(cutAct, SIGNAL(triggered()), edit, SLOT(slotCut())); + + copyAct = new QAction(tr("&Copy"), this); + copyAct->setIcon(QIcon(":button_copy.png")); + copyAct->setShortcut(QKeySequence::Copy); + copyAct->setToolTip(tr("Copy the current selection's contents to the " + "clipboard")); + connect(copyAct, SIGNAL(triggered()), edit, SLOT(slotCopy())); + + quoteAct = new QAction(tr("&Quote"), this); + quoteAct->setIcon(QIcon(":quote.png")); + quoteAct->setToolTip(tr("Quote whole text")); + connect(quoteAct, SIGNAL(triggered()), edit, SLOT(slotQuote())); + + selectallAct = new QAction(tr("Select &All"), this); + selectallAct->setIcon(QIcon(":edit.png")); + selectallAct->setShortcut(QKeySequence::SelectAll); + selectallAct->setToolTip(tr("Select the whole text")); + connect(selectallAct, SIGNAL(triggered()), edit, SLOT(slotSelectAll())); + + findAct = new QAction(tr("&Find"), this); + findAct->setShortcut(QKeySequence::Find); + findAct->setToolTip(tr("Find a word")); + connect(findAct, SIGNAL(triggered()), this, SLOT(slotFind())); + + cleanDoubleLinebreaksAct = new QAction(tr("Remove &spacing"), this); + cleanDoubleLinebreaksAct->setIcon(QIcon(":format-line-spacing-triple.png")); + //cleanDoubleLineBreaksAct->setShortcut(QKeySequence::SelectAll); + cleanDoubleLinebreaksAct->setToolTip(tr("Remove double linebreaks, e.g. in pasted text from webmailer")); + connect(cleanDoubleLinebreaksAct, SIGNAL(triggered()), this, SLOT(slotCleanDoubleLinebreaks())); + + openSettingsAct = new QAction(tr("Se&ttings"), this); + openSettingsAct->setToolTip(tr("Open settings dialog")); + openSettingsAct->setShortcut(QKeySequence::Preferences); + connect(openSettingsAct, SIGNAL(triggered()), this, SLOT(slotOpenSettingsDialog())); + + /* Crypt Menu + */ + encryptAct = new QAction(tr("&Encrypt"), this); + encryptAct->setIcon(QIcon(":encrypted.png")); + encryptAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); + encryptAct->setToolTip(tr("Encrypt Message")); + connect(encryptAct, SIGNAL(triggered()), this, SLOT(slotEncrypt())); + + decryptAct = new QAction(tr("&Decrypt"), this); + decryptAct->setIcon(QIcon(":decrypted.png")); + decryptAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D)); + decryptAct->setToolTip(tr("Decrypt Message")); + connect(decryptAct, SIGNAL(triggered()), this, SLOT(slotDecrypt())); + + /* + * File encryption submenu + */ + fileEncryptAct = new QAction(tr("&Encrypt File"), this); + fileEncryptAct->setToolTip(tr("Encrypt File")); + connect(fileEncryptAct, SIGNAL(triggered()), this, SLOT(slotFileEncrypt())); + + fileDecryptAct = new QAction(tr("&Decrypt File"), this); + fileDecryptAct->setToolTip(tr("Decrypt File")); + connect(fileDecryptAct, SIGNAL(triggered()), this, SLOT(slotFileDecrypt())); + + fileSignAct = new QAction(tr("&Sign File"), this); + fileSignAct->setToolTip(tr("Sign File")); + connect(fileSignAct, SIGNAL(triggered()), this, SLOT(slotFileSign())); + + fileVerifyAct = new QAction(tr("&Verify File"), this); + fileVerifyAct->setToolTip(tr("Verify File")); + connect(fileVerifyAct, SIGNAL(triggered()), this, SLOT(slotFileVerify())); + + + signAct = new QAction(tr("&Sign"), this); + signAct->setIcon(QIcon(":signature.png")); + signAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I)); + signAct->setToolTip(tr("Sign Message")); + connect(signAct, SIGNAL(triggered()), this, SLOT(slotSign())); + + verifyAct = new QAction(tr("&Verify"), this); + verifyAct->setIcon(QIcon(":verify.png")); + verifyAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_V)); + verifyAct->setToolTip(tr("Verify Message")); + connect(verifyAct, SIGNAL(triggered()), this, SLOT(slotVerify())); + + /* Key Menu + */ + + importKeyFromEditAct = new QAction(tr("&Editor"), this); + importKeyFromEditAct->setIcon(QIcon(":txt.png")); + importKeyFromEditAct->setToolTip(tr("Import New Key From Editor")); + connect(importKeyFromEditAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromEdit())); + + openKeyManagementAct = new QAction(tr("Manage &keys"), this); + openKeyManagementAct->setIcon(QIcon(":keymgmt.png")); + openKeyManagementAct->setToolTip(tr("Open Keymanagement")); + connect(openKeyManagementAct, SIGNAL(triggered()), this, SLOT(slotOpenKeyManagement())); + + /* About Menu + */ + aboutAct = new QAction(tr("&About"), this); + aboutAct->setIcon(QIcon(":help.png")); + aboutAct->setToolTip(tr("Show the application's About box")); + connect(aboutAct, SIGNAL(triggered()), this, SLOT(slotAbout())); + + openHelpAct = new QAction(tr("Integrated Help"), this); + openHelpAct->setToolTip(tr("Open integrated Help")); + connect(openHelpAct, SIGNAL(triggered()), this, SLOT(slotOpenHelp())); + + openTutorialAct = new QAction(tr("Online &Tutorials"), this); + openTutorialAct->setToolTip(tr("Open Online Tutorials")); + connect(openTutorialAct, SIGNAL(triggered()), this, SLOT(slotOpenTutorial())); + + openTranslateAct = new QAction(tr("Translate gpg4usb"), this); + openTranslateAct->setToolTip(tr("Translate gpg4usb yourself")); + connect(openTranslateAct, SIGNAL(triggered()), this, SLOT(slotOpenTranslate())); + + startWizardAct= new QAction(tr("Open &Wizard"), this); + startWizardAct->setToolTip(tr("Open the wizard")); + connect(startWizardAct, SIGNAL(triggered()), this, SLOT(slotStartWizard())); + + /* Popup-Menu-Action for KeyList + */ + appendSelectedKeysAct = new QAction(tr("Append Selected Key(s) To Text"), this); + appendSelectedKeysAct->setToolTip(tr("Append The Selected Keys To Text in Editor")); + connect(appendSelectedKeysAct, SIGNAL(triggered()), this, SLOT(slotAppendSelectedKeys())); + + copyMailAddressToClipboardAct = new QAction(tr("Copy EMail-address"), this); + copyMailAddressToClipboardAct->setToolTip(tr("Copy selected EMailaddress to clipboard")); + connect(copyMailAddressToClipboardAct, SIGNAL(triggered()), this, SLOT(slotCopyMailAddressToClipboard())); + + // TODO: find central place for shared actions, to avoid code-duplication with keymgmt.cpp + showKeyDetailsAct = new QAction(tr("Show Keydetails"), this); + showKeyDetailsAct->setToolTip(tr("Show Details for this Key")); + connect(showKeyDetailsAct, SIGNAL(triggered()), this, SLOT(slotShowKeyDetails())); + + refreshKeysFromKeyserverAct = new QAction(tr("Refresh key from keyserver"), this); + refreshKeysFromKeyserverAct->setToolTip(tr("Refresh key from default keyserver")); + connect(refreshKeysFromKeyserverAct, SIGNAL(triggered()), this, SLOT(refreshKeysFromKeyserver())); + + uploadKeyToServerAct = new QAction(tr("Upload Key(s) To Server"), this); + uploadKeyToServerAct->setToolTip(tr("Upload The Selected Keys To Server")); + connect(uploadKeyToServerAct, SIGNAL(triggered()), this, SLOT(uploadKeyToServer())); + /* Key-Shortcuts for Tab-Switchung-Action + */ + switchTabUpAct = new QAction(this); + switchTabUpAct->setShortcut(QKeySequence::NextChild); + connect(switchTabUpAct, SIGNAL(triggered()), edit, SLOT(slotSwitchTabUp())); + this->addAction(switchTabUpAct); + + switchTabDownAct = new QAction(this); + switchTabDownAct->setShortcut(QKeySequence::PreviousChild); + connect(switchTabDownAct, SIGNAL(triggered()), edit, SLOT(slotSwitchTabDown())); + this->addAction(switchTabDownAct); + + cutPgpHeaderAct = new QAction(tr("Remove PGP Header"), this); + connect(cutPgpHeaderAct, SIGNAL(triggered()), this, SLOT(slotCutPgpHeader())); + + addPgpHeaderAct = new QAction(tr("Add PGP Header"), this); + connect(addPgpHeaderAct, SIGNAL(triggered()), this, SLOT(slotAddPgpHeader())); +} + +void MainWindow::slotDisableTabActions(int number) +{ + bool disable; + + if (number == -1 ) { + disable = true; + } else { + disable= false; + } + printAct->setDisabled(disable); + saveAct->setDisabled(disable); + saveAsAct->setDisabled(disable); + quoteAct->setDisabled(disable); + cutAct->setDisabled(disable); + copyAct->setDisabled(disable); + pasteAct->setDisabled(disable); + closeTabAct->setDisabled(disable); + selectallAct->setDisabled(disable); + findAct->setDisabled(disable); + verifyAct->setDisabled(disable); + signAct->setDisabled(disable); + encryptAct->setDisabled(disable); + decryptAct->setDisabled(disable); + + redoAct->setDisabled(disable); + undoAct->setDisabled(disable); + zoomOutAct->setDisabled(disable); + zoomInAct->setDisabled(disable); + cleanDoubleLinebreaksAct->setDisabled(disable); + quoteAct->setDisabled(disable); + appendSelectedKeysAct->setDisabled(disable); + importKeyFromEditAct->setDisabled(disable); + + cutPgpHeaderAct->setDisabled(disable); + addPgpHeaderAct->setDisabled(disable); +} + +void MainWindow::createMenus() +{ + fileMenu = menuBar()->addMenu(tr("&File")); + fileMenu->addAction(newTabAct); + fileMenu->addAction(openAct); + fileMenu->addSeparator(); + fileMenu->addAction(saveAct); + fileMenu->addAction(saveAsAct); + fileMenu->addSeparator(); + fileMenu->addAction(printAct); + fileMenu->addSeparator(); + fileMenu->addAction(closeTabAct); + fileMenu->addAction(quitAct); + + editMenu = menuBar()->addMenu(tr("&Edit")); + editMenu->addAction(undoAct); + editMenu->addAction(redoAct); + editMenu->addSeparator(); + editMenu->addAction(zoomInAct); + editMenu->addAction(zoomOutAct); + editMenu->addSeparator(); + editMenu->addAction(copyAct); + editMenu->addAction(cutAct); + editMenu->addAction(pasteAct); + editMenu->addAction(selectallAct); + editMenu->addAction(findAct); + editMenu->addSeparator(); + editMenu->addAction(quoteAct); + editMenu->addAction(cleanDoubleLinebreaksAct); + editMenu->addSeparator(); + editMenu->addAction(openSettingsAct); + + fileEncMenu = new QMenu(tr("&File...")); + fileEncMenu->addAction(fileEncryptAct); + fileEncMenu->addAction(fileDecryptAct); + fileEncMenu->addAction(fileSignAct); + fileEncMenu->addAction(fileVerifyAct); + + cryptMenu = menuBar()->addMenu(tr("&Crypt")); + cryptMenu->addAction(encryptAct); + cryptMenu->addAction(decryptAct); + cryptMenu->addSeparator(); + cryptMenu->addAction(signAct); + cryptMenu->addAction(verifyAct); + cryptMenu->addSeparator(); + cryptMenu->addMenu(fileEncMenu); + + keyMenu = menuBar()->addMenu(tr("&Keys")); + importKeyMenu = keyMenu->addMenu(tr("&Import Key From...")); + importKeyMenu->setIcon(QIcon(":key_import.png")); + importKeyMenu->addAction(keyMgmt->importKeyFromFileAct); + importKeyMenu->addAction(importKeyFromEditAct); + importKeyMenu->addAction(keyMgmt->importKeyFromClipboardAct); + importKeyMenu->addAction(keyMgmt->importKeyFromKeyServerAct); + importKeyMenu->addAction(keyMgmt->importKeyFromKeyServerAct); + keyMenu->addAction(openKeyManagementAct); + + steganoMenu = menuBar()->addMenu(tr("&Steganography")); + steganoMenu->addAction(cutPgpHeaderAct); + steganoMenu->addAction(addPgpHeaderAct); + + // Hide menu, when steganography menu is disabled in settings + if(!settings.value("advanced/steganography").toBool()) { + this->menuBar()->removeAction(steganoMenu->menuAction()); + } + + viewMenu = menuBar()->addMenu(tr("&View")); + + helpMenu = menuBar()->addMenu(tr("&Help")); + helpMenu->addAction(openHelpAct); + helpMenu->addAction(startWizardAct); + helpMenu->addSeparator(); + helpMenu->addAction(openTutorialAct); + helpMenu->addAction(openTranslateAct); + helpMenu->addSeparator(); + helpMenu->addAction(aboutAct); + +} + +void MainWindow::createToolBars() +{ + fileToolBar = addToolBar(tr("File")); + fileToolBar->setObjectName("fileToolBar"); + fileToolBar->addAction(newTabAct); + fileToolBar->addAction(openAct); + fileToolBar->addAction(saveAct); + fileToolBar->hide(); + viewMenu->addAction(fileToolBar->toggleViewAction()); + + cryptToolBar = addToolBar(tr("Crypt")); + cryptToolBar->setObjectName("cryptToolBar"); + cryptToolBar->addAction(encryptAct); + cryptToolBar->addAction(decryptAct); + cryptToolBar->addAction(signAct); + cryptToolBar->addAction(verifyAct); + //cryptToolBar->addAction(fileEncryptionAct); + viewMenu->addAction(cryptToolBar->toggleViewAction()); + + keyToolBar = addToolBar(tr("Key")); + keyToolBar->setObjectName("keyToolBar"); + keyToolBar->addAction(openKeyManagementAct); + viewMenu->addAction(keyToolBar->toggleViewAction()); + + editToolBar = addToolBar(tr("Edit")); + editToolBar->setObjectName("editToolBar"); + editToolBar->addAction(copyAct); + editToolBar->addAction(pasteAct); + editToolBar->addAction(selectallAct); + viewMenu->addAction(editToolBar->toggleViewAction()); + + specialEditToolBar = addToolBar(tr("Special edit")); + specialEditToolBar->setObjectName("specialEditToolBar"); + specialEditToolBar->addAction(quoteAct); + specialEditToolBar->addAction(cleanDoubleLinebreaksAct); + viewMenu->addAction(specialEditToolBar->toggleViewAction()); + + // Add dropdown menu for key import to keytoolbar + importButton = new QToolButton(); + importButton->setMenu(importKeyMenu); + importButton->setPopupMode(QToolButton::InstantPopup); + importButton->setIcon(QIcon(":key_import.png")); + importButton->setToolTip(tr("Import key from...")); + importButton->setText(tr("Import key")); + keyToolBar->addWidget(importButton); + + // Add dropdown menu for file encryption/decryption to crypttoolbar + fileEncButton = new QToolButton(); + fileEncButton->setMenu(fileEncMenu); + fileEncButton->setPopupMode(QToolButton::InstantPopup); + fileEncButton->setIcon(QIcon(":fileencryption.png")); + fileEncButton->setToolTip(tr("Encrypt or decrypt File")); + fileEncButton->setText(tr("File..")); + + cryptToolBar->addWidget(fileEncButton); + +} + +void MainWindow::createStatusBar() +{ + QWidget *statusBarBox = new QWidget(); + QHBoxLayout *statusBarBoxLayout = new QHBoxLayout(); + QPixmap *pixmap; + + // icon which should be shown if there are files in attachments-folder + pixmap = new QPixmap(":statusbar_icon.png"); + statusBarIcon = new QLabel(statusBar()); + statusBarIcon->setPixmap(*pixmap); + statusBar()->insertPermanentWidget(0,statusBarIcon,0); + statusBarIcon->hide(); + statusBar()->showMessage(tr("Ready"),2000); + statusBarBox->setLayout(statusBarBoxLayout); +} + +void MainWindow::createDockWindows() +{ + /* KeyList-Dockwindow + */ + keylistDock = new QDockWidget(tr("Encrypt for:"), this); + keylistDock->setObjectName("EncryptDock"); + keylistDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); + addDockWidget(Qt::RightDockWidgetArea, keylistDock); + keylistDock->setWidget(mKeyList); + viewMenu->addAction(keylistDock->toggleViewAction()); + + /* Attachments-Dockwindow + */ + if(settings.value("mime/parseMime").toBool()) { + createAttachmentDock(); + } +} + +void MainWindow::createAttachmentDock() { + if (attachmentDockCreated) { + return; + } + mAttachments = new Attachments(); + attachmentDock = new QDockWidget(tr("Attached files:"), this); + attachmentDock->setObjectName("AttachmentDock"); + attachmentDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea); + addDockWidget(Qt::BottomDockWidgetArea, attachmentDock); + attachmentDock->setWidget(mAttachments); + // hide till attachment is decrypted + viewMenu->addAction(attachmentDock->toggleViewAction()); + attachmentDock->hide(); + attachmentDockCreated = true; +} + +void MainWindow::closeAttachmentDock() { + if (!attachmentDockCreated) { + return; + } + attachmentDock->close(); + attachmentDock->deleteLater(); + attachmentDockCreated = false; +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + /* + * ask to save changes, if there are + * modified documents in any tab + */ + if (edit->maybeSaveAnyTab()) { + saveSettings(); + event->accept(); + } else { + event->ignore(); + } + + // clear password from memory + mCtx->clearPasswordCache(); +} + +void MainWindow::slotAbout() +{ + new AboutDialog(this); +} + +void MainWindow::slotOpenTranslate() +{ + QDesktopServices::openUrl(QUrl("http://gpg4usb.cpunk.de/docu_translate.html")); +} + +void MainWindow::slotOpenTutorial() +{ + QDesktopServices::openUrl(QUrl("http://gpg4usb.cpunk.de/docu.html")); +} + +void MainWindow::slotOpenHelp() { + slotOpenHelp("docu.html"); +} + +void MainWindow::slotOpenHelp(const QString page) +{ + edit->slotNewHelpTab("help", "file:" + qApp->applicationDirPath() + "/help/" + page); +} + +void MainWindow::slotSetStatusBarText(QString text) +{ + statusBar()->showMessage(text,20000); +} + +void MainWindow::slotStartWizard() +{ + Wizard *wizard = new Wizard(mCtx,keyMgmt,this); + wizard->show(); + wizard->setModal(true); +} + +/* + * if this is mime, split text and attachments... + * message contains only text afterwards + */ +void MainWindow::parseMime(QByteArray *message) +{ + /*if (! Mime::isMultipart(message)) { + qDebug() << "no multipart"; + return; + }*/ + //qDebug() << "multipart"; + + QString pText; + bool showmadock = false; + + Mime *mime = new Mime(message); + foreach(MimePart tmp, mime->parts()) { + if (tmp.header.getValue("Content-Type") == "text/plain" + && tmp.header.getValue("Content-Transfer-Encoding") != "base64") { + + QByteArray body; + if (tmp.header.getValue("Content-Transfer-Encoding") == "quoted-printable") { + Mime::quotedPrintableDecode(tmp.body, body); + } else { + body = tmp.body; + } + pText.append(QString(body)); + } else { + (mAttachments->addMimePart(&tmp)); + showmadock = true; + } + } + *message = pText.toUtf8(); + if (showmadock) { + attachmentDock->show(); + } +} + +void MainWindow::slotCheckAttachmentFolder() { + // TODO: always check? + if(!settings.value("mime/parseMime").toBool()) { + return; + } + + QString attachmentDir = qApp->applicationDirPath() + "/attachments/"; + // filenum minus . and .. + int filenum = QDir(attachmentDir).count() - 2 ; + if(filenum > 0) { + QString statusText; + if(filenum == 1) { + statusText = tr("There is one unencrypted file in attachment folder"); + } else { + statusText = tr("There are ") + QString::number(filenum) + tr(" unencrypted files in attachment folder"); + } + statusBarIcon->setStatusTip(statusText); + statusBarIcon->show(); + } else { + statusBarIcon->hide(); + } +} + +void MainWindow::slotImportKeyFromEdit() +{ + if (edit->tabCount()==0 || edit->slotCurPage() == 0) { + return; + } + + keyMgmt->slotImportKeys(edit->curTextPage()->toPlainText().toAscii()); +} + +void MainWindow::slotOpenKeyManagement() +{ + keyMgmt->show(); + keyMgmt->raise(); + keyMgmt->activateWindow(); +} + +void MainWindow::slotEncrypt() +{ + if (edit->tabCount()==0 || edit->slotCurPage() == 0) { + return; + } + + QStringList *uidList = mKeyList->getChecked(); + + QByteArray *tmp = new QByteArray(); + if (mCtx->encrypt(uidList, edit->curTextPage()->toPlainText().toUtf8(), tmp)) { + QString *tmp2 = new QString(*tmp); + edit->slotFillTextEditWithText(*tmp2); + } +} + +void MainWindow::slotSign() +{ + if (edit->tabCount()==0 || edit->slotCurPage() == 0) { + return; + } + + QStringList *uidList = mKeyList->getPrivateChecked(); + + QByteArray *tmp = new QByteArray(); + + if (mCtx->sign(uidList, edit->curTextPage()->toPlainText().toUtf8(), tmp)) { + edit->slotFillTextEditWithText(QString::fromUtf8(*tmp)); + } +} + +void MainWindow::slotDecrypt() +{ + if (edit->tabCount()== 0 || edit->slotCurPage() == 0) { + return; + } + + QByteArray *decrypted = new QByteArray(); + QByteArray text = edit->curTextPage()->toPlainText().toAscii(); // TODO: toUtf8() here? + mCtx->preventNoDataErr(&text); + + // try decrypt, if fail do nothing, especially don't replace text + if(!mCtx->decrypt(text, decrypted)) { + return; + } + + /* + * 1) is it mime (content-type:) + * 2) parse header + * 2) choose action depending on content-type + */ + if(Mime::isMime(decrypted)) { + Header header = Mime::getHeader(decrypted); + // is it multipart, is multipart-parsing enabled + if(header.getValue("Content-Type") == "multipart/mixed" + && settings.value("mime/parseMime").toBool()) { + parseMime(decrypted); + } else if(header.getValue("Content-Type") == "text/plain" + && settings.value("mime/parseQP").toBool()){ + if (header.getValue("Content-Transfer-Encoding") == "quoted-printable") { + QByteArray *decoded = new QByteArray(); + Mime::quotedPrintableDecode(*decrypted, *decoded); + //TODO: remove header + decrypted = decoded; + } + } + } + edit->slotFillTextEditWithText(QString::fromUtf8(*decrypted)); +} + +void MainWindow::slotFind() +{ + if (edit->tabCount()==0 || edit->curTextPage() == 0) { + return; + } + + // At first close verifynotification, if existing + edit->slotCurPage()->closeNoteByClass("findwidget"); + + FindWidget *fw = new FindWidget(this,edit->curTextPage()); + edit->slotCurPage()->showNotificationWidget(fw, "findWidget"); + +} + +void MainWindow::slotVerify() +{ + if (edit->tabCount()==0 || edit->slotCurPage() == 0) { + return; + } + + // At first close verifynotification, if existing + edit->slotCurPage()->closeNoteByClass("verifyNotification"); + + // create new verfiy notification + VerifyNotification *vn = new VerifyNotification(this, mCtx, mKeyList, edit->curTextPage()); + + // if signing information is found, show the notification, otherwise close it + if (vn->slotRefresh()) { + edit->slotCurPage()->showNotificationWidget(vn, "verifyNotification"); + } else { + vn->close(); + } +} + +/* + * Append the selected (not checked!) Key(s) To Textedit + */ +void MainWindow::slotAppendSelectedKeys() +{ + if (edit->tabCount()==0 || edit->slotCurPage() == 0) { + return; + } + + QByteArray *keyArray = new QByteArray(); + mCtx->exportKeys(mKeyList->getSelected(), keyArray); + edit->curTextPage()->append(*keyArray); +} + +void MainWindow::slotCopyMailAddressToClipboard() +{ + if (mKeyList->getSelected()->isEmpty()) { + return; + } + + gpgme_key_t key = mCtx->getKeyDetails(mKeyList->getSelected()->first()); + QClipboard *cb = QApplication::clipboard(); + QString mail = key->uids->email; + cb->setText(mail); +} + +void MainWindow::slotShowKeyDetails() +{ + if (mKeyList->getSelected()->isEmpty()) { + return; + } + + gpgme_key_t key = mCtx->getKeyDetails(mKeyList->getSelected()->first()); + if (key) { + new KeyDetailsDialog(mCtx, key, this); + } +} +void MainWindow::refreshKeysFromKeyserver() +{ + if (mKeyList->getSelected()->isEmpty()) { + return; + } + + KeyServerImportDialog *ksid = new KeyServerImportDialog(mCtx,mKeyList,this); + ksid->slotImport(*mKeyList->getSelected()); + +} + +void MainWindow::uploadKeyToServer() +{ + QByteArray *keyArray = new QByteArray(); + mCtx->exportKeys(mKeyList->getSelected(), keyArray); + + mKeyList->uploadKeyToServer(keyArray); +} + +void MainWindow::slotFileEncrypt() +{ + QStringList *keyList; + keyList = mKeyList->getChecked(); + new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Encrypt, this); +} + +void MainWindow::slotFileDecrypt() +{ + QStringList *keyList; + keyList = mKeyList->getChecked(); + new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Decrypt, this); +} + +void MainWindow::slotFileSign() +{ + QStringList *keyList; + keyList = mKeyList->getChecked(); + new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Sign, this); +} + +void MainWindow::slotFileVerify() +{ + QStringList *keyList; + keyList = mKeyList->getChecked(); + new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Verify, this); +} + +void MainWindow::slotOpenSettingsDialog() +{ + + QString preLang = settings.value("int/lang").toString(); + QString preKeydbPath = settings.value("gpgpaths/keydbpath").toString(); + + new SettingsDialog(mCtx, this); + // Iconsize + QSize iconSize = settings.value("toolbar/iconsize", QSize(32, 32)).toSize(); + this->setIconSize(iconSize); + importButton->setIconSize(iconSize); + fileEncButton->setIconSize(iconSize); + + // Iconstyle + Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>(settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon).toUInt()); + this->setToolButtonStyle(buttonStyle); + importButton->setToolButtonStyle(buttonStyle); + fileEncButton->setToolButtonStyle(buttonStyle); + + // Mime-settings + if(settings.value("mime/parseMime").toBool()) { + createAttachmentDock(); + } else if(attachmentDockCreated) { + closeAttachmentDock(); + } + + // restart mainwindow if necessary + if(getRestartNeeded()) { + if(edit->maybeSaveAnyTab()) { + saveSettings(); + qApp->exit(RESTART_CODE); + } + } + + // steganography hide/show + if(!settings.value("advanced/steganography").toBool()) { + this->menuBar()->removeAction(steganoMenu->menuAction()); + } else { + this->menuBar()->insertAction(viewMenu->menuAction(), steganoMenu->menuAction()); + } + +} + +void MainWindow::slotCleanDoubleLinebreaks() +{ + if (edit->tabCount()==0 || edit->slotCurPage() == 0) { + return; + } + + QString content = edit->curTextPage()->toPlainText(); + content.replace("\n\n", "\n"); + edit->slotFillTextEditWithText(content); +} + +void MainWindow::slotAddPgpHeader() { + if (edit->tabCount()==0 || edit->slotCurPage() == 0) { + return; + } + + QString content = edit->curTextPage()->toPlainText().trimmed(); + + content.prepend("\n\n").prepend(GpgConstants::PGP_CRYPT_BEGIN); + content.append("\n").append(GpgConstants::PGP_CRYPT_END); + + edit->slotFillTextEditWithText(content); +} + +void MainWindow::slotCutPgpHeader() { + + if (edit->tabCount()==0 || edit->slotCurPage() == 0) { + return; + } + + QString content = edit->curTextPage()->toPlainText(); + int start = content.indexOf(GpgConstants::PGP_CRYPT_BEGIN); + int end = content.indexOf(GpgConstants::PGP_CRYPT_END); + + if(start < 0 || end < 0) { + return; + } + + // remove head + int headEnd = content.indexOf("\n\n", start) + 2 ; + content.remove(start, headEnd-start); + + // remove tail + end = content.indexOf(GpgConstants::PGP_CRYPT_END); + content.remove(end, QString(GpgConstants::PGP_CRYPT_END).size()); + + edit->slotFillTextEditWithText(content.trimmed()); +} + +void MainWindow::slotSetRestartNeeded(bool needed) +{ + this->restartNeeded = needed; +} + +bool MainWindow::getRestartNeeded() +{ + return this->restartNeeded; +} diff --git a/src/mainwindow.h b/src/mainwindow.h new file mode 100644 index 0000000..9ee1b63 --- /dev/null +++ b/src/mainwindow.h @@ -0,0 +1,374 @@ +/* + * mainwindow.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __GPGWIN_H__ +#define __GPGWIN_H__ + +#include "gpgconstants.h" +#include "attachments.h" +#include "keymgmt.h" +#include "textedit.h" +#include "fileencryptiondialog.h" +#include "settingsdialog.h" +#include "aboutdialog.h" +#include "verifynotification.h" +#include "findwidget.h" +#include "wizard.h" + +QT_BEGIN_NAMESPACE +class QMainWindow; +class QTextEdit; +class QWidget; +class QVBoxLayout; +class QGridLayout; +class iostream; +class QtGui; +class QString; +class QFileDialog; +class QStringList; +class QIcon; +class QMessageBox; +class QVBoxLayout; +class QAction; +class QMenu; +class QTextEdit; +class QComboBox; +class QPushButton; +class QRadioButton; +class QButtonGroup; +class QApplication; +class QDockWidget; +QT_END_NAMESPACE + +/** + * @brief + * + */ +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + /** + * @brief + * + */ + MainWindow(); +public slots: + void slotSetStatusBarText(QString text); + +protected: + /** + * @details Close event shows a save dialog, if there are unsaved documents on exit. + * @param event + */ + void closeEvent(QCloseEvent *event); + +private slots: + /** + * @details encrypt the text of currently active textedit-page + * with the currently checked keys + */ + void slotEncrypt(); + + /** + * @details Show a passphrase dialog and decrypt the text of currently active tab. + */ + void slotDecrypt(); + + /** + * @details Sign the text of currently active tab with the checked private keys + */ + void slotSign(); + + /** + * @details Verify the text of currently active tab and show verify information. + * If document is signed with a key, which is not in keylist, show import missing + * key from keyserver in Menu of verifynotification. + */ + void slotVerify(); + + /** + * @details Show the details of the first of the first of selected keys + */ + void slotShowKeyDetails(); + + /** + * @details Refresh key information of selected keys from default keyserver + */ + void refreshKeysFromKeyserver(); + + /** + * @details upload the selected key to the keyserver + */ + void uploadKeyToServer(); + + /** + * @details Open find widget. + */ + void slotFind(); + + /** + * @details start the wizard + */ + void slotStartWizard(); + + /** + * @details Import keys from currently active tab to keylist if possible. + */ + void slotImportKeyFromEdit(); + + /** + * @details Append the selected keys to currently active textedit. + */ + void slotAppendSelectedKeys(); + + /** + * @details Copy the mailaddress of selected key to clipboard. + * Method for keylists contextmenu. + */ + void slotCopyMailAddressToClipboard(); + + /** + * @details Open key management dialog. + */ + void slotOpenKeyManagement(); + + /** + * @details Open about-dialog. + */ + void slotAbout(); + + /** + * @details Open dialog for encrypting file. + */ + void slotFileEncrypt(); + + /** + * @details Open dialog for decrypting file. + */ + void slotFileDecrypt(); + + /** + * @details Open dialog for signing file. + */ + void slotFileSign(); + + /** + * @details Open dialog for verifying file. + */ + void slotFileVerify(); + + /** + * @details Open settings-dialog. + */ + void slotOpenSettingsDialog(); + + /** + * @details Open online-tutorial in default browser. + */ + void slotOpenTutorial(); + + /** + * @details Open integrated help in new tab. + */ + void slotOpenHelp(); + + /** + * @details Open integrated help in new tab with the specified page. + */ + void slotOpenHelp(const QString page); + + /** + * @details Show a warn message in status bar, if there are files in attachment folder. + */ + void slotCheckAttachmentFolder(); + + /** + * @details Open online translation tutorial in default browser. + */ + void slotOpenTranslate(); + + /** + * @details Replace double linebreaks by single linebreaks in currently active tab. + */ + void slotCleanDoubleLinebreaks(); + + /** + * @details Cut the existing PGP header and footer from current tab. + */ + void slotCutPgpHeader(); + + /** + * @details Add PGP header and footer to current tab. + */ + void slotAddPgpHeader(); + +// void dropEvent(QDropEvent *event); + + /** + * @details Disable tab related actions, if number of tabs is 0. + * @param number number of the opened tabs and -1, if no tab is opened + */ + void slotDisableTabActions(int number); + + /** + * @details get value of member restartNeeded to needed. + * @param needed true, if application has to be restarted + */ + void slotSetRestartNeeded(bool needed); + +private: + /** + * @details Create actions for the main-menu and the context-menu of the keylist. + */ + void createActions(); + + /** + * @details create the menu of the main-window. + */ + void createMenus(); + + /** + * @details Create edit-, crypt- and key-toolbars. + */ + void createToolBars(); + + /** + * @details Create statusbar of mainwindow. + */ + void createStatusBar(); + + /** + * @details Create keylist- and attachment-dockwindows. + */ + void createDockWindows(); + + /** + * @details Create attachment-dockwindow. + */ + void createAttachmentDock(); + + /** + * @details close attachment-dockwindow. + */ + void closeAttachmentDock(); + + /** + * @details Load settings from ini-file. + */ + void restoreSettings(); + + /** + * @details Save settings to ini-file. + */ + void saveSettings(); + + /** + * @brief + * + * @param message + */ + void parseMime(QByteArray *message); + + /** + * @brief return true, if restart is needed + */ + bool getRestartNeeded(); + + TextEdit *edit; /** Tabwidget holding the edit-windows */ + QMenu *fileMenu; /** Submenu for file-operations*/ + QMenu *editMenu; /** Submenu for text-operations*/ + QMenu *cryptMenu; /** Submenu for crypt-operations */ + QMenu *fileEncMenu; /** Submenu for file crypt operations */ + QMenu *helpMenu; /** Submenu for help-operations */ + QMenu *keyMenu; /** Submenu for key-operations */ + QMenu *viewMenu; /** Submenu for view operations */ + QMenu *importKeyMenu; /** Sumenu for import operations */ + QMenu *steganoMenu; /** Submenu for steganographic operations*/ + QToolBar *cryptToolBar; /** Toolbar holding crypt actions */ + QToolBar *fileToolBar; /** Toolbar holding file actions */ + QToolBar *editToolBar; /** Toolbar holding edit actions */ + QToolBar *specialEditToolBar; /** Toolbar holding special edit actions */ + QToolBar *keyToolBar; /** Toolbar holding key operations */ + QToolButton* importButton; /** Toolbutton for import dropdown menu in toolbar */ + QToolButton* fileEncButton; /** Toolbutton for file cryption dropdown menu in toolbar */ + QDockWidget *keylistDock; /** Encrypt Dock*/ + QDockWidget *attachmentDock; /** Attachment Dock */ + QDialog *genkeyDialog; /** Dialog for key generation */ + + QAction *newTabAct; /** Action to create new tab */ + QAction *switchTabUpAct; /** Action to switch tab up*/ + QAction *switchTabDownAct; /** Action to switch tab down */ + QAction *openAct; /** Action to open file */ + QAction *saveAct; /** Action to save file */ + QAction *saveAsAct; /** Action to save file as */ + QAction *printAct; /** Action to print */ + QAction *closeTabAct; /** Action to print */ + QAction *quitAct; /** Action to quit application */ + QAction *encryptAct; /** Action to encrypt text */ + QAction *decryptAct; /** Action to decrypt text */ + QAction *signAct; /** Action to sign text */ + QAction *verifyAct; /** Action to verify text */ + QAction *importKeyFromEditAct; /** Action to import key from edit */ + QAction *cleanDoubleLinebreaksAct; /** Action to remove double line breaks */ + + QAction *appendSelectedKeysAct; /** Action to append selected keys to edit */ + QAction *copyMailAddressToClipboardAct; /** Action to copy mail to clipboard */ + QAction *openKeyManagementAct; /** Action to open key management */ + QAction *copyAct; /** Action to copy text */ + QAction *quoteAct; /** Action to quote text */ + QAction *cutAct; /** Action to cut text */ + QAction *pasteAct; /** Action to paste text */ + QAction *selectallAct; /** Action to select whole text */ + QAction *findAct; /** Action to find text */ + QAction *undoAct; /** Action to undo last action */ + QAction *redoAct; /** Action to redo last action */ + QAction *zoomInAct; /** Action to zoom in */ + QAction *zoomOutAct; /** Action to zoom out */ + QAction *aboutAct; /** Action to open about dialog */ + QAction *fileEncryptAct; /** Action to open dialog for encrypting file */ + QAction *fileDecryptAct; /** Action to open dialog for decrypting file */ + QAction *fileSignAct; /** Action to open dialog for signing file */ + QAction *fileVerifyAct; /** Action to open dialog for verifying file */ + QAction *openSettingsAct; /** Action to open settings dialog */ + QAction *openTranslateAct; /** Action to open translate doc*/ + QAction *openTutorialAct; /** Action to open tutorial */ + QAction *openHelpAct; /** Action to open tutorial */ + QAction *showKeyDetailsAct; /** Action to open key-details dialog */ + QAction *refreshKeysFromKeyserverAct; /** Action to refresh a key from keyserver */ + QAction *uploadKeyToServerAct; /** Action to append selected keys to edit */ + QAction *startWizardAct; /** Action to open the wizard */ + QAction *cutPgpHeaderAct; /** Action for cutting the PGP header */ + QAction *addPgpHeaderAct; /** Action for adding the PGP header */ + + QLabel *statusBarIcon; /**< TODO */ + QSettings settings; /**< TODO */ + KeyList *mKeyList; /**< TODO */ + Attachments *mAttachments; /**< TODO */ + GpgME::GpgContext *mCtx; /**< TODO */ + KeyMgmt *keyMgmt; /**< TODO */ + KeyServerImportDialog *importDialog; /**< TODO */ + bool attachmentDockCreated; + bool restartNeeded; +}; + +#endif // __GPGWIN_H__ diff --git a/src/mime.cpp b/src/mime.cpp new file mode 100644 index 0000000..30f19cf --- /dev/null +++ b/src/mime.cpp @@ -0,0 +1,243 @@ +/* + * mime.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +/*** + * quotedPrintableDecode copied from KCodecs, where it is stated: + + The quoted-printable codec as described in RFC 2045, section 6.7. is by + Rik Hemsley (C) 2001. + + */ + +/* TODO: proper import / copyright statement + * + */ + +#include "mime.h" + +Mime::Mime(QByteArray *message) +{ + splitParts(message); + /* + mMessage = message; + int bStart = mMessage->indexOf("boundary=\"") + 10 ; + int bEnd = mMessage->indexOf("\"\n", bStart ); + + qDebug() << "bStart: " << bStart << " bEnd: " << bEnd; + mBoundary = new QByteArray(mMessage->mid(bStart, bEnd - bStart)); + qDebug() << "boundary: " << *mBoundary; + + Part *p1 = new Part(); + + int nb = mMessage->indexOf(*mBoundary, bEnd) + mBoundary->length() +1 ; + qDebug() << "nb: " << nb; + int eh = mMessage->indexOf("\n\n", nb); + qDebug() << "eh: " << eh; + QByteArray *header = new QByteArray(mMessage->mid(nb , eh - nb)); + qDebug() << "header:" << header; + + // split header at newlines + foreach(QByteArray tmp , header->split(* "\n")) { + // split lines at : + QList<QByteArray> tmp2 = tmp.split(* ":"); + p1->header.insert(QString(tmp2[0].trimmed()), QString(tmp2[1].trimmed())); + } + + QHashIterator<QString, QString> i(p1->header); + while (i.hasNext()) { + i.next(); + qDebug() << "found: " << i.key() << ":" << i.value() << endl; + } + + int nb2 = mMessage->indexOf(*mBoundary, eh); + + p1->body = mMessage->mid(eh , nb2 - eh); + + QTextCodec *codec = QTextCodec::codecForName("ISO-8859-15"); + QString qs = codec->toUnicode(p1->body); + qDebug() << "body: " << qs; + */ +} + +Mime::~Mime() +{ + +} + +void Mime::splitParts(QByteArray *message) +{ + int pos1, pos2, headEnd; + MimePart p_tmp; + + // find the boundary + pos1 = message->indexOf("boundary=\"") + 10 ; + pos2 = message->indexOf("\"\n", pos1); + QByteArray boundary = message->mid(pos1, pos2 - pos1); + //qDebug() << "boundary: " << boundary; + + while (pos2 > pos1) { + + pos1 = message->indexOf(boundary, pos2) + boundary.length() + 1 ; + headEnd = message->indexOf("\n\n", pos1); + if (headEnd < 0) + break; + QByteArray header = message->mid(pos1 , headEnd - pos1); + + p_tmp.header = parseHeader(&header); + + pos2 = message->indexOf(boundary, headEnd); + p_tmp.body = message->mid(headEnd , pos2 - headEnd); + + mPartList.append(p_tmp); + } +} + +Header Mime::parseHeader(QByteArray *header) +{ + + QList<HeadElem> ret; + + /** http://www.aspnetmime.com/help/welcome/overviewmimeii.html : + * If a line starts with any white space, that line is said to be 'folded' and is actually + * part of the header above it. + */ + header->replace("\n ", " "); + + //split header at newlines + foreach(QByteArray line , header->split(* "\n")) { + HeadElem elem; + //split lines at : + QList<QByteArray> tmp2 = line.split(* ":"); + elem.name = tmp2[0].trimmed(); + if (tmp2[1].contains(';')) { + // split lines at ; + // TODO: what if ; is inside "" + QList<QByteArray> tmp3 = tmp2[1].split(* ";"); + elem.value = QString(tmp3.takeFirst().trimmed()); + foreach(QByteArray tmp4, tmp3) { + QList<QByteArray> tmp5 = tmp4.split(* "="); + elem.params.insert(QString(tmp5[0].trimmed()), QString(tmp5[1].trimmed())); + } + } else { + elem.value = tmp2[1].trimmed(); + } + ret.append(elem); + } + return Header(ret); +} + +Header Mime::getHeader(const QByteArray *message) { + int headEnd = message->indexOf("\n\n"); + QByteArray header = message->mid(0, headEnd); + return parseHeader(&header); +} + +bool Mime::isMultipart(QByteArray *message) +{ + return message->startsWith("Content-Type: multipart/mixed;"); +} + +/** + * if Content-Type is specified, it should be mime + * + */ +bool Mime::isMime(const QByteArray *message) +{ + return message->startsWith("Content-Type:"); +} + +/*** + * quotedPrintableDecode copied from KCodecs, where it is stated: + + The quoted-printable codec as described in RFC 2045, section 6.7. is by + Rik Hemsley (C) 2001. + + */ + +static const char hexChars[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + +/******************************** KCodecs ********************************/ +// strchr(3) for broken systems. +static int rikFindChar(register const char * _s, const char c) +{ + register const char * s = _s; + + while (true) { + if ((0 == *s) || (c == *s)) break; ++s; + if ((0 == *s) || (c == *s)) break; ++s; + if ((0 == *s) || (c == *s)) break; ++s; + if ((0 == *s) || (c == *s)) break; ++s; + } + + return s - _s; +} + +void Mime::quotedPrintableDecode(const QByteArray& in, QByteArray& out) +{ + // clear out the output buffer + out.resize(0); + if (in.isEmpty()) + return; + + char *cursor; + const char *data; + const unsigned int length = in.size(); + + data = in.data(); + out.resize(length); + cursor = out.data(); + + for (unsigned int i = 0; i < length; i++) { + char c(in[i]); + + if ('=' == c) { + if (i < length - 2) { + char c1 = in[i + 1]; + char c2 = in[i + 2]; + + if (('\n' == c1) || ('\r' == c1 && '\n' == c2)) { + // Soft line break. No output. + if ('\r' == c1) + i += 2; // CRLF line breaks + else + i += 1; + } else { + // =XX encoded byte. + + int hexChar0 = rikFindChar(hexChars, c1); + int hexChar1 = rikFindChar(hexChars, c2); + + if (hexChar0 < 16 && hexChar1 < 16) { + *cursor++ = char((hexChar0 * 16) | hexChar1); + i += 2; + } + } + } + } else { + *cursor++ = c; + } + } + + out.truncate(cursor - out.data()); +} diff --git a/src/mime.h b/src/mime.h new file mode 100644 index 0000000..df44647 --- /dev/null +++ b/src/mime.h @@ -0,0 +1,134 @@ +/* + * mime.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __MIME_H__ +#define __MIME_H__ + +#include <QHashIterator> +#include <QHash> + +QT_BEGIN_NAMESPACE +class QByteArray; +class QDebug; +class QTextCodec; +QT_END_NAMESPACE + +class HeadElem +{ +public: + QString name; + QString value; + QHash<QString, QString> params; + + /* QDataStream & operator<<(QDataStream& Stream, const HeadElem& H) + { + return Stream << H.name << " : " << H.value; + }*/ + +}; + +class Header +{ +public: + QList<HeadElem> headElems; + + Header() {} + + Header(QList <HeadElem> heads) { + headElems = heads; + } + + void setHeader(QList <HeadElem> heads) { + headElems = heads; + } + + QString getValue(QString key) { + foreach(HeadElem tmp, headElems) { + //qDebug() << "gv: " << tmp.name << ":" << tmp.value; + if (tmp.name == key) + return tmp.value; + } + return ""; + } + + QHash<QString, QString> getParams(QString key) { + foreach(HeadElem tmp, headElems) { + //qDebug() << "gv: " << tmp.name << ":" << tmp.value; + if (tmp.name == key) + //return tmp.value; + return tmp.params; + } + return *(new QHash<QString, QString>()); + } + + QString getParam(QString key, QString pKey) { + foreach(HeadElem tmp, headElems) { + //qDebug() << "gv: " << tmp.name << ":" << tmp.value; + if (tmp.name == key) + return tmp.params.value(pKey); + } + return ""; + } + + +}; + +class MimePart +{ +public: + Header header; + QByteArray body; + + + + /* QDataStream & operator<<(QDataStream& Stream, const Part& P) + { + foreach(HeadElem tmp, header) { + Stream << tmp << "\n"; + } + return Stream; + }*/ +}; + +class Mime +{ + +public: + Mime(QByteArray *message); // Constructor + ~Mime(); // Destructor + static bool isMultipart(QByteArray *message); + static bool isMime(const QByteArray *message); + QList<MimePart> parts() { + return mPartList; + } + void splitParts(QByteArray *message); + static Header getHeader(const QByteArray *message); + static Header parseHeader(QByteArray *header); + static void quotedPrintableDecode(const QByteArray& in, QByteArray& out); + +private: + QByteArray *mMessage; + QByteArray *mBoundary; + QList<MimePart> mPartList; + +}; + +#endif // __MIME_H__ diff --git a/src/quitdialog.cpp b/src/quitdialog.cpp new file mode 100755 index 0000000..e32369b --- /dev/null +++ b/src/quitdialog.cpp @@ -0,0 +1,131 @@ +/* + * + * keymgmt.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "quitdialog.h" + +QuitDialog::QuitDialog(QWidget *parent, QHash<int, QString> unsavedDocs) + : QDialog(parent) +{ + setWindowTitle(tr("Unsaved files")); + setModal(true); + discarded =false; + + /* + * Table of unsaved documents + */ + QHashIterator<int, QString> i (unsavedDocs); + int row = 0; + mFileList = new QTableWidget(this); + mFileList->horizontalHeader()->hide(); + mFileList->setColumnCount(3); + mFileList->setColumnWidth(0, 20); + mFileList->setColumnHidden(2, true); + mFileList->verticalHeader()->hide(); + mFileList->setShowGrid(false); + mFileList->setEditTriggers(QAbstractItemView::NoEditTriggers); + mFileList->setFocusPolicy(Qt::NoFocus); + mFileList->horizontalHeader()->setStretchLastSection( true ); + // fill the table + i.toBack(); //jump to the end of list to fill the table backwards + while (i.hasPrevious()) { + i.previous(); + mFileList->setRowCount(mFileList->rowCount()+1); + + // checkbox in front of filename + QTableWidgetItem *tmp0 = new QTableWidgetItem(); + tmp0->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled ); + tmp0->setCheckState(Qt::Checked); + mFileList->setItem(row, 0, tmp0); + + // filename + QTableWidgetItem *tmp1 = new QTableWidgetItem(i.value()); + mFileList->setItem(row, 1, tmp1); + + // tab-index in hidden column + QTableWidgetItem *tmp2 = new QTableWidgetItem(QString::number(i.key())); + mFileList->setItem(row, 2, tmp2); + ++row; + } + /* + * Warnbox with icon and text + */ + QPixmap *pixmap = new QPixmap(":error.png"); + QLabel *warnicon = new QLabel(); + warnicon->setPixmap(*pixmap); + QLabel *warnlabel = new QLabel(tr("<h3>%1 files contain unsaved information.<br/>Save the changes before closing?</h3>").arg(row)); + QHBoxLayout *warnBoxLayout = new QHBoxLayout(); + warnBoxLayout->addWidget(warnicon); + warnBoxLayout->addWidget(warnlabel); + warnBoxLayout->setAlignment(Qt::AlignLeft); + QWidget *warnBox = new QWidget(this); + warnBox->setLayout(warnBoxLayout); + + /* + * Two labels on top and under the filelist + */ + QLabel *checkLabel = new QLabel(tr("Check the files you want to save:")); + QLabel *notelabel = new QLabel(tr("<b>Note:</b> If you don't save these files, all changes are lost.<br/>")); + + /* + * Buttonbox + */ + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Discard |QDialogButtonBox::Save | QDialogButtonBox::Cancel); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + QPushButton* btnNoKey = buttonBox->button(QDialogButtonBox::Discard); + connect(btnNoKey, SIGNAL(clicked()), SLOT(slotMyDiscard())); + + /* + * Set the layout + */ + QVBoxLayout *vbox = new QVBoxLayout(); + vbox->addWidget(warnBox); + vbox->addWidget(checkLabel); + vbox->addWidget(mFileList); + vbox->addWidget(notelabel); + vbox->addWidget(buttonBox); + this->setLayout(vbox); +} + + +void QuitDialog::slotMyDiscard() +{ + discarded =true; + reject(); +} + +bool QuitDialog::isDiscarded() +{ + return discarded; +} + +QList <int> QuitDialog::getTabIdsToSave() +{ + QList <int> tabIdsToSave; + for (int i = 0; i < mFileList->rowCount(); i++) { + if (mFileList->item(i, 0)->checkState() == Qt::Checked) { + tabIdsToSave << mFileList->item(i, 2)->text().toInt(); + } + } + return tabIdsToSave; +} + diff --git a/src/quitdialog.h b/src/quitdialog.h new file mode 100755 index 0000000..bc24712 --- /dev/null +++ b/src/quitdialog.h @@ -0,0 +1,50 @@ +/* + * keymgmt.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __QUITDIALOG_H__ +#define __QUITDIALOG_H__ + +#include <QtGui> + +QT_BEGIN_NAMESPACE +class QTableWidget; +QT_END_NAMESPACE + +class QuitDialog : public QDialog +{ + Q_OBJECT + +public: + QuitDialog(QWidget *parent,QHash<int, QString> unsavedDocs); + bool isDiscarded(); + QList <int> getTabIdsToSave(); + +private slots: + void slotMyDiscard(); + +private: + QAction *closeAct; + QLabel *nameLabel; + bool discarded; + QTableWidget *mFileList; +}; + +#endif // __QUITDIALOG_H__ diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp new file mode 100755 index 0000000..a99b832 --- /dev/null +++ b/src/settingsdialog.cpp @@ -0,0 +1,716 @@ +/* + * settingsdialog.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "settingsdialog.h" + +SettingsDialog::SettingsDialog(GpgME::GpgContext *ctx, QWidget *parent) + : QDialog(parent) +{ + mCtx=ctx; + tabWidget = new QTabWidget; + generalTab = new GeneralTab(mCtx); + appearanceTab = new AppearanceTab; + mimeTab = new MimeTab; + keyserverTab = new KeyserverTab; + advancedTab = new AdvancedTab; + gpgPathsTab = new GpgPathsTab; + + tabWidget->addTab(generalTab, tr("General")); + tabWidget->addTab(appearanceTab, tr("Appearance")); + tabWidget->addTab(mimeTab, tr("PGP/Mime")); + tabWidget->addTab(keyserverTab, tr("Keyserver")); + tabWidget->addTab(gpgPathsTab, tr("Gpg paths")); + tabWidget->addTab(advancedTab, tr("Advanced")); + + buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok + | QDialogButtonBox::Cancel); + + connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotAccept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(tabWidget); + mainLayout->addWidget(buttonBox); + setLayout(mainLayout); + + setWindowTitle(tr("Settings")); + + // slots for handling the restartneeded member + this->slotSetRestartNeeded(false); + connect(generalTab, SIGNAL(signalRestartNeeded(bool)), this, SLOT(slotSetRestartNeeded(bool))); + connect(appearanceTab, SIGNAL(signalRestartNeeded(bool)), this, SLOT(slotSetRestartNeeded(bool))); + connect(mimeTab, SIGNAL(signalRestartNeeded(bool)), this, SLOT(slotSetRestartNeeded(bool))); + connect(keyserverTab, SIGNAL(signalRestartNeeded(bool)), this, SLOT(slotSetRestartNeeded(bool))); + connect(advancedTab, SIGNAL(signalRestartNeeded(bool)), this, SLOT(slotSetRestartNeeded(bool))); + + connect(this, SIGNAL(signalRestartNeeded(bool)), parent, SLOT(slotSetRestartNeeded(bool))); + + exec(); +} + +bool SettingsDialog::getRestartNeeded() +{ + return this->restartNeeded; +} + +void SettingsDialog::slotSetRestartNeeded(bool needed) +{ + this->restartNeeded = needed; +} + +void SettingsDialog::slotAccept() +{ + generalTab->applySettings(); + mimeTab->applySettings(); + appearanceTab->applySettings(); + keyserverTab->applySettings(); + advancedTab->applySettings(); + gpgPathsTab->applySettings(); + if (getRestartNeeded()) { + emit signalRestartNeeded(true); + } + close(); +} + +// http://www.informit.com/articles/article.aspx?p=1405555&seqNum=3 +// http://developer.qt.nokia.com/wiki/How_to_create_a_multi_language_application +QHash<QString, QString> SettingsDialog::listLanguages() +{ + QHash<QString, QString> languages; + + languages.insert("", tr("System Default")); + + QString appPath = qApp->applicationDirPath(); + QDir qmDir = QDir(appPath + "/ts/"); + QStringList fileNames = + qmDir.entryList(QStringList("gpg4usb_*.qm")); + + for (int i = 0; i < fileNames.size(); ++i) { + QString locale = fileNames[i]; + locale.truncate(locale.lastIndexOf('.')); + locale.remove(0, locale.indexOf('_') + 1); + + // this works in qt 4.8 + QLocale qloc(locale); + #if QT_VERSION < 0x040800 + QString language = QLocale::languageToString(qloc.language()) +" (" + locale + ")"; //+ " (" + QLocale::languageToString(qloc.language()) + ")"; + #else + QString language = qloc.nativeLanguageName() +" (" + locale + ")"; //+ " (" + QLocale::languageToString(qloc.language()) + ")"; + #endif + languages.insert(locale, language); + } + return languages; +} + + + +GeneralTab::GeneralTab(GpgME::GpgContext *ctx,QWidget *parent) + : QWidget(parent) +{ + mCtx=ctx; + + /***************************************** + * remember Password-Box + *****************************************/ + QGroupBox *rememberPasswordBox = new QGroupBox(tr("Remember Password")); + QHBoxLayout *rememberPasswordBoxLayout = new QHBoxLayout(); + rememberPasswordCheckBox = new QCheckBox(tr("Remember password until closing gpg4usb"), this); + rememberPasswordBoxLayout->addWidget(rememberPasswordCheckBox); + rememberPasswordBox->setLayout(rememberPasswordBoxLayout); + + /***************************************** + * Save-Checked-Keys-Box + *****************************************/ + QGroupBox *saveCheckedKeysBox = new QGroupBox(tr("Save Checked Keys")); + QHBoxLayout *saveCheckedKeysBoxLayout = new QHBoxLayout(); + saveCheckedKeysCheckBox = new QCheckBox(tr("Save checked private keys on exit and restore them on next start."), this); + saveCheckedKeysBoxLayout->addWidget(saveCheckedKeysCheckBox); + saveCheckedKeysBox->setLayout(saveCheckedKeysBoxLayout); + + /***************************************** + * Key-Impport-Confirmation Box + *****************************************/ + QGroupBox *importConfirmationBox = new QGroupBox(tr("Confirm drag'n'drop key import")); + QHBoxLayout *importConfirmationBoxLayout = new QHBoxLayout(); + importConfirmationCheckBox= new QCheckBox(tr("Import files dropped on the keylist without confirmation."), this); + importConfirmationBoxLayout->addWidget(importConfirmationCheckBox); + importConfirmationBox->setLayout(importConfirmationBoxLayout); + + /***************************************** + * Language Select Box + *****************************************/ + QGroupBox *langBox = new QGroupBox(tr("Language")); + QVBoxLayout *langBoxLayout = new QVBoxLayout(); + langSelectBox = new QComboBox; + lang = SettingsDialog::listLanguages(); + + foreach(QString l , lang) { + langSelectBox->addItem(l); + } + + langBoxLayout->addWidget(langSelectBox); + langBoxLayout->addWidget(new QLabel(tr("<b>NOTE: </b> Gpg4usb will restart automatically if you change the language!"))); + langBox->setLayout(langBoxLayout); + connect(langSelectBox,SIGNAL(currentIndexChanged(int)),this,SLOT(slotLanguageChanged())); + + /***************************************** + * Own Key Select Box + *****************************************/ + QGroupBox *ownKeyBox = new QGroupBox(tr("Own key")); + QVBoxLayout *ownKeyBoxLayout = new QVBoxLayout(); + ownKeySelectBox = new QComboBox; + + ownKeyBox->setLayout(ownKeyBoxLayout); + mKeyList = new KeyList(mCtx); + + // Fill the keyid hashmap + keyIds.insert("", tr("<none>")); + + foreach (QString keyid, *mKeyList->getAllPrivateKeys()) { + gpgme_key_t key = mCtx->getKeyDetails(keyid); + QString newKey = " (" + keyid + ")"; + if (! QString(key->uids->email).isEmpty()) { + newKey.prepend( " <"+ QString::fromUtf8(key->uids->email) +">"); + } + if (! QString(key->uids->name).isEmpty()) { + newKey.prepend( " "+ QString::fromUtf8(key->uids->name)); + } + keyIds.insert(key->uids->uid, newKey); + } + foreach(QString k , keyIds) { + ownKeySelectBox->addItem(k); + } + connect(ownKeySelectBox,SIGNAL(currentIndexChanged(int)),this,SLOT(slotOwnKeyIdChanged())); + + ownKeyBoxLayout->addWidget(new QLabel(tr("Encrypt all messages additionally to the chosen key:"))); + ownKeyBoxLayout->addWidget(ownKeySelectBox); + + /***************************************** + * Mainlayout + *****************************************/ + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(rememberPasswordBox); + mainLayout->addWidget(saveCheckedKeysBox); + mainLayout->addWidget(importConfirmationBox); + mainLayout->addWidget(langBox); + mainLayout->addWidget(ownKeyBox); + + setSettings(); + mainLayout->addStretch(1); + setLayout(mainLayout); +} + +/********************************** + * Read the settings from config + * and set the buttons and checkboxes + * appropriately + **********************************/ +void GeneralTab::setSettings() +{ + QSettings settings; + // Keysaving + if (settings.value("keys/keySave").toBool()) { + saveCheckedKeysCheckBox->setCheckState(Qt::Checked); + } + + // Remember Password + if (settings.value("general/rememberPassword").toBool()) { + rememberPasswordCheckBox->setCheckState(Qt::Checked); + } + + // Language setting + QString langKey = settings.value("int/lang").toString(); + QString langValue = lang.value(langKey); + if (langKey != "") { + langSelectBox->setCurrentIndex(langSelectBox->findText(langValue)); + } + + // Get own key information from keydb/gpg.conf (if contained) + QFile gpgConfFile(qApp->applicationDirPath() + "/keydb/gpg.conf"); + gpgConfFile.open(QFile::ReadOnly); + while (!gpgConfFile.atEnd()) + { + QString line = gpgConfFile.readLine(); + if (line.startsWith("recipient")){ + QStringList args; + + // get key id from gpg.conf + args=line.split(" "); + ownKeyId = args.at(1); + // remove linebreak at end of id + ownKeyId.remove("\n"); + ownKeyId.remove("\r"); + } + } + gpgConfFile.close(); + if (ownKeyId.isEmpty()) { + ownKeySelectBox->setCurrentIndex(0); + } else { + ownKeySelectBox->setCurrentIndex(ownKeySelectBox->findText(ownKeyId, Qt::MatchContains)); + } + + if (settings.value("general/confirmImportKeys",Qt::Checked).toBool()){ + importConfirmationCheckBox->setCheckState(Qt::Checked); + } +} + +/*********************************** + * get the values of the buttons and + * write them to settings-file + *************************************/ +void GeneralTab::applySettings() +{ + QSettings settings; + settings.setValue("keys/keySave", saveCheckedKeysCheckBox->isChecked()); + // TODO: clear passwordCache instantly on unset rememberPassword + settings.setValue("general/rememberPassword", rememberPasswordCheckBox->isChecked()); + settings.setValue("int/lang", lang.key(langSelectBox->currentText())); + settings.setValue("general/confirmImportKeys", importConfirmationCheckBox->isChecked()); +} + +void GeneralTab::slotLanguageChanged() +{ + emit signalRestartNeeded(true); +} + +void GeneralTab::slotOwnKeyIdChanged() +{ + // Set ownKeyId to currently selected + + QHashIterator<QString, QString> i(keyIds); + while (i.hasNext()) { + i.next(); + if (ownKeySelectBox->currentText() == i.value()) { + ownKeyId = i.key(); + } + } + + /***************************************** + * Write keyid of own key to gpg.conf + *****************************************/ + QFile gpgConfFile(qApp->applicationDirPath() + "/keydb/gpg.conf"); + gpgConfFile.open(QFile::ReadWrite); + QFile gpgConfTempFile(qApp->applicationDirPath() + "/keydb/gpg.conf.swp"); + gpgConfTempFile.open(QFile::WriteOnly); + + // remove line with the hidden-encrypt-to + while (!gpgConfFile.atEnd()) + { + QByteArray line = gpgConfFile.readLine(); + if (!line.startsWith("recipient")) { + gpgConfTempFile.write(line); + } + } + + // add line with hidden-encrypt-to, if a key is chosen + if (!ownKeyId.isEmpty()) { + QByteArray string("recipient "); + string.append(ownKeyId); + string.append("\n"); + gpgConfTempFile.write(string); + } + + gpgConfFile.close(); + gpgConfTempFile.close(); + + // move the temporary gpg.conffile to the actual one + gpgConfFile.remove(); + gpgConfTempFile.copy(gpgConfTempFile.fileName(),gpgConfFile.fileName()); + gpgConfTempFile.remove(); +} + +MimeTab::MimeTab(QWidget *parent) + : QWidget(parent) +{ + /***************************************** + * MIME-Parsing-Box + *****************************************/ + QGroupBox *mimeQPBox = new QGroupBox(tr("Decode quoted printable")); + QVBoxLayout *mimeQPBoxLayout = new QVBoxLayout(); + mimeQPCheckBox = new QCheckBox(tr("Try to recognize quoted printable."), this); + mimeQPBoxLayout->addWidget(mimeQPCheckBox); + mimeQPBox->setLayout(mimeQPBoxLayout); + + QGroupBox *mimeParseBox = new QGroupBox(tr("Parse PGP/MIME (Experimental)")); + QVBoxLayout *mimeParseBoxLayout = new QVBoxLayout(); + mimeParseCheckBox = new QCheckBox(tr("Try to split attachments from PGP-MIME ecrypted messages."), this); + mimeParseBoxLayout->addWidget(mimeParseCheckBox); + mimeParseBox->setLayout(mimeParseBoxLayout); + + QGroupBox *mimeOpenAttachmentBox = new QGroupBox(tr("Open with external application (Experimental)")); + QVBoxLayout *mimeOpenAttachmentBoxLayout = new QVBoxLayout(); + QLabel *mimeOpenAttachmentText = new QLabel(tr("Open attachments with default application for the filetype.<br> " + "There are at least two possible problems with this behaviour:" + "<ol><li>File needs to be saved unencrypted to attachments folder.<br> " + "Its your job to clean this folder.</li>" + "<li>The external application may have its own temp files.</li></ol>")); + + //mimeOpenAttachmentBox->setDisabled(true); + mimeOpenAttachmentCheckBox = new QCheckBox(tr("Enable opening with external applications."), this); + + mimeOpenAttachmentBoxLayout->addWidget(mimeOpenAttachmentText); + mimeOpenAttachmentBoxLayout->addWidget(mimeOpenAttachmentCheckBox); + mimeOpenAttachmentBox->setLayout(mimeOpenAttachmentBoxLayout); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(mimeParseBox); + mainLayout->addWidget(mimeOpenAttachmentBox); + mainLayout->addWidget(mimeQPBox); + mainLayout->addStretch(1); + setLayout(mainLayout); + setSettings(); +} + +/********************************** + * Read the settings from config + * and set the buttons and checkboxes + * appropriately + **********************************/ +void MimeTab::setSettings() +{ + QSettings settings; + + // MIME-Parsing + if (settings.value("mime/parsemime").toBool()) mimeParseCheckBox->setCheckState(Qt::Checked); + + // Qouted Printable + if (settings.value("mime/parseQP",true).toBool()) mimeQPCheckBox->setCheckState(Qt::Checked); + + // Open Attachments with external app + if (settings.value("mime/openAttachment").toBool()) mimeOpenAttachmentCheckBox->setCheckState(Qt::Checked); +} + + +/*********************************** + * get the values of the buttons and + * write them to settings-file + *************************************/ +void MimeTab::applySettings() +{ + QSettings settings; + settings.setValue("mime/parsemime" , mimeParseCheckBox->isChecked()); + settings.setValue("mime/parseQP" , mimeQPCheckBox->isChecked()); + settings.setValue("mime/openAttachment" , mimeOpenAttachmentCheckBox->isChecked()); + +} + +AppearanceTab::AppearanceTab(QWidget *parent) + : QWidget(parent) +{ + /***************************************** + * Icon-Size-Box + *****************************************/ + QGroupBox *iconSizeBox = new QGroupBox(tr("Iconsize")); + iconSizeGroup = new QButtonGroup(); + iconSizeSmall = new QRadioButton(tr("small")); + iconSizeMedium = new QRadioButton(tr("medium")); + iconSizeLarge = new QRadioButton(tr("large")); + + iconSizeGroup->addButton(iconSizeSmall, 1); + iconSizeGroup->addButton(iconSizeMedium, 2); + iconSizeGroup->addButton(iconSizeLarge, 3); + + QHBoxLayout *iconSizeBoxLayout = new QHBoxLayout(); + iconSizeBoxLayout->addWidget(iconSizeSmall); + iconSizeBoxLayout->addWidget(iconSizeMedium); + iconSizeBoxLayout->addWidget(iconSizeLarge); + + iconSizeBox->setLayout(iconSizeBoxLayout); + + /***************************************** + * Icon-Style-Box + *****************************************/ + QGroupBox *iconStyleBox = new QGroupBox(tr("Iconstyle")); + iconStyleGroup = new QButtonGroup(); + iconTextButton = new QRadioButton(tr("just text")); + iconIconsButton = new QRadioButton(tr("just icons")); + iconAllButton = new QRadioButton(tr("text and icons")); + + iconStyleGroup->addButton(iconTextButton, 1); + iconStyleGroup->addButton(iconIconsButton, 2); + iconStyleGroup->addButton(iconAllButton, 3); + + QHBoxLayout *iconStyleBoxLayout = new QHBoxLayout(); + iconStyleBoxLayout->addWidget(iconTextButton); + iconStyleBoxLayout->addWidget(iconIconsButton); + iconStyleBoxLayout->addWidget(iconAllButton); + + iconStyleBox->setLayout(iconStyleBoxLayout); + + /***************************************** + * Window-Size-Box + *****************************************/ + QGroupBox *windowSizeBox = new QGroupBox(tr("Windowstate")); + QHBoxLayout *windowSizeBoxLayout = new QHBoxLayout(); + windowSizeCheckBox = new QCheckBox(tr("Save window size and position on exit."), this); + windowSizeBoxLayout->addWidget(windowSizeCheckBox); + windowSizeBox->setLayout(windowSizeBoxLayout); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(iconSizeBox); + mainLayout->addWidget(iconStyleBox); + mainLayout->addWidget(windowSizeBox); + mainLayout->addStretch(1); + setSettings(); + setLayout(mainLayout); +} + +/********************************** + * Read the settings from config + * and set the buttons and checkboxes + * appropriately + **********************************/ +void AppearanceTab::setSettings() +{ + QSettings settings; + + //Iconsize + QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize(); + switch (iconSize.height()) { + case 12: iconSizeSmall->setChecked(true); + break; + case 24:iconSizeMedium->setChecked(true); + break; + case 32:iconSizeLarge->setChecked(true); + break; + } + // Iconstyle + Qt::ToolButtonStyle iconStyle = static_cast<Qt::ToolButtonStyle>(settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon).toUInt()); + switch (iconStyle) { + case Qt::ToolButtonTextOnly: iconTextButton->setChecked(true); + break; + case Qt::ToolButtonIconOnly:iconIconsButton->setChecked(true); + break; + case Qt::ToolButtonTextUnderIcon:iconAllButton->setChecked(true); + break; + default: + break; + } + + // Window Save and Position + if (settings.value("window/windowSave").toBool()) windowSizeCheckBox->setCheckState(Qt::Checked); + +} + +/*********************************** + * get the values of the buttons and + * write them to settings-file + *************************************/ +void AppearanceTab::applySettings() +{ + QSettings settings; + switch (iconSizeGroup->checkedId()) { + case 1: settings.setValue("toolbar/iconsize", QSize(12, 12)); + break; + case 2:settings.setValue("toolbar/iconsize", QSize(24, 24)); + break; + case 3:settings.setValue("toolbar/iconsize", QSize(32, 32)); + break; + } + + switch (iconStyleGroup->checkedId()) { + case 1: settings.setValue("toolbar/iconstyle", Qt::ToolButtonTextOnly); + break; + case 2:settings.setValue("toolbar/iconstyle", Qt::ToolButtonIconOnly); + break; + case 3:settings.setValue("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon); + break; + } + + settings.setValue("window/windowSave", windowSizeCheckBox->isChecked()); +} + +KeyserverTab::KeyserverTab(QWidget *parent) + : QWidget(parent) +{ + QVBoxLayout *mainLayout = new QVBoxLayout(this); + + QLabel *label = new QLabel(tr("Default Keyserver for import:")); + comboBox = new QComboBox; + comboBox->setEditable(false); + comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + + QWidget *addKeyServerBox = new QWidget(this); + QHBoxLayout *addKeyServerLayout = new QHBoxLayout(addKeyServerBox); + QLabel *http = new QLabel("http://"); + newKeyServerEdit = new QLineEdit(this); + QPushButton *newKeyServerButton = new QPushButton(tr("Add to keyserverlist"), this); + connect(newKeyServerButton,SIGNAL(clicked()), this, SLOT(addKeyServer())); + addKeyServerLayout->addWidget(http); + addKeyServerLayout->addWidget(newKeyServerEdit); + addKeyServerLayout->addWidget(newKeyServerButton); + + mainLayout->addWidget(label); + mainLayout->addWidget(comboBox); + mainLayout->addWidget(addKeyServerBox); + mainLayout->addStretch(1); + + // Read keylist from ini-file and fill it into combobox + setSettings(); +} + + +/********************************** + * Read the settings from config + * and set the buttons and checkboxes + * appropriately + **********************************/ +void KeyserverTab::setSettings() +{ + QSettings settings; + QString defKeyserver = settings.value("keyserver/defaultKeyServer").toString(); + + QStringList *keyServerList = new QStringList(); + for(int i=0; i < comboBox->count(); i++) { + keyServerList->append(comboBox->itemText(i)); + } + settings.setValue("keyserver/keyServerList", *keyServerList); +} + +void KeyserverTab::addKeyServer() +{ + if (newKeyServerEdit->text().startsWith("http://")) { + comboBox->addItem(newKeyServerEdit->text()); + } else { + comboBox->addItem("http://" +newKeyServerEdit->text()); + } + comboBox->setCurrentIndex(comboBox->count()-1); +} +/*********************************** + * get the values of the buttons and + * write them to settings-file + *************************************/ +void KeyserverTab::applySettings() +{ + QSettings settings; + settings.setValue("keyserver/defaultKeyServer",comboBox->currentText()); +} + +AdvancedTab::AdvancedTab(QWidget *parent) + : QWidget(parent) +{ + /***************************************** + * Steganography Box + *****************************************/ + QGroupBox *steganoBox = new QGroupBox(tr("Show Steganography Options [Advanced]")); + QHBoxLayout *steganoBoxLayout = new QHBoxLayout(); + steganoCheckBox= new QCheckBox(tr("Show Steganographic Options."), this); + steganoBoxLayout->addWidget(steganoCheckBox); + steganoBox->setLayout(steganoBoxLayout); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(steganoBox); + setSettings(); + mainLayout->addStretch(1); + setLayout(mainLayout); + +} + +void AdvancedTab::setSettings() +{ + QSettings settings; + if (settings.value("advanced/steganography").toBool()){ + steganoCheckBox->setCheckState(Qt::Checked); + } +} + +void AdvancedTab::applySettings() +{ + QSettings settings; + settings.setValue("advanced/steganography", steganoCheckBox->isChecked()); +} + +GpgPathsTab::GpgPathsTab(QWidget *parent) + : QWidget(parent) +{ + setSettings(); + + /***************************************** + * Keydb Box + *****************************************/ + QGroupBox *keydbBox = new QGroupBox(tr("Relative path to keydb")); + QGridLayout *keydbBoxLayout = new QGridLayout(); + + // Label containing the current keydbpath relative to default keydb path + keydbLabel = new QLabel(accKeydbPath,this); + + QPushButton *keydbButton = new QPushButton("Change keydb path",this); + connect(keydbButton, SIGNAL(clicked()), this, SLOT(chooseKeydbDir())); + QPushButton *keydbDefaultButton = new QPushButton("Set keydb to default path",this); + connect(keydbDefaultButton, SIGNAL(clicked()), this, SLOT(setKeydbPathToDefault())); + + keydbBox->setLayout(keydbBoxLayout); + keydbBoxLayout->addWidget(new QLabel(tr("Current keydb path: ")),1,1); + keydbBoxLayout->addWidget(keydbLabel,1,2); + keydbBoxLayout->addWidget(keydbButton,1,3); + keydbBoxLayout->addWidget(keydbDefaultButton,2,3); + keydbBoxLayout->addWidget(new QLabel(tr("<b>NOTE: </b> Gpg4usb will restart automatically if you change the keydb path!")),3,1,1,3); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(keydbBox); + mainLayout->addStretch(1); + setLayout(mainLayout); +} + +QString GpgPathsTab::getRelativePath(const QString dir1,const QString dir2) +{ + QDir dir(dir1); + QString s; + + s = dir.relativeFilePath(dir2); + qDebug() << "relative path: " << s; + if (s.isEmpty()) { + s = "."; + } + return s; +} + +void GpgPathsTab::setKeydbPathToDefault() +{ + accKeydbPath = "."; + keydbLabel->setText("."); +} + +QString GpgPathsTab::chooseKeydbDir() +{ + QString dir = QFileDialog::getExistingDirectory(this,tr ("Choose keydb directory"),accKeydbPath,QFileDialog::ShowDirsOnly); + + accKeydbPath = getRelativePath(defKeydbPath, dir); + keydbLabel->setText(accKeydbPath); + return ""; +} + +void GpgPathsTab::setSettings() +{ + defKeydbPath = qApp->applicationDirPath() + "/keydb"; + + QSettings settings; + accKeydbPath = settings.value("gpgpaths/keydbpath").toString(); + if (accKeydbPath.isEmpty()) { + accKeydbPath = "."; + } +} + +void GpgPathsTab::applySettings() +{ + QSettings settings; + settings.setValue("gpgpaths/keydbpath",accKeydbPath); +} diff --git a/src/settingsdialog.h b/src/settingsdialog.h new file mode 100755 index 0000000..0b5f164 --- /dev/null +++ b/src/settingsdialog.h @@ -0,0 +1,217 @@ +/* + * settingsdialog.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __SETTINGSDIALOG_H__ +#define __SETTINGSDIALOG_H__ + +#include "keylist.h" + +#include <QHash> +#include <QWidget> +#include <QtGui> + +QT_BEGIN_NAMESPACE +class QDialog; +class QRadioButton; +class QDialogButtonBox; +class QHBoxLayout; +class QVBoxLayout; +class QComboBox; +class QCheckBox; +class QDebug; +class QSettings; +class QApplication; +class QDir; +class QTranslator; +class QLabel; +class QButtonGroup; +class QGroupBox; +class QFileInfo; +class QTabWidget; +QT_END_NAMESPACE + +class GeneralTab : public QWidget + { + Q_OBJECT + + public: + GeneralTab(GpgME::GpgContext *ctx, QWidget *parent = 0); + void setSettings(); + void applySettings(); + + private: + QCheckBox *rememberPasswordCheckBox; + QCheckBox *importConfirmationcheckBox; + QCheckBox *saveCheckedKeysCheckBox; + QCheckBox *importConfirmationCheckBox; + QComboBox *langSelectBox; + QComboBox *ownKeySelectBox; + QHash<QString, QString> lang; + QHash<QString, QString> keyIds; + QString ownKeyId; + KeyList *mKeyList; + GpgME::GpgContext *mCtx; /** The current gpg context */ + +private slots: + void slotOwnKeyIdChanged(); + void slotLanguageChanged(); + +signals: + void signalRestartNeeded(bool needed); + +}; + + class MimeTab : public QWidget + { + Q_OBJECT + + public: + MimeTab(QWidget *parent = 0); + void setSettings(); + void applySettings(); + + private: + QCheckBox *mimeParseCheckBox; + QCheckBox *mimeQPCheckBox; + QCheckBox *mimeOpenAttachmentCheckBox; + + signals: + void signalRestartNeeded(bool needed); + + }; + + class AppearanceTab : public QWidget + { + Q_OBJECT + + public: + //void setSettings(); + AppearanceTab(QWidget *parent = 0); + void setSettings(); + void applySettings(); + + private: + QButtonGroup *iconStyleGroup; + QRadioButton *iconSizeSmall; + QRadioButton *iconSizeMedium; + QRadioButton *iconSizeLarge; + QButtonGroup *iconSizeGroup; + QRadioButton *iconTextButton; + QRadioButton *iconIconsButton; + QRadioButton *iconAllButton; + QCheckBox *windowSizeCheckBox; + + signals: + void signalRestartNeeded(bool needed); + + }; + + class KeyserverTab : public QWidget + { + Q_OBJECT + + public: + KeyserverTab(QWidget *parent = 0); + void setSettings(); + void applySettings(); + + private: + QComboBox *comboBox; + QLineEdit *newKeyServerEdit; + + private slots: + void addKeyServer(); + + signals: + void signalRestartNeeded(bool needed); + + }; + + class AdvancedTab : public QWidget + { + Q_OBJECT + + public: + AdvancedTab(QWidget *parent = 0); + void setSettings(); + void applySettings(); + + private: + QCheckBox *steganoCheckBox; + + signals: + void signalRestartNeeded(bool needed); + + }; + + class GpgPathsTab : public QWidget + { + Q_OBJECT + public: + GpgPathsTab(QWidget *parent = 0); + void applySettings(); + +private: + QString getRelativePath(const QString dir1,const QString dir2); + QString defKeydbPath; /** The default keydb path used by gpg4usb */ + QString accKeydbPath; /** The currently used keydb path */ + QLabel *keydbLabel; + void setSettings(); + + private slots: + QString chooseKeydbDir(); + void setKeydbPathToDefault(); + + }; + + class SettingsDialog : public QDialog +{ + Q_OBJECT + + public: + SettingsDialog(GpgME::GpgContext *ctx, QWidget *parent = 0); + GeneralTab *generalTab; + MimeTab *mimeTab; + AppearanceTab *appearanceTab; + KeyserverTab *keyserverTab; + AdvancedTab *advancedTab; + GpgPathsTab *gpgPathsTab; + static QHash<QString, QString> listLanguages(); + + public slots: + void slotAccept(); + + signals: + void signalRestartNeeded(bool needed); + + private: + QTabWidget *tabWidget; + QDialogButtonBox *buttonBox; + GpgME::GpgContext *mCtx; /** The current gpg context */ + bool restartNeeded; + bool getRestartNeeded(); + + private slots: + void slotSetRestartNeeded(bool needed); + +}; + +#endif // __SETTINGSDIALOG_H__ diff --git a/src/textedit.cpp b/src/textedit.cpp new file mode 100644 index 0000000..e28304d --- /dev/null +++ b/src/textedit.cpp @@ -0,0 +1,573 @@ +/* + * textedit.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "textedit.h" + +TextEdit::TextEdit() +{ + countPage = 0; + tabWidget = new QTabWidget(this); + tabWidget->setMovable(true); + tabWidget->setTabsClosable(true); + tabWidget->setDocumentMode(true); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(tabWidget); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + setLayout(layout); + + connect(tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(removeTab(int))); + slotNewTab(); + setAcceptDrops(false); +} + +void TextEdit::slotNewTab() +{ + QString header = tr("untitled") + + QString::number(++countPage)+".txt"; + + EditorPage *page = new EditorPage(); + tabWidget->addTab(page, header); + tabWidget->setCurrentIndex(tabWidget->count() - 1); + page->getTextPage()->setFocus(); + connect(page->getTextPage()->document(), SIGNAL(modificationChanged(bool)), this, SLOT(slotShowModified())); + } + +void TextEdit::slotNewHelpTab(QString title, QString path) +{ + + HelpPage *page = new HelpPage(path); + tabWidget->addTab(page, title); + tabWidget->setCurrentIndex(tabWidget->count() - 1); + +} + +void TextEdit::slotOpen() +{ + QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open file"), + QDir::currentPath()); + foreach (QString fileName,fileNames){ + if (!fileName.isEmpty()) { + QFile file(fileName); + + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + EditorPage *page = new EditorPage(fileName); + + QTextStream in(&file); + QApplication::setOverrideCursor(Qt::WaitCursor); + page->getTextPage()->setPlainText(in.readAll()); + page->setFilePath(fileName); + QTextDocument *document = page->getTextPage()->document(); + document->setModified(false); + + tabWidget->addTab(page, strippedName(fileName)); + tabWidget->setCurrentIndex(tabWidget->count() - 1); + QApplication::restoreOverrideCursor(); + page->getTextPage()->setFocus(); + connect(page->getTextPage()->document(), SIGNAL(modificationChanged(bool)), this, SLOT(slotShowModified())); + //enableAction(true) + file.close(); + } else { + QMessageBox::warning(this, tr("Application"), + tr("Cannot read file %1:\n%2.") + .arg(fileName) + .arg(file.errorString())); + } + } + } +} + +void TextEdit::slotSave() +{ + if (tabWidget->count() == 0 || slotCurPage() == 0) { + return; + } + + QString fileName = slotCurPage()->getFilePath(); + + if (fileName.isEmpty()) { + //QString docname = tabWidget->tabText(tabWidget->currentIndex()); + //docname.remove(0,2); + slotSaveAs(); + } else { + saveFile(fileName); + } +} + +bool TextEdit::saveFile(const QString &fileName) +{ + if (fileName.isEmpty()) { + return false; + } + + QFile file(fileName); + + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + EditorPage *page = slotCurPage(); + + QTextStream outputStream(&file); + QApplication::setOverrideCursor(Qt::WaitCursor); + outputStream << page->getTextPage()->toPlainText(); + QApplication::restoreOverrideCursor(); + QTextDocument *document = page->getTextPage()->document(); + + document->setModified(false); + + int curIndex = tabWidget->currentIndex(); + tabWidget->setTabText(curIndex, strippedName(fileName)); + page->setFilePath(fileName); + // statusBar()->showMessage(tr("File saved"), 2000); + file.close(); + return true; + } else { + QMessageBox::warning(this, tr("File"), + tr("Cannot write file %1:\n%2.") + .arg(fileName) + .arg(file.errorString())); + return false; + } +} + + +bool TextEdit::slotSaveAs() +{ + if (tabWidget->count() == 0 || slotCurPage() == 0) { + return true; + } + + EditorPage *page = slotCurPage(); + QString path; + if(page->getFilePath() != "") { + path = page->getFilePath(); + } else { + path = tabWidget->tabText(tabWidget->currentIndex()).remove(0,2); + } + + QString fileName = QFileDialog::getSaveFileName(this, tr("Save file "), + path); + return saveFile(fileName); +} + +void TextEdit::slotCloseTab() +{ + removeTab(tabWidget->currentIndex()); + if (tabWidget->count() != 0) { + slotCurPage()->getTextPage()->setFocus(); + } +} + +void TextEdit::removeTab(int index) +{ + // Do nothing, if no tab is opened + if (tabWidget->count() == 0) { + return; + } + + // get the index of the actual current tab + int lastIndex = tabWidget->currentIndex(); + + // set the focus to argument index + tabWidget->setCurrentIndex(index); + + if (maybeSaveCurrentTab(true)) { + tabWidget->removeTab(index); + + if(index >= lastIndex) { + tabWidget->setCurrentIndex(lastIndex); + } else { + tabWidget->setCurrentIndex(lastIndex-1); + } + } + + if (tabWidget->count() == 0) { + // enableAction(false); + } +} + + + /** + * Check if current may need to be saved. + * Call this function before closing the currently active tab- + * + * If it returns false, the close event should be aborted. + */ +bool TextEdit::maybeSaveCurrentTab(bool askToSave) { + + EditorPage *page = slotCurPage(); + // if this page is no textedit, there should be nothing to save + if(page == 0) { + return true; + } + QTextDocument *document = page->getTextPage()->document(); + + if (document->isModified()) { + QMessageBox::StandardButton result = QMessageBox::Cancel; + + // write title of tab to docname and remove the leading * + QString docname = tabWidget->tabText(tabWidget->currentIndex()); + docname.remove(0,2); + + QString filePath = page->getFilePath(); + if (askToSave) { + result = QMessageBox::warning(this, tr("Unsaved document"), + tr("<h3>The document \"%1\" has been modified.<br/>Do you want to save your changes?</h3>").arg(docname)+ + tr("<b>Note:</b> If you don't save these files, all changes are lost.<br/>"), + QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + } + if ((result == QMessageBox::Save) || (!askToSave)) { + if (filePath == "") { + //QString docname = tabWidget->tabText(tabWidget->currentIndex()); + //docname.remove(0,2); + return slotSaveAs(); + } else { + return saveFile(filePath); + } + } else if (result == QMessageBox::Discard) { + return true; + } else { + return false; + } + } + return true; +} + +bool TextEdit::maybeSaveAnyTab() +{ + // get a list of all unsaved documents and their tabids + QHash<int, QString> unsavedDocs = this->unsavedDocuments(); + + /* + * no unsaved documents, so app can be closed + */ + if (unsavedDocs.size() == 0) { + return true; + } + /* + * only 1 unsaved document -> set modified tab as current + * and show normal unsaved doc dialog + */ + if(unsavedDocs.size() == 1) { + int modifiedTab = unsavedDocs.keys().at(0); + tabWidget->setCurrentIndex(modifiedTab); + return maybeSaveCurrentTab(true); + } + + /* + * more than one unsaved documents + */ + if(unsavedDocs.size() > 1) { + QHashIterator<int, QString> i (unsavedDocs); + + QuitDialog *dialog; + dialog=new QuitDialog(this, unsavedDocs); + int result = dialog->exec(); + + // if result is QDialog::Rejected, discard or cancel was clicked + if (result == QDialog::Rejected){ + // return true, if discard is clicked, so app can be closed + if (dialog->isDiscarded()){ + return true; + } else { + return false; + } + } else { + bool allsaved=true; + QList <int> tabIdsToSave = dialog->getTabIdsToSave(); + + foreach (int tabId, tabIdsToSave) { + tabWidget->setCurrentIndex(tabId); + if (! maybeSaveCurrentTab(false)) { + allsaved=false; + } + } + if (allsaved) { + return true; + } else { + return false; + } + } + } + // code should never reach this statement + return false; +} + + +QTextEdit* TextEdit::curTextPage() +{ + EditorPage *curTextPage = qobject_cast<EditorPage *>(tabWidget->currentWidget()); + if(curTextPage != 0) { + return curTextPage->getTextPage(); + } else { + return 0; + } +} + +QTextBrowser* TextEdit::curHelpPage() { + HelpPage *curHelpPage = qobject_cast<HelpPage *>(tabWidget->currentWidget()); + if(curHelpPage != 0) { + return curHelpPage->getBrowser(); + } else { + return 0; + } +} + +int TextEdit::tabCount() +{ + return tabWidget->count(); +} + +EditorPage* TextEdit::slotCurPage() +{ + EditorPage *curPage = qobject_cast<EditorPage *>(tabWidget->currentWidget()); + return curPage; +} + +void TextEdit::slotQuote() +{ + if (tabWidget->count() == 0 || curTextPage() == 0) { + return; + } + + QTextCursor cursor(curTextPage()->document()); + + // beginEditBlock and endEditBlock() let operation look like single undo/redo operation + cursor.beginEditBlock(); + cursor.setPosition(0); + cursor.insertText("> "); + while (!cursor.isNull() && !cursor.atEnd()) { + cursor.movePosition(QTextCursor::EndOfLine); + cursor.movePosition(QTextCursor::NextCharacter); + if(!cursor.atEnd()) { + cursor.insertText("> "); + } + } + cursor.endEditBlock(); +} + +void TextEdit::slotFillTextEditWithText(QString text) { + QTextCursor cursor(curTextPage()->document()); + cursor.beginEditBlock(); + this->curTextPage()->selectAll(); + this->curTextPage()->insertPlainText(text); + cursor.endEditBlock(); +} + +void TextEdit::loadFile(const QString &fileName) +{ + QFile file(fileName); + if (!file.open(QFile::ReadOnly | QFile::Text)) { + QMessageBox::warning(this, tr("Application"), + tr("Cannot read file %1:\n%2.") + .arg(fileName) + .arg(file.errorString())); + return; + } + QTextStream in(&file); + QApplication::setOverrideCursor(Qt::WaitCursor); + curTextPage()->setPlainText(in.readAll()); + QApplication::restoreOverrideCursor(); + slotCurPage()->setFilePath(fileName); + tabWidget->setTabText(tabWidget->currentIndex(), strippedName(fileName)); + file.close(); + // statusBar()->showMessage(tr("File loaded"), 2000); +} + +QString TextEdit::strippedName(const QString &fullFileName) +{ + return QFileInfo(fullFileName).fileName(); +} + +void TextEdit::slotPrint() +{ + if (tabWidget->count() == 0) { + return; + } + +#ifndef QT_NO_PRINTER + QTextDocument *document; + if(curTextPage() == 0) { + document = curHelpPage()->document(); + } else { + document = curTextPage()->document(); + } + QPrinter printer; + + QPrintDialog *dlg = new QPrintDialog(&printer, this); + if (dlg->exec() != QDialog::Accepted) { + return; + } + document->print(&printer); + + //statusBar()->showMessage(tr("Ready"), 2000); +#endif +} + +void TextEdit::slotShowModified() { + int index=tabWidget->currentIndex(); + QString title= tabWidget->tabText(index); + // if doc is modified now, add leading * to title, + // otherwise remove the leading * from the title + if(curTextPage()->document()->isModified()) { + tabWidget->setTabText(index, title.prepend("* ")); + } else { + tabWidget->setTabText(index, title.remove(0,2)); + } +} + +void TextEdit::slotSwitchTabUp() { + if (tabWidget->count() > 1) { + int newindex=(tabWidget->currentIndex()+1)%(tabWidget->count()); + tabWidget->setCurrentIndex(newindex); + } +} + +void TextEdit::slotSwitchTabDown() { + if (tabWidget->count() > 1) { + int newindex=(tabWidget->currentIndex()-1+tabWidget->count())%tabWidget->count(); + tabWidget->setCurrentIndex(newindex); + } +} + +/* + * return a hash of tabindexes and title of unsaved tabs + */ +QHash<int, QString> TextEdit::unsavedDocuments() { + QHash<int, QString> unsavedDocs; // this list could be used to implement gedit like "unsaved changed"-dialog + + for(int i=0; i < tabWidget->count(); i++) { + EditorPage *ep = qobject_cast<EditorPage *> (tabWidget->widget(i)); + if(ep != 0 && ep->getTextPage()->document()->isModified()) { + QString docname = tabWidget->tabText(i); + // remove * before name of modified doc + docname.remove(0,2); + unsavedDocs.insert(i, docname); + } + } + return unsavedDocs; +} + +void TextEdit::slotCut() +{ + if (tabWidget->count() == 0 || curTextPage() == 0) { + return; + } + + curTextPage()->cut(); +} + +void TextEdit::slotCopy() +{ + if (tabWidget->count() == 0) { + return; + } + + if(curTextPage() != 0) { + curTextPage()->copy(); + } else { + curHelpPage()->copy(); + } + + +} + +void TextEdit::slotPaste() +{ + if (tabWidget->count() == 0 || curTextPage() == 0) { + return; + } + + curTextPage()->paste(); +} + +void TextEdit::slotUndo() +{ + if (tabWidget->count() == 0 || curTextPage() == 0) { + return; + } + + curTextPage()->undo(); +} + +void TextEdit::slotRedo() +{ + if (tabWidget->count() == 0 || curTextPage() == 0) { + return; + } + + curTextPage()->redo(); +} + +void TextEdit::slotZoomIn() +{ + if (tabWidget->count() == 0 ) { + return; + } + + if(curTextPage() != 0) { + curTextPage()->zoomIn(); + } else { + curHelpPage()->zoomIn(); + } + +} + +void TextEdit::slotZoomOut() +{ + if (tabWidget->count() == 0 ) { + return; + } + + if(curTextPage() != 0) { + curTextPage()->zoomOut(); + } else { + curHelpPage()->zoomOut(); + } +} + +void TextEdit::slotSelectAll() +{ + if (tabWidget->count() == 0 || curTextPage() == 0) { + return; + } + + curTextPage()->selectAll(); +} + +/*void TextEdit::dragEnterEvent(QDragEnterEvent *event) +{ + if (event->mimeData()->hasFormat("text/plain")) + qDebug() << "enter textedit drag action"; + event->acceptProposedAction(); +} + +void TextEdit::dropEvent(QDropEvent* event) +{ + curTextPage()->setPlainText(event->mimeData()->text()); + + foreach (QUrl tmp, event->mimeData()->urls()) + { + qDebug() << tmp; + } + + //event->acceptProposedAction(); +} +*/ diff --git a/src/textedit.h b/src/textedit.h new file mode 100644 index 0000000..12e4970 --- /dev/null +++ b/src/textedit.h @@ -0,0 +1,275 @@ +/* + * textedit.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __TEXTEDIT_H__ +#define __TEXTEDIT_H__ + +#include "editorpage.h" +#include "helppage.h" +#include "quitdialog.h" + +QT_BEGIN_NAMESPACE +class QDebug; +class QtGui; +class QFileDialog; +class QMessageBox; +class QFileInfo; +class QApplication; +class QFile; +class QTextEdit; +class QFileDialog; +class QMessageBox; +class QWidget; +class QString; +class QTabWidget; +QT_END_NAMESPACE + +/** + * @brief TextEdit class + */ +class TextEdit : public QWidget +{ + Q_OBJECT +public: + /** + * @brief + */ + TextEdit(); + + /** + * @details Load the content of file into the current textpage + * + * @param fileName QString containing the filename to load + * @return nothing + */ + void loadFile(const QString &fileName); + + + /** + * @details Checks if there are unsaved documents in any tab, + * which may need to be saved. Call this function before + * closing the programme or all tabs. + * @return \li false, if the close event should be aborted. + * \li true, otherwise + */ + bool maybeSaveAnyTab(); + + int tabCount(); + /** + * @details textpage of the currently activated tab + * @return \li reference to QTextEdit if tab has one + * \li 0 otherwise (e.g. if helppage) + */ + QTextEdit* curTextPage(); + + QTextBrowser* curHelpPage(); + + /** + * @details List of currently unsaved tabs. + * @returns QHash<int, QString> Hash of tabindexes and title of unsaved tabs. + */ + QHash<int, QString> unsavedDocuments(); + + QTabWidget *tabWidget; /** Widget containing the tabs of the editor */ + +public slots: + /** + * @details Return pointer to the currently activated tabpage. + * + */ + EditorPage *slotCurPage(); + + /** + * @details Insert a ">" at the begining of every line of current textedit. + */ + void slotQuote(); + + /** + * @details replace the text of currently active textedit with given text. + * @param text to fill on. + */ + void slotFillTextEditWithText(QString text); + + /** + * @details Saves the content of the current tab, if it has a filepath + * otherwise it calls saveAs for the current tab + */ + void slotSave(); + + /** + * @details Opens a savefiledialog and calls saveFile with the choosen filename. + * + * @return Return the return value of the savefile method + */ + bool slotSaveAs(); + + /** + * @details Show an OpenFileDoalog and open the file in a new tab. + * Shows an error dialog, if the open fails. + * Set the focus to the tab of the opened file. + */ + void slotOpen(); + + /** + * @details Open a print-dialog for the current tab + */ + void slotPrint(); + + /** + * @details Adds a new tab with the title "untitled"+countpage+".txt" + * Sets the focus to the new tab. Increase Tab-Count by one + */ + void slotNewTab(); + + /** + * @details Adds a new tab with the given title and opens given html file. + * Increase Tab-Count by one + * @param title title for the tab + * @param path path for html file to show + */ + void slotNewHelpTab(QString title, QString path); + + /** + * @details put a * in front of current tabs title, if current textedit is modified + */ + void slotShowModified(); + + /** + * @details close the current tab and decrease TabWidget->count by \a 1 + * + */ + void slotCloseTab(); + + /** + * @details Switch to the next tab. + * + */ + void slotSwitchTabUp(); + + /** + * @details Switch to the previous tab. + * + */ + void slotSwitchTabDown(); + +private: + /** + * @details return just a filename stripped of a whole path + * + * @param a filename path + * @return QString containing the filename + */ + QString strippedName(const QString &fullFileName); + + /** + * @brief + * + */ + bool maybeSaveFile(); + + /** + * @brief + * + * @param askToSave + */ + bool maybeSaveCurrentTab(bool askToSave); + + /**************************************************************************************** + * Name: countPage + * Description: int cotaining the number of added tabs + */ + int countPage; /* TODO */ + +private slots: + /** + * @details Remove the tab with given index + * + * @param index Tab-number to remove + */ + void removeTab(int index); + + /** + * @details Cut selected text in current textpage. + */ + void slotCut(); + + /** + * @details Copy selected text of current textpage to clipboard. + */ + void slotCopy(); + + /** + * @details Paste text from clipboard to current textpage. + */ + void slotPaste(); + + /** + * @details Undo last change in current textpage. + * + */ + void slotUndo(); + /**************************************************************************************** + * Name: redo + * Description: redo last change in current textpage + * Parameters: none + * Return Values: none + * Change on members: none + */ + /** + * @brief + * + */ + void slotRedo(); + + void slotZoomIn(); + void slotZoomOut(); + /**************************************************************************************** + * Name: selectAll + * Description: select all in current textpage + * Parameters: none + * Return Values: none + * Change on members: none + */ + /** + * @brief + * + */ + void slotSelectAll(); + +protected: + // void dragEnterEvent(QDragEnterEvent *event); + // void dropEvent(QDropEvent* event); + /**************************************************************************************** + * Name: saveFile + * Description: Saves the content of currentTab to the file filename + * Parameters: QString filename contains the full path of the file to save + * Return Values: true, if the file was saved succesfully + * false, if parameter filename is empty or the saving failed + * Change on members: sets isModified of the current tab to false + */ + /** + * @brief + * + * @param fileName + */ + bool saveFile(const QString &fileName); +}; +#endif // __TEXTEDIT_H__ diff --git a/src/verifydetailsdialog.cpp b/src/verifydetailsdialog.cpp new file mode 100644 index 0000000..fc9ab6c --- /dev/null +++ b/src/verifydetailsdialog.cpp @@ -0,0 +1,103 @@ +/* + * verifydetailsdialog.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "verifydetailsdialog.h" + +VerifyDetailsDialog::VerifyDetailsDialog(QWidget *parent, GpgME::GpgContext* ctx, KeyList* keyList, QByteArray* inputData, QByteArray* inputSignature) : + QDialog(parent) +{ + mCtx = ctx; + mKeyList = keyList; + //mTextpage = edit; + mInputData = inputData; + mInputSignature = inputSignature; + + this->setWindowTitle(tr("Signaturedetails")); + + connect(mCtx, SIGNAL(keyDBChanged()), this, SLOT(slotRefresh())); + mainLayout = new QHBoxLayout(); + this->setLayout(mainLayout); + + mVbox = new QWidget(); + slotRefresh(); + + this->exec(); +} + +void VerifyDetailsDialog::slotRefresh() +{ + mVbox->close(); + + mVbox = new QWidget(); + QVBoxLayout *mVboxLayout = new QVBoxLayout(mVbox); + mainLayout->addWidget(mVbox); + + // Button Box for close button + buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); + + // Get signature information of current text + //QByteArray text = mTextpage->toPlainText().toUtf8(); + //mCtx->preventNoDataErr(&text); + gpgme_signature_t sign; + if(mInputSignature != 0) { + sign = mCtx->verify(mInputData, mInputSignature); + } else { + sign = mCtx->verify(mInputData); + } + + if(sign==0) { + mVboxLayout->addWidget(new QLabel(tr("No valid input found"))); + mVboxLayout->addWidget(buttonBox); + return; + } + + // Get timestamp of signature of current text + QDateTime timestamp; + timestamp.setTime_t(sign->timestamp); + + // Set the title widget depending on sign status + if(gpg_err_code(sign->status) == GPG_ERR_BAD_SIGNATURE) { + mVboxLayout->addWidget(new QLabel(tr("Error Validating signature"))); + } else if (mInputSignature != 0) { + mVboxLayout->addWidget(new QLabel(tr("File was signed on <br/> %1 by:<br/>").arg(timestamp.toString(Qt::SystemLocaleLongDate)))); + } else { + switch (mCtx->textIsSigned(*mInputData)) + { + case 2: + { + mVboxLayout->addWidget(new QLabel(tr("Text was completely signed on <br/> %1 by:<br/>").arg(timestamp.toString(Qt::SystemLocaleLongDate)))); break; + } + case 1: + { + mVboxLayout->addWidget(new QLabel(tr("Text was partially signed on <br/> %1 by:<br/>").arg(timestamp.toString(Qt::SystemLocaleLongDate)))); break; + } + } + } + // Add informationbox for every single key + while (sign) { + VerifyKeyDetailBox *sbox = new VerifyKeyDetailBox(this,mCtx,mKeyList,sign); + sign = sign->next; + mVboxLayout->addWidget(sbox); + } + + mVboxLayout->addWidget(buttonBox); +} diff --git a/src/verifydetailsdialog.h b/src/verifydetailsdialog.h new file mode 100644 index 0000000..b138f46 --- /dev/null +++ b/src/verifydetailsdialog.h @@ -0,0 +1,48 @@ +/* + * verifydetailsdialog.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __VERIFYDETAILSDIALOG_H__ +#define __VERIFYDETAILSDIALOG_H__ + +#include "editorpage.h" +#include "verifykeydetailbox.h" +#include <QDialog> + +class VerifyDetailsDialog : public QDialog +{ + Q_OBJECT +public: + explicit VerifyDetailsDialog(QWidget *parent, GpgME::GpgContext* ctx, KeyList* mKeyList, QByteArray* inputData, QByteArray* inputSignature = 0); + +private slots: + void slotRefresh(); + +private: + GpgME::GpgContext *mCtx; + KeyList *mKeyList; + QHBoxLayout *mainLayout; + QWidget *mVbox; + QByteArray* mInputData; /** Data to be verified */ + QByteArray* mInputSignature; /** Data to be verified */ + QDialogButtonBox* buttonBox; +}; + +#endif // __VERIFYDETAILSDIALOG_H__ diff --git a/src/verifykeydetailbox.cpp b/src/verifykeydetailbox.cpp new file mode 100644 index 0000000..b040d4f --- /dev/null +++ b/src/verifykeydetailbox.cpp @@ -0,0 +1,99 @@ +/* + * verifydetailbox.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "verifykeydetailbox.h" + +VerifyKeyDetailBox::VerifyKeyDetailBox(QWidget *parent, GpgME::GpgContext* ctx, KeyList* keyList, gpgme_signature_t signature) : + QGroupBox(parent) +{ + this->mCtx = ctx; + this->mKeyList = keyList; + this->fpr=signature->fpr; + + QGridLayout *grid = new QGridLayout(); + + switch (gpg_err_code(signature->status)) + { + case GPG_ERR_NO_PUBKEY: + { + QPushButton *importButton = new QPushButton(tr("Import from keyserver")); + connect(importButton, SIGNAL(clicked()), this, SLOT(slotImportFormKeyserver())); + + this->setTitle(tr("Key not present with id 0x") + signature->fpr); + + grid->addWidget(new QLabel(tr("Status:")), 0, 0); + //grid->addWidget(new QLabel(tr("Fingerprint:")), 1, 0); + grid->addWidget(new QLabel(tr("Key not present in keylist")), 0, 1); + //grid->addWidget(new QLabel(signature->fpr), 1, 1); + grid->addWidget(importButton, 2,0,2,1); + break; + } + case GPG_ERR_NO_ERROR: + { + GpgKey key = mCtx->getKeyByFpr(signature->fpr); + + this->setTitle(key.name); + grid->addWidget(new QLabel(tr("Name:")), 0, 0); + grid->addWidget(new QLabel(tr("EMail:")), 1, 0); + grid->addWidget(new QLabel(tr("Fingerprint:")), 2, 0); + grid->addWidget(new QLabel(tr("Status:")), 3, 0); + + grid->addWidget(new QLabel(key.name), 0, 1); + grid->addWidget(new QLabel(key.email), 1, 1); + grid->addWidget(new QLabel(beautifyFingerprint(signature->fpr)), 2, 1); + grid->addWidget(new QLabel(tr("OK")), 3, 1); + + break; + } + default: + { + GpgKey key = mCtx->getKeyById(signature->fpr); + this->setTitle(tr("Error for key with id 0x") + fpr); + grid->addWidget(new QLabel(tr("Name:")), 0, 0); + grid->addWidget(new QLabel(tr("EMail:")), 1, 0); + grid->addWidget(new QLabel(tr("Status:")), 2, 0); + grid->addWidget(new QLabel(tr("Fingerprint:")), 3, 0); + + grid->addWidget(new QLabel(key.name), 0, 1); + grid->addWidget(new QLabel(key.email), 1, 1); + grid->addWidget(new QLabel(gpg_strerror(signature->status)), 2, 1); + grid->addWidget(new QLabel(beautifyFingerprint(key.fpr)), 3, 1); + + break; + } + } + this->setLayout(grid); +} + +void VerifyKeyDetailBox::slotImportFormKeyserver() +{ + KeyServerImportDialog *importDialog =new KeyServerImportDialog(mCtx,mKeyList,this); + importDialog->slotImport(QStringList(fpr)); +} + +QString VerifyKeyDetailBox::beautifyFingerprint(QString fingerprint) +{ + uint len = fingerprint.length(); + if ((len > 0) && (len % 4 == 0)) + for (uint n = 0; 4 *(n + 1) < len; ++n) + fingerprint.insert(5 * n + 4, ' '); + return fingerprint; +} diff --git a/src/verifykeydetailbox.h b/src/verifykeydetailbox.h new file mode 100644 index 0000000..29d198e --- /dev/null +++ b/src/verifykeydetailbox.h @@ -0,0 +1,47 @@ +/* + * verifydetailbox.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __VERIFYKEYDETAILBOX_H__ +#define __VERIFYKEYDETAILBOX_H__ + +#include "keylist.h" +#include "keyserverimportdialog.h" +#include <QDialog> +#include <QGroupBox> + +class VerifyKeyDetailBox: public QGroupBox +{ + Q_OBJECT +public: + explicit VerifyKeyDetailBox(QWidget *parent, GpgME::GpgContext* ctx, KeyList* mKeyList, gpgme_signature_t signature); + +private slots: + void slotImportFormKeyserver(); + +private: + GpgME::GpgContext* mCtx; + KeyList* mKeyList; + QString beautifyFingerprint(QString fingerprint); + QString fpr; +}; + +#endif // __VERIFYKEYDETAILBOX_H__ + diff --git a/src/verifynotification.cpp b/src/verifynotification.cpp new file mode 100644 index 0000000..6e73961 --- /dev/null +++ b/src/verifynotification.cpp @@ -0,0 +1,185 @@ +/* + * verifynotification.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include "verifynotification.h" + +VerifyNotification::VerifyNotification(QWidget *parent, GpgME::GpgContext *ctx, KeyList *keyList,QTextEdit *edit) : + QWidget(parent) +{ + mCtx = ctx; + mKeyList = keyList; + mTextpage = edit; + verifyLabel = new QLabel(this); + + connect(mCtx, SIGNAL(keyDBChanged()), this, SLOT(slotRefresh())); + connect(edit, SIGNAL(textChanged()), this, SLOT(close())); + + importFromKeyserverAct = new QAction(tr("Import missing key from Keyserver"), this); + connect(importFromKeyserverAct, SIGNAL(triggered()), this, SLOT(slotImportFromKeyserver())); + + showVerifyDetailsAct = new QAction(tr("Show detailed verify information"), this); + connect(showVerifyDetailsAct, SIGNAL(triggered()), this, SLOT(slotShowVerifyDetails())); + + detailMenu = new QMenu(this); + detailMenu->addAction(showVerifyDetailsAct); + detailMenu->addAction(importFromKeyserverAct); + importFromKeyserverAct->setVisible(false); + + keysNotInList = new QStringList(); + detailsButton = new QPushButton(tr("Details"),this); + detailsButton->setMenu(detailMenu); + QHBoxLayout *notificationWidgetLayout = new QHBoxLayout(this); + notificationWidgetLayout->setContentsMargins(10,0,0,0); + notificationWidgetLayout->addWidget(verifyLabel,2); + notificationWidgetLayout->addWidget(detailsButton); + this->setLayout(notificationWidgetLayout); +} + +void VerifyNotification::slotImportFromKeyserver() +{ + KeyServerImportDialog *importDialog =new KeyServerImportDialog(mCtx,mKeyList, this); + importDialog->slotImport(*keysNotInList); +} + +void VerifyNotification::setVerifyLabel(QString text, verify_label_status verifyLabelStatus) +{ + QString color; + verifyLabel->setText(text); + switch (verifyLabelStatus) { + case VERIFY_ERROR_OK: color="#ccffcc"; + break; + case VERIFY_ERROR_WARN: color="#ececba"; + break; + case VERIFY_ERROR_CRITICAL: color="#ff8080"; + break; + default: + break; + } + + verifyLabel->setAutoFillBackground(true); + QPalette status = verifyLabel->palette(); + status.setColor(QPalette::Background, color); + verifyLabel->setPalette(status); +} + +void VerifyNotification::showImportAction(bool visible) +{ + importFromKeyserverAct->setVisible(visible); +} + +void VerifyNotification::slotShowVerifyDetails() +{ + QByteArray text = mTextpage->toPlainText().toUtf8(); + mCtx->preventNoDataErr(&text); + new VerifyDetailsDialog(this, mCtx, mKeyList, &text); +} + +bool VerifyNotification::slotRefresh() +{ + verify_label_status verifyStatus=VERIFY_ERROR_OK; + + QByteArray text = mTextpage->toPlainText().toUtf8(); + mCtx->preventNoDataErr(&text); + int textIsSigned = mCtx->textIsSigned(text); + + gpgme_signature_t sign = mCtx->verify(&text); + + if (sign == NULL) { + return false; + } + + QString verifyLabelText; + bool unknownKeyFound=false; + + while (sign) { + + switch (gpg_err_code(sign->status)) + { + case GPG_ERR_NO_PUBKEY: + { + verifyStatus=VERIFY_ERROR_WARN; + verifyLabelText.append(tr("Key not present with id 0x")+QString(sign->fpr)); + this->keysNotInList->append(sign->fpr); + unknownKeyFound=true; + break; + } + case GPG_ERR_NO_ERROR: + { + GpgKey key = mCtx->getKeyByFpr(sign->fpr); + verifyLabelText.append(key.name); + if (!key.email.isEmpty()) { + verifyLabelText.append("<"+key.email+">"); + } + break; + } + case GPG_ERR_BAD_SIGNATURE: + { + textIsSigned = 3; + verifyStatus=VERIFY_ERROR_CRITICAL; + GpgKey key = mCtx->getKeyById(sign->fpr); + verifyLabelText.append(key.name); + if (!key.email.isEmpty()) { + verifyLabelText.append("<"+key.email+">"); + } + break; + } + default: + { + //textIsSigned = 3; + verifyStatus=VERIFY_ERROR_WARN; + //GpgKey key = mKeyList->getKeyByFpr(sign->fpr); + verifyLabelText.append(tr("Error for key with fingerprint ")+mCtx->beautifyFingerprint(QString(sign->fpr))); + break; + } + } + verifyLabelText.append("\n"); + sign = sign->next; + } + + switch (textIsSigned) + { + case 3: + { + verifyLabelText.prepend(tr("Error validating signature by: ")); + break; + } + case 2: + { + verifyLabelText.prepend(tr("Text was completely signed by: ")); + break; + } + case 1: + { + verifyLabelText.prepend(tr("Text was partially signed by: ")); + break; + } + } + + // If an unknown key is found, enable the importfromkeyserveraction + this->showImportAction(unknownKeyFound); + + // Remove the last linebreak + verifyLabelText.remove(verifyLabelText.length()-1,1); + + this->setVerifyLabel(verifyLabelText,verifyStatus); + + return true; +} diff --git a/src/verifynotification.h b/src/verifynotification.h new file mode 100644 index 0000000..60e55f9 --- /dev/null +++ b/src/verifynotification.h @@ -0,0 +1,109 @@ +/* + * verifynotification.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef __VERIFYNOTIFICATION_H__ +#define __VERIFYNOTIFICATION_H__ + +#include "editorpage.h" +#include "verifydetailsdialog.h" +#include <gpgme.h> +#include <QWidget> + +QT_BEGIN_NAMESPACE +class QLabel; +class QHBoxLayout; +class QMenu; +class QPushButton; +QT_END_NAMESPACE + +/** + * @details Enumeration for the status of Verifylabel + */ +typedef enum +{ + VERIFY_ERROR_OK = 0, + VERIFY_ERROR_WARN = 1, + VERIFY_ERROR_CRITICAL = 2, + VERIFY_ERROR_NEUTRAL =3, +} verify_label_status; + +/** + * @brief Class for handling the verifylabel shown at buttom of a textedit-page + */ +class VerifyNotification : public QWidget +{ + Q_OBJECT +public: + /** + * @brief + * + * @param ctx The GPGme-Context + * @param parent The parent widget + */ + explicit VerifyNotification(QWidget *parent, GpgME::GpgContext *ctx, KeyList *keyList,QTextEdit *edit); + /** + * @details Set the text and background-color of verify notification. + * + * @param text The text to be set. + * @param verifyLabelStatus The status of label to set the specified color. + */ + void setVerifyLabel(QString text, verify_label_status verifyLabelStatus); + + /** + * @details Show the import from keyserver-action in detailsmenu. + * @param visible show the action, if visible is true, otherwise hide it. + */ + void showImportAction(bool visible); + + QStringList *keysNotInList; /** List with keys, which are in signature but not in keylist */ + + +public slots: + /** + * @details Import the keys contained in keysNotInList from keyserver + * + */ + void slotImportFromKeyserver(); + + /** + * @details Show a dialog with signing details. + */ + void slotShowVerifyDetails(); + + /** + * @details Refresh the contents of dialog. + */ + bool slotRefresh(); + +private: + QMenu *detailMenu; /** Menu for te Button in verfiyNotification */ + QAction *importFromKeyserverAct; /** Action for importing keys from keyserver which are notin keylist */ + QAction *showVerifyDetailsAct; /** Action for showing verify detail dialog */ + QPushButton *detailsButton; /** Button shown in verifynotification */ + QLabel *verifyLabel; /** Label holding the text shown in verifyNotification */ + GpgME::GpgContext *mCtx; /** GpgME Context */ + KeyList *mKeyList; /** Table holding the keys */ + QTextEdit *mTextpage; /** Textedit associated to the notification */ + QVector<QString> verifyDetailStringVector; /** Vector containing the text for labels in verifydetaildialog */ + QVector<verify_label_status> verifyDetailStatusVector; /** Vector containing the status for labels in verifydetaildialog */ + +}; +#endif // __VERIFYNOTIFICATION_H__ diff --git a/src/wizard.cpp b/src/wizard.cpp new file mode 100644 index 0000000..675af55 --- /dev/null +++ b/src/wizard.cpp @@ -0,0 +1,431 @@ +/* * wizard.cpp + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#include <QtGui> + +#include "wizard.h" + +#ifdef Q_OS_WIN +#include "windows.h" +#endif + +Wizard::Wizard(GpgME::GpgContext *ctx, KeyMgmt *keyMgmt, QWidget *parent) + : QWizard(parent) +{ + mCtx=ctx; + mKeyMgmt=keyMgmt; + + setPage(Page_Intro,new IntroPage(this)); + setPage(Page_Choose, new ChoosePage(this)); + setPage(Page_ImportFromGpg4usb,new ImportFromGpg4usbPage(mCtx, mKeyMgmt, this)); + setPage(Page_ImportFromGnupg,new ImportFromGnupgPage(mCtx, mKeyMgmt, this)); + setPage(Page_GenKey,new KeyGenPage(mCtx, this)); + setPage(Page_Conclusion,new ConclusionPage(this)); +#ifndef Q_WS_MAC + setWizardStyle(ModernStyle); +#endif + setWindowTitle(tr("First Start Wizard")); + + // http://www.flickr.com/photos/laureenp/6141822934/ + setPixmap(QWizard::WatermarkPixmap, QPixmap(":/keys2.jpg")); + setPixmap(QWizard::LogoPixmap, QPixmap(":/logo_small.png")); + setPixmap(QWizard::BannerPixmap, QPixmap(":/banner.png")); + + QSettings settings; + setStartId(settings.value("wizard/nextPage", -1).toInt()); + settings.remove("wizard/nextPage"); + + connect(this, SIGNAL(accepted()), this, SLOT(slotWizardAccepted())); + connect(this, SIGNAL(signalOpenHelp(QString)), parentWidget(), SLOT(signalOpenHelp(QString))); + +} + +void Wizard::slotWizardAccepted() { + QSettings settings; + // Don't show is mapped to show -> negation + settings.setValue("wizard/showWizard", !field("showWizard").toBool()); + + if(field("openHelp").toBool()) { + emit signalOpenHelp("docu.html#content"); + } +} + +bool Wizard::importPubAndSecKeysFromDir(const QString dir, KeyMgmt *keyMgmt) +{ + QFile secRingFile(dir+"/secring.gpg"); + QFile pubRingFile(dir+"/pubring.gpg"); + + // Return, if no keyrings are found in subdir of chosen dir + if (!(pubRingFile.exists() or secRingFile.exists())) { + QMessageBox::critical(0, tr("Import Error"), tr("Couldn't locate any keyring file in %1").arg(dir)); + return false; + } + + QByteArray inBuffer; + if (secRingFile.exists()) { + // write content of secringfile to inBuffer + if (!secRingFile.open(QIODevice::ReadOnly)) { + QMessageBox::critical(0, tr("Import error"), tr("Couldn't open private keyringfile: %1").arg(secRingFile.fileName())); + return false; + } + inBuffer = secRingFile.readAll(); + secRingFile.close(); + } + + if (pubRingFile.exists()) { + // try to import public keys + if (!pubRingFile.open(QIODevice::ReadOnly)) { + QMessageBox::critical(0, tr("Import error"), tr("Couldn't open public keyringfile: %1").arg(pubRingFile.fileName())); + return false; + } + inBuffer.append(pubRingFile.readAll()); + pubRingFile.close(); + } + keyMgmt->slotImportKeys(inBuffer); + inBuffer.clear(); + + return true; +} + +IntroPage::IntroPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Getting started...")); + setSubTitle(tr("... with gpg4usb")); + + QLabel *topLabel = new QLabel(tr("To use gpg4usb for decrypting and signing messages, you need a " + "private key. The next page will help you with " + "key generation or import.<br><br>" + "For more information have a look at the <a href='docu_concepts.html'>concepts</a> " + "(by clicking the link, the page will open in the main window). <br>")); + topLabel->setWordWrap(true); + connect(topLabel, SIGNAL(linkActivated(const QString&)), parentWidget()->parentWidget(), SLOT(openHelp(const QString&))); + + // QComboBox for language selection + QLabel *langLabel = new QLabel(tr("Choose a Language")); + langLabel->setWordWrap(true); + + languages = SettingsDialog::listLanguages(); + QComboBox *langSelectBox = new QComboBox(); + + foreach(QString l, languages) { + langSelectBox->addItem(l); + } + // selected entry from config + QSettings settings; + QString langKey = settings.value("int/lang").toString(); + QString langValue = languages.value(langKey); + if (langKey != "") { + langSelectBox->setCurrentIndex(langSelectBox->findText(langValue)); + } + + connect(langSelectBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(slotLangChange(QString))); + + // set layout and add widgets + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(topLabel); + layout->addWidget(langLabel); + layout->addWidget(langSelectBox); + setLayout(layout); +} + +void IntroPage::slotLangChange(QString lang) { + QSettings settings; + settings.setValue("int/lang", languages.key(lang)); + settings.setValue("wizard/nextPage", this->wizard()->currentId()); + qApp->exit(RESTART_CODE); +} + +int IntroPage::nextId() const +{ + return Wizard::Page_Choose; +} +ChoosePage::ChoosePage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Choose your action...")); + setSubTitle(tr("...by clicking on the apropriate link.")); + + QLabel *keygenLabel = new QLabel(tr("If you have never used gpg4usb before and also don't own a gpg key yet you " + "may possibly want to ")+"<a href=""Wizard::Page_GenKey"">" + +tr("create a new keypair")+"</a><hr>"); + keygenLabel->setWordWrap(true); + connect(keygenLabel, SIGNAL(linkActivated(const QString&)), this, SLOT(slotJumpPage(const QString&))); + + QLabel *importGpg4usbLabel = new QLabel(tr("If you upgrade from an older version of gpg4usb you may want to ") + +"<a href=""Wizard::Page_ImportFromGpg4usb"">" + +tr("import settings and/or keys from gpg4usb")+"</a>"); + importGpg4usbLabel->setWordWrap(true); + connect(importGpg4usbLabel, SIGNAL(linkActivated(const QString&)), this, SLOT(slotJumpPage(const QString&))); + + QLabel *importGnupgLabel = new QLabel(tr("If you are already using GnuPG you may want to ") + +"<a href=""Wizard::Page_ImportFromGnupg"">" + +tr("import keys from GnuPG")+"</a><hr>"); + importGnupgLabel->setWordWrap(true); + connect(importGnupgLabel, SIGNAL(linkActivated(const QString&)), this, SLOT(slotJumpPage(const QString&))); + + QVBoxLayout *layout = new QVBoxLayout(); + layout->addWidget(keygenLabel); + layout->addWidget(importGnupgLabel); + layout->addWidget(importGpg4usbLabel); + setLayout(layout); + nextPage=Wizard::Page_Conclusion; +} + +int ChoosePage::nextId() const +{ + return nextPage; +} + +void ChoosePage::slotJumpPage(const QString& page) +{ + QMetaObject qmo = Wizard::staticMetaObject; + int index = qmo.indexOfEnumerator("WizardPages"); + QMetaEnum m = qmo.enumerator(index); + + nextPage = m.keyToValue(page.toAscii().data()); + wizard()->next(); +} + +ImportFromGpg4usbPage::ImportFromGpg4usbPage(GpgME::GpgContext *ctx, KeyMgmt *keyMgmt, QWidget *parent) + : QWizardPage(parent) +{ + mCtx=ctx; + mKeyMgmt=keyMgmt; + setTitle(tr("Import from...")); + setSubTitle(tr("...existing gpg4usb")); + + QLabel *topLabel = new QLabel(tr("You can import keys and/or settings from existing gpg4usb. <br><br>" + "Just check what you want to import, click the import button and choose " + "the directory of your other gpg4usb in the appearing file dialog."), this); + topLabel->setWordWrap(true); + + gpg4usbKeyCheckBox = new QCheckBox(); + gpg4usbKeyCheckBox->setChecked(true); + QLabel *keyLabel = new QLabel(tr("Keys")); + + gpg4usbConfigCheckBox = new QCheckBox(); + gpg4usbConfigCheckBox->setChecked(true); + QLabel *configLabel = new QLabel(tr("Configuration")); + + QPushButton *importFromGpg4usbButton = new QPushButton(tr("Import from gpg4usb")); + connect(importFromGpg4usbButton, SIGNAL(clicked()), this, SLOT(slotImportFromOlderGpg4usb())); + + QGridLayout *gpg4usbLayout = new QGridLayout(); + gpg4usbLayout->addWidget(topLabel,1,1,1,2); + gpg4usbLayout->addWidget(gpg4usbKeyCheckBox,2,1,Qt::AlignRight); + gpg4usbLayout->addWidget(keyLabel,2,2); + gpg4usbLayout->addWidget(gpg4usbConfigCheckBox,3,1,Qt::AlignRight); + gpg4usbLayout->addWidget(configLabel,3,2); + gpg4usbLayout->addWidget(importFromGpg4usbButton,4,2); + + this->setLayout(gpg4usbLayout); +} + +void ImportFromGpg4usbPage::slotImportFromOlderGpg4usb() +{ + QString dir = QFileDialog::getExistingDirectory(this,tr("Other gpg4usb directory")); + + // Return, if cancel was hit + if (dir.isEmpty()) { + return; + } + + // try to import keys, if appropriate box is checked, return, if import was unsuccessful + if (gpg4usbKeyCheckBox->isChecked()) { + if (!Wizard::importPubAndSecKeysFromDir(dir+"/keydb",mKeyMgmt)) { + return; + } + } + + // try to import config, if appropriate box is checked + if (gpg4usbConfigCheckBox->isChecked()) { + slotImportConfFromGpg4usb(dir); + + QSettings settings; + settings.setValue("wizard/nextPage", this->nextId()); + QMessageBox::information(0,tr("Configuration Imported"),tr("Imported Configuration from old gpg4usb.<br>" + "Will now restart to activate the configuration.")); + // TODO: edit->maybesave? + qApp->exit(RESTART_CODE); + } + wizard()->next(); +} + +bool ImportFromGpg4usbPage::slotImportConfFromGpg4usb(QString dir) { + QString path = dir+"/conf/gpg4usb.ini"; + QSettings oldconf(path, QSettings::IniFormat, this); + QSettings actualConf; + foreach(QString key, oldconf.allKeys()) { + actualConf.setValue(key, oldconf.value(key)); + } + return true; +} + +int ImportFromGpg4usbPage::nextId() const +{ + return Wizard::Page_Conclusion; +} + +ImportFromGnupgPage::ImportFromGnupgPage(GpgME::GpgContext *ctx, KeyMgmt *keyMgmt, QWidget *parent) + : QWizardPage(parent) +{ + mCtx=ctx; + mKeyMgmt=keyMgmt; + setTitle(tr("Import keys...")); + setSubTitle(tr("...from existing GnuPG installation")); + + QLabel *gnupgLabel = new QLabel(tr("You can import keys from a locally installed GnuPG.<br><br> The location is read " + "from registry in Windows or assumed to be the .gnupg folder in the your home directory in Linux.<br>")); + gnupgLabel->setWordWrap(true); + + importFromGnupgButton = new QPushButton(tr("Import keys from GnuPG")); + connect(importFromGnupgButton, SIGNAL(clicked()), this, SLOT(slotrImportKeysFromGnupg())); + + QGridLayout *layout = new QGridLayout(); + layout->addWidget(gnupgLabel); + layout->addWidget(importFromGnupgButton); + + this->setLayout(layout); +} + +void ImportFromGnupgPage::slotrImportKeysFromGnupg() +{ + // first get gnupghomedir and check, if it exists + QString gnuPGHome = getGnuPGHome(); + if (gnuPGHome == NULL) { + QMessageBox::critical(0, tr("Import Error"), tr("Couldn't locate GnuPG home directory")); + return; + } + + // Try to import the keyring files and return the return value of the method + Wizard::importPubAndSecKeysFromDir(gnuPGHome,mKeyMgmt); + wizard()->next(); +} + +QString ImportFromGnupgPage::getGnuPGHome() +{ + QString gnuPGHome=""; + #ifdef _WIN32 + bool existsAndSuccess = false; + + HKEY hKey; + + existsAndSuccess = (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\GNU\\GNUPG", 0, KEY_READ, &hKey) == ERROR_SUCCESS); + + if (existsAndSuccess) { + QSettings gnuPGsettings("HKEY_CURRENT_USER\\Software\\GNU\\GNUPG", QSettings::NativeFormat); + if (gnuPGsettings.contains("HomeDir")) { + gnuPGHome = gnuPGsettings.value("HomeDir").toString(); + } else { + return NULL; + } + } + #else + gnuPGHome=QDir::homePath()+"/.gnupg"; + if (! QFile(gnuPGHome).exists()) { + return NULL; + } + #endif + + return gnuPGHome; +} + +int ImportFromGnupgPage::nextId() const +{ + return Wizard::Page_Conclusion; +} + +KeyGenPage::KeyGenPage(GpgME::GpgContext *ctx, QWidget *parent) + : QWizardPage(parent) +{ + mCtx=ctx; + setTitle(tr("Create a keypair...")); + setSubTitle(tr("...for decrypting and signing messages")); + QLabel *topLabel = new QLabel(tr("You should create a new keypair." + "The pair consists of a public and a private key.<br>" + "Other users can use the public key to encrypt messages for you " + "and verify messages signed by you." + "You can use the private key to decrypt and sign messages.<br>" + "For more information have a look at the offline tutorial (which then is shown in the main window):")); + topLabel->setWordWrap(true); + QLabel *linkLabel = new QLabel("<a href=""docu_keygen.html#content"">"+tr("Offline tutorial")+"</a>"); + //linkLabel->setOpenExternalLinks(true); + + connect(linkLabel, SIGNAL(linkActivated(const QString&)), parentWidget()->parentWidget(), SLOT(openHelp(const QString&))); + + QWidget *createKeyButtonBox = new QWidget(this); + QHBoxLayout *createKeyButtonBoxLayout = new QHBoxLayout(createKeyButtonBox); + QPushButton *createKeyButton = new QPushButton(tr("Create New Key")); + createKeyButtonBoxLayout->addWidget(createKeyButton); + createKeyButtonBoxLayout->addStretch(1); + QVBoxLayout *layout = new QVBoxLayout(); + layout->addWidget(topLabel); + layout->addWidget(linkLabel); + layout->addWidget(createKeyButtonBox); + connect(createKeyButton, SIGNAL(clicked()), this, SLOT(slotGenerateKeyDialog())); + + setLayout(layout); +} + +int KeyGenPage::nextId() const +{ + return Wizard::Page_Conclusion; +} + +void KeyGenPage::slotGenerateKeyDialog() +{ + KeyGenDialog *keyGenDialog = new KeyGenDialog(mCtx, this); + keyGenDialog->exec(); + wizard()->next(); +} + +ConclusionPage::ConclusionPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Ready.")); + setSubTitle(tr("Have fun with gpg4usb!")); + + QLabel *bottomLabel = new QLabel(tr("You are ready to use gpg4usb now.<br><br>" + "The offline help will get you started with gpg4usb. " + "It will open in the main window.<br>")); + bottomLabel->setWordWrap(true); + + openHelpCheckBox = new QCheckBox(tr("Open offline help.")); + openHelpCheckBox->setChecked(Qt::Checked); + + dontShowWizardCheckBox = new QCheckBox(tr("Dont show the wizard again.")); + dontShowWizardCheckBox->setChecked(Qt::Checked); + + registerField("showWizard", dontShowWizardCheckBox); + registerField("openHelp", openHelpCheckBox); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(bottomLabel); + layout->addWidget(openHelpCheckBox); + layout->addWidget(dontShowWizardCheckBox); + setLayout(layout); + setVisible(true); +} + +int ConclusionPage::nextId() const +{ + return -1; +} diff --git a/src/wizard.h b/src/wizard.h new file mode 100644 index 0000000..4ed34c1 --- /dev/null +++ b/src/wizard.h @@ -0,0 +1,167 @@ +/* + * wizard.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb 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 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb 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 gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + + +#ifndef WIZARD_H +#define WIZARD_H + +#include <QWizard> +#include "keygendialog.h" +#include "keymgmt.h" +#include "gpgconstants.h" +#include "settingsdialog.h" + +class QCheckBox; +class QLabel; +class QLineEdit; +class QRadioButton; + +class Wizard : public QWizard +{ + Q_OBJECT + Q_ENUMS(WizardPages) + +public: + enum WizardPages { Page_Intro, Page_Choose, Page_ImportFromGpg4usb, Page_ImportFromGnupg, Page_GenKey, + Page_Conclusion }; + + Wizard(GpgME::GpgContext *ctx, KeyMgmt *keyMgmt, QWidget *parent = 0); + static bool importPubAndSecKeysFromDir(const QString dir, KeyMgmt *keyMgmt); + +private: + GpgME::GpgContext *mCtx; + KeyMgmt *mKeyMgmt; + +private slots: + void slotWizardAccepted(); + +signals: + void signalOpenHelp(QString page); +}; + +class IntroPage : public QWizardPage +{ + Q_OBJECT + +public: + IntroPage(QWidget *parent = 0); + QHash<QString,QString> languages; + int nextId() const; + +private slots: + void slotLangChange(QString lang); +}; + +class ChoosePage : public QWizardPage +{ + Q_OBJECT + +public: + ChoosePage(QWidget *parent = 0); + +private slots: + void slotJumpPage(const QString& page); + +private: + int nextId() const; + int nextPage; +}; + +class ImportFromGpg4usbPage : public QWizardPage +{ + Q_OBJECT + +public: + ImportFromGpg4usbPage(GpgME::GpgContext *ctx, KeyMgmt *keyMgmt, QWidget *parent = 0); + +private slots: + /** + * @details Import keys from gnupg-homedir, private or/and public depend on the checked boxes + */ + void slotImportFromOlderGpg4usb(); + bool slotImportConfFromGpg4usb(QString dir); + +private: + int nextId() const; + + KeyMgmt *mKeyMgmt; + GpgME::GpgContext *mCtx; + QCheckBox *gpg4usbKeyCheckBox; + QCheckBox *gpg4usbConfigCheckBox; +}; + +class ImportFromGnupgPage : public QWizardPage +{ + Q_OBJECT + +public: + ImportFromGnupgPage(GpgME::GpgContext *ctx, KeyMgmt *keyMgmt, QWidget *parent = 0); + +private slots: + /** + * @details Import keys from gnupg-homedir, private or/and public depend on the checked boxes + */ + void slotrImportKeysFromGnupg(); + +private: + KeyMgmt *mKeyMgmt; + int nextId() const; + + /** + * @details String containing the gnupg-homedir + * @returns String containg the gnupg-homedir, but NULL, if the in windows registry entry + * doesn't exist or in linux ~/.gnupg doesn't exist + */ + QString getGnuPGHome(); + + GpgME::GpgContext *mCtx; + QPushButton *importFromGnupgButton; +}; + +class KeyGenPage : public QWizardPage +{ + Q_OBJECT + +public: + KeyGenPage(GpgME::GpgContext *ctx, QWidget *parent = 0); + int nextId() const; + +private slots: + void slotGenerateKeyDialog(); + +private: + GpgME::GpgContext *mCtx; +}; + +class ConclusionPage : public QWizardPage +{ + Q_OBJECT + +public: + ConclusionPage(QWidget *parent = 0); + int nextId() const; + +private: + QCheckBox *dontShowWizardCheckBox; + QCheckBox *openHelpCheckBox; +}; + +#endif |