/***************************************************************************
                          popuppublic.cpp  -  description
                             -------------------
    begin                : Sat Jun 29 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 option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

////////////////////////////////////////////////////////   code  for choosing a public key from a list for encryption
#include <tqlayout.h>
#include <tqpushbutton.h>
#include <tqptrlist.h>
#include <tqwhatsthis.h>
#include <tqpainter.h>
#include <tqiconset.h>
#include <tqbuttongroup.h>
#include <tqcheckbox.h>
#include <tqhbuttongroup.h>
#include <tqtoolbutton.h>
#include <tqtextcodec.h>

#include <tdelistview.h>
#include <kprocess.h>
#include <kprocio.h>
#include <tdelocale.h>
#include <tdeaccel.h>
#include <tdelistviewsearchline.h>
#include <kactivelabel.h>
#include <tdeaction.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <klineedit.h>


#include "popuppublic.h"
#include "kgpgsettings.h"
#include "kgpgview.h"
#include "kgpg.h"

/////////////////   tdelistviewitem special

class UpdateViewItem2 : public TDEListViewItem
{
public:
        UpdateViewItem2(TQListView *parent, TQString name,TQString mail,TQString id,bool isDefault);
        virtual void paintCell(TQPainter *p, const TQColorGroup &cg,int col, int width, int align);
	virtual TQString key(int c,bool ) const;
	bool def;
};

UpdateViewItem2::UpdateViewItem2(TQListView *parent, TQString name,TQString mail,TQString id,bool isDefault)
                : TDEListViewItem(parent)
{
def=isDefault;
        setText(0,name);
	setText(1,mail);
	setText(2,id);
}


void UpdateViewItem2::paintCell(TQPainter *p, const TQColorGroup &cg,int column, int width, int alignment)
{
        if ((def) && (column<2)) {
                TQFont font(p->font());
                font.setBold(true);
                p->setFont(font);
        }
        TDEListViewItem::paintCell(p, cg, column, width, alignment);
}

TQString UpdateViewItem2 :: key(int c,bool ) const
{
        return text(c).lower();
}

///////////////  main view

popupPublic::popupPublic(TQWidget *parent, const char *name,TQString sfile,bool filemode,TDEShortcut goDefaultKey):
KDialogBase( Plain, i18n("Select Public Key"), Details | Ok | Cancel, Ok, parent, name,true)
{

	TQWidget *page = plainPage();
	TQVBoxLayout *vbox=new TQVBoxLayout(page,0,spacingHint());
	vbox->setAutoAdd(true);

	setButtonText(KDialogBase::Details,i18n("Options"));

        if (KGpgSettings::allowCustomEncryptionOptions())
                customOptions=KGpgSettings::customEncryptionOptions();

        TDEIconLoader *loader = TDEGlobal::iconLoader();

        keyPair=loader->loadIcon("kgpg_key2",TDEIcon::Small,20);
        keySingle=loader->loadIcon("kgpg_key1",TDEIcon::Small,20);
	keyGroup=loader->loadIcon("kgpg_key3",TDEIcon::Small,20);

        if (filemode) setCaption(i18n("Select Public Key for %1").arg(sfile));
        fmode=filemode;

	TQHButtonGroup *hBar=new TQHButtonGroup(page);
	//hBar->setFrameStyle(TQFrame::NoFrame);
	hBar->setMargin(0);

	TQToolButton *clearSearch = new TQToolButton(hBar);
	clearSearch->setTextLabel(i18n("Clear Search"), true);
	clearSearch->setIconSet(SmallIconSet(TQApplication::reverseLayout() ? "clear_left"
                                            : "locationbar_erase"));
	(void) new TQLabel(i18n("Search: "),hBar);
	TDEListViewSearchLine* listViewSearch = new TDEListViewSearchLine(hBar);
	connect(clearSearch, TQ_SIGNAL(pressed()), listViewSearch, TQ_SLOT(clear()));

        keysList = new TDEListView( page );
	 keysList->addColumn(i18n("Name"));
	 keysList->addColumn(i18n("Email"));
	 keysList->addColumn(i18n("ID"));

	 listViewSearch->setListView(keysList);

        keysList->setRootIsDecorated(false);
        page->setMinimumSize(540,200);
        keysList->setShowSortIndicator(true);
        keysList->setFullWidth(true);
	keysList->setAllColumnsShowFocus(true);
        keysList->setSelectionModeExt(TDEListView::Extended);
	keysList->setColumnWidthMode(0,TQListView::Manual);
	keysList->setColumnWidthMode(1,TQListView::Manual);
	keysList->setColumnWidth(0,210);
	keysList->setColumnWidth(1,210);

        boutonboxoptions=new TQButtonGroup(5,TQt::Vertical ,page,0);

	TDEActionCollection *actcol=new TDEActionCollection(this);
	(void) new TDEAction(i18n("&Go to Default Key"),goDefaultKey, this, TQ_SLOT(slotGotoDefaultKey()),actcol,"go_default_key");


        CBarmor=new TQCheckBox(i18n("ASCII armored encryption"),boutonboxoptions);
        CBuntrusted=new TQCheckBox(i18n("Allow encryption with untrusted keys"),boutonboxoptions);
        CBhideid=new TQCheckBox(i18n("Hide user id"),boutonboxoptions);
        setDetailsWidget(boutonboxoptions);
        TQWhatsThis::add
                (keysList,i18n("<b>Public keys list</b>: select the key that will be used for encryption."));
        TQWhatsThis::add
                (CBarmor,i18n("<b>ASCII encryption</b>: makes it possible to open the encrypted file/message in a text editor"));
        TQWhatsThis::add
                (CBhideid,i18n("<b>Hide user ID</b>: Do not put the keyid into encrypted packets. This option hides the receiver "
                                "of the message and is a countermeasure against traffic analysis. It may slow down the decryption process because "
                                "all available secret keys are tried."));
        TQWhatsThis::add
                (CBuntrusted,i18n("<b>Allow encryption with untrusted keys</b>: when you import a public key, it is usually "
                                  "marked as untrusted and you cannot use it unless you sign it in order to make it 'trusted'. Checking this "
                                  "box enables you to use any key, even if it has not be signed."));

        if (filemode) {
		TQWidget *parentBox=new TQWidget(boutonboxoptions);
		TQHBoxLayout *shredBox=new TQHBoxLayout(parentBox,0);
		//shredBox->setFrameStyle(TQFrame::NoFrame);
		//shredBox->setMargin(0);
	       CBshred=new TQCheckBox(i18n("Shred source file"),parentBox);
                TQWhatsThis::add
                        (CBshred,i18n("<b>Shred source file</b>: permanently remove source file. No recovery will be possible"));

		TQString shredWhatsThis = i18n( "<qt><b>Shred source file:</b><br /><p>Checking this option will shred (overwrite several times before erasing) the files you have encrypted. This way, it is almost impossible that the source file is recovered.</p><p><b>But you must be aware that this is not secure</b> on all file systems, and that parts of the file may have been saved in a temporary file or in the spooler of your printer if you previously opened it in an editor or tried to print it. Only works on files (not on folders).</p></qt>");
		  KActiveLabel *warn= new KActiveLabel( i18n("<a href=\"whatsthis:%1\">Read this before using shredding</a>").arg(shredWhatsThis),parentBox );
		  shredBox->addWidget(CBshred);
		  shredBox->addWidget(warn);
        }

	        CBsymmetric=new TQCheckBox(i18n("Symmetrical encryption"),boutonboxoptions);
                TQWhatsThis::add
                        (CBsymmetric,i18n("<b>Symmetrical encryption</b>: encryption does not use keys. You just need to give a password "
                                          "to encrypt/decrypt the file"));
                TQObject::connect(CBsymmetric,TQ_SIGNAL(toggled(bool)),this,TQ_SLOT(isSymetric(bool)));

	CBarmor->setChecked( KGpgSettings::asciiArmor() );
	CBuntrusted->setChecked( KGpgSettings::allowUntrustedKeys() );
	CBhideid->setChecked( KGpgSettings::hideUserID() );
	if (filemode) CBshred->setChecked( KGpgSettings::shredSource() );

        if (KGpgSettings::allowCustomEncryptionOptions()) {
                TQHButtonGroup *bGroup = new TQHButtonGroup(page);
                //bGroup->setFrameStyle(TQFrame::NoFrame);
                (void) new TQLabel(i18n("Custom option:"),bGroup);
                KLineEdit *optiontxt=new KLineEdit(bGroup);
                optiontxt->setText(customOptions);
                TQWhatsThis::add
                        (optiontxt,i18n("<b>Custom option</b>: for experienced users only, allows you to enter a gpg command line option, like: '--armor'"));
                TQObject::connect(optiontxt,TQ_SIGNAL(textChanged ( const TQString & )),this,TQ_SLOT(customOpts(const TQString & )));
        }
        TQObject::connect(keysList,TQ_SIGNAL(doubleClicked(TQListViewItem *,const TQPoint &,int)),this,TQ_SLOT(slotOk()));
//	TQObject::connect(this,TQ_SIGNAL(okClicked()),this,TQ_SLOT(crypte()));
        TQObject::connect(CBuntrusted,TQ_SIGNAL(toggled(bool)),this,TQ_SLOT(refresh(bool)));

        char line[200]="\0";
        FILE *fp2;
        seclist=TQString();

        fp2 = popen("gpg --no-secmem-warning --no-tty --with-colon --list-secret-keys ", "r");
        while ( fgets( line, sizeof(line), fp2))
        {
            TQString readLine=TQString::fromUtf8(line);
            if (readLine.startsWith("sec")) seclist+=", 0x"+readLine.section(":",4,4).right(8);
        }
        pclose(fp2);

        trusted=CBuntrusted->isChecked();

        refreshkeys();
	setMinimumSize(550,200);
	updateGeometry();
	keysList->setFocus();
	show();
}

popupPublic::~popupPublic()
{}


void popupPublic::slotAccept()
{
accept();
}

void popupPublic::enable()
{
        TQListViewItem *current = keysList->firstChild();
        if (current==NULL)
                return;
        current->setVisible(true);
        while ( current->nextSibling() ) {
                current = current->nextSibling();
                current->setVisible(true);
        }
	keysList->ensureItemVisible(keysList->currentItem());
}

void popupPublic::sort()
{
        bool reselect=false;
        TQListViewItem *current = keysList->firstChild();
        if (current==NULL)
                return;

	if ((untrustedList.find(current->text(2))!=untrustedList.end()) && (!current->text(2).isEmpty())){
                if (current->isSelected()) {
                        current->setSelected(false);
                        reselect=true;
                }
                current->setVisible(false);
		}

        while ( current->nextSibling() ) {
                current = current->nextSibling();
                if ((untrustedList.find(current->text(2))!=untrustedList.end()) && (!current->text(2).isEmpty())) {
                if (current->isSelected()) {
                        current->setSelected(false);
                        reselect=true;
                }
                current->setVisible(false);
		}
        }

	if (reselect || !keysList->currentItem()->isVisible()) {
                TQListViewItem *firstvisible;
                firstvisible=keysList->firstChild();
                while (firstvisible->isVisible()!=true) {
                        firstvisible=firstvisible->nextSibling();
                        if (firstvisible==NULL)
                                return;
                }
                keysList->setSelected(firstvisible,true);
		keysList->setCurrentItem(firstvisible);
		keysList->ensureItemVisible(firstvisible);
        }
}

void popupPublic::isSymetric(bool state)
{
        keysList->setEnabled(!state);
        CBuntrusted->setEnabled(!state);
        CBhideid->setEnabled(!state);
}


void popupPublic::customOpts(const TQString &str)
{
        customOptions=str;
}

void popupPublic::slotGotoDefaultKey()
{
    TQListViewItem *myDefaulKey = keysList->findItem(KGpgSettings::defaultKey(),2);
    keysList->clearSelection();
    keysList->setCurrentItem(myDefaulKey);
    keysList->setSelected(myDefaulKey,true);
    keysList->ensureItemVisible(myDefaulKey);
}

void popupPublic::refresh(bool state)
{
        if (state)
                enable();
        else
                sort();
}

void popupPublic::refreshkeys()
{
	keysList->clear();
	currentKey = TQString();
	hashMap.clear();
	TQStringList groups= TQStringList::split(",", KGpgSettings::groups());
	if (!groups.isEmpty())
	{
		for ( TQStringList::Iterator it = groups.begin(); it != groups.end(); ++it )
		{
			if (!TQString(*it).isEmpty())
			{
				UpdateViewItem2 *item=new UpdateViewItem2(keysList,TQString(*it),TQString(),TQString(),false);
				item->setPixmap(0,keyGroup);
			}
		}
	}
        KProcIO *encid=new KProcIO(TQTextCodec::codecForLocale());
        *encid << "gpg"<<"--no-secmem-warning"<<"--no-tty"<<"--with-colon"<<"--list-keys";
        /////////  when process ends, update dialog infos
        TQObject::connect(encid, TQ_SIGNAL(processExited(TDEProcess *)),this, TQ_SLOT(slotpreselect()));
        TQObject::connect(encid, TQ_SIGNAL(readReady(KProcIO *)),this, TQ_SLOT(slotprocread(KProcIO *)));
        encid->start(TDEProcess::NotifyOnExit,true);
}

void popupPublic::slotpreselect()
{

    TQString defaultKey = KGpgSettings::defaultKey().right(8);

    // process the output to update dialog infos
    TQMap<TQString,TQStringList>::Iterator ite;
    for (ite = hashMap.begin(); ite != hashMap.end(); ite++) {
        TQStringList::Iterator it;
        TQString fullname,keyname,keymail,val,id;
        bool dead;
        for (it = ite.data().begin(); it != ite.data().end(); it++) {
            TQString line =  (*it);
            kdDebug(2100) << k_funcinfo << line << endl;

            if (line.startsWith("pub")) {
                TQStringList keyString=TQStringList::split(":",line,true);
                dead=false;
                const TQString trust=keyString[1];
                val=keyString[6];
                id=TQString("0x"+keyString[4].right(8));
                if (val.isEmpty()) {
                    val=i18n("Unlimited");
                }
// unused       TQString tr;
                switch( trust[0] ) {
                    case 'o':   // unknown
                        untrustedList<<id;  // untrustedList used in sort
                        break;
                    case 'i':   // invalid
                    case 'd':   // disabled
                    case 'r':   // revoked
                    case 'e':   // expired
                        dead=true;
                        break;
                    case 'q':   // undefined
                    case 'n':   // none
                    case 'm':   // marginal
                        untrustedList<<id;
                        break;
                    case 'f':   // full
                    case 'u':   // ultimate
                        break;
                    default:
                        untrustedList<<id;
                        break;
                }
                if (keyString[11].find('D')!=-1) {  // disabled
                    dead=true;
                }
                fullname=keyString[9];
            }

            if ( line.startsWith("uid") && fullname.isEmpty() ) {
                fullname = line.section(':',9,9);
            }
        }

        if (fullname.find("<")!=-1) {
            keymail=fullname.section('<',-1,-1);
            keymail.truncate(keymail.length()-1);
            keyname=fullname.section('<',0,0);
            //if (keyname.find("(")!=-1) {
            //  keyname=keyname.section('(',0,0);
            //}
        }
        else {
            keymail=TQString();
            keyname=fullname;//.section('(',0,0);
        }
        if ((!dead) && (!fullname.isEmpty())) {
            bool isDefaultKey=false;
            if (id.right(8)==defaultKey) {
                isDefaultKey=true;
            }
            UpdateViewItem2 *item=new UpdateViewItem2(keysList,keyname,keymail,id,isDefaultKey);
            //TDEListViewItem *sub= new TDEListViewItem(item,i18n("ID: %1, trust: %2, validity: %3").arg(id).arg(tr).arg(val));
            //sub->setSelectable(false);
            if (seclist.find(fullname,0,false)!=-1) {
                item->setPixmap(0,keyPair);
            }
            else {
                item->setPixmap(0,keySingle);
            }
        }
    }
    //
    TQListViewItem *it=NULL;
    if (!keysList->firstChild()) return;
            if (fmode) it=keysList->findItem(KGpgSettings::defaultKey(),2);
    if (!trusted)
                  sort();
    if (fmode)
    {
        keysList->clearSelection();
        keysList->setSelected(it,true);
        keysList->setCurrentItem(it);
        keysList->ensureItemVisible(it);
    }
    emit keyListFilled();
}

void popupPublic::slotSetVisible()
{
	keysList->ensureItemVisible(keysList->currentItem());
}

void popupPublic::slotprocread(KProcIO *p)
{
//  collect all data (output starts with pub line followed by related)
//	kdDebug(2100) << k_funcinfo << endl;
	TQString tst;

	while (p->readln(tst)!=-1) {
		if ( tst.startsWith("pub")  ) {
			currentKey = tst.section(':',4,4);
			TQStringList lst; lst << tst;
			hashMap.insert(currentKey,tst);
		}
		else {
			hashMap.find(currentKey).data().append(tst);
		}
	}
}


void popupPublic::slotOk()
{
        //////   emit selected data
kdDebug(2100)<<"Ok pressed"<<endl;
        TQStringList selectedKeys;
	TQString userid;
        TQPtrList<TQListViewItem> list=keysList->selectedItems();

        for ( uint i = 0; i < list.count(); ++i )
	  if ( list.at(i) && list.at(i)->isVisible()) {
	  		if (!list.at(i)->text(2).isEmpty()) selectedKeys<<list.at(i)->text(2);
			else selectedKeys<<list.at(i)->text(0);
                }
        if (selectedKeys.isEmpty() && !CBsymmetric->isChecked())
                return;
	if (CBsymmetric->isChecked()) selectedKeys=NULL;
//	kdDebug(2100)<<"Selected Key:"<<selectedKeys<<endl;
        TQStringList returnOptions;

        if (CBuntrusted->isChecked())
                returnOptions<<"--always-trust";
        if (CBarmor->isChecked())
                returnOptions<<"--armor";
        if (CBhideid->isChecked())
                returnOptions<<"--throw-keyid";
        if ((KGpgSettings::allowCustomEncryptionOptions()) && (!customOptions.stripWhiteSpace().isEmpty()))
                returnOptions.operator+ (TQStringList::split(TQString(" "),customOptions.simplifyWhiteSpace()));
	//hide();
        if (fmode)
                emit selectedKey(selectedKeys,returnOptions,CBshred->isChecked(),CBsymmetric->isChecked());
        else
                emit selectedKey(selectedKeys,returnOptions,false,CBsymmetric->isChecked());
        accept();
}

#include "popuppublic.moc"
