/***************************************************************************
                          keyinfowidget.cpp  -  description
                             -------------------
    begin                : Mon Nov 18 2002
    copyright          : (C) 2002 by Jean-Baptiste Mardelle
    email                : bj@altern.org

    updated to handle gpg21 : Sun Jul 30 10:18:29 CEST 2017
    copyright          : (C) 2017 by Emanoil Kotsev
    email              : deloptes@yahoo.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 gpgOutpution) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <tdelocale.h>
#include <kprocess.h>
#include <tqdatetime.h>
#include <tqfile.h>
#include <kprocio.h>
#include <kpassivepopup.h>
#include <tdeaction.h>
#include <tqregexp.h>
#include <tdetempfile.h>
#include <tqimage.h>
#include <kdatepicker.h>
#include <tqpushbutton.h>
#include <kcombobox.h>
#include <tqlabel.h>
#include <kiconloader.h>
#include <tqcheckbox.h>
#include <tqlayout.h>
#include <kactivelabel.h>
#include <klineedit.h>
#include <ktrader.h>
#include <kservice.h>
#include <tdemessagebox.h>

#include "keyinfowidget.h"
#include "keyproperties.h"
#include "kgpgsettings.h"
#include "kgpginterface.h"

KgpgKeyInfo::KgpgKeyInfo(TQWidget *parent, const char *name,TQString sigkey):KDialogBase( Swallow, i18n("Key Properties"), Close, Close, parent, name,true)
{

        FILE *pass;
        char line[200]="";
        TQString gpgOutput,fullID;
        hasPhoto=false;
	bool isSecret=false;
	keyWasChanged=false;

	prop=new KeyProperties();
	setMainWidget(prop);
	TQString gpgcmd="gpg --no-tty --no-secmem-warning --with-colon --list-secret-key "+KShellProcess::quote(sigkey);
        pass=popen(TQFile::encodeName(gpgcmd),"r");
        while ( fgets( line, sizeof(line), pass)) {
                gpgOutput=line;
                if (gpgOutput.startsWith("sec")) isSecret=true;
               }
	 pclose(pass);

        if (!isSecret) {
                prop->changeExp->hide();
                prop->changePass->hide();
		        }
	loadKey(sigkey);

        if (hasPhoto) {
	KgpgInterface *photoProcess=new KgpgInterface();
        photoProcess->KgpgGetPhotoList(displayedKeyID);
	connect(photoProcess,TQ_SIGNAL(signalPhotoList(TQStringList)),this,TQ_SLOT(slotSetMainPhoto(TQStringList)));
        }
	else
	prop->comboId->setEnabled(false);

	connect(prop->changeExp,TQ_SIGNAL(clicked()),this,TQ_SLOT(slotChangeExp()));
        connect(this,TQ_SIGNAL(closeClicked()),this,TQ_SLOT(slotPreOk()));
        connect(prop->changePass,TQ_SIGNAL(clicked()),this,TQ_SLOT(slotChangePass()));
	connect(prop->comboId,TQ_SIGNAL(activated (const TQString &)),this,TQ_SLOT(reloadMainPhoto(const TQString &)));
	connect(prop->cbDisabled,TQ_SIGNAL(toggled(bool)),this,TQ_SLOT(slotDisableKey(bool)));
	connect(prop->kCOwnerTrust,TQ_SIGNAL(activated (int)),this,TQ_SLOT(slotChangeTrust(int)));
	connect(this,TQ_SIGNAL(changeMainPhoto(const TQPixmap&)),this,TQ_SLOT(slotSetPhoto(const TQPixmap&)));

	//prop->setMinimumSize(prop->sizeHint());
}

void KgpgKeyInfo::slotDisableKey(bool isOn)
{
//	kdDebug(2100) << k_funcinfo << endl;
	TDEProcess kp;

	kp<<"gpg" <<"--no-tty" <<"--edit-key" <<displayedKeyID;
	if (isOn) kp<<"disable";
	else kp<<"enable";
	kp<<"save";
	kp.start(TDEProcess::Block);
	loadKey(displayedKeyID);
	keyWasChanged=true;
}

void KgpgKeyInfo::loadKey(TQString Keyid)
{
//	kdDebug(2100) << k_funcinfo << endl;
	FILE *pass;
	char line[200]="";
	TQString currentKey;
	TQMap<TQString,TQStringList> hashMap;

	TQString gpgcmd="gpg --no-tty --no-secmem-warning --with-colon --with-fingerprint --list-key "+KShellProcess::quote(Keyid);

	pass=popen(TQFile::encodeName(gpgcmd),"r");
	while ( fgets( line, sizeof(line), pass) ) {
		TQString tst=TQString::fromUtf8(line);
		if ( tst.startsWith("pub")  ) {
			currentKey = tst.section(':',4,4);
			TQStringList lst; lst << tst;
			hashMap.insert(currentKey,lst);
		}
		else {
			hashMap.find(currentKey).data().append(tst);
		}
	}
	pclose(pass);

	TQMap<TQString,TQStringList>::Iterator ite;
	for (ite = hashMap.begin(); ite != hashMap.end(); ite++) {
		TQStringList::Iterator it;
		TQString fullname,gpgOutput;
		TQColor trustColor;
		TQString fingervalue=TQString();

		for (it = ite.data().begin(); it != ite.data().end(); it++) {
			TQString gpgOutput =  (*it);

			if (gpgOutput.startsWith("uat")) {
				hasPhoto=true;
			}
			if ( gpgOutput.startsWith("pub") ) {
                        TQString algo=gpgOutput.section(':',3,3);
                        switch( algo.toInt() ) {
                        case  1:
                                algo="RSA";
                                break;
                        case 16:
                        case 20:
                                algo="ElGamal";
                                break;
                        case 17:
                                algo="DSA";
                                break;
                        default:
                                algo=TQString("#" + algo);
                                break;
                        }
			prop->tLAlgo->setText(algo);

                        const TQString trust=gpgOutput.section(':',1,1);
                        TQString tr;
                        switch( trust[0] ) {
                        case 'o':
                                tr= i18n("Unknown");
				trustColor=KGpgSettings::colorUnknown();
                                break;
                        case 'i':
                                tr= i18n("Invalid");
				trustColor=KGpgSettings::colorBad();
                                break;
                        case 'd':
                                tr=i18n("Disabled");
				trustColor=KGpgSettings::colorBad();
				prop->cbDisabled->setChecked(true);
                                break;
                        case 'r':
                                tr=i18n("Revoked");
				trustColor=KGpgSettings::colorRev();
                                break;
                        case 'e':
                                tr=i18n("Expired");
				trustColor=KGpgSettings::colorBad();
                                break;
                        case 'q':
                                tr=i18n("Undefined");
				trustColor=KGpgSettings::colorUnknown();
                                break;
                        case 'n':
                                tr=i18n("None");
				trustColor=KGpgSettings::colorUnknown();
                                break;
                        case 'm':
                                tr=i18n("Marginal");
				trustColor=KGpgSettings::colorBad();
                                break;
                        case 'f':
                                tr=i18n("Full");
				trustColor=KGpgSettings::colorGood();
                                break;
                        case 'u':
                                tr=i18n("Ultimate");
				trustColor=KGpgSettings::colorGood();
                                break;
                        default:
                                tr="?";
				trustColor=KGpgSettings::colorUnknown();
                                break;
                        }

			if (gpgOutput.section(':',11,11).find("D",0,true)!=-1)  // disabled key
			{
				tr=i18n("Disabled");
				trustColor=KGpgSettings::colorBad();
				prop->cbDisabled->setChecked(true);
			}

                        prop->kLTrust->setText(tr);
                        prop->pixmapTrust->setPaletteBackgroundColor(trustColor);

				TQString fullID=gpgOutput.section(':',4,4);
				displayedKeyID=fullID.right(8);
				prop->tLID->setText(fullID);

				fullname=gpgOutput.section(':',9,9);

				TQDate date;
				if (KgpgInterface::getGpgVersion() >= 210 ) {
					TQDateTime timestamp;
					timestamp.setTime_t(gpgOutput.section(':',5,5).toInt());
					date = timestamp.date();
				}
				else {
					date = TQDate::fromString(gpgOutput.section(':',5,5), TQt::ISODate);
				}
				Q_ASSERT ( date.isValid())/*  tqWarning("create date is not valid")*/;

				prop->tLCreation->setText(TDEGlobal::locale()->formatDate(date));
				if (gpgOutput.section(':',6,6).isEmpty()) {
					expirationDate=i18n("Unlimited");
				}
				else {
					if (KgpgInterface::getGpgVersion() >= 210 ) {
						TQDateTime timestamp;
						timestamp.setTime_t(gpgOutput.section(':',6,6).toInt());
						date = timestamp.date();
					}
					else {
						date = TQDate::fromString(gpgOutput.section(':',6,6), TQt::ISODate);
					}
					Q_ASSERT (date.isValid()) /* tqWarning("Expirationdate date is not valid")*/;
					expirationDate=TDEGlobal::locale()->formatDate(date);
				}
                        prop->tLExpiration->setText(expirationDate);

                        prop->tLLength->setText(gpgOutput.section(':',2,2));

                        const TQString otrust=gpgOutput.section(':',8,8);
			int ownerTrust=0;

			/*	Don't know=1; Do NOT trust=2; Marginally=3; Fully=4; Ultimately=5;   */

                        switch( otrust[0] ) {
                        case 'f':
                                ownerTrust=3;
                                break;
                        case 'u':
                                ownerTrust=4;
                                break;
                        case 'm':
                                ownerTrust=2;
                                break;
                        case 'n':
                                ownerTrust=1;
                                break;
                        default:
                                ownerTrust=0;
                                break;
                        }
                        prop->kCOwnerTrust->setCurrentItem(ownerTrust);
			}

			if ( gpgOutput.startsWith("uid") && fullname.isEmpty() ) {
				fullname = gpgOutput.section(':',9,9);
			}
			if (gpgOutput.startsWith("fpr") && (fingervalue.isNull())) {
				fingervalue=gpgOutput.section(':',9,9);
				// format fingervalue in 4-digit groups
				uint len = fingervalue.length();
				if ((len > 0) && (len % 4 == 0)) {
					for (uint n = 0; 4*(n+1) < len; n++) {
						fingervalue.insert(5*n+4, ' ');
					}
				}
				prop->lEFinger->setText(fingervalue);
			}
		}

		if (!fullname.isEmpty()) {
                        if (fullname.find("<")!=-1) {
                                TQString kmail=fullname;
				if (fullname.find(")")!=-1)
				kmail=kmail.section(')',1);
				kmail=kmail.section('<',1);
				kmail.truncate(kmail.length()-1);
				if (kmail.find("<")!=-1) ////////  several email addresses in the same key
				{
				kmail=kmail.replace(">",";");
				kmail.remove("<");
				}
				prop->tLMail->setText("<qt><a href=mailto:"+kmail+">"+kmail+"</a></qt>");
                        } else
                                prop->tLMail->setText(i18n("none"));

                        TQString kname=fullname.section('<',0,0);
                        if (fullname.find("(")!=-1) {
                                kname=kname.section('(',0,0);
                                TQString comment=fullname.section('(',1,1);
                                comment=comment.section(')',0,0);
                                prop->tLComment->setText(KgpgInterface::checkForUtf8(comment));
                        } else
                                prop->tLComment->setText(i18n("none"));

			prop->tLName->setText("<qt><b>"+KgpgInterface::checkForUtf8(kname).replace(TQRegExp("<"),"&lt;")+"</b></qt>");
                }
        }
}

