SUMMARY = "AGL demo control panel"
LICENSE = "Apache-2.0"
LIC_FILES_CHKSUM = "file://LICENSE;md5=685e0faaaec2c2334cf8159ca6bd2975"
PV = "1.0+git${SRCPV}"
SRC_URI = "git://gerrit.automotivelinux.org/gerrit/src/agl-demo-control-panel;protocol=htt/*
* Copyright (C) 2019 Konsulko Group
* Author: Matt Ranostay <matt.ranostay@konsulko.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define _GNU_SOURCE
#include <errno.h>
#include <string.h>
#include <glib.h>
#include <json-c/json.h>
#define CRLF "\r\n"
#define SUPPORTED_VERSION "3.0"
enum {
VC_FORMATTED_NAME,
VC_TELEPHONE,
VC_DATETIME,
VC_PHOTO,
VC_FIELD_COUNT,
};
static const gchar *VC_PREFIXES[VC_FIELD_COUNT] = {
"FN",
"TEL",
"X-IRMC-CALL-DATETIME",
"PHOTO",
};
#define vc_len(name) strlen(VC_PREFIXES[name])
#define vc_strstr(ptr, name) \
({ \
void *_ptr = strstr(ptr, name); \
if (_ptr) _ptr += strlen(name); \
_ptr; \
})
static void add_fn(json_object *resp, gchar *msg)
{
gchar *name = strstr(msg, ":");
if (!name || !strlen(name + 1))
return;
json_object_object_add(resp, "fn", json_object_new_string(++name));
}
static void add_phone(json_object *array, gchar *msg)
{
gchar *ptr = strstr(msg, ":");
json_object *dict, *number;
if (!ptr || !strlen(ptr + 1))
return;
number = json_object_new_string(ptr + 1);
ptr = vc_strstr(msg, "TYPE=");
if (!ptr)
ptr = "UNKNOWN";
else
ptr = strsep(&ptr, ",;:");
dict = json_object_new_object();
json_object_object_add(dict, ptr, number);
json_object_array_add(array, dict);
}
static void add_datetime(json_object *resp, gchar *msg)
{
gchar *ptr;
msg += vc_len(VC_DATETIME) + 1;
ptr = strsep(&msg, ":");
if (!ptr)
return;
json_object_object_add(resp, "type", json_object_new_string(ptr));
ptr = strsep(&msg, "");
if (!ptr)
return;
json_object_object_add(resp, "timestamp", json_object_new_string(ptr));
}
static gchar **extract_photo(json_object *resp, gchar **msg)
{
GString *data;
gchar *ptr;
json_object *obj;
// TODO: handle other mimetypes
if (!strstr(*msg, "TYPE=JPEG"))
return msg;
ptr = strstr(*msg, ":");
if (!ptr)
return msg;
data = g_string_new(NULL);
g_string_append(data, ptr + 1);
if (!*msg++)
return msg;
for (; *msg; msg++) {
if (!strlen(*msg))
break;
if (!g_ascii_isspace(**msg))
break;
g_string_append(data, g_strchug(*msg));
}
obj = json_object_new_object();
json_object_object_add(obj, "mimetype", json_object_new_string("image/jpeg"));
json_object_object_add(obj, "data", json_object_new_string(data->str));
json_object_object_add(resp, "photo", obj);
g_string_free(data, TRUE);
return msg;
}
static int tag_index(gchar *msg)
{
gchar *ptr;
int i;
for (i = 0; i < VC_FIELD_COUNT; i++) {
if (!g_str_has_prefix(msg, VC_PREFIXES[i]))
continue;
ptr = vc_strstr(msg, VC_PREFIXES[i]);
if (*ptr == ':' || *ptr == ';')
return i;
break;
}
return -EINVAL;
}
static void process_vcard(json_object *resp, gchar **start, gchar **end)
{
json_object *vcard = json_object_new_object();
json_object *phone = NULL;
gboolean history = FALSE;
for (; start != end; start++) {
int idx = tag_index(*start);
switch (idx) {
case VC_FORMATTED_NAME:
add_fn(vcard, *start);
break;
case VC_TELEPHONE:
if (!phone)
phone = json_object_new_array();
add_phone(phone, *start);
break;
case VC_DATETIME:
history = TRUE;
add_datetime(vcard, *start);
break;
case VC_PHOTO:
start = extract_photo(vcard, start);
break;
default:
continue;
}
}
if (phone) {
if (!json_object_array_length(phone)) {
// No phone numbers, so discard
json_object_put(phone);
json_object_put(vcard);
return;
}
if (!history)
json_object_object_add(vcard, "telephone", phone);
else {
json_object *number = json_object_array_get_idx(phone, 0);
json_object_object_foreach(number, unused, val) {
json_object_object_add(vcard, "telephone", val);
(void) unused;
}
}
}
json_object_array_add(resp, vcard);
}
json_object *parse_vcards(const char *message)
{
gchar **lines, **tmp, **ptr = NULL;
json_object *resp;
if (!message || !strlen(message))
return NULL;
resp = json_object_new_array();
lines = g_strsplit(message, CRLF, -1);
for (tmp = lines; *tmp; tmp++) {
// BEGIN:VCARD
if (!g_strcmp0(*tmp, "BEGIN:VCARD")) {
ptr = tmp + 1;
continue;
}
if (!ptr)
continue;
// VERSION should be the line after BEGIN:VCARD
if (tmp == ptr && g_strcmp0(*tmp, "VERSION:" SUPPORTED_VERSION)) {
ptr = NULL;
continue;
}
// END:VCARD
if (!g_strcmp0(*tmp, "END:VCARD")) {
process_vcard(resp, ptr, tmp);
ptr = NULL;
}
}
g_strfreev(lines);
return resp;
}