summaryrefslogtreecommitdiffstats
path: root/pbap.cpp
diff options
context:
space:
mode:
authorMatt Porter <mporter@konsulko.com>2018-06-19 14:56:26 -0400
committerMatt Porter <mporter@konsulko.com>2018-06-22 16:38:30 -0400
commite8b328e0516d8ead9af13c8379a6cd1dbbb8a9e9 (patch)
treedec002e6adcf197c3ac7913fb211b65b73772bc9 /pbap.cpp
parentfc65716b43af6be84d42599d813d3d40df07d376 (diff)
pbap: add contacts support and recent call model
Add support for parsing contacts and recent call data from the PBAP-provided vCards using libvcard. Expose a recent call list model and interfaces to refresh the data. Bug-AGL: SPEC-1436 Change-Id: Ia4a02443e22e4a27dc974ef414b765667b26ff83 Signed-off-by: Matt Porter <mporter@konsulko.com>
Diffstat (limited to 'pbap.cpp')
-rw-r--r--pbap.cpp227
1 files changed, 224 insertions, 3 deletions
diff --git a/pbap.cpp b/pbap.cpp
index a833b9f..43db8bd 100644
--- a/pbap.cpp
+++ b/pbap.cpp
@@ -14,17 +14,80 @@
* limitations under the License.
*/
+#include <QMetaEnum>
+#include <QtQml/QQmlEngine>
+
+#include <vcard/vcard.h>
+
#include "message.h"
#include "messageengine.h"
#include "pbap.h"
#include "pbapmessage.h"
#include "responsemessage.h"
-Pbap::Pbap (QUrl &url, QObject * parent) :
+PhoneNumber::PhoneNumber(QString number, QString type)
+{
+ m_number = number;
+ m_type = stringToEnum(type);
+}
+
+PhoneNumber::~PhoneNumber()
+{
+}
+
+int PhoneNumber::stringToEnum(QString key)
+{
+ const QMetaObject* metaObject = PhoneNumber::metaObject();
+ int enumIndex = metaObject->indexOfEnumerator("PhoneNumberType");
+ QMetaEnum mEnum = metaObject->enumerator(enumIndex);
+
+ int value = mEnum.keyToValue(key.toUtf8().data());
+ return (value < 0) ? 0 : value;
+}
+
+Contact::Contact(QString name, QList<QObject *>numbers)
+{
+ m_name = name;
+ m_numbers = numbers;
+}
+
+Contact::~Contact()
+{
+}
+
+RecentCall::RecentCall(QString name, QString number, QString datetime, QString type)
+{
+ m_name = name;
+ m_number = number;
+ m_datetime = datetime;
+ m_type = stringToEnum(type);
+}
+
+RecentCall::~RecentCall()
+{
+}
+
+int RecentCall::stringToEnum(QString key)
+{
+ const QMetaObject* metaObject = RecentCall::metaObject();
+ int enumIndex = metaObject->indexOfEnumerator("RecentCallType");
+ QMetaEnum mEnum = metaObject->enumerator(enumIndex);
+
+ int value = mEnum.keyToValue(key.toUtf8().data());
+ return (value < 0) ? 0 : value;
+}
+
+Pbap::Pbap (QUrl &url, QQmlContext *context, QObject * parent) :
QObject(parent),
m_mloop(nullptr)
{
m_mloop = new MessageEngine(url);
+ m_context = context;
+ m_context->setContextProperty("RecentCallModel", QVariant::fromValue(m_calls));
+ qmlRegisterUncreatableType<RecentCall>("RecentCall", 1, 0, "RecentCall", "Enum");
+
+ QObject::connect(m_mloop, &MessageEngine::connected, this, &Pbap::onConnected);
+ QObject::connect(m_mloop, &MessageEngine::disconnected, this, &Pbap::onDisconnected);
QObject::connect(m_mloop, &MessageEngine::messageReceived, this, &Pbap::onMessageReceived);
}
@@ -33,6 +96,33 @@ Pbap::~Pbap()
delete m_mloop;
}
+void Pbap::refreshContacts(int max_entries)
+{
+ PbapMessage *tmsg = new PbapMessage();
+ QJsonObject parameter;
+
+ if (max_entries >= 0)
+ parameter.insert("max_entries", max_entries);
+
+ tmsg->createRequest("contacts", parameter);
+ m_mloop->sendMessage(tmsg);
+ tmsg->deleteLater();
+}
+
+void Pbap::refreshCalls(int max_entries)
+{
+ PbapMessage *tmsg = new PbapMessage();
+ QJsonObject parameter;
+
+ parameter.insert("list", "cch");
+ if (max_entries >= 0)
+ parameter.insert("max_entries", max_entries);
+
+ tmsg->createRequest("history", parameter);
+ m_mloop->sendMessage(tmsg);
+ tmsg->deleteLater();
+}
+
void Pbap::search(QString number)
{
PbapMessage *tmsg = new PbapMessage();
@@ -47,6 +137,94 @@ void Pbap::search(QString number)
tmsg->deleteLater();
}
+void Pbap::updateContacts(QString vcards)
+{
+ QString name, number, type;
+
+ QList<vCard> contacts_vcards = vCard::fromByteArray(vcards.toUtf8());
+
+ for (auto vcard : contacts_vcards) {
+ vCardProperty name_prop = vcard.property(VC_FORMATTED_NAME);
+ QStringList values = name_prop.values();
+ name = values.at(vCardProperty::DefaultValue);
+ /*
+ * libvcard has no member function to return a list of named
+ * properties, so we iterate over all properties and parse
+ * each identified VC_TELEPHONE property in the vCard.
+ */
+ QList<QObject *> numbers;
+ vCardPropertyList properties = vcard.properties();
+ for (auto property : properties) {
+ if (property.isValid() && (property.name() == VC_TELEPHONE)) {
+ QStringList values = property.values();
+ number = values.at(0);
+ vCardParamList params = property.params();
+ // The first parameter is always the phone number type
+ type = params.at(0).value();
+ numbers.append(new PhoneNumber(number, type));
+ }
+ }
+ m_contacts.append(new Contact(name, numbers));
+ }
+ refreshCalls(100);
+}
+
+#define VC_DATETIME "X-IRMC-CALL-DATETIME"
+
+void Pbap::updateCalls(QString vcards)
+{
+ QString name, number, datetime, type;
+
+ QList<vCard> history_vcards = vCard::fromByteArray(vcards.toUtf8());
+
+ for (auto vcard : history_vcards) {
+ vCardProperty number_prop = vcard.property(VC_TELEPHONE);
+ if (number_prop.isValid()) {
+ QStringList values = number_prop.values();
+ number = values.at(0);
+ }
+ vCardProperty name_prop = vcard.property(VC_FORMATTED_NAME);
+ QStringList values = name_prop.values();
+ name = values.at(0);
+ // For calls with an empty name, fetch the name from contacts
+ if (name.isEmpty()) {
+ bool found = false;
+ for (auto contact_obj : m_contacts) {
+ Contact *contact = qobject_cast<Contact *>(contact_obj);
+ QList<QObject *>numbers = contact->numbers();
+ for (auto number_obj : numbers) {
+ PhoneNumber *phone_number = qobject_cast<PhoneNumber *>(number_obj);
+ if (number.endsWith(phone_number->number())) {
+ name = contact->name();
+ found = true;
+ break;
+ }
+ }
+ if (found == true)
+ break;
+ }
+ if (!found)
+ name = number;
+ }
+ vCardProperty datetime_prop = vcard.property(VC_DATETIME);
+ if (datetime_prop.isValid()) {
+ vCardParamList params = datetime_prop.params();
+ QStringList values = datetime_prop.values();
+ type = params.at(0).value();
+ datetime = values.at(0);
+ // Convert the PBAP date/time to ISO 8601 format
+ datetime.insert(4, '-');
+ datetime.insert(7, '-');
+ datetime.insert(13, ':');
+ datetime.insert(16, ':');
+ }
+ m_calls.append(new RecentCall(name, number, datetime, type));
+ }
+
+ // Refresh model
+ m_context->setContextProperty("RecentCallModel", QVariant::fromValue(m_calls));
+}
+
void Pbap::sendSearchResults(QJsonArray results)
{
QString name;
@@ -59,12 +237,55 @@ void Pbap::sendSearchResults(QJsonArray results)
emit searchResults(name);
}
+void Pbap::onConnected()
+{
+ QStringListIterator eventIterator(events);
+ PbapMessage *tmsg;
+
+ while (eventIterator.hasNext()) {
+ tmsg = new PbapMessage();
+ QJsonObject parameter;
+ parameter.insert("value", eventIterator.next());
+ tmsg->createRequest("subscribe", parameter);
+ m_mloop->sendMessage(tmsg);
+ tmsg->deleteLater();
+ }
+}
+
+void Pbap::onDisconnected()
+{
+ QStringListIterator eventIterator(events);
+ PbapMessage *tmsg;
+
+ while (eventIterator.hasNext()) {
+ tmsg = new PbapMessage();
+ QJsonObject parameter;
+ parameter.insert("value", eventIterator.next());
+ tmsg->createRequest("unsubscribe", parameter);
+ m_mloop->sendMessage(tmsg);
+ tmsg->deleteLater();
+ }
+}
+
void Pbap::onMessageReceived(MessageType type, Message *msg)
{
- if (msg->isReply() && type == ResponseRequestMessage) {
+ if (msg->isEvent() && type == PbapEventMessage) {
+ PbapMessage *tmsg = qobject_cast<PbapMessage*>(msg);
+
+ if (tmsg->isStatusEvent()) {
+ emit statusChanged(tmsg->connected());
+ if (tmsg->connected() == true) {
+ refreshContacts(-1);
+ }
+ }
+ } else if (msg->isReply() && type == ResponseRequestMessage) {
ResponseMessage *tmsg = qobject_cast<ResponseMessage*>(msg);
- if (tmsg->requestVerb() == "search") {
+ if (tmsg->requestVerb() == "contacts") {
+ updateContacts(tmsg->replyData().value("vcards").toString());
+ } else if (tmsg->requestVerb() == "history") {
+ updateCalls(tmsg->replyData().value("vcards").toString());
+ } else if (tmsg->requestVerb() == "search") {
sendSearchResults(tmsg->replyData().value("results").toArray());
}
}