void KgpgKeyInfo::slotSetMainPhoto(TQStringList list)
{
//	kdDebug(2100) << k_funcinfo << endl;
prop->comboId->insertStringList(list);
reloadMainPhoto(prop->comboId->currentText());
}

void KgpgKeyInfo::reloadMainPhoto(const TQString &uid)
{
//	kdDebug(2100) << k_funcinfo << endl;

                kgpginfotmp=new KTempFile();
                kgpginfotmp->setAutoDelete(true);
                TQString pgpgOutput="cp %i "+kgpginfotmp->name();
                KProcIO *p=new KProcIO();
                *p<<"gpg"<<"--no-tty"<<"--show-photos"<<"--photo-viewer"<<TQString(TQFile::encodeName(pgpgOutput));
		*p<<"--edit-key"<<displayedKeyID<<"uid"<<uid<<"showphoto";
		TQObject::connect(p, TQ_SIGNAL(readReady(KProcIO *)),this, TQ_SLOT(finishphotoreadprocess(KProcIO *)));
                TQObject::connect(p, TQ_SIGNAL(processExited(TDEProcess *)),this, TQ_SLOT(slotMainImageRead(TDEProcess *)));
                p->start(TDEProcess::NotifyOnExit,true);

}


void KgpgKeyInfo::slotMainImageRead(TDEProcess *p)
{
//	kdDebug(2100) << k_funcinfo << endl;
	p->deleteLater();
	TQPixmap pixmap;
        pixmap.load(kgpginfotmp->name());
	emit changeMainPhoto(pixmap);
        kgpginfotmp->unlink();
}


