2
* oFono - GSM Telephony Stack for Linux
4
* Copyright (C) 2008-2009 Intel Corporation. All rights reserved.
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
40
#define PHONEBOOK_INTERFACE "org.ofono.Phonebook"
42
#define TYPE_INTERNATIONAL 145
44
#define PHONEBOOK_FLAG_CACHED 0x1
46
enum phonebook_number_type {
54
struct phonebook_data {
55
struct ofono_phonebook_ops *ops;
57
int storage_index; /* go through all supported storage */
59
GString *vcards; /* entries with vcard 3.0 format */
60
GSList *merge_list; /* cache the entries that may need a merge */
63
struct phonebook_number {
66
enum phonebook_number_type category;
69
struct phonebook_person {
70
GSList *number_list; /* one person may have more than one numbers */
78
static const char *storage_support[] = { "SM", "ME", NULL };
79
static void export_phonebook(struct ofono_modem *modem);
81
static struct phonebook_data *phonebook_create()
83
struct phonebook_data *phonebook;
84
phonebook = g_try_new0(struct phonebook_data, 1);
89
phonebook->vcards = g_string_new(NULL);
94
static void phonebook_destroy(gpointer data)
96
struct ofono_modem *modem = data;
97
struct phonebook_data *phonebook = modem->phonebook;
99
g_string_free(phonebook->vcards, TRUE);
102
modem->phonebook = NULL;
105
/* according to RFC 2425, the output string may need folding */
106
static void vcard_printf(GString *str, const char *fmt, ...)
110
int len_temp, line_number, i;
111
unsigned int line_delimit = 75;
114
vsnprintf(buf, sizeof(buf), fmt, ap);
117
line_number = strlen(buf) / line_delimit + 1;
119
for (i = 0; i < line_number; i++) {
120
len_temp = MIN(line_delimit, strlen(buf) - line_delimit * i);
121
g_string_append_len(str, buf + line_delimit * i, len_temp);
122
if (i != line_number - 1)
123
g_string_append(str, "\r\n ");
126
g_string_append(str, "\r\n");
129
/* According to RFC 2426, we need escape following characters:
130
* '\n', '\r', ';', ',', '\'.
132
static void add_slash(char *dest, const char *src, int len_max, int len)
136
for (i = 0, j = 0; i < len && j < len_max; i++, j++) {
159
static void vcard_printf_begin(GString *vcards)
161
vcard_printf(vcards, "BEGIN:VCARD");
162
vcard_printf(vcards, "VERSION:3.0");
165
static void vcard_printf_text(GString *vcards, const char *text)
168
add_slash(field, text, LEN_MAX, strlen(text));
169
vcard_printf(vcards, "FN:%s", field);
172
static void vcard_printf_number(GString *vcards, const char *number, int type,
173
enum phonebook_number_type category)
175
char *pref = "", *intl = "", *category_string = "";
178
if (!number || !strlen(number) || !type)
183
category_string = "HOME,VOICE";
185
case TEL_TYPE_MOBILE:
186
category_string = "CELL,VOICE";
189
category_string = "FAX";
192
category_string = "WORK,VOICE";
195
category_string = "VOICE";
199
if ((type == TYPE_INTERNATIONAL) && (number[0] != '+'))
202
sprintf(buf, "TEL;TYPE=\%s%s:\%s\%s", pref,
203
category_string, intl, number);
204
vcard_printf(vcards, buf, number);
207
static void vcard_printf_group(GString *vcards, const char *group)
216
add_slash(field, group, LEN_MAX, len);
217
vcard_printf(vcards, "CATEGORIES:%s", field);
221
static void vcard_printf_email(GString *vcards, const char *email)
230
add_slash(field, email, LEN_MAX, len);
232
"EMAIL;TYPE=INTERNET:%s", field);
236
static void vcard_printf_sip_uri(GString *vcards, const char *sip_uri)
241
len = strlen(sip_uri);
245
add_slash(field, sip_uri, LEN_MAX, len);
246
vcard_printf(vcards, "IMPP;TYPE=SIP:%s", field);
250
static void vcard_printf_end(GString *vcards)
252
vcard_printf(vcards, "END:VCARD");
253
vcard_printf(vcards, "");
256
static void print_number(struct phonebook_number *pn, GString *vcards)
258
vcard_printf_number(vcards, pn->number, pn->type, pn->category);
261
static void destroy_number(struct phonebook_number *pn)
267
static void print_merged_entry(struct phonebook_person *person, GString *vcards)
269
vcard_printf_begin(vcards);
270
vcard_printf_text(vcards, person->text);
272
g_slist_foreach(person->number_list, (GFunc)print_number, vcards);
274
vcard_printf_group(vcards, person->group);
275
vcard_printf_email(vcards, person->email);
276
vcard_printf_sip_uri(vcards, person->sip_uri);
277
vcard_printf_end(vcards);
280
static void destroy_merged_entry(struct phonebook_person *person)
282
g_free(person->text);
283
g_free(person->group);
284
g_free(person->email);
285
g_free(person->sip_uri);
287
g_slist_foreach(person->number_list, (GFunc)destroy_number, NULL);
288
g_slist_free(person->number_list);
293
static DBusMessage *generate_export_entries_reply(struct ofono_modem *modem,
296
struct phonebook_data *phonebook = modem->phonebook;
298
DBusMessageIter iter;
300
reply = dbus_message_new_method_return(msg);
304
dbus_message_iter_init_append(reply, &iter);
305
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
310
static gboolean need_merge(const char *text)
323
c = tolower(text[len-1]);
325
if ((text[len-2] == '/') &&
326
((c == 'w') || (c == 'h') || (c == 'm') || (c == 'o')))
332
static void merge_field_generic(char **str1, const char *str2)
334
if ((*str1 == NULL) && (str2 != NULL) && (strlen(str2) != 0))
335
*str1 = g_strdup(str2);
338
static void merge_field_number(GSList **l, const char *number, int type, char c)
340
struct phonebook_number *pn = g_new0(struct phonebook_number, 1);
341
enum phonebook_number_type category;
343
pn->number = g_strdup(number);
345
switch (tolower(c)) {
347
category = TEL_TYPE_WORK;
350
category = TEL_TYPE_HOME;
353
category = TEL_TYPE_MOBILE;
356
category = TEL_TYPE_FAX;
360
category = TEL_TYPE_OTHER;
363
pn->category = category;
364
*l = g_slist_append(*l, pn);
367
void ofono_phonebook_entry(struct ofono_modem *modem, int index,
368
const char *number, int type,
369
const char *text, int hidden,
371
const char *adnumber, int adtype,
372
const char *secondtext, const char *email,
373
const char *sip_uri, const char *tel_uri)
375
struct phonebook_data *phonebook = modem->phonebook;
377
/* There's really nothing to do */
378
if ((number == NULL || number[0] == '\0') &&
379
(text == NULL || text[0] == '\0'))
383
* We need to collect all the entries that belong to one person,
384
* so that only one vCard will be generated at last.
385
* Entries only differ with '/w', '/h', '/m', etc. in field text
386
* are deemed as entries of one person.
388
if (need_merge(text)) {
390
size_t len_text = strlen(text) - 2;
391
struct phonebook_person *person;
393
for (l = phonebook->merge_list; l; l = l->next) {
395
if (!strncmp(text, person->text, len_text) &&
396
(strlen(person->text) == len_text))
401
person = g_new0(struct phonebook_person, 1);
402
phonebook->merge_list =
403
g_slist_prepend(phonebook->merge_list, person);
404
person->text = g_strndup(text, len_text);
407
merge_field_number(&(person->number_list), number, type,
409
merge_field_number(&(person->number_list), adnumber, adtype,
412
merge_field_generic(&(person->group), group);
413
merge_field_generic(&(person->email), email);
414
merge_field_generic(&(person->sip_uri), sip_uri);
419
vcard_printf_begin(phonebook->vcards);
421
if (text == NULL || text[0] == '\0')
422
vcard_printf_text(phonebook->vcards, number);
424
vcard_printf_text(phonebook->vcards, text);
426
vcard_printf_number(phonebook->vcards, number, type, TEL_TYPE_OTHER);
427
vcard_printf_number(phonebook->vcards, adnumber, adtype,
429
vcard_printf_group(phonebook->vcards, group);
430
vcard_printf_email(phonebook->vcards, email);
431
vcard_printf_sip_uri(phonebook->vcards, sip_uri);
432
vcard_printf_end(phonebook->vcards);
435
static void export_phonebook_cb(const struct ofono_error *error, void *data)
437
struct ofono_modem *modem = data;
438
struct phonebook_data *phonebook = modem->phonebook;
440
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
441
ofono_error("export_entries_one_storage_cb with %s failed",
442
storage_support[phonebook->storage_index]);
444
/* convert the collected entries that are already merged to vcard */
445
phonebook->merge_list = g_slist_reverse(phonebook->merge_list);
446
g_slist_foreach(phonebook->merge_list, (GFunc)print_merged_entry,
448
g_slist_foreach(phonebook->merge_list, (GFunc)destroy_merged_entry,
450
g_slist_free(phonebook->merge_list);
451
phonebook->merge_list = NULL;
453
phonebook->storage_index++;
454
export_phonebook(modem);
458
static void export_phonebook(struct ofono_modem *modem)
460
struct phonebook_data *phonebook = modem->phonebook;
462
const char *pb = storage_support[phonebook->storage_index];
465
phonebook->ops->export_entries(modem, pb,
466
export_phonebook_cb, modem);
470
reply = generate_export_entries_reply(modem, phonebook->pending);
473
dbus_message_unref(phonebook->pending);
477
__ofono_dbus_pending_reply(&phonebook->pending, reply);
478
phonebook->flags |= PHONEBOOK_FLAG_CACHED;
481
static DBusMessage *import_entries(DBusConnection *conn, DBusMessage *msg,
484
struct ofono_modem *modem = data;
485
struct phonebook_data *phonebook = modem->phonebook;
488
if (phonebook->pending) {
489
reply = __ofono_error_busy(phonebook->pending);
490
g_dbus_send_message(conn, reply);
494
if (phonebook->flags & PHONEBOOK_FLAG_CACHED) {
495
reply = generate_export_entries_reply(modem, msg);
496
g_dbus_send_message(conn, reply);
500
g_string_set_size(phonebook->vcards, 0);
501
phonebook->storage_index = 0;
503
phonebook->pending = dbus_message_ref(msg);
504
export_phonebook(modem);
509
static GDBusMethodTable phonebook_methods[] = {
510
{ "Import", "", "s", import_entries,
511
G_DBUS_METHOD_FLAG_ASYNC },
515
static GDBusSignalTable phonebook_signals[] = {
519
int ofono_phonebook_register(struct ofono_modem *modem,
520
struct ofono_phonebook_ops *ops)
522
DBusConnection *conn = ofono_dbus_get_connection();
530
modem->phonebook = phonebook_create();
532
if (modem->phonebook == NULL)
535
modem->phonebook->ops = ops;
537
if (!g_dbus_register_interface(conn, modem->path,
539
phonebook_methods, phonebook_signals,
540
NULL, modem, phonebook_destroy)) {
541
ofono_error("Could not register Phonebook %s", modem->path);
543
phonebook_destroy(modem->phonebook);
548
ofono_modem_add_interface(modem, PHONEBOOK_INTERFACE);
552
void ofono_phonebook_unregister(struct ofono_modem *modem)
554
DBusConnection *conn = ofono_dbus_get_connection();
556
if (modem->phonebook == NULL)
559
ofono_modem_remove_interface(modem, PHONEBOOK_INTERFACE);
560
g_dbus_unregister_interface(conn, modem->path,
561
PHONEBOOK_INTERFACE);