summaryrefslogtreecommitdiffstats
path: root/src/phonebook.c
diff options
context:
space:
mode:
authorYang Gu <yang.gu@intel.com>2009-06-22 10:59:25 +0800
committerDenis Kenzior <denkenz@gmail.com>2009-06-22 13:22:13 -0500
commit95ec7c126f65417e2041cd8f3080f801879d5035 (patch)
tree1c47b2c121360d2e83bd25d7a037b00aa9664b4e /src/phonebook.c
parentf2f0fd0501dd16a3af710367474ad37f1d689861 (diff)
downloadofono-95ec7c126f65417e2041cd8f3080f801879d5035.tar.bz2
Merge phonebook entries belong to one person
Diffstat (limited to 'src/phonebook.c')
-rw-r--r--src/phonebook.c246
1 files changed, 212 insertions, 34 deletions
diff --git a/src/phonebook.c b/src/phonebook.c
index fa05d43b..4cfb04e0 100644
--- a/src/phonebook.c
+++ b/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)
+{
+ vcard_printf(vcards, "BEGIN:VCARD");
+ vcard_printf(vcards, "VERSION:3.0");
+}
+
+static void vcard_printf_text(GString *vcards, const char *text)
{
- char *pref = "", *intl = "";
+ 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);
- }
-
- 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);
+ /*
+ * 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;
}
- 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) {