qtmobility/src/contacts/qcontactmanagerengine.cpp
changeset 14 6fbed849b4f4
parent 11 06b8e2af4411
child 15 1f895d8a5b2b
--- a/qtmobility/src/contacts/qcontactmanagerengine.cpp	Fri Jun 11 14:26:25 2010 +0300
+++ b/qtmobility/src/contacts/qcontactmanagerengine.cpp	Wed Jun 23 19:08:38 2010 +0300
@@ -56,6 +56,10 @@
 #include "qcontact_p.h"
 #include "qcontactdetail_p.h"
 
+#include <QMutex>
+#include <QMutexLocker>
+#include <QWeakPointer>
+
 QTM_BEGIN_NAMESPACE
 
 /*!
@@ -323,6 +327,9 @@
   with the key being the index into the input relationships list, and the value being the error which
   occurred for that index.
 
+  The supplied \a errorMap parameter may be null, if the client does not desire detailed error information.
+  If supplied, it will be empty upon entry to this function.
+
   The overall operation error will be saved in \a error.
  */
 bool QContactManagerEngine::saveRelationships(QList<QContactRelationship>* relationships, QMap<int, QContactManager::Error>* errorMap, QContactManager::Error* error)
@@ -398,6 +405,9 @@
   with the key being the index into the input relationships list, and the value being the error which
   occurred for that index.
 
+  The supplied \a errorMap parameter may be null, if the client does not desire detailed error information.
+  If supplied, it will be empty upon entry to this function.
+
   The overall operation error will be saved in \a error.
  */
 bool QContactManagerEngine::removeRelationships(const QList<QContactRelationship>& relationships, QMap<int, QContactManager::Error>* errorMap, QContactManager::Error* error)
@@ -1416,6 +1426,10 @@
   The manager might populate \a errorMap (the map of indices of the \a contacts list to
   the error which occurred when saving the contact at that index) for
   every index for which the contact could not be saved, if it is able.
+
+  The supplied \a errorMap parameter may be null, if the client does not desire detailed error information.
+  If supplied, it will be empty upon entry to this function.
+
   The \l QContactManager::error() function will only return \c QContactManager::NoError
   if all contacts were saved successfully.
 
@@ -1447,6 +1461,10 @@
   The manager might populate \a errorMap (the map of indices of the \a contactIds list to
   the error which occurred when saving the contact at that index) for every
   index for which the contact could not be removed, if it is able.
+
+  The supplied \a errorMap parameter may be null, if the client does not desire detailed error information.
+  If supplied, it will be empty upon entry to this function.
+
   The \l QContactManager::error() function will
   only return \c QContactManager::NoError if all contacts were removed
   successfully.