KgpgKeyInfo::~KgpgKeyInfo()
{
}

void KgpgKeyInfo::slotSetPhoto(const TQPixmap &pix)
{
//	kdDebug(2100) << k_funcinfo << endl;
	TQImage dup=pix.convertToImage();
	TQPixmap dup2;
	dup2.convertFromImage(dup.scale(prop->pLPhoto->width(),prop->pLPhoto->height(),TQImage::ScaleMin));
	prop->pLPhoto->setPixmap(dup2);
}




void KgpgKeyInfo::finishphotoreadprocess(KProcIO *p)
{
//	kdDebug(2100) << k_funcinfo << endl;
        TQString required=TQString();
        while (p->readln(required,true)!=-1)
		if (required.find("keyedit.prompt")!=-1) {
                        p->writeStdin(TQString("quit"));
			p->closeWhenDone();

                }
}


void KgpgKeyInfo::openPhoto()
{
//	kdDebug(2100) << k_funcinfo << endl;
			 TDETrader::OfferList offers = TDETrader::self()->query("image/jpeg", "Type == 'Application'");
 			KService::Ptr ptr = offers.first();
 			//KMessageBox::sorry(0,ptr->desktopEntryName());
                        KProcIO *p=new KProcIO();
                        *p<<"gpg"<<"--show-photos"<<"--photo-viewer"<<TQString(TQFile::encodeName(ptr->desktopEntryName()+" %i"))<<"--list-keys"<<displayedKeyID;
                        p->start(TDEProcess::DontCare,true);
}

