diff --git a/AppConfig.cpp b/AppConfig.cpp index fcaec10..45a3efa 100644 --- a/AppConfig.cpp +++ b/AppConfig.cpp @@ -38,6 +38,7 @@ mutex gs_fileWriteMutex; "canEditUidValidity" : true, "canEditExpiryTime" : true, "canCreateKeys" : true, + "canAddRevokeUids" : true, "privKeyIds" : [ "fullKeyId1", "fullKeyId2" @@ -172,6 +173,17 @@ bool AppConfig::CanCreateKeys() const return cnObject.get("canCreateKeys"); } +bool AppConfig::CanAddRevokeUid() const +{ + const WString commonName = GetSubjectDnAttribute(WSslCertificate::DnAttributeName::CommonName); + if (!m_SubjectCNObject.contains(commonName.toUTF8())) + return false; + Json::Object cnObject = m_SubjectCNObject.get(commonName.toUTF8()); + if (!cnObject.contains("canAddRevokeUids")) + return false; + return cnObject.get("canAddRevokeUids"); +} + bool AppConfig::UpdateSecretKeyOwnership(const WString& fpr, bool own) { const WString commonName = GetSubjectDnAttribute(WSslCertificate::DnAttributeName::CommonName); diff --git a/AppConfig.h b/AppConfig.h index 36e5990..4ffaf0d 100644 --- a/AppConfig.h +++ b/AppConfig.h @@ -67,6 +67,12 @@ public: * @return */ bool CanCreateKeys() const; + /** + * Allows to add or revoke a user identity to a key. It deos not mean + * deleting an identity. + * @return + */ + bool CanAddRevokeUid() const; /** * Disown the user of the secret key, or grants him ownership. It just adds * or remove fpr from the private key array, without any further check. The diff --git a/K7Main.cpp b/K7Main.cpp index 61f4455..53394cf 100644 --- a/K7Main.cpp +++ b/K7Main.cpp @@ -314,7 +314,7 @@ void K7Main::OnKeyAnchorClicked(WAnchor * source) DisplaySubKeys(id, secret); if (m_config->CanDelete()) // m_btnDelete is NULL otherwise m_btnDelete->setHidden(!m_keyringIO->CanKeyBeDeleted(id)); - + m_keyringIO->PrepareExport(id, secret); } @@ -340,20 +340,28 @@ void K7Main::DisplayUids(const WString& fullKeyID, bool secret) rootNode->setChildCountPolicy(ChildCountPolicy::Enabled); m_ttbUids->setTreeRoot(unique_ptr (rootNode), TR("UIDs")); rootNode->expand(); - vector privateKeys = m_config->PrivateKeyIds(); + vector ourKeys = m_config->PrivateKeyIds(); + bool canAddRevokeUid = m_config->CanAddRevokeUid() + && Tools::KeyHasSecret(k.primaryFingerprint()) + && Tools::IsOurKey(k.primaryFingerprint(), ourKeys); for (uint i = 0; i < k.numUserIDs(); i++) { UserID uid = k.userID(i); WTreeTableNode * uidNode = new WTreeTableNode(uid.name()); uidNode->setToolTip(Tools::GetUidStatus(uid)); - TreeTableNodeText * ttntUidEmail = new TreeTableNodeText(uid.email(), uidNode, 1); - uidNode->setColumnWidget(1, unique_ptr (ttntUidEmail)); + WText * lblUidEmail = new WText(uid.email()); + if (canAddRevokeUid) + { + lblUidEmail->setToolTip(TR("TTTDoubleCLick")); + lblUidEmail->doubleClicked().connect(std::bind(&KeyEdit::OnUidEmailClicked, m_keyEdit, uidNode, WString(k.primaryFingerprint()))); + } + uidNode->setColumnWidget(1, unique_ptr (lblUidEmail)); // Show key certify popup on double click WText * lblUidValidity = new WText(UidValidities[uid.validity()]); if (m_config->CanEditUidValidity()) { lblUidValidity->setToolTip(TR("TTTDoubleCLick")); - lblUidValidity->doubleClicked().connect(std::bind(&KeyEdit::OnUidValidityClicked, m_keyEdit, uidNode, privateKeys, WString(k.primaryFingerprint()))); + lblUidValidity->doubleClicked().connect(std::bind(&KeyEdit::OnUidValidityClicked, m_keyEdit, uidNode, ourKeys, WString(k.primaryFingerprint()))); } uidNode->setColumnWidget(2, unique_ptr (lblUidValidity)); TreeTableNodeText * ttntUidComment = new TreeTableNodeText(uid.comment(), uidNode, 3); diff --git a/KeyEdit.cpp b/KeyEdit.cpp index e35ac27..acfe565 100644 --- a/KeyEdit.cpp +++ b/KeyEdit.cpp @@ -22,6 +22,7 @@ KeyEdit::KeyEdit(K7Main * owner) m_owner = owner; m_popupUid = NULL; m_popupExpiryTime = NULL; + m_popupAddUid = NULL; m_targetUidValidityKeyFpr = WString::Empty; m_expiryEditedKeyFpr = WString::Empty; } @@ -200,3 +201,60 @@ void KeyEdit::SetExpiryTime() m_owner->DisplaySubKeys(m_expiryEditedKeyFpr, true); } +void KeyEdit::OnUidEmailClicked(WTreeTableNode* uidNode, const WString& keyFpr) +{ + WText * lblEmail = static_cast (uidNode->columnWidget(1)); + if (keyFpr != m_addUidKeyFpr) + { + delete m_popupAddUid; + m_popupAddUid = new PopupAddUid(lblEmail, m_owner->m_tmwMessage); + m_popupAddUid->Create(); + m_addUidKeyFpr = keyFpr; + m_popupAddUid->GetApplyButton()->clicked().connect(this, &KeyEdit::AddOrRevokeUid); + } + WText * lblName = uidNode->label(); + WText * lblComment = static_cast (uidNode->columnWidget(3)); + m_popupAddUid->SetNodeIdentity(lblName->text(), lblEmail->text(), + lblComment->text()); + m_popupAddUid->show(); +} + +void KeyEdit::AddOrRevokeUid() +{ + if (!m_popupAddUid->Validate()) + { + m_owner->m_tmwMessage->SetText(TR("InvalidInput")); + return; + } + const WString name = m_popupAddUid->GetName(); + const WString email = m_popupAddUid->GetEmail(); + const WString comment = m_popupAddUid->GetComment(); + const WString passphrase = m_popupAddUid->GetPassphrase(); + + Error e; + GpgMEWorker gpgw; + if (m_popupAddUid->WhatToDo() == PopupAddUid::What::Revoke) + { + e = gpgw.RevokeUserID(m_addUidKeyFpr.toUTF8().c_str(), + passphrase.toUTF8(), + name.toUTF8(), email.toUTF8(), comment.toUTF8()); + } + else + { + e = gpgw.AddUserID(m_addUidKeyFpr.toUTF8().c_str(), + passphrase.toUTF8(), + name.toUTF8(), email.toUTF8(), comment.toUTF8()); + } + m_popupAddUid->hide(); + if (e.code() != 0) + { + m_popupAddUid->ShowPassphrase(true); + m_owner->m_tmwMessage->SetText(e.asString()); + } + else + { + m_popupAddUid->ShowPassphrase(false); + } + // Key certifications are not listed on this refresh ! + m_owner->DisplayUids(m_addUidKeyFpr, true); +} diff --git a/KeyEdit.h b/KeyEdit.h index 93e81d3..62744b2 100644 --- a/KeyEdit.h +++ b/KeyEdit.h @@ -15,17 +15,19 @@ #include #include "PopupCertifyUserId.h" #include "PopupExpiryTime.h" +#include "PopupAddUid.h" using namespace Wt; class K7Main; /** - * Some key editing functionalities are or will be implemented here. For now, - * only owner trust level and key certification are implemented. - * Is a pseudo-extension of K7Main. Both classes are friends to each other, and + * Some key editing functionalities are or will be implemented here. + * Owner trust level, key certification adding and revoking user identities are + * implemented. + * \n Is a pseudo-extension of K7Main. Both classes are friends to each other, and * everything is private here. - * Does not manage keyring. + * \n Does not manage keyring. */ class KeyEdit : public WObject { @@ -43,6 +45,9 @@ private: PopupExpiryTime * m_popupExpiryTime; WString m_expiryEditedKeyFpr; + PopupAddUid * m_popupAddUid; + WString m_addUidKeyFpr; + /** * Unknown is common. * \n If keyHasSecret is true, show only Ultimate level. @@ -54,6 +59,7 @@ private: void FillOwnerTrustCombo(WComboBox * cmb, bool keyHasSecret); void CertifyKey(); void SetExpiryTime(); + void AddOrRevokeUid(); /** * Shows a combobox with all trust levels @@ -81,6 +87,8 @@ private: */ void OnExpiryClicked(WTreeTableNode * subkeyNode, const WString& keyFpr); + void OnUidEmailClicked(WTreeTableNode * uidNode, const WString& keyFpr); + }; #endif /* KEYEDIT_H */ diff --git a/PopupAddUid.cpp b/PopupAddUid.cpp new file mode 100644 index 0000000..a2633a4 --- /dev/null +++ b/PopupAddUid.cpp @@ -0,0 +1,161 @@ +/* + * File: PopupAddUid.cpp + * Author: SET - nmset@yandex.com + * License : GPL v2 + * Copyright SET - © 2019 + * + * Created on November 16, 2020, 3:59 PM + */ + +#include "PopupAddUid.h" +#include "global.h" +#include +#include +#include +#include +#include + +PopupAddUid::PopupAddUid(WWidget * anchorWidget, + TransientMessageWidget * txtMessage, + const WLength& width) +: WPopupWidget(cpp14::make_unique()) +{ + m_tmwMessage = txtMessage; + m_cwMain = NULL; + m_leName = NULL; + m_leEmail = NULL; + m_leComment = NULL; + m_lePassphrase = NULL; + m_btnApply = NULL; + + m_nodeName = WString::Empty; + m_nodeEmail = WString::Empty; + m_nodeComment = WString::Empty; + + setTransient(true); + setAnchorWidget(anchorWidget); + setWidth(width); +} + +PopupAddUid::~PopupAddUid() +{ +} + +void PopupAddUid::Create() +{ + m_cwMain = static_cast (implementation()); + m_cwMain->setStyleClass("popup"); + WVBoxLayout * vblMain = new WVBoxLayout(); + m_cwMain->setLayout(unique_ptr (vblMain)); + WGridLayout * grlMain = new WGridLayout(); + grlMain->setColumnStretch(1, 1); + vblMain->addLayout(unique_ptr (grlMain)); + + WText * lblName = new WText(TR("Name")); + grlMain->addWidget(unique_ptr (lblName), 0, 0); + m_leName = new WLineEdit(); + grlMain->addWidget(unique_ptr (m_leName), 0, 1); + WText * lblEmail = new WText(TR("Email")); + grlMain->addWidget(unique_ptr (lblEmail), 1, 0); + m_leEmail = new WLineEdit(); + grlMain->addWidget(unique_ptr (m_leEmail), 1, 1); + WText * lblComment = new WText(TR("Comment")); + grlMain->addWidget(unique_ptr (lblComment), 2, 0); + m_leComment = new WLineEdit(); + grlMain->addWidget(unique_ptr (m_leComment), 2, 1); + m_lblPassphrase = new WText(TR("Passphrase")); + grlMain->addWidget(unique_ptr (m_lblPassphrase), 3, 0); + m_lePassphrase = new WLineEdit(); + m_lePassphrase->setEchoMode(EchoMode::Password); + grlMain->addWidget(unique_ptr (m_lePassphrase), 3, 1); + + WHBoxLayout * hblWhat = new WHBoxLayout(); + WRadioButton * rbAdd = new WRadioButton(WString(TR("AddUid"))); + hblWhat->addWidget(unique_ptr (rbAdd)); + WRadioButton * rbRevoke = new WRadioButton(WString(TR("RevokeUid"))); + hblWhat->addWidget(unique_ptr (rbRevoke)); + m_bgWhat = make_shared(); + m_bgWhat->addButton(rbAdd, What::Add); + m_bgWhat->addButton(rbRevoke, What::Revoke); + m_bgWhat->setCheckedButton(rbAdd); + vblMain->addLayout(unique_ptr (hblWhat)); + + m_cbConfirm = new WCheckBox(TR("Confirm")); + vblMain->addWidget(unique_ptr (m_cbConfirm)); + + WHBoxLayout * hblButtons = new WHBoxLayout(); + WPushButton * btnClose = new WPushButton(TR("Close")); + hblButtons->addWidget(unique_ptr (btnClose)); + m_btnApply = new WPushButton(TR("Apply")); + hblButtons->addWidget(unique_ptr (m_btnApply)); + vblMain->addLayout(unique_ptr (hblButtons)); + + m_bgWhat->checkedChanged().connect(this, &PopupAddUid::OnButtonGroupWhat); + btnClose->clicked().connect(this, &WPopupWidget::hide); + this->hidden().connect(m_cbConfirm, &WCheckBox::setUnChecked); + + // From WRegExpValidator docs + shared_ptr validator + = make_shared + ("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}"); + validator->setMandatory(true); + m_leEmail->setValidator(validator); +} + +void PopupAddUid::ShowPassphrase(bool show) +{ + // See comments in PopupCertifyUserId::ShowPassphrase + if (show) + { + m_lblPassphrase->show(); + m_lePassphrase->show(); + m_lePassphrase->setText(WString::Empty); + } + else + { + m_lblPassphrase->hide(); + m_lePassphrase->hide(); + } +} + +void PopupAddUid::OnButtonGroupWhat(WRadioButton * btn) +{ + m_leName->setDisabled(m_bgWhat->checkedId() == What::Revoke); + m_leEmail->setDisabled(m_bgWhat->checkedId() == What::Revoke); + m_leComment->setDisabled(m_bgWhat->checkedId() == What::Revoke); + + m_leName->setText(m_nodeName); + if (m_bgWhat->checkedId() == What::Revoke) + { + m_leEmail->setText(m_nodeEmail); + m_leComment->setText(m_nodeComment); + } + else + { + m_leEmail->setText(WString::Empty); + m_leComment->setText(WString::Empty); + } + m_cbConfirm->setUnChecked(); +} + +void PopupAddUid::SetNodeIdentity(const WString& name, const WString& email, + const WString& comment) +{ + m_nodeName = name; + m_nodeEmail = email; + m_nodeComment = comment; + OnButtonGroupWhat(m_bgWhat->checkedButton()); +} + +bool PopupAddUid::Validate() const +{ + /* + * It's pointless to check if a passphrase is provided as the loopback + * passphrase provider won't ever be called as long as gpg-agent holds a + * valid passphrase from a previous transaction. + */ + if (m_bgWhat->checkedId() == What::Revoke) + return (m_cbConfirm->isChecked()); + return (m_cbConfirm->isChecked() + && (m_leEmail->validate() == ValidationState::Valid)); +} diff --git a/PopupAddUid.h b/PopupAddUid.h new file mode 100644 index 0000000..588273c --- /dev/null +++ b/PopupAddUid.h @@ -0,0 +1,124 @@ +/* + * File: PopupAddUid.h + * Author: SET - nmset@yandex.com + * License : GPL v2 + * Copyright SET - © 2019 + * + * Created on November 16, 2020, 3:59 PM + */ + +#ifndef POPUPADDUID_H +#define POPUPADDUID_H + +#include +#include +#include +#include +#include +#include +#include +#include "TransientMessageWidget.h" + +using namespace Wt; + +class PopupAddUid : public WPopupWidget +{ +public: + + enum What + { + Revoke = 0, Add + }; + PopupAddUid(WWidget * anchorWidget, TransientMessageWidget * txtMessage, + const WLength& width = 400); + virtual ~PopupAddUid(); + void Create(); + + const WString GetName() const + { + return m_leName->text(); + } + + /** + * GPGME enforces a rightly formatted email address here. + * @return + */ + const WString GetEmail() const + { + return m_leEmail->text(); + } + + const WString GetComment() const + { + return m_leComment->text(); + } + /** + * Add or revoke uid. + * @return + */ + const What WhatToDo() const + { + return (What) m_bgWhat->checkedId(); + } + /** + * Controls visibility of passphrase widgets. + * \n Need not be always visible as the passphrase is cached by gpg-agent. + * \n During that caching period, a wrong input passphrase will not be looked + * for by GPG engine, and may be confusing. + * @param show + */ + void ShowPassphrase(bool show = true); + + /** + * Used to forward the passphrase to the loopback passphrase provider. + * @return + */ + const string GetPassphrase() + { + return m_lePassphrase->text().toUTF8(); + } + + /** + * Caller binds its function here. + * @return + */ + WPushButton* GetApplyButton() + { + return m_btnApply; + } + /** + * Identity values from the tree table node. Should not be modified here + * once assigned. Only KeyEdit::OnUidEmailClicked should do that. + * @param name + * @param email + * @param comment + */ + void SetNodeIdentity(const WString& name, const WString& email, + const WString& comment); + /** + * Confirmation is mandatory. + * \n If adding a uid, a rightly formatted email address is required. + * @return + */ + bool Validate() const; + +private: + TransientMessageWidget * m_tmwMessage; + WContainerWidget * m_cwMain; + WLineEdit * m_leName; + WLineEdit * m_leEmail; + WLineEdit * m_leComment; + WText * m_lblPassphrase; + WLineEdit * m_lePassphrase; + shared_ptr m_bgWhat; + WCheckBox * m_cbConfirm; + WPushButton * m_btnApply; + + // Identity values from the tree table node. + WString m_nodeName, m_nodeEmail, m_nodeComment; + + void OnButtonGroupWhat(WRadioButton * btn); +}; + +#endif /* POPUPADDUID_H */ + diff --git a/README.md b/README.md index 8d40b9b..2b835df 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,8 @@ It is developed in C++ as a NetBeans project on the [WebToolkit](https://www.webtoolkit.eu/)(Wt) libraries. -It allows to view, import, export, create, delete keys. Certification trust level, secret key expiry date can also be changed, and user identities can be certified. +It allows to view, import, export, create, delete keys. Certification trust level, secret key expiry date can also be changed, and user identities can be added, revoked and certified. Export concerns public keys only; secret keys cannot be technically exported on a web server. -Adding user identities is not (yet) implemented. Available keys can then be used by other Wt applications, or web applications based on other libraries, to encrypt and sign data. As such, it suits my personal needs. diff --git a/WTAPPROOT/K7/K7.xml b/WTAPPROOT/K7/K7.xml index a71232c..7dfca67 100644 --- a/WTAPPROOT/K7/K7.xml +++ b/WTAPPROOT/K7/K7.xml @@ -132,4 +132,9 @@ Export Exporting secret keys is technically impossible + + Add an identity + Revoke identity + Input is invalid + \ No newline at end of file diff --git a/WTAPPROOT/K7/K7_fr.xml b/WTAPPROOT/K7/K7_fr.xml index 6eaa41f..04b6746 100644 --- a/WTAPPROOT/K7/K7_fr.xml +++ b/WTAPPROOT/K7/K7_fr.xml @@ -132,4 +132,9 @@ Exporter L'export des clés secrètes est techniquement impossible + + Ajouter une identité + Revoquer une identité + Saisie invalide + diff --git a/WTAPPROOT/K7/k7config.json b/WTAPPROOT/K7/k7config.json index a57806c..d5d334b 100644 --- a/WTAPPROOT/K7/k7config.json +++ b/WTAPPROOT/K7/k7config.json @@ -7,6 +7,7 @@ "canEditUidValidity" : true, "canEditExpiryTime" : true, "canCreateKeys" : true, + "canAddRevokeUids" : true, "privKeyIds" : [ "FullKeyId1", "FullKeyId2" diff --git a/nbproject/Makefile-ARM-Release.mk b/nbproject/Makefile-ARM-Release.mk index b4e47a5..0ca33b6 100644 --- a/nbproject/Makefile-ARM-Release.mk +++ b/nbproject/Makefile-ARM-Release.mk @@ -42,6 +42,7 @@ OBJECTFILES= \ ${OBJECTDIR}/KeyEdit.o \ ${OBJECTDIR}/KeyringIO.o \ ${OBJECTDIR}/LoopbackPassphraseProvider.o \ + ${OBJECTDIR}/PopupAddUid.o \ ${OBJECTDIR}/PopupCertifyUserId.o \ ${OBJECTDIR}/PopupCreate.o \ ${OBJECTDIR}/PopupDeleter.o \ @@ -112,6 +113,11 @@ ${OBJECTDIR}/LoopbackPassphraseProvider.o: LoopbackPassphraseProvider.cpp ${RM} "$@.d" $(COMPILE.cc) -O2 -s -DLARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -I/usr/local/Wt/include -I/usr/include/gpgme++ -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/LoopbackPassphraseProvider.o LoopbackPassphraseProvider.cpp +${OBJECTDIR}/PopupAddUid.o: PopupAddUid.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -DLARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -I/usr/local/Wt/include -I/usr/include/gpgme++ -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/PopupAddUid.o PopupAddUid.cpp + ${OBJECTDIR}/PopupCertifyUserId.o: PopupCertifyUserId.cpp ${MKDIR} -p ${OBJECTDIR} ${RM} "$@.d" diff --git a/nbproject/Makefile-Debug.mk b/nbproject/Makefile-Debug.mk index 2e44454..eb7e9ee 100644 --- a/nbproject/Makefile-Debug.mk +++ b/nbproject/Makefile-Debug.mk @@ -42,6 +42,7 @@ OBJECTFILES= \ ${OBJECTDIR}/KeyEdit.o \ ${OBJECTDIR}/KeyringIO.o \ ${OBJECTDIR}/LoopbackPassphraseProvider.o \ + ${OBJECTDIR}/PopupAddUid.o \ ${OBJECTDIR}/PopupCertifyUserId.o \ ${OBJECTDIR}/PopupCreate.o \ ${OBJECTDIR}/PopupDeleter.o \ @@ -112,6 +113,11 @@ ${OBJECTDIR}/LoopbackPassphraseProvider.o: LoopbackPassphraseProvider.cpp ${RM} "$@.d" $(COMPILE.cc) -g -DDEVTIME -I/usr/local/Wt-Debug/include -I/usr/include/gpgme++ -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/LoopbackPassphraseProvider.o LoopbackPassphraseProvider.cpp +${OBJECTDIR}/PopupAddUid.o: PopupAddUid.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -g -DDEVTIME -I/usr/local/Wt-Debug/include -I/usr/include/gpgme++ -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/PopupAddUid.o PopupAddUid.cpp + ${OBJECTDIR}/PopupCertifyUserId.o: PopupCertifyUserId.cpp ${MKDIR} -p ${OBJECTDIR} ${RM} "$@.d" diff --git a/nbproject/Makefile-Release.mk b/nbproject/Makefile-Release.mk index 7dc8d1b..9658138 100644 --- a/nbproject/Makefile-Release.mk +++ b/nbproject/Makefile-Release.mk @@ -42,6 +42,7 @@ OBJECTFILES= \ ${OBJECTDIR}/KeyEdit.o \ ${OBJECTDIR}/KeyringIO.o \ ${OBJECTDIR}/LoopbackPassphraseProvider.o \ + ${OBJECTDIR}/PopupAddUid.o \ ${OBJECTDIR}/PopupCertifyUserId.o \ ${OBJECTDIR}/PopupCreate.o \ ${OBJECTDIR}/PopupDeleter.o \ @@ -112,6 +113,11 @@ ${OBJECTDIR}/LoopbackPassphraseProvider.o: LoopbackPassphraseProvider.cpp ${RM} "$@.d" $(COMPILE.cc) -O2 -s -I/usr/local/Wt/include -I/usr/include/gpgme++ -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/LoopbackPassphraseProvider.o LoopbackPassphraseProvider.cpp +${OBJECTDIR}/PopupAddUid.o: PopupAddUid.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -I/usr/local/Wt/include -I/usr/include/gpgme++ -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/PopupAddUid.o PopupAddUid.cpp + ${OBJECTDIR}/PopupCertifyUserId.o: PopupCertifyUserId.cpp ${MKDIR} -p ${OBJECTDIR} ${RM} "$@.d" diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 4e180ff..d5d6ae2 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -11,6 +11,7 @@ KeyEdit.h KeyringIO.h LoopbackPassphraseProvider.h + PopupAddUid.h PopupCertifyUserId.h PopupCreate.h PopupDeleter.h @@ -39,6 +40,7 @@ KeyEdit.cpp KeyringIO.cpp LoopbackPassphraseProvider.cpp + PopupAddUid.cpp PopupCertifyUserId.cpp PopupCreate.cpp PopupDeleter.cpp @@ -120,6 +122,10 @@ + + + + @@ -232,6 +238,10 @@ + + + + @@ -348,6 +358,10 @@ + + + +