00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "keyservers.h"
00019
00020
00021 #include <QPushButton>
00022 #include <QTextCodec>
00023 #include <QCheckBox>
00024 #include <QCursor>
00025 #include <QLabel>
00026 #include <QFile>
00027
00028 #include <KConfig>
00029 #include <KMessageBox>
00030 #include <KComboBox>
00031 #include <KLocale>
00032 #include <K3ProcIO>
00033 #include <KDebug>
00034 #include <KDateTime>
00035
00036 #include "kgpgsettings.h"
00037 #include "detailedconsole.h"
00038 #include "convert.h"
00039
00040
00041 using namespace KgpgCore;
00042
00043 ConnectionDialog::ConnectionDialog(QWidget *parent)
00044 : KDialog(parent)
00045 {
00046 setCaption(i18n("Keyserver"));
00047 setModal(true);
00048
00049 setButtons(Cancel);
00050 setDefaultButton(Cancel);
00051 setButtonText(Cancel, i18n("&Abort"));
00052
00053 QWidget *widget = new QWidget(this);
00054 widget->setMinimumWidth(300);
00055
00056 QLabel *label = new QLabel(i18n("<b>Connecting to the server...</b>"), widget);
00057
00058 QVBoxLayout *vlayout = new QVBoxLayout(widget);
00059 vlayout->addWidget(label);
00060
00061 setMainWidget(widget);
00062 layout()->setSizeConstraint(QLayout::SetFixedSize);
00063
00064 show();
00065 }
00066
00067 KeyServer::KeyServer(QWidget *parent, const bool &modal, const bool &autoclose)
00068 : KDialog(parent)
00069 {
00070 setCaption(i18n("Key Server"));
00071 setButtons(Close);
00072 setDefaultButton(Close);
00073 setModal(modal);
00074
00075 m_autoclose = autoclose;
00076
00077 page = new keyServerWidget();
00078 setMainWidget(page);
00079
00080 QStringList serverlist = getServerList();
00081 page->kCBexportks->addItems(serverlist);
00082 page->kCBimportks->addItems(serverlist);
00083 page->kLEimportid->setFocus();
00084
00085 connect(page->Buttonimport, SIGNAL(clicked()), this, SLOT(slotImport()));
00086 connect(page->Buttonsearch, SIGNAL(clicked()), this, SLOT(slotSearch()));
00087 connect(page->Buttonexport, SIGNAL(clicked()), this, SLOT(slotPreExport()));
00088 connect(this, SIGNAL(okClicked()), this, SLOT(slotOk()));
00089 connect(page->cBproxyI, SIGNAL(toggled(bool)), this, SLOT(slotEnableProxyI(bool)));
00090 connect(page->cBproxyE, SIGNAL(toggled(bool)), this, SLOT(slotEnableProxyE(bool)));
00091 connect(page->kLEimportid, SIGNAL(textChanged(const QString &)), this, SLOT(slotTextChanged(const QString &)));
00092
00093 page->cBproxyI->setChecked(KGpgSettings::useProxy());
00094 page->cBproxyE->setChecked(KGpgSettings::useProxy());
00095
00096 QString httpproxy = getenv("http_proxy");
00097 if (!httpproxy.isEmpty())
00098 {
00099 page->cBproxyI->setEnabled(true);
00100 page->cBproxyE->setEnabled(true);
00101 page->kLEproxyI->setText(httpproxy);
00102 page->kLEproxyE->setText(httpproxy);
00103 }
00104
00105 KgpgInterface *interface = new KgpgInterface();
00106 connect (interface, SIGNAL(readPublicKeysFinished(KgpgCore::KgpgKeyList, KgpgInterface*)), this, SLOT(slotReadKeys(KgpgCore::KgpgKeyList, KgpgInterface*)));
00107 interface->readPublicKeys();
00108
00109 page->Buttonimport->setEnabled(!page->kLEimportid->text().isEmpty());
00110 page->Buttonsearch->setEnabled(!page->kLEimportid->text().isEmpty());
00111 setMinimumSize(sizeHint());
00112 }
00113
00114 void KeyServer::slotReadKeys(KgpgKeyList list, KgpgInterface *interface)
00115 {
00116 delete interface;
00117 for (int i = 0; i < list.size(); ++i)
00118 {
00119 const KgpgKey key = list.at(i);
00120
00121 bool dead = false;
00122 if ((key.trust() == 'i') || (key.trust() == 'd') || (key.trust() == 'r') || (key.trust() == 'e'))
00123 dead = true;
00124
00125 if (!dead)
00126 {
00127 QString line = key.name();
00128 if (!key.comment().isEmpty()) line += " (" + key.comment() + ')';
00129 if (!key.email().isEmpty()) line += " <" + key.email() + '>';
00130 if (line.length() > 35)
00131 {
00132 line.remove(35, line.length());
00133 line += "...";
00134 }
00135
00136 if (!line.isEmpty())
00137 page->kCBexportkey->addItem(key.id() + ": " + line);
00138 }
00139 }
00140 }
00141
00142 void KeyServer::refreshKeys(QStringList keys)
00143 {
00144 QApplication::setOverrideCursor(QCursor(Qt::BusyCursor));
00145
00146 QString keyserv = getServerList().first();
00147
00148 QString proxy;
00149 if (KGpgSettings::useProxy())
00150 proxy = getenv("http_proxy");
00151
00152 KgpgInterface *interface = new KgpgInterface();
00153 connect(interface, SIGNAL(downloadKeysFinished(QList<int>, QStringList, bool, QString, KgpgInterface*)), this, SLOT(slotDownloadKeysFinished(QList<int>, QStringList, bool, QString, KgpgInterface*)));
00154 connect(interface, SIGNAL(downloadKeysAborted(KgpgInterface*)), this, SLOT(slotAbort(KgpgInterface*)));
00155
00156 m_importpop = new ConnectionDialog(this);
00157 connect(m_importpop, SIGNAL(cancelClicked()), interface, SLOT(downloadKeysAbort()));
00158
00159 interface->downloadKeys(keys, keyserv, true, proxy);
00160 }
00161
00162 void KeyServer::slotImport()
00163 {
00164 if (page->kCBimportks->currentText().isEmpty())
00165 return;
00166
00167 if (page->kLEimportid->text().isEmpty())
00168 {
00169 KMessageBox::sorry(this, i18n("You must enter a search string."));
00170 return;
00171 }
00172
00173 QApplication::setOverrideCursor(QCursor(Qt::BusyCursor));
00174
00175 KgpgInterface *interface = new KgpgInterface();
00176 connect(interface, SIGNAL(downloadKeysFinished(QList<int>, QStringList, bool, QString, KgpgInterface*)), this, SLOT(slotDownloadKeysFinished(QList<int>, QStringList, bool, QString, KgpgInterface*)));
00177 connect(interface, SIGNAL(downloadKeysAborted(KgpgInterface*)), this, SLOT(slotAbort(KgpgInterface*)));
00178
00179 m_importpop = new ConnectionDialog(this);
00180 connect(m_importpop, SIGNAL(cancelClicked()), interface, SLOT(downloadKeysAbort()));
00181
00182 interface->downloadKeys(page->kLEimportid->text().simplified().split(' '), page->kCBimportks->currentText(), false, page->kLEproxyI->text());
00183 }
00184
00185 void KeyServer::slotDownloadKeysFinished(QList<int> result, QStringList keys, bool imported, QString log, KgpgInterface *interface)
00186 {
00187 delete m_importpop;
00188 m_importpop = 0;
00189 delete interface;
00190
00191 QApplication::restoreOverrideCursor();
00192
00193 QString resultmessage;
00194 if (imported)
00195 {
00196 if (result[0] != 0) resultmessage += i18np("<qt>%1 key processed.<br/></qt>", "<qt>%1 keys processed.<br/></qt>", result[0]);
00197 if (result[4] != 0) resultmessage += i18np("<qt>%1 key unchanged.<br/></qt>", "<qt>%1 keys unchanged.<br/></qt>", result[4]);
00198 if (result[7] != 0) resultmessage += i18np("<qt>%1 signature imported.<br/></qt>", "<qt>%1 signatures imported.<br/></qt>", result[7]);
00199 if (result[1] != 0) resultmessage += i18np("<qt>%1 key without ID.<br/></qt>", "<qt>%1 keys without ID.<br/></qt>", result[1]);
00200 if (result[3] != 0) resultmessage += i18np("<qt>%1 RSA key imported.<br/></qt>", "<qt>%1 RSA keys imported.<br/></qt>", result[3]);
00201 if (result[5] != 0) resultmessage += i18np("<qt>%1 user ID imported.<br/></qt>", "<qt>%1 user IDs imported.<br/></qt>", result[5]);
00202 if (result[6] != 0) resultmessage += i18np("<qt>%1 subkey imported.<br/></qt>", "<qt>%1 subkeys imported.<br/></qt>", result[6]);
00203 if (result[8] != 0) resultmessage += i18np("<qt>%1 revocation certificate imported.<br/></qt>", "<qt>%1 revocation certificates imported.<br/></qt>", result[8]);
00204 if (result[9] != 0) resultmessage += i18np("<qt>%1 secret key processed.<br/></qt>", "<qt>%1 secret keys processed.<br/></qt>", result[9]);
00205 if (result[10] != 0) resultmessage += i18np("<qt><b>%1 secret key imported.</b><br/></qt>", "<qt><b>%1 secret keys imported.</b><br/></qt>", result[10]);
00206 if (result[11] != 0) resultmessage += i18np("<qt>%1 secret key unchanged.<br/></qt>", "<qt>%1 secret keys unchanged.<br/></qt>", result[11]);
00207 if (result[12] != 0) resultmessage += i18np("<qt>%1 secret key not imported.<br/></qt>", "<qt>%1 secret keys not imported.<br/></qt>", result[12]);
00208 if (result[2] != 0) resultmessage += i18np("<qt><b>%1 key imported:</b><br/></qt>", "<qt><b>%1 keys imported:</b><br/></qt>", result[2]);
00209 }
00210 else
00211 resultmessage = i18n("No key imported... \nCheck detailed log for more infos");
00212
00213 if (!keys.empty())
00214 emit importFinished(keys);
00215
00216 (void) new KgpgDetailedInfo(0, resultmessage, log, keys);
00217 }
00218
00219 void KeyServer::slotAbort(KgpgInterface *interface)
00220 {
00221 delete interface;
00222 QApplication::restoreOverrideCursor();
00223 if (m_autoclose)
00224 close();
00225 }
00226
00227 void KeyServer::slotExport(const QString &keyId)
00228 {
00229 if (page->kCBexportks->currentText().isEmpty())
00230 return;
00231
00232 QApplication::setOverrideCursor(QCursor(Qt::BusyCursor));
00233
00234 KgpgInterface *interface = new KgpgInterface();
00235 connect(interface, SIGNAL(uploadKeysFinished(QString, KgpgInterface*)), this, SLOT(slotUploadKeysFinished(QString, KgpgInterface*)));
00236 connect(interface, SIGNAL(uploadKeysAborted(KgpgInterface*)), this, SLOT(slotAbort(KgpgInterface*)));
00237
00238 m_importpop = new ConnectionDialog(this);
00239 connect(m_importpop, SIGNAL(cancelClicked()), interface, SLOT(uploadKeysAbort()));
00240
00241 interface->uploadKeys(keyId.simplified().split(' '), page->kCBimportks->currentText(), expattr, page->kLEproxyI->text());
00242 }
00243
00244 void KeyServer::slotUploadKeysFinished(QString message, KgpgInterface *interface)
00245 {
00246 delete m_importpop;
00247 m_importpop = 0;
00248 delete interface;
00249
00250 QApplication::restoreOverrideCursor();
00251
00252 KMessageBox::information(this, message);
00253 }
00254
00255 void KeyServer::slotSearch()
00256 {
00257 if (page->kCBimportks->currentText().isEmpty())
00258 return;
00259
00260 if (page->kLEimportid->text().isEmpty())
00261 {
00262 KMessageBox::sorry(this, i18n("You must enter a search string."));
00263 return;
00264 }
00265
00266
00267
00268 m_dialogserver = new KDialog(this );
00269 m_dialogserver->setCaption( i18n("Import Key From Keyserver") );
00270 m_dialogserver->setButtons( KDialog::Ok | KDialog::Close );
00271 m_dialogserver->setDefaultButton( KDialog::Ok);
00272 m_dialogserver->setModal( true );
00273
00274 m_dialogserver->setButtonText(KDialog::Ok, i18n("&Import"));
00275 m_dialogserver->enableButtonOk(false);
00276 m_listpop = new searchRes(0);
00277
00278
00279 m_listpop->statusText->setText(i18n("Connecting to the server..."));
00280
00281 connect(m_listpop->kLVsearch, SIGNAL(itemSelectionChanged()), this, SLOT(transferKeyID()));
00282 connect(m_dialogserver, SIGNAL(okClicked()), this, SLOT(slotPreImport()));
00283 connect(m_listpop->kLVsearch, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), m_dialogserver, SIGNAL(okClicked()));
00284
00285 connect(m_dialogserver, SIGNAL(closeClicked()), this, SLOT(handleQuit()));
00286 connect(m_listpop, SIGNAL(destroyed()), this, SLOT(slotAbortSearch()));
00287
00288 m_listpop->kLVsearch->setSelectionMode(QAbstractItemView::ExtendedSelection);
00289
00290 m_count = 0;
00291 m_keyid = QString();
00292 m_readmessage.clear();
00293 m_kitem = NULL;
00294
00295 QString keyserv = page->kCBimportks->currentText();
00296 QStringList *args = new QStringList();
00297
00298 *args << "--command-fd=0" << "--with-colons"<< "--search-keys" << page->kLEimportid->text().simplified().toLocal8Bit();
00299
00300 m_searchproc = createGPGProc(args);
00301
00302 m_keynumbers = 0;
00303 connect(m_searchproc, SIGNAL(processExited(K3Process *)), this, SLOT(slotSearchResult(K3Process *)));
00304 connect(m_searchproc, SIGNAL(readReady(K3ProcIO *)), this, SLOT(slotSearchRead(K3ProcIO *)));
00305 m_searchproc->start(K3Process::NotifyOnExit, true);
00306
00307 QApplication::setOverrideCursor(QCursor(Qt::BusyCursor));
00308 m_dialogserver->setMainWidget(m_listpop);
00309 m_listpop->setMinimumSize(m_listpop->sizeHint());
00310 m_dialogserver->exec();
00311 }
00312
00313 void KeyServer::slotAbortSearch()
00314 {
00315 if (m_dialogserver)
00316 {
00317 delete m_dialogserver;
00318 m_dialogserver = 0L;
00319 }
00320 }
00321
00322 void KeyServer::slotSearchRead(K3ProcIO *p)
00323 {
00324 QString required;
00325 while (p->readln(required, true) != -1)
00326 {
00327
00328 if (required.contains("keysearch.prompt"))
00329 {
00330 if (m_count < 4)
00331 p->writeStdin(QByteArray("N"), true);
00332 else
00333 {
00334 p->writeStdin(QByteArray("Q"), true);
00335 p->closeWhenDone();
00336 }
00337
00338 required.clear();
00339 }
00340
00341 if (required.contains("GOT_IT"))
00342 {
00343 m_count++;
00344 required.clear();
00345 } else if (required.startsWith("pub")) {
00346 if (m_keyid.length() > 0)
00347 CreateUidEntry();
00348 m_keyid = required;
00349 m_kitem = NULL;
00350 } else if (required.startsWith("uid")) {
00351 QString kid = required.section(':', 1, 1);
00352
00353 if (m_kitem != NULL) {
00354 QTreeWidgetItem *k = new QTreeWidgetItem(m_kitem);
00355 k->setText(0, kid);
00356 } else {
00357 m_kitem = new QTreeWidgetItem(m_listpop->kLVsearch);
00358 m_kitem->setText(0, kid);
00359 m_keynumbers++;
00360 }
00361 m_count = 0;
00362 required.clear();
00363 }
00364 }
00365 }
00366
00367 void KeyServer::slotSearchResult(K3Process *)
00368 {
00369
00370 if (m_kitem != NULL)
00371 CreateUidEntry();
00372
00373 QString nb;
00374 m_dialogserver->enableButtonOk(true);
00375 QApplication::restoreOverrideCursor();
00376 nb = nb.setNum(m_keynumbers);
00377
00378 m_listpop->statusText->setText(i18n("Found %1 matching keys", nb));
00379
00380 if (m_listpop->kLVsearch->topLevelItemCount() > 0)
00381 {
00382 m_listpop->kLVsearch->setCurrentItem(m_listpop->kLVsearch->topLevelItem(0));
00383 transferKeyID();
00384 }
00385 }
00386
00387 void KeyServer::slotSetText(const QString &text)
00388 {
00389 page->kLEimportid->setText(text);
00390 }
00391
00392 void KeyServer::slotTextChanged(const QString &text)
00393 {
00394 page->Buttonimport->setEnabled(!text.isEmpty());
00395 page->Buttonsearch->setEnabled(!text.isEmpty());
00396 }
00397
00398 void KeyServer::slotSetExportAttribute(const QString *state)
00399 {
00400 if (state != 0)
00401 expattr = QString(*state);
00402 else
00403 expattr = QString();
00404 }
00405
00406 void KeyServer::slotEnableProxyI(const bool &on)
00407 {
00408 page->kLEproxyI->setEnabled(on);
00409 }
00410
00411 void KeyServer::slotEnableProxyE(const bool &on)
00412 {
00413 page->kLEproxyE->setEnabled(on);
00414 }
00415
00416 void KeyServer::transferKeyID()
00417 {
00418 if (m_listpop->kLVsearch->topLevelItemCount() == 0)
00419 return;
00420
00421 QStringList keysToSearch;
00422 m_listpop->kLEID->clear();
00423 const QList<QTreeWidgetItem*> &searchList = m_listpop->kLVsearch->selectedItems();
00424
00425 foreach (QTreeWidgetItem *searchItem, searchList)
00426 {
00427 if (searchItem)
00428 {
00429 QTreeWidgetItem *item = searchItem->parent();
00430
00431 if (item == NULL)
00432 item = searchItem;
00433
00434 QString id = item->data(0, Qt::UserRole).toString();
00435 if (!keysToSearch.contains(id))
00436 keysToSearch << id;
00437 }
00438 }
00439
00440
00441 m_listpop->kLEID->setText(keysToSearch.join(" "));
00442 }
00443
00444 void KeyServer::slotPreImport()
00445 {
00446 transferKeyID();
00447 if (m_listpop->kLEID->text().isEmpty())
00448 {
00449 KMessageBox::sorry(this, i18n("You must choose a key."));
00450 return;
00451 }
00452 page->kLEimportid->setText(m_listpop->kLEID->text());
00453 m_dialogserver->close();
00454 slotImport();
00455 }
00456
00457 void KeyServer::slotPreExport()
00458 {
00459 slotExport(page->kCBexportkey->currentText().section(':', 0, 0));
00460 }
00461
00462 void KeyServer::slotOk()
00463 {
00464 accept();
00465 }
00466
00467 QStringList KeyServer::getServerList()
00468 {
00469 KConfig config("kgpgrc", KConfig::SimpleConfig);
00470 KConfigGroup group = config.group("Servers");
00471
00472 QStringList serverlist;
00473 serverlist << KgpgInterface::getGpgSetting("keyserver", KGpgSettings::gpgConfigPath());
00474 serverlist << group.readEntry("Server_List").split(',', QString::SkipEmptyParts);
00475
00476 return serverlist;
00477 }
00478
00479 void KeyServer::handleQuit()
00480 {
00481 if (m_searchproc->isRunning())
00482 {
00483 QApplication::restoreOverrideCursor();
00484 disconnect(m_searchproc, 0, 0, 0);
00485 m_searchproc->kill();
00486 }
00487 m_dialogserver->close();
00488 }
00489
00494 K3ProcIO *KeyServer::createGPGProc(QStringList *args)
00495 {
00496 K3ProcIO *gp = new K3ProcIO();
00497
00498 QString keyserv = page->kCBimportks->currentText();
00499 bool useproxy = page->cBproxyI->isChecked();
00500 QString proxy = page->kLEproxyI->text();
00501
00502 *gp << KGpgSettings::gpgBinaryPath();
00503
00504 if (useproxy)
00505 {
00506 gp->setEnvironment("http_proxy", proxy);
00507 *gp << "--keyserver-options" << "honor-http-proxy";
00508 }
00509 else
00510 *gp << "--keyserver-options" << "no-honor-http-proxy";
00511 *gp << "--keyserver" << keyserv << "--status-fd=2";
00512
00513 *gp << *args;
00514 delete args;
00515
00516 return gp;
00517 }
00518
00519 void KeyServer::slotSetKeyserver(const QString &server)
00520 {
00521 page->kCBimportks->setCurrentIndex(page->kCBimportks->findText(server));
00522 }
00523
00524 void KeyServer::CreateUidEntry(void)
00525 {
00526 Q_ASSERT(m_keyid.section(':', 1, 1).length() > 0);
00527
00528 QString id = m_keyid.section(':', 1, 1).right(16);
00529 KDateTime kd;
00530 kd.setTime_t(m_keyid.section(':', 4, 4).toULongLong());
00531
00532 QTreeWidgetItem *k = new QTreeWidgetItem(m_kitem);
00533 if (m_keyid.section(':', 6, 6) == "r")
00534 {
00535 k->setText(0, i18n("ID %1, %2 bit %3 key, created %4 revoked", id, m_keyid.section(':', 3, 3),
00536 Convert::toString(Convert::toAlgo(m_keyid.section(':', 2, 2))),
00537 kd.toString(KDateTime::LocalDate)));
00538 }
00539 else
00540 {
00541 k->setText(0, i18n("ID %1, %2 bit %3 key, created %4", id, m_keyid.section(':', 3, 3),
00542 Convert::toString(Convert::toAlgo(m_keyid.section(':', 2, 2))),
00543 kd.toString(KDateTime::LocalDate)));
00544 }
00545 m_kitem->setData(0, Qt::UserRole, id);
00546 }
00547
00548 #include "keyservers.moc"