void KgpgKeyInfo::slotChangeExp()
{
//	kdDebug(2100) << k_funcinfo << endl;
	chdate=new KDialogBase( this, "choose_date", true,i18n("Choose New Expiration"),KDialogBase::Ok | KDialogBase::Cancel);
	TQWidget *page = new TQWidget(chdate);
	kb= new TQCheckBox(i18n("Unlimited"),page );
	
	if (prop->tLExpiration->text()==i18n("Unlimited")) {
		kdt= new KDatePicker( page );
		kb->setChecked(true);
		kdt->setEnabled(false);
	}
	else {
		kdt= new KDatePicker(page,TDEGlobal::locale()->readDate(prop->tLExpiration->text()));
	}
	TQVBoxLayout *vbox=new TQVBoxLayout(page,3);
	vbox->addWidget(kdt);
	vbox->addWidget(kb);
	connect(kb,TQ_SIGNAL(toggled(bool)),this,TQ_SLOT(slotEnableDate(bool)));
	connect(chdate,TQ_SIGNAL(okClicked()),this,TQ_SLOT(slotChangeDate()));
	connect(kdt,TQ_SIGNAL(dateChanged(TQDate)),this,TQ_SLOT(slotCheckDate(TQDate)));
	connect(kdt,TQ_SIGNAL(dateEntered(TQDate)),this,TQ_SLOT(slotCheckDate(TQDate)));

	chdate->setMainWidget(page);
	chdate->show();
}

void KgpgKeyInfo::slotCheckDate(TQDate date)
{
//	kdDebug(2100) << k_funcinfo << endl;
//	kdDebug(2100) << "slotCheckDate" << date<<endl;
	chdate->enableButtonOK(date>=TQDate::currentDate ());
}

