/* * Copyright (C) 2002 Jean-Baptiste Mardelle * Copyright (C) 2007,2008,2009,2010,2011 Rolf Eike Beer */ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "kgpgeditor.h" #include "detailedconsole.h" #include "selectsecretkey.h" #include "kgpgmd5widget.h" #include "kgpgsettings.h" #include "keyservers.h" #include "sourceselect.h" #include "kgpg.h" #include "keysmanager.h" #include "editor/kgpgtextedit.h" #include "transactions/kgpgdecrypt.h" #include "transactions/kgpgkeyservergettransaction.h" #include "transactions/kgpgsigntext.h" #include "transactions/kgpgverify.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class KgpgView : public QWidget { public: KgpgView(QWidget *parent, KgpgTextEdit *editor, KToolBar *toolbar); }; KgpgView::KgpgView(QWidget *parent, KgpgTextEdit *editor, KToolBar *toolbar) : QWidget(parent) { QVBoxLayout *vb = new QVBoxLayout(this); vb->setSpacing(3); vb->addWidget(editor); vb->addWidget(toolbar); setAcceptDrops(true); } KgpgEditor::KgpgEditor(KeysManager *parent, KGpgItemModel *model, Qt::WFlags f) : KXmlGuiWindow(0, f), m_editor(new KgpgTextEdit(this, model, parent)), m_recentfiles(NULL), m_find(0), m_textchanged(false), m_emptytext(true), m_model(model), m_parent(parent) { // call inits to invoke all other construction parts initActions(); connect(m_editor, SIGNAL(resetEncoding(bool)), SLOT(slotResetEncoding(bool))); KgpgView *kb = new KgpgView(this, m_editor, toolBar(QLatin1String( "gpgToolBar" ))); setCentralWidget(kb); setCaption(i18n("Untitled"), false); m_editredo->setEnabled(false); m_editundo->setEnabled(false); m_editcopy->setEnabled(false); m_editcut->setEnabled(false); setObjectName( QLatin1String("editor" )); slotSetFont(KGpgSettings::font()); setupGUI((ToolBar | Keys | StatusBar | Save | Create), QLatin1String( "kgpgeditor.rc" )); setAutoSaveSettings(QLatin1String( "Editor" ), true); connect(m_editor, SIGNAL(textChanged()), SLOT(modified())); connect(m_editor, SIGNAL(newText()), SLOT(newText())); connect(m_editor, SIGNAL(undoAvailable(bool)), SLOT(slotUndoAvailable(bool))); connect(m_editor, SIGNAL(redoAvailable(bool)), SLOT(slotRedoAvailable(bool))); connect(m_editor, SIGNAL(copyAvailable(bool)), SLOT(slotCopyAvailable(bool))); } KgpgEditor::~KgpgEditor() { m_recentfiles->saveEntries( KConfigGroup(KGlobal::config(), "Recent Files" ) ); } void KgpgEditor::openDocumentFile(const KUrl& url, const QString &encoding) { QString tempopenfile; if(KIO::NetAccess::download(url, tempopenfile, this)) { QFile qfile(tempopenfile); if (qfile.open(QIODevice::ReadOnly)) { QTextStream t(&qfile); t.setCodec(encoding.toAscii()); m_editor->setPlainText(t.readAll()); qfile.close(); m_docname = url; m_textchanged = false; m_emptytext = false; setCaption(url.fileName(), false); m_recentfiles->addUrl(url); } KIO::NetAccess::removeTempFile(tempopenfile); } } void KgpgEditor::openEncryptedDocumentFile(const KUrl& url) { m_editor->slotDroppedFile(url); } void KgpgEditor::slotSetFont(QFont myFont) { m_editor->setFont(myFont); } void KgpgEditor::closeWindow() { m_recentfiles->saveEntries( KConfigGroup(KGlobal::config(), "Recent Files" ) ); close(); } void KgpgEditor::saveOptions() { KGpgSettings::setFirstRun(false); KGpgSettings::self()->writeConfig(); } void KgpgEditor::initActions() { KStandardAction::openNew(this, SLOT(slotFileNew()), actionCollection()); KStandardAction::open(this, SLOT(slotFileOpen()), actionCollection()); KStandardAction::save(this, SLOT(slotFileSave()), actionCollection()); KStandardAction::saveAs(this, SLOT(slotFileSaveAs()), actionCollection()); KStandardAction::close(this, SLOT(slotFileClose()), actionCollection()); KStandardAction::paste(this, SLOT(slotEditPaste()), actionCollection()); KStandardAction::print(this, SLOT(slotFilePrint()), actionCollection()); KStandardAction::selectAll(this, SLOT(slotSelectAll()), actionCollection()); KStandardAction::find(this, SLOT(slotFind()), actionCollection()); KStandardAction::findNext(this, SLOT(slotFindNext()), actionCollection()); KStandardAction::findPrev(this, SLOT(slotFindPrev()), actionCollection()); actionCollection()->addAction(KStandardAction::Preferences, QLatin1String( "options_configure" ), this, SLOT(slotOptions())); m_editundo = KStandardAction::undo(this, SLOT(slotundo()), actionCollection()); m_editredo = KStandardAction::redo(this, SLOT(slotredo()), actionCollection()); m_editcopy = KStandardAction::copy(this, SLOT(slotEditCopy()), actionCollection()); m_editcut = KStandardAction::cut(this, SLOT(slotEditCut()), actionCollection()); m_recentfiles = KStandardAction::openRecent(this, SLOT(openDocumentFile(KUrl)), this); menuBar()->addAction(m_recentfiles); m_recentfiles->loadEntries( KConfigGroup(KGlobal::config(), "Recent Files" ) ); m_recentfiles->setMaxItems(KGpgSettings::recentFiles()); KAction *action = actionCollection()->addAction(QLatin1String("file_encrypt"), this, SLOT(slotFilePreEnc())); action->setIcon(KIcon( QLatin1String( "document-encrypt" ))); action->setText(i18n("&Encrypt File...")); action = actionCollection()->addAction(QLatin1String("file_decrypt"), this, SLOT(slotFilePreDec())); action->setIcon(KIcon( QLatin1String( "document-decrypt" ))); action->setText(i18n("&Decrypt File...")); action = actionCollection()->addAction(QLatin1String("key_manage"), this, SLOT(slotKeyManager())); action->setIcon(KIcon( QLatin1String( "kgpg" ))); action->setText(i18n("&Open Key Manager")); action = actionCollection()->addAction(QLatin1String("sign_generate"), this, SLOT(slotPreSignFile())); action->setText(i18n("&Generate Signature...")); action->setIcon(KIcon( QLatin1String( "document-sign-key" ))); action = actionCollection()->addAction(QLatin1String("sign_verify"), this, SLOT(slotPreVerifyFile())); action->setText(i18n("&Verify Signature...")); action = actionCollection()->addAction(QLatin1String("sign_check"), this, SLOT(slotCheckMd5())); action->setText(i18n("&Check MD5 Sum...")); m_encodingaction = actionCollection()->add(QLatin1String("charsets"), this, SLOT(slotSetCharset())); m_encodingaction->setText(i18n("&Unicode (utf-8) Encoding")); actionCollection()->addAction(m_recentfiles->objectName(), m_recentfiles); action = actionCollection()->addAction(QLatin1String("text_encrypt"), m_editor, SLOT(slotEncode())); action->setIcon(KIcon( QLatin1String( "document-encrypt" ))); action->setText(i18n("En&crypt")); action = actionCollection()->addAction(QLatin1String("text_decrypt"), m_editor, SLOT(slotDecode())); action->setIcon(KIcon( QLatin1String( "document-decrypt" ))); action->setText(i18n("&Decrypt")); action = actionCollection()->addAction(QLatin1String("text_sign_verify"), m_editor, SLOT(slotSignVerify())); action->setIcon(KIcon( QLatin1String( "document-sign-key" ))); action->setText(i18n("S&ign/Verify")); } bool KgpgEditor::queryClose() { bool b = saveBeforeClear(); if (b) { m_editor->clear(); newText(); } return b; } bool KgpgEditor::saveBeforeClear() { if (m_textchanged) { QString fname; if (m_docname.fileName().isEmpty()) fname = i18n("Untitled"); else fname = m_docname.fileName(); QString msg = i18n("The document \"%1\" has changed.\nDo you want to save it?", fname); QString caption = i18n("Close the document"); int res = KMessageBox::warningYesNoCancel(this, msg, caption, KStandardGuiItem::save(), KStandardGuiItem::discard()); if (res == KMessageBox::Yes) return slotFileSave(); else if (res == KMessageBox::No) return true; else return false; } return true; } void KgpgEditor::slotFileNew() { if (saveBeforeClear()) { m_editor->clear(); newText(); } } void KgpgEditor::slotFileOpen() { if (saveBeforeClear()) { KEncodingFileDialog::Result loadResult; loadResult = KEncodingFileDialog::getOpenUrlAndEncoding(QString(), QString(), QString(), this); KUrl url = loadResult.URLs.first(); m_textencoding = loadResult.encoding; if(!url.isEmpty()) openDocumentFile(url, m_textencoding); } } bool KgpgEditor::slotFileSave() { QString filn = m_docname.path(); if (filn.isEmpty()) return slotFileSaveAs(); QTextCodec *cod = QTextCodec::codecForName(m_textencoding.toAscii()); if (cod == NULL) { KMessageBox::sorry(this, i18n("The document could not been saved, as the selected codec is not supported.")); return false; } if (!checkEncoding(cod)) { KMessageBox::sorry(this, i18n("The document could not been saved, as the selected encoding cannot encode every unicode character in it.")); return false; } if (m_docname.isLocalFile()) { QFile f(filn); if (!f.open(QIODevice::WriteOnly)) { KMessageBox::sorry(this, i18n("The document could not be saved, please check your permissions and disk space.")); return false; } QTextStream t(&f); t.setCodec(cod); t << m_editor->toPlainText(); f.close(); } else { KTemporaryFile tmpfile; tmpfile.open(); QTextStream stream(&tmpfile); stream.setCodec(cod); stream << m_editor->toPlainText(); if(!KIO::NetAccess::upload(tmpfile.fileName(), m_docname, this)) { KMessageBox::sorry(this, i18n("The document could not be saved, please check your permissions and disk space.")); return false; } } m_textchanged = false; m_emptytext = false; setCaption(m_docname.fileName(), false); return true; } bool KgpgEditor::slotFileSaveAs() { KEncodingFileDialog::Result saveResult; saveResult = KEncodingFileDialog::getSaveUrlAndEncoding(QString(), QString(), QString(), this); KUrl url; if (!saveResult.URLs.empty()) url = saveResult.URLs.first(); if(!url.isEmpty()) { const QString selectedEncoding = saveResult.encoding; if (url.isLocalFile()) { QString filn = url.path(); QFile f(url.path()); if (f.exists()) { const QString message = i18n("Overwrite existing file %1?", url.fileName()); int result = KMessageBox::warningContinueCancel(this, message, QString(), KStandardGuiItem::overwrite()); if (result == KMessageBox::Cancel) return false; } f.close(); } else if (KIO::NetAccess::exists(url, KIO::NetAccess::DestinationSide, this)) { const QString message = i18n("Overwrite existing file %1?", url.fileName()); int result = KMessageBox::warningContinueCancel(this, message, QString(), KStandardGuiItem::overwrite()); if (result == KMessageBox::Cancel) return false; } m_docname = url; m_textencoding = selectedEncoding; slotFileSave(); return true; } return false; } void KgpgEditor::slotFilePrint() { QPrinter prt; QPointer printDialog = new QPrintDialog(&prt, this); if (printDialog->exec() == QDialog::Accepted) { int width = prt.width(); int height = prt.height(); QPainter painter(&prt); painter.drawText(0, 0, width, height, Qt::AlignLeft | Qt::AlignTop | Qt::TextDontClip, m_editor->toPlainText()); } delete printDialog; } void KgpgEditor::slotFind() { QPointer fd = new KFindDialog(this); if (m_find) { fd->setOptions(m_find->options()); fd->setPattern(m_find->pattern()); } if (fd->exec() != QDialog::Accepted) { delete fd; return; } if (!m_find) { m_find = new KFind(fd->pattern(), fd->options(), this); if (m_find->options() & KFind::FromCursor) m_find->setData(m_editor->toPlainText(), m_editor->textCursor().selectionStart()); else m_find->setData(m_editor->toPlainText()); connect(m_find, SIGNAL(highlight(QString,int,int)), m_editor, SLOT(slotHighlightText(QString,int,int))); connect(m_find, SIGNAL(findNext()), this, SLOT(slotFindText())); } else { m_find->setPattern(fd->pattern()); m_find->setOptions(fd->options()); m_find->resetCounts(); } slotFindText(); delete fd; } void KgpgEditor::slotFindNext() { slotFindText(); } void KgpgEditor::slotFindPrev() { if(!m_find) { slotFind(); return; } long oldopt = m_find->options(); long newopt = oldopt ^ KFind::FindBackwards; m_find->setOptions(newopt); slotFindText(); m_find->setOptions(oldopt); } void KgpgEditor::slotFindText() { if (!m_find) { slotFind(); return; } if (m_find->find() == KFind::NoMatch) { if (m_find->numMatches() == 0) { m_find->displayFinalDialog(); delete m_find; m_find = 0; } else { if (m_find->shouldRestart(true, false)) { m_find->setData(m_editor->toPlainText()); slotFindText(); } else m_find->closeFindNextDialog(); } } } void KgpgEditor::slotFilePreEnc() { KUrl::List urls = KFileDialog::getOpenUrls(KUrl(), i18n("*|All Files"), this, i18n("Open File to Encode")); if (urls.isEmpty()) return; KGpgExternalActions::encryptFiles(m_parent, urls); } void KgpgEditor::slotFilePreDec() { KUrl url = KFileDialog::getOpenUrl(KUrl(), i18n("*|All Files"), this, i18n("Open File to Decode")); if (url.isEmpty()) return; QString oldname = url.fileName(); QString newname; if (oldname.endsWith(QLatin1String(".gpg")) || oldname.endsWith(QLatin1String(".asc")) || oldname.endsWith(QLatin1String(".pgp"))) oldname.chop(4); else oldname.append(QLatin1String( ".clear" )); oldname.prepend(url.directory(KUrl::AppendTrailingSlash)); QPointer popn = new KDialog(this); popn->setCaption( i18n("Decrypt File To") ); popn->setButtons( KDialog::Ok | KDialog::Cancel ); popn->setDefaultButton( KDialog::Ok ); popn->setModal( true ); SrcSelect *page = new SrcSelect(); popn->setMainWidget(page); page->newFilename->setUrl(oldname); page->newFilename->setMode(KFile::File); page->newFilename->setWindowTitle(i18n("Save File")); page->checkClipboard->setText(i18n("Editor")); page->resize(page->minimumSize()); popn->resize(popn->minimumSize()); if (popn->exec() == QDialog::Accepted) { if (page->checkFile->isChecked()) newname = page->newFilename->url().path(); } else { delete popn; return; } delete popn; if (!newname.isEmpty()) { QFile fgpg(newname); if (fgpg.exists()) { QPointer over = new KIO::RenameDialog(this, i18n("File Already Exists"), KUrl(), KUrl::fromPath(newname), KIO::M_OVERWRITE); if (over->exec() != QDialog::Accepted) { delete over; return; } newname = over->newDestUrl().path(); delete over; } KGpgDecrypt *decr = new KGpgDecrypt(this, url, KUrl(newname)); connect(decr, SIGNAL(done(int)), SLOT(slotLibraryDone())); decr->start(); } else openEncryptedDocumentFile(url); } void KgpgEditor::slotLibraryDone() { sender()->deleteLater(); } void KgpgEditor::slotKeyManager() { m_parent->show(); m_parent->raise(); } void KgpgEditor::slotFileClose() { saveOptions(); close(); } void KgpgEditor::slotundo() { m_editor->undo(); } void KgpgEditor::slotredo() { m_editor->redo(); } void KgpgEditor::slotEditCut() { m_editor->cut(); } void KgpgEditor::slotEditCopy() { m_editor->copy(); } void KgpgEditor::slotEditPaste() { m_editor->paste(); } void KgpgEditor::slotSelectAll() { m_editor->selectAll(); } void KgpgEditor::slotSetCharset() { if (!m_encodingaction->isChecked()) m_editor->setPlainText(QString::fromUtf8(m_editor->toPlainText().toAscii())); else { if (checkEncoding(QTextCodec::codecForLocale())) return; m_editor->setPlainText(QLatin1String( m_editor->toPlainText().toUtf8() )); } } bool KgpgEditor::checkEncoding(QTextCodec *codec) { return codec->canEncode(m_editor->toPlainText()); } void KgpgEditor::slotResetEncoding(bool enc) { m_encodingaction->setChecked(enc); } void KgpgEditor::slotPreSignFile() { // create a detached signature for a chosen file KUrl url = KFileDialog::getOpenUrl(KUrl(), i18n("*|All Files"), this, i18n("Open File to Sign")); if (!url.isEmpty()) slotSignFile(url); } void KgpgEditor::slotSignFile(const KUrl &url) { // create a detached signature for a chosen file if (!url.isEmpty()) { QString signKeyID; QPointer opts = new KgpgSelectSecretKey(this, m_model, false); if (opts->exec() == QDialog::Accepted) { signKeyID = opts->getKeyID(); } else { delete opts; return; } delete opts; KGpgSignText::SignOptions sopts = KGpgSignText::DetachedSignature; if (KGpgSettings::asciiArmor()) sopts |= KGpgSignText::AsciiArmored; KGpgSignText *signt = new KGpgSignText(this, signKeyID, KUrl::List(url), sopts); connect(signt, SIGNAL(done(int)), SLOT(slotSignFileFin())); signt->start(); } } void KgpgEditor::slotSignFileFin() { sender()->deleteLater(); } void KgpgEditor::slotPreVerifyFile() { KUrl url = KFileDialog::getOpenUrl(KUrl(), i18n("*|All Files"), this, i18n("Open File to Verify")); slotVerifyFile(url); } void KgpgEditor::slotVerifyFile(const KUrl &url) { if (!url.isEmpty()) { QString sigfile; if (!url.fileName().endsWith(QLatin1String(".sig"))) { sigfile = url.path() + QLatin1String( ".sig" ); QFile fsig(sigfile); if (!fsig.exists()) { sigfile = url.path() + QLatin1String( ".asc" ); QFile fsig(sigfile); // if no .asc or .sig signature file included, assume the file is internally signed if (!fsig.exists()) sigfile.clear(); } } KUrl::List chkfiles; if (sigfile.isEmpty()) chkfiles << url; else chkfiles << KUrl::fromPath(sigfile); KGpgVerify *verify = new KGpgVerify(this, chkfiles); connect(verify, SIGNAL(done(int)), m_editor, SLOT(slotVerifyDone(int))); verify->start(); } } void KgpgEditor::slotCheckMd5() { // display md5 sum for a chosen file KUrl url = KFileDialog::getOpenUrl(KUrl(), i18n("*|All Files"), this, i18n("Open File to Verify")); if (!url.isEmpty()) { QPointer mdwidget = new Md5Widget(this, url); mdwidget->exec(); delete mdwidget; } } void KgpgEditor::importSignatureKey(const QString &id, const QString &fileName) { sender()->deleteLater(); if (KMessageBox::questionYesNo(0, i18n("Missing signature:
Key id: %1

