Ran qt3to4
[basket4.git] / src / kgpgme.cpp
blob85c83acf77436301a595b4ac242dbc02d65650a7
1 /***************************************************************************
2 * Copyright (C) 2006 by Petri Damsten *
3 * damu@iki.fi *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 #include "kgpgme.h"
23 #ifdef HAVE_LIBGPGME
25 #include <kapplication.h>
26 #include <kmessagebox.h>
27 #include <kpassdlg.h>
28 #include <kiconloader.h>
29 #include <klistview.h>
30 #include <kdebug.h>
31 #include <qcheckbox.h>
32 #include <qlayout.h>
33 #include <qlabel.h>
34 //Added by qt3to4:
35 #include <Q3CString>
36 #include <QPixmap>
37 #include <Q3VBoxLayout>
38 #include <klocale.h>
39 #include <locale.h>
40 #include <errno.h>
41 #include <stdlib.h>
42 #include <unistd.h>
44 // KGpgSelKey class based on class in KGpg with the same name
46 class KGpgSelKey : public KDialogBase
48 private:
49 KListView* keysListpr;
51 public:
53 KGpgSelKey(QWidget *parent, const char *name, QString preselected,
54 const KGpgMe& gpg):
55 KDialogBase( parent, name, true,i18n("Private Key List"),Ok | Cancel) {
56 QString keyname;
57 Q3VBoxLayout* vbox;
58 QWidget* page = new QWidget(this);
59 QLabel* labeltxt;
60 KIconLoader* loader = KGlobal::iconLoader();
61 QPixmap keyPair = loader->loadIcon("kgpg_key2", KIcon::Small, 20);
63 setMinimumSize(350,100);
64 keysListpr = new KListView(page);
65 keysListpr->setRootIsDecorated(true);
66 keysListpr->addColumn(i18n("Name"));
67 keysListpr->addColumn(i18n("Email"));
68 keysListpr->addColumn(i18n("ID"));
69 keysListpr->setShowSortIndicator(true);
70 keysListpr->setFullWidth(true);
71 keysListpr->setAllColumnsShowFocus(true);
73 labeltxt = new QLabel(i18n("Choose a secret key:"),page);
74 vbox = new Q3VBoxLayout(page);
76 KGpgKeyList list = gpg.keys(true);
78 for(KGpgKeyList::iterator it = list.begin(); it != list.end(); ++it) {
79 QString name = gpg.checkForUtf8((*it).name);
80 KListViewItem *item = new
81 KListViewItem(keysListpr, name, (*it).email, (*it).id);
82 item->setPixmap(0,keyPair);
83 if(preselected == (*it).id) {
84 keysListpr->setSelected(item, true);
85 keysListpr->setCurrentItem(item);
88 if(!keysListpr->selectedItem()) {
89 keysListpr->setSelected(keysListpr->firstChild(), true);
90 keysListpr->setCurrentItem(keysListpr->firstChild());
92 vbox->addWidget(labeltxt);
93 vbox->addWidget(keysListpr);
94 setMainWidget(page);
97 QString key() {
98 Q3ListViewItem* item = keysListpr->selectedItem();
100 if(item)
101 return item->text(2);
102 return "";
106 KGpgMe::KGpgMe() : m_ctx(0), m_useGnuPGAgent(true)
108 init(GPGME_PROTOCOL_OpenPGP);
109 if(gpgme_new(&m_ctx)) {
110 m_ctx = 0;
112 else {
113 gpgme_set_armor(m_ctx, 1);
114 setPassphraseCb();
118 KGpgMe::~KGpgMe()
120 if(m_ctx)
121 gpgme_release(m_ctx);
122 clearCache();
125 void KGpgMe::clearCache()
127 if(m_cache.size() > 0)
129 m_cache.fill('\0');
130 m_cache.truncate(0);
134 void KGpgMe::init(gpgme_protocol_t proto)
136 gpgme_error_t err;
138 gpgme_check_version(NULL);
139 setlocale(LC_ALL, "");
140 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
141 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
143 err = gpgme_engine_check_version(proto);
144 if(err) {
145 KMessageBox::error(kapp->activeWindow(), QString("%1: %2")
146 .arg(gpgme_strsource(err)).arg(gpgme_strerror(err)));
150 QString KGpgMe::checkForUtf8(QString txt)
152 // code borrowed from KGpg which borrowed it from gpa
153 const char *s;
155 // Make sure the encoding is UTF-8.
156 // Test structure suggested by Werner Koch
157 if(txt.isEmpty())
158 return QString::null;
160 for(s = txt.ascii(); *s && !(*s & 0x80); s++)
162 if (*s && !strchr (txt.ascii(), 0xc3) && (txt.find("\\x")==-1))
163 return txt;
165 // The string is not in UTF-8
166 //if (strchr (txt.ascii(), 0xc3)) return (txt+" +++");
167 if (txt.find("\\x")==-1)
168 return QString::fromUtf8(txt.ascii());
169 // if (!strchr (txt.ascii(), 0xc3) || (txt.find("\\x")!=-1)) {
170 for(int idx = 0 ; (idx = txt.find( "\\x", idx )) >= 0 ; ++idx) {
171 char str[2] = "x";
172 str[0] = (char)QString(txt.mid(idx + 2, 2)).toShort(0, 16);
173 txt.replace(idx, 4, str);
175 if (!strchr (txt.ascii(), 0xc3))
176 return QString::fromUtf8(txt.ascii());
177 else
178 return QString::fromUtf8(QString::fromUtf8(txt.ascii()).ascii());
179 // perform Utf8 twice, or some keys display badly
180 return txt;
183 QString KGpgMe::selectKey(QString previous)
185 KGpgSelKey dlg(kapp->activeWindow(), "", previous, *this);
187 if(dlg.exec())
188 return dlg.key();
189 return "";
192 // Rest of the code is mainly based in gpgme examples
194 KGpgKeyList KGpgMe::keys(bool privateKeys /* = false */) const
196 KGpgKeyList keys;
197 gpgme_error_t err = 0, err2 = 0;
198 gpgme_key_t key = 0;
199 gpgme_keylist_result_t result = 0;
201 if(m_ctx) {
202 err = gpgme_op_keylist_start(m_ctx, NULL, privateKeys);
203 if(!err) {
204 while(!(err = gpgme_op_keylist_next(m_ctx, &key))) {
205 KGpgKey gpgkey;
207 if(!key->subkeys)
208 continue;
209 gpgkey.id = key->subkeys->keyid;
210 if(key->uids) {
211 gpgkey.name = key->uids->name;
212 gpgkey.email = key->uids->email;
214 keys.append(gpgkey);
215 gpgme_key_unref(key);
218 if (gpg_err_code (err) == GPG_ERR_EOF)
219 err = 0;
220 err2 = gpgme_op_keylist_end(m_ctx);
221 if(!err)
222 err = err2;
226 if(err) {
227 KMessageBox::error(kapp->activeWindow(), QString("%1: %2")
228 .arg(gpgme_strsource(err)).arg(gpgme_strerror(err)));
230 else {
231 result = gpgme_op_keylist_result(m_ctx);
232 if (result->truncated) {
233 KMessageBox::error(kapp->activeWindow(),
234 i18n("Key listing unexpectedly truncated."));
237 return keys;
240 bool KGpgMe::encrypt(const QByteArray& inBuffer, Q_ULONG length,
241 QByteArray* outBuffer, QString keyid /* = QString::null */)
243 gpgme_error_t err = 0;
244 gpgme_data_t in = 0, out = 0;
245 gpgme_key_t keys[2] = { NULL, NULL };
246 gpgme_key_t* key = NULL;
247 gpgme_encrypt_result_t result = 0;
249 outBuffer->resize(0);
250 if(m_ctx) {
251 err = gpgme_data_new_from_mem(&in, inBuffer.data(), length, 1);
252 if(!err) {
253 err = gpgme_data_new(&out);
254 if(!err) {
255 if(keyid.isNull()) {
256 key = NULL;
258 else {
259 err = gpgme_get_key(m_ctx, keyid.ascii(), &keys[0], 0);
260 key = keys;
263 if(!err) {
264 err = gpgme_op_encrypt(m_ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST,
265 in, out);
266 if(!err) {
267 result = gpgme_op_encrypt_result(m_ctx);
268 if (result->invalid_recipients) {
269 KMessageBox::error(kapp->activeWindow(), QString("%1: %2")
270 .arg(i18n("That public key is not meant for encryption"))
271 .arg(result->invalid_recipients->fpr));
273 else {
274 err = readToBuffer(out, outBuffer);
281 if(err != GPG_ERR_NO_ERROR && err != GPG_ERR_CANCELED) {
282 KMessageBox::error(kapp->activeWindow(), QString("%1: %2")
283 .arg(gpgme_strsource(err)).arg(gpgme_strerror(err)));
285 if(err != GPG_ERR_NO_ERROR)
286 clearCache();
287 if(keys[0])
288 gpgme_key_unref(keys[0]);
289 if(in)
290 gpgme_data_release(in);
291 if(out)
292 gpgme_data_release(out);
293 return (err == GPG_ERR_NO_ERROR);
296 bool KGpgMe::decrypt(const QByteArray& inBuffer, QByteArray* outBuffer)
298 gpgme_error_t err = 0;
299 gpgme_data_t in = 0, out = 0;
300 gpgme_decrypt_result_t result = 0;
302 outBuffer->resize(0);
303 if(m_ctx) {
304 err = gpgme_data_new_from_mem(&in, inBuffer.data(), inBuffer.size(), 1);
305 if(!err) {
306 err = gpgme_data_new(&out);
307 if(!err) {
308 err = gpgme_op_decrypt(m_ctx, in, out);
309 if(!err) {
310 result = gpgme_op_decrypt_result(m_ctx);
311 if(result->unsupported_algorithm) {
312 KMessageBox::error(kapp->activeWindow(), QString("%1: %2")
313 .arg(i18n("Unsupported algorithm"))
314 .arg(result->unsupported_algorithm));
316 else {
317 err = readToBuffer(out, outBuffer);
323 if(err != GPG_ERR_NO_ERROR && err != GPG_ERR_CANCELED) {
324 KMessageBox::error(kapp->activeWindow(), QString("%1: %2")
325 .arg(gpgme_strsource(err)).arg(gpgme_strerror(err)));
327 if(err != GPG_ERR_NO_ERROR)
328 clearCache();
329 if(in)
330 gpgme_data_release(in);
331 if(out)
332 gpgme_data_release(out);
333 return (err == GPG_ERR_NO_ERROR);
336 #define BUF_SIZE (32 * 1024)
338 gpgme_error_t KGpgMe::readToBuffer(gpgme_data_t in, QByteArray* outBuffer) const
340 int ret;
341 gpgme_error_t err = GPG_ERR_NO_ERROR;
343 ret = gpgme_data_seek(in, 0, SEEK_SET);
344 if(ret) {
345 err = gpgme_err_code_from_errno(errno);
347 else {
348 char* buf = new char[BUF_SIZE + 2];
350 if(buf) {
351 while((ret = gpgme_data_read(in, buf, BUF_SIZE)) > 0) {
352 uint size = outBuffer->size();
353 if(outBuffer->resize(size + ret))
354 memcpy(outBuffer->data() + size, buf, ret);
356 if(ret < 0)
357 err = gpgme_err_code_from_errno(errno);
358 delete[] buf;
361 return err;
364 bool KGpgMe::isGnuPGAgentAvailable()
366 QString agent_info = getenv("GPG_AGENT_INFO");
368 if (agent_info.find(':') > 0)
369 return true;
370 return false;
373 void KGpgMe::setPassphraseCb()
375 bool agent = false;
376 QString agent_info;
378 agent_info = getenv("GPG_AGENT_INFO");
380 if(m_useGnuPGAgent)
382 if (agent_info.find(':'))
383 agent = true;
384 if(agent_info.startsWith("disable:"))
385 setenv("GPG_AGENT_INFO", agent_info.mid(8), 1);
387 else
389 if(!agent_info.startsWith("disable:"))
390 setenv("GPG_AGENT_INFO", "disable:" + agent_info, 1);
392 if (agent)
393 gpgme_set_passphrase_cb(m_ctx, 0, 0);
394 else
395 gpgme_set_passphrase_cb(m_ctx, passphraseCb, this);
398 gpgme_error_t KGpgMe::passphraseCb(void* hook, const char* uid_hint,
399 const char* passphrase_info,
400 int last_was_bad, int fd)
402 KGpgMe* gpg = static_cast<KGpgMe*>(hook);
403 return gpg->passphrase(uid_hint, passphrase_info, last_was_bad, fd);
406 gpgme_error_t KGpgMe::passphrase(const char* uid_hint,
407 const char* /*passphrase_info*/,
408 int last_was_bad, int fd)
410 gpgme_error_t res = GPG_ERR_CANCELED;
411 QString s;
412 QString gpg_hint = checkForUtf8(uid_hint);
413 int result;
415 if(last_was_bad){
416 s += "<b>" + i18n("Wrong password.") + "</b><br><br>\n\n";
417 clearCache();
420 if(!m_text.isEmpty())
421 s += m_text + "<br>";
423 if(!gpg_hint.isEmpty())
424 s += gpg_hint;
426 if(m_cache.isEmpty()){
427 Q3CString password;
429 if(m_saving)
430 result = KPasswordDialog::getNewPassword(password, s);
431 else
432 result = KPasswordDialog::getPassword(password, s);
434 if(result == KPasswordDialog::Accepted)
435 m_cache = password;
437 else
438 result = KPasswordDialog::Accepted;
440 if(result == KPasswordDialog::Accepted) {
441 write(fd, m_cache.data(), m_cache.length());
442 res = 0;
444 write(fd, "\n", 1);
445 return res;
447 #endif // HAVE_LIBGPGME