Skip to content
Snippets Groups Projects
Commit 7a98f3da authored by Emmanuel Lepage Vallee's avatar Emmanuel Lepage Vallee
Browse files

contact: Add option to purge the contact list of unreachable members

It is a very conservative algorithm, when it is unsure, it will be
shown.

This commit also fix 2 off by one and a vCard parsing error for
the URI handling.

Refs #70365
parent 7a7b52ef
No related branches found
No related tags found
No related merge requests found
......@@ -65,11 +65,12 @@ public:
ContactTreeNode* m_pParent ;
QVector<ContactTreeNode*> m_lChildren ;
CategorizedContactModel* m_pModel ;
bool m_Visible ;
//Helpers
void slotChanged ( );
void slotContactMethodCountChanged (int,int);
void slotContactMethodCountAboutToChange(int,int);
void slotChanged ( );
void slotContactMethodCountChanged (int,int );
void slotContactMethodCountAboutToChange(int,int );
};
class CategorizedContactModelPrivate : public QObject
{
......@@ -88,10 +89,12 @@ public:
QStringList m_lMimes ;
bool m_SortAlphabetical ;
QString m_DefaultCategory ;
bool m_UnreachableHidden;
//Helper
ContactTreeNode* getContactTopLevelItem(const QString& category);
QModelIndex getIndex(int row, int column, ContactTreeNode* parent);
void reloadTreeVisibility (ContactTreeNode*);
//Singleton
static CategorizedContactModel* m_spInstance;
......@@ -107,21 +110,24 @@ public Q_SLOTS:
CategorizedContactModel* CategorizedContactModelPrivate::m_spInstance = nullptr;
ContactTreeNode::ContactTreeNode(const Person* ct, CategorizedContactModel* parent) : CategorizedCompositeNode(CategorizedCompositeNode::Type::CONTACT),
m_pContact(ct),m_Index(-1),m_pContactMethod(nullptr),m_Type(ContactTreeNode::NodeType::PERSON),m_pParent(nullptr),m_pModel(parent)
m_pContact(ct),m_Index(-1),m_pContactMethod(nullptr),m_Type(ContactTreeNode::NodeType::PERSON),m_pParent(nullptr),m_pModel(parent),m_Visible(true)
{
m_Visible = m_pContact->isActive() && ((!parent->d_ptr->m_UnreachableHidden) || m_pContact->isReachable());
QObject::connect(m_pContact,&Person::changed ,[this]( ){ slotChanged ( ); });
QObject::connect(m_pContact,&Person::phoneNumberCountChanged ,[this](int n, int o){ slotContactMethodCountChanged (n,o); });
QObject::connect(m_pContact,&Person::phoneNumberCountAboutToChange,[this](int n, int o){ slotContactMethodCountAboutToChange(n,o); });
}
ContactTreeNode::ContactTreeNode(ContactMethod* cm, CategorizedContactModel* parent) : CategorizedCompositeNode(CategorizedCompositeNode::Type::NUMBER),
m_pContactMethod(cm),m_Index(-1),m_pContact(nullptr),m_Type(ContactTreeNode::NodeType::CONTACTMETHOD),m_pParent(nullptr),m_pModel(parent)
m_pContactMethod(cm),m_Index(-1),m_pContact(nullptr),m_Type(ContactTreeNode::NodeType::CONTACTMETHOD),m_pParent(nullptr),m_pModel(parent),
m_Visible(true)
{
QObject::connect(m_pContactMethod,&ContactMethod::changed,[this](){ slotChanged(); });
}
ContactTreeNode::ContactTreeNode(const QString& name, CategorizedContactModel* parent) : CategorizedCompositeNode(CategorizedCompositeNode::Type::CONTACT),
m_pContactMethod(nullptr),m_Index(-1),m_pContact(nullptr),m_Type(ContactTreeNode::NodeType::CATEGORY),m_Name(name),m_pParent(nullptr),m_pModel(parent)
m_pContactMethod(nullptr),m_Index(-1),m_pContact(nullptr),m_Type(ContactTreeNode::NodeType::CATEGORY),m_Name(name),m_pParent(nullptr),
m_pModel(parent),m_Visible(true)
{
}
......@@ -179,7 +185,7 @@ void ContactTreeNode::slotContactMethodCountAboutToChange(int count, int oldCoun
}
CategorizedContactModelPrivate::CategorizedContactModelPrivate(CategorizedContactModel* parent) : QObject(parent), q_ptr(parent),
m_lCategoryCounter(),m_Role(Qt::DisplayRole),m_SortAlphabetical(true)
m_lCategoryCounter(),m_Role(Qt::DisplayRole),m_SortAlphabetical(true),m_UnreachableHidden(false)
{
}
......@@ -413,7 +419,7 @@ Qt::ItemFlags CategorizedContactModel::flags( const QModelIndex& index ) const
const ContactTreeNode* modelNode = static_cast<ContactTreeNode*>(index.internalPointer());
return (((!modelNode->m_pContact) || (modelNode->m_pContact->isActive())) ? Qt::ItemIsEnabled : Qt::NoItemFlags )
return ((modelNode->m_Visible) ? Qt::ItemIsEnabled : Qt::NoItemFlags )
| Qt::ItemIsSelectable
| (modelNode->m_pParent? (Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled) : Qt::ItemIsEnabled
);
......@@ -551,4 +557,45 @@ QString CategorizedContactModel::defaultCategory() const
return d_ptr->m_DefaultCategory;
}
bool CategorizedContactModel::areUnreachableHidden() const
{
return d_ptr->m_UnreachableHidden;
}
/**
* Show/hide contacts that are currently unreachable
*
* @warning This method will reloaded person reachability status,
* this require large amount of CPU when many contacts are present
*/
void CategorizedContactModel::setUnreachableHidden(bool val)
{
if (d_ptr->m_UnreachableHidden != val) {
d_ptr->m_UnreachableHidden = val;
d_ptr->reloadTreeVisibility(nullptr);
}
}
void CategorizedContactModelPrivate::reloadTreeVisibility( ContactTreeNode* node )
{
if (!node) {
for(ContactTreeNode* n : m_hCategories)
reloadTreeVisibility(n);
return;
}
switch(node->m_Type) {
case ContactTreeNode::NodeType::PERSON :
node->m_Visible = node->m_pContact->isActive() && ((!m_UnreachableHidden) || node->m_pContact->isReachable());
break;
case ContactTreeNode::NodeType::CONTACTMETHOD:
//Nothing to do
break;
case ContactTreeNode::NodeType::CATEGORY :
for (ContactTreeNode* n : node->m_lChildren)
reloadTreeVisibility(n);
break;
};
}
#include <categorizedcontactmodel.moc>
......@@ -38,35 +38,37 @@ class LIB_EXPORT CategorizedContactModel : public QAbstractItemModel
Q_OBJECT
#pragma GCC diagnostic pop
public:
friend class PersonModel;
friend class ContactTreeNode;
friend class PersonModel ;
friend class ContactTreeNode ;
friend class ContactTreeBinder;
explicit CategorizedContactModel(int role = Qt::DisplayRole);
virtual ~CategorizedContactModel();
//Setters
void setRole(int role);
void setSortAlphabetical(bool alpha = true);
void setDefaultCategory(const QString& cat);
void setRole ( int role );
void setSortAlphabetical ( bool alpha = true );
void setDefaultCategory ( const QString& cat );
void setUnreachableHidden( bool value );
//Model implementation
virtual bool setData ( const QModelIndex& index, const QVariant &value, int role ) override;
virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override;
virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override;
virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override;
virtual int columnCount ( const QModelIndex& parent = QModelIndex() ) const override;
virtual QModelIndex parent ( const QModelIndex& index ) const override;
virtual QModelIndex index ( int row, int column, const QModelIndex& parent=QModelIndex()) const override;
virtual bool setData ( const QModelIndex& index, const QVariant &value, int role ) override;
virtual bool dropMimeData( const QMimeData*, Qt::DropAction, int, int, const QModelIndex& ) override;
virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override;
virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override;
virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override;
virtual int columnCount ( const QModelIndex& parent = QModelIndex() ) const override;
virtual QModelIndex parent ( const QModelIndex& index ) const override;
virtual QModelIndex index ( int row, int column, const QModelIndex& parent=QModelIndex() ) const override;
virtual QStringList mimeTypes ( ) const override;
virtual QMimeData* mimeData ( const QModelIndexList &indexes ) const override;
virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override;
virtual QStringList mimeTypes ( ) const override;
virtual QMimeData* mimeData ( const QModelIndexList &indexes ) const override;
virtual bool dropMimeData ( const QMimeData*, Qt::DropAction, int, int, const QModelIndex& ) override;
virtual QHash<int,QByteArray> roleNames() const override;
//Getter
static int acceptedPayloadTypes() ;
bool isSortAlphabetical () const;
QString defaultCategory () const;
bool areUnreachableHidden() const;
//Singleton
static CategorizedContactModel* instance();
......
......@@ -588,7 +588,7 @@ bool ContactMethod::operator==(const ContactMethod& other) const
* *
***********************************************************************************/
void TemporaryContactMethod::setUri(const QString& uri)
void TemporaryContactMethod::setUri(const URI& uri)
{
d_ptr->m_Uri = uri;
d_ptr->changed();
......
......@@ -208,7 +208,7 @@ class LIB_EXPORT TemporaryContactMethod : public ContactMethod {
Q_OBJECT
public:
explicit TemporaryContactMethod(const ContactMethod* number = nullptr);
void setUri(const QString& uri);
void setUri(const URI& uri);
};
#endif
......@@ -295,26 +295,23 @@ bool VCardUtils::mapToPerson(Person* p, const QByteArray& all, Account** a)
// qDebug() << "Could not extract: " << previousKey;
}
const QList<QByteArray> splitted = property.split(':');
if(splitted.size() < 2){
qDebug() << "Malformed vCard property!" << splitted[0] << property[0] << (property[0] == ' ');
continue;
}
//Do not use split, URIs can have : in them
const int dblptPos = property.indexOf(':');
const QByteArray k(property.left(dblptPos)),v(property.right(property.size()-dblptPos-1));
//Link with accounts
if(splitted[0] == VCardUtils::Property::X_RINGACCOUNT) {
if(k == VCardUtils::Property::X_RINGACCOUNT) {
if (a) {
*a = AccountModel::instance()->getById(splitted[1].trimmed(),true);
*a = AccountModel::instance()->getById(v.trimmed(),true);
if(!*a) {
qDebug() << "Could not find account: " << splitted[1].trimmed();
qDebug() << "Could not find account: " << v.trimmed();
continue;
}
}
}
previousKey = splitted[0];
previousValue = splitted[1];
previousKey = k;
previousValue = v;
}
}
......
......@@ -47,7 +47,7 @@ public:
//Helper
static QString strip(const QString& uri, URI::SchemeType& scheme);
void parse();
static bool checkIp(const QString& str, bool &isHash);
static bool checkIp(const QString& str, bool &isHash, const URI::SchemeType& scheme);
private:
QString* q_ptr;
};
......@@ -69,8 +69,11 @@ URI::URI(const QString& other):QString(), d_ptr(new URIPrivate(this))
///Copy constructor
URI::URI(const URI& o):QString(), d_ptr(new URIPrivate(this))
{
//TODO see if a copy on write kind of algo could be used for this
d_ptr->m_Parsed = o.d_ptr->m_Parsed ;
d_ptr->m_HintParsed = o.d_ptr->m_HintParsed;
d_ptr->m_Hostname = o.d_ptr->m_Hostname ;
d_ptr->m_HasAt = o.d_ptr->m_HasAt ;
d_ptr->m_HeaderType = o.d_ptr->m_HeaderType;
d_ptr->m_Userinfo = o.d_ptr->m_Userinfo ;
d_ptr->m_Stripped = o.d_ptr->m_Stripped ;
......@@ -90,7 +93,9 @@ URI::~URI()
URI& URI::operator=(const URI& o)
{
d_ptr->m_Parsed = o.d_ptr->m_Parsed ;
d_ptr->m_HintParsed = o.d_ptr->m_HintParsed;
d_ptr->m_Hostname = o.d_ptr->m_Hostname ;
d_ptr->m_HasAt = o.d_ptr->m_HasAt ;
d_ptr->m_HeaderType = o.d_ptr->m_HeaderType;
d_ptr->m_Userinfo = o.d_ptr->m_Userinfo ;
d_ptr->m_Stripped = o.d_ptr->m_Stripped ;
......@@ -103,15 +108,19 @@ URI& URI::operator=(const URI& o)
QString URIPrivate::strip(const QString& uri, URI::SchemeType& scheme)
{
if (uri.isEmpty())
return QString();
return {};
int start(uri[0] == '<'?1:0),end(uri.size()-1); //Other type of comparisons were too slow
uchar c;
if (start == end+1)
return {};
const uchar c = uri[start].toLatin1();
//Assume the scheme is either iax, sip or ring using the first letter and length, this
//is dangerous and can cause undefined behaviour that will cause the call to fail
//later on, but this is not really a problem for now
if (end > start+3 && (c = uri[start+3].toLatin1()) == ':') {
if (end > start+3 && uri[start+3] == ':') {
switch (c) {
case 'i':
scheme = URI::SchemeType::IAX;
......@@ -120,9 +129,9 @@ QString URIPrivate::strip(const QString& uri, URI::SchemeType& scheme)
scheme = URI::SchemeType::SIP;
break;
}
start = 5;
start = start +4;
}
else if (end > start+4 && (c = uri[start+4].toLatin1()) == ':') {
else if (end > start+4 && uri[start+4] == ':') {
switch (c) {
case 'i':
scheme = URI::SchemeType::IAX2;
......@@ -134,7 +143,7 @@ QString URIPrivate::strip(const QString& uri, URI::SchemeType& scheme)
scheme = URI::SchemeType::SIPS;
break;
}
start = 6;
start = start +5;
}
if (end && uri[end] == '>')
......@@ -187,12 +196,12 @@ URI::SchemeType URI::schemeType() const
* @param str an uservalue (faster the scheme and before the "at" sign)
* @param [out] isHash if the content is pure hexadecimal ASCII
*/
bool URIPrivate::checkIp(const QString& str, bool &isHash)
bool URIPrivate::checkIp(const QString& str, bool &isHash, const URI::SchemeType& scheme)
{
char* raw = str.toLatin1().data();
ushort max = str.size();
if (max < 3 || max > 45)
if (max < 3 || max > 45 || (!isHash && scheme == URI::SchemeType::RING))
return false;
uchar dc(0),sc(0),i(0),d(0),hx(1);
......@@ -204,15 +213,9 @@ bool URIPrivate::checkIp(const QString& str, bool &isHash)
d = 0;
dc++;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '0': case '1': case '2':
case '3': case '4': case '5':
case '6': case '7': case '8':
case '9':
if (++d > 3 && dc)
return false;
......@@ -221,26 +224,19 @@ bool URIPrivate::checkIp(const QString& str, bool &isHash)
isHash = false;
sc++;
//No break
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F':
case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f':
hx = 0;
break;
default:
isHash = false;
return false;
};
i++;
}
return (hx && dc == 3 && d < 4) ^ (~(sc < 2 || dc));
return (hx && dc == 3 && d < 4) ^ (sc > 1 && dc==0);
}
/**
......@@ -264,7 +260,7 @@ URI::ProtocolHint URI::protocolHint() const
: (
//Step two : check IP
URIPrivate::checkIp(d_ptr->m_Userinfo,isHash) ? URI::ProtocolHint::IP
URIPrivate::checkIp(d_ptr->m_Userinfo,isHash,d_ptr->m_HeaderType) ? URI::ProtocolHint::IP
: (
//Step three : Check RING protocol, is has already been detected at this point
......@@ -277,7 +273,6 @@ URI::ProtocolHint URI::protocolHint() const
))));
d_ptr->m_HintParsed = true;
qDebug() << "ICI" << (int)d_ptr->m_ProtocolHint;
}
return d_ptr->m_ProtocolHint;
}
......@@ -288,11 +283,13 @@ void URIPrivate::parse()
//FIXME the indexOf is done twice, the second time could be avoided
if (q_ptr->indexOf('@') != -1) {
const QStringList split = q_ptr->split('@');
m_Hostname = split[1];//split[1].left(split[1].size())
m_HasAt = true;
m_Hostname = split[1];
m_Userinfo = split[0];
m_HasAt = split.size();
m_Parsed = true;
m_Parsed = true;
}
else
m_Userinfo = (*q_ptr);
}
/**
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment