4 /* vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:��,trail\:�: */
7 * Claws-contacts is a proposed new design for the address book feature
8 * in Claws Mail. The goal for this new design was to create a
9 * solution more suitable for the term lightweight and to be more
10 * maintainable than the present implementation.
12 * More lightweight is achieved by design, in that sence that the whole
13 * structure is based on a plugable design.
15 * Claws Mail is Copyright (C) 1999-2018 by the Claws Mail Team and
16 * Claws-contacts is Copyright (C) 2018 by Michael Rasmussen.
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 3 of the License, or
21 * (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
38 #include <glib/gi18n.h>
39 #include <dbus/dbus.h>
40 #include <dbus/dbus-glib-bindings.h>
41 #include "dbus-contact.h"
42 #include "addrgather.h"
47 #include "addressbook-dbus.h"
48 #include "client-bindings.h"
50 static DBusGProxy
* proxy
= NULL
;
51 static DBusGConnection
* connection
= NULL
;
52 static Compose
* compose_instance
= NULL
;
54 static GQuark
client_object_error_quark() {
55 static GQuark quark
= 0;
57 quark
= g_quark_from_static_string ("client_object_error");
62 static gboolean
init(GError
** error
) {
63 connection
= dbus_g_bus_get (DBUS_BUS_SESSION
, error
);
64 if (connection
== NULL
|| *error
) {
66 g_set_error(error
, client_object_error_quark(), 1, "Unable to connect to dbus");
67 g_warning("unable to connect to dbus: %s", (*error
)->message
);
71 proxy
= dbus_g_proxy_new_for_name (connection
,
72 "org.clawsmail.Contacts",
73 "/org/clawsmail/contacts",
74 "org.clawsmail.Contacts");
76 g_warning("could not get a proxy object");
77 g_set_error(error
, client_object_error_quark(), 1, "Could not get a proxy object");
84 static void dbus_contact_free(const DBusContact
* contact
) {
85 g_hash_table_destroy(contact
->data
);
86 g_ptr_array_free(contact
->emails
, TRUE
);
89 static GHashTable
* hash_table_new(void) {
90 GHashTable
* hash_table
;
92 hash_table
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
97 static void g_value_email_free(gpointer data
) {
98 GArray
* email
= (GArray
*) data
;
102 for (i
= 0; i
< email
->len
; i
++) {
103 email_member
= g_array_index(email
, GValue
*, i
);
104 g_value_unset(email_member
);
108 static GPtrArray
* g_value_email_new() {
109 return g_ptr_array_new_with_free_func(g_value_email_free
);
112 static gchar
* convert_2_utf8(gchar
* locale
) {
114 GError
* error
= NULL
;
115 gchar
*current
, *utf8
;
116 const gchar
* charset
;
118 if (g_get_charset(&charset
) || g_utf8_validate(locale
, -1, 0))
119 return g_strdup(locale
);
121 if (strcmp("ANSI_X3.4-1968", charset
) == 0)
122 current
= g_strdup("ISO-8859-1");
124 current
= g_strdup(charset
);
126 utf8
= g_convert(locale
, -1, "UTF-8", current
, &read
, &write
, &error
);
128 g_warning("failed to convert [%s]: %s", charset
, error
->message
);
137 static void format_contact(DBusContact
* contact
, ContactData
* c
) {
140 GArray
* email
= NULL
;
141 GValue email_member
= {0};
146 contact
->data
= hash_table_new();
147 contact
->emails
= g_value_email_new();
148 firstname
= lastname
= NULL
;
151 gchar
* pos
= strchr(c
->name
, ' ');
153 firstname
= g_strndup(c
->name
, pos
- c
->name
);
154 lastname
= g_strdup(++pos
);
155 g_hash_table_replace(contact
->data
,
156 g_strdup("first-name"), convert_2_utf8(firstname
));
157 g_hash_table_replace(contact
->data
,
158 g_strdup("last-name"), convert_2_utf8(lastname
));
161 lastname
= g_strdup(c
->name
);
162 g_hash_table_replace(contact
->data
,
163 g_strdup("last-name"), convert_2_utf8(lastname
));
169 g_hash_table_replace(contact
->data
,
170 g_strdup("cn"), convert_2_utf8(c
->cn
));
174 gdk_pixbuf_save_to_buffer(
175 c
->picture
, &image
, &size
, "png", NULL
, NULL
);
176 g_hash_table_replace(contact
->data
,
177 g_strdup("image"), g_base64_encode((const guchar
*) image
, size
));
180 email
= g_array_new(FALSE
, FALSE
, sizeof(GValue
*));
182 /* Alias is not available but needed so make an empty string */
183 g_value_init(&email_member
, G_TYPE_STRING
);
184 g_value_set_string(&email_member
, "");
185 g_array_append_val(email
, email_member
);
186 g_value_unset(&email_member
);
189 str
= convert_2_utf8(c
->email
);
193 g_value_init(&email_member
, G_TYPE_STRING
);
194 g_value_set_string(&email_member
, str
);
195 g_array_append_val(email
, email_member
);
196 g_value_unset(&email_member
);
200 str
= convert_2_utf8(c
->remarks
);
204 g_value_init(&email_member
, G_TYPE_STRING
);
205 g_value_set_string(&email_member
, str
);
206 g_array_append_val(email
, email_member
);
207 g_value_unset(&email_member
);
210 g_ptr_array_add(contact
->emails
, email
);
213 static DBusHandlerResult
contact_add_signal(DBusConnection
* bus
,
214 DBusMessage
* message
,
219 if (! compose_instance
) {
220 g_message("Missing compose instance\n");
221 return DBUS_HANDLER_RESULT_HANDLED
;
224 dbus_error_init (&error
);
226 if (dbus_message_is_signal(message
, "org.clawsmail.Contacts", "ContactMailTo")) {
227 if (dbus_message_get_args(
228 message
, &error
, DBUS_TYPE_STRING
, &s
, DBUS_TYPE_INVALID
)) {
229 debug_print("ContactMailTo address received: %s\n", s
);
230 compose_entry_append(compose_instance
, s
, COMPOSE_TO
, PREF_NONE
);
233 debug_print("ContactMailTo received with error: %s\n", error
.message
);
234 dbus_error_free(&error
);
237 else if (dbus_message_is_signal(message
, "org.clawsmail.Contacts", "ContactMailCc")) {
238 if (dbus_message_get_args(
239 message
, &error
, DBUS_TYPE_STRING
, &s
, DBUS_TYPE_INVALID
)) {
240 debug_print("ContactMailTo address received: %s\n", s
);
241 compose_entry_append(compose_instance
, s
, COMPOSE_CC
, PREF_NONE
);
244 debug_print("ContactMailTo received with error: %s\n", error
.message
);
245 dbus_error_free(&error
);
248 else if (dbus_message_is_signal(message
, "org.clawsmail.Contacts", "ContactMailBcc")) {
249 if (dbus_message_get_args(
250 message
, &error
, DBUS_TYPE_STRING
, &s
, DBUS_TYPE_INVALID
)) {
251 debug_print("ContactMailTo address received: %s\n", s
);
252 compose_entry_append(compose_instance
, s
, COMPOSE_BCC
, PREF_NONE
);
255 debug_print("ContactMailTo received with error: %s\n", error
.message
);
256 dbus_error_free(&error
);
261 g_warning("reception error: %s", error
.message
);
262 dbus_error_free(&error
);
264 debug_print("Unhandled signal received\n");
265 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
268 return DBUS_HANDLER_RESULT_HANDLED
;
271 gboolean
addressbook_start_service(GError
** error
) {
273 gboolean result
= FALSE
;
278 if (!org_clawsmail_Contacts_ping(proxy
, &reply
, error
)) {
280 g_set_error(error
, client_object_error_quark(), 1, "Woops remote method failed");
281 g_warning("woops remote method failed: %s", (*error
)->message
);
283 if (reply
&& strcmp("PONG", reply
) == 0)
289 int addressbook_dbus_add_contact(ContactData
* contact
, GError
** error
) {
290 DBusContact dbus_contact
;
295 format_contact(&dbus_contact
, contact
);
296 if (!org_clawsmail_Contacts_add_contact(
297 proxy
, contact
->book
, dbus_contact
.data
, dbus_contact
.emails
, error
)) {
299 g_set_error(error
, client_object_error_quark(), 1, "Woops remote method failed");
300 g_warning("woops remote method failed: %s", (*error
)->message
);
301 dbus_contact_free(&dbus_contact
);
304 dbus_contact_free(&dbus_contact
);
308 gboolean
addrindex_dbus_load_completion(gint (*callBackFunc
)
310 const gchar
* address
,
315 gchar
**list
= NULL
, **contacts
;
321 if (!org_clawsmail_Contacts_search_addressbook(
322 proxy
, "*", NULL
, &list
, error
)) {
324 g_set_error(error
, client_object_error_quark(), 1, "Woops remote method failed");
325 g_warning("woops remote method failed: %s", (*error
)->message
);
329 for (contacts
= list
; *contacts
!= NULL
; contacts
+= 1) {
330 gchar
* tmp
= g_strdup(*contacts
);
331 gchar
* pos
= g_strrstr(tmp
, "\"");
333 /* Contact has a name as part of email address */
339 pos
= g_strrstr(email
, ">");
347 debug_print("Adding: %s <%s> to completition\n", name
, email
);
348 callBackFunc(name
, email
, NULL
, NULL
, NULL
);
355 void addressbook_dbus_open(gboolean compose
, GError
** error
) {
359 if (!org_clawsmail_Contacts_show_addressbook(proxy
, compose
, error
)) {
361 g_set_error(error
, client_object_error_quark(), 1, "Woops remote method failed");
362 g_warning("woops remote method failed: %s", (*error
)->message
);
366 GSList
* addressbook_dbus_get_books(GError
** error
) {
367 gchar
**book_names
= NULL
, **cur
;
368 GSList
* books
= NULL
;
374 if (!org_clawsmail_Contacts_book_list(proxy
, &book_names
, error
)) {
376 g_set_error(error
, client_object_error_quark(), 1, "Woops remote method failed");
377 g_warning("woops remote method failed: %s", (*error
)->message
);
378 g_strfreev(book_names
);
381 for (cur
= book_names
; *cur
; cur
+= 1)
382 books
= g_slist_prepend(books
, g_strdup(*cur
));
384 g_strfreev(book_names
);
389 void contact_data_free(ContactData
** data
) {
390 ContactData
* contact
;
392 if (! data
&& ! *data
)
397 g_free(contact
->email
);
398 g_free(contact
->remarks
);
399 g_free(contact
->name
);
400 g_free(contact
->book
);
405 void addressbook_harvest(FolderItem
*folderItem
,
408 addrgather_dlg_execute(folderItem
, sourceInd
, msgList
);
411 void addressbook_connect_signals(Compose
* compose
) {
413 DBusError
* error
= NULL
;
415 g_return_if_fail(compose
!= NULL
);
417 bus
= dbus_bus_get (DBUS_BUS_SESSION
, error
);
419 g_warning("failed to connect to the D-BUS daemon: %s", error
->message
);
420 dbus_error_free(error
);
424 debug_print("Compose: %p\n", compose
);
425 compose_instance
= compose
;
426 dbus_bus_add_match(bus
, "type='signal',interface='org.clawsmail.Contacts'", error
);
428 debug_print("Failed to add match to the D-BUS daemon: %s\n", error
->message
);
429 dbus_error_free(error
);
432 dbus_connection_add_filter(bus
, contact_add_signal
, NULL
, NULL
);
435 gchar
* addressbook_get_vcard(const gchar
* account
, GError
** error
) {
438 g_return_val_if_fail(account
!= NULL
, vcard
);
444 if (!org_clawsmail_Contacts_get_vcard(proxy
, account
, &vcard
, error
)) {
446 g_set_error(error
, client_object_error_quark(), 1, "Woops remote method failed");
447 g_warning("woops remote method failed: %s", (*error
)->message
);
455 gboolean
addressbook_add_vcard(const gchar
* abook
, const gchar
* vcard
, GError
** error
) {
456 gboolean result
= FALSE
;
461 static gboolean
my_compose_create_hook(gpointer source
, gpointer user_data
) {
462 //Compose *compose = (Compose*) source;
463 GError
* error
= NULL
;
465 gchar
* vcard
= addressbook_get_vcard("test", &error
);
467 g_warning("%s", error
->message
);
468 g_clear_error(&error
);
471 debug_print("test.vcf:\n%s\n", vcard
);
478 void addressbook_install_hooks(GError
** error
) {
479 if ((guint
)-1 == hooks_register_hook(COMPOSE_CREATED_HOOKLIST
, my_compose_create_hook
, NULL
)) {
480 g_warning("could not register hook for adding vCards");
482 g_set_error(error
, client_object_error_quark(), 1,
483 "Could not register hook for adding vCards");