diff --git a/src/call.cpp b/src/call.cpp index 03541aebdf24244cd9ea4e052e8aa940275e1783..cf89a3c289a457c5b2c41a94d4ca8371d8d0f651 100644 --- a/src/call.cpp +++ b/src/call.cpp @@ -332,7 +332,7 @@ Call* CallPrivate::buildExistingCall(const QString& callId) //Load the certificate if it's now available if (!call->certificate() && !details[DRing::Call::Details::TLS_PEER_CERT].isEmpty()) { - call->d_ptr->m_pCertificate = CertificateModel::instance()->getCertificateFromContent(details[DRing::Call::Details::TLS_PEER_CERT].toLatin1()); + call->d_ptr->m_pCertificate = CertificateModel::instance()->getCertificateFromContent(details[DRing::Call::Details::TLS_PEER_CERT].toLatin1(),call->account()); } return call; @@ -370,7 +370,7 @@ Call* CallPrivate::buildIncomingCall(const QString& callId) //Load the certificate if it's now available if (!call->certificate() && !details[DRing::Call::Details::TLS_PEER_CERT].isEmpty()) { - call->d_ptr->m_pCertificate = CertificateModel::instance()->getCertificateFromContent(details[DRing::Call::Details::TLS_PEER_CERT].toLatin1()); + call->d_ptr->m_pCertificate = CertificateModel::instance()->getCertificateFromContent(details[DRing::Call::Details::TLS_PEER_CERT].toLatin1(),call->account()); } return call; @@ -397,7 +397,7 @@ Call* CallPrivate::buildRingingCall(const QString & callId) //Load the certificate if it's now available if (!call->certificate() && !details[DRing::Call::Details::TLS_PEER_CERT].isEmpty()) { - call->d_ptr->m_pCertificate = CertificateModel::instance()->getCertificateFromContent(details[DRing::Call::Details::TLS_PEER_CERT].toLatin1()); + call->d_ptr->m_pCertificate = CertificateModel::instance()->getCertificateFromContent(details[DRing::Call::Details::TLS_PEER_CERT].toLatin1(),call->account()); } return call; @@ -475,6 +475,11 @@ Call* Call::buildHistoryCall(const QMap<QString,QString>& hc) connect(call->peerContactMethod(),SIGNAL(rebased(ContactMethod*)),call->d_ptr,SLOT(updated())); } + //Check the certificate + if (!hc[Call::HistoryMapFields::CERT_PATH].isEmpty()) { + call->d_ptr->m_pCertificate = CertificateModel::instance()->getCertificate(QUrl(hc[Call::HistoryMapFields::CERT_PATH]),acc); + } + return call; } @@ -937,7 +942,7 @@ Call::State CallPrivate::stateChanged(const QString& newStateName) //Load the certificate if it's now available if (!q_ptr->certificate() && !details[DRing::Call::Details::TLS_PEER_CERT].isEmpty()) { - m_pCertificate = CertificateModel::instance()->getCertificateFromContent(details[DRing::Call::Details::TLS_PEER_CERT].toLatin1()); + m_pCertificate = CertificateModel::instance()->getCertificateFromContent(details[DRing::Call::Details::TLS_PEER_CERT].toLatin1(),q_ptr->account()); } try { diff --git a/src/certificate.h b/src/certificate.h index d29ec45c2a6ca65ca7614869f5cf9868a652a93c..d812316e248b3df4ae8d1365ba84493a6693733b 100644 --- a/src/certificate.h +++ b/src/certificate.h @@ -179,10 +179,10 @@ public: QVariant detailResult(Certificate::Details detail) const; QAbstractItemModel* model() const; - QString getName (Certificate::Checks check ); - QString getName (Certificate::Details details ); - QString getDescription (Certificate::Checks check ); - QString getDescription (Certificate::Details details ); + static QString getName (Certificate::Checks check ); + static QString getName (Certificate::Details details ); + static QString getDescription (Certificate::Checks check ); + static QString getDescription (Certificate::Details details ); //Checks CheckValues hasPrivateKey () const; diff --git a/src/certificatemodel.cpp b/src/certificatemodel.cpp index a17f308074598eaef4334a9fa91918c8b71aa8a6..d6ebf08cf75d4ec154888956fd89766894eb8c9a 100644 --- a/src/certificatemodel.cpp +++ b/src/certificatemodel.cpp @@ -31,6 +31,7 @@ //Ring #include "certificate.h" +#include "account.h" #include "delegates/certificateserializationdelegate.h" struct CertificateNode { @@ -39,16 +40,17 @@ struct CertificateNode { void setStrings(const QString& col1, const QVariant& col2, const QString& tooltip); //Attributes - QVector<CertificateNode*> m_lChildren ; - CertificateNode* m_pParent ; - Certificate* m_pCertificate; - CertificateModel::NodeType m_Level ; - int m_Index ; - QString m_Col1 ; - QVariant m_Col2 ; - QString m_ToolTip ; - std::function<void()> m_fLoader ; - bool m_IsLoaded ; + QVector<CertificateNode*> m_lChildren ; + CertificateNode* m_pParent ; + Certificate* m_pCertificate ; + CertificateModel::NodeType m_Level ; + int m_Index ; + QString m_Col1 ; + QVariant m_Col2 ; + QString m_ToolTip ; + std::function<void()> m_fLoader ; + bool m_IsLoaded ; + QHash<Account*,CertificateNode*> m_hSiblings; }; class BackgroundLoader : public QThread @@ -96,15 +98,19 @@ public: //Helper CertificateNode* defaultCategory(); + CertificateNode* createCategory(const QString& name, const QString& col2, const QString& tooltip); + CertificateNode* createCategory(Account* a); CertificateNode* addToTree(Certificate* cert, CertificateNode* category = nullptr); + CertificateNode* addToTree(Certificate* cert, Account* a); QModelIndex createIndex(int r ,int c , void* p); QAbstractItemModel* getModelCommon(CertificateNode* node); //Attributes - QVector<CertificateNode*> m_lTopLevelNodes ; - QHash<QString,Certificate*> m_hCertificates ; - CertificateNode* m_pDefaultCategory; - QMutex m_CertLoader ; + QVector<CertificateNode*> m_lTopLevelNodes ; + QHash<Account*,CertificateNode*> m_hAccToCat ; + QHash<QString,Certificate*> m_hCertificates ; + CertificateNode* m_pDefaultCategory ; + QMutex m_CertLoader ; QHash<const Certificate*,CertificateNode*> m_hNodes ; //Singleton @@ -151,6 +157,17 @@ CertificateModel::CertificateModel(QObject* parent) : QAbstractItemModel(parent) d_ptr(new CertificateModelPrivate(this)) { setObjectName("CertificateModel"); + + //Load the stored certificates + BackgroundLoader* loader = new BackgroundLoader(); + connect(loader, SIGNAL(finished()), loader, SLOT(deleteLater())); + + /*if (!loader->isFinished()) + connect(loader,&BackgroundLoader::finished,[loader](){ + delete loader; + });*/ + + loader->start(); } CertificateModel::~CertificateModel() @@ -168,11 +185,11 @@ CertificateModel* CertificateModel::instance() void BackgroundLoader::run() { if (m_lIdList.isEmpty()) //WARNING potential race - QList<QByteArray> m_lIdList = CertificateSerializationDelegate::instance()->listCertificates(); + m_lIdList = CertificateSerializationDelegate::instance()->listCertificates(); QMutexLocker(&this->m_LoaderMutex); for(const QByteArray& id : m_lIdList) { - CertificateModel::instance()->getCertificateFromContent(loadCert(id),false); + CertificateModel::instance()->getCertificateFromContent(loadCert(id),nullptr,false); } exit(0); } @@ -180,11 +197,23 @@ void BackgroundLoader::run() QHash<int,QByteArray> CertificateModel::roleNames() const { static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - /*static bool initRoles = false; + static bool initRoles = false; if (!initRoles) { initRoles = true; - - }*/ + roles[static_cast<int>(Role::NodeType)] = "nodeType"; + + //Add all the details, this isn't safe because of tr(), but good enough for debugging + for (const Certificate::Details d : EnumIterator<Certificate::Details>()) { + QString name = Certificate::getName(d).toLatin1(); + while (name.indexOf(' ') != -1) { + const int idx = name.indexOf(' ') ; + name = name.remove(idx,1) ; + name[idx] = name[idx].toUpper(); + name[0 ] = name[0].toLower (); + } + roles[static_cast<int>(Role::DetailRoleBase)+static_cast<int>(d)] = name.toLatin1(); + } + } return roles; } @@ -195,17 +224,24 @@ void CertificateNode::setStrings(const QString& col1, const QVariant& col2, cons m_ToolTip = tooltip; } -CertificateNode* CertificateModelPrivate::defaultCategory() +CertificateNode* CertificateModelPrivate::createCategory(const QString& name, const QString& col2, const QString& tooltip ) { - if (!m_pDefaultCategory) { - const int idx = m_hCertificates.size(); + const int idx = m_hCertificates.size(); - m_pDefaultCategory = new CertificateNode(idx, CertificateModel::NodeType::CATEGORY, nullptr, nullptr); - m_pDefaultCategory->setStrings(QObject::tr("Default"),QObject::tr("Certificate not associated with a group"),QString()); + CertificateNode* n = new CertificateNode(idx, CertificateModel::NodeType::CATEGORY, nullptr, nullptr); + n->setStrings(name,col2,tooltip); - q_ptr->beginInsertRows(QModelIndex(), idx, idx); - m_lTopLevelNodes << m_pDefaultCategory; - q_ptr->endInsertRows(); + q_ptr->beginInsertRows(QModelIndex(), idx, idx); + m_lTopLevelNodes << n; + q_ptr->endInsertRows(); + + return n; +} + +CertificateNode* CertificateModelPrivate::defaultCategory() +{ + if (!m_pDefaultCategory) { + m_pDefaultCategory = createCategory(QObject::tr("Default"),QObject::tr("Certificate not associated with a group"),QString()); } return m_pDefaultCategory; @@ -216,6 +252,29 @@ QModelIndex CertificateModelPrivate::createIndex(int r ,int c , void* p) return q_ptr->createIndex(r,c,p); } +CertificateNode* CertificateModelPrivate::createCategory(Account* a) +{ + CertificateNode* cat = m_hAccToCat[a]; + + if (!cat) { + cat = createCategory(a->alias(),QString(),QString()); + m_hAccToCat[a] = cat; + } + + return cat; +} + +//For convenience +CertificateNode* CertificateModelPrivate::addToTree(Certificate* cert, Account* a) +{ + if (!a) + return addToTree(cert); + + CertificateNode* cat = createCategory(a); + + return addToTree(cert,cat); +} + CertificateNode* CertificateModelPrivate::addToTree(Certificate* cert, CertificateNode* category) { QMutexLocker(&this->m_CertLoader); @@ -292,15 +351,25 @@ QVariant CertificateModel::data( const QModelIndex& index, int role) const if (!index.isValid()) return QVariant(); const CertificateNode* node = static_cast<CertificateNode*>(index.internalPointer()); - switch(role) { - case Qt::DisplayRole: - case Qt::EditRole: - return index.column()?node->m_Col2:node->m_Col1; - case Qt::ToolTipRole: - return node->m_ToolTip; - case static_cast<int>(Role::NodeType): - return QVariant::fromValue(node->m_Level); - }; + + switch(role) { + case Qt::DisplayRole: + case Qt::EditRole: + return index.column()?node->m_Col2:node->m_Col1; + case Qt::ToolTipRole: + return node->m_ToolTip; + case static_cast<int>(Role::NodeType): + return QVariant::fromValue(node->m_Level); + }; + + //Add the details as roles for certificates + if (node && node->m_Level == NodeType::CERTIFICATE && role >= static_cast<int>(Role::DetailRoleBase) && role < static_cast<int>(Role::DetailRoleBase)+enum_class_size<Certificate::Details>()) { + Certificate* cert = node->m_pCertificate; + if (cert) { + return cert->detailResult(static_cast<Certificate::Details>(role - static_cast<int>(Role::DetailRoleBase))); + } + } + return QVariant(); } @@ -360,6 +429,34 @@ QVariant CertificateModel::headerData( int section, Qt::Orientation orientation, return QVariant(); } +Certificate* CertificateModel::getCertificate(const QUrl& path, Account* a) +{ + if (!a) + return getCertificate(path,Certificate::Type::CALL); + + CertificateNode* cat = d_ptr->createCategory(a); + + Certificate* cert = d_ptr->m_hCertificates[path.path()]; + + if (!cert) { + cert = new Certificate(path); + d_ptr->m_hCertificates[path.toString().toLatin1()] = cert; + + //Add it to the model + d_ptr->addToTree(cert,a); + } + + CertificateNode* node = d_ptr->m_hNodes[cert]; + + if (node) { + if (node->m_pParent != cat) { + CertificateNode* node2 = d_ptr->addToTree(cert,cat); + node->m_hSiblings[a] = node2; + } + } + return cert; +} + Certificate* CertificateModel::getCertificate(const QUrl& path, Certificate::Type type) { Q_UNUSED(type) @@ -379,7 +476,7 @@ Certificate* CertificateModel::getCertificate(const QUrl& path, Certificate::Typ return cert; } -Certificate* CertificateModel::getCertificateFromContent(const QByteArray& rawContent, bool save) +Certificate* CertificateModel::getCertificateFromContent(const QByteArray& rawContent, Account* a, bool save) { QCryptographicHash hash(QCryptographicHash::Sha1); @@ -392,10 +489,11 @@ Certificate* CertificateModel::getCertificateFromContent(const QByteArray& rawCo cert = new Certificate(rawContent); d_ptr->m_hCertificates[id] = cert; - d_ptr->addToTree(cert); + d_ptr->addToTree(cert,a); if (save) { - CertificateSerializationDelegate::instance()->saveCertificate(id,rawContent); + const QUrl path = CertificateSerializationDelegate::instance()->saveCertificate(id,rawContent); + cert->setPath(path); } } diff --git a/src/certificatemodel.h b/src/certificatemodel.h index 737521b7201156d163e3131f89a24eade3177a58..a751c36663ce4a0e99b8a98bb1fe9c925f11b5e3 100644 --- a/src/certificatemodel.h +++ b/src/certificatemodel.h @@ -22,6 +22,8 @@ #include "certificate.h" +class Account; + class CertificateModelPrivate; class LIB_EXPORT CertificateModel : public QAbstractItemModel @@ -32,7 +34,8 @@ public: friend class CertificateNode; enum class Role { - NodeType = 100, + NodeType = 100, + DetailRoleBase = 1000, }; enum class Columns { @@ -64,11 +67,12 @@ public: //Getters QAbstractItemModel* model(const Certificate* cert) const; - QAbstractItemModel* model(const QModelIndex& idx) const; + QAbstractItemModel* model(const QModelIndex& idx ) const; //Mutator Certificate* getCertificate(const QUrl& path, Certificate::Type type = Certificate::Type::NONE); - Certificate* getCertificateFromContent(const QByteArray& rawContent, bool save = true); + Certificate* getCertificate(const QUrl& path, Account* a); + Certificate* getCertificateFromContent(const QByteArray& rawContent, Account* a = nullptr, bool save = true); //Singleton static CertificateModel* instance(); diff --git a/src/useractionmodel.cpp b/src/useractionmodel.cpp index f8bcbf7e674549cd44af124f1bdb04bac85a9aa7..537ea8ab461a536cd97b3f608a256cbd2a9fa4e9 100644 --- a/src/useractionmodel.cpp +++ b/src/useractionmodel.cpp @@ -110,7 +110,7 @@ const TypedStateMachine< TypedStateMachine< bool , Call::State > , UserActionMod /*MUTE_VIDEO */ {{ false , true , true , false, false, false, false, false, false, false, false, false, false, false}}, /*SERVER_TRANSFER */ {{ false , false, true , false, true , false, false, false, false, false, false, false, false, false}}, /*RECORD */ {{ false , true , true , false, true , false, false, true , true , false, false, true , true , false}}, - /*HANGUP */ {{ true , true , true , true , true , true , true , true , true , false, true , true , true , false}}, + /*HANGUP */ {{ true , true , true , true , true , true , true , true , true , false, true , true , true , true }}, /*JOIN */ {{ false , true , true , false, true , false, false, true , true , false, false, true , true , false }}, }};