void KgpgKeyInfo::slotChangeDate()
{
//	kdDebug(2100) << k_funcinfo << endl;
	KgpgInterface *KeyExpirationProcess=new KgpgInterface();
//	kdDebug(2100) << "slotChangeDate" << kdt->date()<<endl;
	if (kb->isChecked()) {
		KeyExpirationProcess->KgpgKeyExpire(displayedKeyID,TQDate::currentDate(),true);
	}
	else {
		KeyExpirationProcess->KgpgKeyExpire(displayedKeyID,kdt->date(),false);
	}
	connect(KeyExpirationProcess,TQ_SIGNAL(expirationFinished(int)),this,TQ_SLOT(slotInfoExpirationChanged(int)));
}

void KgpgKeyInfo::slotEnableDate(bool isOn)
{
//	kdDebug(2100) << k_funcinfo << endl;
	if (isOn) {
		kdt->setEnabled(false);
		chdate->enableButtonOK(true);
	}
	else {
		kdt->setEnabled(true);
		//kdDebug(2100) << "slotEnableDate" << kdt->date()<<endl;
		chdate->enableButtonOK(kdt->date()>=TQDate::currentDate ());
	}
}

void KgpgKeyInfo::slotinfoimgread(TDEProcess *)
{
//	kdDebug(2100) << k_funcinfo << endl;
	TQPixmap pixmap;
        pixmap.load(kgpginfotmp->name());
	emit signalPhotoId(pixmap);
        kgpginfotmp->unlink();
}

void KgpgKeyInfo::slotChangePass()
{
//	kdDebug(2100) << k_funcinfo << endl;
	KgpgInterface *ChangeKeyPassProcess=new KgpgInterface();
	ChangeKeyPassProcess->KgpgChangePass(displayedKeyID);
	connect(ChangeKeyPassProcess,TQ_SIGNAL(passwordChanged()),this,TQ_SLOT(slotInfoPasswordChanged()));
}

void KgpgKeyInfo::slotChangeTrust(int newTrust)
{
//	kdDebug(2100) << k_funcinfo << endl;
        KgpgInterface *KeyTrustProcess=new KgpgInterface();
                KeyTrustProcess->KgpgTrustExpire(displayedKeyID,newTrust);
                connect(KeyTrustProcess,TQ_SIGNAL(trustfinished()),this,TQ_SLOT(slotInfoTrustChanged()));
}


void KgpgKeyInfo::slotInfoPasswordChanged()
{
//	kdDebug(2100) << k_funcinfo << endl;
	KPassivePopup::message(i18n("Passphrase for the key was changed"),TQString(),TDEGlobal::iconLoader()->loadIcon("kgpg",TDEIcon::Desktop),this);
}

void KgpgKeyInfo::slotInfoTrustChanged()
{
	keyWasChanged=true;
	loadKey(displayedKeyID);
	//KPassivePopup::message(i18n("Owner trust of the key was changed"),TQString(),TDEGlobal::iconLoader()->loadIcon("kgpg",TDEIcon::Desktop),this,0,600);
}

void KgpgKeyInfo::slotInfoExpirationChanged(int res)
{
//	kdDebug(2100) << k_funcinfo << endl;
	TQString infoMessage,infoText;
	if (res==3) {
		keyWasChanged=true;
		if (kb->isChecked()) {
			prop->tLExpiration->setText(i18n("Unlimited"));
		}
		else {
			prop->tLExpiration->setText(TDEGlobal::locale()->formatDate(kdt->date()));
		}
	}
	if (res==2) {
		infoMessage=i18n("Could not change expiration");
		infoText=i18n("Bad passphrase");
		KPassivePopup::message(infoMessage,infoText,TDEGlobal::iconLoader()->loadIcon("kgpg",TDEIcon::Desktop),this);
	}
}


void KgpgKeyInfo::slotPreOk()
{
//	kdDebug(2100) << k_funcinfo << endl;
	if (keyWasChanged) {
		emit keyNeedsRefresh();
	}
	accept();
}

#include "keyinfowidget.moc"