Do you want to import this key from a keyserver?
", id), fileName, KGuiItem(i18n("Import")), KGuiItem(i18n("Do Not Import"))) != KMessageBox::Yes) return; KeyServer *ks = new KeyServer(this); connect(ks, SIGNAL(importFinished(QStringList)), SLOT(slotDownloadKeysFinished(QStringList))); connect(ks, SIGNAL(importFailed()), ks, SLOT(deleteLater())); ks->startImport(QStringList(id), QString(),QLatin1String( qgetenv("http_proxy") )); } void KgpgEditor::slotDownloadKeysFinished(QStringList ids) { m_parent->refreshKeys(ids); sender()->deleteLater(); } void KgpgEditor::slotVerifyFinished(const QString &id, const QString &message) { sender()->deleteLater(); QString showId; if (id.isEmpty()) showId = i18n("No signature found."); else showId = id; (void) new KgpgDetailedInfo(this, showId, message, QStringList(), i18nc("Caption of message box", "Verification Finished")); } void KgpgEditor::slotOptions() { m_parent->showOptions(); } void KgpgEditor::modified() { QString capt = m_docname.fileName(); if (m_emptytext) { m_textchanged = !m_editor->toPlainText().isEmpty(); if (capt.isEmpty()) capt = i18n("Untitled"); } else if (!m_textchanged) { m_textchanged = true; } setCaption(capt, m_textchanged); m_editor->document()->setModified(m_textchanged); } void KgpgEditor::slotUndoAvailable(const bool v) { m_editundo->setEnabled(v); } void KgpgEditor::slotRedoAvailable(const bool v) { m_editredo->setEnabled(v); } void KgpgEditor::slotCopyAvailable(const bool v) { m_editcopy->setEnabled(v); m_editcut->setEnabled(v); } void KgpgEditor::newText() { m_textchanged = false; m_emptytext = true; m_docname.clear(); setCaption(i18n("Untitled"), false); slotResetEncoding(false); } #include "moc_kgpgeditor.cpp"