mirror of git://git.sysmocom.de/ofono
Merge phonebook entries belong to one person
This commit is contained in:
parent
f2f0fd0501
commit
95ec7c126f
|
@ -55,7 +55,7 @@ static void at_cpbr_notify(GAtResult *result, gpointer user_data)
|
|||
const char *number;
|
||||
int type;
|
||||
const char *text;
|
||||
int hidden = 0;
|
||||
int hidden = -1;
|
||||
const char *group = NULL;
|
||||
const char *adnumber = NULL;
|
||||
int adtype = -1;
|
||||
|
|
246
src/phonebook.c
246
src/phonebook.c
|
@ -46,12 +46,39 @@
|
|||
|
||||
#define PHONEBOOK_FLAG_CACHED 0x1
|
||||
|
||||
enum {
|
||||
TEL_TYPE_VOICE,
|
||||
TEL_TYPE_HOME,
|
||||
TEL_TYPE_MOBILE,
|
||||
TEL_TYPE_FAX,
|
||||
TEL_TYPE_WORK
|
||||
};
|
||||
|
||||
struct phonebook_data {
|
||||
struct ofono_phonebook_ops *ops;
|
||||
DBusMessage *pending;
|
||||
int storage_index; /* go through all supported storage */
|
||||
int flags;
|
||||
GString *vcards; /* entries with vcard 3.0 format */
|
||||
GSList *merge_list; /* cache the entries that may need a merge */
|
||||
};
|
||||
|
||||
struct phonebook_number {
|
||||
char *number;
|
||||
int type; /* international or not */
|
||||
int category; /* represent for "WORK", "HOME", etc */
|
||||
int prefer;
|
||||
};
|
||||
|
||||
struct phonebook_person {
|
||||
GSList *number_list; /* one person may have more than one numbers */
|
||||
char *text;
|
||||
int hidden;
|
||||
char *group;
|
||||
char *secondtext;
|
||||
char *email;
|
||||
char *sip_uri;
|
||||
char *tel_uri;
|
||||
};
|
||||
|
||||
static const char *storage_support[] = { "\"SM\"", "\"ME\"", NULL };
|
||||
|
@ -135,20 +162,93 @@ static void add_slash(char *dest, const char *src, int len_max, int len)
|
|||
return;
|
||||
}
|
||||
|
||||
static void vcard_printf_number(GString *entries_vcard_pointer, int type,
|
||||
const char *number, int prefer)
|
||||
static void vcard_printf_begin(GString *vcards)
|
||||
{
|
||||
char *pref = "", *intl = "";
|
||||
vcard_printf(vcards, "BEGIN:VCARD");
|
||||
vcard_printf(vcards, "VERSION:3.0");
|
||||
}
|
||||
|
||||
static void vcard_printf_text(GString *vcards, const char *text)
|
||||
{
|
||||
char field[LEN_MAX];
|
||||
add_slash(field, text, LEN_MAX, strlen(text));
|
||||
vcard_printf(vcards, "FN:%s", field);
|
||||
}
|
||||
|
||||
static void vcard_printf_number(GString *vcards, const char *number, int type,
|
||||
int category, int prefer)
|
||||
{
|
||||
char *pref = "", *intl = "", *category_string = "";
|
||||
char buf[128];
|
||||
|
||||
if (!number || !strlen(number) || !type)
|
||||
return;
|
||||
|
||||
if (prefer)
|
||||
pref = "PREF,";
|
||||
|
||||
switch (category) {
|
||||
case TEL_TYPE_HOME:
|
||||
category_string = "HOME";
|
||||
break;
|
||||
case TEL_TYPE_MOBILE:
|
||||
category_string = "CELL";
|
||||
break;
|
||||
case TEL_TYPE_FAX:
|
||||
category_string = "FAX";
|
||||
break;
|
||||
case TEL_TYPE_WORK:
|
||||
category_string = "WORK";
|
||||
break;
|
||||
case TEL_TYPE_VOICE:
|
||||
default:
|
||||
category_string = "VOICE";
|
||||
break;
|
||||
}
|
||||
|
||||
if ((type == TYPE_INTERNATIONAL) && (number[0] != '+'))
|
||||
intl = "+";
|
||||
|
||||
sprintf(buf, "TEL;TYPE=\%sVOICE:\%s\%s", pref, intl, number);
|
||||
vcard_printf(entries_vcard_pointer, buf, number);
|
||||
sprintf(buf, "TEL;TYPE=\%s%s:\%s\%s", pref,
|
||||
category_string, intl, number);
|
||||
vcard_printf(vcards, buf, number);
|
||||
}
|
||||
|
||||
static void vcard_printf_group(GString *vcards, const char *group)
|
||||
{
|
||||
int len = strlen(group);
|
||||
if (group && len) {
|
||||
char field[LEN_MAX];
|
||||
add_slash(field, group, LEN_MAX, len);
|
||||
vcard_printf(vcards, "CATEGORIES:%s", field);
|
||||
}
|
||||
}
|
||||
|
||||
static void vcard_printf_email(GString *vcards, const char *email)
|
||||
{
|
||||
int len = strlen(email);
|
||||
if (email && len) {
|
||||
char field[LEN_MAX];
|
||||
add_slash(field, email, LEN_MAX, len);
|
||||
vcard_printf(vcards,
|
||||
"EMAIL;TYPE=INTERNET:%s", field);
|
||||
}
|
||||
}
|
||||
|
||||
static void vcard_printf_sip_uri(GString *vcards, const char *sip_uri)
|
||||
{
|
||||
int len = strlen(sip_uri);
|
||||
if (sip_uri && len) {
|
||||
char field[LEN_MAX];
|
||||
add_slash(field, sip_uri, LEN_MAX, len);
|
||||
vcard_printf(vcards, "IMPP;TYPE=SIP:%s", field);
|
||||
}
|
||||
}
|
||||
|
||||
static void vcard_printf_end(GString *vcards)
|
||||
{
|
||||
vcard_printf(vcards, "END:VCARD");
|
||||
vcard_printf(vcards, "");
|
||||
}
|
||||
|
||||
static DBusMessage *generate_export_entries_reply(struct ofono_modem *modem,
|
||||
|
@ -169,6 +269,50 @@ static DBusMessage *generate_export_entries_reply(struct ofono_modem *modem,
|
|||
return reply;
|
||||
}
|
||||
|
||||
static gboolean need_merge(const char *text)
|
||||
{
|
||||
int len = strlen(text);
|
||||
char c = text[len-1];
|
||||
if ((text[len-2] == '/') &&
|
||||
((c == 'w') || (c == 'h') || (c == 'm') || (c == 'o')))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void merge_field_generic(char **str1, const char *str2)
|
||||
{
|
||||
if ((*str1 == NULL) && (str2 != NULL))
|
||||
*str1 = g_strdup(str2);
|
||||
}
|
||||
|
||||
static void merge_field_number(GSList **l, const char *number, int type,
|
||||
char c, int prefer)
|
||||
{
|
||||
struct phonebook_number *pn = g_new0(struct phonebook_number, 1);
|
||||
int category;
|
||||
|
||||
pn->number = g_strdup(number);
|
||||
pn->type = type;
|
||||
switch (c) {
|
||||
case 'w':
|
||||
case 'o':
|
||||
category = TEL_TYPE_WORK;
|
||||
break;
|
||||
case 'h':
|
||||
category = TEL_TYPE_HOME;
|
||||
break;
|
||||
case 'm':
|
||||
category = TEL_TYPE_MOBILE;
|
||||
break;
|
||||
default:
|
||||
category = TEL_TYPE_VOICE;
|
||||
break;
|
||||
}
|
||||
pn->category = category;
|
||||
pn->prefer = prefer;
|
||||
*l = g_slist_append(*l, pn);
|
||||
}
|
||||
|
||||
void ofono_phonebook_entry(struct ofono_modem *modem, int index,
|
||||
const char *number, int type,
|
||||
const char *text, int hidden,
|
||||
|
@ -179,37 +323,54 @@ void ofono_phonebook_entry(struct ofono_modem *modem, int index,
|
|||
{
|
||||
struct phonebook_data *phonebook = modem->phonebook;
|
||||
char field[LEN_MAX];
|
||||
int len;
|
||||
|
||||
vcard_printf(phonebook->vcards, "BEGIN:VCARD");
|
||||
vcard_printf(phonebook->vcards, "VERSION:3.0");
|
||||
|
||||
add_slash(field, text, LEN_MAX, strlen(text));
|
||||
|
||||
vcard_printf(phonebook->vcards, "FN:%s", field);
|
||||
vcard_printf_number(phonebook->vcards, type, number, 1);
|
||||
|
||||
if (group && (len = strlen(group))) {
|
||||
add_slash(field, group, LEN_MAX, len);
|
||||
vcard_printf(phonebook->vcards, "CATEGORIES:%s", field);
|
||||
/*
|
||||
* We need to collect all the entries that belong to one person,
|
||||
* so that only one vCard will be generated at last.
|
||||
* Entries only differ with '/w', '/h', '/m', etc. in field text
|
||||
* are deemed as entries of one person.
|
||||
*/
|
||||
if (need_merge(text)) {
|
||||
GSList *l;
|
||||
int has_merge = 0;
|
||||
int len_text = strlen(text);
|
||||
char *text_temp = g_strndup(text, len_text - 2);
|
||||
struct phonebook_person *person;
|
||||
for (l = phonebook->merge_list; l; l = l->next) {
|
||||
person = l->data;
|
||||
if (!strcmp(text_temp, person->text)) {
|
||||
has_merge = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (has_merge == 0) {
|
||||
person = g_new0(struct phonebook_person, 1);
|
||||
phonebook->merge_list = g_slist_append(
|
||||
phonebook->merge_list, person);
|
||||
}
|
||||
merge_field_generic(&(person->text), text_temp);
|
||||
merge_field_number(&(person->number_list), number, type,
|
||||
text[len_text - 1], 1);
|
||||
merge_field_number(&(person->number_list), adnumber, adtype,
|
||||
text[len_text - 1], 0);
|
||||
merge_field_generic(&(person->group), group);
|
||||
merge_field_generic(&(person->secondtext), secondtext);
|
||||
merge_field_generic(&(person->email), email);
|
||||
merge_field_generic(&(person->sip_uri), sip_uri);
|
||||
merge_field_generic(&(person->tel_uri), tel_uri);
|
||||
g_free(text_temp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (adnumber && strlen(adnumber) && adtype != -1)
|
||||
vcard_printf_number(phonebook->vcards, adtype, adnumber, 0);
|
||||
|
||||
if (email && (len = strlen(email))) {
|
||||
add_slash(field, email, LEN_MAX, len);
|
||||
vcard_printf(phonebook->vcards,
|
||||
"EMAIL;TYPE=INTERNET:%s", field);
|
||||
}
|
||||
|
||||
if (sip_uri && (len = strlen(sip_uri))) {
|
||||
add_slash(field, sip_uri, LEN_MAX, len);
|
||||
vcard_printf(phonebook->vcards, "IMPP;TYPE=SIP:%s", field);
|
||||
}
|
||||
|
||||
vcard_printf(phonebook->vcards, "END:VCARD");
|
||||
vcard_printf(phonebook->vcards, "");
|
||||
vcard_printf_begin(phonebook->vcards);
|
||||
vcard_printf_text(phonebook->vcards, text);
|
||||
vcard_printf_number(phonebook->vcards, number, type,
|
||||
TEL_TYPE_VOICE, 1);
|
||||
vcard_printf_number(phonebook->vcards, adnumber, adtype,
|
||||
TEL_TYPE_VOICE, 0);
|
||||
vcard_printf_group(phonebook->vcards, group);
|
||||
vcard_printf_email(phonebook->vcards, email);
|
||||
vcard_printf_sip_uri(phonebook->vcards, sip_uri);
|
||||
vcard_printf_end(phonebook->vcards);
|
||||
}
|
||||
|
||||
static void export_phonebook_cb(const struct ofono_error *error, void *data)
|
||||
|
@ -232,6 +393,7 @@ static void export_phonebook(struct ofono_modem *modem)
|
|||
struct phonebook_data *phonebook = modem->phonebook;
|
||||
DBusMessage *reply;
|
||||
const char *pb = storage_support[phonebook->storage_index];
|
||||
GSList *l, *m;
|
||||
|
||||
if (pb) {
|
||||
phonebook->ops->export_entries(modem, pb,
|
||||
|
@ -239,6 +401,22 @@ static void export_phonebook(struct ofono_modem *modem)
|
|||
return;
|
||||
}
|
||||
|
||||
/* convert the collected entries that are already merged to vcard */
|
||||
for (l = phonebook->merge_list; l; l = l->next) {
|
||||
struct phonebook_person *person = l->data;
|
||||
vcard_printf_begin(phonebook->vcards);
|
||||
vcard_printf_text(phonebook->vcards, person->text);
|
||||
for (m = person->number_list; m; m = m->next) {
|
||||
struct phonebook_number *pn = m->data;
|
||||
vcard_printf_number(phonebook->vcards, pn->number,
|
||||
pn->type, pn->category, pn->prefer);
|
||||
}
|
||||
vcard_printf_group(phonebook->vcards, person->group);
|
||||
vcard_printf_email(phonebook->vcards, person->email);
|
||||
vcard_printf_sip_uri(phonebook->vcards, person->sip_uri);
|
||||
vcard_printf_end(phonebook->vcards);
|
||||
}
|
||||
|
||||
reply = generate_export_entries_reply(modem, phonebook->pending);
|
||||
|
||||
if (!reply) {
|
||||
|
|
Loading…
Reference in New Issue