@@ -1521,8 +1539,8 @@
             // if the allowable values is an empty list, any are allowed.
             if (!field.allowableValues().isEmpty()) {
                 // if the field datatype is a list, remove non-allowable values
-                if (field.dataType() == QVariant::List || field.dataType() == QVariant::StringList) {
-                    QList<QVariant> innerValues = variant.toList();
+                if (field.dataType() == QVariant::List) {
+                    QVariantList innerValues = variant.toList();
                     QMutableListIterator<QVariant> it(innerValues);
                     while (it.hasNext()) {
                         if (!field.allowableValues().contains(it.next())) {
@@ -1533,6 +1551,19 @@
                         detail.removeValue(key);
                     else
                         detail.setValue(key, innerValues);
+                } 
+                if (field.dataType() == QVariant::StringList) {
+                    QStringList innerValues = variant.toStringList();
+                    QMutableListIterator<QString> it(innerValues);
+                    while (it.hasNext()) {
+                        if (!field.allowableValues().contains(it.next())) {
+                            it.remove();
+                        }
+                    }
+                    if (innerValues.isEmpty())
+                        detail.removeValue(key);
+                    else
+                        detail.setValue(key, innerValues);
                 } else if (!field.allowableValues().contains(variant)) {
                     detail.removeValue(key);
                 }
@@ -1552,10 +1583,41 @@
     return conforming;
 }
 
+
+/* This implements the string comparison behaviour required for compareVariant, amongst others */
+static inline int compareStrings(const QString& left, const QString& right, Qt::CaseSensitivity sensitivity)
+{
+    if (sensitivity == Qt::CaseSensitive) {
+        return left.localeAwareCompare(right);
+    } else {
+        return left.toCaseFolded().localeAwareCompare(right.toCaseFolded());
+    }
+}
+
 /*!
   Compares \a first against \a second.  If the types are
   strings (QVariant::String), the \a sensitivity argument controls
-  case sensitivity when comparing.
+  case sensitivity when comparing.  Also, when comparing strings,
+  a locale aware comparison is used, and if the sensitivity is
+  CaseSensitive, strings that are identical under a case insensitive
+  sort are then sorted case sensitively within that context.
+
+
+  For example:
+
+  aaron
+  Bob
+  Aaron
+  aAron
+  Carol
+
+  would sort as:
+
+  aaron
+  aAron
+  Aaron
+  Bob
+  Carol
 
   Returns:
   <0 if \a first is less than \a second
@@ -1583,7 +1645,7 @@
             return first.toULongLong() - second.toULongLong();
 
        case QVariant::String:
-            return first.toString().compare(second.toString(), sensitivity);
+            return compareStrings(first.toString(), second.toString(), sensitivity);
 
         case QVariant::Double:
             {
@@ -1776,7 +1838,7 @@
                             return true;
                         if (matchContains && var.contains(needle, cs))
                             return true;
-                        if (QString::compare(var, needle, cs) == 0)
+                        if (compareStrings(var, needle, cs) == 0)
                             return true;
                     }
                     return false;
@@ -1795,6 +1857,8 @@
 
         case QContactFilter::ContactDetailRangeFilter:
             {
+                /* The only supported flags are: MatchExactly, MatchFixedString, MatchCaseSensitive */
+
                 const QContactDetailRangeFilter cdf(filter);
                 if (cdf.detailDefinitionName().isEmpty())
                     return false; /* we do not know which field to check */
@@ -1823,56 +1887,45 @@
                 const int minComp = cdf.rangeFlags() & QContactDetailRangeFilter::ExcludeLower ? 1 : 0;
                 const int maxComp = cdf.rangeFlags() & QContactDetailRangeFilter::IncludeUpper ? 1 : 0;
 
-                const bool testMin = cdf.minValue().isValid();
-                const bool testMax = cdf.maxValue().isValid();
-
-                /* At this point we know that at least of testMin & testMax is true */
-
                 /* Case sensitivity, for those parts that use it */
                 Qt::CaseSensitivity cs = (cdf.matchFlags() & QContactFilter::MatchCaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive;
 
                 /* See what flags are requested, since we're looking at a value */
-                if (cdf.matchFlags() & (QContactFilter::MatchEndsWith | QContactFilter::MatchStartsWith | QContactFilter::MatchContains | QContactFilter::MatchFixedString)) {
+                if (cdf.matchFlags() & QContactFilter::MatchFixedString) {
                     /* We're strictly doing string comparisons here */
-                    //bool matchStarts = (cdf.matchFlags() & 7) == QContactFilter::MatchStartsWith;
-                    bool matchEnds = (cdf.matchFlags() & 7) == QContactFilter::MatchEndsWith;
-                    bool matchContains = (cdf.matchFlags() & 7) == QContactFilter::MatchContains;
-
-                    /* Min/Max and contains do not make sense */
-                    if (matchContains)
-                        return false;
-
                     QString minVal = cdf.minValue().toString();
                     QString maxVal = cdf.maxValue().toString();
 
-                    /* Starts with is the normal compare case, endsWith is a bit trickier */
+                    const bool testMin = !minVal.isEmpty();
+                    const bool testMax = !maxVal.isEmpty();
+
                     for(int j=0; j < details.count(); j++) {
                         const QContactDetail& detail = details.at(j);
+
+                        // The detail has to have a field of this type in order to be compared.
+                        if (!detail.variantValue(cdf.detailFieldName()).isValid())
+                            continue;
                         const QString& var = detail.value(cdf.detailFieldName());
-                        if (!matchEnds) {
-                            // MatchStarts or MatchFixedString
-                            if (testMin && QString::compare(var, minVal, cs) < minComp)
-                                continue;
-                            if (testMax && QString::compare(var, maxVal, cs) >= maxComp)
-                                continue;
-                            return true;
-                        } else {
-                            /* Have to test the length of min & max */
-                            // using refs means the parameter order is backwards, so negate the result of compare
-                            if (testMin && -QString::compare(minVal, var.rightRef(minVal.length()), cs) < minComp)
-                                continue;
-                            if (testMax && -QString::compare(maxVal, var.rightRef(maxVal.length()), cs) >= maxComp)
-                                continue;
-                            return true;
-                        }
+                        if (testMin && compareStrings(var, minVal, cs) < minComp)
+                            continue;
+                        if (testMax && compareStrings(var, maxVal, cs) >= maxComp)
+                            continue;
+                        return true;
                     }
                     // Fall through to end
                 } else {
+                    const bool testMin = cdf.minValue().isValid();
+                    const bool testMax = cdf.maxValue().isValid();
+
                     /* Nope, testing the values as a variant */
                     for(int j=0; j < details.count(); j++) {
                         const QContactDetail& detail = details.at(j);
                         const QVariant& var = detail.variantValue(cdf.detailFieldName());
 
+                        // The detail has to have a field of this type in order to be compared.
+                        if (!var.isValid())
+                            continue;
+
                         if (testMin && compareVariant(var, cdf.minValue(), cs) < minComp)
                             continue;
                         if (testMax && compareVariant(var, cdf.maxValue(), cs) >= maxComp)
@@ -2005,10 +2058,7 @@
  */
 int QContactManagerEngine::compareContact(const QContact& a, const QContact& b, const QList<QContactSortOrder>& sortOrders)
 {
-    QList<QContactSortOrder> copy = sortOrders;
-    while (copy.size()) {
-        // retrieve the next sort order in the list
-        QContactSortOrder sortOrder = copy.takeFirst();
+    foreach(const QContactSortOrder& sortOrder, sortOrders) {
         if (!sortOrder.isValid())
             break;
 
@@ -2045,47 +2095,51 @@
     return 0; // or according to id? return (a.id() < b.id() ? -1 : 1);
 }
 
+/* A functor that returns true iff a is less than b, according to the sortOrders passed in to the
+ * ctor.  The sortOrders pointer passed in must remain valid for the lifetime of the functor. */
+class ContactLessThan {
+    public:
+        ContactLessThan(const QList<QContactSortOrder>* sortOrders) : mSortOrders(sortOrders) {}
+        bool operator()(const QContact& a, const QContact& b) const
+        {
+            return QContactManagerEngine::compareContact(a, b, *mSortOrders) < 0;
+        }
+    private:
+        const QList<QContactSortOrder>* mSortOrders;
+};
 
 /*!
   Performs insertion sort of the contact \a toAdd into the \a sorted list, according to the provided \a sortOrders list.
-  The first QContactSortOrder in the list has the highest priority; if the contact \a toAdd is deemed equal to another
-  in the \a sorted list, the second QContactSortOrder in the list is used (and so on until either the contact is inserted
-  or there are no more sort order objects in the list).
+  The first QContactSortOrder in the list has the highest priority: if the contact \a toAdd is deemed equal to another
+  in the \a sorted list according to the first QContactSortOrder, the second QContactSortOrder in the list is used (and
+  so on until either the contact is inserted or there are no more sort order objects in the list).
+
+  If a contact is equal to another contact according to all sort orders, it is inserted after the previously-added contact.
  */
 void QContactManagerEngine::addSorted(QList<QContact>* sorted, const QContact& toAdd, const QList<QContactSortOrder>& sortOrders)
 {
     if (sortOrders.count() > 0) {
-        for (int i = 0; i < sorted->size(); i++) {
-            // check to see if the new contact should be inserted here
-            int comparison = compareContact(sorted->at(i), toAdd, sortOrders);
-            if (comparison > 0) {
-                sorted->insert(i, toAdd);
-                return;
-            }
-        }
+        ContactLessThan lessThan(&sortOrders);
+        QList<QContact>::iterator it(qUpperBound(sorted->begin(), sorted->end(), toAdd, lessThan));
+        sorted->insert(it, toAdd);
+    } else {
+        // no sort order? just add it to the end
+        sorted->append(toAdd);
     }
-
-    // hasn't been inserted yet?  append to the list.
-    sorted->append(toAdd);
 }
 
 /*! Sorts the given list of contacts \a cs according to the provided \a sortOrders */
 QList<QContactLocalId> QContactManagerEngine::sortContacts(const QList<QContact>& cs, const QList<QContactSortOrder>& sortOrders)
 {
     QList<QContactLocalId> sortedIds;
-    QList<QContact> sortedContacts;
+    QList<QContact> sortedContacts = cs;
     if (!sortOrders.isEmpty()) {
-        foreach (const QContact& c, cs) {
-            QContactManagerEngine::addSorted(&sortedContacts, c, sortOrders);
-        }
+        ContactLessThan lessThan(&sortOrders);
+        qStableSort(sortedContacts.begin(), sortedContacts.end(), lessThan);
+    }
 
-        foreach(const QContact& c, sortedContacts) {
-            sortedIds.append(c.localId());
-        }
-    } else {
-        foreach(const QContact& c, cs) {
-            sortedIds.append(c.localId());
-        }
+    foreach(const QContact& c, sortedContacts) {
+        sortedIds.append(c.localId());
     }
     return sortedIds;
 }
@@ -2147,9 +2201,13 @@
  */
 void QContactManagerEngine::updateRequestState(QContactAbstractRequest* req, QContactAbstractRequest::State state)
 {
-    if (req->d_ptr->m_state != state) {
-        req->d_ptr->m_state = state;
-        emit req->stateChanged(state);
+    if (req) {
+        QMutexLocker ml(&req->d_ptr->m_mutex);
+        if (req->d_ptr->m_state != state) {
+            req->d_ptr->m_state = state;
+            ml.unlock();
+            emit req->stateChanged(state);
+        }
     }
 }
 
@@ -2163,14 +2221,19 @@
  */
 void QContactManagerEngine::updateContactLocalIdFetchRequest(QContactLocalIdFetchRequest* req, const QList<QContactLocalId>& result, QContactManager::Error error, QContactAbstractRequest::State newState)
 {
-    QContactLocalIdFetchRequestPrivate* rd = static_cast<QContactLocalIdFetchRequestPrivate*>(req->d_ptr);
-    req->d_ptr->m_error = error;
-    rd->m_ids = result;
-    bool emitState = rd->m_state != newState;
-    rd->m_state = newState;
-    emit req->resultsAvailable();
-    if (emitState)
-        emit req->stateChanged(newState);
+    if (req) {
+        QWeakPointer<QContactLocalIdFetchRequest> ireq(req); // Take this in case the first emit deletes us
+        QContactLocalIdFetchRequestPrivate* rd = static_cast<QContactLocalIdFetchRequestPrivate*>(ireq.data()->d_ptr);
+        QMutexLocker ml(&rd->m_mutex);
+        bool emitState = rd->m_state != newState;
+        rd->m_ids = result;
+        rd->m_error = error;
+        rd->m_state = newState;
+        ml.unlock();
+        emit ireq.data()->resultsAvailable();
+        if (emitState && ireq)
+            emit ireq.data()->stateChanged(newState);
+    }
 }
 
 /*!
@@ -2183,14 +2246,19 @@
  */
 void QContactManagerEngine::updateContactFetchRequest(QContactFetchRequest* req, const QList<QContact>& result, QContactManager::Error error, QContactAbstractRequest::State newState)
 {
-    QContactFetchRequestPrivate* rd = static_cast<QContactFetchRequestPrivate*>(req->d_ptr);
-    req->d_ptr->m_error = error;
-    rd->m_contacts = result;
-    bool emitState = rd->m_state != newState;
-    rd->m_state = newState;
-    emit req->resultsAvailable();
-    if (emitState)
-        emit req->stateChanged(newState);
+    if (req) {
+        QWeakPointer<QContactFetchRequest> ireq(req); // Take this in case the first emit deletes us
+        QContactFetchRequestPrivate* rd = static_cast<QContactFetchRequestPrivate*>(ireq.data()->d_ptr);
+        QMutexLocker ml(&rd->m_mutex);
+        bool emitState = rd->m_state != newState;
+        rd->m_contacts = result;
+        rd->m_error = error;
+        rd->m_state = newState;
+        ml.unlock();
+        emit ireq.data()->resultsAvailable();
+        if (emitState && ireq)
+            emit ireq.data()->stateChanged(newState);
+    }
 }
 
 /*!
@@ -2203,14 +2271,19 @@
  */
 void QContactManagerEngine::updateContactRemoveRequest(QContactRemoveRequest* req, QContactManager::Error error, const QMap<int, QContactManager::Error>& errorMap, QContactAbstractRequest::State newState)
 {
-    QContactRemoveRequestPrivate* rd = static_cast<QContactRemoveRequestPrivate*>(req->d_ptr);
-    req->d_ptr->m_error = error;
-    rd->m_errors = errorMap;
-    bool emitState = rd->m_state != newState;
-    rd->m_state = newState;
-    emit req->resultsAvailable();
-    if (emitState)
-        emit req->stateChanged(newState);
+    if (req) {
+        QWeakPointer<QContactRemoveRequest> ireq(req); // Take this in case the first emit deletes us
+        QContactRemoveRequestPrivate* rd = static_cast<QContactRemoveRequestPrivate*>(ireq.data()->d_ptr);
+        QMutexLocker ml(&rd->m_mutex);
+        bool emitState = rd->m_state != newState;
+        rd->m_errors = errorMap;
+        rd->m_error = error;
+        rd->m_state = newState;
+        ml.unlock();
+        emit ireq.data()->resultsAvailable();
+        if (emitState && ireq)
+            emit ireq.data()->stateChanged(newState);
+    }
 }
 
 /*!
@@ -2223,15 +2296,20 @@
  */
 void QContactManagerEngine::updateContactSaveRequest(QContactSaveRequest* req, const QList<QContact>& result, QContactManager::Error error, const QMap<int, QContactManager::Error>& errorMap, QContactAbstractRequest::State newState)
 {
-    QContactSaveRequestPrivate* rd = static_cast<QContactSaveRequestPrivate*>(req->d_ptr);
-    req->d_ptr->m_error = error;
-    rd->m_errors = errorMap;
-    rd->m_contacts = result;
-    bool emitState = rd->m_state != newState;
-    rd->m_state = newState;
-    emit req->resultsAvailable();
-    if (emitState)
-        emit req->stateChanged(newState);
+    if (req) {
+        QWeakPointer<QContactSaveRequest> ireq(req); // Take this in case the first emit deletes us
+        QContactSaveRequestPrivate* rd = static_cast<QContactSaveRequestPrivate*>(ireq.data()->d_ptr);
+        QMutexLocker ml(&rd->m_mutex);
+        bool emitState = rd->m_state != newState;
+        rd->m_contacts = result;
+        rd->m_errors = errorMap;
+        rd->m_error = error;
+        rd->m_state = newState;
+        ml.unlock();
+        emit ireq.data()->resultsAvailable();
+        if (emitState && ireq)
+            emit ireq.data()->stateChanged(newState);
+    }
 }
 
 /*!
@@ -2244,15 +2322,20 @@
  */
 void QContactManagerEngine::updateDefinitionSaveRequest(QContactDetailDefinitionSaveRequest* req, const QList<QContactDetailDefinition>& result, QContactManager::Error error, const QMap<int, QContactManager::Error>& errorMap, QContactAbstractRequest::State newState)
 {
-    QContactDetailDefinitionSaveRequestPrivate* rd = static_cast<QContactDetailDefinitionSaveRequestPrivate*>(req->d_ptr);
-    req->d_ptr->m_error = error;
-    rd->m_errors = errorMap;
-    rd->m_definitions = result;
-    bool emitState = rd->m_state != newState;
-    rd->m_state = newState;
-    emit req->resultsAvailable();
-    if (emitState)
-        emit req->stateChanged(newState);
+    if (req) {
+        QWeakPointer<QContactDetailDefinitionSaveRequest> ireq(req); // Take this in case the first emit deletes us
+        QContactDetailDefinitionSaveRequestPrivate* rd = static_cast<QContactDetailDefinitionSaveRequestPrivate*>(req->d_ptr);
+        QMutexLocker ml(&rd->m_mutex);
+        bool emitState = rd->m_state != newState;
+        rd->m_definitions = result;
+        rd->m_errors = errorMap;
+        rd->m_error = error;
+        rd->m_state = newState;
+        ml.unlock();
+        emit ireq.data()->resultsAvailable();
+        if (emitState && ireq)
+            emit ireq.data()->stateChanged(newState);
+    }
 }
 
 /*!
@@ -2265,14 +2348,19 @@
  */
 void QContactManagerEngine::updateDefinitionRemoveRequest(QContactDetailDefinitionRemoveRequest* req, QContactManager::Error error, const QMap<int, QContactManager::Error>& errorMap, QContactAbstractRequest::State newState)
 {
-    QContactDetailDefinitionRemoveRequestPrivate* rd = static_cast<QContactDetailDefinitionRemoveRequestPrivate*>(req->d_ptr);
-    req->d_ptr->m_error = error;
-    rd->m_errors = errorMap;
-    bool emitState = rd->m_state != newState;
-    rd->m_state = newState;
-    emit req->resultsAvailable();
-    if (emitState)
-        emit req->stateChanged(newState);
+    if (req) {
+        QWeakPointer<QContactDetailDefinitionRemoveRequest> ireq(req); // Take this in case the first emit deletes us
+        QContactDetailDefinitionRemoveRequestPrivate* rd = static_cast<QContactDetailDefinitionRemoveRequestPrivate*>(req->d_ptr);
+        QMutexLocker ml(&rd->m_mutex);
+        bool emitState = rd->m_state != newState;
+        rd->m_errors = errorMap;
+        rd->m_error = error;
+        rd->m_state = newState;
+        ml.unlock();
+        emit ireq.data()->resultsAvailable();
+        if (emitState && ireq)
+            emit ireq.data()->stateChanged(newState);
+    }
 }
 
 /*!
@@ -2285,15 +2373,20 @@
  */
 void QContactManagerEngine::updateDefinitionFetchRequest(QContactDetailDefinitionFetchRequest* req, const QMap<QString, QContactDetailDefinition>& result, QContactManager::Error error, const QMap<int, QContactManager::Error>& errorMap, QContactAbstractRequest::State newState)
 {
-    QContactDetailDefinitionFetchRequestPrivate* rd = static_cast<QContactDetailDefinitionFetchRequestPrivate*>(req->d_ptr);
-    req->d_ptr->m_error = error;
-    rd->m_errors = errorMap;
-    rd->m_definitions = result;
-    bool emitState = rd->m_state != newState;
-    rd->m_state = newState;
-    emit req->resultsAvailable();
-    if (emitState)
-        emit req->stateChanged(newState);
+    if (req) {
+        QWeakPointer<QContactDetailDefinitionFetchRequest> ireq(req); // Take this in case the first emit deletes us
+        QContactDetailDefinitionFetchRequestPrivate* rd = static_cast<QContactDetailDefinitionFetchRequestPrivate*>(req->d_ptr);
+        QMutexLocker ml(&rd->m_mutex);
+        bool emitState = rd->m_state != newState;
+        rd->m_definitions = result;
+        rd->m_errors = errorMap;
+        rd->m_error = error;
+        rd->m_state = newState;
+        ml.unlock();
+        emit ireq.data()->resultsAvailable();
+        if (emitState && ireq)
+            emit ireq.data()->stateChanged(newState);
+    }
 }
 
 /*!
@@ -2306,15 +2399,20 @@
  */
 void QContactManagerEngine::updateRelationshipSaveRequest(QContactRelationshipSaveRequest* req, const QList<QContactRelationship>& result, QContactManager::Error error, const QMap<int, QContactManager::Error>& errorMap, QContactAbstractRequest::State newState)
 {
-    QContactRelationshipSaveRequestPrivate* rd = static_cast<QContactRelationshipSaveRequestPrivate*>(req->d_ptr);
-    req->d_ptr->m_error = error;
-    rd->m_errors = errorMap;
-    rd->m_relationships = result;
-    bool emitState = rd->m_state != newState;
-    rd->m_state = newState;
-    emit req->resultsAvailable();
-    if (emitState)
-        emit req->stateChanged(newState);
+    if (req) {
+        QWeakPointer<QContactRelationshipSaveRequest> ireq(req); // Take this in case the first emit deletes us
+        QContactRelationshipSaveRequestPrivate* rd = static_cast<QContactRelationshipSaveRequestPrivate*>(req->d_ptr);
+        QMutexLocker ml(&rd->m_mutex);
+        bool emitState = rd->m_state != newState;
+        rd->m_relationships = result;
+        rd->m_errors = errorMap;
+        rd->m_error = error;
+        rd->m_state = newState;
+        ml.unlock();
+        emit ireq.data()->resultsAvailable();
+        if (emitState && ireq)
+            emit ireq.data()->stateChanged(newState);
+    }
 }
 
 /*!
@@ -2327,14 +2425,19 @@
  */
 void QContactManagerEngine::updateRelationshipRemoveRequest(QContactRelationshipRemoveRequest* req, QContactManager::Error error, const QMap<int, QContactManager::Error>& errorMap, QContactAbstractRequest::State newState)
 {
-    QContactRelationshipRemoveRequestPrivate* rd = static_cast<QContactRelationshipRemoveRequestPrivate*>(req->d_ptr);
-    req->d_ptr->m_error = error;
-    rd->m_errors = errorMap;
-    bool emitState = rd->m_state != newState;
-    rd->m_state = newState;
-    emit req->resultsAvailable();
-    if (emitState)
-        emit req->stateChanged(newState);
+    if (req) {
+        QWeakPointer<QContactRelationshipRemoveRequest> ireq(req); // Take this in case the first emit deletes us
+        QContactRelationshipRemoveRequestPrivate* rd = static_cast<QContactRelationshipRemoveRequestPrivate*>(req->d_ptr);
+        QMutexLocker ml(&rd->m_mutex);
+        bool emitState = rd->m_state != newState;
+        rd->m_errors = errorMap;
+        rd->m_error = error;
+        rd->m_state = newState;
+        ml.unlock();
+        emit ireq.data()->resultsAvailable();
+        if (emitState && ireq)
+            emit ireq.data()->stateChanged(newState);
+    }
 }
 
 /*!
@@ -2347,14 +2450,19 @@
  */
 void QContactManagerEngine::updateRelationshipFetchRequest(QContactRelationshipFetchRequest* req, const QList<QContactRelationship>& result, QContactManager::Error error, QContactAbstractRequest::State newState)
 {
-    QContactRelationshipFetchRequestPrivate* rd = static_cast<QContactRelationshipFetchRequestPrivate*>(req->d_ptr);
-    req->d_ptr->m_error = error;
-    rd->m_relationships = result;
-    bool emitState = rd->m_state != newState;
-    rd->m_state = newState;
-    emit req->resultsAvailable();
-    if (emitState)
-        emit req->stateChanged(newState);
+    if (req) {
+        QWeakPointer<QContactRelationshipFetchRequest> ireq(req); // Take this in case the first emit deletes us
+        QContactRelationshipFetchRequestPrivate* rd = static_cast<QContactRelationshipFetchRequestPrivate*>(req->d_ptr);
+        QMutexLocker ml(&rd->m_mutex);
+        bool emitState = rd->m_state != newState;
+        rd->m_relationships = result;
+        rd->m_error = error;
+        rd->m_state = newState;
+        ml.unlock();
+        emit ireq.data()->resultsAvailable();
+        if (emitState && ireq)
+            emit ireq.data()->stateChanged(newState);
+    }
 }
 
 #include "moc_qcontactmanagerengine.cpp"