From 653cfffc0e00dfb59b36813c1b45c53d3f773c65 Mon Sep 17 00:00:00 2001 From: Ettore Perazzoli Date: Tue, 21 Oct 2003 18:49:34 +0000 Subject: Merge new-ui-branch to the trunk. svn path=/trunk/; revision=22965 --- addressbook/backend/ebook/.cvsignore | 1 + addressbook/backend/ebook/Makefile.am | 114 +- addressbook/backend/ebook/docs/rfc2739.txt | 899 +++++++ addressbook/backend/ebook/e-book-async.c | 1120 ++++++++ addressbook/backend/ebook/e-book-async.h | 107 + addressbook/backend/ebook/e-book-listener.c | 779 ++---- addressbook/backend/ebook/e-book-listener.h | 42 +- addressbook/backend/ebook/e-book-query.c | 524 ++++ addressbook/backend/ebook/e-book-query.h | 49 + addressbook/backend/ebook/e-book-types.h | 59 +- addressbook/backend/ebook/e-book-util.c | 808 ------ addressbook/backend/ebook/e-book-util.h | 94 - addressbook/backend/ebook/e-book-view-listener.c | 263 +- addressbook/backend/ebook/e-book-view-listener.h | 30 +- addressbook/backend/ebook/e-book-view.c | 101 +- addressbook/backend/ebook/e-book-view.h | 15 +- addressbook/backend/ebook/e-book.c | 2579 ++++++++++-------- addressbook/backend/ebook/e-book.h | 212 +- addressbook/backend/ebook/e-card-compare.c | 706 ----- addressbook/backend/ebook/e-card-compare.h | 72 - addressbook/backend/ebook/e-card-cursor.c | 239 -- addressbook/backend/ebook/e-card-cursor.h | 53 - addressbook/backend/ebook/e-card-pairs.h | 118 - addressbook/backend/ebook/e-card-simple.c | 1344 ---------- addressbook/backend/ebook/e-card-simple.h | 234 -- addressbook/backend/ebook/e-card-types.h | 101 - addressbook/backend/ebook/e-card.c | 2807 -------------------- addressbook/backend/ebook/e-card.h | 209 -- addressbook/backend/ebook/e-contact.c | 1288 +++++++++ addressbook/backend/ebook/e-contact.h | 227 ++ addressbook/backend/ebook/e-destination.h | 140 - addressbook/backend/ebook/e-vcard.c | 488 +++- addressbook/backend/ebook/e-vcard.h | 99 +- addressbook/backend/ebook/test-client-list.c | 65 - addressbook/backend/ebook/test-client.c | 191 -- addressbook/backend/ebook/tests/Makefile.am | 2 +- addressbook/backend/ebook/tests/ebook/.cvsignore | 7 + addressbook/backend/ebook/tests/ebook/Makefile.am | 12 + .../backend/ebook/tests/ebook/test-changes.c | 89 + addressbook/backend/ebook/tests/ebook/test-date.c | 36 + addressbook/backend/ebook/tests/ebook/test-ebook.c | 110 + addressbook/backend/ebook/tests/ebook/test-photo.c | 59 + .../backend/ebook/tests/ebook/test-string.c | 27 + addressbook/backend/ebook/tests/vcard/Makefile.am | 6 +- addressbook/backend/ebook/tests/vcard/dump-vcard.c | 2 +- 45 files changed, 7080 insertions(+), 9447 deletions(-) create mode 100644 addressbook/backend/ebook/docs/rfc2739.txt create mode 100644 addressbook/backend/ebook/e-book-async.c create mode 100644 addressbook/backend/ebook/e-book-async.h create mode 100644 addressbook/backend/ebook/e-book-query.c create mode 100644 addressbook/backend/ebook/e-book-query.h delete mode 100644 addressbook/backend/ebook/e-book-util.c delete mode 100644 addressbook/backend/ebook/e-book-util.h delete mode 100644 addressbook/backend/ebook/e-card-compare.c delete mode 100644 addressbook/backend/ebook/e-card-compare.h delete mode 100644 addressbook/backend/ebook/e-card-cursor.c delete mode 100644 addressbook/backend/ebook/e-card-cursor.h delete mode 100644 addressbook/backend/ebook/e-card-pairs.h delete mode 100644 addressbook/backend/ebook/e-card-simple.c delete mode 100644 addressbook/backend/ebook/e-card-simple.h delete mode 100644 addressbook/backend/ebook/e-card-types.h delete mode 100644 addressbook/backend/ebook/e-card.c delete mode 100644 addressbook/backend/ebook/e-card.h create mode 100644 addressbook/backend/ebook/e-contact.c create mode 100644 addressbook/backend/ebook/e-contact.h delete mode 100644 addressbook/backend/ebook/e-destination.h delete mode 100644 addressbook/backend/ebook/test-client-list.c delete mode 100644 addressbook/backend/ebook/test-client.c create mode 100644 addressbook/backend/ebook/tests/ebook/.cvsignore create mode 100644 addressbook/backend/ebook/tests/ebook/Makefile.am create mode 100644 addressbook/backend/ebook/tests/ebook/test-changes.c create mode 100644 addressbook/backend/ebook/tests/ebook/test-date.c create mode 100644 addressbook/backend/ebook/tests/ebook/test-ebook.c create mode 100644 addressbook/backend/ebook/tests/ebook/test-photo.c create mode 100644 addressbook/backend/ebook/tests/ebook/test-string.c (limited to 'addressbook/backend/ebook') diff --git a/addressbook/backend/ebook/.cvsignore b/addressbook/backend/ebook/.cvsignore index e3e9c805bb..17250008f8 100644 --- a/addressbook/backend/ebook/.cvsignore +++ b/addressbook/backend/ebook/.cvsignore @@ -12,6 +12,7 @@ addressbook.h test-card test-client test-client-list +test-ebook load-pine-addressbook load-gnomecard-addressbook evolution-vcard-importer diff --git a/addressbook/backend/ebook/Makefile.am b/addressbook/backend/ebook/Makefile.am index 9d2b6d1b05..e83e3e1411 100644 --- a/addressbook/backend/ebook/Makefile.am +++ b/addressbook/backend/ebook/Makefile.am @@ -1,16 +1,7 @@ -noinst_PROGRAMS = test-card test-client test-client-list - -privlibexec_PROGRAMS = \ - evolution-vcard-importer \ - evolution-ldif-importer - -toolsdir = $(privlibexecdir)/ -tools_PROGRAMS = \ - load-pine-addressbook \ - load-gnomecard-addressbook - # CORBA stuff +SUBDIRS = . tests + CORBA_ADDRESSBOOK_SOURCE_H = \ addressbook.h CORBA_ADDRESSBOOK_SOURCE_C = \ @@ -38,13 +29,10 @@ INCLUDES = \ -DLIBDIR=\"$(libdir)\" \ -DG_LOG_DOMAIN=\"EBook\" \ -I$(top_srcdir) \ - -I$(top_srcdir)/camel \ -I$(top_srcdir)/addressbook/backend \ -I$(top_srcdir)/addressbook/ename \ -I$(top_builddir)/addressbook/backend \ -I$(top_builddir)/addressbook/ename \ - -I$(top_builddir)/shell \ - -I$(top_srcdir)/shell \ -DG_DISABLE_DEPRECATED \ -DLIBGNOME_DISABLE_DEPRECATED \ $(EVOLUTION_ADDRESSBOOK_CFLAGS) @@ -53,113 +41,39 @@ privlib_LTLIBRARIES = libebook.la libebook_la_SOURCES = \ $(CORBA_SOURCE) \ - e-book-listener.c \ + addressbook.h \ e-book-marshal.c \ + e-book-query.c \ e-book-view-listener.c \ e-book-view.c \ + e-book-listener.c \ e-book.c \ - e-book-util.c \ - e-card-cursor.c \ - e-card-simple.c \ - e-card.c \ - e-card-compare.c \ - e-destination.c + e-book-async.c \ + e-contact.c \ + e-vcard.c libebook_la_LIBADD = \ $(top_builddir)/libversit/libversit.la \ - $(top_builddir)/camel/libcamel.la \ $(top_builddir)/e-util/ename/libename.la \ $(top_builddir)/e-util/libeutil.la libebookincludedir = $(privincludedir)/ebook libebookinclude_HEADERS = \ - e-book-listener.h \ - e-book-types.h \ + e-book-query.h \ e-book-view-listener.h \ e-book-view.h \ + e-book-types.h \ + e-book-listener.h \ e-book.h \ - e-book-util.h \ - e-card-cursor.h \ - e-card-simple.h \ - e-card-types.h \ - e-card.h \ - e-card-compare.h \ - e-destination.h \ - addressbook.h - + e-contact.h \ + e-vcard.h MARSHAL_GENERATED = e-book-marshal.c e-book-marshal.h @EVO_MARSHAL_RULE@ -test_client_SOURCES = \ - test-client.c - -test_client_LDADD = \ - libebook.la \ - $(EVOLUTION_ADDRESSBOOK_LIBS) - -test_client_list_SOURCES = \ - test-client-list.c - -test_client_list_LDADD = \ - libebook.la \ - $(EVOLUTION_ADDRESSBOOK_LIBS) - -test_card_SOURCES = \ - test-card.c - -test_card_LDADD = \ - libebook.la \ - $(EVOLUTION_ADDRESSBOOK_LIBS) - -evolution_vcard_importer_SOURCES = \ - evolution-vcard-importer.c - -evolution_vcard_importer_LDADD = \ - libebook.la \ - $(EVOLUTION_ADDRESSBOOK_LIBS) \ - $(top_builddir)/shell/importer/libevolution-importer.la \ - $(DB3_LDADD) - -evolution_ldif_importer_SOURCES = \ - evolution-ldif-importer.c - -evolution_ldif_importer_LDADD = \ - libebook.la \ - $(EVOLUTION_ADDRESSBOOK_LIBS) \ - $(top_builddir)/shell/importer/libevolution-importer.la \ - $(DB3_LDADD) - -load_pine_addressbook_SOURCES = \ - load-pine-addressbook.c - -load_pine_addressbook_LDADD = \ - libebook.la \ - $(EVOLUTION_ADDRESSBOOK_LIBS) - -load_gnomecard_addressbook_SOURCES = \ - load-gnomecard-addressbook.c - -load_gnomecard_addressbook_LDADD = \ - libebook.la \ - $(EVOLUTION_ADDRESSBOOK_LIBS) - - -BUILT_SOURCES = $(CORBA_SOURCE) $(MARSHAL_GENERATED) $(server_DATA) +BUILT_SOURCES = $(CORBA_SOURCE) $(MARSHAL_GENERATED) CLEANFILES = $(BUILT_SOURCES) dist-hook: cd $(distdir); rm -f $(BUILT_SOURCES) - -server_in_files = GNOME_Evolution_Addressbook_VCard_Importer.server.in.in \ - GNOME_Evolution_Addressbook_LDIF_Importer.server.in.in - -server_DATA = $(server_in_files:.server.in.in=.server) -%.server.in: %.server.in.in - sed -e "s|\@LIBEXECDIR\@|$(privlibexecdir)|" $< > $@ - - -@INTLTOOL_SERVER_RULE@ - -EXTRA_DIST = $(server_in_files) $(server_DATA) e-book-marshal.list diff --git a/addressbook/backend/ebook/docs/rfc2739.txt b/addressbook/backend/ebook/docs/rfc2739.txt new file mode 100644 index 0000000000..5c1dbbcf77 --- /dev/null +++ b/addressbook/backend/ebook/docs/rfc2739.txt @@ -0,0 +1,899 @@ + + + + + + +Network Working Group T. Small +Request for Comments: 2739 XpertSite.Com +Category: Standards Track D. Hennessy + ISOCOR + F. Dawson + Lotus + January 2000 + + + Calendar Attributes for vCard and LDAP + + +Status of this Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2000). All Rights Reserved. + +Abstract + + When scheduling a calendar entity, such as an event, it is a + prerequisite that an organizer has the calendar address of each + attendee that will be invited to the event. Additionally, access to + an attendee's current "busy time" provides an a priori indication of + whether the attendee will be free to participate in the event. + + In order to meet these challenges, a calendar user agent (CUA) needs + a mechanism to locate (URI) individual user's calendar and free/busy + time. + + This memo defines three mechanisms for obtaining a URI to a user's + calendar and free/busy time. These include: + + - Manual transfer of the information; + + - Personal data exchange using the vCard format; and + + - Directory lookup using the LDAP protocol. + + + + + + + +Small, et al. Standards Track [Page 1] + +RFC 2739 Locating a Calendar User January 2000 + + +Table of Contents + + 1 CALENDARING AND SCHEDULING URIS...................................3 + 1.1 FREE/BUSY URI (FBURL) .........................................3 + 1.2 CALENDAR ACCESS URI (CAPURI) ..................................4 + 1.3 CALENDAR URI (CALURI) .........................................4 + 1.4 DEFAULT URIS ..................................................4 + 2 DISTRIBUTION......................................................4 + 2.1 MANUAL TRANSFER ...............................................5 + 2.2 PERSONAL DATA EXCHANGE USING A VCARD ..........................5 + 2.3 VCARD SCHEMA EXTENSIONS .......................................5 + 2.3.1 FBURL Property IANA Registration ...........................6 + 2.3.2 CALADRURI Property IANA Registration .......................7 + 2.3.3 CAPURI Property IANA Registration ......................... 8 + 2.3.4 CALURI Property IANA Registration ......................... 8 + 2.4 DIRECTORY LOOKUP USING THE LDAP V3 PROTOCOL .................. 9 + 2.4.1 LDAP Schema Extensions .................................... 9 + 2.4.2 Notation ..................................................10 + 2.4.3 Object Definitions ........................................10 + 2.4.3.1 calEntry ..............................................10 + 2.4.4 Attribute Definitions .....................................10 + 2.4.4.1 calCalURI .............................................10 + 2.4.4.2 calFBURL ..............................................10 + 2.4.4.3 calCAPURI .............................................11 + 2.4.4.4 calCalAdrURI ..........................................11 + 2.4.4.5 calOtherCalURIs .......................................11 + 2.4.4.6 calOtherFBURLs ........................................11 + 2.4.4.7 calOtherCAPURIs .......................................12 + 2.4.4.8 calOtherCalAdrURIs ....................................12 + 3 IANA Considerations..............................................12 + 4 Security Considerations..........................................12 + 5 Acknowledgments..................................................13 + 6 Authors' Addresses...............................................13 + 7 Bibliography.....................................................15 + 8 Full Copyright Statement.........................................16 + + + + + + + + + + + + + + + + +Small, et al. Standards Track [Page 2] + +RFC 2739 Locating a Calendar User January 2000 + + +1 Calendaring and Scheduling URIs + + This memo defines four classes of URIs. URIs are more useful if it is + understood what the URIs point to. Here is a brief description: + +1.1 Free/Busy URI (FBURL) + + The free/busy URI is defined to be a transport independent location + where a client can obtain information about when a user is busy. At + the present time, this URI only points to busy time data. Future + revisions of this specification may provide for the extended + capability of publishing free time data. + + If a calendaring and scheduling client (i.e., CUA) were to retrieve + data from this location using FTP or HTTP, it would get back an + iCalendar object [4] containing one or more "VFREEBUSY" calendar + components. If a MIME transport is being used, the response will be + contained within a "text/calendar" MIME body part as specified in the + iCalendar specification [4]. For example: + + BEGIN:VCALENDAR + VERSION:2.0 + PRODID:-//hacksw/handcal//NONSGML v1.0//EN + METHOD:PUBLISH + BEGIN:VFREEBUSY + ATTENDEE:MAILTO:jane_doe@host1.com + DTSTART:19971013T050000Z + DTEND:19971124T050000Z + DTSTAMP:19970901T083000Z + FREEBUSY:19971015T133000Z/19971015T180000Z + FREEBUSY:19971015T190000Z/19971015T220000Z + FBURL:http://www.host.com/calendar/busy/jdoe.ifb + END:VFREEBUSY + END:VCALENDAR + + The amount of busy time data pointed to by the FBURL will generally + be pre-determined; for example one month of busy time data. As a + guideline, it is recommended that the previous six weeks of busy time + data be published at the location associated with the FBURL. If this + URI points to a file resource, it is recommended that the file + extension be "ifb" to distinguish it from an arbitrary iCalendar + object (e.g., with the "ics" file extension). + + + + + + + + + +Small, et al. Standards Track [Page 3] + +RFC 2739 Locating a Calendar User January 2000 + + +1.2 Calendar Access URI (CAPURI) + + The Calendar Access URI is defined to be a protocol independent + location from which a calendaring and scheduling client (i.e., CUA) + can communicate with a user's entire calendar. + + The semantics for using this URI as an access protocol locator are + yet to be defined by the IETF CALSCH Working Group. This will be + addressed in the "Calendar Access Protocol" specification. + +1.3 Calendar URI (CALURI) + + The Calendar URI is defined to be a protocol independent location + from which a calendaring and scheduling client (i.e. CUA) can + retrieve an entire copy of a user's calendar. Retrieving data from + this URI obtains a published "snapshot" of the user's calendar. + + HTTP URI -- If the URI is an HTTP URI, then the content returned with + a GET should be a "text/calendar" MIME body part containing one or + more iCalendar object. + + FTP URI -- If the URI is an FTP URI, then the resource pointed to + should be a file with an "ics" file extension containing one or more + iCalendar objects. + +1.4 Default URIs + + There are many cases where a user may have more than one calendar. In + these cases, a user may have multiple URIs, each URI pointing to a + calendar or free/busy data. + + To make the case of multiple calendars simpler for clients, the + concept of the "default" calendar is introduced. A "default" calendar + is one that the user has designated as the calendar that other users + should look at when accessing the user's calendar, or retrieving the + user's free/busy time. + + The default calendar may, in fact, include rolled-up information from + all the user's other calendars. The other calendars may only exist + for organizational purposes. + +2 Distribution + + These four URIs provide valuable pointers to calendaring and + scheduling data that other users need in order to know when to + schedule meetings, etc. There are several possibilities on how users + can communicate these URIs to other users. The following section + outlines how these URIs can be distributed to other users. + + + +Small, et al. Standards Track [Page 4] + +RFC 2739 Locating a Calendar User January 2000 + + +2.1 Manual Transfer + + The simplest way to obtain these URIs is for a user to communicate + the URIs using some out-of-band mechanism such as verbally, or in an + e-mail message, or by printing these URIs on a paper business card. + + When using this mechanism, the user obtains these URIs using an out- + of-band mechanism and then enters these URIs into their calendaring + software manually. + +2.2 Personal Data Exchange Using A vCard + + A more sophisticated way to obtain these URIs is for users to publish + vCards containing these URIs. The vCard object can be transferred + between one another. Since many e-mail clients allow a user to + automatically include a vCard with every message that the user sends, + this provides a simple, transparent way for a user to distribute + their calendaring and scheduling URIs. + + On the receiving end, an e-mail client that provides an integrated + vCard database can provide a way to lookup calendaring URIs for users + whose vCards are stored locally. + +2.3 vCard Schema Extensions + + Since the vCard [3] specification doesn't specify how to encode + calendaring URIs in a vCard, this section is provided as an extension + to vCard which specifies how to encode calendaring URIs within a + vCard. + + Inside a vCard object, four new properties are defined: "CALURI", + "CAPURI", "CALADRURI", and "FBURL", as defined above. + + Any vCard can have one or more of these properties, each representing + a calendar or free/busy time that is associated with the user. + + One of these properties can be designated as the "default" by adding + the "PREF" parameter. + + + + + + + + + + + + + +Small, et al. Standards Track [Page 5] + +RFC 2739 Locating a Calendar User January 2000 + + + Here is a simple example of a vCard containing a "FBURL" and a + "CALURI". + + BEGIN:VCARD + VERSION:3.0 + N:Dun;Alec + FN:Alec Dun + ORG:Microsoft Corporation + ADR;WORK;POSTAL;PARCEL:;;One Microsoft Way; + Redmond;WA;98052-6399;USA + TEL;WORK;MSG:+1-206-936-4544 + TEL;WORK;FAX:+1-206-936-7329 + EMAIL;INTERNET:user@host1.com + CALADRURI;PREF:mailto:user@host1.com + CALURI;PREF:http://cal.host1.com/user/cal.ics + FBURL;PREF:http://cal.host1.com/user/fb.ifb + CALURI:http://cal.company.com/projectA/pjtA.ics + FBURL:http://cal.company.com/projectA/pjtAfb.ifb + END:VCARD + +2.3.1 FBURL Property IANA Registration + + To: ietf-mime-directory@imc.org + + Subject: Registration of FBURL type for text/directory MIME type + vCard profile. + + Type name: FBURL + + Type purpose: To specify the URI for a user's busy time in a vCard + object. + + Type encoding: 8bit + + Type value: A single URI value. + + Type special notes: Where multiple FBURL properties are specified, + the default FBURL property is indicated with the PREF parameter. The + FTP or HTTP type of URI points to an iCalendar object associated with + a snapshot of the last six weeks of the user's busy time data. If the + iCalendar object is represented as a file or document, it's file type + should be "ifb". + + Intended usage: Refer to section 1.1. + + + + + + + +Small, et al. Standards Track [Page 6] + +RFC 2739 Locating a Calendar User January 2000 + + + Type examples: + + FBURL;PREF:http://www.host1.com/busy/janedoe + FBURL:FTP://ftp.host.com/busy/project-a.ifb + +2.3.2 CALADRURI Property IANA Registration + + To: ietf-mime-directory@imc.org + + Subject: Registration of CALADRURI type for application/directory + MIME type vCard profile. + + Type name: CALADRURI + + Type purpose: To specify the location to which an event request + should be sent for the user. + + Type encoding: 8bit + + Type value: A single URI value. + + Type special notes: Where multiple CALADRURI properties are + specified, the default CALADRURI property is indicated with the PREF + parameter. + + Intended usage: Refer to section 1.2. + + Type examples: + + CALADRURI;PREF:mailto:janedoe@host.com + + + + + + + + + + + + + + + + + + + + + +Small, et al. Standards Track [Page 7] + +RFC 2739 Locating a Calendar User January 2000 + + +2.3.3 CAPURI Property IANA Registration + + To: ietf-mime-directory@imc.org + + Subject: Registration of CAPURI type for application/directory MIME + type vCard profile. + + Type name: CAPURI + + Type purpose: To specify a protocol independent location from which a + calendaring and scheduling client (i.e., CUA) can communicate with a + user's entire calendar. + + Type encoding: 8bit + + Type value: A single URI value. + + Type special notes: Where multiple CAPURI properties are specified, + the default CAPURI property is indicated with the PREF parameter. + + Intended usage: Refer to section 1.3. + +2.3.4 CALURI Property IANA Registration + + To: ietf-mime-directory@imc.org + + Subject: Registration of CALURI type for text/directory MIME type + vCard profile. + + Type name: CALURI + + Type purpose: To specify the URI for a user's calendar in a vCard + object. + + Type encoding: 8bit + + Type value type: A single URI value. + + Type special notes: Where multiple CALURI properties are specified, + the default CALURI property is indicated with the PREF parameter. The + property should contain a URI pointing to an iCalendar object + associated with a snapshot of the user's calendar store. If the + iCalendar object is represented as a file or document, it's file type + should be "ics". + + Intended usage: Refer to section 1.4. + + + + + +Small, et al. Standards Track [Page 8] + +RFC 2739 Locating a Calendar User January 2000 + + + Type examples: + + CALURI;PREF:http://cal.host1.com/calA + CALURI:ftp://ftp.host1.com/calA.ics + +2.4 Directory Lookup Using The LDAP v3 Protocol + + Another way to obtain these URIs is to look them up in a directory + using the LDAP protocol [1]. + + If a user's URIs can be found using directory lookup (i.e., searching + for one of the LDAP schema extensions defined below), they should, in + general, be considered "more up-to-date" than URIs in any vCards that + are stored locally. + +2.4.1 LDAP Schema Extensions + + In order to encode the calendaring URIs in the directory, the + following are defined: + + - One object class: + + - calEntry + + - Eight attributes: + + - calCalURI + + - calFBURL + + - calCAPURI + + - calCalAdrURI + + - calOtherCalURIs + + - calOtherFBURLs + + - calOtherCAPURIs + + - calOtherCalAdrURIs + + The calCalURI contains the URI to a snapshot of the user's entire + default calendar. The calFBURL contains the URI to the user's default + busy time data. The calCAPURI represents contains a URI that can be + used to communicate with the user's calendar. The calCalAdrURI + contains a URI that points to the location to which event requests + should be sent for that user. + + + +Small, et al. Standards Track [Page 9] + +RFC 2739 Locating a Calendar User January 2000 + + + The calOtherCalURIs is a multi-valued property containing URIs to + snapshots of other calendars that the user may have. The + calOtherFBURLs is a multi-valued property containing URIs to other + free/busy data that the user may have. The calOtherCAPURIs attribute + is a multi-valued property containing URIs to other calendars that + the user may have. The calOtherCalAdrURIs attribute is a multi-valued + property containing URIs to other locations that a user may want + event requests sent to. + + There is no predetermined order to the values in either multi-valued + property. + +2.4.2 Notation + + The notation used in this memo is the same as that used in [2]. + +2.4.3 Object Definitions + +2.4.3.1 calEntry + + The Calendar Entry is a class derived from "TOP" [2], which contains + the four calendaring attributes. + + (1.2.840.113556.1.5.87 + NAME 'calEntry' + TOP + AUXILIARY + MAY (calCalURI calFBURL calOtherCalURIs calOtherFBURLs calCAPURI + calOtherCAPURLs) + ) + +2.4.4 Attribute Definitions + +2.4.4.1 calCalURI + + (1.2.840.113556.1.4.478 + NAME 'calCalURI' + EQUALITY caseIgnoreMatch + SUBSTRING caseIgnoreMatch + SYNTAX 'IA5String' + USAGE userApplications + ) + +2.4.4.2 calFBURL + + (1.2.840.113556.1.4.479 + NAME 'calFBURL' + EQUALITY caseIgnoreMatch + + + +Small, et al. Standards Track [Page 10] + +RFC 2739 Locating a Calendar User January 2000 + + + SUBSTRING caseIgnoreMatch + SYNTAX 'IA5String' + USAGE userApplications + ) + +2.4.4.3 calCAPURI + + (1.2.840.113556.1.4.480 + NAME 'calCAPURI' + EQUALITY caseIgnoreMatch + SUBSTRING caseIgnoreMatch + SYNTAX 'IA5String' + USAGE userApplications + ) + +2.4.4.4 calCalAdrURI + + (1.2.840.113556.1.4.481 + NAME 'calCalAdrURI' + EQUALITY caseIgnoreMatch + SUBSTRING caseIgnoreMatch + SYNTAX 'IA5String' + USAGE userApplications + ) + +2.4.4.5 calOtherCalURIs + + (1.2.840.113556.1.4.482 + NAME 'calOtherCalURIs' + EQUALITY caseIgnoreMatch + SUBSTRING caseIgnoreMatch + SYNTAX 'IA5String' + MULTI-VALUE + USAGE userApplications + ) + +2.4.4.6 calOtherFBURLs + + (1.2.840.113556.1.4.483 + NAME 'calOtherFBURLs' + EQUALITY caseIgnoreMatch + SUBSTRING caseIgnoreMatch + SYNTAX 'IA5String' + MULTI-VALUE + USAGE userApplications + ) + + + + + +Small, et al. Standards Track [Page 11] + +RFC 2739 Locating a Calendar User January 2000 + + +2.4.4.7 calOtherCAPURIs + + (1.2.840.113556.1.4.484 + NAME 'calOtherCAPURIs' + EQUALITY caseIgnoreMatch + SUBSTRING caseIgnoreMatch + SYNTAX 'IA5String' + MULTI-VALUE + USAGE userApplications + ) + +2.4.4.8 calOtherCalAdrURIs + + (1.2.840.113556.1.4.485 + NAME 'calOtherCalAdrURIs' + EQUALITY caseIgnoreMatch + SUBSTRING caseIgnoreMatch + SYNTAX 'IA5String' + MULTI-VALUE + USAGE userApplications + ) + +3 IANA Considerations + + This memo defines IANA registered extensions to the attributes + defined by LDAP [1] and vCard [3]. + + IANA registration proposals for vCard are to be emailed to the + registration agent for the "text/directory" MIME content-type, + using the format defined in + [3]. + +4 Security Considerations + + Standard vCard and LDAP security rules and support apply for the + extensions described in this document, and there are no special + security issues for these extensions. + + Please note, though, that LDAP servers may permit anonymous clients + to refresh entries which they did not create. Servers are also + permitted to control a refresh access to an entry by requiring + clients to bind before issuing a RefreshRequest. This will have + implications on the server performance and scalability. + + Please also note, though, that vCard objects may have been created by + an entity other than that represented by the vCard. Recipients should + be certain of the source that generated the vCard. + + + + +Small, et al. Standards Track [Page 12] + +RFC 2739 Locating a Calendar User January 2000 + + + Also, care should be taken in making use of information obtained from + directory servers that has been supplied by client, as it may now be + out of date. In many networks, for example, IP addresses are + automatically assigned when a host connects to the network, and may + be reassigned if that host later disconnects. An IP address obtained + from the directory may no longer be assigned to the host that placed + the address in the directory. This issue is not specific to LDAP or + dynamic directories. + +5 Acknowledgments + + The authors wish to acknowledge the work of Alec Dun, who acted as an + author for the early drafts of this memo. In addition, this document + received input from the various participants in the IETF CALSCH + Working Group discussions. + +6 Authors' Addresses + + The following address information is provided in a vCard v3.0 [3], + Electronic Business Card, format. + + BEGIN:VCARD + VERSION:3.0 + N:Small;Tony + FN:Tony Small + ORG:XpertSite.Com + ADR;TYPE=WORK,POSTAL,PARCEL:;;4700 42nd Ave. SW, Suite 440; + Seattle;WA;98116;USA + TEL;TYPE=WORK,MSG:+1-206-937-9972 + TEL;TYPE=WORK,FAX:+1-206-936-7329 + EMAIL;TYPE=INTERNET:tony@xpertsite.com + CALADRURI:MAILTO:tony@xpertsite.com + END:VCARD + + BEGIN:VCARD + VERSION:3.0 + N:Hennessy;Denis + FN:Denis Hennessy + ORG:ISOCOR + ADR;TYPE=WORK,POSTAL,PARCEL:;;42-47 Lower Mount St; + Dublin 2;Ireland + TEL;TYPE=WORK,MSG:+353-1-676-0366 + TEL;TYPE=WORK,FAX:+353-1-676-0856 + EMAIL;TYPE=INTERNET:denis.hennessy@isocor.com + CALADRURI:MAILTO:denis.hennessy@isocor.com + END:VCARD + + + + + +Small, et al. Standards Track [Page 13] + +RFC 2739 Locating a Calendar User January 2000 + + + BEGIN:VCARD + VERSION:3.0 + N:Dawson;Frank + FN:Frank Dawson + ORG:Lotus Development Corporation + ADR;TYPE=WORK,POSTAL,PARCEL:;;6544 Battleford Drive; + Raleigh;NC;27613-3502;USA + TEL;TYPE=WORK,PREF:+1-617-693-8728 + TEL;TYPE=WORK,MSG:+1-919-676-9515 + TEL;TYPE=FAX:+1-617-693-8728 + EMAIL;TYPE=INTERNET,PREF:Frank_Dawson@Lotus.com + EMAIL;TYPE=INTERNET:fdawson@earthlink.net + CALADRURI;TYPE=PREF:MAILTO:Frank_Dawson@Lotus.com + CALADRURI:MAILTO:fdawson@earthlink.net + URL:http://home.earthlink.net/~fdawson + END:VCARD + + This memo is a result of the work of the Internet Engineering Task + Force Calendaring and scheduling Working Group. The chairman of that + working group is: + + BEGIN:VCARD + VERSION:3.0 + N:Egen;Pat + FN:Pat Egen + ORG:Engan Consulting + ADR;TYPE=WORK:;;803 Creek Overlook;Chattanooga;TN;37415;USA + TEL;TYPE=WORK,VOICE:423.875.2652 + TEL;TYPE=WORK,FAX:423.875.2017 + EMAIL:pregen@egenconsulting.com + URL:http://www.egenconsulting.com + CALADRURI:MAILTO:pregen@egenconsulting.com + END:VCARD + + + + + + + + + + + + + + + + + + +Small, et al. Standards Track [Page 14] + +RFC 2739 Locating a Calendar User January 2000 + + +7 Bibliography + + [1] Wahl, M., Howes, T. and S. Kille, "Lightweight Directory Access + Protocol (v3)", RFC 2251, December 1997. + + [2] Wahl, M., Coulbeck, A., Howes, T. and S. Kille, "Lightweight + Directory Access Protocol (v3): Attribute Syntax Definitions", + RFC 2252, December 1997. + + [3] Dawson, F. and T. Howes, "vCard MIME Directory Profile", RFC + 2426, September 1998. + + [4] Dawson, F. and D. Stenerson, "Internet Calendaring and Scheduling + Core Object Specification (iCalendar)", RFC 2445, November 1997. + + [5] Dawson, F. and S. Mansour, "iCalendar Message-Based + Interopability Protocal (iMIP)", RFC 2447, November 1997. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Small, et al. Standards Track [Page 15] + +RFC 2739 Locating a Calendar User January 2000 + + +8 Full Copyright Statement + + Copyright (C) The Internet Society (2000). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Small, et al. Standards Track [Page 16] + diff --git a/addressbook/backend/ebook/e-book-async.c b/addressbook/backend/ebook/e-book-async.c new file mode 100644 index 0000000000..2ccc565eb9 --- /dev/null +++ b/addressbook/backend/ebook/e-book-async.c @@ -0,0 +1,1120 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +#include "ebook/e-book-async.h" + +static GThread *worker_thread; +static GAsyncQueue *to_worker_queue; +static GAsyncQueue *from_worker_queue; + +typedef struct _EBookMsg EBookMsg; + +typedef void (*EBookMsgHandler)(EBookMsg* msg); +typedef void (*EBookMsgDtor)(EBookMsg* msg); + +struct _EBookMsg { + EBookMsgHandler handler; + EBookMsgDtor dtor; +}; + +static gpointer +worker (gpointer data) +{ + while (TRUE) { + EBookMsg *msg = g_async_queue_pop (to_worker_queue); + msg->handler (msg); + msg->dtor (msg); + } + + return NULL; +} + +static gboolean +main_thread_check_for_response (gpointer data) +{ + EBookMsg *msg; + + while ((msg = g_async_queue_try_pop (from_worker_queue)) != NULL) { + msg->handler (msg); + msg->dtor (msg); + } + + return TRUE; +} + +static void +e_book_msg_init (EBookMsg *msg, EBookMsgHandler handler, EBookMsgDtor dtor) +{ + msg->handler = handler; + msg->dtor = dtor; +} + +static void +init_async() +{ + static gboolean init_done = FALSE; + if (!init_done) { + init_done = TRUE; + to_worker_queue = g_async_queue_new (); + from_worker_queue = g_async_queue_new (); + worker_thread = g_thread_create (worker, NULL, FALSE, NULL); + g_timeout_add (300, main_thread_check_for_response, NULL); + } +} + + + +typedef struct { + EBookMsg msg; + + EBook *book; + char *uri; + EBookCallback open_response; + gpointer closure; +} LoadUriMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + EBookCallback open_response; + gpointer closure; +} LoadUriResponse; + +static void +_load_uri_response_handler (EBookMsg *msg) +{ + LoadUriResponse *resp = (LoadUriResponse*)msg; + + resp->open_response (resp->book, resp->status, resp->closure); +} + +static void +_load_uri_response_dtor (EBookMsg *msg) +{ + LoadUriResponse *resp = (LoadUriResponse*)msg; + + g_object_unref (resp->book); + g_free (resp); +} + +static void +_load_uri_handler (EBookMsg *msg) +{ + LoadUriMsg *uri_msg = (LoadUriMsg *)msg; + LoadUriResponse *response; + GError *error = NULL; + + response = g_new (LoadUriResponse, 1); + e_book_msg_init ((EBookMsg*)response, _load_uri_response_handler, _load_uri_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_load_uri (uri_msg->book, uri_msg->uri, FALSE, &error)) { + response->status = error->code; + g_error_free (error); + } + + response->book = uri_msg->book; + response->open_response = uri_msg->open_response; + response->closure = uri_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_load_uri_dtor (EBookMsg *msg) +{ + LoadUriMsg *uri_msg = (LoadUriMsg *)msg; + + g_free (uri_msg->uri); + g_free (uri_msg); +} + +void +e_book_async_load_uri (EBook *book, + const char *uri, + EBookCallback open_response, + gpointer closure) +{ + LoadUriMsg *msg; + + init_async (); + + msg = g_new (LoadUriMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _load_uri_handler, _load_uri_dtor); + + msg->book = g_object_ref (book); + msg->uri = g_strdup (uri); + msg->open_response = open_response; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); +} + + +void +e_book_async_unload_uri (EBook *book) +{ + e_book_unload_uri (book, NULL); +} + + + + +typedef struct { + EBookMsg msg; + + EBookCallback open_response; + gpointer closure; +} DefaultBookMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + EBookCallback open_response; + gpointer closure; +} DefaultBookResponse; + +static void +_default_book_response_handler (EBookMsg *msg) +{ + LoadUriResponse *resp = (LoadUriResponse*)msg; + + resp->open_response (resp->book, resp->status, resp->closure); +} + +static void +_default_book_response_dtor (EBookMsg *msg) +{ + LoadUriResponse *resp = (LoadUriResponse*)msg; + + g_object_unref (resp->book); + g_free (resp); +} + +static void +_default_book_handler (EBookMsg *msg) +{ + DefaultBookMsg *dfb_msg = (DefaultBookMsg *)msg; + DefaultBookResponse *response; + GError *error = NULL; + + response = g_new (DefaultBookResponse, 1); + e_book_msg_init ((EBookMsg*)response, _default_book_response_handler, _default_book_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_get_default_addressbook (&response->book, &error)) { + response->status = error->code; + g_error_free (error); + } + + response->open_response = dfb_msg->open_response; + response->closure = dfb_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_default_book_dtor (EBookMsg *msg) +{ + DefaultBookMsg *dfb_msg = (DefaultBookMsg *)msg; + + g_free (dfb_msg); +} + +void +e_book_async_get_default_addressbook (EBookCallback open_response, + gpointer closure) +{ + DefaultBookMsg *msg; + + init_async (); + + msg = g_new (DefaultBookMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _default_book_handler, _default_book_dtor); + + msg->open_response = open_response; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); +} + + + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookFieldsCallback cb; + gpointer closure; +} GetFieldsMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + GList *fields; + EBookFieldsCallback cb; + gpointer closure; +} GetFieldsResponse; + +static void +_get_fields_response_handler (EBookMsg *msg) +{ + GetFieldsResponse *resp = (GetFieldsResponse*)msg; + GList *l; + EList *fields = e_list_new ((EListCopyFunc) g_strdup, + (EListFreeFunc) g_free, + NULL); + + for (l = resp->fields; l; l = l->next) + e_list_append (fields, l->data); + + if (resp->cb) + resp->cb (resp->book, resp->status, fields, resp->closure); + + g_object_unref (fields); +} + +static void +_get_fields_response_dtor (EBookMsg *msg) +{ + GetFieldsResponse *resp = (GetFieldsResponse*)msg; + + g_list_foreach (resp->fields, (GFunc)g_free, NULL); + g_list_free (resp->fields); + g_object_unref (resp->book); + g_free (resp); +} + +static void +_get_fields_handler (EBookMsg *msg) +{ + GetFieldsMsg *fields_msg = (GetFieldsMsg *)msg; + GetFieldsResponse *response; + GError *error = NULL; + + response = g_new (GetFieldsResponse, 1); + e_book_msg_init ((EBookMsg*)response, _get_fields_response_handler, _get_fields_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_get_supported_fields (fields_msg->book, &response->fields, &error)) { + response->status = error->code; + g_error_free (error); + } + response->book = fields_msg->book; + response->cb = fields_msg->cb; + response->closure = fields_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +guint +e_book_async_get_supported_fields (EBook *book, + EBookFieldsCallback cb, + gpointer closure) +{ + GetFieldsMsg *msg; + + init_async (); + + msg = g_new (GetFieldsMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _get_fields_handler, (EBookMsgDtor)g_free); + + msg->book = g_object_ref (book); + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); + + return 0; +} + + + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookAuthMethodsCallback cb; + gpointer closure; +} GetMethodsMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + GList *methods; + EBookAuthMethodsCallback cb; + gpointer closure; +} GetMethodsResponse; + +static void +_get_methods_response_handler (EBookMsg *msg) +{ + GetMethodsResponse *resp = (GetMethodsResponse*)msg; + GList *l; + EList *methods = e_list_new ((EListCopyFunc) g_strdup, + (EListFreeFunc) g_free, + NULL); + + for (l = resp->methods; l; l = l->next) + e_list_append (methods, l->data); + + if (resp->cb) + resp->cb (resp->book, resp->status, methods, resp->closure); + + g_object_unref (methods); +} + +static void +_get_methods_response_dtor (EBookMsg *msg) +{ + GetMethodsResponse *resp = (GetMethodsResponse*)msg; + + g_list_foreach (resp->methods, (GFunc)g_free, NULL); + g_list_free (resp->methods); + g_object_unref (resp->book); + g_free (resp); +} + +static void +_get_methods_handler (EBookMsg *msg) +{ + GetMethodsMsg *methods_msg = (GetMethodsMsg *)msg; + GetMethodsResponse *response; + GError *error = NULL; + + response = g_new (GetMethodsResponse, 1); + e_book_msg_init ((EBookMsg*)response, _get_methods_response_handler, _get_methods_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_get_supported_auth_methods (methods_msg->book, &response->methods, &error)) { + response->status = error->code; + g_error_free (error); + } + + response->book = methods_msg->book; + response->cb = methods_msg->cb; + response->closure = methods_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +guint +e_book_async_get_supported_auth_methods (EBook *book, + EBookAuthMethodsCallback cb, + gpointer closure) +{ + GetMethodsMsg *msg; + + init_async (); + + msg = g_new (GetMethodsMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _get_methods_handler, (EBookMsgDtor)g_free); + + msg->book = g_object_ref (book); + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); + + return 0; +} + + + +typedef struct { + EBookMsg msg; + + EBook *book; + char *user; + char *passwd; + char *auth_method; + EBookCallback cb; + gpointer closure; +} AuthUserMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + EBookCallback cb; + gpointer closure; +} AuthUserResponse; + +static void +_auth_user_response_handler (EBookMsg *msg) +{ + AuthUserResponse *resp = (AuthUserResponse*)msg; + + if (resp->cb) + resp->cb (resp->book, resp->status, resp->closure); +} + +static void +_auth_user_response_dtor (EBookMsg *msg) +{ + AuthUserResponse *resp = (AuthUserResponse*)msg; + + g_object_unref (resp->book); + g_free (resp); +} + +static void +_auth_user_handler (EBookMsg *msg) +{ + AuthUserMsg *auth_msg = (AuthUserMsg *)msg; + AuthUserResponse *response; + GError *error = NULL; + + response = g_new (AuthUserResponse, 1); + e_book_msg_init ((EBookMsg*)response, _auth_user_response_handler, _auth_user_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_authenticate_user (auth_msg->book, auth_msg->user, auth_msg->passwd, auth_msg->auth_method, &error)) { + response->status = error->code; + g_error_free (error); + } + response->book = auth_msg->book; + response->cb = auth_msg->cb; + response->closure = auth_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_auth_user_dtor (EBookMsg *msg) +{ + AuthUserMsg *auth_msg = (AuthUserMsg *)msg; + + g_free (auth_msg->user); + g_free (auth_msg->passwd); + g_free (auth_msg->auth_method); + + g_free (auth_msg); +} + +/* User authentication. */ +void +e_book_async_authenticate_user (EBook *book, + const char *user, + const char *passwd, + const char *auth_method, + EBookCallback cb, + gpointer closure) +{ + AuthUserMsg *msg; + + init_async (); + + msg = g_new (AuthUserMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _auth_user_handler, _auth_user_dtor); + + msg->book = g_object_ref (book); + msg->user = g_strdup (user); + msg->passwd = g_strdup (passwd); + msg->auth_method = g_strdup (auth_method); + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); +} + + + +typedef struct { + EBookMsg msg; + + EBook *book; + char *id; + EBookContactCallback cb; + gpointer closure; +} GetContactMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EContact *contact; + EBookStatus status; + EBookContactCallback cb; + gpointer closure; +} GetContactResponse; + +static void +_get_contact_response_handler (EBookMsg *msg) +{ + GetContactResponse *resp = (GetContactResponse*)msg; + + if (resp->cb) + resp->cb (resp->book, resp->status, resp->contact, resp->closure); +} + +static void +_get_contact_response_dtor (EBookMsg *msg) +{ + GetContactResponse *resp = (GetContactResponse*)msg; + + g_object_unref (resp->contact); + g_object_unref (resp->book); + g_free (resp); +} + +static void +_get_contact_handler (EBookMsg *msg) +{ + GetContactMsg *get_contact_msg = (GetContactMsg *)msg; + GetContactResponse *response; + GError *error = NULL; + + response = g_new (GetContactResponse, 1); + e_book_msg_init ((EBookMsg*)response, _get_contact_response_handler, _get_contact_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_get_contact (get_contact_msg->book, get_contact_msg->id, &response->contact, &error)) { + response->status = error->code; + g_error_free (error); + } + response->book = get_contact_msg->book; + response->cb = get_contact_msg->cb; + response->closure = get_contact_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_get_contact_dtor (EBookMsg *msg) +{ + GetContactMsg *get_contact_msg = (GetContactMsg *)msg; + + g_free (get_contact_msg->id); + g_free (get_contact_msg); +} + +/* Fetching contacts. */ +guint +e_book_async_get_contact (EBook *book, + const char *id, + EBookContactCallback cb, + gpointer closure) +{ + GetContactMsg *msg; + + init_async (); + + msg = g_new (GetContactMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _get_contact_handler, _get_contact_dtor); + + msg->book = g_object_ref (book); + msg->id = g_strdup (id); + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); + + return 0; +} + + + +/* Deleting cards. */ +gboolean +e_book_async_remove_contact (EBook *book, + EContact *contact, + EBookCallback cb, + gpointer closure) +{ + const char *id = e_contact_get_const (contact, E_CONTACT_UID); + + return e_book_async_remove_contact_by_id (book, id, cb, closure); +} + +gboolean +e_book_async_remove_contact_by_id (EBook *book, + const char *id, + EBookCallback cb, + gpointer closure) +{ + GList *list = g_list_append (NULL, g_strdup (id)); + + return e_book_async_remove_contacts (book, list, cb, closure); +} + + +typedef struct { + EBookMsg msg; + + EBook *book; + GList *id_list; + EBookCallback cb; + gpointer closure; +} RemoveContactsMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + EBookCallback cb; + gpointer closure; +} RemoveContactsResponse; + +static void +_remove_contacts_response_handler (EBookMsg *msg) +{ + RemoveContactsResponse *resp = (RemoveContactsResponse*)msg; + + if (resp->cb) + resp->cb (resp->book, resp->status, resp->closure); +} + +static void +_remove_contacts_response_dtor (EBookMsg *msg) +{ + RemoveContactsResponse *resp = (RemoveContactsResponse*)msg; + + g_object_unref (resp->book); + g_free (resp); +} + +static void +_remove_contacts_handler (EBookMsg *msg) +{ + RemoveContactsMsg *remove_contacts_msg = (RemoveContactsMsg *)msg; + RemoveContactsResponse *response; + GError *error = NULL; + + response = g_new (RemoveContactsResponse, 1); + e_book_msg_init ((EBookMsg*)response, _remove_contacts_response_handler, _remove_contacts_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_remove_contacts (remove_contacts_msg->book, remove_contacts_msg->id_list, &error)) { + response->status = error->code; + g_error_free (error); + } + response->book = remove_contacts_msg->book; + response->cb = remove_contacts_msg->cb; + response->closure = remove_contacts_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_remove_contacts_dtor (EBookMsg *msg) +{ + RemoveContactsMsg *remove_contacts_msg = (RemoveContactsMsg *)msg; + + g_list_foreach (remove_contacts_msg->id_list, (GFunc)g_free, NULL); + g_list_free (remove_contacts_msg->id_list); + g_free (remove_contacts_msg); +} + +gboolean +e_book_async_remove_contacts (EBook *book, + GList *id_list, + EBookCallback cb, + gpointer closure) +{ + RemoveContactsMsg *msg; + GList *l; + init_async (); + + msg = g_new (RemoveContactsMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _remove_contacts_handler, _remove_contacts_dtor); + + msg->book = g_object_ref (book); + msg->id_list = g_list_copy (id_list); + for (l = msg->id_list; l; l = l->next) + l->data = g_strdup (l->data); + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); + + return 0; +} + + + +/* Adding contacts. */ +typedef struct { + EBookMsg msg; + + EBook *book; + EContact *contact; + EBookIdCallback cb; + gpointer closure; +} AddContactMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + char *id; + EBookStatus status; + EBookIdCallback cb; + gpointer closure; +} AddContactResponse; + +static void +_add_contact_response_handler (EBookMsg *msg) +{ + AddContactResponse *resp = (AddContactResponse*)msg; + + if (resp->cb) + resp->cb (resp->book, resp->status, resp->id, resp->closure); +} + +static void +_add_contact_response_dtor (EBookMsg *msg) +{ + AddContactResponse *resp = (AddContactResponse*)msg; + + g_object_unref (resp->book); + g_free (resp->id); + g_free (resp); +} + +static void +_add_contact_handler (EBookMsg *msg) +{ + AddContactMsg *add_contact_msg = (AddContactMsg *)msg; + AddContactResponse *response; + GError *error = NULL; + + response = g_new (AddContactResponse, 1); + e_book_msg_init ((EBookMsg*)response, _add_contact_response_handler, _add_contact_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_add_contact (add_contact_msg->book, add_contact_msg->contact, &error)) { + response->status = error->code; + response->id = NULL; + g_error_free (error); + } + else { + response->id = e_contact_get (add_contact_msg->contact, E_CONTACT_UID); + } + response->book = add_contact_msg->book; + response->cb = add_contact_msg->cb; + response->closure = add_contact_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_add_contact_dtor (EBookMsg *msg) +{ + AddContactMsg *add_contact_msg = (AddContactMsg *)msg; + + g_object_unref (add_contact_msg->contact); + g_free (add_contact_msg); +} + +gboolean +e_book_async_add_contact (EBook *book, + EContact *contact, + EBookIdCallback cb, + gpointer closure) +{ + AddContactMsg *msg; + + init_async (); + + msg = g_new (AddContactMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _add_contact_handler, _add_contact_dtor); + + msg->book = g_object_ref (book); + msg->contact = g_object_ref (contact); /* XXX maybe we should _duplicate it here instead */ + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); + + return TRUE; +} + + + +/* Modifying cards. */ +typedef struct { + EBookMsg msg; + + EBook *book; + EContact *contact; + EBookCallback cb; + gpointer closure; +} CommitContactMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + EBookCallback cb; + gpointer closure; +} CommitContactResponse; + +static void +_commit_contact_response_handler (EBookMsg *msg) +{ + CommitContactResponse *resp = (CommitContactResponse*)msg; + + if (resp->cb) + resp->cb (resp->book, resp->status, resp->closure); +} + +static void +_commit_contact_response_dtor (EBookMsg *msg) +{ + CommitContactResponse *resp = (CommitContactResponse*)msg; + + g_object_unref (resp->book); + g_free (resp); +} + +static void +_commit_contact_handler (EBookMsg *msg) +{ + CommitContactMsg *commit_contact_msg = (CommitContactMsg *)msg; + CommitContactResponse *response; + GError *error = NULL; + + response = g_new (CommitContactResponse, 1); + e_book_msg_init ((EBookMsg*)response, _commit_contact_response_handler, _commit_contact_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_commit_contact (commit_contact_msg->book, commit_contact_msg->contact, &error)) { + response->status = error->code; + g_error_free (error); + } + response->book = commit_contact_msg->book; + response->cb = commit_contact_msg->cb; + response->closure = commit_contact_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_commit_contact_dtor (EBookMsg *msg) +{ + CommitContactMsg *commit_contact_msg = (CommitContactMsg *)msg; + + g_object_unref (commit_contact_msg->contact); + g_free (commit_contact_msg); +} + + +gboolean +e_book_async_commit_contact (EBook *book, + EContact *contact, + EBookCallback cb, + gpointer closure) +{ + CommitContactMsg *msg; + + init_async (); + + msg = g_new (CommitContactMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _commit_contact_handler, _commit_contact_dtor); + + msg->book = g_object_ref (book); + msg->contact = g_object_ref (contact); /* XXX maybe we should _duplicate it here instead */ + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); + + return TRUE; +} + + + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookQuery *query; + EBookBookViewCallback cb; + gpointer closure; +} GetBookViewMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + EBookView *book_view; + EBookBookViewCallback cb; + gpointer closure; +} GetBookViewResponse; + +static void +_get_book_view_response_handler (EBookMsg *msg) +{ + GetBookViewResponse *resp = (GetBookViewResponse*)msg; + + if (resp->cb) + resp->cb (resp->book, resp->status, resp->book_view, resp->closure); +} + +static void +_get_book_view_response_dtor (EBookMsg *msg) +{ + GetBookViewResponse *resp = (GetBookViewResponse*)msg; + + g_object_unref (resp->book); + g_free (resp); +} + +static void +_get_book_view_handler (EBookMsg *msg) +{ + GetBookViewMsg *view_msg = (GetBookViewMsg *)msg; + GetBookViewResponse *response; + GError *error = NULL; + + response = g_new (GetBookViewResponse, 1); + e_book_msg_init ((EBookMsg*)response, _get_book_view_response_handler, _get_book_view_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_get_book_view (view_msg->book, view_msg->query, NULL, -1, &response->book_view, &error)) { + response->status = error->code; + g_error_free (error); + } + response->book = view_msg->book; + response->cb = view_msg->cb; + response->closure = view_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_get_book_view_dtor (EBookMsg *msg) +{ + GetBookViewMsg *view_msg = (GetBookViewMsg *)msg; + + e_book_query_unref (view_msg->query); + g_free (view_msg); +} + +guint +e_book_async_get_book_view (EBook *book, + const gchar *query, + EBookBookViewCallback cb, + gpointer closure) +{ + GetBookViewMsg *msg; + + init_async (); + + msg = g_new (GetBookViewMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _get_book_view_handler, _get_book_view_dtor); + + msg->book = g_object_ref (book); + msg->query = e_book_query_from_string (query); + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); + + return 0; +} + + + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookQuery *query; + EBookContactsCallback cb; + gpointer closure; +} GetContactsMsg; + +typedef struct { + EBookMsg msg; + + EBook *book; + EBookStatus status; + GList *contacts; + EBookContactsCallback cb; + gpointer closure; +} GetContactsResponse; + +static void +_get_contacts_response_handler (EBookMsg *msg) +{ + GetContactsResponse *resp = (GetContactsResponse*)msg; + + if (resp->cb) + resp->cb (resp->book, resp->status, resp->contacts, resp->closure); +} + +static void +_get_contacts_response_dtor (EBookMsg *msg) +{ + GetContactsResponse *resp = (GetContactsResponse*)msg; + + g_object_unref (resp->book); + g_free (resp); +} + +static void +_get_contacts_handler (EBookMsg *msg) +{ + GetContactsMsg *view_msg = (GetContactsMsg *)msg; + GetContactsResponse *response; + GError *error = NULL; + + response = g_new (GetContactsResponse, 1); + e_book_msg_init ((EBookMsg*)response, _get_contacts_response_handler, _get_contacts_response_dtor); + + response->status = E_BOOK_ERROR_OK; + if (!e_book_get_contacts (view_msg->book, view_msg->query, &response->contacts, &error)) { + response->status = error->code; + g_error_free (error); + } + response->book = view_msg->book; + response->cb = view_msg->cb; + response->closure = view_msg->closure; + + g_async_queue_push (from_worker_queue, response); +} + +static void +_get_contacts_dtor (EBookMsg *msg) +{ + GetContactsMsg *view_msg = (GetContactsMsg *)msg; + + e_book_query_unref (view_msg->query); + g_free (view_msg); +} + +guint +e_book_async_get_contacts (EBook *book, + const gchar *query, + EBookContactsCallback cb, + gpointer closure) +{ + GetContactsMsg *msg; + + init_async (); + + msg = g_new (GetContactsMsg, 1); + e_book_msg_init ((EBookMsg*)msg, _get_contacts_handler, _get_contacts_dtor); + + msg->book = g_object_ref (book); + msg->query = e_book_query_from_string (query); + msg->cb = cb; + msg->closure = closure; + + g_async_queue_push (to_worker_queue, msg); + + return 0; +} diff --git a/addressbook/backend/ebook/e-book-async.h b/addressbook/backend/ebook/e-book-async.h new file mode 100644 index 0000000000..097f3cff61 --- /dev/null +++ b/addressbook/backend/ebook/e-book-async.h @@ -0,0 +1,107 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * The Evolution addressbook client object. + * + * Author: + * Chris Toshok (toshok@ximian.com) + * + * Copyright (C) 2003, Ximian, Inc. + */ + +#ifndef __E_BOOK_ASYNC_H__ +#define __E_BOOK_ASYNC_H__ + +#include +#include + +#include +#include +#include + +G_BEGIN_DECLS + +/* Callbacks for asynchronous functions. */ +typedef void (*EBookCallback) (EBook *book, EBookStatus status, gpointer closure); +typedef void (*EBookOpenProgressCallback) (EBook *book, + const char *status_message, + short percent, + gpointer closure); +typedef void (*EBookIdCallback) (EBook *book, EBookStatus status, const char *id, gpointer closure); +typedef void (*EBookContactCallback) (EBook *book, EBookStatus status, EContact *contact, gpointer closure); +typedef void (*EBookContactsCallback) (EBook *book, EBookStatus status, GList *contacts, gpointer closure); +typedef void (*EBookBookViewCallback) (EBook *book, EBookStatus status, EBookView *book_view, gpointer closure); +typedef void (*EBookFieldsCallback) (EBook *book, EBookStatus status, EList *fields, gpointer closure); +typedef void (*EBookAuthMethodsCallback) (EBook *book, EBookStatus status, EList *auth_methods, gpointer closure); + +void e_book_async_load_uri (EBook *book, + const char *uri, + EBookCallback open_response, + gpointer closure); + +void e_book_async_get_default_addressbook (EBookCallback open_response, + gpointer closure); + +void e_book_async_unload_uri (EBook *book); + +guint e_book_async_get_supported_fields (EBook *book, + EBookFieldsCallback cb, + gpointer closure); + +guint e_book_async_get_supported_auth_methods (EBook *book, + EBookAuthMethodsCallback cb, + gpointer closure); + +/* User authentication. */ +void e_book_async_authenticate_user (EBook *book, + const char *user, + const char *passwd, + const char *auth_method, + EBookCallback cb, + gpointer closure); + +/* Fetching cards. */ +guint e_book_async_get_contact (EBook *book, + const char *id, + EBookContactCallback cb, + gpointer closure); + +guint e_book_async_get_contacts (EBook *book, + const char *query, + EBookContactsCallback cb, + gpointer closure); + +/* Deleting cards. */ +gboolean e_book_async_remove_contact (EBook *book, + EContact *contact, + EBookCallback cb, + gpointer closure); +gboolean e_book_async_remove_contact_by_id (EBook *book, + const char *id, + EBookCallback cb, + gpointer closure); + +gboolean e_book_async_remove_contacts (EBook *book, + GList *id_list, + EBookCallback cb, + gpointer closure); + +/* Adding cards. */ +gboolean e_book_async_add_contact (EBook *book, + EContact *contact, + EBookIdCallback cb, + gpointer closure); + +/* Modifying cards. */ +gboolean e_book_async_commit_contact (EBook *book, + EContact *contact, + EBookCallback cb, + gpointer closure); + +guint e_book_async_get_book_view (EBook *book, + const gchar *query, /* XXX this needs to change to an EBookQuery */ + EBookBookViewCallback cb, + gpointer closure); + +G_END_DECLS + +#endif /* ! __E_BOOK_H__ */ diff --git a/addressbook/backend/ebook/e-book-listener.c b/addressbook/backend/ebook/e-book-listener.c index 9d6d876045..0bb5193376 100644 --- a/addressbook/backend/ebook/e-book-listener.c +++ b/addressbook/backend/ebook/e-book-listener.c @@ -11,13 +11,14 @@ #include #include +#include "e-contact.h" #include "e-book-listener.h" #include "e-book-marshal.h" -static EBookStatus e_book_listener_convert_status (GNOME_Evolution_Addressbook_BookListener_CallStatus status); +static EBookStatus e_book_listener_convert_status (GNOME_Evolution_Addressbook_CallStatus status); enum { - RESPONSES_QUEUED, + RESPONSE, LAST_SIGNAL }; @@ -26,569 +27,267 @@ static guint e_book_listener_signals [LAST_SIGNAL]; static BonoboObjectClass *parent_class; struct _EBookListenerPrivate { - GList *response_queue; - gint timeout_id; - - guint timeout_lock : 1; guint stopped : 1; }; -static void -response_free (EBookListenerResponse *resp) -{ - if (resp == NULL) - return; - - g_free (resp->msg); - g_free (resp->id); - - if (resp->book != CORBA_OBJECT_NIL) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - - bonobo_object_release_unref (resp->book, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_listener_destroy: " - "Exception destroying book " - "in response queue!\n"); - } - - CORBA_exception_free (&ev); - } - - if (resp->cursor != CORBA_OBJECT_NIL) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - - bonobo_object_release_unref (resp->cursor, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_listener_destroy: " - "Exception destroying cursor " - "in response queue!\n"); - } - - CORBA_exception_free (&ev); - } - - if (resp->book_view != CORBA_OBJECT_NIL) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - - bonobo_object_release_unref (resp->book_view, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_listener_destroy: " - "Exception destroying book_view " - "in response queue!\n"); - } - - CORBA_exception_free (&ev); - } - - g_free (resp); -} - -static gboolean -e_book_listener_check_queue (EBookListener *listener) -{ - if (listener->priv->timeout_lock) - return TRUE; - - listener->priv->timeout_lock = TRUE; - - if (listener->priv->response_queue != NULL && !listener->priv->stopped) { - g_signal_emit (listener, e_book_listener_signals [RESPONSES_QUEUED], 0); - } - - if (listener->priv->response_queue == NULL || listener->priv->stopped) { - listener->priv->timeout_id = 0; - listener->priv->timeout_lock = FALSE; - bonobo_object_unref (BONOBO_OBJECT (listener)); /* release the timeout's reference */ - return FALSE; - } - - listener->priv->timeout_lock = FALSE; - return TRUE; -} - -static void -e_book_listener_queue_response (EBookListener *listener, - EBookListenerResponse *response) +static EBookStatus +e_book_listener_convert_status (const GNOME_Evolution_Addressbook_CallStatus status) { - if (response == NULL) - return; - - if (listener->priv->stopped) { - response_free (response); - return; - } - - listener->priv->response_queue = g_list_append (listener->priv->response_queue, response); - - if (listener->priv->timeout_id == 0) { - - /* 20 == an arbitrary small integer */ - listener->priv->timeout_id = g_timeout_add (20, (GSourceFunc) e_book_listener_check_queue, listener); - - /* Hold a reference on behalf of the timeout */ - bonobo_object_ref (BONOBO_OBJECT (listener)); - + switch (status) { + case GNOME_Evolution_Addressbook_Success: + return E_BOOK_ERROR_OK; + case GNOME_Evolution_Addressbook_RepositoryOffline: + return E_BOOK_ERROR_REPOSITORY_OFFLINE; + case GNOME_Evolution_Addressbook_PermissionDenied: + return E_BOOK_ERROR_PERMISSION_DENIED; + case GNOME_Evolution_Addressbook_ContactNotFound: + return E_BOOK_ERROR_CONTACT_NOT_FOUND; + case GNOME_Evolution_Addressbook_ContactIdAlreadyExists: + return E_BOOK_ERROR_CONTACT_ID_ALREADY_EXISTS; + case GNOME_Evolution_Addressbook_AuthenticationFailed: + return E_BOOK_ERROR_AUTHENTICATION_FAILED; + case GNOME_Evolution_Addressbook_AuthenticationRequired: + return E_BOOK_ERROR_AUTHENTICATION_REQUIRED; + case GNOME_Evolution_Addressbook_TLSNotAvailable: + return E_BOOK_ERROR_TLS_NOT_AVAILABLE; + case GNOME_Evolution_Addressbook_NoSuchBook: + return E_BOOK_ERROR_NO_SUCH_BOOK; + case GNOME_Evolution_Addressbook_OtherError: + default: + return E_BOOK_ERROR_OTHER_ERROR; } } -/* Add, Remove, Modify */ -static void -e_book_listener_queue_generic_response (EBookListener *listener, - EBookListenerOperation op, - EBookStatus status) -{ - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); - - resp->op = op; - resp->status = status; - - e_book_listener_queue_response (listener, resp); -} - -static void -e_book_listener_queue_open_response (EBookListener *listener, - EBookStatus status, - GNOME_Evolution_Addressbook_Book book) -{ - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); - - resp->op = OpenBookResponse; - resp->status = status; - resp->book = book; - - e_book_listener_queue_response (listener, resp); -} - -static void -e_book_listener_queue_open_progress (EBookListener *listener, - const char *msg, - short percent) -{ - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); - - resp->op = OpenProgressEvent; - resp->msg = g_strdup (msg); - resp->percent = percent; - - e_book_listener_queue_response (listener, resp); -} - - -static void -e_book_listener_queue_create_card_response (EBookListener *listener, - EBookStatus status, - const char *id) -{ - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); - - resp->op = CreateCardResponse; - resp->status = status; - resp->id = g_strdup (id); - - e_book_listener_queue_response (listener, resp); -} - -static void -e_book_listener_queue_get_vcard_response (EBookListener *listener, - EBookStatus status, - const char *vcard) -{ - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); - - resp->op = GetCardResponse; - resp->status = status; - resp->vcard = g_strdup (vcard); - - e_book_listener_queue_response (listener, resp); -} - -static void -e_book_listener_queue_get_cursor_response (EBookListener *listener, - EBookStatus status, - GNOME_Evolution_Addressbook_CardCursor cursor) -{ - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); - - resp->op = GetCursorResponse; - resp->status = status; - resp->cursor = cursor; - - e_book_listener_queue_response (listener, resp); -} - -static void -e_book_listener_queue_get_view_response (EBookListener *listener, - EBookStatus status, - GNOME_Evolution_Addressbook_BookView book_view) -{ - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); - - resp->op = GetBookViewResponse; - resp->status = status; - resp->book_view = book_view; - - e_book_listener_queue_response (listener, resp); -} - static void -e_book_listener_queue_get_changes_response (EBookListener *listener, - EBookStatus status, - GNOME_Evolution_Addressbook_BookView book_view) +impl_BookListener_respond_create_contact (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_CallStatus status, + const CORBA_char* id, + CORBA_Environment *ev) { - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); - - resp->op = GetChangesResponse; - resp->status = status; - resp->book_view = book_view; - - e_book_listener_queue_response (listener, resp); -} - -static void -e_book_listener_queue_link_status (EBookListener *listener, - gboolean connected) -{ - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; + EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; - resp = g_new0 (EBookListenerResponse, 1); + response.op = CreateContactResponse; + response.status = e_book_listener_convert_status (status); + response.id = g_strdup (id); - resp->op = LinkStatusEvent; - resp->connected = connected; + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); - e_book_listener_queue_response (listener, resp); + g_free (response.id); } static void -e_book_listener_queue_writable_status (EBookListener *listener, - gboolean writable) +impl_BookListener_respond_remove_contacts (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_CallStatus status, + CORBA_Environment *ev) { - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); + EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; - resp->op = WritableStatusEvent; - resp->writable = writable; + response.op = RemoveContactResponse; + response.status = e_book_listener_convert_status (status); - e_book_listener_queue_response (listener, resp); + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void -e_book_listener_queue_authentication_response (EBookListener *listener, - EBookStatus status) +impl_BookListener_respond_modify_contact (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_CallStatus status, + CORBA_Environment *ev) { - EBookListenerResponse *resp; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); + EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; - resp->op = AuthenticationResponse; - resp->status = status; + response.op = ModifyContactResponse; + response.status = e_book_listener_convert_status (status); - e_book_listener_queue_response (listener, resp); + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void -e_book_listener_queue_get_supported_fields_response (EBookListener *listener, - EBookStatus status, - const GNOME_Evolution_Addressbook_stringlist *fields) +impl_BookListener_respond_get_contact (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_CallStatus status, + const CORBA_char* card, + CORBA_Environment *ev) { - EBookListenerResponse *resp; - int i; - - if (listener->priv->stopped) - return; - - resp = g_new0 (EBookListenerResponse, 1); + EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; - resp->op = GetSupportedFieldsResponse; - resp->status = status; - resp->list = e_list_new ((EListCopyFunc)g_strdup, (EListFreeFunc)g_free, NULL); + response.op = GetContactResponse; + response.status = e_book_listener_convert_status (status); + response.vcard = g_strdup (card); - for (i = 0; i < fields->_length; i ++) { - e_list_append (resp->list, fields->_buffer[i]); - } + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); - e_book_listener_queue_response (listener, resp); + g_free (response.vcard); } static void -e_book_listener_queue_get_supported_auth_methods_response (EBookListener *listener, - EBookStatus status, - const GNOME_Evolution_Addressbook_stringlist *auth_methods) +impl_BookListener_respond_get_contact_list (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_CallStatus status, + const GNOME_Evolution_Addressbook_stringlist *cards, + CORBA_Environment *ev) { - EBookListenerResponse *resp; + EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; int i; if (listener->priv->stopped) return; - resp = g_new0 (EBookListenerResponse, 1); + response.op = GetContactListResponse; + response.status = e_book_listener_convert_status (status); + response.list = NULL; - resp->op = GetSupportedAuthMethodsResponse; - resp->status = status; - resp->list = e_list_new ((EListCopyFunc)g_strdup, (EListFreeFunc)g_free, NULL); - - for (i = 0; i < auth_methods->_length; i ++) { - e_list_append (resp->list, auth_methods->_buffer[i]); + for (i = 0; i < cards->_length; i ++) { + response.list = g_list_prepend (response.list, e_contact_new_from_vcard (cards->_buffer[i])); } - e_book_listener_queue_response (listener, resp); -} - -static void -impl_BookListener_respond_create_card (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - const CORBA_char* id, - CORBA_Environment *ev) -{ - EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); - - e_book_listener_queue_create_card_response ( - listener, - e_book_listener_convert_status (status), - id); -} - -static void -impl_BookListener_respond_remove_cards (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - CORBA_Environment *ev) -{ - EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); - - e_book_listener_queue_generic_response ( - listener, RemoveCardResponse, - e_book_listener_convert_status (status)); -} - -static void -impl_BookListener_respond_modify_card (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - CORBA_Environment *ev) -{ - EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); - - e_book_listener_queue_generic_response ( - listener, ModifyCardResponse, - e_book_listener_convert_status (status)); -} - -static void -impl_BookListener_respond_get_vcard (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - const CORBA_char* card, - CORBA_Environment *ev) -{ - EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); - - e_book_listener_queue_get_vcard_response ( - listener, - e_book_listener_convert_status (status), - g_strdup (card)); -} - -static void -impl_BookListener_respond_get_cursor (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - const GNOME_Evolution_Addressbook_CardCursor cursor, - CORBA_Environment *ev) -{ - EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); - GNOME_Evolution_Addressbook_CardCursor cursor_copy; - - cursor_copy = bonobo_object_dup_ref (cursor, ev); + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); - if (ev->_major != CORBA_NO_EXCEPTION) { - g_warning ("EBookListener: Exception while duplicating CardCursor!\n"); - return; - } - - e_book_listener_queue_get_cursor_response ( - listener, - e_book_listener_convert_status (status), - cursor_copy); + /* XXX free response.list? */ } static void impl_BookListener_respond_get_view (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, + const GNOME_Evolution_Addressbook_CallStatus status, const GNOME_Evolution_Addressbook_BookView book_view, CORBA_Environment *ev) { - EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); - GNOME_Evolution_Addressbook_BookView book_view_copy; + EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; - book_view_copy = bonobo_object_dup_ref (book_view, ev); + printf ("impl_BookListener_respond_get_view\n"); - if (ev->_major != CORBA_NO_EXCEPTION) { - g_warning ("EBookListener: Exception while duplicating BookView.\n"); + if (listener->priv->stopped) return; - } - e_book_listener_queue_get_view_response ( - listener, - e_book_listener_convert_status (status), - book_view_copy); + response.op = GetBookViewResponse; + response.status = e_book_listener_convert_status (status); + response.book_view = bonobo_object_dup_ref (book_view, ev); + + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void impl_BookListener_respond_get_changes (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - const GNOME_Evolution_Addressbook_BookView book_view, + const GNOME_Evolution_Addressbook_CallStatus status, + const GNOME_Evolution_Addressbook_BookChangeList *changes, CORBA_Environment *ev) { EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); - GNOME_Evolution_Addressbook_BookView book_view_copy; + EBookListenerResponse response; + int i; - book_view_copy = bonobo_object_dup_ref (book_view, ev); + response.op = GetChangesResponse; + response.status = e_book_listener_convert_status (status); + response.list = NULL; + + for (i = 0; i < changes->_length; i ++) { + EBookChange *change = g_new (EBookChange, 1); + GNOME_Evolution_Addressbook_BookChangeItem corba_change = changes->_buffer[i]; + + switch (corba_change._d) { + case GNOME_Evolution_Addressbook_ContactAdded: + change->change_type = E_BOOK_CHANGE_CARD_ADDED; + change->vcard = g_strdup (corba_change._u.add_vcard); + break; + case GNOME_Evolution_Addressbook_ContactDeleted: + change->change_type = E_BOOK_CHANGE_CARD_DELETED; + change->id = g_strdup (corba_change._u.del_id); + break; + case GNOME_Evolution_Addressbook_ContactModified: + change->change_type = E_BOOK_CHANGE_CARD_MODIFIED; + change->vcard = g_strdup (corba_change._u.mod_vcard); + break; + } - if (ev->_major != CORBA_NO_EXCEPTION) { - g_warning ("EBookListener: Exception while duplicating BookView.\n"); - return; + response.list = g_list_prepend (response.list, change); } - e_book_listener_queue_get_changes_response ( - listener, - e_book_listener_convert_status (status), - book_view_copy); + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void impl_BookListener_respond_open_book (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - const GNOME_Evolution_Addressbook_Book book, + const GNOME_Evolution_Addressbook_CallStatus status, CORBA_Environment *ev) { - EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); - GNOME_Evolution_Addressbook_Book book_copy; - - book_copy = bonobo_object_dup_ref (book, ev); + EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; - if (ev->_major != CORBA_NO_EXCEPTION) { - g_warning ("EBookListener: Exception while duplicating Book!\n"); - return; - } + response.op = OpenBookResponse; + response.status = e_book_listener_convert_status (status); - e_book_listener_queue_open_response ( - listener, - e_book_listener_convert_status (status), - book_copy); + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void -impl_BookListener_report_open_book_progress (PortableServer_Servant servant, - const CORBA_char *status_message, - const CORBA_short percent, - CORBA_Environment *ev) +impl_BookListener_respond_remove_book (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_CallStatus status, + CORBA_Environment *ev) { EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; - e_book_listener_queue_open_progress ( - listener, status_message, percent); + response.op = RemoveBookResponse; + response.status = e_book_listener_convert_status (status); + + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void impl_BookListener_respond_authentication_result (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, + const GNOME_Evolution_Addressbook_CallStatus status, CORBA_Environment *ev) { EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; + + response.op = AuthenticationResponse; + response.status = e_book_listener_convert_status (status); - e_book_listener_queue_authentication_response ( - listener, status); + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void -impl_BookListener_response_get_supported_fields (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - const GNOME_Evolution_Addressbook_stringlist *fields, - CORBA_Environment *ev) +impl_BookListener_respond_get_supported_fields (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_CallStatus status, + const GNOME_Evolution_Addressbook_stringlist *fields, + CORBA_Environment *ev) { EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; + int i; - e_book_listener_queue_get_supported_fields_response ( - listener, status, fields); -} + response.op = GetSupportedFieldsResponse; + response.status = e_book_listener_convert_status (status); + response.list = NULL; -static void -impl_BookListener_response_get_supported_auth_methods (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookListener_CallStatus status, - const GNOME_Evolution_Addressbook_stringlist *auth_methods, - CORBA_Environment *ev) -{ - EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + for (i = 0; i < fields->_length; i ++) + response.list = g_list_prepend (response.list, g_strdup (fields->_buffer[i])); - e_book_listener_queue_get_supported_auth_methods_response ( - listener, status, auth_methods); + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void -impl_BookListener_report_connection_status (PortableServer_Servant servant, - const CORBA_boolean connected, - CORBA_Environment *ev) +impl_BookListener_respond_get_supported_auth_methods (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_CallStatus status, + const GNOME_Evolution_Addressbook_stringlist *auth_methods, + CORBA_Environment *ev) { EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; + int i; + + response.op = GetSupportedAuthMethodsResponse; + response.status = e_book_listener_convert_status (status); + response.list = NULL; - e_book_listener_queue_link_status ( - listener, connected); + for (i = 0; i < auth_methods->_length; i ++) + response.list = g_list_prepend (response.list, g_strdup (auth_methods->_buffer[i])); + + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } static void @@ -597,89 +296,20 @@ impl_BookListener_report_writable (PortableServer_Servant servant, CORBA_Environment *ev) { EBookListener *listener = E_BOOK_LISTENER (bonobo_object (servant)); + EBookListenerResponse response; - e_book_listener_queue_writable_status (listener, writable); -} + response.op = WritableStatusEvent; + response.writable = writable; -/** - * e_book_listener_check_pending: - * @listener: the #EBookListener - * - * Returns: the number of items on the response queue, - * or -1 if the @listener is isn't an #EBookListener. - */ -int -e_book_listener_check_pending (EBookListener *listener) -{ - g_return_val_if_fail (listener != NULL, -1); - g_return_val_if_fail (E_IS_BOOK_LISTENER (listener), -1); - - return g_list_length (listener->priv->response_queue); + g_signal_emit (listener, e_book_listener_signals [RESPONSE], 0, &response); } -/** - * e_book_listener_pop_response: - * @listener: the #EBookListener for which a request is to be popped - * - * Returns: an #EBookListenerResponse if there are responses on the - * queue to be returned; %NULL if there aren't, or if the @listener - * isn't an EBookListener. - */ -EBookListenerResponse * -e_book_listener_pop_response (EBookListener *listener) -{ - EBookListenerResponse *resp; - GList *popped; - - g_return_val_if_fail (listener != NULL, NULL); - g_return_val_if_fail (E_IS_BOOK_LISTENER (listener), NULL); - - if (listener->priv->response_queue == NULL) - return NULL; - - resp = listener->priv->response_queue->data; - - popped = listener->priv->response_queue; - listener->priv->response_queue = - g_list_remove_link (listener->priv->response_queue, - listener->priv->response_queue); - g_list_free_1 (popped); - - return resp; -} - -static EBookStatus -e_book_listener_convert_status (const GNOME_Evolution_Addressbook_BookListener_CallStatus status) +static void +impl_BookListener_respond_progress (PortableServer_Servant servant, + const CORBA_char * message, + const CORBA_short percent, + CORBA_Environment *ev) { - switch (status) { - case GNOME_Evolution_Addressbook_BookListener_Success: - return E_BOOK_STATUS_SUCCESS; - case GNOME_Evolution_Addressbook_BookListener_RepositoryOffline: - return E_BOOK_STATUS_REPOSITORY_OFFLINE; - case GNOME_Evolution_Addressbook_BookListener_PermissionDenied: - return E_BOOK_STATUS_PERMISSION_DENIED; - case GNOME_Evolution_Addressbook_BookListener_CardNotFound: - return E_BOOK_STATUS_CARD_NOT_FOUND; - case GNOME_Evolution_Addressbook_BookListener_CardIdAlreadyExists: - return E_BOOK_STATUS_CARD_ID_ALREADY_EXISTS; - case GNOME_Evolution_Addressbook_BookListener_ProtocolNotSupported: - return E_BOOK_STATUS_PROTOCOL_NOT_SUPPORTED; - case GNOME_Evolution_Addressbook_BookListener_AuthenticationFailed: - return E_BOOK_STATUS_AUTHENTICATION_FAILED; - case GNOME_Evolution_Addressbook_BookListener_AuthenticationRequired: - return E_BOOK_STATUS_AUTHENTICATION_REQUIRED; - case GNOME_Evolution_Addressbook_BookListener_TLSNotAvailable: - return E_BOOK_STATUS_TLS_NOT_AVAILABLE; - case GNOME_Evolution_Addressbook_BookListener_NoSuchBook: - return E_BOOK_STATUS_NO_SUCH_BOOK; - case GNOME_Evolution_Addressbook_BookListener_OtherError: - return E_BOOK_STATUS_OTHER_ERROR; - default: - g_warning ("e_book_listener_convert_status: Unknown status " - "from card server: %d\n", (int) status); - return E_BOOK_STATUS_UNKNOWN; - - } } static void @@ -701,7 +331,9 @@ e_book_listener_new () { EBookListener *listener; - listener = g_object_new (E_TYPE_BOOK_LISTENER, NULL); + listener = g_object_new (E_TYPE_BOOK_LISTENER, + "poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_ALL_AT_IDLE, NULL), + NULL); e_book_listener_construct (listener); @@ -722,38 +354,6 @@ e_book_listener_stop (EBookListener *listener) listener->priv->stopped = TRUE; } -static void -e_book_listener_dispose (GObject *object) -{ - EBookListener *listener = E_BOOK_LISTENER (object); - - if (listener->priv) { - GList *l; - - /* Remove our response queue handler: In theory, this - can never happen since we always hold a reference - to the listener while the timeout is running. */ - if (listener->priv->timeout_id) { - g_source_remove (listener->priv->timeout_id); - } - - /* Clean up anything still sitting in response_queue */ - for (l = listener->priv->response_queue; l != NULL; l = l->next) { - EBookListenerResponse *resp = l->data; - - response_free (resp); - } - g_list_free (listener->priv->response_queue); - - g_free (listener->priv); - - listener->priv = NULL; - } - - if (G_OBJECT_CLASS (parent_class)->dispose) - G_OBJECT_CLASS (parent_class)->dispose (object); -} - static void e_book_listener_class_init (EBookListenerClass *klass) { @@ -762,31 +362,30 @@ e_book_listener_class_init (EBookListenerClass *klass) parent_class = g_type_class_ref (BONOBO_TYPE_OBJECT); - e_book_listener_signals [RESPONSES_QUEUED] = - g_signal_new ("responses_queued", + e_book_listener_signals [RESPONSE] = + g_signal_new ("response", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EBookListenerClass, responses_queued), + G_STRUCT_OFFSET (EBookListenerClass, response), NULL, NULL, - e_book_marshal_NONE__NONE, - G_TYPE_NONE, 0); - - object_class->dispose = e_book_listener_dispose; + e_book_marshal_NONE__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); epv = &klass->epv; - epv->notifyOpenBookProgress = impl_BookListener_report_open_book_progress; + epv->notifyProgress = impl_BookListener_respond_progress; epv->notifyBookOpened = impl_BookListener_respond_open_book; - epv->notifyCardCreated = impl_BookListener_respond_create_card; - epv->notifyCardsRemoved = impl_BookListener_respond_remove_cards; - epv->notifyCardModified = impl_BookListener_respond_modify_card; + epv->notifyBookRemoved = impl_BookListener_respond_remove_book; + epv->notifyContactCreated = impl_BookListener_respond_create_contact; + epv->notifyContactsRemoved = impl_BookListener_respond_remove_contacts; + epv->notifyContactModified = impl_BookListener_respond_modify_contact; epv->notifyAuthenticationResult = impl_BookListener_respond_authentication_result; - epv->notifySupportedFields = impl_BookListener_response_get_supported_fields; - epv->notifySupportedAuthMethods = impl_BookListener_response_get_supported_auth_methods; - epv->notifyCardRequested = impl_BookListener_respond_get_vcard; - epv->notifyCursorRequested = impl_BookListener_respond_get_cursor; + epv->notifySupportedFields = impl_BookListener_respond_get_supported_fields; + epv->notifySupportedAuthMethods = impl_BookListener_respond_get_supported_auth_methods; + epv->notifyContactRequested = impl_BookListener_respond_get_contact; + epv->notifyContactListRequested = impl_BookListener_respond_get_contact_list; epv->notifyViewRequested = impl_BookListener_respond_get_view; epv->notifyChangesRequested = impl_BookListener_respond_get_changes; - epv->notifyConnectionStatus = impl_BookListener_report_connection_status; epv->notifyWritable = impl_BookListener_report_writable; } diff --git a/addressbook/backend/ebook/e-book-listener.h b/addressbook/backend/ebook/e-book-listener.h index 1b02dd4bb6..4d1f0c0231 100644 --- a/addressbook/backend/ebook/e-book-listener.h +++ b/addressbook/backend/ebook/e-book-listener.h @@ -15,7 +15,6 @@ #include #include #include -#include #define E_TYPE_BOOK_LISTENER (e_book_listener_get_type ()) #define E_BOOK_LISTENER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_LISTENER, EBookListener)) @@ -29,6 +28,7 @@ G_BEGIN_DECLS typedef struct _EBookListener EBookListener; typedef struct _EBookListenerClass EBookListenerClass; typedef struct _EBookListenerPrivate EBookListenerPrivate; +typedef struct _EBookListenerResponse EBookListenerResponse; struct _EBookListener { BonoboObject parent; @@ -39,20 +39,30 @@ struct _EBookListenerClass { BonoboObjectClass parent; POA_GNOME_Evolution_Addressbook_BookListener__epv epv; + /* * Signals */ - void (*responses_queued) (void); + + void (*response) (EBookListener *listener, EBookListenerResponse *response); + + /* Padding for future expansion */ + void (*_ebook_reserved0) (void); + void (*_ebook_reserved1) (void); + void (*_ebook_reserved2) (void); + void (*_ebook_reserved3) (void); + void (*_ebook_reserved4) (void); }; typedef enum { /* Async responses */ OpenBookResponse, - CreateCardResponse, - RemoveCardResponse, - ModifyCardResponse, - GetCardResponse, - GetCursorResponse, + RemoveBookResponse, + CreateContactResponse, + RemoveContactResponse, + ModifyContactResponse, + GetContactResponse, + GetContactListResponse, GetBookViewResponse, GetChangesResponse, AuthenticationResponse, @@ -62,28 +72,22 @@ typedef enum { /* Async events */ LinkStatusEvent, WritableStatusEvent, - OpenProgressEvent, + ProgressEvent, } EBookListenerOperation; -typedef struct { +struct _EBookListenerResponse { EBookListenerOperation op; /* For most Response notifications */ EBookStatus status; - /* For OpenBookResponse */ - GNOME_Evolution_Addressbook_Book book; - - /* For GetCursorResponse */ - GNOME_Evolution_Addressbook_CardCursor cursor; - /* For GetBookViewReponse */ GNOME_Evolution_Addressbook_BookView book_view; /* For GetSupportedFields/GetSupportedAuthMethods */ - EList *list; + GList *list; - /* For OpenProgressEvent */ + /* For ProgressEvent */ char *msg; short percent; @@ -96,12 +100,10 @@ typedef struct { /* For Card[Added|Removed|Modified]Event */ char *id; char *vcard; -} EBookListenerResponse; +}; EBookListener *e_book_listener_new (void); -int e_book_listener_check_pending (EBookListener *listener); -EBookListenerResponse *e_book_listener_pop_response (EBookListener *listener); GType e_book_listener_get_type (void); void e_book_listener_stop (EBookListener *listener); diff --git a/addressbook/backend/ebook/e-book-query.c b/addressbook/backend/ebook/e-book-query.c new file mode 100644 index 0000000000..16e325303c --- /dev/null +++ b/addressbook/backend/ebook/e-book-query.c @@ -0,0 +1,524 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +#include + +#include "e-book-query.h" +#include + +#include +#include + +typedef enum { + E_BOOK_QUERY_TYPE_AND, + E_BOOK_QUERY_TYPE_OR, + E_BOOK_QUERY_TYPE_NOT, + E_BOOK_QUERY_TYPE_FIELD_EXISTS, + E_BOOK_QUERY_TYPE_FIELD_TEST, + E_BOOK_QUERY_TYPE_ANY_FIELD_CONTAINS +} EBookQueryType; + +struct EBookQuery { + EBookQueryType type; + int ref_count; + + union { + struct { + guint nqs; + EBookQuery **qs; + } andor; + + struct { + EBookQuery *q; + } not; + + struct { + EBookQueryTest test; + EContactField field; + char *value; + } field_test; + + struct { + EContactField field; + } exist; + + struct { + char *value; + } any_field_contains; + } query; +}; + +static EBookQuery * +conjoin (EBookQueryType type, int nqs, EBookQuery **qs, gboolean unref) +{ + EBookQuery *ret = g_new0 (EBookQuery, 1); + int i; + + ret->type = type; + ret->query.andor.nqs = nqs; + ret->query.andor.qs = g_new (EBookQuery *, nqs); + for (i = 0; i < nqs; i++) { + ret->query.andor.qs[i] = qs[i]; + if (!unref) + e_book_query_ref (qs[i]); + } + + return ret; +} + +EBookQuery * +e_book_query_and (int nqs, EBookQuery **qs, gboolean unref) +{ + return conjoin (E_BOOK_QUERY_TYPE_AND, nqs, qs, unref); +} + +EBookQuery * +e_book_query_or (int nqs, EBookQuery **qs, gboolean unref) +{ + return conjoin (E_BOOK_QUERY_TYPE_OR, nqs, qs, unref); +} + +static EBookQuery * +conjoinv (EBookQueryType type, EBookQuery *q, va_list ap) +{ + EBookQuery *ret = g_new0 (EBookQuery, 1); + GPtrArray *qs; + + qs = g_ptr_array_new (); + while (q) { + g_ptr_array_add (qs, q); + q = va_arg (ap, EBookQuery *); + } + va_end (ap); + + ret->type = type; + ret->query.andor.nqs = qs->len; + ret->query.andor.qs = (EBookQuery **)qs->pdata; + g_ptr_array_free (qs, FALSE); + + return ret; +} + +EBookQuery * +e_book_query_andv (EBookQuery *q, ...) +{ + va_list ap; + + va_start (ap, q); + return conjoinv (E_BOOK_QUERY_TYPE_AND, q, ap); +} + +EBookQuery * +e_book_query_orv (EBookQuery *q, ...) +{ + va_list ap; + + va_start (ap, q); + return conjoinv (E_BOOK_QUERY_TYPE_OR, q, ap); +} + +EBookQuery * +e_book_query_not (EBookQuery *q, gboolean unref) +{ + EBookQuery *ret = g_new0 (EBookQuery, 1); + + ret->type = E_BOOK_QUERY_TYPE_NOT; + ret->query.not.q = q; + if (!unref) + e_book_query_ref (q); + + return ret; +} + +EBookQuery * +e_book_query_field_test (EContactField field, + EBookQueryTest test, + const char *value) +{ + EBookQuery *ret = g_new0 (EBookQuery, 1); + + ret->type = E_BOOK_QUERY_TYPE_FIELD_TEST; + ret->query.field_test.field = field; + ret->query.field_test.test = test; + ret->query.field_test.value = g_strdup (value); + + return ret; +} + +EBookQuery * +e_book_query_field_exists (EContactField field) +{ + EBookQuery *ret = g_new0 (EBookQuery, 1); + + ret->type = E_BOOK_QUERY_TYPE_FIELD_EXISTS; + ret->query.exist.field = field; + + return ret; +} + +EBookQuery * +e_book_query_any_field_contains (const char *value) +{ + EBookQuery *ret = g_new0 (EBookQuery, 1); + + ret->type = E_BOOK_QUERY_TYPE_ANY_FIELD_CONTAINS; + ret->query.any_field_contains.value = g_strdup (value); + + return ret; +} + +void +e_book_query_unref (EBookQuery *q) +{ + int i; + + if (q->ref_count--) + return; + + switch (q->type) { + case E_BOOK_QUERY_TYPE_AND: + case E_BOOK_QUERY_TYPE_OR: + for (i = 0; i < q->query.andor.nqs; i++) + e_book_query_unref (q->query.andor.qs[i]); + g_free (q->query.andor.qs); + break; + + case E_BOOK_QUERY_TYPE_NOT: + e_book_query_unref (q->query.not.q); + break; + + case E_BOOK_QUERY_TYPE_FIELD_TEST: + g_free (q->query.field_test.value); + break; + + case E_BOOK_QUERY_TYPE_ANY_FIELD_CONTAINS: + g_free (q->query.any_field_contains.value); + break; + + default: + break; + } + + g_free (q); +} + +void +e_book_query_ref (EBookQuery *q) +{ + q->ref_count++; +} + +static ESExpResult * +func_and(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; + EBookQuery **qs; + + if (argc > 0) { + int i; + + qs = g_new0(EBookQuery*, argc); + + for (i = 0; i < argc; i ++) { + GList *list_head = *list; + if (!list_head) + break; + qs[i] = list_head->data; + *list = g_list_remove_link(*list, list_head); + g_list_free_1(list_head); + } + + *list = g_list_prepend(*list, + e_book_query_and (argc, qs, TRUE)); + + g_free (qs); + } + + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + +static ESExpResult * +func_or(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; + EBookQuery **qs; + + if (argc > 0) { + int i; + + qs = g_new0(EBookQuery*, argc); + + for (i = 0; i < argc; i ++) { + GList *list_head = *list; + if (!list_head) + break; + qs[i] = list_head->data; + *list = g_list_remove_link(*list, list_head); + g_list_free_1(list_head); + } + + *list = g_list_prepend(*list, + e_book_query_or (argc, qs, TRUE)); + + g_free (qs); + } + + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + +static ESExpResult * +func_not(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; + + /* just replace the head of the list with the NOT of it. */ + if (argc > 0) { + EBookQuery *term = (*list)->data; + (*list)->data = e_book_query_not (term, TRUE); + } + + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + +static ESExpResult * +func_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; + + if (argc == 2 + && argv[0]->type == ESEXP_RES_STRING + && argv[1]->type == ESEXP_RES_STRING) { + char *propname = argv[0]->value.string; + char *str = argv[1]->value.string; + + if (!strcmp (propname, "x-evolution-any-field")) { + *list = g_list_prepend (*list, e_book_query_any_field_contains (str)); + } + else { + EContactField field = e_contact_field_id (propname); + + if (field) + *list = g_list_prepend (*list, e_book_query_field_test (field, + E_BOOK_QUERY_CONTAINS, + str)); + } + } + + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + +static ESExpResult * +func_is(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; + + if (argc == 2 + && argv[0]->type == ESEXP_RES_STRING + && argv[1]->type == ESEXP_RES_STRING) { + char *propname = argv[0]->value.string; + char *str = argv[1]->value.string; + EContactField field = e_contact_field_id (propname); + + if (field) + *list = g_list_prepend (*list, e_book_query_field_test (field, + E_BOOK_QUERY_IS, + str)); + } + + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + +static ESExpResult * +func_beginswith(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; + + if (argc == 2 + && argv[0]->type == ESEXP_RES_STRING + && argv[1]->type == ESEXP_RES_STRING) { + char *propname = argv[0]->value.string; + char *str = argv[1]->value.string; + EContactField field = e_contact_field_id (propname); + + if (field) + *list = g_list_prepend (*list, e_book_query_field_test (field, + E_BOOK_QUERY_BEGINS_WITH, + str)); + } + + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + +static ESExpResult * +func_endswith(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; + + if (argc == 2 + && argv[0]->type == ESEXP_RES_STRING + && argv[1]->type == ESEXP_RES_STRING) { + char *propname = argv[0]->value.string; + char *str = argv[1]->value.string; + EContactField field = e_contact_field_id (propname); + + if (field) + *list = g_list_prepend (*list, e_book_query_field_test (field, + E_BOOK_QUERY_ENDS_WITH, + str)); + } + + r = e_sexp_result_new(f, ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + +/* 'builtin' functions */ +static struct { + char *name; + ESExpFunc *func; + int type; /* set to 1 if a function can perform shortcut evaluation, or + doesn't execute everything, 0 otherwise */ +} symbols[] = { + { "and", func_and, 0 }, + { "or", func_or, 0 }, + { "not", func_not, 0 }, + { "contains", func_contains, 0 }, + { "is", func_is, 0 }, + { "beginswith", func_beginswith, 0 }, + { "endswith", func_endswith, 0 }, +}; + +EBookQuery* +e_book_query_from_string (const char *query_string) +{ + ESExp *sexp; + ESExpResult *r; + EBookQuery *retval; + GList *list = NULL; + int i; + + sexp = e_sexp_new(); + + for(i=0;inext) { + g_warning ("conversion to EBookQuery"); + retval = NULL; + g_list_foreach (list, (GFunc)e_book_query_unref, NULL); + } + else { + retval = list->data; + } + } + else { + g_warning ("conversion to EBookQuery failed"); + retval = NULL; + } + + g_list_free (list); + return retval; +} + +char* +e_book_query_to_string (EBookQuery *q) +{ + GString *str = g_string_new ("("); + int i; + char *s = NULL; + + switch (q->type) { + case E_BOOK_QUERY_TYPE_AND: + g_string_append (str, "and "); + for (i = 0; i < q->query.andor.nqs; i ++) { + s = e_book_query_to_string (q->query.andor.qs[i]); + g_string_append (str, s); + g_free (s); + g_string_append_c (str, ' '); + } + break; + case E_BOOK_QUERY_TYPE_OR: + g_string_append (str, "or "); + for (i = 0; i < q->query.andor.nqs; i ++) { + s = e_book_query_to_string (q->query.andor.qs[i]); + g_string_append (str, s); + g_free (s); + g_string_append_c (str, ' '); + } + break; + case E_BOOK_QUERY_TYPE_NOT: + s = e_book_query_to_string (q->query.not.q); + g_string_append_printf (str, "not %s", s); + g_free (s); + break; + case E_BOOK_QUERY_TYPE_FIELD_EXISTS: + g_string_append_printf (str, "exists \"%s\"", e_contact_field_name (q->query.exist.field)); + break; + case E_BOOK_QUERY_TYPE_FIELD_TEST: + switch (q->query.field_test.test) { + case E_BOOK_QUERY_IS: s = "is"; break; + case E_BOOK_QUERY_CONTAINS: s = "contains"; break; + case E_BOOK_QUERY_BEGINS_WITH: s = "beginswith"; break; + case E_BOOK_QUERY_ENDS_WITH: s = "endswith"; break; + default: + g_assert_not_reached(); + break; + } + + /* XXX need to escape q->query.field_test.value */ + g_string_append_printf (str, "%s \"%s\" \"%s\"", + s, + e_contact_field_name (q->query.field_test.field), + q->query.field_test.value); + break; + case E_BOOK_QUERY_TYPE_ANY_FIELD_CONTAINS: + g_string_append_printf (str, "contains \"x-evolution-any-field\" \"%s\"", q->query.any_field_contains.value); + break; + } + + + g_string_append (str, ")"); + + return g_string_free (str, FALSE); +} diff --git a/addressbook/backend/ebook/e-book-query.h b/addressbook/backend/ebook/e-book-query.h new file mode 100644 index 0000000000..e36887f6f2 --- /dev/null +++ b/addressbook/backend/ebook/e-book-query.h @@ -0,0 +1,49 @@ + +#ifndef __E_BOOK_QUERY_H__ +#define __E_BOOK_QUERY_H__ + +#include + +G_BEGIN_DECLS + +typedef struct EBookQuery EBookQuery; + +typedef enum { + E_BOOK_QUERY_IS, + E_BOOK_QUERY_CONTAINS, + E_BOOK_QUERY_BEGINS_WITH, + E_BOOK_QUERY_ENDS_WITH, + +#if notyet + E_BOOK_QUERY_LT, + E_BOOK_QUERY_LE, + E_BOOK_QUERY_GT, + E_BOOK_QUERY_GE, + E_BOOK_QUERY_EQ, +#endif +} EBookQueryTest; + +EBookQuery* e_book_query_from_string (const char *sexp); +char* e_book_query_to_string (EBookQuery *q); + +void e_book_query_ref (EBookQuery *q); +void e_book_query_unref (EBookQuery *q); + +EBookQuery* e_book_query_and (int nqs, EBookQuery **qs, gboolean unref); +EBookQuery* e_book_query_andv (EBookQuery *q, ...); +EBookQuery* e_book_query_or (int nqs, EBookQuery **qs, gboolean unref); +EBookQuery* e_book_query_orv (EBookQuery *q, ...); + +EBookQuery* e_book_query_not (EBookQuery *qs, gboolean unref); + +EBookQuery* e_book_query_field_exists (EContactField field); +EBookQuery* e_book_query_field_test (EContactField field, + EBookQueryTest test, + const char *value); + +/* a special any field contains query */ +EBookQuery* e_book_query_any_field_contains (const char *value); + +G_END_DECLS + +#endif /* __E_BOOK_QUERY_H__ */ diff --git a/addressbook/backend/ebook/e-book-types.h b/addressbook/backend/ebook/e-book-types.h index b1900e77ed..4ca69bd516 100644 --- a/addressbook/backend/ebook/e-book-types.h +++ b/addressbook/backend/ebook/e-book-types.h @@ -16,37 +16,52 @@ G_BEGIN_DECLS +#define E_BOOK_ERROR e_book_error_quark() + +GQuark e_book_error_quark (void) G_GNUC_CONST; + typedef enum { - E_BOOK_STATUS_SUCCESS, - E_BOOK_STATUS_UNKNOWN, - E_BOOK_STATUS_REPOSITORY_OFFLINE, - E_BOOK_STATUS_PERMISSION_DENIED, - E_BOOK_STATUS_CARD_NOT_FOUND, - E_BOOK_STATUS_CARD_ID_ALREADY_EXISTS, - E_BOOK_STATUS_PROTOCOL_NOT_SUPPORTED, - E_BOOK_STATUS_CANCELLED, - E_BOOK_STATUS_AUTHENTICATION_FAILED, - E_BOOK_STATUS_AUTHENTICATION_REQUIRED, - E_BOOK_STATUS_TLS_NOT_AVAILABLE, - E_BOOK_STATUS_NO_SUCH_BOOK, - E_BOOK_STATUS_OTHER_ERROR + E_BOOK_ERROR_OK, + E_BOOK_ERROR_INVALID_ARG, + E_BOOK_ERROR_BUSY, + E_BOOK_ERROR_REPOSITORY_OFFLINE, + E_BOOK_ERROR_NO_SUCH_BOOK, + E_BOOK_ERROR_URI_NOT_LOADED, + E_BOOK_ERROR_URI_ALREADY_LOADED, + E_BOOK_ERROR_PERMISSION_DENIED, + E_BOOK_ERROR_CONTACT_NOT_FOUND, + E_BOOK_ERROR_CONTACT_ID_ALREADY_EXISTS, + E_BOOK_ERROR_PROTOCOL_NOT_SUPPORTED, + E_BOOK_ERROR_CANCELLED, + E_BOOK_ERROR_COULD_NOT_CANCEL, + E_BOOK_ERROR_AUTHENTICATION_FAILED, + E_BOOK_ERROR_AUTHENTICATION_REQUIRED, + E_BOOK_ERROR_TLS_NOT_AVAILABLE, + E_BOOK_ERROR_CORBA_EXCEPTION, + E_BOOK_ERROR_OTHER_ERROR } EBookStatus; + typedef enum { - E_BOOK_VIEW_STATUS_SUCCESS, + E_BOOK_VIEW_STATUS_OK, E_BOOK_VIEW_STATUS_TIME_LIMIT_EXCEEDED, E_BOOK_VIEW_STATUS_SIZE_LIMIT_EXCEEDED, - E_BOOK_VIEW_STATUS_INVALID_QUERY, - E_BOOK_VIEW_STATUS_QUERY_REFUSED, - E_BOOK_VIEW_STATUS_OTHER_ERROR, - E_BOOK_VIEW_STATUS_UNKNOWN + E_BOOK_VIEW_ERROR_INVALID_QUERY, + E_BOOK_VIEW_ERROR_QUERY_REFUSED, + E_BOOK_VIEW_ERROR_OTHER_ERROR } EBookViewStatus; typedef enum { - E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS, - E_BOOK_SIMPLE_QUERY_STATUS_CANCELLED, - E_BOOK_SIMPLE_QUERY_STATUS_OTHER_ERROR -} EBookSimpleQueryStatus; + E_BOOK_CHANGE_CARD_ADDED, + E_BOOK_CHANGE_CARD_DELETED, + E_BOOK_CHANGE_CARD_MODIFIED +} EBookChangeType; + +typedef struct { + EBookChangeType change_type; + char *vcard; /* used in the ADDED/MODIFIED case */ + char *id; /* used in the DELETED case */ +} EBookChange; G_END_DECLS diff --git a/addressbook/backend/ebook/e-book-util.c b/addressbook/backend/ebook/e-book-util.c deleted file mode 100644 index cc00d045f4..0000000000 --- a/addressbook/backend/ebook/e-book-util.c +++ /dev/null @@ -1,808 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* - * e-book-util.c - * - * Copyright (C) 2001 Ximian, Inc. - * - * Developed by Jon Trowbridge - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - */ - -#include -#include "e-book-util.h" - -#include -#include -#include -#include -#include "e-card-compare.h" - -typedef struct _CommonBookInfo CommonBookInfo; -struct _CommonBookInfo { - EBookCommonCallback cb; - gpointer closure; -}; - -char * -e_book_expand_uri (const char *uri) -{ - if (!strncmp (uri, "file:", 5)) { - int length = strlen (uri); - int offset = 5; - - if (!strncmp (uri, "file://", 7)) - offset = 7; - - if (length < 3 || strcmp (uri + length - 3, ".db")) { - /* we assume it's a dir and glom addressbook.db onto the end. */ - - char *ret_val; - char *file_name; - - file_name = g_build_filename(uri + offset, "addressbook.db", NULL); - ret_val = g_strdup_printf("file://%s", file_name); - g_free(file_name); - return ret_val; - } - } - - return g_strdup (uri); -} - -static void -got_uri_book_cb (EBook *book, EBookStatus status, gpointer closure) -{ - CommonBookInfo *info = (CommonBookInfo *) closure; - - if (status == E_BOOK_STATUS_SUCCESS) { - info->cb (book, info->closure); - } else { - if (book) - g_object_unref (book); - info->cb (NULL, info->closure); - } - g_free (info); -} - -void -e_book_load_address_book_by_uri (EBook *book, const char *uri, EBookCallback open_response, gpointer closure) -{ - char *real_uri; - - g_return_if_fail (book != NULL); - g_return_if_fail (E_IS_BOOK (book)); - g_return_if_fail (open_response != NULL); - - real_uri = e_book_expand_uri (uri); - - e_book_load_uri (book, real_uri, open_response, closure); - - g_free (real_uri); -} - -void -e_book_use_address_book_by_uri (const char *uri, EBookCommonCallback cb, gpointer closure) -{ - EBook *book; - CommonBookInfo *info; - - g_return_if_fail (cb != NULL); - - info = g_new0 (CommonBookInfo, 1); - info->cb = cb; - info->closure = closure; - - book = e_book_new (); - e_book_load_address_book_by_uri (book, uri, got_uri_book_cb, info); -} - -EConfigListener * -e_book_get_config_database () -{ - static EConfigListener *config_db; - - if (config_db == NULL) - config_db = e_config_listener_new (); - - return config_db; -} - -static EBook *common_default_book = NULL; - -static void -got_default_book_cb (EBook *book, EBookStatus status, gpointer closure) -{ - CommonBookInfo *info = (CommonBookInfo *) closure; - - if (status == E_BOOK_STATUS_SUCCESS) { - - /* We try not to leak in a race condition where the - default book got loaded twice. */ - - if (common_default_book) { - g_object_unref (book); - book = common_default_book; - } - - info->cb (book, info->closure); - - if (common_default_book == NULL) { - common_default_book = book; - } - - } else { - if (book) - g_object_unref (book); - info->cb (NULL, info->closure); - - } - g_free (info); -} - -void -e_book_use_default_book (EBookCommonCallback cb, gpointer closure) -{ - EBook *book; - CommonBookInfo *info; - - g_return_if_fail (cb != NULL); - - if (common_default_book != NULL) { - cb (common_default_book, closure); - return; - } - - info = g_new0 (CommonBookInfo, 1); - info->cb = cb; - info->closure = closure; - - book = e_book_new (); - e_book_load_default_book (book, got_default_book_cb, info); -} - -static char *default_book_uri; - -static char* -get_local_book_uri (void) -{ - char *filename; - char *uri; - - filename = g_build_filename (g_get_home_dir(), - "evolution/local/Contacts/addressbook.db", - NULL); - uri = g_strdup_printf ("file://%s", filename); - - g_free (filename); - - return uri; -} - -static void -set_default_book_uri_local (void) -{ - g_free (default_book_uri); - - default_book_uri = get_local_book_uri (); -} - -static void -set_default_book_uri (char *val) -{ - if (default_book_uri) - g_free (default_book_uri); - - if (val) { - default_book_uri = e_book_expand_uri (val); - g_free (val); - } - else { - set_default_book_uri_local (); - } -} - -#define DEFAULT_CONTACTS_URI_PATH "/apps/evolution/shell/default_folders/contacts_uri" -static void -default_folder_listener (EConfigListener *cl, const char *key, gpointer data) -{ - char *val; - - if (strcmp (key, DEFAULT_CONTACTS_URI_PATH)) - return; - - val = e_config_listener_get_string (cl, DEFAULT_CONTACTS_URI_PATH); - - set_default_book_uri (val); -} - -static void -set_default_book_uri_from_config_db (void) -{ - char *val; - EConfigListener* config_db; - - config_db = e_book_get_config_database (); - val = e_config_listener_get_string_with_default (config_db, DEFAULT_CONTACTS_URI_PATH, NULL, NULL); - - g_signal_connect (config_db, - "key_changed", - G_CALLBACK (default_folder_listener), NULL); - - set_default_book_uri (val); -} - -typedef struct { - gpointer closure; - EBookCallback open_response; -} DefaultBookClosure; - -static void -e_book_default_book_open (EBook *book, EBookStatus status, gpointer closure) -{ - DefaultBookClosure *default_book_closure = closure; - gpointer user_closure = default_book_closure->closure; - EBookCallback user_response = default_book_closure->open_response; - - g_free (default_book_closure); - - /* If there's a transient error, report it to the caller, but - * if the old default folder has disappeared, fall back to the - * local contacts folder instead, except when the default - * folder is also the local folder. - */ - if (status == E_BOOK_STATUS_PROTOCOL_NOT_SUPPORTED || - status == E_BOOK_STATUS_NO_SUCH_BOOK) { - char *local_uri = get_local_book_uri(); - if (strcmp (local_uri, default_book_uri)) { - set_default_book_uri_local (); - e_book_load_default_book (book, user_response, user_closure); - } - else - user_response (book, status, user_closure); - g_free (local_uri); - } else { - user_response (book, status, user_closure); - } -} - -void -e_book_load_default_book (EBook *book, EBookCallback open_response, gpointer closure) -{ - const char *uri; - DefaultBookClosure *default_book_closure; - - g_return_if_fail (book != NULL); - g_return_if_fail (E_IS_BOOK (book)); - g_return_if_fail (open_response != NULL); - - uri = e_book_get_default_book_uri (); - - default_book_closure = g_new (DefaultBookClosure, 1); - - default_book_closure->closure = closure; - default_book_closure->open_response = open_response; - - e_book_load_uri (book, uri, - e_book_default_book_open, default_book_closure); - -} - -const char * -e_book_get_default_book_uri () -{ - if (!default_book_uri) - set_default_book_uri_from_config_db (); - - return default_book_uri; -} - -/* - * - * Simple Query Stuff - * - */ - -typedef struct _SimpleQueryInfo SimpleQueryInfo; -struct _SimpleQueryInfo { - guint tag; - EBook *book; - gchar *query; - EBookSimpleQueryCallback cb; - gpointer closure; - EBookView *view; - guint add_tag; - guint seq_complete_tag; - GList *cards; - gboolean cancelled; -}; - -static void -book_add_simple_query (EBook *book, SimpleQueryInfo *info) -{ - GList *pending = g_object_get_data (G_OBJECT(book), "sq_pending"); - pending = g_list_prepend (pending, info); - g_object_set_data (G_OBJECT (book), "sq_pending", pending); -} - -static SimpleQueryInfo * -book_lookup_simple_query (EBook *book, guint tag) -{ - GList *pending = g_object_get_data (G_OBJECT (book), "sq_pending"); - while (pending) { - SimpleQueryInfo *sq = pending->data; - if (sq->tag == tag) - return sq; - pending = g_list_next (pending); - } - return NULL; -} - -static void -book_remove_simple_query (EBook *book, SimpleQueryInfo *info) -{ - GList *pending = g_object_get_data (G_OBJECT (book), "sq_pending"); - GList *i; - - for (i=pending; i != NULL; i = g_list_next (i)) { - if (i->data == info) { - pending = g_list_remove_link (pending, i); - g_list_free_1 (i); - break; - } - } - g_object_set_data (G_OBJECT (book), "sq_pending", pending); -} - -static guint -book_issue_tag (EBook *book) -{ - gpointer ptr = g_object_get_data (G_OBJECT (book), "sq_tag"); - guint tag = GPOINTER_TO_UINT (ptr); - if (tag == 0) - tag = 1; - g_object_set_data (G_OBJECT (book), "sq_tag", GUINT_TO_POINTER (tag+1)); - return tag; -} - -static SimpleQueryInfo * -simple_query_new (EBook *book, const char *query, EBookSimpleQueryCallback cb, gpointer closure) -{ - SimpleQueryInfo *sq = g_new0 (SimpleQueryInfo, 1); - - sq->tag = book_issue_tag (book); - sq->book = book; - g_object_ref (book); - sq->query = g_strdup (query); - sq->cb = cb; - sq->closure = closure; - sq->cancelled = FALSE; - - /* Automatically add ourselves to the EBook's pending list. */ - book_add_simple_query (book, sq); - - return sq; -} - -static void -simple_query_disconnect (SimpleQueryInfo *sq) -{ - if (sq->add_tag) { - g_signal_handler_disconnect (sq->view, sq->add_tag); - sq->add_tag = 0; - } - - if (sq->seq_complete_tag) { - g_signal_handler_disconnect (sq->view, sq->seq_complete_tag); - sq->seq_complete_tag = 0; - } - - if (sq->view) { - g_object_unref (sq->view); - sq->view = NULL; - } -} - -static void -simple_query_free (SimpleQueryInfo *sq) -{ - simple_query_disconnect (sq); - - /* Remove ourselves from the EBook's pending list. */ - book_remove_simple_query (sq->book, sq); - - g_free (sq->query); - - if (sq->book) - g_object_unref (sq->book); - - g_list_foreach (sq->cards, (GFunc) g_object_unref, NULL); - g_list_free (sq->cards); - - g_free (sq); -} - -static void -simple_query_card_added_cb (EBookView *view, const GList *cards, gpointer closure) -{ - SimpleQueryInfo *sq = closure; - - if (sq->cancelled) - return; - - sq->cards = g_list_concat (sq->cards, g_list_copy ((GList *) cards)); - g_list_foreach ((GList *) cards, (GFunc) g_object_ref, NULL); -} - -static void -simple_query_sequence_complete_cb (EBookView *view, EBookViewStatus status, gpointer closure) -{ - SimpleQueryInfo *sq = closure; - - /* Disconnect signals, so that we don't pick up any changes to the book that occur - in our callback */ - simple_query_disconnect (sq); - if (! sq->cancelled) - sq->cb (sq->book, E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS, sq->cards, sq->closure); - simple_query_free (sq); -} - -static void -simple_query_book_view_cb (EBook *book, EBookStatus status, EBookView *book_view, gpointer closure) -{ - SimpleQueryInfo *sq = closure; - - if (sq->cancelled) { - simple_query_free (sq); - return; - } - - if (status != E_BOOK_STATUS_SUCCESS) { - simple_query_disconnect (sq); - sq->cb (sq->book, E_BOOK_SIMPLE_QUERY_STATUS_OTHER_ERROR, NULL, sq->closure); - simple_query_free (sq); - return; - } - - sq->view = book_view; - g_object_ref (book_view); - - sq->add_tag = g_signal_connect (sq->view, "card_added", - G_CALLBACK (simple_query_card_added_cb), sq); - sq->seq_complete_tag = g_signal_connect (sq->view, "sequence_complete", - G_CALLBACK (simple_query_sequence_complete_cb), sq); -} - -guint -e_book_simple_query (EBook *book, const char *query, EBookSimpleQueryCallback cb, gpointer closure) -{ - SimpleQueryInfo *sq; - - g_return_val_if_fail (book && E_IS_BOOK (book), 0); - g_return_val_if_fail (query, 0); - g_return_val_if_fail (cb, 0); - - sq = simple_query_new (book, query, cb, closure); - e_book_get_book_view (book, (gchar *) query, simple_query_book_view_cb, sq); - - return sq->tag; -} - -void -e_book_simple_query_cancel (EBook *book, guint tag) -{ - SimpleQueryInfo *sq; - - g_return_if_fail (book && E_IS_BOOK (book)); - - sq = book_lookup_simple_query (book, tag); - - if (sq) { - sq->cancelled = TRUE; - sq->cb (sq->book, E_BOOK_SIMPLE_QUERY_STATUS_CANCELLED, NULL, sq->closure); - } else { - g_warning ("Simple query tag %d is unknown", tag); - } -} - -/* - * - * Specialized Queries - * - */ - -typedef struct _NameEmailQueryInfo NameEmailQueryInfo; -struct _NameEmailQueryInfo { - gchar *name; - gchar *email; - EBookSimpleQueryCallback cb; - gpointer closure; -}; - -static void -name_email_query_info_free (NameEmailQueryInfo *info) -{ - if (info) { - g_free (info->name); - g_free (info->email); - g_free (info); - } -} - -static void -name_and_email_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure) -{ - NameEmailQueryInfo *info = closure; - GList *filtered_cards = NULL; - - while (cards) { - ECard *card = E_CARD (cards->data); - if ((info->name == NULL || e_card_compare_name_to_string (card, info->name) >= E_CARD_MATCH_VAGUE) - && (info->email == NULL || e_card_email_match_string (card, info->email))) { - filtered_cards = g_list_append (filtered_cards, card); - } - cards = g_list_next (cards); - } - - info->cb (book, status, filtered_cards, info->closure); - - g_list_free (filtered_cards); - - name_email_query_info_free (info); -} - -guint -e_book_name_and_email_query (EBook *book, - const gchar *name, - const gchar *email, - EBookSimpleQueryCallback cb, - gpointer closure) -{ - NameEmailQueryInfo *info; - gchar *email_query=NULL, *name_query=NULL, *query; - guint tag; - - g_return_val_if_fail (book && E_IS_BOOK (book), 0); - g_return_val_if_fail (cb != NULL, 0); - - if (name && !*name) - name = NULL; - if (email && !*email) - email = NULL; - - if (name == NULL && email == NULL) - return 0; - - /* Build our e-mail query. - * We only query against the username part of the address, to avoid not matching - * fred@foo.com and fred@mail.foo.com. While their may be namespace collisions - * in the usernames of everyone out there, it shouldn't be that bad. (Famous last words.) - */ - if (email) { - const gchar *t = email; - while (*t && *t != '@') - ++t; - if (*t == '@') { - email_query = g_strdup_printf ("(beginswith \"email\" \"%.*s@\")", t-email, email); - - } else { - email_query = g_strdup_printf ("(beginswith \"email\" \"%s\")", email); - } - } - - /* Build our name query. - * We only do name-query stuff if we don't have an e-mail address. Our basic assumption - * is that the username part of the email is good enough to keep the amount of stuff returned - * in the query relatively small. - */ - if (name && !email) { - gchar *name_cpy = g_strdup (name), *qjoined; - gchar **namev; - gint i, count=0; - - g_strstrip (name_cpy); - namev = g_strsplit (name_cpy, " ", 0); - for (i=0; namev[i]; ++i) { - if (*namev[i]) { - char *str = namev[i]; - - namev[i] = g_strdup_printf ("(contains \"file_as\" \"%s\")", namev[i]); - ++count; - - g_free (str); - } - } - - qjoined = g_strjoinv (" ", namev); - if (count > 1) { - name_query = g_strdup_printf ("(or %s)", qjoined); - } else { - name_query = qjoined; - qjoined = NULL; - } - - g_free (name_cpy); - g_strfreev (namev); - g_free (qjoined); - } - - /* Assemble our e-mail & name queries */ - if (email_query && name_query) { - query = g_strdup_printf ("(and %s %s)", email_query, name_query); - } else if (email_query) { - query = email_query; - email_query = NULL; - } else if (name_query) { - query = name_query; - name_query = NULL; - } else - return 0; - - info = g_new0 (NameEmailQueryInfo, 1); - info->name = g_strdup (name); - info->email = g_strdup (email); - info->cb = cb; - info->closure = closure; - - tag = e_book_simple_query (book, query, name_and_email_cb, info); - - g_free (email_query); - g_free (name_query); - g_free (query); - - return tag; -} - -/* - * Simple nickname query - */ - -typedef struct _NicknameQueryInfo NicknameQueryInfo; -struct _NicknameQueryInfo { - gchar *nickname; - EBookSimpleQueryCallback cb; - gpointer closure; -}; - -static void -nickname_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure) -{ - NicknameQueryInfo *info = closure; - - if (info->cb) - info->cb (book, status, cards, info->closure); - - g_free (info->nickname); - g_free (info); -} - -guint -e_book_nickname_query (EBook *book, - const char *nickname, - EBookSimpleQueryCallback cb, - gpointer closure) -{ - NicknameQueryInfo *info; - gchar *query; - guint retval; - - g_return_val_if_fail (E_IS_BOOK (book), 0); - g_return_val_if_fail (nickname != NULL, 0); - - /* The empty-string case shouldn't generate a warning. */ - if (! *nickname) - return 0; - - info = g_new0 (NicknameQueryInfo, 1); - info->nickname = g_strdup (nickname); - info->cb = cb; - info->closure = closure; - - query = g_strdup_printf ("(is \"nickname\" \"%s\")", info->nickname); - - retval = e_book_simple_query (book, query, nickname_cb, info); - - g_free (query); - - return retval; -} - -/* - * Convenience routine to check for addresses in the local address book. - */ - -typedef struct _HaveAddressInfo HaveAddressInfo; -struct _HaveAddressInfo { - gchar *email; - EBookHaveAddressCallback cb; - gpointer closure; -}; - -static void -have_address_query_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure) -{ - HaveAddressInfo *info = (HaveAddressInfo *) closure; - - info->cb (book, - info->email, - cards && (status == E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS) ? E_CARD (cards->data) : NULL, - info->closure); - - g_free (info->email); - g_free (info); -} - -static void -have_address_book_open_cb (EBook *book, gpointer closure) -{ - HaveAddressInfo *info = (HaveAddressInfo *) closure; - - if (book) { - - e_book_name_and_email_query (book, NULL, info->email, have_address_query_cb, info); - - } else { - - info->cb (NULL, info->email, NULL, info->closure); - - g_free (info->email); - g_free (info); - - } -} - -void -e_book_query_address_default (const gchar *email, - EBookHaveAddressCallback cb, - gpointer closure) -{ - HaveAddressInfo *info; - - g_return_if_fail (email != NULL); - g_return_if_fail (cb != NULL); - - info = g_new0 (HaveAddressInfo, 1); - info->email = g_strdup (email); - info->cb = cb; - info->closure = closure; - - e_book_use_default_book (have_address_book_open_cb, info); -} - -/* bad place for this i know. */ -int -e_utf8_casefold_collate_len (const gchar *str1, const gchar *str2, int len) -{ - gchar *s1 = g_utf8_casefold(str1, len); - gchar *s2 = g_utf8_casefold(str2, len); - int rv; - - rv = g_utf8_collate (s1, s2); - - g_free (s1); - g_free (s2); - - return rv; -} - -int -e_utf8_casefold_collate (const gchar *str1, const gchar *str2) -{ - return e_utf8_casefold_collate_len (str1, str2, -1); -} - diff --git a/addressbook/backend/ebook/e-book-util.h b/addressbook/backend/ebook/e-book-util.h deleted file mode 100644 index 39eb135332..0000000000 --- a/addressbook/backend/ebook/e-book-util.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* - * e-book-util.h - * - * Copyright (C) 2001 Ximian, Inc. - * - * Developed by Jon Trowbridge - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - */ - -#ifndef __E_BOOK_UTIL_H__ -#define __E_BOOK_UTIL_H__ - -#include "e-book.h" -#include "e-util/e-config-listener.h" -#include -#include - -G_BEGIN_DECLS - -/* Callbacks for asynchronous functions. */ -typedef void (*EBookCommonCallback) (EBook *book, gpointer closure); -typedef void (*EBookSimpleQueryCallback) (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure); -typedef void (*EBookHaveAddressCallback) (EBook *book, const gchar *addr, ECard *card, gpointer closure); - -/* expand file:///foo/foo/ to file:///foo/foo/addressbook.db */ -char *e_book_expand_uri (const char *uri); - -void e_book_load_address_book_by_uri (EBook *book, - const char *uri, - EBookCallback open_response, - gpointer closure); -void e_book_use_address_book_by_uri (const char *uri, - EBookCommonCallback cb, - gpointer closure); - -void e_book_use_default_book (EBookCommonCallback cb, - gpointer closure); -void e_book_load_default_book (EBook *book, - EBookCallback open_response, - gpointer closure); -const char *e_book_get_default_book_uri (void); - -/* config database interface. */ -EConfigListener *e_book_get_config_database (void); - -/* Simple Query Interface. */ -guint e_book_simple_query (EBook *book, - const char *query, - EBookSimpleQueryCallback cb, - gpointer closure); -void e_book_simple_query_cancel (EBook *book, - guint tag); - -/* Specialized Name/Email Queries */ -guint e_book_name_and_email_query (EBook *book, - const char *name, - const char *email, - EBookSimpleQueryCallback cb, - gpointer closure); -guint e_book_nickname_query (EBook *book, - const char *nickname, - EBookSimpleQueryCallback cb, - gpointer closure); - -/* Returns the ECard associated to email in the callback, - or NULL if no match is found in the default address book. */ -void e_book_query_address_default (const gchar *email, - EBookHaveAddressCallback cb, - gpointer closure); - -int e_utf8_casefold_collate_len (const gchar *str1, const gchar *str2, int len); -int e_utf8_casefold_collate (const gchar *str1, const gchar *str2); - -G_END_DECLS - -#endif /* __E_BOOK_UTIL_H__ */ - diff --git a/addressbook/backend/ebook/e-book-view-listener.c b/addressbook/backend/ebook/e-book-view-listener.c index 668c442a9a..3ab2ff2708 100644 --- a/addressbook/backend/ebook/e-book-view-listener.c +++ b/addressbook/backend/ebook/e-book-view-listener.c @@ -13,13 +13,13 @@ #include #include "e-book-view-listener.h" #include "e-book-view.h" -#include "e-card.h" +#include "e-contact.h" #include "e-book-marshal.h" -static EBookViewStatus e_book_view_listener_convert_status (GNOME_Evolution_Addressbook_BookViewListener_CallStatus status); +static EBookViewStatus e_book_view_listener_convert_status (GNOME_Evolution_Addressbook_CallStatus status); enum { - RESPONSES_QUEUED, + RESPONSE, LAST_SIGNAL }; @@ -28,36 +28,9 @@ static guint e_book_view_listener_signals [LAST_SIGNAL]; static BonoboObjectClass *parent_class; struct _EBookViewListenerPrivate { - GList *response_queue; - gint timeout_id; - - guint timeout_lock : 1; guint stopped : 1; }; -static gboolean -e_book_view_listener_check_queue (EBookViewListener *listener) -{ - if (listener->priv->timeout_lock) - return TRUE; - - listener->priv->timeout_lock = TRUE; - - if (listener->priv->response_queue != NULL && !listener->priv->stopped) { - g_signal_emit (listener, e_book_view_listener_signals [RESPONSES_QUEUED], 0); - } - - if (listener->priv->response_queue == NULL || listener->priv->stopped) { - listener->priv->timeout_id = 0; - listener->priv->timeout_lock = FALSE; - bonobo_object_unref (BONOBO_OBJECT (listener)); - return FALSE; - } - - listener->priv->timeout_lock = FALSE; - return TRUE; -} - static void e_book_view_listener_queue_response (EBookViewListener *listener, EBookViewListenerResponse *response) @@ -69,45 +42,14 @@ e_book_view_listener_queue_response (EBookViewListener *listener, /* Free response and return */ g_list_foreach (response->ids, (GFunc)g_free, NULL); g_list_free (response->ids); - g_list_foreach (response->cards, (GFunc) g_object_unref, NULL); - g_list_free (response->cards); + g_list_foreach (response->contacts, (GFunc) g_object_unref, NULL); + g_list_free (response->contacts); g_free (response->message); g_free (response); return; } - /* a slight optimization for huge ldap queries. if there's an - existing Add response on the end of the queue, and we're an - Add response, we just glom the two lists of cards - together */ - if (response->op == CardAddedEvent) { - GList *last = g_list_last (listener->priv->response_queue); - EBookViewListenerResponse *last_resp = NULL; - - if (last) last_resp = last->data; - - if (last_resp && last_resp->op == CardAddedEvent ) { - response->cards = g_list_concat (last_resp->cards, response->cards); - g_free (response); - /* there should already be a timeout since the - queue isn't empty, so we'll just return - here */ - return; - } - else - listener->priv->response_queue = g_list_append (last, response); - } - else - listener->priv->response_queue = g_list_append (listener->priv->response_queue, response); - - if (listener->priv->timeout_id == 0) { - - /* Here, 20 == an arbitrary small number */ - listener->priv->timeout_id = g_timeout_add (20, (GSourceFunc) e_book_view_listener_check_queue, listener); - - /* Hold a reference to the listener on behalf of the timeout */ - bonobo_object_ref (BONOBO_OBJECT (listener)); - } + g_signal_emit (listener, e_book_view_listener_signals [RESPONSE], 0, response); } /* Add, Remove, Modify */ @@ -125,9 +67,6 @@ e_book_view_listener_queue_status_event (EBookViewListener *listener, resp->op = op; resp->status = status; - resp->ids = NULL; - resp->cards = NULL; - resp->message = NULL; e_book_view_listener_queue_response (listener, resp); } @@ -136,7 +75,7 @@ e_book_view_listener_queue_status_event (EBookViewListener *listener, static void e_book_view_listener_queue_idlist_event (EBookViewListener *listener, EBookViewListenerOperation op, - const GNOME_Evolution_Addressbook_CardIdList *ids) + const GNOME_Evolution_Addressbook_ContactIdList *ids) { EBookViewListenerResponse *resp; int i; @@ -147,10 +86,7 @@ e_book_view_listener_queue_idlist_event (EBookViewListener *listener, resp = g_new0 (EBookViewListenerResponse, 1); resp->op = op; - resp->status = E_BOOK_VIEW_STATUS_SUCCESS; - resp->ids = NULL; - resp->cards = NULL; - resp->message = NULL; + resp->status = E_BOOK_VIEW_STATUS_OK; for (i = 0; i < ids->_length; i ++) { resp->ids = g_list_prepend (resp->ids, g_strdup (ids->_buffer[i])); @@ -163,7 +99,7 @@ e_book_view_listener_queue_idlist_event (EBookViewListener *listener, static void e_book_view_listener_queue_sequence_event (EBookViewListener *listener, EBookViewListenerOperation op, - const GNOME_Evolution_Addressbook_VCardList *cards) + const GNOME_Evolution_Addressbook_VCardList *vcards) { EBookViewListenerResponse *resp; int i; @@ -174,13 +110,10 @@ e_book_view_listener_queue_sequence_event (EBookViewListener *listener, resp = g_new0 (EBookViewListenerResponse, 1); resp->op = op; - resp->status = E_BOOK_VIEW_STATUS_SUCCESS; - resp->ids = NULL; - resp->cards = NULL; - resp->message = NULL; + resp->status = E_BOOK_VIEW_STATUS_OK; - for ( i = 0; i < cards->_length; i++ ) { - resp->cards = g_list_append(resp->cards, e_card_new(cards->_buffer[i])); + for ( i = 0; i < vcards->_length; i++ ) { + resp->contacts = g_list_append(resp->contacts, e_contact_new_from_vcard (vcards->_buffer[i])); } e_book_view_listener_queue_response (listener, resp); @@ -200,135 +133,93 @@ e_book_view_listener_queue_message_event (EBookViewListener *listener, resp = g_new0 (EBookViewListenerResponse, 1); resp->op = op; - resp->status = E_BOOK_VIEW_STATUS_SUCCESS; - resp->ids = NULL; - resp->cards = NULL; + resp->status = E_BOOK_VIEW_STATUS_OK; resp->message = g_strdup(message); e_book_view_listener_queue_response (listener, resp); } static void -impl_BookViewListener_notify_card_added (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_VCardList *cards, - CORBA_Environment *ev) +impl_BookViewListener_notify_contacts_added (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_VCardList *vcards, + CORBA_Environment *ev) { EBookViewListener *listener = E_BOOK_VIEW_LISTENER (bonobo_object (servant)); + printf ("impl_BookViewListener_notify_contacts_added\n"); + e_book_view_listener_queue_sequence_event ( - listener, CardAddedEvent, cards); + listener, ContactsAddedEvent, vcards); } static void -impl_BookViewListener_notify_cards_removed (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_CardIdList *ids, - CORBA_Environment *ev) +impl_BookViewListener_notify_contacts_removed (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_ContactIdList *ids, + CORBA_Environment *ev) { EBookViewListener *listener = E_BOOK_VIEW_LISTENER (bonobo_object (servant)); - e_book_view_listener_queue_idlist_event (listener, CardsRemovedEvent, ids); + printf ("impl_BookViewListener_notify_contacts_removed\n"); + + e_book_view_listener_queue_idlist_event (listener, ContactsRemovedEvent, ids); } static void -impl_BookViewListener_notify_card_changed (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_VCardList *cards, - CORBA_Environment *ev) +impl_BookViewListener_notify_contacts_changed (PortableServer_Servant servant, + const GNOME_Evolution_Addressbook_VCardList *vcards, + CORBA_Environment *ev) { EBookViewListener *listener = E_BOOK_VIEW_LISTENER (bonobo_object (servant)); + printf ("impl_BookViewListener_notify_contacts_changed\n"); + e_book_view_listener_queue_sequence_event ( - listener, CardModifiedEvent, cards); + listener, ContactsModifiedEvent, vcards); } static void impl_BookViewListener_notify_sequence_complete (PortableServer_Servant servant, - const GNOME_Evolution_Addressbook_BookViewListener_CallStatus status, + const GNOME_Evolution_Addressbook_CallStatus status, CORBA_Environment *ev) { EBookViewListener *listener = E_BOOK_VIEW_LISTENER (bonobo_object (servant)); + printf ("impl_BookViewListener_notify_sequence_complete\n"); + e_book_view_listener_queue_status_event (listener, SequenceCompleteEvent, e_book_view_listener_convert_status (status)); } static void -impl_BookViewListener_notify_status_message (PortableServer_Servant servant, - const char *message, - CORBA_Environment *ev) +impl_BookViewListener_notify_progress (PortableServer_Servant servant, + const char *message, + const CORBA_short percent, + CORBA_Environment *ev) { EBookViewListener *listener = E_BOOK_VIEW_LISTENER (bonobo_object (servant)); - e_book_view_listener_queue_message_event (listener, StatusMessageEvent, message); -} + printf ("impl_BookViewListener_notify_progress\n"); -/** - * e_book_view_listener_check_pending: - * @listener: the #EBookViewListener - * - * Returns: the number of items on the response queue, - * or -1 if the @listener is isn't an #EBookViewListener. - */ -int -e_book_view_listener_check_pending (EBookViewListener *listener) -{ - g_return_val_if_fail (listener != NULL, -1); - g_return_val_if_fail (E_IS_BOOK_VIEW_LISTENER (listener), -1); - - return g_list_length (listener->priv->response_queue); -} - -/** - * e_book_view_listener_pop_response: - * @listener: the #EBookViewListener for which a request is to be popped - * - * Returns: an #EBookViewListenerResponse if there are responses on the - * queue to be returned; %NULL if there aren't, or if the @listener - * isn't an EBookViewListener. - */ -EBookViewListenerResponse * -e_book_view_listener_pop_response (EBookViewListener *listener) -{ - EBookViewListenerResponse *resp; - GList *popped; - - g_return_val_if_fail (listener != NULL, NULL); - g_return_val_if_fail (E_IS_BOOK_VIEW_LISTENER (listener), NULL); - - if (listener->priv->response_queue == NULL) - return NULL; - - resp = listener->priv->response_queue->data; - - popped = listener->priv->response_queue; - listener->priv->response_queue = - g_list_remove_link (listener->priv->response_queue, - listener->priv->response_queue); - g_list_free_1 (popped); - - return resp; + e_book_view_listener_queue_message_event (listener, StatusMessageEvent, message); } static EBookViewStatus -e_book_view_listener_convert_status (const GNOME_Evolution_Addressbook_BookViewListener_CallStatus status) +e_book_view_listener_convert_status (const GNOME_Evolution_Addressbook_CallStatus status) { switch (status) { - case GNOME_Evolution_Addressbook_BookViewListener_Success: - return E_BOOK_VIEW_STATUS_SUCCESS; - case GNOME_Evolution_Addressbook_BookViewListener_SearchTimeLimitExceeded: + case GNOME_Evolution_Addressbook_Success: + return E_BOOK_VIEW_STATUS_OK; + case GNOME_Evolution_Addressbook_SearchTimeLimitExceeded: return E_BOOK_VIEW_STATUS_TIME_LIMIT_EXCEEDED; - case GNOME_Evolution_Addressbook_BookViewListener_SearchSizeLimitExceeded: + case GNOME_Evolution_Addressbook_SearchSizeLimitExceeded: return E_BOOK_VIEW_STATUS_SIZE_LIMIT_EXCEEDED; - case GNOME_Evolution_Addressbook_BookViewListener_InvalidQuery: - return E_BOOK_VIEW_STATUS_INVALID_QUERY; - case GNOME_Evolution_Addressbook_BookViewListener_QueryRefused: - return E_BOOK_VIEW_STATUS_QUERY_REFUSED; - case GNOME_Evolution_Addressbook_BookViewListener_OtherError: - return E_BOOK_VIEW_STATUS_OTHER_ERROR; + case GNOME_Evolution_Addressbook_InvalidQuery: + return E_BOOK_VIEW_ERROR_INVALID_QUERY; + case GNOME_Evolution_Addressbook_QueryRefused: + return E_BOOK_VIEW_ERROR_QUERY_REFUSED; + case GNOME_Evolution_Addressbook_OtherError: default: - g_warning ("e_book_view_listener_convert_status: Unknown status " - "from card server: %d\n", (int) status); - return E_BOOK_VIEW_STATUS_UNKNOWN; - + return E_BOOK_VIEW_ERROR_OTHER_ERROR; } } @@ -351,7 +242,9 @@ e_book_view_listener_new () { EBookViewListener *listener; - listener = g_object_new (E_TYPE_BOOK_VIEW_LISTENER, NULL); + listener = g_object_new (E_TYPE_BOOK_VIEW_LISTENER, + "poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_ALL_AT_IDLE, NULL), + NULL); e_book_view_listener_construct (listener); @@ -362,9 +255,6 @@ static void e_book_view_listener_init (EBookViewListener *listener) { listener->priv = g_new0 (EBookViewListenerPrivate, 1); - listener->priv->response_queue = NULL; - listener->priv->timeout_id = 0; - listener->priv->timeout_lock = FALSE; listener->priv->stopped = FALSE; } @@ -381,32 +271,6 @@ e_book_view_listener_dispose (GObject *object) EBookViewListener *listener = E_BOOK_VIEW_LISTENER (object); if (listener->priv) { - GList *l; - /* Remove our response queue handler: In theory, this - can never happen since we always hold a reference - to the listener while the timeout is running. */ - if (listener->priv->timeout_id) { - g_source_remove (listener->priv->timeout_id); - } - - /* Clear out the queue */ - for (l = listener->priv->response_queue; l != NULL; l = l->next) { - EBookViewListenerResponse *resp = l->data; - - g_list_foreach (resp->ids, (GFunc)g_free, NULL); - g_list_free (resp->ids); - - g_list_foreach(resp->cards, (GFunc) g_object_unref, NULL); - g_list_free(resp->cards); - resp->cards = NULL; - - g_free (resp->message); - resp->message = NULL; - - g_free (resp); - } - g_list_free (listener->priv->response_queue); - g_free (listener->priv); listener->priv = NULL; } @@ -423,23 +287,24 @@ e_book_view_listener_class_init (EBookViewListenerClass *klass) parent_class = g_type_class_ref (BONOBO_TYPE_OBJECT); - e_book_view_listener_signals [RESPONSES_QUEUED] = - g_signal_new ("responses_queued", + e_book_view_listener_signals [RESPONSE] = + g_signal_new ("response", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EBookViewListenerClass, responses_queued), + G_STRUCT_OFFSET (EBookViewListenerClass, response), NULL, NULL, - e_book_marshal_NONE__NONE, - G_TYPE_NONE, 0); + e_book_marshal_NONE__POINTER, + G_TYPE_NONE, + 1, G_TYPE_POINTER); object_class->dispose = e_book_view_listener_dispose; epv = &klass->epv; - epv->notifyCardChanged = impl_BookViewListener_notify_card_changed; - epv->notifyCardsRemoved = impl_BookViewListener_notify_cards_removed; - epv->notifyCardAdded = impl_BookViewListener_notify_card_added; + epv->notifyContactsChanged = impl_BookViewListener_notify_contacts_changed; + epv->notifyContactsRemoved = impl_BookViewListener_notify_contacts_removed; + epv->notifyContactsAdded = impl_BookViewListener_notify_contacts_added; epv->notifySequenceComplete = impl_BookViewListener_notify_sequence_complete; - epv->notifyStatusMessage = impl_BookViewListener_notify_status_message; + epv->notifyProgress = impl_BookViewListener_notify_progress; } BONOBO_TYPE_FUNC_FULL ( diff --git a/addressbook/backend/ebook/e-book-view-listener.h b/addressbook/backend/ebook/e-book-view-listener.h index fd1c1395a7..a68f25c337 100644 --- a/addressbook/backend/ebook/e-book-view-listener.h +++ b/addressbook/backend/ebook/e-book-view-listener.h @@ -29,6 +29,8 @@ typedef struct _EBookViewListener EBookViewListener; typedef struct _EBookViewListenerClass EBookViewListenerClass; typedef struct _EBookViewListenerPrivate EBookViewListenerPrivate; +typedef struct _EBookViewListenerResponse EBookViewListenerResponse; + struct _EBookViewListener { BonoboObject parent; EBookViewListenerPrivate *priv; @@ -42,38 +44,44 @@ struct _EBookViewListenerClass { /* * Signals */ - void (*responses_queued) (void); + void (*response) (EBookViewListener *listener, EBookViewListenerResponse *response); + + + /* Padding for future expansion */ + void (*_ebook_reserved0) (void); + void (*_ebook_reserved1) (void); + void (*_ebook_reserved2) (void); + void (*_ebook_reserved3) (void); + void (*_ebook_reserved4) (void); }; typedef enum { /* Async events */ - CardAddedEvent, - CardsRemovedEvent, - CardModifiedEvent, + ContactsAddedEvent, + ContactsRemovedEvent, + ContactsModifiedEvent, SequenceCompleteEvent, StatusMessageEvent, } EBookViewListenerOperation; -typedef struct { +struct _EBookViewListenerResponse { EBookViewListenerOperation op; /* For SequenceComplete */ EBookViewStatus status; - /* For CardsRemovedEvent */ + /* For ContactsRemovedEvent */ GList *ids; - /* For Card[Added|Modified]Event */ - GList *cards; /* Of type ECard. */ + /* For Contact[sAdded|Modified]Event */ + GList *contacts; /* Of type EContact. */ /* For StatusMessageEvent */ char *message; -} EBookViewListenerResponse; +}; EBookViewListener *e_book_view_listener_new (void); -int e_book_view_listener_check_pending (EBookViewListener *listener); -EBookViewListenerResponse *e_book_view_listener_pop_response (EBookViewListener *listener); GType e_book_view_listener_get_type (void); void e_book_view_listener_stop (EBookViewListener *listener); diff --git a/addressbook/backend/ebook/e-book-view.c b/addressbook/backend/ebook/e-book-view.c index e1f4b1623c..e8468e35de 100644 --- a/addressbook/backend/ebook/e-book-view.c +++ b/addressbook/backend/ebook/e-book-view.c @@ -11,7 +11,6 @@ #include #include "addressbook.h" -#include "e-card-cursor.h" #include "e-book-view-listener.h" #include "e-book-view.h" #include "e-book.h" @@ -26,13 +25,13 @@ struct _EBookViewPrivate { EBookViewListener *listener; - int responses_queued_id; + int response_id; }; enum { - CARD_CHANGED, - CARD_REMOVED, - CARD_ADDED, + CONTACTS_CHANGED, + CONTACTS_REMOVED, + CONTACTS_ADDED, SEQUENCE_COMPLETE, STATUS_MESSAGE, LAST_SIGNAL @@ -40,48 +39,33 @@ enum { static guint e_book_view_signals [LAST_SIGNAL]; -static void -add_book_iterator (gpointer data, gpointer closure) -{ - ECard *card = E_CARD (data); - EBook *book = E_BOOK (closure); - - e_card_set_book (card, book); -} - static void e_book_view_do_added_event (EBookView *book_view, EBookViewListenerResponse *resp) { - if (book_view->priv->book) - g_list_foreach (resp->cards, add_book_iterator, book_view->priv->book); - - g_signal_emit (book_view, e_book_view_signals [CARD_ADDED], 0, - resp->cards); + g_signal_emit (book_view, e_book_view_signals [CONTACTS_ADDED], 0, + resp->contacts); - g_list_foreach (resp->cards, (GFunc) g_object_unref, NULL); - g_list_free (resp->cards); + g_list_foreach (resp->contacts, (GFunc) g_object_unref, NULL); + g_list_free (resp->contacts); } static void e_book_view_do_modified_event (EBookView *book_view, EBookViewListenerResponse *resp) { - if (book_view->priv->book) - g_list_foreach (resp->cards, add_book_iterator, book_view->priv->book); + g_signal_emit (book_view, e_book_view_signals [CONTACTS_CHANGED], 0, + resp->contacts); - g_signal_emit (book_view, e_book_view_signals [CARD_CHANGED], 0, - resp->cards); - - g_list_foreach (resp->cards, (GFunc) g_object_unref, NULL); - g_list_free (resp->cards); + g_list_foreach (resp->contacts, (GFunc) g_object_unref, NULL); + g_list_free (resp->contacts); } static void e_book_view_do_removed_event (EBookView *book_view, EBookViewListenerResponse *resp) { - g_signal_emit (book_view, e_book_view_signals [CARD_REMOVED], 0, + g_signal_emit (book_view, e_book_view_signals [CONTACTS_REMOVED], 0, resp->ids); g_list_foreach (resp->ids, (GFunc) g_free, NULL); @@ -106,27 +90,20 @@ e_book_view_do_status_message_event (EBookView *book_view, } -/* - * Reading notices out of the EBookViewListener's queue. - */ static void -e_book_view_check_listener_queue (EBookViewListener *listener, EBookView *book_view) +e_book_view_handle_response (EBookViewListener *listener, EBookViewListenerResponse *resp, EBookView *book_view) { - EBookViewListenerResponse *resp; - - resp = e_book_view_listener_pop_response (listener); - if (resp == NULL) return; switch (resp->op) { - case CardAddedEvent: + case ContactsAddedEvent: e_book_view_do_added_event (book_view, resp); break; - case CardModifiedEvent: + case ContactsModifiedEvent: e_book_view_do_modified_event (book_view, resp); break; - case CardsRemovedEvent: + case ContactsRemovedEvent: e_book_view_do_removed_event (book_view, resp); break; case SequenceCompleteEvent: @@ -171,8 +148,8 @@ e_book_view_construct (EBookView *book_view, GNOME_Evolution_Addressbook_BookVie * Create our local BookListener interface. */ book_view->priv->listener = listener; - book_view->priv->responses_queued_id = g_signal_connect (book_view->priv->listener, "responses_queued", - G_CALLBACK (e_book_view_check_listener_queue), book_view); + book_view->priv->response_id = g_signal_connect (book_view->priv->listener, "response", + G_CALLBACK (e_book_view_handle_response), book_view); bonobo_object_ref(BONOBO_OBJECT(book_view->priv->listener)); @@ -208,6 +185,22 @@ e_book_view_set_book (EBookView *book_view, EBook *book) g_object_ref (book); } +void +e_book_view_start (EBookView *book_view) +{ + CORBA_Environment ev; + + g_return_if_fail (book_view && E_IS_BOOK_VIEW (book_view)); + + CORBA_exception_init (&ev); + + GNOME_Evolution_Addressbook_BookView_start (book_view->priv->corba_book_view, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + g_warning ("corba exception._major = %d\n", ev._major); + } +} + void e_book_view_stop (EBookView *book_view) { @@ -223,7 +216,7 @@ e_book_view_init (EBookView *book_view) book_view->priv->book = NULL; book_view->priv->corba_book_view = CORBA_OBJECT_NIL; book_view->priv->listener = NULL; - book_view->priv->responses_queued_id = 0; + book_view->priv->response_id = 0; } static void @@ -250,9 +243,9 @@ e_book_view_dispose (GObject *object) } if (book_view->priv->listener) { - if (book_view->priv->responses_queued_id) + if (book_view->priv->response_id) g_signal_handler_disconnect(book_view->priv->listener, - book_view->priv->responses_queued_id); + book_view->priv->response_id); e_book_view_listener_stop (book_view->priv->listener); bonobo_object_unref (BONOBO_OBJECT(book_view->priv->listener)); } @@ -271,31 +264,31 @@ e_book_view_class_init (EBookViewClass *klass) parent_class = g_type_class_ref (G_TYPE_OBJECT); - e_book_view_signals [CARD_CHANGED] = - g_signal_new ("card_changed", + e_book_view_signals [CONTACTS_CHANGED] = + g_signal_new ("contacts_changed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EBookViewClass, card_changed), + G_STRUCT_OFFSET (EBookViewClass, contacts_changed), NULL, NULL, e_book_marshal_NONE__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - e_book_view_signals [CARD_ADDED] = - g_signal_new ("card_added", + e_book_view_signals [CONTACTS_ADDED] = + g_signal_new ("contacts_added", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EBookViewClass, card_added), + G_STRUCT_OFFSET (EBookViewClass, contacts_added), NULL, NULL, e_book_marshal_NONE__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - e_book_view_signals [CARD_REMOVED] = - g_signal_new ("card_removed", + e_book_view_signals [CONTACTS_REMOVED] = + g_signal_new ("contacts_removed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EBookViewClass, card_removed), + G_STRUCT_OFFSET (EBookViewClass, contacts_removed), NULL, NULL, e_book_marshal_NONE__POINTER, G_TYPE_NONE, 1, diff --git a/addressbook/backend/ebook/e-book-view.h b/addressbook/backend/ebook/e-book-view.h index bd7a97d1d5..5b9768315b 100644 --- a/addressbook/backend/ebook/e-book-view.h +++ b/addressbook/backend/ebook/e-book-view.h @@ -13,7 +13,6 @@ #include #include -#include #include #define E_TYPE_BOOK_VIEW (e_book_view_get_type ()) @@ -42,11 +41,18 @@ struct _EBookViewClass { /* * Signals. */ - void (* card_changed) (EBookView *book_view, const GList *cards); - void (* card_removed) (EBookView *book_view, const GList *ids); - void (* card_added) (EBookView *book_view, const GList *cards); + void (* contacts_changed) (EBookView *book_view, const GList *contacts); + void (* contacts_removed) (EBookView *book_view, const GList *ids); + void (* contacts_added) (EBookView *book_view, const GList *contacts); void (* sequence_complete) (EBookView *book_view, EBookViewStatus status); void (* status_message) (EBookView *book_view, const char *message); + + /* Padding for future expansion */ + void (*_ebook_reserved0) (void); + void (*_ebook_reserved1) (void); + void (*_ebook_reserved2) (void); + void (*_ebook_reserved3) (void); + void (*_ebook_reserved4) (void); }; /* Creating a new addressbook. */ @@ -56,6 +62,7 @@ GType e_book_view_get_type (void); void e_book_view_set_book (EBookView *book_view, struct _EBook *book); +void e_book_view_start (EBookView *book_view); void e_book_view_stop (EBookView *book_view); G_END_DECLS diff --git a/addressbook/backend/ebook/e-book.c b/addressbook/backend/ebook/e-book.c index 08a0aac995..3883cd4b15 100644 --- a/addressbook/backend/ebook/e-book.c +++ b/addressbook/backend/ebook/e-book.c @@ -1,34 +1,86 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * The Evolution addressbook client object. - * - * Author: - * Nat Friedman (nat@ximian.com) - * - * Copyright 1999, 2000, Ximian, Inc. - */ #include -#include -#include + +#include + #include -#include -#include "addressbook.h" -#include "e-card-cursor.h" -#include "e-book-listener.h" #include "e-book.h" +#include "e-vcard.h" + +#include + +#include +#include + +#include + #include "e-book-marshal.h" +#include "e-book-listener.h" +#include "addressbook.h" #include "e-util/e-component-listener.h" +#include "e-util/e-msgport.h" static GObjectClass *parent_class; #define CARDSERVER_OAF_ID "OAFIID:GNOME_Evolution_Wombat_ServerFactory" +#define e_return_error_if_fail(expr,error_code) G_STMT_START{ \ + if G_LIKELY(expr) { } else \ + { \ + g_log (G_LOG_DOMAIN, \ + G_LOG_LEVEL_CRITICAL, \ + "file %s: line %d (%s): assertion `%s' failed", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #expr); \ + g_set_error (error, E_BOOK_ERROR, (error_code), \ + "file %s: line %d (%s): assertion `%s' failed", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #expr); \ + return FALSE; \ + }; }G_STMT_END + +/* XXX we need a better error message here */ +#define E_BOOK_CHECK_STATUS(status,error) G_STMT_START{ \ + if ((status) == E_BOOK_ERROR_OK) { \ + return TRUE; \ + } \ + else { \ + g_set_error ((error), E_BOOK_ERROR, (status), "EBookStatus returned %d", (status)); \ + return FALSE; \ + } }G_STMT_END + +enum { + OPEN_PROGRESS, + WRITABLE_STATUS, + BACKEND_DIED, + LAST_SIGNAL +}; + +static guint e_book_signals [LAST_SIGNAL]; + +typedef struct { + EMutex *mutex; + pthread_cond_t cond; + EBookStatus status; + + char *id; + GList *list; + EContact *contact; + + EBookView *view; + EBookViewListener *listener; +} EBookOp; + typedef enum { - URINotLoaded, - URILoading, - URILoaded + E_BOOK_URI_NOT_LOADED, + E_BOOK_URI_LOADING, + E_BOOK_URI_LOADED } EBookLoadState; struct _EBookPrivate { @@ -39,21 +91,20 @@ struct _EBookPrivate { char *cap; gboolean cap_queried; - EBookListener *listener; + /* cached writable status */ + gboolean writable; + + EBookListener *listener; EComponentListener *comp_listener; GNOME_Evolution_Addressbook_Book corba_book; EBookLoadState load_state; - /* - * The operation queue. New operations are appended to the - * end of the queue. When responses come back from the PAS, - * the op structures are popped off the front of the queue. - */ - GList *pending_ops; - guint op_tag; + EBookOp *current_op; + + EMutex *mutex; gchar *uri; @@ -61,1526 +112,1844 @@ struct _EBookPrivate { gulong died_signal; }; -enum { - OPEN_PROGRESS, - WRITABLE_STATUS, - LINK_STATUS, - BACKEND_DIED, - LAST_SIGNAL -}; - -static guint e_book_signals [LAST_SIGNAL]; + +/* Error quark */ +GQuark +e_book_error_quark (void) +{ + static GQuark q = 0; + if (q == 0) + q = g_quark_from_static_string ("e-book-error-quark"); -typedef struct { - guint tag; - gboolean active; - gpointer cb; - gpointer closure; - EBookViewListener *listener; -} EBookOp; + return q; +} -/* - * Local response queue management. - */ + -static void -e_book_op_free (EBookOp *op) -{ - if (op->listener) { - bonobo_object_unref (BONOBO_OBJECT (op->listener)); - op->listener = NULL; - } - g_free (op); -} +/* EBookOp calls */ -static guint -e_book_queue_op (EBook *book, - gpointer cb, - gpointer closure, - EBookViewListener *listener) +static EBookOp* +e_book_new_op (EBook *book) { - EBookOp *op; + EBookOp *op = g_new0 (EBookOp, 1); - op = g_new0 (EBookOp, 1); - op->tag = book->priv->op_tag++; - op->active = TRUE; - op->cb = cb; - op->closure = closure; - op->listener = listener; + op->mutex = e_mutex_new (E_MUTEX_SIMPLE); + pthread_cond_init (&op->cond, 0); - if (op->listener) - bonobo_object_ref (BONOBO_OBJECT (op->listener)); + book->priv->current_op = op; - book->priv->pending_ops = - g_list_append (book->priv->pending_ops, op); + return op; +} - return op->tag; +static EBookOp* +e_book_get_op (EBook *book) +{ + if (!book->priv->current_op) { + g_warning ("unexpected response"); + return NULL; + } + + return book->priv->current_op; } -/* - * Local response queue management. - */ static void -e_book_unqueue_op (EBook *book) +e_book_op_free (EBookOp *op) { - EBookOp *op; - GList *removed; + /* XXX more stuff here */ + pthread_cond_destroy (&op->cond); + e_mutex_destroy (op->mutex); + g_free (op); +} - removed = g_list_last (book->priv->pending_ops); +static void +e_book_op_remove (EBook *book, + EBookOp *op) +{ + if (book->priv->current_op != op) + g_warning ("cannot remove op, it's not current"); - if (removed) { - book->priv->pending_ops = g_list_remove_link (book->priv->pending_ops, - removed); - op = removed->data; - e_book_op_free (op); - g_list_free_1 (removed); - book->priv->op_tag--; - } + book->priv->current_op = NULL; } -static EBookOp * -e_book_pop_op (EBook *book) +static void +e_book_clear_op (EBook *book, + EBookOp *op) { - GList *popped; - EBookOp *op; + e_book_op_remove (book, op); + e_mutex_unlock (op->mutex); + e_book_op_free (op); +} - if (book->priv->pending_ops == NULL) - return NULL; + - op = book->priv->pending_ops->data; +/** + * e_book_add_card: + * @book: an #EBook + * @contact: an #EContact + * + * adds @contact to @book. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_add_contact (EBook *book, + EContact *contact, + GError **error) +{ + EBookOp *our_op; + EBookStatus status; + CORBA_Environment ev; + char *vcard_str; - popped = book->priv->pending_ops; - book->priv->pending_ops = - g_list_remove_link (book->priv->pending_ops, - book->priv->pending_ops); + printf ("e_book_add_contact\n"); - g_list_free_1 (popped); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (contact && E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG); - return op; -} + e_mutex_lock (book->priv->mutex); -static gboolean -e_book_cancel_op (EBook *book, guint tag) -{ - GList *iter; - gboolean cancelled = FALSE; + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_add_contact called on book before e_book_load_uri")); + return FALSE; + } - for (iter = book->priv->pending_ops; iter != NULL && !cancelled; iter = g_list_next (iter)) { - EBookOp *op = iter->data; - if (op->tag == tag) { - op->active = FALSE; - cancelled = TRUE; - } + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; } - - return cancelled; -} -static void -e_book_do_response_create_card (EBook *book, - EBookListenerResponse *resp) -{ - EBookOp *op; + vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30); - op = e_book_pop_op (book); + our_op = e_book_new_op (book); - if (op == NULL) { - g_warning ("e_book_do_response_create_card: Cannot find operation " - "in local op queue!\n"); - return; - } + e_mutex_lock (our_op->mutex); - if (op->cb) - ((EBookIdCallback) op->cb) (book, resp->status, resp->id, op->closure); - g_free (resp->id); - e_book_op_free (op); -} + e_mutex_unlock (book->priv->mutex); -static void -e_book_do_response_generic (EBook *book, - EBookListenerResponse *resp) -{ - EBookOp *op; + CORBA_exception_init (&ev); - op = e_book_pop_op (book); + /* will eventually end up calling e_book_response_add_contact */ + GNOME_Evolution_Addressbook_Book_addContact (book->priv->corba_book, + (const GNOME_Evolution_Addressbook_VCard) vcard_str, &ev); - if (op == NULL) { - g_warning ("e_book_do_response_generic: Cannot find operation " - "in local op queue!\n"); + g_free (vcard_str); + + if (ev._major != CORBA_NO_EXCEPTION) { + + e_book_clear_op (book, our_op); + + CORBA_exception_free (&ev); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::addContact call")); + return FALSE; } - if (op->cb) - ((EBookCallback) op->cb) (book, resp->status, op->closure); + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - e_book_op_free (op); + status = our_op->status; + e_contact_set (contact, E_CONTACT_UID, our_op->id); + g_free (our_op->id); + + e_book_clear_op (book, our_op); + + E_BOOK_CHECK_STATUS (status, error); } static void -e_book_do_response_get_vcard (EBook *book, - EBookListenerResponse *resp) +e_book_response_add_contact (EBook *book, + EBookStatus status, + char *id) { EBookOp *op; - ECard *card; - op = e_book_pop_op (book); + printf ("e_book_response_add_contact\n"); + + op = e_book_get_op (book); if (op == NULL) { - g_warning ("e_book_do_response_get_vcard: Cannot find operation " - "in local op queue!\n"); - return; + g_warning ("e_book_response_add_contact: Cannot find operation "); + return; } - if (resp->vcard != NULL) { - card = e_card_new(resp->vcard); + e_mutex_lock (op->mutex); - if (card != NULL) { - e_card_set_book (card, book); - if (op->cb) { - if (op->active) - ((EBookCardCallback) op->cb) (book, resp->status, card, op->closure); - else - ((EBookCardCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); - } + op->status = status; + op->id = g_strdup (id); - g_object_unref(card); - } else { - ((EBookCursorCallback) op->cb) (book, resp->status, NULL, op->closure); - } - } else { - ((EBookCardCallback) op->cb) (book, resp->status, NULL, op->closure); - } + pthread_cond_signal (&op->cond); - g_free (resp->vcard); - e_book_op_free (op); + e_mutex_unlock (op->mutex); } -static void -e_book_do_response_get_cursor (EBook *book, - EBookListenerResponse *resp) + + +/** + * e_book_commit_contact: + * @book: an #EBook + * @contact: an #EContact + * + * applies the changes made to @contact to the stored version in + * @book. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_commit_contact (EBook *book, + EContact *contact, + GError **error) { + EBookOp *our_op; + EBookStatus status; CORBA_Environment ev; - EBookOp *op; - ECardCursor *cursor; + char *vcard_str; - op = e_book_pop_op (book); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (contact && E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG); - if (op == NULL) { - g_warning ("e_book_do_response_get_cursor: Cannot find operation " - "in local op queue!\n"); - return; + e_mutex_lock (book->priv->mutex); + + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_commit_contact called on book before e_book_load_uri")); + return FALSE; } - cursor = e_card_cursor_new(resp->cursor); + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; + } - if (cursor != NULL) { - if (op->cb) { - if (op->active) - ((EBookCursorCallback) op->cb) (book, resp->status, cursor, op->closure); - else - ((EBookCursorCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); - } + vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30); - /* - * Release the remote GNOME_Evolution_Addressbook_Book in the PAS. - */ - CORBA_exception_init (&ev); + our_op = e_book_new_op (book); - bonobo_object_release_unref (resp->cursor, &ev); + e_mutex_lock (our_op->mutex); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_do_response_get_cursor: Exception releasing " - "remote GNOME_Evolution_Addressbook_CardCursor interface!\n"); - } + e_mutex_unlock (book->priv->mutex); - CORBA_exception_free (&ev); + CORBA_exception_init (&ev); - g_object_unref(cursor); - } else { - ((EBookCursorCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); - } - - e_book_op_free (op); -} + /* will eventually end up calling _e_book_response_generic */ + GNOME_Evolution_Addressbook_Book_modifyContact (book->priv->corba_book, + (const GNOME_Evolution_Addressbook_VCard) vcard_str, &ev); -static void -e_book_do_response_get_view (EBook *book, - EBookListenerResponse *resp) -{ - CORBA_Environment ev; - EBookOp *op; - EBookView *book_view; + g_free (vcard_str); + + if (ev._major != CORBA_NO_EXCEPTION) { - op = e_book_pop_op (book); + e_book_clear_op (book, our_op); - if (op == NULL) { - g_warning ("e_book_do_response_get_view: Cannot find operation " - "in local op queue!\n"); - return; + CORBA_exception_free (&ev); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::modifyContact call")); + return FALSE; } - - book_view = e_book_view_new (resp->book_view, op->listener); - - if (book_view != NULL) { - e_book_view_set_book (book_view, book); - - /* Only execute the callback if the operation is still flagged as active (i.e. hasn't - been cancelled. This is mildly wasteful since we unnecessaryily create the - book_view, etc... but I'm leery of tinkering with the CORBA magic. */ - if (op->cb) { - if (op->active) - ((EBookBookViewCallback) op->cb) (book, resp->status, book_view, op->closure); - else - ((EBookBookViewCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); - } - - /* - * Release the remote GNOME_Evolution_Addressbook_Book in the PAS. - */ - CORBA_exception_init (&ev); - bonobo_object_release_unref (resp->book_view, &ev); + CORBA_exception_free (&ev); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_do_response_get_view: Exception releasing " - "remote GNOME_Evolution_Addressbook_BookView interface!\n"); - } + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - CORBA_exception_free (&ev); + status = our_op->status; + e_contact_set (contact, E_CONTACT_UID, our_op->id); + g_free (our_op->id); - g_object_unref(book_view); - } else { - e_book_view_listener_stop (op->listener); - ((EBookBookViewCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); - } + /* remove the op from the book's hash of operations */ + e_book_clear_op (book, our_op); - e_book_op_free (op); + E_BOOK_CHECK_STATUS (status, error); } -static void -e_book_do_response_get_changes (EBook *book, - EBookListenerResponse *resp) + +/** + * e_book_get_supported_fields: + * @book: an #EBook + * @fields: a #GList + * + * queries @book for the list of fields it supports. mostly for use + * by the contact editor so it knows what fields to sensitize. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_get_supported_fields (EBook *book, + GList **fields, + GError **error) { + EBookOp *our_op; + EBookStatus status; CORBA_Environment ev; - EBookOp *op; - EBookView *book_view; - op = e_book_pop_op (book); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (fields, E_BOOK_ERROR_INVALID_ARG); - if (op == NULL) { - g_warning ("e_book_do_response_get_changes: Cannot find operation " - "in local op queue!\n"); - return; + e_mutex_lock (book->priv->mutex); + + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_get_supported_fields on book before e_book_load_uri")); + return FALSE; } - book_view = e_book_view_new (resp->book_view, op->listener); + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + } - if (book_view != NULL) { - e_book_view_set_book (book_view, book); - - if (op->cb) { - if (op->active) - ((EBookBookViewCallback) op->cb) (book, resp->status, book_view, op->closure); - else - ((EBookBookViewCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); - } + our_op = e_book_new_op (book); - /* - * Release the remote GNOME_Evolution_Addressbook_BookView in the PAS. - */ - CORBA_exception_init (&ev); + e_mutex_lock (our_op->mutex); - bonobo_object_release_unref (resp->book_view, &ev); + e_mutex_unlock (book->priv->mutex); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_do_response_get_changes: Exception releasing " - "remote GNOME_Evolution_Addressbook_BookView interface!\n"); - } + CORBA_exception_init (&ev); + + /* will eventually end up calling + _e_book_response_get_supported_fields */ + GNOME_Evolution_Addressbook_Book_getSupportedFields(book->priv->corba_book, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + + e_book_clear_op (book, our_op); CORBA_exception_free (&ev); - g_object_unref(book_view); - } else { - e_book_view_listener_stop (op->listener); - ((EBookBookViewCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::getSupportedFields call")); + return FALSE; } - e_book_op_free (op); -} -static void -backend_died_cb (EComponentListener *cl, gpointer user_data) -{ - EBook *book = user_data; + CORBA_exception_free (&ev); - book->priv->load_state = URINotLoaded; - g_signal_emit (book, e_book_signals [BACKEND_DIED], 0); + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + *fields = our_op->list; + + e_book_clear_op (book, our_op); + + E_BOOK_CHECK_STATUS (status, error); } static void -e_book_do_response_open (EBook *book, - EBookListenerResponse *resp) +e_book_response_get_supported_fields (EBook *book, + EBookStatus status, + GList *fields) { EBookOp *op; - if (resp->status == E_BOOK_STATUS_SUCCESS) { - book->priv->corba_book = resp->book; - book->priv->load_state = URILoaded; - - book->priv->comp_listener = e_component_listener_new (book->priv->corba_book); - book->priv->died_signal = g_signal_connect (book->priv->comp_listener, "component_died", - G_CALLBACK (backend_died_cb), book); - } - - op = e_book_pop_op (book); + op = e_book_get_op (book); if (op == NULL) { - g_warning ("e_book_do_response_open: Cannot find operation " - "in local op queue!\n"); - return; + g_warning ("e_book_response_get_supported_fields: Cannot find operation "); + return; } - if (op->cb) - ((EBookCallback) op->cb) (book, resp->status, op->closure); - e_book_op_free (op); -} + e_mutex_lock (op->mutex); -static void -e_book_do_progress_event (EBook *book, - EBookListenerResponse *resp) -{ - g_signal_emit (book, e_book_signals [OPEN_PROGRESS], 0, - resp->msg, resp->percent); + op->status = status; + op->list = fields; - g_free (resp->msg); -} + pthread_cond_signal (&op->cond); -static void -e_book_do_link_event (EBook *book, - EBookListenerResponse *resp) -{ - g_signal_emit (book, e_book_signals [LINK_STATUS], 0, - resp->connected); + e_mutex_unlock (op->mutex); } -static void -e_book_do_writable_event (EBook *book, - EBookListenerResponse *resp) + +/** + * e_book_get_supported_auth_methods: + * @book: an #EBook + * @auth_methods: a #GList + * + * queries @book for the list of authentication methods it supports. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_get_supported_auth_methods (EBook *book, + GList **auth_methods, + GError **error) { - g_signal_emit (book, e_book_signals [WRITABLE_STATUS], 0, - resp->writable); -} + EBookOp *our_op; + EBookStatus status; + CORBA_Environment ev; -static void -e_book_do_response_get_supported_fields (EBook *book, - EBookListenerResponse *resp) -{ - EBookOp *op; + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (auth_methods, E_BOOK_ERROR_INVALID_ARG); - op = e_book_pop_op (book); + e_mutex_lock (book->priv->mutex); - if (op == NULL) { - g_warning ("e_book_do_response_get_supported_fields: Cannot find operation " - "in local op queue!\n"); - return; + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_get_supported_auth_methods on book before e_book_load_uri")); + return FALSE; } - if (op->cb) { - if (op->active) - ((EBookFieldsCallback) op->cb) (book, resp->status, resp->list, op->closure); - else - ((EBookFieldsCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; } - g_object_unref(resp->list); + our_op = e_book_new_op (book); - e_book_op_free (op); + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (book->priv->mutex); + + CORBA_exception_init (&ev); + + /* will eventually end up calling + e_book_response_get_supported_fields */ + GNOME_Evolution_Addressbook_Book_getSupportedAuthMethods(book->priv->corba_book, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + + e_book_clear_op (book, our_op); + + CORBA_exception_free (&ev); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::getSupportedAuthMethods call")); + return FALSE; + } + + + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + *auth_methods = our_op->list; + + e_book_clear_op (book, our_op); + + E_BOOK_CHECK_STATUS (status, error); } static void -e_book_do_response_get_supported_auth_methods (EBook *book, - EBookListenerResponse *resp) +e_book_response_get_supported_auth_methods (EBook *book, + EBookStatus status, + GList *auth_methods) { EBookOp *op; - op = e_book_pop_op (book); + op = e_book_get_op (book); if (op == NULL) { - g_warning ("e_book_do_response_get_supported_auth_methods: Cannot find operation " - "in local op queue!\n"); - return; - } - - if (op->cb) { - if (op->active) - ((EBookAuthMethodsCallback) op->cb) (book, resp->status, resp->list, op->closure); - else - ((EBookAuthMethodsCallback) op->cb) (book, E_BOOK_STATUS_CANCELLED, NULL, op->closure); + g_warning ("e_book_response_get_supported_auth_methods: Cannot find operation "); + return; } - g_object_unref(resp->list); + e_mutex_lock (op->mutex); - e_book_op_free (op); -} + op->status = status; + op->list = auth_methods; -/* - * Reading notices out of the EBookListener's queue. - */ -static void -e_book_check_listener_queue (EBookListener *listener, EBook *book) -{ - EBookListenerResponse *resp; + pthread_cond_signal (&op->cond); - resp = e_book_listener_pop_response (listener); + e_mutex_unlock (op->mutex); +} - if (resp == NULL) - return; - - switch (resp->op) { - case CreateCardResponse: - e_book_do_response_create_card (book, resp); - break; - case RemoveCardResponse: - case ModifyCardResponse: - case AuthenticationResponse: - e_book_do_response_generic (book, resp); - break; - case GetCardResponse: - e_book_do_response_get_vcard (book, resp); - break; - case GetCursorResponse: - e_book_do_response_get_cursor (book, resp); - break; - case GetBookViewResponse: - e_book_do_response_get_view(book, resp); - break; - case GetChangesResponse: - e_book_do_response_get_changes(book, resp); - break; - case OpenBookResponse: - e_book_do_response_open (book, resp); - break; - case GetSupportedFieldsResponse: - e_book_do_response_get_supported_fields (book, resp); - break; - case GetSupportedAuthMethodsResponse: - e_book_do_response_get_supported_auth_methods (book, resp); - break; - - case OpenProgressEvent: - e_book_do_progress_event (book, resp); - break; - case LinkStatusEvent: - e_book_do_link_event (book, resp); - break; - case WritableStatusEvent: - e_book_do_writable_event (book, resp); - break; - default: - g_error ("EBook: Unknown operation %d in listener queue!\n", - resp->op); - } - - g_free (resp); -} + /** - * e_book_load_uri: - */ + * e_book_authenticate_user: + * @book: an #EBook + * @user: a string + * @passwd: a string + * @auth_method: a string + * + * authenticates @user with @passwd, using the auth method + * @auth_method. @auth_method must be one of the authentication + * methods returned using e_book_get_supported_auth_methods. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_authenticate_user (EBook *book, + const char *user, + const char *passwd, + const char *auth_method, + GError **error) +{ + EBookOp *our_op; + EBookStatus status; + CORBA_Environment ev; -typedef struct { - char *uri; - EBookCallback open_response; - gpointer closure; -} EBookLoadURIData; + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (user, E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (passwd, E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (auth_method, E_BOOK_ERROR_INVALID_ARG); -static void e_book_load_uri_from_factory (EBook *book, - GNOME_Evolution_Addressbook_BookFactory factory, - EBookLoadURIData *load_uri_data); + e_mutex_lock (book->priv->mutex); -static void -e_book_load_uri_step (EBook *book, EBookStatus status, EBookLoadURIData *data) -{ - /* iterate to the next possible CardFactory, or fail - if it's the last one */ - book->priv->iter = book->priv->iter->next; - if (book->priv->iter) { - GNOME_Evolution_Addressbook_BookFactory factory = book->priv->iter->data; - e_book_load_uri_from_factory (book, factory, data); + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_authenticate_user on book before e_book_load_uri")); + return FALSE; } - else { - EBookCallback cb = data->open_response; - gpointer closure = data->closure; - - /* reset the load_state to NotLoaded so people can - attempt another load_uri on the book. */ - book->priv->load_state = URINotLoaded; - g_free (data); - - cb (book, status, closure); + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; } -} - -static void -e_book_load_uri_open_cb (EBook *book, EBookStatus status, EBookLoadURIData *data) -{ - if (status == E_BOOK_STATUS_SUCCESS) { - EBookCallback cb = data->open_response; - gpointer closure = data->closure; - g_free (data); + our_op = e_book_new_op (book); - cb (book, status, closure); - } - else { - e_book_load_uri_step (book, status, data); - } -} + e_mutex_lock (our_op->mutex); -static void -e_book_load_uri_from_factory (EBook *book, - GNOME_Evolution_Addressbook_BookFactory factory, - EBookLoadURIData *load_uri_data) -{ - CORBA_Environment ev; + e_mutex_unlock (book->priv->mutex); CORBA_exception_init (&ev); - e_book_queue_op (book, e_book_load_uri_open_cb, load_uri_data, NULL); - - GNOME_Evolution_Addressbook_BookFactory_openBook ( - factory, book->priv->uri, - bonobo_object_corba_objref (BONOBO_OBJECT (book->priv->listener)), - &ev); + /* will eventually end up calling + e_book_response_generic */ + GNOME_Evolution_Addressbook_Book_authenticateUser (book->priv->corba_book, + user, passwd, + auth_method, + &ev); if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_load_uri: CORBA exception while opening addressbook!\n"); - e_book_unqueue_op (book); + + e_book_clear_op (book, our_op); + CORBA_exception_free (&ev); - e_book_load_uri_step (book, E_BOOK_STATUS_OTHER_ERROR, load_uri_data); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::authenticateUser call")); + return FALSE; } CORBA_exception_free (&ev); + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + + e_book_clear_op (book, our_op); + + E_BOOK_CHECK_STATUS (status, error); } + -static gboolean -activate_factories_for_uri (EBook *book, const char *uri) +/** + * e_book_get_contact: + * @book: an #EBook + * @id: a string + * @contact: an #EContact + * + * Fills in @contact with the contents of the vcard in @book + * corresponding to @id. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_get_contact (EBook *book, + const char *id, + EContact **contact, + GError **error) { + EBookOp *our_op; + EBookStatus status; CORBA_Environment ev; - Bonobo_ServerInfoList *info_list = NULL; - int i; - char *protocol, *query, *colon; - gboolean retval = FALSE; - colon = strchr (uri, ':'); - if (!colon) { - g_warning ("e_book_load_uri: Unable to determine protocol in the URI\n"); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (id, E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (contact, E_BOOK_ERROR_INVALID_ARG); + + e_mutex_lock (book->priv->mutex); + + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_get_contact on book before e_book_load_uri")); return FALSE; } - protocol = g_strndup (uri, colon-uri); - query = g_strdup_printf ("repo_ids.has ('IDL:GNOME/Evolution/BookFactory:1.0')" - " AND addressbook:supported_protocols.has ('%s')", protocol - ); + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; + } + + our_op = e_book_new_op (book); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (book->priv->mutex); CORBA_exception_init (&ev); - - info_list = bonobo_activation_query (query, NULL, &ev); + + /* will eventually end up calling e_book_response_generic */ + GNOME_Evolution_Addressbook_Book_getContact (book->priv->corba_book, + (const GNOME_Evolution_Addressbook_VCard) id, &ev); if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("Eeek! Cannot perform bonobo-activation query for book factories."); - CORBA_exception_free (&ev); - goto shutdown; - } - if (info_list->_length == 0) { - g_warning ("Can't find installed BookFactory that handles protocol '%s'.", protocol); + e_book_clear_op (book, our_op); + CORBA_exception_free (&ev); - goto shutdown; + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::getContact call")); + return FALSE; } CORBA_exception_free (&ev); - for (i = 0; i < info_list->_length; i ++) { - const Bonobo_ServerInfo *info; - GNOME_Evolution_Addressbook_BookFactory factory; + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - info = info_list->_buffer + i; + status = our_op->status; + *contact = our_op->contact; - factory = bonobo_activation_activate_from_id (info->iid, 0, NULL, NULL); + e_book_clear_op (book, our_op); - if (factory == CORBA_OBJECT_NIL) - g_warning ("e_book_construct: Could not obtain a handle " - "to the Personal Addressbook Server with IID `%s'\n", info->iid); - else - book->priv->book_factories = g_list_append (book->priv->book_factories, - factory); - } + E_BOOK_CHECK_STATUS (status, error); +} + +static void +e_book_response_get_contact (EBook *book, + EBookStatus status, + EContact *contact) +{ + EBookOp *op; - if (!book->priv->book_factories) { - g_warning ("Couldn't activate any book factories."); - goto shutdown; + printf ("e_book_response_get_contact\n"); + + op = e_book_get_op (book); + + if (op == NULL) { + g_warning ("e_book_response_get_contact: Cannot find operation "); + return; } - retval = TRUE; + e_mutex_lock (op->mutex); - shutdown: - if (info_list) - CORBA_free (info_list); - g_free (query); - g_free (protocol); + op->status = status; + op->contact = contact; - return retval; + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); } -void -e_book_load_uri (EBook *book, - const char *uri, - EBookCallback open_response, - gpointer closure) + +/** + * e_book_remove_contact: + * @book: an #EBook + * @id: a string + * + * Removes the contact with id @id from @book. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_remove_contact (EBook *book, + const char *id, + GError **error) { - EBookLoadURIData *load_uri_data; - GNOME_Evolution_Addressbook_BookFactory factory; + GList *list; + gboolean rv; - g_return_if_fail (book != NULL); - g_return_if_fail (E_IS_BOOK (book)); - g_return_if_fail (uri != NULL); - g_return_if_fail (open_response != NULL); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (id, E_BOOK_ERROR_INVALID_ARG); - if (book->priv->load_state != URINotLoaded) { - g_warning ("e_book_load_uri: Attempted to load a URI " - "on a book which already has a URI loaded!\n"); - open_response (book, E_BOOK_STATUS_OTHER_ERROR, closure); /* XXX need a new status code here */ - return; - } + e_mutex_lock (book->priv->mutex); - /* try to find a list of factories that can handle the protocol */ - if (!activate_factories_for_uri (book, uri)) { - open_response (book, E_BOOK_STATUS_PROTOCOL_NOT_SUPPORTED, closure); - return; + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_remove_contact on book before e_book_load_uri")); + return FALSE; } - - g_free (book->priv->uri); - book->priv->uri = g_strdup (uri); - /* - * Create our local BookListener interface. - */ - book->priv->listener = e_book_listener_new (); - if (book->priv->listener == NULL) { - g_warning ("e_book_load_uri: Could not create EBookListener!\n"); - open_response (NULL, E_BOOK_STATUS_OTHER_ERROR, closure); /* XXX need a new status code here */ - return; + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; } - book->priv->listener_signal = g_signal_connect (book->priv->listener, "responses_queued", - G_CALLBACK (e_book_check_listener_queue), book); - - load_uri_data = g_new (EBookLoadURIData, 1); - load_uri_data->open_response = open_response; - load_uri_data->closure = closure; + e_mutex_lock (book->priv->mutex); - /* initialize the iterator, and load from the first one*/ - book->priv->iter = book->priv->book_factories; + list = g_list_append (NULL, (char*)id); - factory = book->priv->iter->data; + rv = e_book_remove_contacts (book, list, error); - e_book_load_uri_from_factory (book, factory, load_uri_data); - - book->priv->load_state = URILoading; + return rv; } /** - * e_book_unload_uri: - */ -void -e_book_unload_uri (EBook *book) + * e_book_remove_contacts: + * @book: an #EBook + * @ids: an #GList of const char *id's + * + * Removes the contacts with ids from the list @ids from @book. This is + * always more efficient than calling e_book_remove_contact_by_id if you + * have more than one id to remove, as some backends can implement it + * as a batch request. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_remove_contacts (EBook *book, + GList *ids, + GError **error) { + GNOME_Evolution_Addressbook_ContactIdList idlist; CORBA_Environment ev; + GList *iter; + int num_ids, i; + EBookOp *our_op; + EBookStatus status; - g_return_if_fail (book != NULL); - g_return_if_fail (E_IS_BOOK (book)); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (ids, E_BOOK_ERROR_INVALID_ARG); - /* - * FIXME: Make sure this works if the URI is still being - * loaded. - */ - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_unload_uri: No URI is loaded!\n"); - return; + e_mutex_lock (book->priv->mutex); + + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_remove_contacts on book before e_book_load_uri")); + return FALSE; } - /* - * Release the remote GNOME_Evolution_Addressbook_Book in the PAS. - */ + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; + } + + our_op = e_book_new_op (book); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (book->priv->mutex); + CORBA_exception_init (&ev); - bonobo_object_release_unref (book->priv->corba_book, &ev); + num_ids = g_list_length (ids); + idlist._buffer = CORBA_sequence_GNOME_Evolution_Addressbook_ContactId_allocbuf (num_ids); + idlist._maximum = num_ids; + idlist._length = num_ids; + + for (iter = ids, i = 0; iter; iter = iter->next) + idlist._buffer[i++] = CORBA_string_dup (iter->data); + + /* will eventually end up calling e_book_response_generic */ + GNOME_Evolution_Addressbook_Book_removeContacts (book->priv->corba_book, &idlist, &ev); + + CORBA_free(idlist._buffer); + if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_unload_uri: Exception releasing " - "remote book interface!\n"); - } + e_book_clear_op (book, our_op); + + CORBA_exception_free (&ev); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::removeContacts call")); + return FALSE; + } + CORBA_exception_free (&ev); - e_book_listener_stop (book->priv->listener); - bonobo_object_unref (BONOBO_OBJECT (book->priv->listener)); + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - book->priv->listener = NULL; - book->priv->load_state = URINotLoaded; -} + status = our_op->status; -const char * -e_book_get_uri (EBook *book) -{ - g_return_val_if_fail (book && E_IS_BOOK (book), NULL); + e_book_clear_op (book, our_op); - return book->priv->uri; + E_BOOK_CHECK_STATUS (status, error); } -char * -e_book_get_static_capabilities (EBook *book) + +/** + * e_book_get_book_view: + * @book: an #EBook + * @query: an #EBookQuery + * @requested_fields a #GList containing the names of fields to return, or NULL for all + * @max_results the maximum number of contacts to show (or 0 for all) + * + * need docs here.. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_get_book_view (EBook *book, + EBookQuery *query, + GList *requested_fields, + int max_results, + EBookView **book_view, + GError **error) { - if (!book->priv->cap_queried) { - CORBA_Environment ev; - char *temp; + GNOME_Evolution_Addressbook_stringlist stringlist; + CORBA_Environment ev; + EBookOp *our_op; + EBookStatus status; + int num_fields, i; + GList *iter; + char *query_string; - CORBA_exception_init (&ev); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (query, E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (book_view, E_BOOK_ERROR_INVALID_ARG); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_unload_uri: No URI is loaded!\n"); - return g_strdup(""); - } + e_mutex_lock (book->priv->mutex); - temp = GNOME_Evolution_Addressbook_Book_getStaticCapabilities(book->priv->corba_book, &ev); + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_get_book_view on book before e_book_load_uri")); + return FALSE; + } - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_get_static_capabilities: Exception " - "during get_static_capabilities!\n"); - CORBA_exception_free (&ev); - return g_strdup(""); - } + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; + } - book->priv->cap = g_strdup(temp); - book->priv->cap_queried = TRUE; + our_op = e_book_new_op (book); - CORBA_free(temp); + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (book->priv->mutex); + + CORBA_exception_init (&ev); + + our_op->listener = e_book_view_listener_new(); + + num_fields = g_list_length (requested_fields); + + stringlist._buffer = CORBA_sequence_CORBA_string_allocbuf (num_fields); + stringlist._maximum = num_fields; + stringlist._length = num_fields; + + for (i = 0, iter = requested_fields; iter; iter = iter->next, i ++) { + stringlist._buffer[i] = CORBA_string_dup ((char*)iter->data); + } + + query_string = e_book_query_to_string (query); + + /* will eventually end up calling e_book_response_get_book_view */ + GNOME_Evolution_Addressbook_Book_getBookView (book->priv->corba_book, + bonobo_object_corba_objref(BONOBO_OBJECT(our_op->listener)), + query_string, + &stringlist, max_results, &ev); + + CORBA_free(stringlist._buffer); + g_free (query_string); + + if (ev._major != CORBA_NO_EXCEPTION) { + + e_book_clear_op (book, our_op); CORBA_exception_free (&ev); + + g_warning ("corba exception._major = %d\n", ev._major); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::getBookView call")); + return FALSE; } + + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - return g_strdup (book->priv->cap); + status = our_op->status; + *book_view = our_op->view; + + e_book_clear_op (book, our_op); + + E_BOOK_CHECK_STATUS (status, error); } -gboolean -e_book_check_static_capability (EBook *book, const char *cap) +static void +e_book_response_get_book_view (EBook *book, + EBookStatus status, + GNOME_Evolution_Addressbook_BookView corba_book_view) { - gboolean rv = FALSE; - char *caps = e_book_get_static_capabilities (book); - if (!caps) - return FALSE; - /* XXX this is an inexact test but it works for our use */ - if (strstr (caps, cap)) - rv = TRUE; + EBookOp *op; - g_free (caps); + printf ("e_book_response_get_book_view\n"); - return rv; + op = e_book_get_op (book); + + if (op == NULL) { + g_warning ("e_book_response_get_book_view: Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + op->view = e_book_view_new (corba_book_view, op->listener); + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); } -guint -e_book_get_supported_fields (EBook *book, - EBookFieldsCallback cb, - gpointer closure) + + +/** + * e_book_get_contacts: + * @book: an #EBook + * @query: an #EBookQuery + * + * need docs here.. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_get_contacts (EBook *book, + EBookQuery *query, + GList **contacts, + GError **error) { CORBA_Environment ev; - guint tag; + EBookOp *our_op; + EBookStatus status; + char *query_string; - CORBA_exception_init (&ev); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (query, E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (contacts, E_BOOK_ERROR_INVALID_ARG); + + e_mutex_lock (book->priv->mutex); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_unload_uri: No URI is loaded!\n"); - return 0; + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_get_contacts on book before e_book_load_uri")); + return FALSE; } - tag = e_book_queue_op (book, cb, closure, NULL); + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; + } - GNOME_Evolution_Addressbook_Book_getSupportedFields(book->priv->corba_book, &ev); + our_op = e_book_new_op (book); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (book->priv->mutex); + + CORBA_exception_init (&ev); + + query_string = e_book_query_to_string (query); + + /* will eventually end up calling e_book_response_get_contacts */ + GNOME_Evolution_Addressbook_Book_getContactList (book->priv->corba_book, query_string, &ev); + + g_free (query_string); if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_get_supported_fields: Exception " - "during get_supported_fields!\n"); + + e_book_clear_op (book, our_op); + CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return 0; - } + g_warning ("corba exception._major = %d\n", ev._major); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::getContactList call")); + return FALSE; + } + CORBA_exception_free (&ev); - return tag; + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + *contacts = our_op->list; + + e_book_clear_op (book, our_op); + + E_BOOK_CHECK_STATUS (status, error); } -guint -e_book_get_supported_auth_methods (EBook *book, - EBookAuthMethodsCallback cb, - gpointer closure) +static void +e_book_response_get_contacts (EBook *book, + EBookStatus status, + GList *contact_list) +{ + + EBookOp *op; + + op = e_book_get_op (book); + + if (op == NULL) { + g_warning ("e_book_response_get_contacts: Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + op->list = contact_list; + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + + +gboolean +e_book_get_changes (EBook *book, + char *changeid, + GList **changes, + GError **error) { CORBA_Environment ev; - guint tag; + EBookOp *our_op; + EBookStatus status; - CORBA_exception_init (&ev); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (changeid, E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (changes, E_BOOK_ERROR_INVALID_ARG); + + e_mutex_lock (book->priv->mutex); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_unload_uri: No URI is loaded!\n"); - return 0; + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_get_changes on book before e_book_load_uri")); + return FALSE; } - tag = e_book_queue_op (book, cb, closure, NULL); + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; + } - GNOME_Evolution_Addressbook_Book_getSupportedAuthMethods(book->priv->corba_book, &ev); + our_op = e_book_new_op (book); + + e_mutex_lock (our_op->mutex); + + e_mutex_unlock (book->priv->mutex); + + CORBA_exception_init (&ev); + + /* will eventually end up calling e_book_response_get_changes */ + GNOME_Evolution_Addressbook_Book_getChanges (book->priv->corba_book, changeid, &ev); if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_get_supported_auth_methods: Exception " - "during get_supported_auth_methods!\n"); + + e_book_clear_op (book, our_op); + CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return 0; - } + g_warning ("corba exception._major = %d\n", ev._major); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::getChanges call")); + return FALSE; + } + CORBA_exception_free (&ev); - return tag; -} + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); -static gboolean -e_book_construct (EBook *book) -{ - g_return_val_if_fail (book != NULL, FALSE); - g_return_val_if_fail (E_IS_BOOK (book), FALSE); + status = our_op->status; + *changes = our_op->list; - book->priv->book_factories = NULL; + e_book_clear_op (book, our_op); - return TRUE; + E_BOOK_CHECK_STATUS (status, error); } -/** - * e_book_new: - */ -EBook * -e_book_new (void) +static void +e_book_response_get_changes (EBook *book, + EBookStatus status, + GList *change_list) { - EBook *book; - book = g_object_new (E_TYPE_BOOK, NULL); + EBookOp *op; - if (! e_book_construct (book)) { - g_object_unref (book); - return NULL; + op = e_book_get_op (book); + + if (op == NULL) { + g_warning ("e_book_response_get_contacts: Cannot find operation "); + return; } - return book; -} + e_mutex_lock (op->mutex); + + op->status = status; + op->list = change_list; -/* User authentication. */ + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} void -e_book_authenticate_user (EBook *book, - const char *user, - const char *passwd, - const char *auth_method, - EBookCallback cb, - gpointer closure) +e_book_free_change_list (GList *change_list) { - CORBA_Environment ev; - - g_return_if_fail (book != NULL); - g_return_if_fail (E_IS_BOOK (book)); + GList *l; + for (l = change_list; l; l = l->next) { + EBookChange *change = l->data; - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_authenticate_user: No URI loaded!\n"); - return; + g_free (change->vcard); + g_free (change); } - CORBA_exception_init (&ev); + g_list_free (change_list); +} - e_book_queue_op (book, cb, closure, NULL); + - GNOME_Evolution_Addressbook_Book_authenticateUser (book->priv->corba_book, - user, - passwd, - auth_method, - &ev); +static void +e_book_response_generic (EBook *book, + EBookStatus status) +{ + EBookOp *op; - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_authenticate_user: Exception authenticating user with the PAS!\n"); - CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return; + op = e_book_get_op (book); + + if (op == NULL) { + g_warning ("e_book_response_generic: Cannot find operation "); + return; } - CORBA_exception_free (&ev); -} + e_mutex_lock (op->mutex); + + op->status = status; -/* Fetching cards */ + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} /** - * e_book_get_card: - */ -guint -e_book_get_card (EBook *book, - const char *id, - EBookCardCallback cb, - gpointer closure) + * e_book_cancel: + * @book: an #EBook + * + * Used to cancel an already running operation on @book. This + * function makes a synchronous CORBA to the backend telling it to + * cancel the operation. If the operation wasn't cancellable (either + * transiently or permanently) or had already comopleted on the wombat + * side, this function will return E_BOOK_STATUS_COULD_NOT_CANCEL, and + * the operation will continue uncancelled. If the operation could be + * cancelled, this function will return E_BOOK_ERROR_OK, and the + * blocked e_book function corresponding to current operation will + * return with a status of E_BOOK_STATUS_CANCELLED. + * + * Return value: a #EBookStatus value. + **/ +gboolean +e_book_cancel (EBook *book, + GError **error) { + EBookOp *op; + EBookStatus status; + gboolean rv; CORBA_Environment ev; - guint tag; - g_return_val_if_fail (book != NULL, 0); - g_return_val_if_fail (E_IS_BOOK (book), 0); + e_mutex_lock (book->priv->mutex); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_get_card: No URI loaded!\n"); - return 0; + if (book->priv->current_op == NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_COULD_NOT_CANCEL, + _("e_book_cancel: there is no current operation")); + return FALSE; } - CORBA_exception_init (&ev); + op = book->priv->current_op; + + e_mutex_lock (op->mutex); - tag = e_book_queue_op (book, cb, closure, NULL); + e_mutex_unlock (book->priv->mutex); - GNOME_Evolution_Addressbook_Book_getVCard (book->priv->corba_book, (const GNOME_Evolution_Addressbook_VCard) id, &ev); + status = GNOME_Evolution_Addressbook_Book_cancelOperation(book->priv->corba_book, &ev); if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_get_card: Exception " - "getting card!\n"); + + e_mutex_unlock (op->mutex); + CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return 0; + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::cancelOperation call")); + return FALSE; } CORBA_exception_free (&ev); - return tag; + if (status == E_BOOK_ERROR_OK) { + op->status = E_BOOK_ERROR_CANCELLED; + + pthread_cond_signal (&op->cond); + + rv = TRUE; + } + else { + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_COULD_NOT_CANCEL, + _("e_book_cancel: couldn't cancel")); + rv = FALSE; + } + + e_mutex_unlock (op->mutex); + + return rv; } -/* Deleting cards. */ +static void +e_book_response_open (EBook *book, + EBookStatus status) +{ + EBookOp *op; + + op = e_book_get_op (book); + + if (op == NULL) { + g_warning ("e_book_response_open: Cannot find operation "); + return; + } + + e_mutex_lock (op->mutex); + + op->status = status; + + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + + -/** - * e_book_remove_card: - */ gboolean -e_book_remove_card (EBook *book, - ECard *card, - EBookCallback cb, - gpointer closure) +e_book_remove (EBook *book, + GError **error) { - const char *id; + CORBA_Environment ev; + EBookOp *our_op; + EBookStatus status; + + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); - g_return_val_if_fail (book != NULL, FALSE); - g_return_val_if_fail (E_IS_BOOK (book), FALSE); - g_return_val_if_fail (card != NULL, FALSE); - g_return_val_if_fail (E_IS_CARD (card), FALSE); + e_mutex_lock (book->priv->mutex); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_remove_card: No URI loaded!\n"); + if (book->priv->load_state != E_BOOK_URI_LOADED) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_URI_NOT_LOADED, + _("e_book_remove on book before e_book_load_uri")); return FALSE; } - id = e_card_get_id (card); - g_assert (id != NULL); + if (book->priv->current_op != NULL) { + e_mutex_unlock (book->priv->mutex); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY, + _("book busy")); + return FALSE; + } - return e_book_remove_card_by_id (book, id, cb, closure); -} + our_op = e_book_new_op (book); -/** - * e_book_remove_card_by_id: - */ -gboolean -e_book_remove_card_by_id (EBook *book, - const char *id, - EBookCallback cb, - gpointer closure) + e_mutex_lock (our_op->mutex); -{ - GList *list = NULL; - gboolean rv; + e_mutex_unlock (book->priv->mutex); - list = g_list_prepend (list, (char*)id); - - rv = e_book_remove_cards (book, list, cb, closure); + CORBA_exception_init (&ev); - g_list_free (list); + /* will eventually end up calling e_book_response_remove */ + GNOME_Evolution_Addressbook_Book_remove (book->priv->corba_book, &ev); - return rv; + if (ev._major != CORBA_NO_EXCEPTION) { + + e_book_clear_op (book, our_op); + + CORBA_exception_free (&ev); + + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION, + _("Corba exception making Book::remove call")); + return FALSE; + } + + CORBA_exception_free (&ev); + + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); + + status = our_op->status; + + e_book_clear_op (book, our_op); + + E_BOOK_CHECK_STATUS (status, error); } -gboolean -e_book_remove_cards (EBook *book, - GList *ids, - EBookCallback cb, - gpointer closure) +static void +e_book_response_remove (EBook *book, + EBookStatus status) { - GNOME_Evolution_Addressbook_CardIdList idlist; - CORBA_Environment ev; - GList *l; - int num_ids, i; + EBookOp *op; - g_return_val_if_fail (book != NULL, FALSE); - g_return_val_if_fail (E_IS_BOOK (book), FALSE); - g_return_val_if_fail (ids != NULL, FALSE); + printf ("e_book_response_remove\n"); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_remove_card_by_id: No URI loaded!\n"); - return FALSE; + op = e_book_get_op (book); + + if (op == NULL) { + g_warning ("e_book_response_remove: Cannot find operation "); + return; } - CORBA_exception_init (&ev); + e_mutex_lock (op->mutex); - e_book_queue_op (book, cb, closure, NULL); + op->status = status; - num_ids = g_list_length (ids); - idlist._buffer = CORBA_sequence_GNOME_Evolution_Addressbook_CardId_allocbuf (num_ids); - idlist._maximum = num_ids; - idlist._length = num_ids; + pthread_cond_signal (&op->cond); + + e_mutex_unlock (op->mutex); +} + + - for (l = ids, i = 0; l; l=l->next, i ++) { - idlist._buffer[i] = CORBA_string_dup (l->data); +static void +e_book_handle_response (EBookListener *listener, EBookListenerResponse *resp, EBook *book) +{ + switch (resp->op) { + case CreateContactResponse: + e_book_response_add_contact (book, resp->status, resp->id); + break; + case RemoveContactResponse: + case ModifyContactResponse: + case AuthenticationResponse: + e_book_response_generic (book, resp->status); + break; + case GetContactResponse: { + EContact *contact = e_contact_new_from_vcard (resp->vcard); + e_book_response_get_contact (book, resp->status, contact); + break; } + case GetContactListResponse: + e_book_response_get_contacts (book, resp->status, resp->list); + break; + case GetBookViewResponse: + e_book_response_get_book_view(book, resp->status, resp->book_view); + break; + case GetChangesResponse: + e_book_response_get_changes(book, resp->status, resp->list); + break; + case OpenBookResponse: + e_book_response_open (book, resp->status); + break; + case RemoveBookResponse: + e_book_response_remove (book, resp->status); + break; + case GetSupportedFieldsResponse: + e_book_response_get_supported_fields (book, resp->status, resp->list); + break; + case GetSupportedAuthMethodsResponse: + e_book_response_get_supported_auth_methods (book, resp->status, resp->list); + break; + case WritableStatusEvent: + book->priv->writable = resp->writable; + g_signal_emit (book, e_book_signals [WRITABLE_STATUS], 0, resp->writable); + break; + default: + g_error ("EBook: Unknown response code %d!\n", + resp->op); + } +} + + + +gboolean +e_book_unload_uri (EBook *book, + GError **error) +{ + CORBA_Environment ev; - GNOME_Evolution_Addressbook_Book_removeCards (book->priv->corba_book, &idlist, &ev); + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (book->priv->load_state != E_BOOK_URI_NOT_LOADED, E_BOOK_ERROR_URI_NOT_LOADED); + /* Release the remote GNOME_Evolution_Addressbook_Book in the PAS. */ + CORBA_exception_init (&ev); + + bonobo_object_release_unref (book->priv->corba_book, &ev); if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_remove_card_by_id: CORBA exception " - "talking to PAS!\n"); - CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return FALSE; + g_warning ("e_book_unload_uri: Exception releasing " + "remote book interface!\n"); } - + CORBA_exception_free (&ev); - CORBA_free(idlist._buffer); + e_book_listener_stop (book->priv->listener); + bonobo_object_unref (BONOBO_OBJECT (book->priv->listener)); + + book->priv->listener = NULL; + book->priv->load_state = E_BOOK_URI_NOT_LOADED; + g_free (book->priv->cap); + book->priv->cap = NULL; + book->priv->writable = FALSE; return TRUE; } - -/* Adding cards. */ + /** - * e_book_add_card: + * e_book_load_uri: */ -gboolean -e_book_add_card (EBook *book, - ECard *card, - EBookIdCallback cb, - gpointer closure) +static void +backend_died_cb (EComponentListener *cl, gpointer user_data) { - char *vcard; - gboolean retval; + EBook *book = user_data; + + book->priv->load_state = E_BOOK_URI_NOT_LOADED; + g_signal_emit (book, e_book_signals [BACKEND_DIED], 0); +} - g_return_val_if_fail (book != NULL, FALSE); - g_return_val_if_fail (E_IS_BOOK (book), FALSE); - g_return_val_if_fail (card != NULL, FALSE); - g_return_val_if_fail (E_IS_CARD (card), FALSE); +static GList * +activate_factories_for_uri (EBook *book, const char *uri) +{ + CORBA_Environment ev; + Bonobo_ServerInfoList *info_list = NULL; + int i; + char *protocol, *query, *colon; + GList *factories = NULL; - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_add_card: No URI loaded!\n"); + colon = strchr (uri, ':'); + if (!colon) { + g_warning ("e_book_load_uri: Unable to determine protocol in the URI\n"); return FALSE; } - vcard = e_card_get_vcard_assume_utf8 (card); + protocol = g_strndup (uri, colon-uri); + query = g_strdup_printf ("repo_ids.has ('IDL:GNOME/Evolution/BookFactory:1.0')" + " AND addressbook:supported_protocols.has ('%s')", protocol + ); - if (vcard == NULL) { - g_warning ("e_book_add_card: Cannot convert card to VCard string!\n"); - return FALSE; + CORBA_exception_init (&ev); + + info_list = bonobo_activation_query (query, NULL, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + g_warning ("Eeek! Cannot perform bonobo-activation query for book factories."); + CORBA_exception_free (&ev); + goto done; + return NULL; + } + + if (info_list->_length == 0) { + g_warning ("Can't find installed BookFactory that handles protocol '%s'.", protocol); + CORBA_exception_free (&ev); + goto done; } - retval = e_book_add_vcard (book, vcard, cb, closure); + CORBA_exception_free (&ev); + + for (i = 0; i < info_list->_length; i ++) { + const Bonobo_ServerInfo *info; + GNOME_Evolution_Addressbook_BookFactory factory; + + info = info_list->_buffer + i; + + factory = bonobo_activation_activate_from_id (info->iid, 0, NULL, NULL); - g_free (vcard); + if (factory == CORBA_OBJECT_NIL) + g_warning ("e_book_construct: Could not obtain a handle " + "to the Personal Addressbook Server with IID `%s'\n", info->iid); + else + factories = g_list_append (factories, factory); + } - e_card_set_book (card, book); + done: + if (info_list) + CORBA_free (info_list); + g_free (query); + g_free (protocol); - return retval; + return factories; } -/** - * e_book_add_vcard: - */ gboolean -e_book_add_vcard (EBook *book, - const char *vcard, - EBookIdCallback cb, - gpointer closure) +e_book_load_uri (EBook *book, + const char *uri, + gboolean only_if_exists, + GError **error) { - CORBA_Environment ev; + GList *factories; + GList *l; + gboolean rv = FALSE; + GNOME_Evolution_Addressbook_Book corba_book = CORBA_OBJECT_NIL; + + e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG); + e_return_error_if_fail (uri, E_BOOK_ERROR_INVALID_ARG); - g_return_val_if_fail (book != NULL, FALSE); - g_return_val_if_fail (E_IS_BOOK (book), FALSE); - g_return_val_if_fail (vcard != NULL, FALSE); + /* XXX this needs to happen while holding the book's lock i would think... */ + e_return_error_if_fail (book->priv->load_state == E_BOOK_URI_NOT_LOADED, E_BOOK_ERROR_URI_ALREADY_LOADED); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_add_vcard: No URI loaded!\n"); + /* try to find a list of factories that can handle the protocol */ + if (! (factories = activate_factories_for_uri (book, uri))) { + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_PROTOCOL_NOT_SUPPORTED, + _("e_book_load_uri: no factories available for uri `%s'"), uri); return FALSE; } - CORBA_exception_init (&ev); - - e_book_queue_op (book, (EBookCallback) cb, closure, NULL); - GNOME_Evolution_Addressbook_Book_addCard ( - book->priv->corba_book, (const GNOME_Evolution_Addressbook_VCard) vcard, &ev); + book->priv->load_state = E_BOOK_URI_LOADING; - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_add_vcard: Exception adding card to PAS!\n"); - CORBA_exception_free (&ev); - e_book_unqueue_op (book); + /* + * Create our local BookListener interface. + */ + book->priv->listener = e_book_listener_new (); + if (book->priv->listener == NULL) { + g_warning ("e_book_load_uri: Could not create EBookListener!\n"); + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_OTHER_ERROR, + _("e_book_load_uri: Could not create EBookListener")); return FALSE; } + book->priv->listener_signal = g_signal_connect (book->priv->listener, "response", + G_CALLBACK (e_book_handle_response), book); - CORBA_exception_free (&ev); + g_free (book->priv->uri); + book->priv->uri = g_strdup (uri); - return TRUE; -} + for (l = factories; l; l = l->next) { + GNOME_Evolution_Addressbook_BookFactory factory = l->data; + EBookOp *our_op; + CORBA_Environment ev; + EBookStatus status; -/* Modifying cards. */ + our_op = e_book_new_op (book); -/** - * e_book_commit_card: - */ -gboolean -e_book_commit_card (EBook *book, - ECard *card, - EBookCallback cb, - gpointer closure) -{ - char *vcard; - gboolean retval; - - g_return_val_if_fail (book != NULL, FALSE); - g_return_val_if_fail (E_IS_BOOK (book), FALSE); - g_return_val_if_fail (card != NULL, FALSE); - g_return_val_if_fail (E_IS_CARD (card), FALSE); + e_mutex_lock (our_op->mutex); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_commit_card: No URI loaded!\n"); - return FALSE; - } + CORBA_exception_init (&ev); - vcard = e_card_get_vcard_assume_utf8 (card); + corba_book = GNOME_Evolution_Addressbook_BookFactory_getBook (factory, book->priv->uri, + bonobo_object_corba_objref (BONOBO_OBJECT (book->priv->listener)), + &ev); - if (vcard == NULL) { - g_warning ("e_book_commit_card: Error " - "getting VCard for card!\n"); - return FALSE; - } + if (ev._major != CORBA_NO_EXCEPTION) { - retval = e_book_commit_vcard (book, vcard, cb, closure); + e_book_clear_op (book, our_op); - g_free (vcard); + CORBA_exception_free (&ev); + continue; + } - e_card_set_book (card, book); + GNOME_Evolution_Addressbook_Book_open (corba_book, + only_if_exists, + &ev); - return retval; -} + if (ev._major != CORBA_NO_EXCEPTION) { + /* kill the listener so the book will die */ + g_signal_handler_disconnect (book->priv->listener, book->priv->listener_signal); + bonobo_object_unref (book->priv->listener); + book->priv->listener = NULL; -/** - * e_book_commit_vcard: - */ -gboolean -e_book_commit_vcard (EBook *book, - const char *vcard, - EBookCallback cb, - gpointer closure) -{ - CORBA_Environment ev; + e_book_clear_op (book, our_op); - g_return_val_if_fail (book != NULL, FALSE); - g_return_val_if_fail (E_IS_BOOK (book), FALSE); - g_return_val_if_fail (vcard != NULL, FALSE); + CORBA_exception_free (&ev); + continue; + } - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_commit_vcard: No URI loaded!\n"); - return FALSE; - } + CORBA_exception_free (&ev); - CORBA_exception_init (&ev); + /* wait for something to happen (both cancellation and a + successful response will notity us via our cv */ + e_mutex_cond_wait (&our_op->cond, our_op->mutex); - e_book_queue_op (book, cb, closure, NULL); + status = our_op->status; - GNOME_Evolution_Addressbook_Book_modifyCard ( - book->priv->corba_book, (const GNOME_Evolution_Addressbook_VCard) vcard, &ev); + /* remove the op from the book's hash of operations */ + e_book_clear_op (book, our_op); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_commit_vcard: Exception " - "modifying card in PAS!\n"); - CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return FALSE; + if (status == E_BOOK_ERROR_CANCELLED + || status == E_BOOK_ERROR_OK) { + rv = TRUE; + break; + } } - CORBA_exception_free (&ev); + /* free up the factories */ + for (l = factories; l; l = l->next) + CORBA_Object_release ((CORBA_Object)l->data, NULL); - return TRUE; + if (rv == TRUE) { + book->priv->corba_book = corba_book; + book->priv->load_state = E_BOOK_URI_LOADED; + book->priv->comp_listener = e_component_listener_new (book->priv->corba_book); + book->priv->died_signal = g_signal_connect (book->priv->comp_listener, "component_died", + G_CALLBACK (backend_died_cb), book); + return TRUE; + } + else { + g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_PROTOCOL_NOT_SUPPORTED, + _("e_book_load_uri: no factories available for uri `%s'"), uri); + return FALSE; + } + + return rv; } -/** - * e_book_check_connection: - */ gboolean -e_book_check_connection (EBook *book) +e_book_load_local_addressbook (EBook *book, + GError **error) { - CORBA_Environment ev; - - g_return_val_if_fail (book != NULL, FALSE); - g_return_val_if_fail (E_IS_BOOK (book), FALSE); - - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_check_connection: No URI loaded!\n"); - return FALSE; - } - - CORBA_exception_init (&ev); + char *filename; + char *uri; + gboolean rv; - GNOME_Evolution_Addressbook_Book_checkConnection (book->priv->corba_book, &ev); + filename = g_build_filename (g_get_home_dir(), + "evolution/local/Contacts", + NULL); + uri = g_strdup_printf ("file://%s", filename); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_check_connection: Exception " - "querying the PAS!\n"); - CORBA_exception_free (&ev); - return FALSE; - } + g_free (filename); - CORBA_exception_free (&ev); + rv = e_book_load_uri (book, uri, TRUE, error); + + g_free (uri); - return TRUE; + return rv; } -guint -e_book_get_cursor (EBook *book, - gchar *query, - EBookCursorCallback cb, - gpointer closure) +const char * +e_book_get_uri (EBook *book) { - CORBA_Environment ev; - guint tag; - - g_return_val_if_fail (book != NULL, 0); - g_return_val_if_fail (E_IS_BOOK (book), 0); - - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_check_connection: No URI loaded!\n"); - return 0; - } - - CORBA_exception_init (&ev); + return book->priv->uri; +} - tag = e_book_queue_op (book, cb, closure, NULL); - - GNOME_Evolution_Addressbook_Book_getCursor (book->priv->corba_book, query, &ev); +const char * +e_book_get_static_capabilities (EBook *book, + GError **error) +{ + if (!book->priv->cap_queried) { + CORBA_Environment ev; + char *temp; - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_get_all_cards: Exception " - "querying list of cards!\n"); - CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return 0; - } - - CORBA_exception_free (&ev); + CORBA_exception_init (&ev); - return tag; -} + if (book->priv->load_state != E_BOOK_URI_LOADED) { + g_warning ("e_book_unload_uri: No URI is loaded!\n"); + return g_strdup(""); + } -guint -e_book_get_book_view (EBook *book, - const gchar *query, - EBookBookViewCallback cb, - gpointer closure) -{ - CORBA_Environment ev; - EBookViewListener *listener; - guint tag; - - g_return_val_if_fail (book != NULL, 0); - g_return_val_if_fail (E_IS_BOOK (book), 0); + temp = GNOME_Evolution_Addressbook_Book_getStaticCapabilities(book->priv->corba_book, &ev); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_get_book_view: No URI loaded!\n"); - return 0; - } + if (ev._major != CORBA_NO_EXCEPTION) { + g_warning ("e_book_get_static_capabilities: Exception " + "during get_static_capabilities!\n"); + CORBA_exception_free (&ev); + return g_strdup(""); + } - listener = e_book_view_listener_new(); - - CORBA_exception_init (&ev); + book->priv->cap = g_strdup(temp); + book->priv->cap_queried = TRUE; - tag = e_book_queue_op (book, cb, closure, listener); - - GNOME_Evolution_Addressbook_Book_getBookView (book->priv->corba_book, bonobo_object_corba_objref(BONOBO_OBJECT(listener)), query, &ev); + CORBA_free(temp); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_get_book_view: Exception " - "getting book_view!\n"); CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return 0; } - - CORBA_exception_free (&ev); - return tag; + return book->priv->cap; } -guint -e_book_get_completion_view (EBook *book, - const gchar *query, - EBookBookViewCallback cb, - gpointer closure) +gboolean +e_book_check_static_capability (EBook *book, + const char *cap) { - CORBA_Environment ev; - EBookViewListener *listener; - guint tag; - - g_return_val_if_fail (book != NULL, 0); - g_return_val_if_fail (E_IS_BOOK (book), 0); + const char *caps = e_book_get_static_capabilities (book, NULL); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_get_completion_view: No URI loaded!\n"); - return 0; - } + /* XXX this is an inexact test but it works for our use */ + if (caps && strstr (caps, cap)) + return TRUE; - listener = e_book_view_listener_new(); - - CORBA_exception_init (&ev); + return FALSE; +} - tag = e_book_queue_op (book, cb, closure, listener); - - GNOME_Evolution_Addressbook_Book_getCompletionView (book->priv->corba_book, - bonobo_object_corba_objref(BONOBO_OBJECT(listener)), - query, &ev); +gboolean +e_book_is_writable (EBook *book) +{ + return book->priv->writable; +} - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_get_completion_view: Exception " - "getting completion_view!\n"); - CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return 0; - } - - CORBA_exception_free (&ev); - return tag; -} + -guint -e_book_get_changes (EBook *book, - gchar *changeid, - EBookBookViewCallback cb, - gpointer closure) +gboolean +e_book_get_self (EContact **contact, EBook **book, GError **error) { - CORBA_Environment ev; - EBookViewListener *listener; - guint tag; - - g_return_val_if_fail (book != NULL, 0); - g_return_val_if_fail (E_IS_BOOK (book), 0); + GError *e = NULL; - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_get_changes: No URI loaded!\n"); + if (!e_book_get_default_addressbook (book, &e)) { + g_propagate_error (error, e); return FALSE; } - listener = e_book_view_listener_new(); - - CORBA_exception_init (&ev); +#if notyet + EBook *b; + char *self_uri, *self_uid; - tag = e_book_queue_op (book, cb, closure, listener); - - GNOME_Evolution_Addressbook_Book_getChanges (book->priv->corba_book, bonobo_object_corba_objref(BONOBO_OBJECT(listener)), changeid, &ev); + /* XXX get the setting for the self book and self uid from gconf */ - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_changes: Exception " - "getting changes!\n"); - CORBA_exception_free (&ev); - e_book_unqueue_op (book); - return 0; + b = e_book_new(); + if (! e_book_load_uri (b, self_uri, TRUE, error)) { + g_object_unref (b); + return FALSE; } - - CORBA_exception_free (&ev); - return tag; -} + if (! e_book_get_contact (b, self_uid, + contact, error)) { + g_object_unref (b); + return FALSE; + } -/** - * e_book_cancel - */ + if (book) + *book = b; + else + g_object_unref (b); + return TRUE; +#endif +} -void -e_book_cancel (EBook *book, guint tag) +gboolean +e_book_set_self (EBook *book, const char *id, GError **error) { - g_return_if_fail (book != NULL); - g_return_if_fail (E_IS_BOOK (book)); - g_return_if_fail (tag != 0); - - /* In an attempt to be useful, we take a bit of extra care in reporting - errors. This might come in handy someday. */ - if (tag >= book->priv->op_tag) - g_warning ("Attempt to cancel unassigned operation (%u)", tag); - else if (! e_book_cancel_op (book, tag)) - g_warning ("Attempt to cancel unknown operation (%u)", tag); } -/** - * e_book_get_name: - */ -char * -e_book_get_name (EBook *book) + + +gboolean +e_book_get_default_addressbook (EBook **book, GError **error) { - CORBA_Environment ev; - char *retval; - char *name; + /* XXX for now just load the local ~/evolution/local/Contacts */ + char *path, *uri; + gboolean rv; - g_return_val_if_fail (book != NULL, NULL); - g_return_val_if_fail (E_IS_BOOK (book), NULL); + *book = e_book_new (); - if (book->priv->load_state != URILoaded) { - g_warning ("e_book_get_name: No URI loaded!\n"); - return NULL; - } + path = g_build_filename (g_get_home_dir (), + "evolution/local/Contacts", + NULL); + uri = g_strdup_printf ("file://%s", path); + g_free (path); - CORBA_exception_init (&ev); + rv = e_book_load_uri (*book, uri, FALSE, error); - name = GNOME_Evolution_Addressbook_Book_getName (book->priv->corba_book, &ev); + g_free (uri); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("e_book_get_name: Exception getting name from PAS!\n"); - CORBA_exception_free (&ev); - return NULL; + if (!rv) { + g_object_unref (*book); + *book = NULL; } - CORBA_exception_free (&ev); + return rv; +#if notyet + EConfigListener *listener = e_config_listener_new (); + ESourceList *sources = ...; + ESource *default_source; + + default_source = e_source_list_peek_source_by_uid (sources, + "default_"); +#endif +} - if (name == NULL) { - g_warning ("e_book_get_name: Got NULL name from PAS!\n"); - return NULL; +#if notyet +ESourceList* +e_book_get_addressbooks (GError **error) +{ +} +#endif + + +static void* +startup_mainloop (void *arg) +{ + bonobo_main(); + return NULL; +} + +/* one-time start up for libebook */ +static void +e_book_activate() +{ + static GStaticMutex e_book_lock = G_STATIC_MUTEX_INIT; + static gboolean activated = FALSE; + + g_static_mutex_lock (&e_book_lock); + if (!activated) { + pthread_t ebook_mainloop_thread; + activated = TRUE; + pthread_create(&ebook_mainloop_thread, NULL, startup_mainloop, NULL); } + g_static_mutex_unlock (&e_book_lock); +} - retval = g_strdup (name); - CORBA_free (name); + - return retval; +EBook* +e_book_new (void) +{ + e_book_activate (); + return g_object_new (E_TYPE_BOOK, NULL); } + static void e_book_init (EBook *book) { book->priv = g_new0 (EBookPrivate, 1); - book->priv->load_state = URINotLoaded; - book->priv->op_tag = 1; + book->priv->load_state = E_BOOK_URI_NOT_LOADED; book->priv->uri = NULL; + book->priv->mutex = e_mutex_new (E_MUTEX_REC); } static void @@ -1598,8 +1967,8 @@ e_book_dispose (GObject *object) book->priv->comp_listener = NULL; } - if (book->priv->load_state == URILoaded) - e_book_unload_uri (book); + if (book->priv->load_state == E_BOOK_URI_LOADED) + e_book_unload_uri (book, NULL); CORBA_exception_init (&ev); @@ -1640,16 +2009,6 @@ e_book_class_init (EBookClass *klass) parent_class = g_type_class_ref (G_TYPE_OBJECT); - e_book_signals [LINK_STATUS] = - g_signal_new ("link_status", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EBookClass, link_status), - NULL, NULL, - e_book_marshal_NONE__BOOL, - G_TYPE_NONE, 1, - G_TYPE_BOOLEAN); - e_book_signals [WRITABLE_STATUS] = g_signal_new ("writable_status", G_OBJECT_CLASS_TYPE (object_class), diff --git a/addressbook/backend/ebook/e-book.h b/addressbook/backend/ebook/e-book.h index d2c5a7bce4..1d2a4dc2d4 100644 --- a/addressbook/backend/ebook/e-book.h +++ b/addressbook/backend/ebook/e-book.h @@ -3,9 +3,9 @@ * The Evolution addressbook client object. * * Author: - * Nat Friedman (nat@ximian.com) + * Chris Toshok (toshok@ximian.com) * - * Copyright 1999, 2000, Ximian, Inc. + * Copyright (C) 1999-2003, Ximian, Inc. */ #ifndef __E_BOOK_H__ @@ -14,10 +14,13 @@ #include #include -#include -#include +#include +#include #include #include +#if notyet +#include +#endif #define E_TYPE_BOOK (e_book_get_type ()) #define E_BOOK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK, EBook)) @@ -43,127 +46,120 @@ struct _EBookClass { /* * Signals. */ - void (* open_progress) (EBook *book, const char *msg, short percent); - void (* link_status) (EBook *book, gboolean connected); void (* writable_status) (EBook *book, gboolean writable); void (* backend_died) (EBook *book); -}; -/* Callbacks for asynchronous functions. */ -typedef void (*EBookCallback) (EBook *book, EBookStatus status, gpointer closure); -typedef void (*EBookOpenProgressCallback) (EBook *book, - const char *status_message, - short percent, - gpointer closure); -typedef void (*EBookIdCallback) (EBook *book, EBookStatus status, const char *id, gpointer closure); -typedef void (*EBookCardCallback) (EBook *book, EBookStatus status, ECard *card, gpointer closure); -typedef void (*EBookCursorCallback) (EBook *book, EBookStatus status, ECardCursor *cursor, gpointer closure); -typedef void (*EBookBookViewCallback) (EBook *book, EBookStatus status, EBookView *book_view, gpointer closure); -typedef void (*EBookFieldsCallback) (EBook *book, EBookStatus status, EList *fields, gpointer closure); -typedef void (*EBookAuthMethodsCallback) (EBook *book, EBookStatus status, EList *auth_methods, gpointer closure); + /* Padding for future expansion */ + void (*_ebook_reserved0) (void); + void (*_ebook_reserved1) (void); + void (*_ebook_reserved2) (void); + void (*_ebook_reserved3) (void); + void (*_ebook_reserved4) (void); +}; /* Creating a new addressbook. */ -EBook *e_book_new (void); +EBook *e_book_new (void); + +/* loading arbitrary addressbooks */ +gboolean e_book_load_uri (EBook *book, + const char *uri, + gboolean only_if_exists, + GError **error); -void e_book_load_uri (EBook *book, - const char *uri, - EBookCallback open_response, - gpointer closure); -void e_book_unload_uri (EBook *book); +gboolean e_book_unload_uri (EBook *book, + GError **error); -const char *e_book_get_uri (EBook *book); +gboolean e_book_remove (EBook *book, + GError **error); -char *e_book_get_static_capabilities (EBook *book); -gboolean e_book_check_static_capability (EBook *book, const char *cap); +/* convenience function for loading the "local" contact folder */ +gboolean e_book_load_local_addressbook (EBook *book, + GError **error); -guint e_book_get_supported_fields (EBook *book, - EBookFieldsCallback cb, - gpointer closure); +gboolean e_book_get_supported_fields (EBook *book, + GList **fields, + GError **error); -guint e_book_get_supported_auth_methods (EBook *book, - EBookAuthMethodsCallback cb, - gpointer closure); +gboolean e_book_get_supported_auth_methods (EBook *book, + GList **auth_methods, + GError **error); /* User authentication. */ -void e_book_authenticate_user (EBook *book, - const char *user, - const char *passwd, - const char *auth_method, - EBookCallback cb, - gpointer closure); - -/* Fetching cards. */ -guint e_book_get_card (EBook *book, - const char *id, - EBookCardCallback cb, - gpointer closure); - -/* Deleting cards. */ -gboolean e_book_remove_card (EBook *book, - ECard *card, - EBookCallback cb, - gpointer closure); -gboolean e_book_remove_card_by_id (EBook *book, - const char *id, - EBookCallback cb, - gpointer closure); - -gboolean e_book_remove_cards (EBook *book, - GList *id_list, - EBookCallback cb, - gpointer closure); - -/* Adding cards. */ -gboolean e_book_add_card (EBook *book, - ECard *card, - EBookIdCallback cb, - gpointer closure); -gboolean e_book_add_vcard (EBook *book, - const char *vcard, - EBookIdCallback cb, - gpointer closure); - -/* Modifying cards. */ -gboolean e_book_commit_card (EBook *book, - ECard *card, - EBookCallback cb, - gpointer closure); -gboolean e_book_commit_vcard (EBook *book, - const char *vcard, - EBookCallback cb, - gpointer closure); - -/* Checking to see if we're connected to the card repository. */ -gboolean e_book_check_connection (EBook *book); -guint e_book_get_cursor (EBook *book, - char *query, - EBookCursorCallback cb, - gpointer closure); - -guint e_book_get_book_view (EBook *book, - const gchar *query, - EBookBookViewCallback cb, - gpointer closure); - -guint e_book_get_completion_view (EBook *book, - const gchar *query, - EBookBookViewCallback cb, - gpointer closure); - -guint e_book_get_changes (EBook *book, - char *changeid, - EBookBookViewCallback cb, - gpointer closure); +gboolean e_book_authenticate_user (EBook *book, + const char *user, + const char *passwd, + const char *auth_method, + GError **error); + +/* Fetching contacts. */ +gboolean e_book_get_contact (EBook *book, + const char *id, + EContact **contact, + GError **error); + +/* Deleting contacts. */ +gboolean e_book_remove_contact (EBook *book, + const char *id, + GError **error); + +gboolean e_book_remove_contacts (EBook *book, + GList *id_list, + GError **error); + +/* Adding contacts. */ +gboolean e_book_add_contact (EBook *book, + EContact *contact, + GError **error); + +/* Modifying contacts. */ +gboolean e_book_commit_contact (EBook *book, + EContact *contact, + GError **error); + +/* Returns a live view of a query. */ +gboolean e_book_get_book_view (EBook *book, + EBookQuery *query, + GList *requested_fields, + int max_results, + EBookView **book_view, + GError **error); + +/* Returns a static snapshot of a query. */ +gboolean e_book_get_contacts (EBook *book, + EBookQuery *query, + GList **contacts, + GError **error); + +gboolean e_book_get_changes (EBook *book, + char *changeid, + GList **changes, + GError **error); + +void e_book_free_change_list (GList *change_list); + +const char *e_book_get_uri (EBook *book); + +const char *e_book_get_static_capabilities (EBook *book, + GError **error); +gboolean e_book_check_static_capability (EBook *book, + const char *cap); +gboolean e_book_is_writable (EBook *book); /* Cancel a pending operation. */ -void e_book_cancel (EBook *book, - guint tag); +gboolean e_book_cancel (EBook *book, + GError **error); +/* Identity */ +gboolean e_book_get_self (EContact **contact, EBook **book, GError **error); +gboolean e_book_set_self (EBook *book, const char *id, GError **error); -/* Getting the name of the repository. */ -char *e_book_get_name (EBook *book); +/* Addressbook Discovery */ +gboolean e_book_get_default_addressbook (EBook **book, GError **error); +#if notyet +gboolean e_book_get_addressbooks (ESourceList** addressbook_sources, GError **error); +#endif -GType e_book_get_type (void); +GType e_book_get_type (void); G_END_DECLS diff --git a/addressbook/backend/ebook/e-card-compare.c b/addressbook/backend/ebook/e-card-compare.c deleted file mode 100644 index 2413d987e5..0000000000 --- a/addressbook/backend/ebook/e-card-compare.c +++ /dev/null @@ -1,706 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* - * e-card-compare.c - * - * Copyright (C) 2001 Ximian, Inc. - * - * Developed by Jon Trowbridge - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - */ - -#include -#include -#include -#include "e-book-util.h" -#include "e-card-compare.h" - -/* This is an "optimistic" combiner: the best of the two outcomes is - selected. */ -static ECardMatchType -combine_comparisons (ECardMatchType prev, - ECardMatchType new_info) -{ - if (new_info == E_CARD_MATCH_NOT_APPLICABLE) - return prev; - return (ECardMatchType) MAX ((gint) prev, (gint) new_info); -} - - -/*** Name comparisons ***/ - -/* This *so* doesn't belong here... at least not implemented in a - sucky way like this. But it can be fixed later. */ - -/* This is very Anglocentric. */ -static gchar *name_synonyms[][2] = { - { "jon", "john" }, /* Ah, the hacker's perogative */ - { "joseph", "joe" }, - { "robert", "bob" }, - { "gene", "jean" }, - { "jesse", "jessie" }, - { "ian", "iain" }, - { "richard", "dick" }, - { "william", "bill" }, - { "william", "will" }, - { "anthony", "tony" }, - { "michael", "mike" }, - { "eric", "erik" }, - { "elizabeth", "liz" }, - { "jeff", "geoff" }, - { "jeff", "geoffrey" }, - { "tom", "thomas" }, - { "dave", "david" }, - { "jim", "james" }, - { "abigal", "abby" }, - { "amanda", "amy" }, - { "amanda", "manda" }, - { "jennifer", "jenny" }, - { "christopher", "chris" }, - { "rebecca", "becca" }, - { "rebecca", "becky" }, - { "anderson", "andersen" }, - { "johnson", "johnsen" }, - /* We could go on and on... */ - /* We should add soundex here. */ - { NULL, NULL } -}; - -static gboolean -name_fragment_match (const gchar *a, const gchar *b, gboolean strict) -{ - gint len; - - if (!(a && b && *a && *b)) - return FALSE; - - /* If we are in 'strict' mode, b must match the beginning of a. - So "Robert", "Rob" would match, but "Robert", "Robbie" wouldn't. - - If strict is FALSE, it is sufficient for the strings to share - some leading characters. In this case, "Robert" and "Robbie" - would match, as would "Dave" and "Dan". */ - - if (strict) { - len = g_utf8_strlen (b, -1); - } else { - len = MIN (g_utf8_strlen (a, -1), g_utf8_strlen (b, -1)); - } - - return !e_utf8_casefold_collate_len (a, b, len); -} - -static gboolean -name_fragment_match_with_synonyms (const gchar *a, const gchar *b, gboolean strict) -{ - gint i; - - if (!(a && b && *a && *b)) - return FALSE; - - if (name_fragment_match (a, b, strict)) - return TRUE; - - /* Check for nicknames. Yes, the linear search blows. */ - for (i=0; name_synonyms[i][0]; ++i) { - - if (!e_utf8_casefold_collate (name_synonyms[i][0], a) - && !e_utf8_casefold_collate (name_synonyms[i][1], b)) - return TRUE; - - if (!e_utf8_casefold_collate (name_synonyms[i][0], b) - && !e_utf8_casefold_collate (name_synonyms[i][1], a)) - return TRUE; - } - - return FALSE; -} - -ECardMatchType -e_card_compare_name_to_string (ECard *card, const gchar *str) -{ - return e_card_compare_name_to_string_full (card, str, FALSE, NULL, NULL, NULL); -} - -ECardMatchType -e_card_compare_name_to_string_full (ECard *card, const gchar *str, gboolean allow_partial_matches, - gint *matched_parts_out, ECardMatchPart *first_matched_part_out, gint *matched_character_count_out) -{ - gchar **namev, **givenv = NULL, **addv = NULL, **familyv = NULL; - - gint matched_parts = E_CARD_MATCH_PART_NONE; - ECardMatchPart first_matched_part = E_CARD_MATCH_PART_NONE; - ECardMatchPart this_part_match = E_CARD_MATCH_PART_NOT_APPLICABLE; - ECardMatchType match_type; - - gint match_count = 0, matched_character_count = 0, fragment_count; - gint i, j; - gchar *str_cpy, *s; - - g_return_val_if_fail (E_IS_CARD (card), E_CARD_MATCH_NOT_APPLICABLE); - g_return_val_if_fail (card->name != NULL, E_CARD_MATCH_NOT_APPLICABLE); - g_return_val_if_fail (str != NULL, E_CARD_MATCH_NOT_APPLICABLE); - - str_cpy = s = g_strdup (str); - while (*s) { - if (*s == ',' || *s == '"') - *s = ' '; - ++s; - } - namev = g_strsplit (str_cpy, " ", 0); - g_free (str_cpy); - - if (card->name->given) - givenv = g_strsplit (card->name->given, " ", 0); - if (card->name->additional) - addv = g_strsplit (card->name->additional, " ", 0); - if (card->name->family) - familyv = g_strsplit (card->name->family, " ", 0); - - fragment_count = 0; - for (i = 0; givenv && givenv[i]; ++i) - ++fragment_count; - for (i = 0; addv && addv[i]; ++i) - ++fragment_count; - for (i = 0; familyv && familyv[i]; ++i) - ++fragment_count; - - for (i = 0; namev[i] && this_part_match != E_CARD_MATCH_PART_NONE; ++i) { - - if (*namev[i]) { - - this_part_match = E_CARD_MATCH_PART_NONE; - - /* When we are allowing partials, we are strict about the matches we allow. - Does this make sense? Not really, but it does the right thing for the purposes - of completion. */ - - if (givenv && this_part_match == E_CARD_MATCH_PART_NONE) { - for (j = 0; givenv[j]; ++j) { - if (name_fragment_match_with_synonyms (givenv[j], namev[i], allow_partial_matches)) { - - this_part_match = E_CARD_MATCH_PART_GIVEN_NAME; - - /* We remove a piece of a name once it has been matched against, so - that "john john" won't match "john doe". */ - g_free (givenv[j]); - givenv[j] = g_strdup (""); - break; - } - } - } - - if (addv && this_part_match == E_CARD_MATCH_PART_NONE) { - for (j = 0; addv[j]; ++j) { - if (name_fragment_match_with_synonyms (addv[j], namev[i], allow_partial_matches)) { - - this_part_match = E_CARD_MATCH_PART_ADDITIONAL_NAME; - - g_free (addv[j]); - addv[j] = g_strdup (""); - break; - } - } - } - - if (familyv && this_part_match == E_CARD_MATCH_PART_NONE) { - for (j = 0; familyv[j]; ++j) { - if (allow_partial_matches ? name_fragment_match_with_synonyms (familyv[j], namev[i], allow_partial_matches) - : !e_utf8_casefold_collate (familyv[j], namev[i])) { - - this_part_match = E_CARD_MATCH_PART_FAMILY_NAME; - - g_free (familyv[j]); - familyv[j] = g_strdup (""); - break; - } - } - } - - if (this_part_match != E_CARD_MATCH_PART_NONE) { - ++match_count; - matched_character_count += g_utf8_strlen (namev[i], -1); - matched_parts |= this_part_match; - if (first_matched_part == E_CARD_MATCH_PART_NONE) - first_matched_part = this_part_match; - } - } - } - - match_type = E_CARD_MATCH_NONE; - - if (this_part_match != E_CARD_MATCH_PART_NONE) { - - if (match_count > 0) - match_type = E_CARD_MATCH_VAGUE; - - if (fragment_count == match_count) { - - match_type = E_CARD_MATCH_EXACT; - - } else if (fragment_count == match_count + 1) { - - match_type = E_CARD_MATCH_PARTIAL; - - } - } - - if (matched_parts_out) - *matched_parts_out = matched_parts; - if (first_matched_part_out) - *first_matched_part_out = first_matched_part; - if (matched_character_count_out) - *matched_character_count_out = matched_character_count; - - g_strfreev (namev); - g_strfreev (givenv); - g_strfreev (addv); - g_strfreev (familyv); - - return match_type; -} - -ECardMatchType -e_card_compare_name (ECard *card1, ECard *card2) -{ - ECardName *a, *b; - gint matches=0, possible=0; - gboolean given_match = FALSE, additional_match = FALSE, family_match = FALSE; - - g_return_val_if_fail (E_IS_CARD (card1), E_CARD_MATCH_NOT_APPLICABLE); - g_return_val_if_fail (E_IS_CARD (card2), E_CARD_MATCH_NOT_APPLICABLE); - - a = card1->name; - b = card2->name; - - if (a == NULL || b == NULL) - return E_CARD_MATCH_NOT_APPLICABLE; - - if (a->given && b->given) { - ++possible; - if (name_fragment_match_with_synonyms (a->given, b->given, FALSE /* both inputs are complete */)) { - ++matches; - given_match = TRUE; - } - } - - if (a->additional && b->additional) { - ++possible; - if (name_fragment_match_with_synonyms (a->additional, b->additional, FALSE /* both inputs are complete */)) { - ++matches; - additional_match = TRUE; - } - } - - if (a->family && b->family) { - ++possible; - /* We don't allow "loose matching" (i.e. John vs. Jon) on family names */ - if (! e_utf8_casefold_collate (a->family, b->family)) { - ++matches; - family_match = TRUE; - } - } - - /* Now look at the # of matches and try to intelligently map - an E_CARD_MATCH_* type to it. Special consideration is given - to family-name matches. */ - - if (possible == 0) - return E_CARD_MATCH_NOT_APPLICABLE; - - if (possible == 1) - return family_match ? E_CARD_MATCH_VAGUE : E_CARD_MATCH_NONE; - - if (possible == matches) - return family_match ? E_CARD_MATCH_EXACT : E_CARD_MATCH_PARTIAL; - - if (possible == matches+1) - return family_match ? E_CARD_MATCH_VAGUE : E_CARD_MATCH_NONE; - - return E_CARD_MATCH_NONE; -} - - -/*** Nickname Comparisons ***/ - -ECardMatchType -e_card_compare_nickname (ECard *card1, ECard *card2) -{ - g_return_val_if_fail (card1 && E_IS_CARD (card1), E_CARD_MATCH_NOT_APPLICABLE); - g_return_val_if_fail (card2 && E_IS_CARD (card2), E_CARD_MATCH_NOT_APPLICABLE); - - return E_CARD_MATCH_NOT_APPLICABLE; -} - - - -/*** E-mail Comparisons ***/ - -static gboolean -match_email_username (const gchar *addr1, const gchar *addr2) -{ - gint c1, c2; - if (addr1 == NULL || addr2 == NULL) - return FALSE; - - while (*addr1 && *addr2 && *addr1 != '@' && *addr2 != '@') { - c1 = isupper (*addr1) ? tolower (*addr1) : *addr1; - c2 = isupper (*addr2) ? tolower (*addr2) : *addr2; - if (c1 != c2) - return FALSE; - ++addr1; - ++addr2; - } - - return *addr1 == *addr2; -} - -static gboolean -match_email_hostname (const gchar *addr1, const gchar *addr2) -{ - gint c1, c2; - gboolean seen_at1, seen_at2; - if (addr1 == NULL || addr2 == NULL) - return FALSE; - - /* Walk to the end of each string. */ - seen_at1 = FALSE; - if (*addr1) { - while (*addr1) { - if (*addr1 == '@') - seen_at1 = TRUE; - ++addr1; - } - --addr1; - } - - seen_at2 = FALSE; - if (*addr2) { - while (*addr2) { - if (*addr2 == '@') - seen_at2 = TRUE; - ++addr2; - } - --addr2; - } - - if (!seen_at1 && !seen_at2) - return TRUE; - if (!seen_at1 || !seen_at2) - return FALSE; - - while (*addr1 != '@' && *addr2 != '@') { - c1 = isupper (*addr1) ? tolower (*addr1) : *addr1; - c2 = isupper (*addr2) ? tolower (*addr2) : *addr2; - if (c1 != c2) - return FALSE; - --addr1; - --addr2; - } - - /* This will match bob@foo.ximian.com and bob@ximian.com */ - return *addr1 == '.' || *addr2 == '.'; -} - -static ECardMatchType -compare_email_addresses (const gchar *addr1, const gchar *addr2) -{ - if (addr1 == NULL || *addr1 == 0 || - addr2 == NULL || *addr2 == 0) - return E_CARD_MATCH_NOT_APPLICABLE; - - if (match_email_username (addr1, addr2)) - return match_email_hostname (addr1, addr2) ? E_CARD_MATCH_EXACT : E_CARD_MATCH_VAGUE; - - return E_CARD_MATCH_NONE; -} - -ECardMatchType -e_card_compare_email (ECard *card1, ECard *card2) -{ - EIterator *i1, *i2; - ECardMatchType match = E_CARD_MATCH_NOT_APPLICABLE; - - g_return_val_if_fail (card1 && E_IS_CARD (card1), E_CARD_MATCH_NOT_APPLICABLE); - g_return_val_if_fail (card2 && E_IS_CARD (card2), E_CARD_MATCH_NOT_APPLICABLE); - - if (card1->email == NULL || card2->email == NULL) - return E_CARD_MATCH_NOT_APPLICABLE; - - i1 = e_list_get_iterator (card1->email); - i2 = e_list_get_iterator (card2->email); - - /* Do pairwise-comparisons on all of the e-mail addresses. If - we find an exact match, there is no reason to keep - checking. */ - e_iterator_reset (i1); - while (e_iterator_is_valid (i1) && match != E_CARD_MATCH_EXACT) { - const gchar *addr1 = (const gchar *) e_iterator_get (i1); - - e_iterator_reset (i2); - while (e_iterator_is_valid (i2) && match != E_CARD_MATCH_EXACT) { - const gchar *addr2 = (const gchar *) e_iterator_get (i2); - - match = combine_comparisons (match, compare_email_addresses (addr1, addr2)); - - e_iterator_next (i2); - } - - e_iterator_next (i1); - } - - g_object_unref (i1); - g_object_unref (i2); - - return match; -} - -ECardMatchType -e_card_compare_address (ECard *card1, ECard *card2) -{ - g_return_val_if_fail (card1 && E_IS_CARD (card1), E_CARD_MATCH_NOT_APPLICABLE); - g_return_val_if_fail (card2 && E_IS_CARD (card2), E_CARD_MATCH_NOT_APPLICABLE); - - /* Unimplemented */ - - return E_CARD_MATCH_NOT_APPLICABLE; -} - -ECardMatchType -e_card_compare_telephone (ECard *card1, ECard *card2) -{ - g_return_val_if_fail (card1 && E_IS_CARD (card1), E_CARD_MATCH_NOT_APPLICABLE); - g_return_val_if_fail (card2 && E_IS_CARD (card2), E_CARD_MATCH_NOT_APPLICABLE); - - /* Unimplemented */ - - return E_CARD_MATCH_NOT_APPLICABLE; -} - -ECardMatchType -e_card_compare (ECard *card1, ECard *card2) -{ - ECardMatchType result; - - g_return_val_if_fail (card1 && E_IS_CARD (card1), E_CARD_MATCH_NOT_APPLICABLE); - g_return_val_if_fail (card2 && E_IS_CARD (card2), E_CARD_MATCH_NOT_APPLICABLE); - - result = E_CARD_MATCH_NONE; - result = combine_comparisons (result, e_card_compare_name (card1, card2)); - result = combine_comparisons (result, e_card_compare_nickname (card1, card2)); - result = combine_comparisons (result, e_card_compare_email (card1, card2)); - result = combine_comparisons (result, e_card_compare_address (card1, card2)); - result = combine_comparisons (result, e_card_compare_telephone (card1, card2)); - - return result; -} - -typedef struct _MatchSearchInfo MatchSearchInfo; -struct _MatchSearchInfo { - ECard *card; - GList *avoid; - ECardMatchQueryCallback cb; - gpointer closure; -}; - -static void -match_search_info_free (MatchSearchInfo *info) -{ - if (info) { - g_object_unref (info->card); - - /* This should already have been deallocated, but just in case... */ - if (info->avoid) { - g_list_foreach (info->avoid, (GFunc) g_object_unref, NULL); - g_list_free (info->avoid); - info->avoid = NULL; - } - - g_free (info); - } -} - -static void -simple_query_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure) -{ - MatchSearchInfo *info = (MatchSearchInfo *) closure; - ECardMatchType best_match = E_CARD_MATCH_NONE; - ECard *best_card = NULL; - GList *remaining_cards = NULL; - const GList *i; - - if (status != E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS) { - info->cb (info->card, NULL, E_CARD_MATCH_NONE, info->closure); - match_search_info_free (info); - return; - } - - /* remove the cards we're to avoid from the list, if they're present */ - for (i = cards; i != NULL; i = g_list_next (i)) { - ECard *this_card = E_CARD (i->data); - GList *iterator; - gboolean avoid = FALSE; - for (iterator = info->avoid; iterator; iterator = iterator->next) { - if (!strcmp (e_card_get_id (iterator->data), e_card_get_id (this_card))) { - avoid = TRUE; - break; - } - } - if (!avoid) - remaining_cards = g_list_prepend (remaining_cards, this_card); - } - - remaining_cards = g_list_reverse (remaining_cards); - - for (i = remaining_cards; i != NULL; i = g_list_next (i)) { - ECard *this_card = E_CARD (i->data); - ECardMatchType this_match = e_card_compare (info->card, this_card); - if ((gint)this_match > (gint)best_match) { - best_match = this_match; - best_card = this_card; - } - } - - g_list_free (remaining_cards); - - info->cb (info->card, best_card, best_match, info->closure); - match_search_info_free (info); -} - -#define MAX_QUERY_PARTS 10 -static void -use_common_book_cb (EBook *book, gpointer closure) -{ - MatchSearchInfo *info = (MatchSearchInfo *) closure; - ECard *card = info->card; - gchar *query_parts[MAX_QUERY_PARTS]; - gint p=0; - gchar *query, *qj; - int i; - - if (book == NULL) { - info->cb (info->card, NULL, E_CARD_MATCH_NONE, info->closure); - match_search_info_free (info); - return; - } - -#if 0 - if (card->nickname && *card->nickname) - query_parts[p++] = g_strdup_printf ("(beginswith \"nickname\" \"%s\")", card->nickname); -#endif - - if (card->name->given && strlen (card->name->given) > 1) - query_parts[p++] = g_strdup_printf ("(contains \"full_name\" \"%s\")", card->name->given); - - if (card->name->additional && strlen (card->name->additional) > 1) - query_parts[p++] = g_strdup_printf ("(contains \"full_name\" \"%s\")", card->name->additional); - - if (card->name->family && strlen (card->name->family) > 1) - query_parts[p++] = g_strdup_printf ("(contains \"full_name\" \"%s\")", card->name->family); - - - if (card->email) { - EIterator *iter = e_list_get_iterator (card->email); - while (e_iterator_is_valid (iter) && p < MAX_QUERY_PARTS) { - gchar *addr = g_strdup (e_iterator_get (iter)); - if (addr && *addr) { - gchar *s = addr; - while (*s) { - if (*s == '@') { - *s = '\0'; - break; - } - ++s; - } - query_parts[p++] = g_strdup_printf ("(beginswith \"email\" \"%s\")", addr); - g_free (addr); - } - e_iterator_next (iter); - } - } - - - - /* Build up our full query from the parts. */ - query_parts[p] = NULL; - qj = g_strjoinv (" ", query_parts); - for(i = 0; query_parts[i] != NULL; i++) - g_free(query_parts[i]); - if (p > 0) { - query = g_strdup_printf ("(or %s)", qj); - g_free (qj); - } else { - query = qj; - } - - e_book_simple_query (book, query, simple_query_cb, info); - - g_free (query); -} - -void -e_card_locate_match (ECard *card, ECardMatchQueryCallback cb, gpointer closure) -{ - MatchSearchInfo *info; - - g_return_if_fail (card && E_IS_CARD (card)); - g_return_if_fail (cb != NULL); - - info = g_new (MatchSearchInfo, 1); - info->card = card; - g_object_ref (card); - info->cb = cb; - info->closure = closure; - info->avoid = NULL; - - e_book_use_default_book (use_common_book_cb, info); -} - -/** - * e_card_locate_match_full: - * @book: The book to look in. If this is NULL, use the default - * addressbook. - * @card: The card to compare to. - * @avoid: A list of cards to not match. These will not show up in the search. - * @cb: The function to call. - * @closure: The closure to add to the call. - * - * Look for the best match and return it using the ECardMatchQueryCallback. - **/ -void -e_card_locate_match_full (EBook *book, ECard *card, GList *avoid, ECardMatchQueryCallback cb, gpointer closure) -{ - MatchSearchInfo *info; - - g_return_if_fail (card && E_IS_CARD (card)); - g_return_if_fail (cb != NULL); - - info = g_new (MatchSearchInfo, 1); - info->card = card; - g_object_ref (card); - info->cb = cb; - info->closure = closure; - info->avoid = g_list_copy (avoid); - g_list_foreach (info->avoid, (GFunc) g_object_ref, NULL); - - if (book) - use_common_book_cb (book, info); - else - e_book_use_default_book (use_common_book_cb, info); -} - diff --git a/addressbook/backend/ebook/e-card-compare.h b/addressbook/backend/ebook/e-card-compare.h deleted file mode 100644 index 07ccb54e89..0000000000 --- a/addressbook/backend/ebook/e-card-compare.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* - * e-card-compare.h - * - * Copyright (C) 2001 Ximian, Inc. - * - * Developed by Jon Trowbridge - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - */ - -#ifndef __E_CARD_COMPARE_H__ -#define __E_CARD_COMPARE_H__ - -#include "e-book.h" -#include "e-card.h" - -typedef enum { - E_CARD_MATCH_NOT_APPLICABLE = 0, - E_CARD_MATCH_NONE = 1, - E_CARD_MATCH_VAGUE = 2, - E_CARD_MATCH_PARTIAL = 3, - E_CARD_MATCH_EXACT = 4 -} ECardMatchType; - -typedef enum { - E_CARD_MATCH_PART_NOT_APPLICABLE = -1, - E_CARD_MATCH_PART_NONE = 0, - E_CARD_MATCH_PART_GIVEN_NAME = 1<<0, - E_CARD_MATCH_PART_ADDITIONAL_NAME = 1<<2, - E_CARD_MATCH_PART_FAMILY_NAME = 1<<3 -} ECardMatchPart; - -typedef void (*ECardMatchQueryCallback) (ECard *card, ECard *match, ECardMatchType type, gpointer closure); - -ECardMatchType e_card_compare_name_to_string (ECard *card, const gchar *str); - -ECardMatchType e_card_compare_name_to_string_full (ECard *card, const gchar *str, - gboolean allow_partial_matches, - gint *matched_parts, ECardMatchPart *first_matched_part, - gint *matched_character_count); - -ECardMatchType e_card_compare_name (ECard *card1, ECard *card2); -ECardMatchType e_card_compare_nickname (ECard *card1, ECard *card2); -ECardMatchType e_card_compare_email (ECard *card1, ECard *card2); -ECardMatchType e_card_compare_address (ECard *card1, ECard *card2); -ECardMatchType e_card_compare_telephone (ECard *card1, ECard *card2); - -ECardMatchType e_card_compare (ECard *card1, ECard *card2); - -void e_card_locate_match (ECard *card, ECardMatchQueryCallback cb, gpointer closure); -void e_card_locate_match_full (EBook *book, ECard *card, GList *avoid, ECardMatchQueryCallback cb, gpointer closure); - - - -#endif /* __E_CARD_COMPARE_H__ */ - diff --git a/addressbook/backend/ebook/e-card-cursor.c b/addressbook/backend/ebook/e-card-cursor.c deleted file mode 100644 index 0aa9c8c1e0..0000000000 --- a/addressbook/backend/ebook/e-card-cursor.c +++ /dev/null @@ -1,239 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * e-card-cursor.c: Implements card cursors. - * - * Author: - * Christopher James Lahey -#include "addressbook.h" -#include "e-card-cursor.h" - -struct _ECardCursorPrivate { - GNOME_Evolution_Addressbook_CardCursor corba_cursor; -}; - -/* - * A pointer to our parent object class - */ -static GObjectClass *parent_class; - -/* - * Implemented GObject::dispose - */ -static void -e_card_cursor_dispose (GObject *object) -{ - ECardCursor *cursor = E_CARD_CURSOR (object); - - if (cursor->priv) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - - GNOME_Evolution_Addressbook_CardCursor_unref( cursor->priv->corba_cursor, &ev ); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning("e_card_cursor_destroy: Exception unreffing " - "corba cursor.\n"); - CORBA_exception_free (&ev); - CORBA_exception_init (&ev); - } - - CORBA_Object_release (cursor->priv->corba_cursor, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning("e_card_cursor_destroy: Exception releasing " - "corba cursor.\n"); - } - - CORBA_exception_free (&ev); - - g_free ( cursor->priv ); - cursor->priv = NULL; - } - - if (G_OBJECT_CLASS (parent_class)->dispose) - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -/** - * e_card_cursor_get_length: - * @cursor: the #ECardCursor whose length is being queried - * - * Returns: the number of items the cursor references, or -1 there's - * an error. - */ -long -e_card_cursor_get_length (ECardCursor *cursor) -{ - if ( cursor->priv->corba_cursor != CORBA_OBJECT_NIL ) { - CORBA_Environment ev; - long ret_val; - - CORBA_exception_init (&ev); - - ret_val = GNOME_Evolution_Addressbook_CardCursor_count (cursor->priv->corba_cursor, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning("e_card_cursor_get_length: Exception during " - "get_length corba call.\n"); - ret_val = -1; - } - - CORBA_exception_free (&ev); - - return ret_val; - } - else - return -1; -} - -/** - * e_card_cursor_get_nth: - * @cursor: an #ECardCursor object - * @n: the index of the item requested - * - * Gets an #ECard based on an index. - * - * Returns: a new #ECard on success, or %NULL on failure. - */ -ECard * -e_card_cursor_get_nth (ECardCursor *cursor, - const long n) -{ - if ( cursor->priv->corba_cursor != CORBA_OBJECT_NIL ) { - CORBA_Environment en; - CORBA_char *vcard; - ECard *card; - - CORBA_exception_init (&en); - - vcard = GNOME_Evolution_Addressbook_CardCursor_getNth(cursor->priv->corba_cursor, n, &en); - - if (en._major != CORBA_NO_EXCEPTION) { - g_warning("e_card_cursor_get_nth: Exception during " - "get_nth corba call.\n"); - } - - CORBA_exception_free (&en); - - card = e_card_new (vcard); - - CORBA_free(vcard); - - return card; - } - else - return e_card_new(""); -} - -static void -e_card_cursor_class_init (ECardCursorClass *klass) -{ - GObjectClass *object_class = (GObjectClass *) klass; - - parent_class = g_type_class_ref (G_TYPE_OBJECT); - - object_class->dispose = e_card_cursor_dispose; -} - -static void -e_card_cursor_init (ECardCursor *cursor) -{ - cursor->priv = g_new(ECardCursorPrivate, 1); - cursor->priv->corba_cursor = CORBA_OBJECT_NIL; -} - -GType -e_card_cursor_get_type (void) -{ - static GType type = 0; - - if (!type){ - static const GTypeInfo info = { - sizeof (ECardCursorClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) e_card_cursor_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (ECardCursor), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_card_cursor_init, - }; - - type = g_type_register_static (G_TYPE_OBJECT, "ECardCursor", &info, 0); - } - - return type; -} - -/** - * e_card_cursor_construct: - * @cursor: an #ECardCursor object - * @corba_cursor: an #GNOME_Evolution_Addressbook_CardCursor - * - * Wraps an #GNOME_Evolution_Addressbook_CardCursor object inside the #ECardCursor - * @cursor object. - * - * Returns: a new #ECardCursor on success, or %NULL on failure. - */ -ECardCursor * -e_card_cursor_construct (ECardCursor *cursor, - GNOME_Evolution_Addressbook_CardCursor corba_cursor) -{ - CORBA_Environment ev; - g_return_val_if_fail (cursor != NULL, NULL); - g_return_val_if_fail (E_IS_CARD_CURSOR (cursor), NULL); - g_return_val_if_fail (corba_cursor != CORBA_OBJECT_NIL, NULL); - - CORBA_exception_init (&ev); - - /* - * Initialize cursor - */ - cursor->priv->corba_cursor = CORBA_Object_duplicate(corba_cursor, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning("e_card_cursor_construct: Exception duplicating " - "corba cursor.\n"); - CORBA_exception_free (&ev); - CORBA_exception_init (&ev); - } - - GNOME_Evolution_Addressbook_CardCursor_ref(cursor->priv->corba_cursor, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning("e_card_cursor_construct: Exception reffing " - "corba cursor.\n"); - } - - CORBA_exception_free (&ev); - - /* - * Success: return the GType we were given - */ - return cursor; -} - -/** - * e_card_cursor_new: - * @cursor: the #GNOME_Evolution_Addressbook_CardCursor to be wrapped - * - * Creates a new #ECardCursor, which wraps an #GNOME_Evolution_Addressbook_CardCursor - * object. - * - * Returns: a new #ECardCursor on success, or %NULL on failure. - */ -ECardCursor * -e_card_cursor_new (GNOME_Evolution_Addressbook_CardCursor corba_cursor) -{ - ECardCursor *cursor; - - cursor = g_object_new (E_TYPE_CARD_CURSOR, NULL); - - return e_card_cursor_construct (cursor, - corba_cursor); -} diff --git a/addressbook/backend/ebook/e-card-cursor.h b/addressbook/backend/ebook/e-card-cursor.h deleted file mode 100644 index b8da39f023..0000000000 --- a/addressbook/backend/ebook/e-card-cursor.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * - * Author: - * Nat Friedman (nat@ximian.com) - * - * Copyright 2000, Ximian, Inc. - */ - -#ifndef __E_CARD_CURSOR_H__ -#define __E_CARD_CURSOR_H__ - -#include -#include -#include -#include - -#define E_TYPE_CARD_CURSOR (e_card_cursor_get_type ()) -#define E_CARD_CURSOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_CARD_CURSOR, ECardCursor)) -#define E_CARD_CURSOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_CARD_CURSOR, ECardCursorClass)) -#define E_IS_CARD_CURSOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_CARD_CURSOR)) -#define E_IS_CARD_CURSOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_CARD_CURSOR)) -#define E_CARD_CURSOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CARD_CURSOR, ECardCursorClass)) - -G_BEGIN_DECLS - -typedef struct _ECardCursor ECardCursor; -typedef struct _ECardCursorPrivate ECardCursorPrivate; -typedef struct _ECardCursorClass ECardCursorClass; - -struct _ECardCursor { - GObject parent; - ECardCursorPrivate *priv; -}; - -struct _ECardCursorClass { - GObjectClass parent; -}; - -/* Creating a new addressbook. */ -ECardCursor *e_card_cursor_new (GNOME_Evolution_Addressbook_CardCursor corba_cursor); -ECardCursor *e_card_cursor_construct (ECardCursor *cursor, - GNOME_Evolution_Addressbook_CardCursor corba_cursor); - -GType e_card_cursor_get_type (void); - -/* Fetching cards. */ -long e_card_cursor_get_length (ECardCursor *cursor); -ECard *e_card_cursor_get_nth (ECardCursor *cursor, - const long nth); -G_END_DECLS - -#endif /* ! __E_CARD_CURSOR_H__ */ diff --git a/addressbook/backend/ebook/e-card-pairs.h b/addressbook/backend/ebook/e-card-pairs.h deleted file mode 100644 index f82f948ebb..0000000000 --- a/addressbook/backend/ebook/e-card-pairs.h +++ /dev/null @@ -1,118 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* GnomeCard - a graphical contact manager. - * - * pairs.h: This file is part of GnomeCard. - * - * Copyright (C) 1999 The Free Software Foundation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __E_CARD_PAIRS_H__ -#define __E_CARD_PAIRS_H__ - -#include -#include - - -#if 0 -struct pair -{ - char *str; - ECardPropertyType i ; -}; - -struct pair prop_lookup[] = { - { VCFullNameProp, PROP_FNAME }, - { VCNameProp, PROP_NAME }, - { VCPhotoProp, PROP_PHOTO }, - { VCBirthDateProp, PROP_BDAY }, - { VCAdrProp, PROP_DELADDR }, - { VCDeliveryLabelProp, PROP_DELLABEL }, - { VCTelephoneProp, PROP_PHONE }, - { VCEmailAddressProp, PROP_EMAIL }, - { VCMailerProp, PROP_MAILER }, - { VCTimeZoneProp, PROP_TIMEZN }, - { VCGeoProp, PROP_GEOPOS }, - { VCTitleProp, PROP_TITLE }, - { VCBusinessRoleProp, PROP_ROLE }, - { VCLogoProp, PROP_LOGO }, - { VCAgentProp, PROP_AGENT }, - { VCOrgProp, PROP_ORG }, - { VCCategoriesProp, PROP_CATEGORIES }, - { VCCommentProp, PROP_COMMENT }, - { VCLastRevisedProp, PROP_REV }, - { VCPronunciationProp, PROP_SOUND }, - { VCURLProp, PROP_URL }, - { VCUniqueStringProp, PROP_UID }, - { VCVersionProp, PROP_VERSION }, - { VCPublicKeyProp, PROP_KEY }, - { VCValueProp, PROP_VALUE }, - { VCEncodingProp, PROP_ENCODING }, - { VCQuotedPrintableProp, PROP_QUOTED_PRINTABLE }, - { VC8bitProp, PROP_8BIT }, - { VCBase64Prop, PROP_BASE64 }, - { VCLanguageProp, PROP_LANG }, - { VCCharSetProp, PROP_CHARSET }, - { NULL, PROP_NONE} }; - -struct pair photo_pairs[] = { - { VCGIFProp, PHOTO_GIF }, - { VCCGMProp, PHOTO_CGM }, - { VCWMFProp, PHOTO_WMF }, - { VCBMPProp, PHOTO_BMP }, - { VCMETProp, PHOTO_MET }, - { VCPMBProp, PHOTO_PMB }, - { VCDIBProp, PHOTO_DIB }, - { VCPICTProp, PHOTO_PICT }, - { VCTIFFProp, PHOTO_TIFF }, - { VCPDFProp, PHOTO_PDF }, - { VCPSProp, PHOTO_PS }, - { VCJPEGProp, PHOTO_JPEG }, - { VCMPEGProp, PHOTO_MPEG }, - { VCMPEG2Prop, PHOTO_MPEG2 }, - { VCAVIProp, PHOTO_AVI }, - { VCQuickTimeProp, PHOTO_QTIME }, - { NULL, 0 } }; - -struct pair email_pairs[] = { - { VCAOLProp, EMAIL_AOL }, - { VCAppleLinkProp, EMAIL_APPLE_LINK }, - { VCATTMailProp, EMAIL_ATT }, - { VCCISProp, EMAIL_CIS }, - { VCEWorldProp, EMAIL_EWORLD }, - { VCInternetProp, EMAIL_INET }, - { VCIBMMailProp, EMAIL_IBM }, - { VCMCIMailProp, EMAIL_MCI }, - { VCPowerShareProp, EMAIL_POWERSHARE }, - { VCProdigyProp, EMAIL_PRODIGY }, - { VCTLXProp, EMAIL_TLX }, - { VCX400Prop, EMAIL_X400 }, - { NULL, 0 } }; - -struct pair sound_pairs[] = { - { VCAIFFProp, SOUND_AIFF }, - { VCPCMProp, SOUND_PCM }, - { VCWAVEProp, SOUND_WAVE }, - { NULL, 0 } }; - -struct pair key_pairs[] = { - { VCX509Prop, KEY_X509 }, - { VCPGPProp, KEY_PGP }, - { NULL, 0 } }; - - -#endif -#endif /* ! __E_CARD_PAIRS_H__ */ diff --git a/addressbook/backend/ebook/e-card-simple.c b/addressbook/backend/ebook/e-card-simple.c deleted file mode 100644 index b9e32762fe..0000000000 --- a/addressbook/backend/ebook/e-card-simple.c +++ /dev/null @@ -1,1344 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: - * Chris Lahey - * Arturo Espinosa (arturo@nuclecu.unam.mx) - * Nat Friedman (nat@ximian.com) - * - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 1999 The Free Software Foundation - */ - -#include -#include -#include -#include -#include -#include - -#include -#include "e-card-simple.h" - -/* Object property IDs */ -enum { - PROP_0, - PROP_CARD, -}; - -static GObjectClass *parent_class; - -typedef enum _ECardSimpleInternalType ECardSimpleInternalType; -typedef struct _ECardSimpleFieldData ECardSimpleFieldData; - -enum _ECardSimpleInternalType { - E_CARD_SIMPLE_INTERNAL_TYPE_STRING, - E_CARD_SIMPLE_INTERNAL_TYPE_DATE, - E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS, - E_CARD_SIMPLE_INTERNAL_TYPE_PHONE, - E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL, - E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL, - E_CARD_SIMPLE_INTERNAL_TYPE_BOOL, -}; - -struct _ECardSimpleFieldData { - ECardSimpleField field; - char *ecard_field; - char *name; - char *short_name; - int list_type_index; - ECardSimpleInternalType type; -}; - -/* This order must match the order in the .h. */ - -/* the ecard_field data below should only be used for TYPE_STRING, - TYPE_DATE, and TYPE_SPECIAL fields. that is, it's only valid for - e-cards for those types. it is used as a unique name for fields - for the get_supported functionality. */ -static ECardSimpleFieldData field_data[] = -{ - { E_CARD_SIMPLE_FIELD_FILE_AS, "file_as", N_("File As"), "", 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_FULL_NAME, "full_name", N_("Name"), N_("Name"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_EMAIL, "email", N_("Email"), N_("Email"), E_CARD_SIMPLE_EMAIL_ID_EMAIL, E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL }, - { E_CARD_SIMPLE_FIELD_PHONE_PRIMARY, "primary_phone", N_("Primary"), N_("Prim"), E_CARD_SIMPLE_PHONE_ID_PRIMARY, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_ASSISTANT, "assistant_phone", N_("Assistant"), N_("Assistant"),E_CARD_SIMPLE_PHONE_ID_ASSISTANT, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_BUSINESS, "business_phone", N_("Business"), N_("Bus"), E_CARD_SIMPLE_PHONE_ID_BUSINESS, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_CALLBACK, "callback_phone", N_("Callback"), N_("Callback"), E_CARD_SIMPLE_PHONE_ID_CALLBACK, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_COMPANY, "company_phone", N_("Company"), N_("Comp"), E_CARD_SIMPLE_PHONE_ID_COMPANY, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_HOME, "home_phone", N_("Home"), N_("Home"), E_CARD_SIMPLE_PHONE_ID_HOME, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_ORG, "org", N_("Organization"), N_("Org"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_ADDRESS_BUSINESS, "business_address",N_("Business"), N_("Bus"), E_CARD_SIMPLE_ADDRESS_ID_BUSINESS, E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS }, - { E_CARD_SIMPLE_FIELD_ADDRESS_HOME, "home_address", N_("Home"), N_("Home"), E_CARD_SIMPLE_ADDRESS_ID_HOME, E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS }, - { E_CARD_SIMPLE_FIELD_PHONE_MOBILE, "mobile_phone", N_("Mobile"), N_("Mobile"), E_CARD_SIMPLE_PHONE_ID_MOBILE, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_CAR, "car_phone", N_("Car"), N_("Car"), E_CARD_SIMPLE_PHONE_ID_CAR, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_BUSINESS_FAX, "business_fax", N_("Business Fax"), N_("Bus Fax"), E_CARD_SIMPLE_PHONE_ID_BUSINESS_FAX, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_HOME_FAX, "home_fax", N_("Home Fax"), N_("Home Fax"), E_CARD_SIMPLE_PHONE_ID_HOME_FAX, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_BUSINESS_2, "business_phone_2",N_("Business 2"), N_("Bus 2"), E_CARD_SIMPLE_PHONE_ID_BUSINESS_2, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_HOME_2, "home_phone_2", N_("Home 2"), N_("Home 2"), E_CARD_SIMPLE_PHONE_ID_HOME_2, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_ISDN, "isdn", N_("ISDN"), N_("ISDN"), E_CARD_SIMPLE_PHONE_ID_ISDN, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_OTHER, "other_phone", N_("Other"), N_("Other"), E_CARD_SIMPLE_PHONE_ID_OTHER, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_OTHER_FAX, "other_fax", N_("Other Fax"), N_("Other Fax"), E_CARD_SIMPLE_PHONE_ID_OTHER_FAX, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_PAGER, "pager", N_("Pager"), N_("Pager"), E_CARD_SIMPLE_PHONE_ID_PAGER, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_RADIO, "radio", N_("Radio"), N_("Radio"), E_CARD_SIMPLE_PHONE_ID_RADIO, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_TELEX, "telex", N_("Telex"), N_("Telex"), E_CARD_SIMPLE_PHONE_ID_TELEX, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_PHONE_TTYTDD, "tty", N_("TTY"), N_("TTY"), E_CARD_SIMPLE_PHONE_ID_TTYTDD, E_CARD_SIMPLE_INTERNAL_TYPE_PHONE }, - { E_CARD_SIMPLE_FIELD_ADDRESS_OTHER, "other_address", N_("Other"), N_("Other"), E_CARD_SIMPLE_ADDRESS_ID_OTHER, E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS }, - { E_CARD_SIMPLE_FIELD_EMAIL_2, "email_2", N_("Email 2"), N_("Email 2"), E_CARD_SIMPLE_EMAIL_ID_EMAIL_2, E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL }, - { E_CARD_SIMPLE_FIELD_EMAIL_3, "email_3", N_("Email 3"), N_("Email 3"), E_CARD_SIMPLE_EMAIL_ID_EMAIL_3, E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL }, - { E_CARD_SIMPLE_FIELD_URL, "url", N_("Web Site"), N_("Url"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_ORG_UNIT, "org_unit", N_("Department"), N_("Dep"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_OFFICE, "office", N_("Office"), N_("Off"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_TITLE, "title", N_("Title"), N_("Title"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_ROLE, "role", N_("Profession"), N_("Prof"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_MANAGER, "manager", N_("Manager"), N_("Man"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_ASSISTANT, "assistant", N_("Assistant"), N_("Ass"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_NICKNAME, "nickname", N_("Nickname"), N_("Nick"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_SPOUSE, "spouse", N_("Spouse"), N_("Spouse"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_NOTE, "note", N_("Note"), N_("Note"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_CALURI, "caluri", N_("Calendar URI"), N_("CALUri"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_FBURL, "fburl", N_("Free-busy URL"), N_("FBUrl"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_ICSCALENDAR, "icscalendar", N_("Default server calendar"), N_("icsCalendar"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_ANNIVERSARY, "anniversary", N_("Anniversary"), N_("Anniv"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_DATE }, - { E_CARD_SIMPLE_FIELD_BIRTH_DATE, "birth_date", N_("Birth Date"), "", 0, E_CARD_SIMPLE_INTERNAL_TYPE_DATE }, - { E_CARD_SIMPLE_FIELD_MAILER, "mailer", "", "", 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_NAME_OR_ORG, "nameororg", "", "", 0, E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL }, - { E_CARD_SIMPLE_FIELD_CATEGORIES, "categories", N_("Categories"), N_("Categories"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_STRING }, - { E_CARD_SIMPLE_FIELD_FAMILY_NAME, "family_name", N_("Family Name"), N_("Family Name"), 0, E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL }, - { E_CARD_SIMPLE_FIELD_GIVEN_NAME, "given_name", "Given Name", "Given Name", 0, E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL }, - { E_CARD_SIMPLE_FIELD_ADDITIONAL_NAME, "additional_name", "Additional Name", "Additional Name", 0, E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL }, - { E_CARD_SIMPLE_FIELD_NAME_SUFFIX, "name_suffix", "Name Suffix", "Name Suffix", 0, E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL }, - { E_CARD_SIMPLE_FIELD_WANTS_HTML, "wants_html", "Wants HTML", "Wants HTML", 0, E_CARD_SIMPLE_INTERNAL_TYPE_BOOL }, - { E_CARD_SIMPLE_FIELD_IS_LIST, "list", "Is List", "Is List", 0, E_CARD_SIMPLE_INTERNAL_TYPE_BOOL }, -}; -static int field_data_count = sizeof (field_data) / sizeof (field_data[0]); - -static void e_card_simple_init (ECardSimple *simple); -static void e_card_simple_class_init (ECardSimpleClass *klass); - -static void e_card_simple_dispose (GObject *object); -static void e_card_simple_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void e_card_simple_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); - -static void fill_in_info(ECardSimple *simple); - -ECardPhoneFlags phone_correspondences[] = { - E_CARD_PHONE_ASSISTANT, /* E_CARD_SIMPLE_PHONE_ID_ASSISTANT, */ - E_CARD_PHONE_WORK | E_CARD_PHONE_VOICE, /* E_CARD_SIMPLE_PHONE_ID_BUSINESS, */ - E_CARD_PHONE_WORK | E_CARD_PHONE_VOICE, /* E_CARD_SIMPLE_PHONE_ID_BUSINESS_2, */ - E_CARD_PHONE_WORK | E_CARD_PHONE_FAX, /* E_CARD_SIMPLE_PHONE_ID_BUSINESS_FAX, */ - E_CARD_PHONE_CALLBACK, /* E_CARD_SIMPLE_PHONE_ID_CALLBACK, */ - E_CARD_PHONE_CAR, /* E_CARD_SIMPLE_PHONE_ID_CAR, */ - E_CARD_PHONE_WORK, /* E_CARD_SIMPLE_PHONE_ID_COMPANY, */ - E_CARD_PHONE_HOME, /* E_CARD_SIMPLE_PHONE_ID_HOME, */ - E_CARD_PHONE_HOME, /* E_CARD_SIMPLE_PHONE_ID_HOME_2, */ - E_CARD_PHONE_HOME | E_CARD_PHONE_FAX, /* E_CARD_SIMPLE_PHONE_ID_HOME_FAX, */ - E_CARD_PHONE_ISDN, /* E_CARD_SIMPLE_PHONE_ID_ISDN, */ - E_CARD_PHONE_CELL, /* E_CARD_SIMPLE_PHONE_ID_MOBILE, */ - E_CARD_PHONE_VOICE, /* E_CARD_SIMPLE_PHONE_ID_OTHER, */ - E_CARD_PHONE_FAX, /* E_CARD_SIMPLE_PHONE_ID_OTHER_FAX, */ - E_CARD_PHONE_PAGER, /* E_CARD_SIMPLE_PHONE_ID_PAGER, */ - E_CARD_PHONE_PREF, /* E_CARD_SIMPLE_PHONE_ID_PRIMARY, */ - E_CARD_PHONE_RADIO, /* E_CARD_SIMPLE_PHONE_ID_RADIO, */ - E_CARD_PHONE_TELEX, /* E_CARD_SIMPLE_PHONE_ID_TELEX, */ - E_CARD_PHONE_TTYTDD, /* E_CARD_SIMPLE_PHONE_ID_TTYTDD, */ -}; - -char *phone_names[] = { - NULL, /* E_CARD_SIMPLE_PHONE_ID_ASSISTANT, */ - "Business", - "Business 2", - "Business Fax", - NULL, /* E_CARD_SIMPLE_PHONE_ID_CALLBACK, */ - "Car", - NULL, /* E_CARD_SIMPLE_PHONE_ID_COMPANY, */ - "Home", - "Home 2", - "Home Fax", - "ISDN", - "Mobile", - "Other", - NULL, /* E_CARD_SIMPLE_PHONE_ID_OTHER_FAX, */ - "Pager", - "Primary", - NULL, /* E_CARD_SIMPLE_PHONE_ID_RADIO, */ - NULL, /* E_CARD_SIMPLE_PHONE_ID_TELEX, */ - NULL, /* E_CARD_SIMPLE_PHONE_ID_TTYTDD, */ -}; - -char *phone_short_names[] = { - NULL, /* E_CARD_SIMPLE_PHONE_ID_ASSISTANT, */ - "Bus", - "Bus 2", - "Bus Fax", - NULL, /* E_CARD_SIMPLE_PHONE_ID_CALLBACK, */ - "Car", - NULL, /* E_CARD_SIMPLE_PHONE_ID_COMPANY, */ - "Home", - "Home 2", - "Home Fax", - "ISDN", - "Mob", - "Other", - NULL, /* E_CARD_SIMPLE_PHONE_ID_OTHER_FAX, */ - "Pag", - "Prim", - NULL, /* E_CARD_SIMPLE_PHONE_ID_RADIO, */ - NULL, /* E_CARD_SIMPLE_PHONE_ID_TELEX, */ - NULL, /* E_CARD_SIMPLE_PHONE_ID_TTYTDD, */ -}; - -ECardAddressFlags addr_correspondences[] = { - E_CARD_ADDR_WORK, /* E_CARD_SIMPLE_ADDRESS_ID_BUSINESS, */ - E_CARD_ADDR_HOME, /* E_CARD_SIMPLE_ADDRESS_ID_HOME, */ - E_CARD_ADDR_POSTAL, /* E_CARD_SIMPLE_ADDRESS_ID_OTHER, */ -}; - -char *address_names[] = { - "Business", - "Home", - "Other", -}; - -/** - * e_card_simple_get_type: - * @void: - * - * Registers the &ECardSimple class if necessary, and returns the type ID - * associated to it. - * - * Return value: The type ID of the &ECardSimple class. - **/ -GType -e_card_simple_get_type (void) -{ - static GType simple_type = 0; - - if (!simple_type) { - static const GTypeInfo simple_info = { - sizeof (ECardSimpleClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) e_card_simple_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (ECardSimple), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_card_simple_init, - }; - - simple_type = g_type_register_static (G_TYPE_OBJECT, "ECardSimple", &simple_info, 0); - } - - return simple_type; -} - -/** - * e_card_simple_new: - * @VCard: a string in vCard format - * - * Returns: a new #ECardSimple that wraps the @VCard. - */ -ECardSimple * -e_card_simple_new (ECard *card) -{ - ECardSimple *simple = g_object_new (E_TYPE_CARD_SIMPLE, NULL); - g_object_set(simple, - "card", card, - NULL); - return simple; -} - -ECardSimple * -e_card_simple_duplicate(ECardSimple *simple) -{ - ECard *card = simple->card ? e_card_duplicate (simple->card) : e_card_new (""); - ECardSimple *new_simple = e_card_simple_new(card); - return new_simple; -} - -/** - * e_card_simple_get_id: - * @simple: an #ECardSimple - * - * Returns: a string representing the id of the simple, which is unique - * within its book. - */ -const char * -e_card_simple_get_id (ECardSimple *simple) -{ - if (simple->card) - return e_card_get_id(simple->card); - else - return ""; -} - -/** - * e_card_simple_get_id: - * @simple: an #ECardSimple - * @id: a id in string format - * - * Sets the identifier of a simple, which should be unique within its - * book. - */ -void -e_card_simple_set_id (ECardSimple *simple, const char *id) -{ - if ( simple->card ) - e_card_set_id(simple->card, id); -} - -/** - * e_card_simple_get_vcard: - * @simple: an #ECardSimple - * - * Returns: a string in vcard format, which is wrapped by the @simple. - */ -char * -e_card_simple_get_vcard (ECardSimple *simple) -{ - if (simple->card) - return e_card_get_vcard(simple->card); - else - return g_strdup(""); -} - -/** - * e_card_simple_get_vcard_assume_utf8: - * @simple: an #ECardSimple - * - * Returns: a string in vcard format, which is wrapped by the @simple. - */ -char * -e_card_simple_get_vcard_assume_utf8 (ECardSimple *simple) -{ - if (simple->card) - return e_card_get_vcard_assume_utf8(simple->card); - else - return g_strdup(""); -} - -static void -e_card_simple_class_init (ECardSimpleClass *klass) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS(klass); - - parent_class = g_type_class_ref (G_TYPE_OBJECT); - - object_class->dispose = e_card_simple_dispose; - object_class->get_property = e_card_simple_get_property; - object_class->set_property = e_card_simple_set_property; - - g_object_class_install_property (object_class, PROP_CARD, - g_param_spec_object ("card", - _("ECard"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_CARD, - G_PARAM_READWRITE)); -} - -/* - * ECardSimple lifecycle management and vcard loading/saving. - */ - -static void -e_card_simple_dispose (GObject *object) -{ - ECardSimple *simple; - int i; - - simple = E_CARD_SIMPLE (object); - - if (simple->card) { - g_object_unref(simple->card); - simple->card = NULL; - } - if (simple->temp_fields) { - g_list_foreach(simple->temp_fields, (GFunc) g_free, NULL); - g_list_free(simple->temp_fields); - simple->temp_fields = NULL; - } - - for(i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i++) { - if (simple->phone[i]) { - e_card_phone_unref (simple->phone[i]); - simple->phone[i] = NULL; - } - } - for(i = 0; i < E_CARD_SIMPLE_EMAIL_ID_LAST; i++) { - if (simple->email[i]) { - g_free(simple->email[i]); - simple->email[i] = NULL; - } - } - for(i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i++) { - if (simple->address[i]) { - e_card_address_label_unref(simple->address[i]); - simple->address[i] = NULL; - } - } - for(i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i++) { - if (simple->delivery[i]) { - e_card_delivery_address_unref(simple->delivery[i]); - simple->delivery[i] = NULL; - } - } - - if (G_OBJECT_CLASS (parent_class)->dispose) - G_OBJECT_CLASS (parent_class)->dispose (object); -} - - -/* Set_arg handler for the simple */ -static void -e_card_simple_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - ECardSimple *simple; - - simple = E_CARD_SIMPLE (object); - - switch (prop_id) { - case PROP_CARD: - if (simple->card) - g_object_unref(simple->card); - g_list_foreach(simple->temp_fields, (GFunc) g_free, NULL); - g_list_free(simple->temp_fields); - simple->temp_fields = NULL; - if (g_value_get_object (value)) - simple->card = E_CARD(g_value_get_object (value)); - else - simple->card = NULL; - if(simple->card) - g_object_ref(simple->card); - fill_in_info(simple); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* Get_arg handler for the simple */ -static void -e_card_simple_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - ECardSimple *simple; - - simple = E_CARD_SIMPLE (object); - - switch (prop_id) { - case PROP_CARD: - e_card_simple_sync_card(simple); - g_value_set_object (value, simple->card); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -/** - * e_card_simple_init: - */ -static void -e_card_simple_init (ECardSimple *simple) -{ - int i; - simple->card = NULL; - for(i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i++) - simple->phone[i] = NULL; - for(i = 0; i < E_CARD_SIMPLE_EMAIL_ID_LAST; i++) - simple->email[i] = NULL; - for(i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i++) - simple->address[i] = NULL; - simple->temp_fields = NULL; - - simple->changed = TRUE; -} - -static void -fill_in_info(ECardSimple *simple) -{ - ECard *card = simple->card; - if (card) { - EList *address_list; - EList *phone_list; - EList *email_list; - EList *delivery_list; - const ECardPhone *phone; - const char *email; - const ECardAddrLabel *address; - const ECardDeliveryAddress *delivery; - int i; - - EIterator *iterator; - - g_object_get(card, - "address_label", &address_list, - "address", &delivery_list, - "phone", &phone_list, - "email", &email_list, - NULL); - for (i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i++) { - e_card_phone_unref(simple->phone[i]); - simple->phone[i] = NULL; - } - for (iterator = e_list_get_iterator(phone_list); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - gboolean found = FALSE; - phone = e_iterator_get(iterator); - for (i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i ++) { - if ((phone->flags == phone_correspondences[i]) && (simple->phone[i] == NULL)) { - simple->phone[i] = e_card_phone_ref(phone); - found = TRUE; - break; - } - } - if (found) - continue; - for (i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i ++) { - if (((phone->flags & phone_correspondences[i]) == phone_correspondences[i]) && (simple->phone[i] == NULL)) { - simple->phone[i] = e_card_phone_ref(phone); - break; - } - } - } - g_object_unref(iterator); - - for (i = 0; i < E_CARD_SIMPLE_EMAIL_ID_LAST; i++) { - g_free(simple->email[i]); - simple->email[i] = NULL; - } - for (iterator = e_list_get_iterator(email_list); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - email = e_iterator_get(iterator); - for (i = 0; i < E_CARD_SIMPLE_EMAIL_ID_LAST; i ++) { - if ((simple->email[i] == NULL)) { - simple->email[i] = g_strdup(email); - break; - } - } - } - g_object_unref(iterator); - - for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i++) { - e_card_address_label_unref(simple->address[i]); - simple->address[i] = NULL; - } - for (iterator = e_list_get_iterator(address_list); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - address = e_iterator_get(iterator); - for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i ++) { - if (((address->flags & addr_correspondences[i]) == addr_correspondences[i]) && (simple->address[i] == NULL)) { - simple->address[i] = e_card_address_label_ref(address); - break; - } - } - } - g_object_unref(iterator); - - for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i++) { - e_card_delivery_address_unref(simple->delivery[i]); - simple->delivery[i] = NULL; - } - for (iterator = e_list_get_iterator(delivery_list); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - delivery = e_iterator_get(iterator); - for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i ++) { - if (((delivery->flags & addr_correspondences[i]) == addr_correspondences[i]) && (simple->delivery[i] == NULL)) { - simple->delivery[i] = e_card_delivery_address_ref(delivery); - break; - } - } - } - g_object_unref(iterator); - - g_object_unref(phone_list); - g_object_unref(email_list); - g_object_unref(address_list); - g_object_unref(delivery_list); - e_card_free_empty_lists (card); - } -} - -void -e_card_simple_sync_card(ECardSimple *simple) -{ - ECard *card = simple->card; - if (card && simple->changed) { - EList *address_list; - EList *phone_list; - EList *email_list; - EList *delivery_list; - const ECardPhone *phone; - const ECardAddrLabel *address; - const ECardDeliveryAddress *delivery; - const char *email; - int i; - - EIterator *iterator; - - g_object_get(card, - "address_label", &address_list, - "address", &delivery_list, - "phone", &phone_list, - "email", &email_list, - NULL); - - for (iterator = e_list_get_iterator(phone_list); e_iterator_is_valid(iterator); e_iterator_next(iterator) ) { - int i; - gboolean found = FALSE; - phone = e_iterator_get(iterator); - for (i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i ++) { - if (phone->flags == phone_correspondences[i]) { - if (simple->phone[i]) { - simple->phone[i]->flags = phone_correspondences[i]; - if (simple->phone[i]->number && *simple->phone[i]->number) { - e_iterator_set(iterator, simple->phone[i]); - } else { - e_iterator_delete(iterator); - } - e_card_phone_unref(simple->phone[i]); - simple->phone[i] = NULL; - found = TRUE; - break; - } - } - } - if (found) - continue; - for (i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i ++) { - if ((phone->flags & phone_correspondences[i]) == phone_correspondences[i]) { - if (simple->phone[i]) { - simple->phone[i]->flags = phone_correspondences[i]; - if (simple->phone[i]->number && *simple->phone[i]->number) { - e_iterator_set(iterator, simple->phone[i]); - } else { - e_iterator_delete(iterator); - } - e_card_phone_unref(simple->phone[i]); - simple->phone[i] = NULL; - break; - } - } - } - } - g_object_unref(iterator); - for (i = 0; i < E_CARD_SIMPLE_PHONE_ID_LAST; i ++) { - if (simple->phone[i]) { - simple->phone[i]->flags = phone_correspondences[i]; - e_list_append(phone_list, simple->phone[i]); - e_card_phone_unref(simple->phone[i]); - simple->phone[i] = NULL; - } - } - - for (iterator = e_list_get_iterator(email_list); e_iterator_is_valid(iterator); e_iterator_next(iterator) ) { - int i; - email = e_iterator_get(iterator); - for (i = 0; i < E_CARD_SIMPLE_EMAIL_ID_LAST; i ++) { - if (simple->email[i]) { - if (*simple->email[i]) { - e_iterator_set(iterator, simple->email[i]); - } else { - e_iterator_delete(iterator); - } - g_free(simple->email[i]); - simple->email[i] = NULL; - break; - } - } - } - g_object_unref(iterator); - for (i = 0; i < E_CARD_SIMPLE_EMAIL_ID_LAST; i ++) { - if (simple->email[i]) { - e_list_append(email_list, simple->email[i]); - g_free(simple->email[i]); - simple->email[i] = NULL; - } - } - - for (iterator = e_list_get_iterator(address_list); e_iterator_is_valid(iterator); e_iterator_next(iterator) ) { - int i; - address = e_iterator_get(iterator); - for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i ++) { - if ((address->flags & addr_correspondences[i]) == addr_correspondences[i]) { - if (simple->address[i]) { - simple->address[i]->flags &= ~E_CARD_ADDR_MASK; - simple->address[i]->flags |= addr_correspondences[i]; - if (simple->address[i]->data && *simple->address[i]->data) { - e_iterator_set(iterator, simple->address[i]); - } else { - e_iterator_delete(iterator); - } - e_card_address_label_unref(simple->address[i]); - simple->address[i] = NULL; - break; - } - } - } - } - g_object_unref(iterator); - for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i ++) { - if (simple->address[i]) { - simple->address[i]->flags &= ~E_CARD_ADDR_MASK; - simple->address[i]->flags |= addr_correspondences[i]; - e_list_append(address_list, simple->address[i]); - e_card_address_label_unref(simple->address[i]); - simple->address[i] = NULL; - } - } - - for (iterator = e_list_get_iterator(delivery_list); e_iterator_is_valid(iterator); e_iterator_next(iterator) ) { - int i; - delivery = e_iterator_get(iterator); - for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i ++) { - if ((delivery->flags & addr_correspondences[i]) == addr_correspondences[i]) { - if (simple->delivery[i]) { - simple->delivery[i]->flags &= ~E_CARD_ADDR_MASK; - simple->delivery[i]->flags |= addr_correspondences[i]; - if (!e_card_delivery_address_is_empty(simple->delivery[i])) { - e_iterator_set(iterator, simple->delivery[i]); - } else { - e_iterator_delete(iterator); - } - e_card_delivery_address_unref(simple->delivery[i]); - simple->delivery[i] = NULL; - break; - } - } - } - } - g_object_unref(iterator); - for (i = 0; i < E_CARD_SIMPLE_ADDRESS_ID_LAST; i ++) { - if (simple->delivery[i]) { - simple->delivery[i]->flags &= ~E_CARD_ADDR_MASK; - simple->delivery[i]->flags |= addr_correspondences[i]; - e_list_append(delivery_list, simple->delivery[i]); - e_card_delivery_address_unref(simple->delivery[i]); - simple->delivery[i] = NULL; - } - } - fill_in_info(simple); - - g_object_unref(phone_list); - g_object_unref(email_list); - g_object_unref(address_list); - g_object_unref(delivery_list); - e_card_free_empty_lists (card); - } - - simple->changed = FALSE; -} - -const ECardPhone *e_card_simple_get_phone (ECardSimple *simple, - ECardSimplePhoneId id) -{ - return simple->phone[id]; -} - -const char *e_card_simple_get_email (ECardSimple *simple, - ECardSimpleEmailId id) -{ - return simple->email[id]; -} - -const ECardAddrLabel *e_card_simple_get_address (ECardSimple *simple, - ECardSimpleAddressId id) -{ - return simple->address[id]; -} - -const ECardDeliveryAddress *e_card_simple_get_delivery_address (ECardSimple *simple, - ECardSimpleAddressId id) -{ - return simple->delivery[id]; -} - -void e_card_simple_set_phone (ECardSimple *simple, - ECardSimplePhoneId id, - const ECardPhone *phone) -{ - e_card_phone_unref(simple->phone[id]); - simple->phone[id] = e_card_phone_ref(phone); - simple->changed = TRUE; -} - -void e_card_simple_set_email (ECardSimple *simple, - ECardSimpleEmailId id, - const char *email) -{ - g_free(simple->email[id]); - simple->email[id] = g_strdup(email); - simple->changed = TRUE; -} - -void -e_card_simple_set_address (ECardSimple *simple, ECardSimpleAddressId id, const ECardAddrLabel *address) -{ - e_card_address_label_unref(simple->address[id]); - simple->address[id] = e_card_address_label_ref(address); - e_card_delivery_address_unref(simple->delivery[id]); - simple->delivery[id] = e_card_delivery_address_from_label(simple->address[id]); - simple->changed = TRUE; -} - -void e_card_simple_set_delivery_address (ECardSimple *simple, - ECardSimpleAddressId id, - const ECardDeliveryAddress *delivery) -{ - e_card_delivery_address_unref(simple->delivery[id]); - simple->delivery[id] = e_card_delivery_address_ref(delivery); - e_card_address_label_unref(simple->address[id]); - simple->address[id] = e_card_delivery_address_to_label(simple->delivery[id]); - simple->changed = TRUE; -} - -const char *e_card_simple_get_const (ECardSimple *simple, - ECardSimpleField field) -{ - char *ret_val = e_card_simple_get(simple, field); - if (ret_val) - simple->temp_fields = g_list_prepend(simple->temp_fields, ret_val); - return ret_val; -} - -char *e_card_simple_get (ECardSimple *simple, - ECardSimpleField field) -{ - ECardSimpleInternalType type = field_data[field].type; - const ECardAddrLabel *addr; - const ECardPhone *phone; - char *string; - ECardDate *date; - ECardName *name; - switch(type) { - case E_CARD_SIMPLE_INTERNAL_TYPE_STRING: - if (simple->card) { - g_object_get(simple->card, - field_data[field].ecard_field, &string, - NULL); - return string; - } else - return NULL; - case E_CARD_SIMPLE_INTERNAL_TYPE_DATE: - if (simple->card) { - g_object_get(simple->card, - field_data[field].ecard_field, &date, - NULL); - if (date != NULL) { - char buf[26]; - struct tm then; - then.tm_year = date->year; - then.tm_mon = date->month - 1; - then.tm_mday = date->day; - then.tm_hour = 12; - then.tm_min = 0; - then.tm_sec = 0; - e_strftime_fix_am_pm (buf, 26, _("%x"), &then); - return g_strdup (buf); - } else { - return NULL; - } - } else - return NULL; - case E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS: - addr = e_card_simple_get_address(simple, - field_data[field].list_type_index); - if (addr) - return g_strdup(addr->data); - else - return NULL; - case E_CARD_SIMPLE_INTERNAL_TYPE_PHONE: - phone = e_card_simple_get_phone(simple, - field_data[field].list_type_index); - if (phone) - return g_strdup(phone->number); - else - return NULL; - case E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL: - string = e_card_simple_get_email(simple, - field_data[field].list_type_index); - return g_strdup(string); - case E_CARD_SIMPLE_INTERNAL_TYPE_BOOL: - if (simple->card) { - gboolean boole; - g_object_get (simple->card, - field_data[field].ecard_field, &boole, - NULL); - if (boole) - return g_strdup("true"); - else - return NULL; - } else { - return NULL; - } - case E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL: - switch (field) { - case E_CARD_SIMPLE_FIELD_NAME_OR_ORG: - if (simple->card) { - gboolean is_list; - - g_object_get(simple->card, - "file_as", &string, - NULL); - if (string && *string) - return string -; else - g_free (string); - - g_object_get(simple->card, - "full_name", &string, - NULL); - if (string && *string) - return g_strdup(string); - else - g_free (string); - - g_object_get(simple->card, - "org", &string, - NULL); - if (string && *string) - return g_strdup(string); - else - g_free (string); - - is_list = e_card_evolution_list (simple->card); - if (is_list) - string = _("Unnamed List"); - else - string = e_card_simple_get_email(simple, - E_CARD_SIMPLE_EMAIL_ID_EMAIL); - return g_strdup(string); - } else - return NULL; - case E_CARD_SIMPLE_FIELD_FAMILY_NAME: - if (simple->card) { - g_object_get (simple->card, - "name", &name, - NULL); - return g_strdup (name->family); - } else - return NULL; - case E_CARD_SIMPLE_FIELD_GIVEN_NAME: - if (simple->card) { - g_object_get (simple->card, - "name", &name, - NULL); - return g_strdup (name->given); - } else - return NULL; - case E_CARD_SIMPLE_FIELD_ADDITIONAL_NAME: - if (simple->card) { - g_object_get (simple->card, - "name", &name, - NULL); - return g_strdup (name->additional); - } else - return NULL; - case E_CARD_SIMPLE_FIELD_NAME_SUFFIX: - if (simple->card) { - g_object_get (simple->card, - "name", &name, - NULL); - return g_strdup (name->suffix); - } else - return NULL; - default: - return NULL; - } - default: - return NULL; - } -} - -static char * -name_to_style(const ECardName *name, char *company, int style) -{ - char *string; - char *strings[4], **stringptr; - char *substring; - switch (style) { - case 0: - stringptr = strings; - if (name->family && *name->family) - *(stringptr++) = name->family; - if (name->given && *name->given) - *(stringptr++) = name->given; - *stringptr = NULL; - string = g_strjoinv(", ", strings); - break; - case 1: - stringptr = strings; - if (name->given && *name->given) - *(stringptr++) = name->given; - if (name->family && *name->family) - *(stringptr++) = name->family; - *stringptr = NULL; - string = g_strjoinv(" ", strings); - break; - case 2: - string = g_strdup(company); - break; - case 3: /* Fall Through */ - case 4: - stringptr = strings; - if (name->family && *name->family) - *(stringptr++) = name->family; - if (name->given && *name->given) - *(stringptr++) = name->given; - *stringptr = NULL; - substring = g_strjoinv(", ", strings); - if (!(company && *company)) - company = ""; - if (style == 3) - string = g_strdup_printf("%s (%s)", substring, company); - else - string = g_strdup_printf("%s (%s)", company, substring); - g_free(substring); - break; - default: - string = g_strdup(""); - } - return string; -} - -static int -file_as_get_style (ECardSimple *simple) -{ - char *filestring = e_card_simple_get(simple, E_CARD_SIMPLE_FIELD_FILE_AS); - char *trystring; - char *company = e_card_simple_get(simple, E_CARD_SIMPLE_FIELD_ORG); - ECardName *name = NULL; - int i; - int style; - style = 0; - if (!company) - company = g_strdup(""); - if (filestring) { - g_object_get (simple->card, - "name", &name, - NULL); - - if (!name) { - goto end; - } - - style = -1; - - for (i = 0; i < 5; i++) { - trystring = name_to_style(name, company, i); - if (!strcmp(trystring, filestring)) { - g_free(trystring); - style = i; - goto end; - } - g_free(trystring); - } - } - end: - - g_free(filestring); - g_free(company); - - return style; -} - -static void -file_as_set_style(ECardSimple *simple, int style) -{ - if (style != -1) { - char *string; - char *company = e_card_simple_get(simple, E_CARD_SIMPLE_FIELD_ORG); - ECardName *name; - - if (!company) - company = g_strdup(""); - g_object_get (simple->card, - "name", &name, - NULL); - if (name) { - string = name_to_style(name, company, style); - e_card_simple_set(simple, E_CARD_SIMPLE_FIELD_FILE_AS, string); - g_free(string); - } - g_free(company); - } -} - -void e_card_simple_set (ECardSimple *simple, - ECardSimpleField field, - const char *data) -{ - ECardSimpleInternalType type = field_data[field].type; - ECardAddrLabel *address; - ECardPhone *phone; - int style; - simple->changed = TRUE; - switch (field) { - case E_CARD_SIMPLE_FIELD_FULL_NAME: - case E_CARD_SIMPLE_FIELD_ORG: - style = file_as_get_style(simple); - g_object_set(simple->card, - field_data[field].ecard_field, data, - NULL); - file_as_set_style(simple, style); - break; - default: - switch(type) { - case E_CARD_SIMPLE_INTERNAL_TYPE_STRING: - g_object_set(simple->card, - field_data[field].ecard_field, data, - NULL); - break; - case E_CARD_SIMPLE_INTERNAL_TYPE_DATE: - break; /* FIXME!!!! */ - case E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS: - address = e_card_address_label_new(); - address->data = g_strdup (data); - e_card_simple_set_address(simple, - field_data[field].list_type_index, - address); - e_card_address_label_unref(address); - break; - case E_CARD_SIMPLE_INTERNAL_TYPE_PHONE: - phone = e_card_phone_new(); - phone->number = g_strdup (data); - e_card_simple_set_phone(simple, - field_data[field].list_type_index, - phone); - e_card_phone_unref(phone); - break; - case E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL: - e_card_simple_set_email(simple, - field_data[field].list_type_index, - data); - break; - case E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL: - break; - case E_CARD_SIMPLE_INTERNAL_TYPE_BOOL: - if (simple->card) { - gboolean boole = TRUE; - if (data == NULL) - boole = FALSE; - else if (!strcasecmp (data, "false")) - boole = FALSE; - g_object_set (simple->card, - field_data[field].ecard_field, boole, - NULL); - } - break; - } - break; - } -} - -ECardSimpleType e_card_simple_type (ECardSimple *simple, - ECardSimpleField field) -{ - ECardSimpleInternalType type = field_data[field].type; - switch(type) { - case E_CARD_SIMPLE_INTERNAL_TYPE_STRING: - case E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS: - case E_CARD_SIMPLE_INTERNAL_TYPE_PHONE: - case E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL: - default: - return E_CARD_SIMPLE_TYPE_STRING; - - case E_CARD_SIMPLE_INTERNAL_TYPE_BOOL: - return E_CARD_SIMPLE_TYPE_BOOL; - - case E_CARD_SIMPLE_INTERNAL_TYPE_DATE: - return E_CARD_SIMPLE_TYPE_DATE; - - case E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL: - return E_CARD_SIMPLE_TYPE_STRING; - } -} - -const char *e_card_simple_get_ecard_field (ECardSimple *simple, - ECardSimpleField field) -{ - return field_data[field].ecard_field; -} - -const char *e_card_simple_get_name (ECardSimple *simple, - ECardSimpleField field) -{ - return _(field_data[field].name); -} - -gboolean -e_card_simple_get_allow_newlines (ECardSimple *simple, - ECardSimpleField field) -{ - ECardSimpleInternalType type = field_data[field].type; - switch(type) { - case E_CARD_SIMPLE_INTERNAL_TYPE_STRING: - case E_CARD_SIMPLE_INTERNAL_TYPE_PHONE: - case E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL: - case E_CARD_SIMPLE_INTERNAL_TYPE_BOOL: - case E_CARD_SIMPLE_INTERNAL_TYPE_DATE: - case E_CARD_SIMPLE_INTERNAL_TYPE_SPECIAL: - default: - switch (field) { - case E_CARD_SIMPLE_FIELD_NOTE: - return TRUE; - default: - return FALSE; - } - - case E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS: - return TRUE; - } -} - -const char *e_card_simple_get_short_name (ECardSimple *simple, - ECardSimpleField field) -{ - return _(field_data[field].short_name); -} - -void e_card_simple_arbitrary_foreach (ECardSimple *simple, - ECardSimpleArbitraryCallback *callback, - gpointer closure) -{ - if (simple->card) { - EList *list; - EIterator *iterator; - g_object_get(simple->card, - "arbitrary", &list, - NULL); - for (iterator = e_list_get_iterator(list); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - const ECardArbitrary *arbitrary = e_iterator_get(iterator); - if (callback) - (*callback) (arbitrary, closure); - } - - g_object_unref (list); - e_card_free_empty_lists (simple->card); - } -} - -const ECardArbitrary *e_card_simple_get_arbitrary (ECardSimple *simple, - const char *key) -{ - if (simple->card) { - EList *list; - EIterator *iterator; - g_object_get(simple->card, - "arbitrary", &list, - NULL); - for (iterator = e_list_get_iterator(list); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - const ECardArbitrary *arbitrary = e_iterator_get(iterator); - if (!strcasecmp(arbitrary->key, key)) - return arbitrary; - } - - g_object_unref (list); - e_card_free_empty_lists (simple->card); - } - return NULL; -} - -/* Any of these except key can be NULL */ -void e_card_simple_set_arbitrary (ECardSimple *simple, - const char *key, - const char *type, - const char *value) -{ - if (simple->card) { - ECardArbitrary *new_arb; - EList *list; - EIterator *iterator; - - simple->changed = TRUE; - g_object_get(simple->card, - "arbitrary", &list, - NULL); - for (iterator = e_list_get_iterator(list); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - const ECardArbitrary *arbitrary = e_iterator_get(iterator); - if (!strcasecmp(arbitrary->key, key)) { - new_arb = e_card_arbitrary_new(); - new_arb->key = g_strdup(key); - new_arb->type = g_strdup(type); - new_arb->value = g_strdup(value); - e_iterator_set(iterator, new_arb); - e_card_arbitrary_unref(new_arb); - return; - } - } - new_arb = e_card_arbitrary_new(); - new_arb->key = g_strdup(key); - new_arb->type = g_strdup(type); - new_arb->value = g_strdup(value); - e_list_append(list, new_arb); - g_object_unref(list); - e_card_arbitrary_unref(new_arb); - } -} - -void -e_card_simple_set_name (ECardSimple *simple, ECardName *name) -{ - int style; - style = file_as_get_style(simple); - g_object_set (simple->card, - "name", name, - NULL); - file_as_set_style(simple, style); -} - -/* These map between the individual list types and ECardSimpleField */ -ECardSimpleField -e_card_simple_map_phone_to_field (ECardSimplePhoneId phone_id) -{ - int i; - - g_return_val_if_fail (phone_id < E_CARD_SIMPLE_PHONE_ID_LAST, 0); - - for (i = 0; i < field_data_count; i ++) - if (field_data[i].list_type_index == phone_id - && field_data[i].type == E_CARD_SIMPLE_INTERNAL_TYPE_PHONE) - return i; - - g_warning ("couldn't find phone id %d, returning 0 (which is almost assuredly incorrect)\n", phone_id); - - return 0; -} - -ECardSimpleField -e_card_simple_map_email_to_field (ECardSimpleEmailId email_id) -{ - int i; - - g_return_val_if_fail (email_id < E_CARD_SIMPLE_EMAIL_ID_LAST, 0); - - for (i = 0; i < field_data_count; i ++) - if (field_data[i].list_type_index == email_id - && field_data[i].type == E_CARD_SIMPLE_INTERNAL_TYPE_EMAIL) - return i; - - g_warning ("couldn't find email id %d, returning 0 (which is almost assuredly incorrect)\n", email_id); - return 0; -} - -ECardSimpleField -e_card_simple_map_address_to_field (ECardSimpleAddressId address_id) -{ - int i; - - g_return_val_if_fail (address_id < E_CARD_SIMPLE_ADDRESS_ID_LAST, 0); - - for (i = 0; i < field_data_count; i ++) - if (field_data[i].list_type_index == address_id - && field_data[i].type == E_CARD_SIMPLE_INTERNAL_TYPE_ADDRESS) - return i; - - g_warning ("couldn't find address id %d, returning 0 (which is almost assuredly incorrect)\n", address_id); - return 0; -} diff --git a/addressbook/backend/ebook/e-card-simple.h b/addressbook/backend/ebook/e-card-simple.h deleted file mode 100644 index 868d4e1573..0000000000 --- a/addressbook/backend/ebook/e-card-simple.h +++ /dev/null @@ -1,234 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: - * Chris Lahey - * Arturo Espinosa - * Nat Friedman (nat@ximian.com) - * - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 1999 The Free Software Foundation - */ - -#ifndef __E_CARD_SIMPLE_H__ -#define __E_CARD_SIMPLE_H__ - -#include -#include -#include -#include -#include -#include - -#define E_TYPE_CARD_SIMPLE (e_card_simple_get_type ()) -#define E_CARD_SIMPLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CARD_SIMPLE, ECardSimple)) -#define E_CARD_SIMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CARD_SIMPLE, ECardSimpleClass)) -#define E_IS_CARD_SIMPLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CARD_SIMPLE)) -#define E_IS_CARD_SIMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CARD_SIMPLE)) -#define E_CARD_SIMPLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CARD_SIMPLE, ECardSimpleClass)) - -typedef enum _ECardSimplePhoneId ECardSimplePhoneId; -typedef enum _ECardSimpleEmailId ECardSimpleEmailId; -typedef enum _ECardSimpleAddressId ECardSimpleAddressId; -typedef enum _ECardSimpleType ECardSimpleType; -typedef enum _ECardSimpleField ECardSimpleField; - -enum _ECardSimplePhoneId { - E_CARD_SIMPLE_PHONE_ID_ASSISTANT, - E_CARD_SIMPLE_PHONE_ID_BUSINESS, - E_CARD_SIMPLE_PHONE_ID_BUSINESS_2, - E_CARD_SIMPLE_PHONE_ID_BUSINESS_FAX, - E_CARD_SIMPLE_PHONE_ID_CALLBACK, - E_CARD_SIMPLE_PHONE_ID_CAR, - E_CARD_SIMPLE_PHONE_ID_COMPANY, - E_CARD_SIMPLE_PHONE_ID_HOME, - E_CARD_SIMPLE_PHONE_ID_HOME_2, - E_CARD_SIMPLE_PHONE_ID_HOME_FAX, - E_CARD_SIMPLE_PHONE_ID_ISDN, - E_CARD_SIMPLE_PHONE_ID_MOBILE, - E_CARD_SIMPLE_PHONE_ID_OTHER, - E_CARD_SIMPLE_PHONE_ID_OTHER_FAX, - E_CARD_SIMPLE_PHONE_ID_PAGER, - E_CARD_SIMPLE_PHONE_ID_PRIMARY, - E_CARD_SIMPLE_PHONE_ID_RADIO, - E_CARD_SIMPLE_PHONE_ID_TELEX, - E_CARD_SIMPLE_PHONE_ID_TTYTDD, - E_CARD_SIMPLE_PHONE_ID_LAST -}; - -/* We need HOME and WORK email addresses here. */ -enum _ECardSimpleEmailId { - E_CARD_SIMPLE_EMAIL_ID_EMAIL, - E_CARD_SIMPLE_EMAIL_ID_EMAIL_2, - E_CARD_SIMPLE_EMAIL_ID_EMAIL_3, - E_CARD_SIMPLE_EMAIL_ID_LAST -}; - -/* Should this include (BILLING/SHIPPING)? */ -enum _ECardSimpleAddressId { - E_CARD_SIMPLE_ADDRESS_ID_BUSINESS, - E_CARD_SIMPLE_ADDRESS_ID_HOME, - E_CARD_SIMPLE_ADDRESS_ID_OTHER, - E_CARD_SIMPLE_ADDRESS_ID_LAST -}; - -enum _ECardSimpleType { - E_CARD_SIMPLE_TYPE_STRING, - E_CARD_SIMPLE_TYPE_DATE, - E_CARD_SIMPLE_TYPE_BOOL, -}; - -enum _ECardSimpleField { - E_CARD_SIMPLE_FIELD_FILE_AS, - E_CARD_SIMPLE_FIELD_FULL_NAME, - E_CARD_SIMPLE_FIELD_EMAIL, - E_CARD_SIMPLE_FIELD_PHONE_PRIMARY, - E_CARD_SIMPLE_FIELD_PHONE_ASSISTANT, - E_CARD_SIMPLE_FIELD_PHONE_BUSINESS, - E_CARD_SIMPLE_FIELD_PHONE_CALLBACK, - E_CARD_SIMPLE_FIELD_PHONE_COMPANY, - E_CARD_SIMPLE_FIELD_PHONE_HOME, - E_CARD_SIMPLE_FIELD_ORG, - E_CARD_SIMPLE_FIELD_ADDRESS_BUSINESS, - E_CARD_SIMPLE_FIELD_ADDRESS_HOME, - E_CARD_SIMPLE_FIELD_PHONE_MOBILE, - E_CARD_SIMPLE_FIELD_PHONE_CAR, - E_CARD_SIMPLE_FIELD_PHONE_BUSINESS_FAX, - E_CARD_SIMPLE_FIELD_PHONE_HOME_FAX, - E_CARD_SIMPLE_FIELD_PHONE_BUSINESS_2, - E_CARD_SIMPLE_FIELD_PHONE_HOME_2, - E_CARD_SIMPLE_FIELD_PHONE_ISDN, - E_CARD_SIMPLE_FIELD_PHONE_OTHER, - E_CARD_SIMPLE_FIELD_PHONE_OTHER_FAX, - E_CARD_SIMPLE_FIELD_PHONE_PAGER, - E_CARD_SIMPLE_FIELD_PHONE_RADIO, - E_CARD_SIMPLE_FIELD_PHONE_TELEX, - E_CARD_SIMPLE_FIELD_PHONE_TTYTDD, - E_CARD_SIMPLE_FIELD_ADDRESS_OTHER, - E_CARD_SIMPLE_FIELD_EMAIL_2, - E_CARD_SIMPLE_FIELD_EMAIL_3, - E_CARD_SIMPLE_FIELD_URL, - E_CARD_SIMPLE_FIELD_ORG_UNIT, - E_CARD_SIMPLE_FIELD_OFFICE, - E_CARD_SIMPLE_FIELD_TITLE, - E_CARD_SIMPLE_FIELD_ROLE, - E_CARD_SIMPLE_FIELD_MANAGER, - E_CARD_SIMPLE_FIELD_ASSISTANT, - E_CARD_SIMPLE_FIELD_NICKNAME, - E_CARD_SIMPLE_FIELD_SPOUSE, - E_CARD_SIMPLE_FIELD_NOTE, - E_CARD_SIMPLE_FIELD_CALURI, - E_CARD_SIMPLE_FIELD_FBURL, - E_CARD_SIMPLE_FIELD_ICSCALENDAR, - /* If you add after icscalendar, make sure to move LAST_SIMPLE_STRING */ - E_CARD_SIMPLE_FIELD_LAST_SIMPLE_STRING = E_CARD_SIMPLE_FIELD_ICSCALENDAR, - E_CARD_SIMPLE_FIELD_ANNIVERSARY, - E_CARD_SIMPLE_FIELD_BIRTH_DATE, - E_CARD_SIMPLE_FIELD_MAILER, - E_CARD_SIMPLE_FIELD_NAME_OR_ORG, - E_CARD_SIMPLE_FIELD_CATEGORIES, - E_CARD_SIMPLE_FIELD_FAMILY_NAME, - E_CARD_SIMPLE_FIELD_GIVEN_NAME, - E_CARD_SIMPLE_FIELD_ADDITIONAL_NAME, - E_CARD_SIMPLE_FIELD_NAME_SUFFIX, - E_CARD_SIMPLE_FIELD_WANTS_HTML, - E_CARD_SIMPLE_FIELD_IS_LIST, - E_CARD_SIMPLE_FIELD_LAST -}; - -typedef struct _ECardSimple ECardSimple; -typedef struct _ECardSimpleClass ECardSimpleClass; - -struct _ECardSimple { - GObject object; - ECard *card; - - GList *temp_fields; - - ECardPhone *phone[E_CARD_SIMPLE_PHONE_ID_LAST]; - char *email[E_CARD_SIMPLE_EMAIL_ID_LAST]; - ECardAddrLabel *address[E_CARD_SIMPLE_ADDRESS_ID_LAST]; - ECardDeliveryAddress *delivery[E_CARD_SIMPLE_ADDRESS_ID_LAST]; - - gboolean changed; -}; - -struct _ECardSimpleClass { - GObjectClass parent_class; -}; - -typedef void (*ECardSimpleArbitraryCallback) (const ECardArbitrary *arbitrary, gpointer closure); -ECardSimple *e_card_simple_new (ECard *card); -const char *e_card_simple_get_id (ECardSimple *simple); -void e_card_simple_set_id (ECardSimple *simple, - const gchar *character); -char *e_card_simple_get_vcard (ECardSimple *simple); -char *e_card_simple_get_vcard_assume_utf8 (ECardSimple *simple); -ECardSimple *e_card_simple_duplicate (ECardSimple *simple); -char *e_card_simple_get (ECardSimple *simple, - ECardSimpleField field); -const char *e_card_simple_get_const (ECardSimple *simple, - ECardSimpleField field); -void e_card_simple_set (ECardSimple *simple, - ECardSimpleField field, - const char *data); -ECardSimpleType e_card_simple_type (ECardSimple *simple, - ECardSimpleField field); - -const char *e_card_simple_get_ecard_field (ECardSimple *simple, - ECardSimpleField field); -const char *e_card_simple_get_name (ECardSimple *simple, - ECardSimpleField field); -const char *e_card_simple_get_short_name (ECardSimple *simple, - ECardSimpleField field); -gboolean e_card_simple_get_allow_newlines (ECardSimple *simple, - ECardSimpleField field); - - -/* Use these only if building lists of specific types. It should be - * easier to use the above if you consider a phone field to be the - * same as any other field. - */ -const ECardPhone *e_card_simple_get_phone (ECardSimple *simple, - ECardSimplePhoneId id); -const char *e_card_simple_get_email (ECardSimple *simple, - ECardSimpleEmailId id); -const ECardAddrLabel *e_card_simple_get_address (ECardSimple *simple, - ECardSimpleAddressId id); -const ECardDeliveryAddress *e_card_simple_get_delivery_address (ECardSimple *simple, - ECardSimpleAddressId id); -void e_card_simple_set_phone (ECardSimple *simple, - ECardSimplePhoneId id, - const ECardPhone *phone); -void e_card_simple_set_email (ECardSimple *simple, - ECardSimpleEmailId id, - const char *email); -void e_card_simple_set_address (ECardSimple *simple, - ECardSimpleAddressId id, - const ECardAddrLabel *address); -void e_card_simple_set_delivery_address (ECardSimple *simple, - ECardSimpleAddressId id, - const ECardDeliveryAddress *delivery); -void e_card_simple_arbitrary_foreach (ECardSimple *simple, - ECardSimpleArbitraryCallback *callback, - gpointer closure); -const ECardArbitrary *e_card_simple_get_arbitrary (ECardSimple *simple, - const char *key); -/* Any of these except key can be NULL */ -void e_card_simple_set_arbitrary (ECardSimple *simple, - const char *key, - const char *type, - const char *value); -void e_card_simple_set_name (ECardSimple *simple, - ECardName *name); -void e_card_simple_sync_card (ECardSimple *simple); - -/* These map between the individual list types and ECardSimpleField */ -ECardSimpleField e_card_simple_map_phone_to_field (ECardSimplePhoneId phone_id); -ECardSimpleField e_card_simple_map_email_to_field (ECardSimpleEmailId email_id); -ECardSimpleField e_card_simple_map_address_to_field (ECardSimpleAddressId address_id); - -GType e_card_simple_get_type (void); - -#endif /* ! __E_CARD_SIMPLE_H__ */ - - diff --git a/addressbook/backend/ebook/e-card-types.h b/addressbook/backend/ebook/e-card-types.h deleted file mode 100644 index 8d35c54924..0000000000 --- a/addressbook/backend/ebook/e-card-types.h +++ /dev/null @@ -1,101 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: - * Arturo Espinosa - * Nat Friedman (nat@ximian.com) - * - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 1999 The Free Software Foundation - */ - -#ifndef __E_CARD_TYPES_H__ -#define __E_CARD_TYPES_H__ - -/* IDENTIFICATION PROPERTIES */ - -typedef struct { - gint ref_count; - char *prefix; /* Mr. */ - char *given; /* John */ - char *additional; /* Quinlan */ - char *family; /* Public */ - char *suffix; /* Esq. */ -} ECardName; - -typedef struct { - int year; - int month; - int day; -} ECardDate; - -/* TELECOMMUNICATIONS ADDRESSING PROPERTIES */ - -typedef enum { - E_CARD_PHONE_PREF = 1 << 0, - E_CARD_PHONE_WORK = 1 << 1, - E_CARD_PHONE_HOME = 1 << 2, - E_CARD_PHONE_VOICE = 1 << 3, - E_CARD_PHONE_FAX = 1 << 4, - E_CARD_PHONE_MSG = 1 << 5, - E_CARD_PHONE_CELL = 1 << 6, - E_CARD_PHONE_PAGER = 1 << 7, - E_CARD_PHONE_BBS = 1 << 8, - E_CARD_PHONE_MODEM = 1 << 9, - E_CARD_PHONE_CAR = 1 << 10, - E_CARD_PHONE_ISDN = 1 << 11, - E_CARD_PHONE_VIDEO = 1 << 12, - E_CARD_PHONE_ASSISTANT = 1 << 13, - E_CARD_PHONE_CALLBACK = 1 << 14, - E_CARD_PHONE_RADIO = 1 << 15, - E_CARD_PHONE_TELEX = 1 << 16, - E_CARD_PHONE_TTYTDD = 1 << 17, -} ECardPhoneFlags; - -typedef struct { - gint ref_count; - ECardPhoneFlags flags; - char *number; -} ECardPhone; - -/* DELIVERY ADDRESSING PROPERTIES */ - -typedef enum { - E_CARD_ADDR_HOME = 1 << 0, - E_CARD_ADDR_WORK = 1 << 1, - E_CARD_ADDR_POSTAL = 1 << 2, - E_CARD_ADDR_MASK = 7, - E_CARD_ADDR_PARCEL = 1 << 3, - E_CARD_ADDR_DOM = 1 << 4, - E_CARD_ADDR_INTL = 1 << 5, - E_CARD_ADDR_DEFAULT = 1 << 6 -} ECardAddressFlags; - -typedef struct { - gint ref_count; - ECardAddressFlags flags; - - char *po; - char *ext; - char *street; - char *city; - char *region; - char *code; - char *country; -} ECardDeliveryAddress; - -typedef struct { - gint ref_count; - ECardAddressFlags flags; - char *data; -} ECardAddrLabel; - -/* ARBITRARY PROPERTIES */ - -typedef struct { - gint ref_count; - char *key; - char *type; - char *value; -} ECardArbitrary; - -#endif /* __E_CARD_TYPES_H__ */ diff --git a/addressbook/backend/ebook/e-card.c b/addressbook/backend/ebook/e-card.c deleted file mode 100644 index 1b3bbfba88..0000000000 --- a/addressbook/backend/ebook/e-card.c +++ /dev/null @@ -1,2807 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: - * Arturo Espinosa (arturo@nuclecu.unam.mx) - * Nat Friedman (nat@ximian.com) - * - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 1999 The Free Software Foundation - */ - -#include - -#include "e-card.h" - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include "e-util/ename/e-name-western.h" -#include "e-util/ename/e-address-western.h" -#include "e-book.h" - -#define is_a_prop_of(obj,prop) (isAPropertyOf ((obj),(prop))) -#define str_val(obj) (the_str = (vObjectValueType (obj))? fakeCString (vObjectUStringZValue (obj)) : calloc (1, 1)) -#define has(obj,prop) (vo = isAPropertyOf ((obj), (prop))) - -#define XEV_WANTS_HTML "X-MOZILLA-HTML" -#define XEV_ARBITRARY "X-EVOLUTION-ARBITRARY" -#define XEV_LIST "X-EVOLUTION-LIST" -#define XEV_LIST_SHOW_ADDRESSES "X-EVOLUTION-LIST-SHOW_ADDRESSES" -#define XEV_RELATED_CONTACTS "X-EVOLUTION-RELATED_CONTACTS" - -/* Object property IDs */ -enum { - PROP_0, - PROP_FILE_AS, - PROP_FULL_NAME, - PROP_NAME, - PROP_ADDRESS, - PROP_ADDRESS_LABEL, - PROP_PHONE, - PROP_EMAIL, - PROP_BIRTH_DATE, - PROP_URL, - PROP_ORG, - PROP_ORG_UNIT, - PROP_OFFICE, - PROP_TITLE, - PROP_ROLE, - PROP_MANAGER, - PROP_ASSISTANT, - PROP_NICKNAME, - PROP_SPOUSE, - PROP_ANNIVERSARY, - PROP_MAILER, - PROP_CALURI, - PROP_FBURL, - PROP_ICSCALENDAR, - PROP_NOTE, - PROP_RELATED_CONTACTS, - PROP_CATEGORIES, - PROP_CATEGORY_LIST, - PROP_WANTS_HTML, - PROP_WANTS_HTML_SET, - PROP_EVOLUTION_LIST, - PROP_EVOLUTION_LIST_SHOW_ADDRESSES, - PROP_ARBITRARY, - PROP_ID, - PROP_LAST_USE, - PROP_USE_SCORE, -}; - -static GObjectClass *parent_class; - -static void parse(ECard *card, VObject *vobj, const char *default_charset); -static void e_card_init (ECard *card); -static void e_card_class_init (ECardClass *klass); - -static void e_card_dispose (GObject *object); -static void e_card_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void e_card_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); - -static void assign_string(VObject *vobj, const char *default_charset, char **string); - -char *e_v_object_get_child_value(VObject *vobj, char *name, const char *default_charset); - -static void parse_bday(ECard *card, VObject *object, const char *default_charset); -static void parse_full_name(ECard *card, VObject *object, const char *default_charset); -static void parse_file_as(ECard *card, VObject *object, const char *default_charset); -static void parse_name(ECard *card, VObject *object, const char *default_charset); -static void parse_email(ECard *card, VObject *object, const char *default_charset); -static void parse_phone(ECard *card, VObject *object, const char *default_charset); -static void parse_address(ECard *card, VObject *object, const char *default_charset); -static void parse_address_label(ECard *card, VObject *object, const char *default_charset); -static void parse_url(ECard *card, VObject *object, const char *default_charset); -static void parse_org(ECard *card, VObject *object, const char *default_charset); -static void parse_office(ECard *card, VObject *object, const char *default_charset); -static void parse_title(ECard *card, VObject *object, const char *default_charset); -static void parse_role(ECard *card, VObject *object, const char *default_charset); -static void parse_manager(ECard *card, VObject *object, const char *default_charset); -static void parse_assistant(ECard *card, VObject *object, const char *default_charset); -static void parse_nickname(ECard *card, VObject *object, const char *default_charset); -static void parse_spouse(ECard *card, VObject *object, const char *default_charset); -static void parse_anniversary(ECard *card, VObject *object, const char *default_charset); -static void parse_mailer(ECard *card, VObject *object, const char *default_charset); -static void parse_caluri(ECard *card, VObject *object, const char *default_charset); -static void parse_fburl(ECard *card, VObject *object, const char *default_charset); -static void parse_icscalendar(ECard *card, VObject *object, const char *default_charset); -static void parse_note(ECard *card, VObject *object, const char *default_charset); -static void parse_related_contacts(ECard *card, VObject *object, const char *default_charset); -static void parse_categories(ECard *card, VObject *object, const char *default_charset); -static void parse_wants_html(ECard *card, VObject *object, const char *default_charset); -static void parse_list(ECard *card, VObject *object, const char *default_charset); -static void parse_list_show_addresses(ECard *card, VObject *object, const char *default_charset); -static void parse_arbitrary(ECard *card, VObject *object, const char *default_charset); -static void parse_id(ECard *card, VObject *object, const char *default_charset); -static void parse_last_use(ECard *card, VObject *object, const char *default_charset); -static void parse_use_score(ECard *card, VObject *object, const char *default_charset); - -static ECardPhoneFlags get_phone_flags (VObject *vobj); -static void set_phone_flags (VObject *vobj, ECardPhoneFlags flags); -static ECardAddressFlags get_address_flags (VObject *vobj); -static void set_address_flags (VObject *vobj, ECardAddressFlags flags); - -typedef void (* ParsePropertyFunc) (ECard *card, VObject *object, const char *default_charset); - -struct { - char *key; - ParsePropertyFunc function; -} attribute_jump_array[] = -{ - { VCFullNameProp, parse_full_name }, - { "X-EVOLUTION-FILE-AS", parse_file_as }, - { VCNameProp, parse_name }, - { VCBirthDateProp, parse_bday }, - { VCEmailAddressProp, parse_email }, - { VCTelephoneProp, parse_phone }, - { VCAdrProp, parse_address }, - { VCDeliveryLabelProp, parse_address_label }, - { VCURLProp, parse_url }, - { VCOrgProp, parse_org }, - { "X-EVOLUTION-OFFICE", parse_office }, - { VCTitleProp, parse_title }, - { VCBusinessRoleProp, parse_role }, - { "X-EVOLUTION-MANAGER", parse_manager }, - { "X-EVOLUTION-ASSISTANT", parse_assistant }, - { "NICKNAME", parse_nickname }, - { "X-EVOLUTION-SPOUSE", parse_spouse }, - { "X-EVOLUTION-ANNIVERSARY", parse_anniversary }, - { VCMailerProp, parse_mailer }, - { "CALURI", parse_caluri }, - { "FBURL", parse_fburl }, - { "ICSCALENDAR", parse_icscalendar }, - { VCNoteProp, parse_note }, - { XEV_RELATED_CONTACTS, parse_related_contacts }, - { "CATEGORIES", parse_categories }, - { XEV_WANTS_HTML, parse_wants_html }, - { XEV_ARBITRARY, parse_arbitrary }, - { VCUniqueStringProp, parse_id }, - { "X-EVOLUTION-LAST-USE", parse_last_use }, - { "X-EVOLUTION-USE-SCORE", parse_use_score }, - { XEV_LIST, parse_list }, - { XEV_LIST_SHOW_ADDRESSES, parse_list_show_addresses }, - { VCUniqueStringProp, parse_id } -}; - -/** - * e_card_get_type: - * @void: - * - * Registers the &ECard class if necessary, and returns the type ID - * associated to it. - * - * Return value: The type ID of the &ECard class. - **/ -GType -e_card_get_type (void) -{ - static GType card_type = 0; - - if (!card_type) { - static const GTypeInfo card_info = { - sizeof (ECardClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) e_card_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (ECard), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_card_init, - }; - - card_type = g_type_register_static (G_TYPE_OBJECT, "ECard", &card_info, 0); - } - - return card_type; -} - -ECard * -e_card_new_with_default_charset (const char *vcard, const char *default_charset) -{ - ECard *card = g_object_new (E_TYPE_CARD, NULL); - VObject *vobj = Parse_MIME(vcard, strlen(vcard)); - while(vobj) { - VObject *next; - parse(card, vobj, default_charset); - next = nextVObjectInList(vobj); - cleanVObject(vobj); - vobj = next; - } - if (card->name == NULL) - card->name = e_card_name_new(); - if (card->file_as == NULL) - card->file_as = g_strdup(""); - if (card->fname == NULL) - card->fname = g_strdup(""); - return card; -} - -/** - * e_card_new: - * @vcard: a string in vCard format - * - * Returns: a new #ECard that wraps the @vcard. - */ -ECard * -e_card_new (const char *vcard) -{ - return e_card_new_with_default_charset (vcard, "UTF-8"); -} - -ECard * -e_card_duplicate(ECard *card) -{ - char *vcard = e_card_get_vcard_assume_utf8(card); - ECard *new_card = e_card_new(vcard); - g_free (vcard); - - if (card->book) { - new_card->book = card->book; - g_object_ref (new_card->book); - } - - return new_card; -} - -static void -e_card_get_today (GDate *dt) -{ - time_t now; - struct tm *now_tm; - if (dt == NULL) - return; - - time (&now); - now_tm = localtime (&now); - - g_date_set_dmy (dt, now_tm->tm_mday, now_tm->tm_mon + 1, now_tm->tm_year + 1900); -} - -float -e_card_get_use_score(ECard *card) -{ - GDate today, last_use; - gint days_since_last_use; - - g_return_val_if_fail (card != NULL && E_IS_CARD (card), 0); - - if (card->last_use == NULL) - return 0.0; - - e_card_get_today (&today); - g_date_set_dmy (&last_use, card->last_use->day, card->last_use->month, card->last_use->year); - - days_since_last_use = g_date_get_julian (&today) - g_date_get_julian (&last_use); - - /* Apply a seven-day "grace period" to the use score decay. */ - days_since_last_use -= 7; - if (days_since_last_use < 0) - days_since_last_use = 0; - - return MAX (card->raw_use_score, 0) * exp (- days_since_last_use / 30.0); -} - -void -e_card_touch(ECard *card) -{ - GDate today; - double use_score; - - g_return_if_fail (card != NULL && E_IS_CARD (card)); - - e_card_get_today (&today); - use_score = e_card_get_use_score (card); - - if (card->last_use == NULL) - card->last_use = g_new (ECardDate, 1); - - card->last_use->day = g_date_get_day (&today); - card->last_use->month = g_date_get_month (&today); - card->last_use->year = g_date_get_year (&today); - - card->raw_use_score = use_score + 1.0; -} - -/** - * e_card_get_id: - * @card: an #ECard - * - * Returns: a string representing the id of the card, which is unique - * within its book. - */ -const char * -e_card_get_id (ECard *card) -{ - g_return_val_if_fail (card && E_IS_CARD (card), NULL); - - return card->id ? card->id : ""; -} - -/** - * e_card_get_id: - * @card: an #ECard - * @id: a id in string format - * - * Sets the identifier of a card, which should be unique within its - * book. - */ -void -e_card_set_id (ECard *card, const char *id) -{ - g_return_if_fail (card && E_IS_CARD (card)); - - if ( card->id ) - g_free(card->id); - card->id = g_strdup(id ? id : ""); -} - -EBook * -e_card_get_book (ECard *card) -{ - g_return_val_if_fail (card && E_IS_CARD (card), NULL); - - return card->book; -} - -void -e_card_set_book (ECard *card, EBook *book) -{ - g_return_if_fail (card && E_IS_CARD (card)); - - if (card->book) - g_object_unref (card->book); - card->book = book; - if (card->book) - g_object_ref (card->book); -} - -gchar * -e_card_date_to_string (ECardDate *dt) -{ - if (dt) - return g_strdup_printf ("%04d-%02d-%02d", - CLAMP(dt->year, 1000, 9999), - CLAMP(dt->month, 1, 12), - CLAMP(dt->day, 1, 31)); - else - return NULL; -} - -static VObject * -addPropValueUTF8(VObject *o, const char *p, const char *v) -{ - VObject *prop = addPropValue (o, p, v); - for (; *v; v++) { - if ((*v) & 0x80) { - addPropValue (prop, "CHARSET", "UTF-8"); - addProp(prop, VCQuotedPrintableProp); - - return prop; - } - if (*v == '\n') { - addProp(prop, VCQuotedPrintableProp); - for (; *v; v++) { - if ((*v) & 0x80) { - addPropValue (prop, "CHARSET", "UTF-8"); - return prop; - } - } - return prop; - } - } - return prop; -} - -static VObject * -addPropValueQP(VObject *o, const char *p, const char *v) -{ - VObject *prop = addPropValue (o, p, v); - for (; *v; v++) { - if (*v == '\n') { - addProp(prop, VCQuotedPrintableProp); - break; - } - } - return prop; -} - -static void -addPropValueSets (VObject *o, const char *p, const char *v, gboolean assumeUTF8, gboolean *is_ascii, gboolean *has_return) -{ - addPropValue (o, p, v); - if (*has_return && (assumeUTF8 || !*is_ascii)) - return; - if (*has_return) { - for (; *v; v++) { - if (*v & 0x80) { - *is_ascii = FALSE; - return; - } - } - return; - } - if (assumeUTF8 || !*is_ascii) { - for (; *v; v++) { - if (*v == '\n') { - *has_return = TRUE; - return; - } - } - return; - } - for (; *v; v++) { - if (*v & 0x80) { - *is_ascii = FALSE; - for (; *v; v++) { - if (*v == '\n') { - *has_return = TRUE; - return; - } - } - return; - } - if (*v == '\n') { - *has_return = TRUE; - for (; *v; v++) { - if (*v & 0x80) { - *is_ascii = FALSE; - return; - } - } - return; - } - } - return; -} - -#define ADD_PROP_VALUE(o, p, v) (assumeUTF8 ? (addPropValueQP ((o), (p), (v))) : addPropValueUTF8 ((o), (p), (v))) -#define ADD_PROP_VALUE_SET_IS_ASCII(o, p, v) (addPropValueSets ((o), (p), (v), assumeUTF8, &is_ascii, &has_return)) - - -static VObject * -e_card_get_vobject (const ECard *card, gboolean assumeUTF8) -{ - VObject *vobj; - - vobj = newVObject (VCCardProp); - - ADD_PROP_VALUE(vobj, VCVersionProp, "2.1"); - - if (card->file_as && *card->file_as) - ADD_PROP_VALUE(vobj, "X-EVOLUTION-FILE-AS", card->file_as); - else if (card->file_as) - addProp(vobj, "X-EVOLUTION-FILE_AS"); - - if (card->fname && *card->fname) - ADD_PROP_VALUE(vobj, VCFullNameProp, card->fname); - else if (card->fname) - addProp(vobj, VCFullNameProp); - - if ( card->name && (card->name->prefix || card->name->given || card->name->additional || card->name->family || card->name->suffix) ) { - VObject *nameprop; - gboolean is_ascii = TRUE; - gboolean has_return = FALSE; - nameprop = addProp(vobj, VCNameProp); - if ( card->name->prefix ) - ADD_PROP_VALUE_SET_IS_ASCII(nameprop, VCNamePrefixesProp, card->name->prefix); - if ( card->name->given ) - ADD_PROP_VALUE_SET_IS_ASCII(nameprop, VCGivenNameProp, card->name->given); - if ( card->name->additional ) - ADD_PROP_VALUE_SET_IS_ASCII(nameprop, VCAdditionalNamesProp, card->name->additional); - if ( card->name->family ) - ADD_PROP_VALUE_SET_IS_ASCII(nameprop, VCFamilyNameProp, card->name->family); - if ( card->name->suffix ) - ADD_PROP_VALUE_SET_IS_ASCII(nameprop, VCNameSuffixesProp, card->name->suffix); - if (has_return) - addProp(nameprop, VCQuotedPrintableProp); - if (!(is_ascii || assumeUTF8)) - addPropValue (nameprop, "CHARSET", "UTF-8"); - } - else if (card->name) - addProp(vobj, VCNameProp); - - - if ( card->address ) { - EIterator *iterator = e_list_get_iterator(card->address); - for ( ; e_iterator_is_valid(iterator) ;e_iterator_next(iterator) ) { - VObject *addressprop; - ECardDeliveryAddress *address = (ECardDeliveryAddress *) e_iterator_get(iterator); - gboolean is_ascii = TRUE; - gboolean has_return = FALSE; - - addressprop = addProp(vobj, VCAdrProp); - - set_address_flags (addressprop, address->flags); - if (address->po) - ADD_PROP_VALUE_SET_IS_ASCII(addressprop, VCPostalBoxProp, address->po); - if (address->ext) - ADD_PROP_VALUE_SET_IS_ASCII(addressprop, VCExtAddressProp, address->ext); - if (address->street) - ADD_PROP_VALUE_SET_IS_ASCII(addressprop, VCStreetAddressProp, address->street); - if (address->city) - ADD_PROP_VALUE_SET_IS_ASCII(addressprop, VCCityProp, address->city); - if (address->region) - ADD_PROP_VALUE_SET_IS_ASCII(addressprop, VCRegionProp, address->region); - if (address->code) - ADD_PROP_VALUE_SET_IS_ASCII(addressprop, VCPostalCodeProp, address->code); - if (address->country) - ADD_PROP_VALUE_SET_IS_ASCII(addressprop, VCCountryNameProp, address->country); - - if (has_return) - addProp(addressprop, VCQuotedPrintableProp); - if (!(is_ascii || assumeUTF8)) - addPropValue (addressprop, "CHARSET", "UTF-8"); - } - g_object_unref(iterator); - } - - if ( card->address_label ) { - EIterator *iterator = e_list_get_iterator(card->address_label); - for ( ; e_iterator_is_valid(iterator) ;e_iterator_next(iterator) ) { - VObject *labelprop; - ECardAddrLabel *address_label = (ECardAddrLabel *) e_iterator_get(iterator); - if (address_label->data) - labelprop = ADD_PROP_VALUE(vobj, VCDeliveryLabelProp, address_label->data); - else - labelprop = addProp(vobj, VCDeliveryLabelProp); - - set_address_flags (labelprop, address_label->flags); - } - g_object_unref(iterator); - } - - if ( card->phone ) { - EIterator *iterator = e_list_get_iterator(card->phone); - for ( ; e_iterator_is_valid(iterator) ;e_iterator_next(iterator) ) { - VObject *phoneprop; - ECardPhone *phone = (ECardPhone *) e_iterator_get(iterator); - phoneprop = ADD_PROP_VALUE(vobj, VCTelephoneProp, phone->number); - - set_phone_flags (phoneprop, phone->flags); - } - g_object_unref(iterator); - } - - if ( card->email ) { - EIterator *iterator = e_list_get_iterator(card->email); - for ( ; e_iterator_is_valid(iterator) ;e_iterator_next(iterator) ) { - VObject *emailprop; - emailprop = ADD_PROP_VALUE(vobj, VCEmailAddressProp, (char *) e_iterator_get(iterator)); - addProp (emailprop, VCInternetProp); - } - g_object_unref(iterator); - } - - if ( card->bday ) { - char *value; - value = e_card_date_to_string (card->bday); - ADD_PROP_VALUE(vobj, VCBirthDateProp, value); - g_free(value); - } - - if (card->url) - ADD_PROP_VALUE(vobj, VCURLProp, card->url); - - if (card->org || card->org_unit) { - VObject *orgprop; - gboolean is_ascii = TRUE; - gboolean has_return = FALSE; - orgprop = addProp(vobj, VCOrgProp); - - if (card->org) - ADD_PROP_VALUE_SET_IS_ASCII(orgprop, VCOrgNameProp, card->org); - if (card->org_unit) - ADD_PROP_VALUE_SET_IS_ASCII(orgprop, VCOrgUnitProp, card->org_unit); - - if (has_return) - addProp(orgprop, VCQuotedPrintableProp); - if (!(is_ascii || assumeUTF8)) - addPropValue (orgprop, "CHARSET", "UTF-8"); - } - - if (card->office) - ADD_PROP_VALUE(vobj, "X-EVOLUTION-OFFICE", card->office); - - if (card->title) - ADD_PROP_VALUE(vobj, VCTitleProp, card->title); - - if (card->role) - ADD_PROP_VALUE(vobj, VCBusinessRoleProp, card->role); - - if (card->manager) - ADD_PROP_VALUE(vobj, "X-EVOLUTION-MANAGER", card->manager); - - if (card->assistant) - ADD_PROP_VALUE(vobj, "X-EVOLUTION-ASSISTANT", card->assistant); - - if (card->nickname) - ADD_PROP_VALUE(vobj, "NICKNAME", card->nickname); - - if (card->spouse) - ADD_PROP_VALUE(vobj, "X-EVOLUTION-SPOUSE", card->spouse); - - if ( card->anniversary ) { - char *value; - value = e_card_date_to_string (card->anniversary); - ADD_PROP_VALUE(vobj, "X-EVOLUTION-ANNIVERSARY", value); - g_free(value); - } - - if (card->mailer) { - ADD_PROP_VALUE(vobj, VCMailerProp, card->mailer); - } - - if (card->caluri) - addPropValueQP(vobj, "CALURI", card->caluri); - - if (card->fburl) - ADD_PROP_VALUE(vobj, "FBURL", card->fburl); - - if (card->icscalendar) - ADD_PROP_VALUE(vobj, "ICSCALENDAR", card->icscalendar); - - if (card->note) { - VObject *noteprop; - - noteprop = ADD_PROP_VALUE(vobj, VCNoteProp, card->note); - } - - if (card->last_use) { - char *value; - value = e_card_date_to_string (card->last_use); - ADD_PROP_VALUE (vobj, "X-EVOLUTION-LAST-USE", value); - g_free (value); - } - - if (card->raw_use_score > 0) { - char *value; - value = g_strdup_printf ("%f", card->raw_use_score); - ADD_PROP_VALUE (vobj, "X-EVOLUTION-USE-SCORE", value); - g_free (value); - } - - if (card->related_contacts && *card->related_contacts) { - ADD_PROP_VALUE(vobj, XEV_RELATED_CONTACTS, card->related_contacts); - } - - if (card->categories) { - EIterator *iterator; - int length = 0; - char *string; - char *stringptr; - for (iterator = e_list_get_iterator(card->categories); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - length += strlen(e_iterator_get(iterator)) + 1; - } - string = g_new(char, length + 1); - stringptr = string; - *stringptr = 0; - for (e_iterator_reset(iterator); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - strcpy(stringptr, e_iterator_get(iterator)); - stringptr += strlen(stringptr); - *stringptr = ','; - stringptr++; - *stringptr = 0; - } - if (stringptr > string) { - stringptr --; - *stringptr = 0; - } - ADD_PROP_VALUE (vobj, "CATEGORIES", string); - g_free(string); - } - - if (card->wants_html_set) { - ADD_PROP_VALUE (vobj, XEV_WANTS_HTML, card->wants_html ? "TRUE" : "FALSE"); - } - - if (card->list) { - ADD_PROP_VALUE (vobj, XEV_LIST, "TRUE"); - ADD_PROP_VALUE (vobj, XEV_LIST_SHOW_ADDRESSES, card->list_show_addresses ? "TRUE" : "FALSE"); - } - - if (card->arbitrary) { - EIterator *iterator; - for (iterator = e_list_get_iterator(card->arbitrary); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - const ECardArbitrary *arbitrary = e_iterator_get(iterator); - VObject *arb_object; - if (arbitrary->value) { - arb_object = ADD_PROP_VALUE (vobj, XEV_ARBITRARY, arbitrary->value); - } else { - arb_object = addProp (vobj, XEV_ARBITRARY); - } - if (arbitrary->type) { - ADD_PROP_VALUE (arb_object, "TYPE", arbitrary->type); - } - if (arbitrary->key) { - addProp (arb_object, arbitrary->key); - } - } - } - - addPropValueQP (vobj, VCUniqueStringProp, (card->id ? card->id : "")); - - return vobj; -} - -/** - * e_card_get_vcard: - * @card: an #ECard - * - * Returns: a string in vCard format, which is wrapped by the @card. - */ -char * -e_card_get_vcard (ECard *card) -{ - VObject *vobj; - char *temp, *ret_val; - - vobj = e_card_get_vobject (card, FALSE); - temp = writeMemVObject(NULL, NULL, vobj); - ret_val = g_strdup(temp); - free(temp); - cleanVObject(vobj); - return ret_val; -} - -char * -e_card_get_vcard_assume_utf8 (ECard *card) -{ - VObject *vobj; - char *temp, *ret_val; - - vobj = e_card_get_vobject (card, TRUE); - temp = writeMemVObject(NULL, NULL, vobj); - ret_val = g_strdup(temp); - free(temp); - cleanVObject(vobj); - return ret_val; -} - -/** - * e_card_list_get_vcard: - * @list: a list of #ECards - * - * Returns: a string in vCard format. - */ -char * -e_card_list_get_vcard (const GList *list) -{ - VObject *vobj; - - char *temp, *ret_val; - - vobj = NULL; - - for (; list; list = list->next) { - VObject *tempvobj; - ECard *card = list->data; - - tempvobj = e_card_get_vobject (card, FALSE); - addList (&vobj, tempvobj); - } - temp = writeMemVObjects(NULL, NULL, vobj); - ret_val = g_strdup(temp); - free(temp); - cleanVObjects(vobj); - return ret_val; -} - -static void -parse_file_as(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( card->file_as ) - g_free(card->file_as); - assign_string(vobj, default_charset, &(card->file_as)); -} - -static void -parse_name(ECard *card, VObject *vobj, const char *default_charset) -{ - e_card_name_unref(card->name); - - card->name = e_card_name_new(); - - card->name->family = e_v_object_get_child_value (vobj, VCFamilyNameProp, default_charset); - card->name->given = e_v_object_get_child_value (vobj, VCGivenNameProp, default_charset); - card->name->additional = e_v_object_get_child_value (vobj, VCAdditionalNamesProp, default_charset); - card->name->prefix = e_v_object_get_child_value (vobj, VCNamePrefixesProp, default_charset); - card->name->suffix = e_v_object_get_child_value (vobj, VCNameSuffixesProp, default_charset); -} - -static void -parse_full_name(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( card->fname ) - g_free(card->fname); - assign_string(vobj, default_charset, &(card->fname)); -} - -static void -parse_email(ECard *card, VObject *vobj, const char *default_charset) -{ - char *next_email; - EList *list; - - assign_string(vobj, default_charset, &next_email); - g_object_get(card, - "email", &list, - NULL); - e_list_append(list, next_email); - g_free (next_email); - g_object_unref(list); -} - -/* Deal with charset */ -static void -parse_bday(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( vObjectValueType (vobj) ) { - char *str = fakeCString (vObjectUStringZValue (vobj)); - if ( card->bday ) - g_free(card->bday); - card->bday = g_new(ECardDate, 1); - *(card->bday) = e_card_date_from_string(str); - free(str); - } -} - -static void -parse_phone(ECard *card, VObject *vobj, const char *default_charset) -{ - ECardPhone *next_phone = e_card_phone_new (); - EList *list; - - assign_string(vobj, default_charset, &(next_phone->number)); - next_phone->flags = get_phone_flags(vobj); - - g_object_get(card, - "phone", &list, - NULL); - e_list_append(list, next_phone); - e_card_phone_unref (next_phone); - g_object_unref(list); -} - -static void -parse_address(ECard *card, VObject *vobj, const char *default_charset) -{ - ECardDeliveryAddress *next_addr = e_card_delivery_address_new (); - EList *list; - - next_addr->flags = get_address_flags (vobj); - next_addr->po = e_v_object_get_child_value (vobj, VCPostalBoxProp, default_charset); - next_addr->ext = e_v_object_get_child_value (vobj, VCExtAddressProp, default_charset); - next_addr->street = e_v_object_get_child_value (vobj, VCStreetAddressProp, default_charset); - next_addr->city = e_v_object_get_child_value (vobj, VCCityProp, default_charset); - next_addr->region = e_v_object_get_child_value (vobj, VCRegionProp, default_charset); - next_addr->code = e_v_object_get_child_value (vobj, VCPostalCodeProp, default_charset); - next_addr->country = e_v_object_get_child_value (vobj, VCCountryNameProp, default_charset); - - g_object_get(card, - "address", &list, - NULL); - e_list_append(list, next_addr); - e_card_delivery_address_unref (next_addr); - g_object_unref(list); -} - -static void -parse_address_label(ECard *card, VObject *vobj, const char *default_charset) -{ - ECardAddrLabel *next_addr = e_card_address_label_new (); - EList *list; - - next_addr->flags = get_address_flags (vobj); - assign_string(vobj, default_charset, &next_addr->data); - - g_object_get(card, - "address_label", &list, - NULL); - e_list_append(list, next_addr); - e_card_address_label_unref (next_addr); - g_object_unref(list); -} - -static void -parse_url(ECard *card, VObject *vobj, const char *default_charset) -{ - if (card->url) - g_free(card->url); - assign_string(vobj, default_charset, &(card->url)); -} - -static void -parse_org(ECard *card, VObject *vobj, const char *default_charset) -{ - char *temp; - - temp = e_v_object_get_child_value(vobj, VCOrgNameProp, default_charset); - g_free(card->org); - card->org = temp; - - temp = e_v_object_get_child_value(vobj, VCOrgUnitProp, default_charset); - g_free(card->org_unit); - card->org_unit = temp; -} - -static void -parse_office(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( card->office ) - g_free(card->office); - assign_string(vobj, default_charset, &(card->office)); -} - -static void -parse_title(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( card->title ) - g_free(card->title); - assign_string(vobj, default_charset, &(card->title)); -} - -static void -parse_role(ECard *card, VObject *vobj, const char *default_charset) -{ - if (card->role) - g_free(card->role); - assign_string(vobj, default_charset, &(card->role)); -} - -static void -parse_manager(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( card->manager ) - g_free(card->manager); - assign_string(vobj, default_charset, &(card->manager)); -} - -static void -parse_assistant(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( card->assistant ) - g_free(card->assistant); - assign_string(vobj, default_charset, &(card->assistant)); -} - -static void -parse_nickname(ECard *card, VObject *vobj, const char *default_charset) -{ - if (card->nickname) - g_free(card->nickname); - assign_string(vobj, default_charset, &(card->nickname)); -} - -static void -parse_spouse(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( card->spouse ) - g_free(card->spouse); - assign_string(vobj, default_charset, &(card->spouse)); -} - -/* Deal with charset */ -static void -parse_anniversary(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( vObjectValueType (vobj) ) { - char *str = fakeCString (vObjectUStringZValue (vobj)); - if (card->anniversary) - g_free(card->anniversary); - card->anniversary = g_new(ECardDate, 1); - *(card->anniversary) = e_card_date_from_string(str); - free(str); - } -} - -static void -parse_mailer(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( card->mailer ) - g_free(card->mailer); - assign_string(vobj, default_charset, &(card->mailer)); -} - -static void -parse_caluri(ECard *card, VObject *vobj, const char *default_charset) -{ - g_free(card->caluri); - assign_string(vobj, default_charset, &(card->caluri)); -} - -static void -parse_fburl(ECard *card, VObject *vobj, const char *default_charset) -{ - g_free(card->fburl); - assign_string(vobj, default_charset, &(card->fburl)); -} - -static void -parse_icscalendar(ECard *card, VObject *vobj, const char *default_charset) -{ - g_free(card->icscalendar); - assign_string(vobj, default_charset, &(card->icscalendar)); -} - -static void -parse_note(ECard *card, VObject *vobj, const char *default_charset) -{ - g_free(card->note); - assign_string(vobj, default_charset, &(card->note)); -} - -static void -parse_related_contacts(ECard *card, VObject *vobj, const char *default_charset) -{ - g_free(card->related_contacts); - assign_string(vobj, default_charset, &(card->related_contacts)); -} - -static void -add_list_unique(ECard *card, EList *list, char *string) -{ - char *temp = e_strdup_strip(string); - EIterator *iterator; - - if (!*temp) { - g_free(temp); - return; - } - for ( iterator = e_list_get_iterator(list); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - if (!strcmp(e_iterator_get(iterator), temp)) { - break; - } - } - if (!e_iterator_is_valid(iterator)) { - e_list_append(list, temp); - } - g_free(temp); - g_object_unref(iterator); -} - -static void -do_parse_categories(ECard *card, char *str) -{ - int length = strlen(str); - char *copy = g_new(char, length + 1); - int i, j; - EList *list; - g_object_get(card, - "category_list", &list, - NULL); - for (i = 0, j = 0; str[i]; i++, j++) { - switch (str[i]) { - case '\\': - i++; - if (str[i]) { - copy[j] = str[i]; - } else - i--; - break; - case ',': - copy[j] = 0; - add_list_unique(card, list, copy); - j = -1; - break; - default: - copy[j] = str[i]; - break; - } - } - copy[j] = 0; - add_list_unique(card, list, copy); - g_object_unref(list); - g_free(copy); -} - -/* Deal with charset */ -static void -parse_categories(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( vObjectValueType (vobj) ) { - char *str = fakeCString (vObjectUStringZValue (vobj)); - do_parse_categories(card, str); - free(str); - } -} - -/* Deal with charset */ -static void -parse_wants_html(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( vObjectValueType (vobj) ) { - char *str = fakeCString (vObjectUStringZValue (vobj)); - if (!strcasecmp(str, "true")) { - card->wants_html = TRUE; - card->wants_html_set = TRUE; - } - if (!strcasecmp(str, "false")) { - card->wants_html = FALSE; - card->wants_html_set = TRUE; - } - free(str); - } -} - -/* Deal with charset */ -static void -parse_list(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( vObjectValueType (vobj) ) { - char *str = fakeCString (vObjectUStringZValue (vobj)); - if (!strcasecmp(str, "true")) { - card->list = TRUE; - } - if (!strcasecmp(str, "false")) { - card->list = FALSE; - } - free(str); - } -} - -/* Deal with charset */ -static void -parse_list_show_addresses(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( vObjectValueType (vobj) ) { - char *str = fakeCString (vObjectUStringZValue (vobj)); - if (!strcasecmp(str, "true")) { - card->list_show_addresses = TRUE; - } - if (!strcasecmp(str, "false")) { - card->list_show_addresses = FALSE; - } - free(str); - } -} - -typedef union ValueItem { - const char *strs; - const wchar_t *ustrs; - unsigned int i; - unsigned long l; - void *any; - VObject *vobj; -} ValueItem; - -struct VObject { - VObject *next; - const char *id; - VObject *prop; - unsigned short valType; - ValueItem val; -}; - -static void -parse_arbitrary(ECard *card, VObject *vobj, const char *default_charset) -{ - ECardArbitrary *arbitrary = e_card_arbitrary_new(); - VObjectIterator iterator; - EList *list; - for ( initPropIterator (&iterator, vobj); moreIteration(&iterator); ) { - VObject *temp = nextVObject(&iterator); - const char *name = vObjectName(temp); - if (name && !strcmp(name, "TYPE")) { - g_free(arbitrary->type); - assign_string(temp, default_charset, &(arbitrary->type)); - } else { - g_free(arbitrary->key); - arbitrary->key = g_strdup(name); - } - } - - assign_string(vobj, default_charset, &(arbitrary->value)); - - g_object_get(card, - "arbitrary", &list, - NULL); - e_list_append(list, arbitrary); - e_card_arbitrary_unref(arbitrary); - g_object_unref(list); -} - -static void -parse_id(ECard *card, VObject *vobj, const char *default_charset) -{ - g_free(card->id); - assign_string(vobj, default_charset, &(card->id)); -} - -/* Deal with charset */ -static void -parse_last_use(ECard *card, VObject *vobj, const char *default_charset) -{ - if ( vObjectValueType (vobj) ) { - char *str = fakeCString (vObjectUStringZValue (vobj)); - g_free(card->last_use); - card->last_use = g_new(ECardDate, 1); - *(card->last_use) = e_card_date_from_string(str); - free(str); - } -} - -/* Deal with charset */ -static void -parse_use_score(ECard *card, VObject *vobj, const char *default_charset) -{ - card->raw_use_score = 0; - - if ( vObjectValueType (vobj) ) { - char *str = fakeCString (vObjectUStringZValue (vobj)); - card->raw_use_score = MAX(0, atof (str)); - free (str); - } -} - -static void -parse_attribute(ECard *card, VObject *vobj, const char *default_charset) -{ - ParsePropertyFunc function = g_hash_table_lookup(E_CARD_GET_CLASS(card)->attribute_jump_table, vObjectName(vobj)); - if ( function ) - function(card, vobj, default_charset); -} - -static void -parse(ECard *card, VObject *vobj, const char *default_charset) -{ - VObjectIterator iterator; - initPropIterator(&iterator, vobj); - while(moreIteration (&iterator)) { - parse_attribute(card, nextVObject(&iterator), default_charset); - } - if (!card->fname) { - card->fname = g_strdup(""); - } - if (!card->name) { - card->name = e_card_name_from_string(card->fname); - } - if (!card->file_as) { - ECardName *name = card->name; - char *strings[3], **stringptr; - char *string; - stringptr = strings; - if (name->family && *name->family) - *(stringptr++) = name->family; - if (name->given && *name->given) - *(stringptr++) = name->given; - *stringptr = NULL; - string = g_strjoinv(", ", strings); - card->file_as = string; - } -} - -static void -e_card_class_init (ECardClass *klass) -{ - int i; - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS(klass); - - parent_class = g_type_class_ref (G_TYPE_OBJECT); - - klass->attribute_jump_table = g_hash_table_new(g_str_hash, g_str_equal); - - for ( i = 0; i < sizeof(attribute_jump_array) / sizeof(attribute_jump_array[0]); i++ ) { - g_hash_table_insert(klass->attribute_jump_table, attribute_jump_array[i].key, attribute_jump_array[i].function); - } - - object_class->dispose = e_card_dispose; - object_class->get_property = e_card_get_property; - object_class->set_property = e_card_set_property; - - g_object_class_install_property (object_class, PROP_FILE_AS, - g_param_spec_string ("file_as", - _("File As"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_FULL_NAME, - g_param_spec_string ("full_name", - _("Full Name"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_NAME, - g_param_spec_pointer ("name", - _("Name"), - /*_( */"XXX blurb" /*)*/, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ADDRESS, - g_param_spec_object ("address", - _("Address"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_LIST, - G_PARAM_READABLE)); - - g_object_class_install_property (object_class, PROP_ADDRESS_LABEL, - g_param_spec_object ("address_label", - _("Address Label"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_LIST, - G_PARAM_READABLE)); - - g_object_class_install_property (object_class, PROP_PHONE, - g_param_spec_object ("phone", - _("Phone"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_LIST, - G_PARAM_READABLE)); - - g_object_class_install_property (object_class, PROP_EMAIL, - g_param_spec_object ("email", - _("Email"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_LIST, - G_PARAM_READABLE)); - - g_object_class_install_property (object_class, PROP_BIRTH_DATE, - g_param_spec_pointer ("birth_date", - _("Birth date"), - /*_( */"XXX blurb" /*)*/, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_URL, - g_param_spec_string ("url", - _("URL"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ORG, - g_param_spec_string ("org", - _("Organization"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ORG_UNIT, - g_param_spec_string ("org_unit", - _("Organizational Unit"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_OFFICE, - g_param_spec_string ("office", - _("Office"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_TITLE, - g_param_spec_string ("title", - _("Title"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ROLE, - g_param_spec_string ("role", - _("Role"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_MANAGER, - g_param_spec_string ("manager", - _("Manager"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ASSISTANT, - g_param_spec_string ("assistant", - _("Assistant"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_NICKNAME, - g_param_spec_string ("nickname", - _("Nickname"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_SPOUSE, - g_param_spec_string ("spouse", - _("Spouse"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ANNIVERSARY, - g_param_spec_pointer ("anniversary", - _("Anniversary"), - /*_( */"XXX blurb" /*)*/, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_MAILER, - g_param_spec_string ("mailer", - _("Mailer"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_CALURI, - g_param_spec_string ("caluri", - _("Calendar URI"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_FBURL, - g_param_spec_string ("fburl", - _("Free/Busy URL"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ICSCALENDAR, - g_param_spec_string ("icscalendar", - _("ICS Calendar"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_NOTE, - g_param_spec_string ("note", - _("Note"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_RELATED_CONTACTS, - g_param_spec_string ("related_contacts", - _("Related Contacts"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_CATEGORIES, - g_param_spec_string ("categories", - _("Categories"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_CATEGORY_LIST, - g_param_spec_object ("category list", - _("Category List"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_LIST, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_WANTS_HTML, - g_param_spec_boolean ("wants_html", - _("Wants HTML"), - /*_( */"XXX blurb" /*)*/, - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_WANTS_HTML_SET, - g_param_spec_boolean ("wants_html_set", - _("Wants HTML set"), - /*_( */"XXX blurb" /*)*/, - FALSE, - G_PARAM_READABLE)); - - g_object_class_install_property (object_class, PROP_EVOLUTION_LIST, - g_param_spec_boolean ("list", - _("List"), - /*_( */"XXX blurb" /*)*/, - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_EVOLUTION_LIST_SHOW_ADDRESSES, - g_param_spec_boolean ("list_show_addresses", - _("List Show Addresses"), - /*_( */"XXX blurb" /*)*/, - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ARBITRARY, - g_param_spec_object ("arbitrary", - _("Arbitrary"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_LIST, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_ID, - g_param_spec_string ("id", - _("ID"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_LAST_USE, - g_param_spec_pointer ("last_use", - _("Last Use"), - /*_( */"XXX blurb" /*)*/, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_USE_SCORE, - /* XXX at some point we - should remove - LAX_VALIDATION and figure - out some hard min & max - scores. */ - g_param_spec_float ("use_score", - _("Use Score"), - /*_( */"XXX blurb" /*)*/, - 0.0, - 0.0, - 0.0, - G_PARAM_READWRITE | G_PARAM_LAX_VALIDATION)); -} - -ECardPhone * -e_card_phone_new (void) -{ - ECardPhone *newphone = g_new(ECardPhone, 1); - - newphone->ref_count = 1; - newphone->number = NULL; - newphone->flags = 0; - - return newphone; -} - -void -e_card_phone_unref (ECardPhone *phone) -{ - if (phone) { - phone->ref_count --; - if (phone->ref_count == 0) { - g_free(phone->number); - g_free(phone); - } - } -} - -ECardPhone * -e_card_phone_ref (const ECardPhone *phone) -{ - ECardPhone *phone_mutable = (ECardPhone *) phone; - if (phone_mutable) - phone_mutable->ref_count ++; - return phone_mutable; -} - -ECardPhone * -e_card_phone_copy (const ECardPhone *phone) -{ - if ( phone ) { - ECardPhone *phone_copy = e_card_phone_new(); - phone_copy->number = g_strdup(phone->number); - phone_copy->flags = phone->flags; - return phone_copy; - } else - return NULL; -} - -ECardDeliveryAddress * -e_card_delivery_address_new (void) -{ - ECardDeliveryAddress *newaddr = g_new(ECardDeliveryAddress, 1); - - newaddr->ref_count = 1; - newaddr->po = NULL; - newaddr->ext = NULL; - newaddr->street = NULL; - newaddr->city = NULL; - newaddr->region = NULL; - newaddr->code = NULL; - newaddr->country = NULL; - newaddr->flags = 0; - - return newaddr; -} - -void -e_card_delivery_address_unref (ECardDeliveryAddress *addr) -{ - if ( addr ) { - addr->ref_count --; - if (addr->ref_count == 0) { - g_free(addr->po); - g_free(addr->ext); - g_free(addr->street); - g_free(addr->city); - g_free(addr->region); - g_free(addr->code); - g_free(addr->country); - g_free(addr); - } - } -} - -ECardDeliveryAddress * -e_card_delivery_address_ref (const ECardDeliveryAddress *addr) -{ - ECardDeliveryAddress *addr_mutable = (ECardDeliveryAddress *) addr; - if (addr_mutable) - addr_mutable->ref_count ++; - return addr_mutable; -} - -ECardDeliveryAddress * -e_card_delivery_address_copy (const ECardDeliveryAddress *addr) -{ - if ( addr ) { - ECardDeliveryAddress *addr_copy = e_card_delivery_address_new (); - addr_copy->po = g_strdup(addr->po ); - addr_copy->ext = g_strdup(addr->ext ); - addr_copy->street = g_strdup(addr->street ); - addr_copy->city = g_strdup(addr->city ); - addr_copy->region = g_strdup(addr->region ); - addr_copy->code = g_strdup(addr->code ); - addr_copy->country = g_strdup(addr->country); - addr_copy->flags = addr->flags; - return addr_copy; - } else - return NULL; -} - -gboolean -e_card_delivery_address_is_empty (const ECardDeliveryAddress *addr) -{ - return (((addr->po == NULL) || (*addr->po == 0)) && - ((addr->ext == NULL) || (*addr->ext == 0)) && - ((addr->street == NULL) || (*addr->street == 0)) && - ((addr->city == NULL) || (*addr->city == 0)) && - ((addr->region == NULL) || (*addr->region == 0)) && - ((addr->code == NULL) || (*addr->code == 0)) && - ((addr->country == NULL) || (*addr->country == 0))); -} - -ECardDeliveryAddress * -e_card_delivery_address_from_label(const ECardAddrLabel *label) -{ - ECardDeliveryAddress *addr = e_card_delivery_address_new (); - EAddressWestern *western = e_address_western_parse (label->data); - - addr->po = g_strdup (western->po_box ); - addr->ext = g_strdup (western->extended ); - addr->street = g_strdup (western->street ); - addr->city = g_strdup (western->locality ); - addr->region = g_strdup (western->region ); - addr->code = g_strdup (western->postal_code); - addr->country = g_strdup (western->country ); - addr->flags = label->flags; - - e_address_western_free(western); - - return addr; -} - -char * -e_card_delivery_address_to_string(const ECardDeliveryAddress *addr) -{ - char *strings[5], **stringptr = strings; - char *line1, *line22, *line2; - char *final; - if (addr->po && *addr->po) - *(stringptr++) = addr->po; - if (addr->street && *addr->street) - *(stringptr++) = addr->street; - *stringptr = NULL; - line1 = g_strjoinv(" ", strings); - stringptr = strings; - if (addr->region && *addr->region) - *(stringptr++) = addr->region; - if (addr->code && *addr->code) - *(stringptr++) = addr->code; - *stringptr = NULL; - line22 = g_strjoinv(" ", strings); - stringptr = strings; - if (addr->city && *addr->city) - *(stringptr++) = addr->city; - if (line22 && *line22) - *(stringptr++) = line22; - *stringptr = NULL; - line2 = g_strjoinv(", ", strings); - stringptr = strings; - if (line1 && *line1) - *(stringptr++) = line1; - if (addr->ext && *addr->ext) - *(stringptr++) = addr->ext; - if (line2 && *line2) - *(stringptr++) = line2; - if (addr->country && *addr->country) - *(stringptr++) = addr->country; - *stringptr = NULL; - final = g_strjoinv("\n", strings); - g_free(line1); - g_free(line22); - g_free(line2); - return final; -} - -ECardAddrLabel * -e_card_delivery_address_to_label (const ECardDeliveryAddress *addr) -{ - ECardAddrLabel *label; - label = e_card_address_label_new(); - label->flags = addr->flags; - label->data = e_card_delivery_address_to_string(addr); - - return label; -} - -ECardAddrLabel * -e_card_address_label_new (void) -{ - ECardAddrLabel *newaddr = g_new(ECardAddrLabel, 1); - - newaddr->ref_count = 1; - newaddr->data = NULL; - newaddr->flags = 0; - - return newaddr; -} - -void -e_card_address_label_unref (ECardAddrLabel *addr) -{ - if (addr) { - addr->ref_count --; - if (addr->ref_count == 0) { - g_free(addr->data); - g_free(addr); - } - } -} - -ECardAddrLabel * -e_card_address_label_ref (const ECardAddrLabel *addr) -{ - ECardAddrLabel *addr_mutable = (ECardAddrLabel *) addr; - if (addr_mutable) - addr_mutable->ref_count ++; - return addr_mutable; -} - -ECardAddrLabel * -e_card_address_label_copy (const ECardAddrLabel *addr) -{ - if ( addr ) { - ECardAddrLabel *addr_copy = e_card_address_label_new (); - addr_copy->data = g_strdup(addr->data); - addr_copy->flags = addr->flags; - return addr_copy; - } else - return NULL; -} - -ECardName *e_card_name_new(void) -{ - ECardName *newname = g_new(ECardName, 1); - - newname->ref_count = 1; - newname->prefix = NULL; - newname->given = NULL; - newname->additional = NULL; - newname->family = NULL; - newname->suffix = NULL; - - return newname; -} - -void -e_card_name_unref(ECardName *name) -{ - if (name) { - name->ref_count --; - if (name->ref_count == 0) { - g_free (name->prefix); - g_free (name->given); - g_free (name->additional); - g_free (name->family); - g_free (name->suffix); - g_free (name); - } - } -} - -ECardName * -e_card_name_ref(const ECardName *name) -{ - ECardName *name_mutable = (ECardName *) name; - if (name_mutable) - name_mutable->ref_count ++; - return name_mutable; -} - -ECardName * -e_card_name_copy(const ECardName *name) -{ - if (name) { - ECardName *newname = e_card_name_new (); - - newname->prefix = g_strdup(name->prefix); - newname->given = g_strdup(name->given); - newname->additional = g_strdup(name->additional); - newname->family = g_strdup(name->family); - newname->suffix = g_strdup(name->suffix); - - return newname; - } else - return NULL; -} - - -char * -e_card_name_to_string(const ECardName *name) -{ - char *strings[6], **stringptr = strings; - - g_return_val_if_fail (name != NULL, NULL); - - if (name->prefix && *name->prefix) - *(stringptr++) = name->prefix; - if (name->given && *name->given) - *(stringptr++) = name->given; - if (name->additional && *name->additional) - *(stringptr++) = name->additional; - if (name->family && *name->family) - *(stringptr++) = name->family; - if (name->suffix && *name->suffix) - *(stringptr++) = name->suffix; - *stringptr = NULL; - return g_strjoinv(" ", strings); -} - -ECardName * -e_card_name_from_string(const char *full_name) -{ - ECardName *name = e_card_name_new (); - ENameWestern *western = e_name_western_parse (full_name); - - name->prefix = g_strdup (western->prefix); - name->given = g_strdup (western->first ); - name->additional = g_strdup (western->middle); - name->family = g_strdup (western->last ); - name->suffix = g_strdup (western->suffix); - - e_name_western_free(western); - - return name; -} - -ECardArbitrary * -e_card_arbitrary_new(void) -{ - ECardArbitrary *arbitrary = g_new(ECardArbitrary, 1); - arbitrary->ref_count = 1; - arbitrary->key = NULL; - arbitrary->type = NULL; - arbitrary->value = NULL; - return arbitrary; -} - -void -e_card_arbitrary_unref(ECardArbitrary *arbitrary) -{ - if (arbitrary) { - arbitrary->ref_count --; - if (arbitrary->ref_count == 0) { - g_free(arbitrary->key); - g_free(arbitrary->type); - g_free(arbitrary->value); - g_free(arbitrary); - } - } -} - -ECardArbitrary * -e_card_arbitrary_copy(const ECardArbitrary *arbitrary) -{ - if (arbitrary) { - ECardArbitrary *arb_copy = e_card_arbitrary_new (); - arb_copy->key = g_strdup(arbitrary->key); - arb_copy->type = g_strdup(arbitrary->type); - arb_copy->value = g_strdup(arbitrary->value); - return arb_copy; - } else - return NULL; -} - -ECardArbitrary * -e_card_arbitrary_ref(const ECardArbitrary *arbitrary) -{ - ECardArbitrary *arbitrary_mutable = (ECardArbitrary *) arbitrary; - if (arbitrary_mutable) - arbitrary_mutable->ref_count ++; - return arbitrary_mutable; -} - -/* EMail matching */ -static gboolean -e_card_email_match_single_string (const gchar *a, const gchar *b) -{ - const gchar *xa = NULL, *xb = NULL; - gboolean match = TRUE; - - for (xa=a; *xa && *xa != '@'; ++xa); - for (xb=b; *xb && *xb != '@'; ++xb); - - if (xa-a != xb-b || *xa != *xb || g_ascii_strncasecmp (a, b, xa-a)) - return FALSE; - - if (*xa == '\0') - return TRUE; - - /* Find the end of the string, then walk through backwards comparing. - This is so that we'll match joe@foobar.com and joe@mail.foobar.com. - */ - while (*xa) - ++xa; - while (*xb) - ++xb; - - while (match && *xa != '@' && *xb != '@') { - match = (tolower (*xa) == tolower (*xb)); - --xa; - --xb; - } - - match = match && ((tolower (*xa) == tolower (*xb)) || (*xa == '.') || (*xb == '.')); - - return match; -} - -gboolean -e_card_email_match_string (const ECard *card, const gchar *str) -{ - EIterator *iter; - - g_return_val_if_fail (card && E_IS_CARD (card), FALSE); - g_return_val_if_fail (str != NULL, FALSE); - - if (!card->email) - return FALSE; - - iter = e_list_get_iterator (card->email); - for (e_iterator_reset (iter); e_iterator_is_valid (iter); e_iterator_next (iter)) { - if (e_card_email_match_single_string (e_iterator_get (iter), str)) - return TRUE; - } - g_object_unref (iter); - - return FALSE; -} - -gint -e_card_email_find_number (const ECard *card, const gchar *email) -{ - EIterator *iter; - gint count = 0; - - g_return_val_if_fail (E_IS_CARD (card), -1); - g_return_val_if_fail (email != NULL, -1); - - if (!card->email) - return -1; - - iter = e_list_get_iterator (card->email); - for (e_iterator_reset (iter); e_iterator_is_valid (iter); e_iterator_next (iter)) { - if (!g_ascii_strcasecmp (e_iterator_get (iter), email)) - goto finished; - ++count; - } - count = -1; - - finished: - g_object_unref (iter); - - return count; -} - -/* - * ECard lifecycle management and vCard loading/saving. - */ - -static void -e_card_dispose (GObject *object) -{ - ECard *card = E_CARD(object); - -#define FREE_IF(x) do { if ((x)) { g_free (x); x = NULL; } } while (0) -#define UNREF_IF(x) do { if ((x)) { g_object_unref (x); x = NULL; } } while (0) - - FREE_IF (card->id); - UNREF_IF (card->book); - FREE_IF(card->file_as); - FREE_IF(card->fname); - if (card->name) { - e_card_name_unref(card->name); - card->name = NULL; - } - FREE_IF(card->bday); - - FREE_IF(card->url); - FREE_IF(card->org); - FREE_IF(card->org_unit); - FREE_IF(card->office); - FREE_IF(card->title); - FREE_IF(card->role); - FREE_IF(card->manager); - FREE_IF(card->assistant); - FREE_IF(card->nickname); - FREE_IF(card->spouse); - FREE_IF(card->anniversary); - FREE_IF(card->caluri); - FREE_IF(card->fburl); - FREE_IF(card->icscalendar); - FREE_IF(card->last_use); - FREE_IF(card->note); - FREE_IF(card->related_contacts); - - UNREF_IF (card->categories); - UNREF_IF (card->email); - UNREF_IF (card->phone); - UNREF_IF (card->address); - UNREF_IF (card->address_label); - - if (G_OBJECT_CLASS (parent_class)->dispose) - G_OBJECT_CLASS (parent_class)->dispose (object); -} - - -/* Set_arg handler for the card */ -static void -e_card_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - ECard *card; - - card = E_CARD (object); - - switch (prop_id) { - case PROP_FILE_AS: - g_free(card->file_as); - card->file_as = g_strdup(g_value_get_string (value)); - if (card->file_as == NULL) - card->file_as = g_strdup(""); - break; - - case PROP_FULL_NAME: - g_free(card->fname); - card->fname = g_strdup(g_value_get_string (value)); - if (card->fname == NULL) - card->fname = g_strdup(""); - - e_card_name_unref (card->name); - card->name = e_card_name_from_string (card->fname); - break; - case PROP_NAME: - e_card_name_unref (card->name); - card->name = e_card_name_ref(g_value_get_pointer (value)); - if (card->name == NULL) - card->name = e_card_name_new(); - if (card->fname == NULL) { - card->fname = e_card_name_to_string(card->name); - } - if (card->file_as == NULL) { - ECardName *name = card->name; - char *strings[3], **stringptr; - char *string; - stringptr = strings; - if (name->family && *name->family) - *(stringptr++) = name->family; - if (name->given && *name->given) - *(stringptr++) = name->given; - *stringptr = NULL; - string = g_strjoinv(", ", strings); - card->file_as = string; - } - break; - case PROP_CATEGORIES: - if (card->categories) - g_object_unref(card->categories); - card->categories = NULL; - if (g_value_get_string (value)) - do_parse_categories(card, (char*)g_value_get_string (value)); - break; - case PROP_CATEGORY_LIST: - if (card->categories) - g_object_unref(card->categories); - card->categories = E_LIST(g_value_get_object(value)); - if (card->categories) - g_object_ref(card->categories); - break; - case PROP_BIRTH_DATE: - g_free(card->bday); - if (g_value_get_pointer (value)) { - card->bday = g_new (ECardDate, 1); - memcpy (card->bday, g_value_get_pointer (value), sizeof (ECardDate)); - } else { - card->bday = NULL; - } - break; - case PROP_URL: - g_free(card->url); - card->url = g_strdup(g_value_get_string(value)); - break; - case PROP_ORG: - g_free(card->org); - card->org = g_strdup(g_value_get_string(value)); - break; - case PROP_ORG_UNIT: - g_free(card->org_unit); - card->org_unit = g_strdup(g_value_get_string(value)); - break; - case PROP_OFFICE: - g_free(card->office); - card->office = g_strdup(g_value_get_string(value)); - break; - case PROP_TITLE: - g_free(card->title); - card->title = g_strdup(g_value_get_string(value)); - break; - case PROP_ROLE: - g_free(card->role); - card->role = g_strdup(g_value_get_string(value)); - break; - case PROP_MANAGER: - g_free(card->manager); - card->manager = g_strdup(g_value_get_string(value)); - break; - case PROP_ASSISTANT: - g_free(card->assistant); - card->assistant = g_strdup(g_value_get_string(value)); - break; - case PROP_NICKNAME: - g_free(card->nickname); - card->nickname = g_strdup(g_value_get_string(value)); - break; - case PROP_SPOUSE: - g_free(card->spouse); - card->spouse = g_strdup(g_value_get_string(value)); - break; - case PROP_ANNIVERSARY: - g_free(card->anniversary); - if (g_value_get_pointer (value)) { - card->anniversary = g_new (ECardDate, 1); - memcpy (card->anniversary, g_value_get_pointer (value), sizeof (ECardDate)); - } else { - card->anniversary = NULL; - } - break; - case PROP_MAILER: - g_free(card->mailer); - card->mailer = g_strdup(g_value_get_string(value)); - break; - case PROP_CALURI: - g_free(card->caluri); - card->caluri = g_strdup(g_value_get_string(value)); - break; - case PROP_FBURL: - g_free(card->fburl); - card->fburl = g_strdup(g_value_get_string(value)); - break; - case PROP_ICSCALENDAR: - g_free(card->icscalendar); - card->icscalendar = g_strdup(g_value_get_string(value)); - break; - case PROP_NOTE: - g_free (card->note); - card->note = g_strdup(g_value_get_string(value)); - break; - case PROP_RELATED_CONTACTS: - g_free (card->related_contacts); - card->related_contacts = g_strdup(g_value_get_string(value)); - break; - case PROP_WANTS_HTML: - card->wants_html = g_value_get_boolean (value); - card->wants_html_set = TRUE; - break; - case PROP_ARBITRARY: - if (card->arbitrary) - g_object_unref(card->arbitrary); - card->arbitrary = E_LIST(g_value_get_pointer(value)); - if (card->arbitrary) - g_object_ref(card->arbitrary); - break; - case PROP_ID: - g_free(card->id); - card->id = g_strdup(g_value_get_string(value)); - if (card->id == NULL) - card->id = g_strdup (""); - break; - case PROP_LAST_USE: - g_free(card->last_use); - if (g_value_get_pointer (value)) { - card->last_use = g_new (ECardDate, 1); - memcpy (card->last_use, g_value_get_pointer (value), sizeof (ECardDate)); - } else { - card->last_use = NULL; - } - break; - case PROP_USE_SCORE: - card->raw_use_score = g_value_get_float (value); - break; - case PROP_EVOLUTION_LIST: - card->list = g_value_get_boolean (value); - break; - case PROP_EVOLUTION_LIST_SHOW_ADDRESSES: - card->list_show_addresses = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* Get_arg handler for the card */ -static void -e_card_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - ECard *card; - - card = E_CARD (object); - - switch (prop_id) { - case PROP_FILE_AS: - g_value_set_string (value, card->file_as); - break; - case PROP_FULL_NAME: - g_value_set_string (value, card->fname); - break; - case PROP_NAME: - g_value_set_pointer (value, card->name); - break; - case PROP_ADDRESS: - if (!card->address) - card->address = e_list_new((EListCopyFunc) e_card_delivery_address_ref, - (EListFreeFunc) e_card_delivery_address_unref, - NULL); - g_value_set_object (value, card->address); - break; - case PROP_ADDRESS_LABEL: - if (!card->address_label) - card->address_label = e_list_new((EListCopyFunc) e_card_address_label_ref, - (EListFreeFunc) e_card_address_label_unref, - NULL); - g_value_set_object (value, card->address_label); - break; - case PROP_PHONE: - if (!card->phone) - card->phone = e_list_new((EListCopyFunc) e_card_phone_ref, - (EListFreeFunc) e_card_phone_unref, - NULL); - g_value_set_object (value, card->phone); - break; - case PROP_EMAIL: - if (!card->email) - card->email = e_list_new((EListCopyFunc) g_strdup, - (EListFreeFunc) g_free, - NULL); - g_value_set_object (value, card->email); - break; - case PROP_CATEGORIES: - { - int i; - char ** strs; - int length; - EIterator *iterator; - if (!card->categories) - card->categories = e_list_new((EListCopyFunc) g_strdup, - (EListFreeFunc) g_free, - NULL); - length = e_list_length(card->categories); - strs = g_new(char *, length + 1); - for (iterator = e_list_get_iterator(card->categories), i = 0; e_iterator_is_valid(iterator); e_iterator_next(iterator), i++) { - strs[i] = (char *)e_iterator_get(iterator); - } - strs[i] = 0; - g_value_set_string_take_ownership(value, g_strjoinv(", ", strs)); - g_free(strs); - } - break; - case PROP_CATEGORY_LIST: - if (!card->categories) - card->categories = e_list_new((EListCopyFunc) g_strdup, - (EListFreeFunc) g_free, - NULL); - g_value_set_object (value, card->categories); - break; - case PROP_BIRTH_DATE: - g_value_set_pointer (value, card->bday); - break; - case PROP_URL: - g_value_set_string (value, card->url); - break; - case PROP_ORG: - g_value_set_string (value, card->org); - break; - case PROP_ORG_UNIT: - g_value_set_string (value, card->org_unit); - break; - case PROP_OFFICE: - g_value_set_string (value, card->office); - break; - case PROP_TITLE: - g_value_set_string (value, card->title); - break; - case PROP_ROLE: - g_value_set_string (value, card->role); - break; - case PROP_MANAGER: - g_value_set_string (value, card->manager); - break; - case PROP_ASSISTANT: - g_value_set_string (value, card->assistant); - break; - case PROP_NICKNAME: - g_value_set_string (value, card->nickname); - break; - case PROP_SPOUSE: - g_value_set_string (value, card->spouse); - break; - case PROP_ANNIVERSARY: - g_value_set_pointer (value, card->anniversary); - break; - case PROP_MAILER: - g_value_set_string (value, card->mailer); - break; - case PROP_CALURI: - g_value_set_string (value, card->caluri); - break; - case PROP_FBURL: - g_value_set_string (value, card->fburl); - break; - case PROP_ICSCALENDAR: - g_value_set_string (value, card->icscalendar); - break; - case PROP_NOTE: - g_value_set_string (value, card->note); - break; - case PROP_RELATED_CONTACTS: - g_value_set_string (value, card->related_contacts); - break; - case PROP_WANTS_HTML: - g_value_set_boolean (value, card->wants_html); - break; - case PROP_WANTS_HTML_SET: - g_value_set_boolean (value, card->wants_html_set); - break; - case PROP_ARBITRARY: - if (!card->arbitrary) - card->arbitrary = e_list_new((EListCopyFunc) e_card_arbitrary_ref, - (EListFreeFunc) e_card_arbitrary_unref, - NULL); - - g_value_set_object (value, card->arbitrary); - break; - case PROP_ID: - g_value_set_string (value, card->id); - break; - case PROP_LAST_USE: - g_value_set_pointer (value, card->last_use); - break; - case PROP_USE_SCORE: - g_value_set_float (value, e_card_get_use_score (card)); - break; - case PROP_EVOLUTION_LIST: - g_value_set_boolean (value, card->list); - break; - case PROP_EVOLUTION_LIST_SHOW_ADDRESSES: - g_value_set_boolean (value, card->list_show_addresses); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -/** - * e_card_init: - */ -static void -e_card_init (ECard *card) -{ - card->id = g_strdup(""); - - card->file_as = NULL; - card->fname = NULL; - card->name = NULL; - card->bday = NULL; - card->email = NULL; - card->phone = NULL; - card->address = NULL; - card->address_label = NULL; - card->url = NULL; - card->org = NULL; - card->org_unit = NULL; - card->office = NULL; - card->title = NULL; - card->role = NULL; - card->manager = NULL; - card->assistant = NULL; - card->nickname = NULL; - card->spouse = NULL; - card->anniversary = NULL; - card->mailer = NULL; - card->caluri = NULL; - card->fburl = NULL; - card->icscalendar = NULL; - card->note = NULL; - card->related_contacts = NULL; - card->categories = NULL; - card->wants_html = FALSE; - card->wants_html_set = FALSE; - card->list = FALSE; - card->list_show_addresses = FALSE; - card->arbitrary = NULL; - card->last_use = NULL; - card->raw_use_score = 0; -} - -GList * -e_card_load_cards_from_file_with_default_charset(const char *filename, const char *default_charset) -{ - VObject *vobj = Parse_MIME_FromFileName((char *) filename); - GList *list = NULL; - while(vobj) { - VObject *next; - ECard *card = g_object_new (E_TYPE_CARD, NULL); - parse(card, vobj, default_charset); - next = nextVObjectInList(vobj); - cleanVObject(vobj); - vobj = next; - list = g_list_prepend(list, card); - } - list = g_list_reverse(list); - return list; -} - -GList * -e_card_load_cards_from_file(const char *filename) -{ - return e_card_load_cards_from_file_with_default_charset (filename, "UTF-8"); -} - -GList * -e_card_load_cards_from_string_with_default_charset(const char *str, const char *default_charset) -{ - VObject *vobj = Parse_MIME(str, strlen (str)); - GList *list = NULL; - while(vobj) { - VObject *next; - ECard *card = g_object_new (E_TYPE_CARD, NULL); - parse(card, vobj, default_charset); - next = nextVObjectInList(vobj); - cleanVObject(vobj); - vobj = next; - list = g_list_prepend(list, card); - } - list = g_list_reverse(list); - return list; -} - -GList * -e_card_load_cards_from_string(const char *str) -{ - return e_card_load_cards_from_string_with_default_charset (str, "UTF-8"); -} - -void -e_card_free_empty_lists (ECard *card) -{ - if (card->address && e_list_length (card->address) == 0) { - g_object_unref (card->address); - card->address = NULL; - } - - if (card->address_label && e_list_length (card->address_label) == 0) { - g_object_unref (card->address_label); - card->address_label = NULL; - } - - if (card->phone && e_list_length (card->phone) == 0) { - g_object_unref (card->phone); - card->phone = NULL; - } - - if (card->email && e_list_length (card->email) == 0) { - g_object_unref (card->email); - card->email = NULL; - } - - if (card->categories && e_list_length (card->categories) == 0) { - g_object_unref (card->categories); - card->categories = NULL; - } - - if (card->arbitrary && e_list_length (card->arbitrary) == 0) { - g_object_unref (card->arbitrary); - card->arbitrary = NULL; - } -} - -static void -assign_string(VObject *vobj, const char *default_charset, char **string) -{ - int type = vObjectValueType(vobj); - char *str; - const char *charset = default_charset; - char *charset_buf = NULL; - VObject *charset_obj; - - if ((charset_obj = isAPropertyOf (vobj, "CHARSET"))) { - switch (vObjectValueType (charset_obj)) { - case VCVT_STRINGZ: - charset = vObjectStringZValue(charset_obj); - break; - case VCVT_USTRINGZ: - charset_buf = fakeCString (vObjectUStringZValue (charset_obj)); - charset = charset_buf; - break; - } - } - - switch(type) { - case VCVT_STRINGZ: - if (strcmp (charset, "UTF-8")) - *string = e_utf8_from_charset_string (charset, vObjectStringZValue(vobj)); - else - *string = g_strdup(vObjectStringZValue(vobj)); - break; - case VCVT_USTRINGZ: - str = fakeCString (vObjectUStringZValue (vobj)); - if (strcmp (charset, "UTF-8")) - *string = e_utf8_from_charset_string (charset, str); - else - *string = g_strdup(str); - free(str); - break; - default: - *string = g_strdup(""); - break; - } - - if (charset_buf) { - free (charset_buf); - } -} - - -ECardDate -e_card_date_from_string (const char *str) -{ - ECardDate date; - int length; - - date.year = 0; - date.month = 0; - date.day = 0; - - length = strlen(str); - - if (length == 10 ) { - date.year = str[0] * 1000 + str[1] * 100 + str[2] * 10 + str[3] - '0' * 1111; - date.month = str[5] * 10 + str[6] - '0' * 11; - date.day = str[8] * 10 + str[9] - '0' * 11; - } else if ( length == 8 ) { - date.year = str[0] * 1000 + str[1] * 100 + str[2] * 10 + str[3] - '0' * 1111; - date.month = str[4] * 10 + str[5] - '0' * 11; - date.day = str[6] * 10 + str[7] - '0' * 11; - } - - return date; -} - -char * -e_v_object_get_child_value(VObject *vobj, char *name, const char *default_charset) -{ - char *ret_val; - VObjectIterator iterator; - char *charset_buf = NULL; - VObject *charset_obj; - - if ((charset_obj = isAPropertyOf (vobj, "CHARSET"))) { - switch (vObjectValueType (charset_obj)) { - case VCVT_STRINGZ: - default_charset = vObjectStringZValue(charset_obj); - break; - case VCVT_USTRINGZ: - charset_buf = fakeCString (vObjectUStringZValue (charset_obj)); - default_charset = charset_buf; - break; - } - } - - initPropIterator(&iterator, vobj); - while(moreIteration (&iterator)) { - VObject *attribute = nextVObject(&iterator); - const char *id = vObjectName(attribute); - if ( ! strcmp(id, name) ) { - assign_string(attribute, default_charset, &ret_val); - return ret_val; - } - } - if (charset_buf) - free (charset_buf); - - return NULL; -} - -static struct { - char *id; - ECardPhoneFlags flag; -} phone_pairs[] = { - { VCPreferredProp, E_CARD_PHONE_PREF }, - { VCWorkProp, E_CARD_PHONE_WORK }, - { VCHomeProp, E_CARD_PHONE_HOME }, - { VCVoiceProp, E_CARD_PHONE_VOICE }, - { VCFaxProp, E_CARD_PHONE_FAX }, - { VCMessageProp, E_CARD_PHONE_MSG }, - { VCCellularProp, E_CARD_PHONE_CELL }, - { VCPagerProp, E_CARD_PHONE_PAGER }, - { VCBBSProp, E_CARD_PHONE_BBS }, - { VCModemProp, E_CARD_PHONE_MODEM }, - { VCCarProp, E_CARD_PHONE_CAR }, - { VCISDNProp, E_CARD_PHONE_ISDN }, - { VCVideoProp, E_CARD_PHONE_VIDEO }, - { "X-EVOLUTION-ASSISTANT", E_CARD_PHONE_ASSISTANT }, - { "X-EVOLUTION-CALLBACK", E_CARD_PHONE_CALLBACK }, - { "X-EVOLUTION-RADIO", E_CARD_PHONE_RADIO }, - { "X-EVOLUTION-TELEX", E_CARD_PHONE_TELEX }, - { "X-EVOLUTION-TTYTDD", E_CARD_PHONE_TTYTDD }, -}; - -static ECardPhoneFlags -get_phone_flags (VObject *vobj) -{ - ECardPhoneFlags ret = 0; - int i; - - for (i = 0; i < sizeof(phone_pairs) / sizeof(phone_pairs[0]); i++) { - if (isAPropertyOf (vobj, phone_pairs[i].id)) { - ret |= phone_pairs[i].flag; - } - } - - return ret; -} - -static void -set_phone_flags (VObject *vobj, ECardPhoneFlags flags) -{ - int i; - - for (i = 0; i < sizeof(phone_pairs) / sizeof(phone_pairs[0]); i++) { - if (flags & phone_pairs[i].flag) { - addProp (vobj, phone_pairs[i].id); - } - } -} - -static struct { - char *id; - ECardAddressFlags flag; -} addr_pairs[] = { - { VCDomesticProp, E_CARD_ADDR_DOM }, - { VCInternationalProp, E_CARD_ADDR_INTL }, - { VCPostalProp, E_CARD_ADDR_POSTAL }, - { VCParcelProp, E_CARD_ADDR_PARCEL }, - { VCHomeProp, E_CARD_ADDR_HOME }, - { VCWorkProp, E_CARD_ADDR_WORK }, - { "PREF", E_CARD_ADDR_DEFAULT }, -}; - -static ECardAddressFlags -get_address_flags (VObject *vobj) -{ - ECardAddressFlags ret = 0; - int i; - - for (i = 0; i < sizeof(addr_pairs) / sizeof(addr_pairs[0]); i++) { - if (isAPropertyOf (vobj, addr_pairs[i].id)) { - ret |= addr_pairs[i].flag; - } - } - - return ret; -} - -static void -set_address_flags (VObject *vobj, ECardAddressFlags flags) -{ - int i; - - for (i = 0; i < sizeof(addr_pairs) / sizeof(addr_pairs[0]); i++) { - if (flags & addr_pairs[i].flag) { - addProp (vobj, addr_pairs[i].id); - } - } -} - -gboolean -e_card_evolution_list (ECard *card) -{ - g_return_val_if_fail (card && E_IS_CARD (card), FALSE); - return card->list; -} - -gboolean -e_card_evolution_list_show_addresses (ECard *card) -{ - g_return_val_if_fail (card && E_IS_CARD (card), FALSE); - return card->list_show_addresses; -} - -typedef struct _CardLoadData CardLoadData; -struct _CardLoadData { - gchar *card_id; - ECardCallback cb; - gpointer closure; -}; - -static void -get_card_cb (EBook *book, EBookStatus status, ECard *card, gpointer closure) -{ - CardLoadData *data = (CardLoadData *) closure; - - if (data->cb != NULL) { - if (status == E_BOOK_STATUS_SUCCESS) - data->cb (card, data->closure); - else - data->cb (NULL, data->closure); - } - - g_free (data->card_id); - g_free (data); -} - -static void -card_load_cb (EBook *book, EBookStatus status, gpointer closure) -{ - CardLoadData *data = (CardLoadData *) closure; - - if (status == E_BOOK_STATUS_SUCCESS) - e_book_get_card (book, data->card_id, get_card_cb, closure); - else { - data->cb (NULL, data->closure); - g_free (data->card_id); - g_free (data); - } -} - -void -e_card_load_uri (const gchar *book_uri, const gchar *uid, ECardCallback cb, gpointer closure) -{ - CardLoadData *data; - EBook *book; - - data = g_new (CardLoadData, 1); - data->card_id = g_strdup (uid); - data->cb = cb; - data->closure = closure; - - book = e_book_new (); - e_book_load_uri (book, book_uri, card_load_cb, data); -} diff --git a/addressbook/backend/ebook/e-card.h b/addressbook/backend/ebook/e-card.h deleted file mode 100644 index 8819966d5b..0000000000 --- a/addressbook/backend/ebook/e-card.h +++ /dev/null @@ -1,209 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: - * Chris Lahey - * Arturo Espinosa - * Nat Friedman (nat@ximian.com) - * - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 1999 The Free Software Foundation - */ - -#ifndef __E_CARD_H__ -#define __E_CARD_H__ - -#include -#include -#include -#include -#include - -#define E_TYPE_CARD (e_card_get_type ()) -#define E_CARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CARD, ECard)) -#define E_CARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CARD, ECardClass)) -#define E_IS_CARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CARD)) -#define E_IS_CARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CARD)) -#define E_CARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CARD, ECardClass)) - -typedef struct _ECard ECard; -typedef struct _ECardClass ECardClass; - -struct _EBook; /* Forward reference */ - -struct _ECard { - GObject object; - char *id; - - struct _EBook *book; /* The EBook this card is from. */ - - char *file_as; /* The File As field. */ - char *fname; /* The full name. */ - ECardName *name; /* The structured name. */ - EList *address; /* Delivery addresses (ECardDeliveryAddress *) */ - EList *address_label; /* Delivery address labels - * (ECardAddrLabel *) */ - - EList *phone; /* Phone numbers (ECardPhone *) */ - EList *email; /* Email addresses (char *) */ - char *url; /* The person's web page. */ - - ECardDate *bday; /* The person's birthday. */ - - char *note; - - - char *org; /* The person's organization. */ - char *org_unit; /* The person's organization unit. */ - char *office; /* The person's office. */ - char *role; /* The person's role w/in his org */ - char *title; /* The person's title w/in his org */ - - char *manager; - char *assistant; - - char *nickname; /* The person's nickname */ - - char *spouse; /* The person's spouse. */ - ECardDate *anniversary; /* The person's anniversary. */ - - char *mailer; /* Mailer */ - - char *caluri; /* Calendar URI */ - char *fburl; /* Free Busy URL */ - char *icscalendar; /* Default server calendar */ - - gint timezone; /* number of minutes from UTC as an int */ - - ECardDate *last_use; - float raw_use_score; - - char *related_contacts; /* EDestinationV (serialized) of related contacts. */ - - EList *categories; /* Categories. */ - - EList *arbitrary; /* Arbitrary fields. */ - - - - guint32 wants_html : 1; /* Wants html mail. */ - guint32 wants_html_set : 1; /* Wants html mail. */ - guint32 list : 1; /* If the card corresponds to a contact list */ - guint32 list_show_addresses : 1; /* Whether to show the addresses - in the To: or Bcc: field */ - -#if 0 - ECardPhoto *logo; /* This person's org's logo. */ - - ECardPhoto *photo; /* A photo of the person. */ - - ECard *agent; /* A person who sereves as this - guy's agent/secretary/etc. */ - - ECardSound *sound; - - ECardKey *key; /* The person's public key. */ - ECardTimeZone *timezn; /* The person's time zone. */ - ECardGeoPos *geopos; /* The person's long/lat. */ - - ECardRev *rev; /* The time this card was last - modified. */ - - EList xtension; -#endif -}; - -struct _ECardClass { - GObjectClass parent_class; - GHashTable *attribute_jump_table; -}; - - -/* Simple functions */ -ECard *e_card_new (const char *vcard); /* Assumes utf8 */ -ECard *e_card_new_with_default_charset (const char *vcard, - const char *default_charset); -const char *e_card_get_id (ECard *card); -void e_card_set_id (ECard *card, - const char *character); - -struct _EBook *e_card_get_book (ECard *card); -void e_card_set_book (ECard *card, - struct _EBook *book); -char *e_card_get_vcard (ECard *card); -char *e_card_get_vcard_assume_utf8 (ECard *card); -char *e_card_list_get_vcard (const GList *list); -ECard *e_card_duplicate (ECard *card); -float e_card_get_use_score (ECard *card); -void e_card_touch (ECard *card); - -/* Evolution List convenience functions */ -/* used for encoding uids in email addresses */ -gboolean e_card_evolution_list (ECard *card); -gboolean e_card_evolution_list_show_addresses (ECard *card); - -/* ECardPhone manipulation */ -ECardPhone *e_card_phone_new (void); -ECardPhone *e_card_phone_copy (const ECardPhone *phone); -ECardPhone *e_card_phone_ref (const ECardPhone *phone); -void e_card_phone_unref (ECardPhone *phone); - -/* ECardDeliveryAddress manipulation */ -ECardDeliveryAddress *e_card_delivery_address_new (void); -ECardDeliveryAddress *e_card_delivery_address_copy (const ECardDeliveryAddress *addr); -ECardDeliveryAddress *e_card_delivery_address_ref (const ECardDeliveryAddress *addr); -void e_card_delivery_address_unref (ECardDeliveryAddress *addr); -gboolean e_card_delivery_address_is_empty (const ECardDeliveryAddress *addr); -char *e_card_delivery_address_to_string (const ECardDeliveryAddress *addr); -ECardDeliveryAddress *e_card_delivery_address_from_label (const ECardAddrLabel *label); -ECardAddrLabel *e_card_delivery_address_to_label (const ECardDeliveryAddress *addr); - -/* ECardAddrLabel manipulation */ -ECardAddrLabel *e_card_address_label_new (void); -ECardAddrLabel *e_card_address_label_copy (const ECardAddrLabel *addr); -ECardAddrLabel *e_card_address_label_ref (const ECardAddrLabel *addr); -void e_card_address_label_unref (ECardAddrLabel *addr); - -/* ECardName manipulation */ -ECardName *e_card_name_new (void); -ECardName *e_card_name_copy (const ECardName *name); -ECardName *e_card_name_ref (const ECardName *name); -void e_card_name_unref (ECardName *name); -char *e_card_name_to_string (const ECardName *name); -ECardName *e_card_name_from_string (const char *full_name); - -/* ECardDate */ -ECardDate e_card_date_from_string (const gchar *str); -gchar *e_card_date_to_string (ECardDate *dt); - -/* ECardArbitrary manipulation */ -ECardArbitrary *e_card_arbitrary_new (void); -ECardArbitrary *e_card_arbitrary_copy (const ECardArbitrary *arbitrary); -ECardArbitrary *e_card_arbitrary_ref (const ECardArbitrary *arbitrary); -void e_card_arbitrary_unref (ECardArbitrary *arbitrary); - -/* ECard email manipulation */ -gboolean e_card_email_match_string (const ECard *card, - const gchar *str); -gint e_card_email_find_number (const ECard *card, - const gchar *email); - -/* Specialized functionality */ -GList *e_card_load_cards_from_file (const char *filename); -GList *e_card_load_cards_from_file_with_default_charset (const char *filename, - const char *default_charset); -GList *e_card_load_cards_from_string (const char *str); -GList *e_card_load_cards_from_string_with_default_charset (const char *str, - const char *default_charset); -void e_card_free_empty_lists (ECard *card); - -/* Getting ECards via their URIs */ -typedef void (*ECardCallback) (ECard *card, gpointer closure); -void e_card_load_uri (const gchar *book_uri, - const gchar *uid, - ECardCallback cb, - gpointer closure); - - -GType e_card_get_type (void); - -#endif /* ! __E_CARD_H__ */ diff --git a/addressbook/backend/ebook/e-contact.c b/addressbook/backend/ebook/e-contact.c new file mode 100644 index 0000000000..ce92b31f71 --- /dev/null +++ b/addressbook/backend/ebook/e-contact.c @@ -0,0 +1,1288 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* e-contact.c + * + * Copyright (C) 2003 Ximian, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Chris Toshok (toshok@ximian.com) + */ + +#include +#include +#include +#include +#include +#include +#include "e-contact.h" +#include "e-book.h" +#include "e-util/ename/e-name-western.h" + +struct _EContactPrivate { +}; + +#define E_CONTACT_FIELD_TYPE_STRING 0x00000001 /* used for simple single valued attributes */ +/*E_CONTACT_FIELD_TYPE_FLOAT*/ +#define E_CONTACT_FIELD_TYPE_LIST 0x00000002 /* used for multivalued single attributes - the elements are of type char* */ +#define E_CONTACT_FIELD_TYPE_MULTI 0x00000004 /* used for multivalued attributes - the elements are of type EVCardAttribute */ +#define E_CONTACT_FIELD_TYPE_STRUCT 0x00000008 /* used for structured types (N and ADR properties, in particular) */ +#define E_CONTACT_FIELD_TYPE_BOOLEAN 0x00000010 /* used for boolean types (WANTS_HTML) */ + +#define E_CONTACT_FIELD_TYPE_SYNTHETIC 0x10000000 /* used when there isn't a corresponding vcard field (such as email_1) */ +#define E_CONTACT_FIELD_TYPE_LIST_ELEM 0x20000000 /* used when a synthetic attribute is a numbered list element */ +#define E_CONTACT_FIELD_TYPE_MULTI_ELEM 0x40000000 /* used when we're looking for the nth attribute where more than 1 can be present in the vcard */ +#define E_CONTACT_FIELD_TYPE_ATTR_TYPE 0x80000000 /* used when a synthetic attribute is flagged with a TYPE= that we'll be looking for */ + +typedef struct { + guint32 t; + + EContactField field_id; + const char *vcard_field_name; + const char *field_name; /* non translated */ + const char *pretty_name; /* translated */ + + gboolean read_only; + + int list_elem; + const char *attr_type1; + const char *attr_type2; + + void* (*struct_getter)(EContact *contact, EVCardAttribute *attribute); + void (*struct_setter)(EContact *contact, EVCardAttribute *attribute, void *data); + +} EContactFieldInfo; + +static void* photo_getter (EContact *contact, EVCardAttribute *attr); +static void photo_setter (EContact *contact, EVCardAttribute *attr, void *data); +static void* fn_getter (EContact *contact, EVCardAttribute *attr); +static void fn_setter (EContact *contact, EVCardAttribute *attr, void *data); +static void* n_getter (EContact *contact, EVCardAttribute *attr); +static void n_setter (EContact *contact, EVCardAttribute *attr, void *data); +static void* adr_getter (EContact *contact, EVCardAttribute *attr); +static void adr_setter (EContact *contact, EVCardAttribute *attr, void *data); +static void* date_getter (EContact *contact, EVCardAttribute *attr); +static void date_setter (EContact *contact, EVCardAttribute *attr, void *data); + +#define STRING_FIELD(id,vc,n,pn,ro) { E_CONTACT_FIELD_TYPE_STRING, (id), (vc), (n), (pn), (ro) } +#define BOOLEAN_FIELD(id,vc,n,pn,ro) { E_CONTACT_FIELD_TYPE_BOOLEAN, (id), (vc), (n), (pn), (ro) } +#define LIST_FIELD(id,vc,n,pn,ro) { E_CONTACT_FIELD_TYPE_LIST, (id), (vc), (n), (pn), (ro) } +#define MULTI_LIST_FIELD(id,vc,n,pn,ro) { E_CONTACT_FIELD_TYPE_MULTI, (id), (vc), (n), (pn), (ro) } +#define STRUCT_FIELD(id,vc,n,pn,ro,get,set) { E_CONTACT_FIELD_TYPE_STRUCT, (id), (vc), (n), (pn), (ro), -1, NULL, NULL, (get), (set) } +#define LIST_ELEM_STR_FIELD(id,vc,n,pn,ro,nm) { E_CONTACT_FIELD_TYPE_LIST_ELEM | E_CONTACT_FIELD_TYPE_SYNTHETIC | E_CONTACT_FIELD_TYPE_STRING, (id), (vc), (n), (pn), (ro), (nm) } +#define MULTI_ELEM_STR_FIELD(id,vc,n,pn,ro,nm) { E_CONTACT_FIELD_TYPE_MULTI_ELEM | E_CONTACT_FIELD_TYPE_SYNTHETIC | E_CONTACT_FIELD_TYPE_STRING, (id), (vc), (n), (pn), (ro), (nm) } +#define ATTR_TYPE_STR_FIELD(id,vc,n,pn,ro,at1,nth) { E_CONTACT_FIELD_TYPE_ATTR_TYPE | E_CONTACT_FIELD_TYPE_SYNTHETIC | E_CONTACT_FIELD_TYPE_STRING, (id), (vc), (n), (pn), (ro), (nth), (at1), NULL } +#define ATTR2_TYPE_STR_FIELD(id,vc,n,pn,ro,at1,at2,nth) { E_CONTACT_FIELD_TYPE_ATTR_TYPE | E_CONTACT_FIELD_TYPE_SYNTHETIC | E_CONTACT_FIELD_TYPE_STRING, (id), (vc), (n), (pn), (ro), (nth), (at1), (at2) } +#define ATTR_TYPE_STRUCT_FIELD(id,vc,n,pn,ro,at,get,set) { E_CONTACT_FIELD_TYPE_ATTR_TYPE | E_CONTACT_FIELD_TYPE_SYNTHETIC | E_CONTACT_FIELD_TYPE_STRUCT, (id), (vc), (n), (pn), (ro), 0, (at), NULL, (get), (set) } + +static EContactFieldInfo field_info[] = { + STRING_FIELD (E_CONTACT_UID, EVC_UID, "id", N_("Unique ID"), FALSE), + STRING_FIELD (E_CONTACT_FILE_AS, EVC_X_FILE_AS, "file_as", N_("File As"), FALSE), + + /* Name fields */ + /* FN isn't really a structured field - we use a getter/setter + so we can set the N property (since evo 1.4 works fine with + vcards that don't even have a N attribute. *sigh*) */ + STRUCT_FIELD (E_CONTACT_FULL_NAME, EVC_FN, "full_name", N_("Full Name"), FALSE, fn_getter, fn_setter), + STRUCT_FIELD (E_CONTACT_NAME, EVC_N, "name", N_("Name"), FALSE, n_getter, n_setter), + LIST_ELEM_STR_FIELD (E_CONTACT_GIVEN_NAME, EVC_N, "given_name", N_("Given Name"), FALSE, 1), + LIST_ELEM_STR_FIELD (E_CONTACT_FAMILY_NAME, EVC_N, "family_name", N_("Family Name"), FALSE, 0), + STRING_FIELD (E_CONTACT_NICKNAME, EVC_NICKNAME, "nickname", N_("Nickname"), FALSE), + + /* Address fields */ + MULTI_LIST_FIELD (E_CONTACT_ADDRESS, EVC_ADR, "address", N_("Address List"), FALSE), + ATTR_TYPE_STRUCT_FIELD (E_CONTACT_ADDRESS_HOME, EVC_ADR, "address_home", N_("Home Address"), FALSE, "HOME", adr_getter, adr_setter), + ATTR_TYPE_STRUCT_FIELD (E_CONTACT_ADDRESS_WORK, EVC_ADR, "address_work", N_("Work Address"), FALSE, "WORK", adr_getter, adr_setter), + ATTR_TYPE_STRUCT_FIELD (E_CONTACT_ADDRESS_OTHER, EVC_ADR, "address_other", N_("Other Address"), FALSE, "OTHER", adr_getter, adr_setter), + + ATTR_TYPE_STR_FIELD (E_CONTACT_ADDRESS_LABEL_HOME, EVC_LABEL, "address_label_home", N_("Home Address Label"), FALSE, "HOME", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_ADDRESS_LABEL_WORK, EVC_LABEL, "address_label_work", N_("Work Address Label"), FALSE, "WORK", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_ADDRESS_LABEL_OTHER, EVC_LABEL, "address_label_other", N_("Other Address Label"), FALSE, "OTHER", 0), + + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_ASSISTANT, EVC_TEL, "assistant_phone", N_("Assistant Phone"), FALSE, "X-EVOLUTION-ASSISTANT", 0), + ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_BUSINESS, EVC_TEL, "business_phone", N_("Business Phone"), FALSE, "WORK", "VOICE", 0), + ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_BUSINESS_2, EVC_TEL, "business_phone_2", N_("Business Phone 2"), FALSE, "WORK", "VOICE", 1), + ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_BUSINESS_FAX, EVC_TEL, "business_fax", N_("Business Fax"), FALSE, "WORK", "FAX", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_CALLBACK, EVC_TEL, "callback_phone", N_("Callback Phone"), FALSE, "X-EVOLUTION-CALLBACK", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_CAR, EVC_TEL, "car_phone", N_("Car Phone"), FALSE, "CAR", 0), + ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_COMPANY, EVC_TEL, "company_phone", N_("Company Phone"), FALSE, "WORK", "VOICE", 2), + ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_HOME, EVC_TEL, "home_phone", N_("Home Phone"), FALSE, "HOME", "VOICE", 0), + ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_HOME_2, EVC_TEL, "home_phone_2", N_("Home Phone 2"), FALSE, "HOME", "VOICE", 1), + ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_HOME_FAX, EVC_TEL, "home_fax", N_("Home Fax"), FALSE, "HOME", "FAX", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_ISDN, EVC_TEL, "isdn_phone", N_("ISDN"), FALSE, "ISDN", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_MOBILE, EVC_TEL, "mobile_phone", N_("Mobile Phone"), FALSE, "CELL", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_OTHER, EVC_TEL, "other_phone", N_("Other Phone"), FALSE, "VOICE", 0), /* XXX */ + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_OTHER_FAX, EVC_TEL, "other_fax", N_("Other Fax"), FALSE, "FAX", 0), /* XXX */ + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_PAGER, EVC_TEL, "pager", N_("Pager"), FALSE, "PAGER", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_PRIMARY, EVC_TEL, "primary_phone", N_("Primary Phone"), FALSE, "PREF", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_RADIO, EVC_TEL, "radio", N_("Radio"), FALSE, "X-EVOLUTION-RADIO", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_TELEX, EVC_TEL, "telex", N_("Telex"), FALSE, "X-EVOLUTION-TELEX", 0), + ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_TTYTDD, EVC_TEL, "tty", N_("TTY"), FALSE, "X-EVOLUTION-TTYTDD", 0), + + /* Email fields */ + MULTI_LIST_FIELD (E_CONTACT_EMAIL, EVC_EMAIL, "email", N_("Email List"), FALSE), + MULTI_ELEM_STR_FIELD (E_CONTACT_EMAIL_1, EVC_EMAIL, "email_1", N_("Email 1"), FALSE, 0), + MULTI_ELEM_STR_FIELD (E_CONTACT_EMAIL_2, EVC_EMAIL, "email_2", N_("Email 2"), FALSE, 1), + MULTI_ELEM_STR_FIELD (E_CONTACT_EMAIL_3, EVC_EMAIL, "email_3", N_("Email 3"), FALSE, 2), + STRING_FIELD (E_CONTACT_MAILER, EVC_MAILER, "mailer", N_("Mailer"), FALSE), + BOOLEAN_FIELD (E_CONTACT_WANTS_HTML, EVC_X_WANTS_HTML, "wants_html", N_("Wants HTML Mail"), FALSE), + + /* Instant messaging fields */ + LIST_FIELD (E_CONTACT_IM_AIM, EVC_X_AIM, "im_aim", N_("AIM Screen Name List"), FALSE), + LIST_FIELD (E_CONTACT_IM_JABBER, EVC_X_JABBER, "im_jabber", N_("Jabber Id List"), FALSE), + LIST_FIELD (E_CONTACT_IM_YAHOO, EVC_X_YAHOO, "im_yahoo", N_("Yahoo! Screen Name List"), FALSE), + LIST_FIELD (E_CONTACT_IM_MSN, EVC_X_MSN, "im_msn", N_("MSN Screen Name List"), FALSE), + LIST_FIELD (E_CONTACT_IM_ICQ, EVC_X_ICQ, "im_icq", N_("ICQ Id List"), FALSE), + + /* Organizational fields */ + LIST_ELEM_STR_FIELD (E_CONTACT_ORG, EVC_ORG, "org", N_("Organization"), FALSE, 0), + LIST_ELEM_STR_FIELD (E_CONTACT_ORG_UNIT, EVC_ORG, "org_unit", N_("Organizational Unit"), FALSE, 1), + LIST_ELEM_STR_FIELD (E_CONTACT_OFFICE, EVC_ORG, "office", N_("Office"), FALSE, 2), + + STRING_FIELD (E_CONTACT_TITLE, EVC_TITLE, "title", N_("Title"), FALSE), + STRING_FIELD (E_CONTACT_ROLE, EVC_ROLE, "role", N_("Role"), FALSE), + STRING_FIELD (E_CONTACT_MANAGER, EVC_X_MANAGER, "manager", N_("Manager"), FALSE), + STRING_FIELD (E_CONTACT_ASSISTANT, EVC_X_ASSISTANT, "assistant", N_("Assistant"), FALSE), + + /* Web fields */ + STRING_FIELD (E_CONTACT_HOMEPAGE_URL, EVC_URL, "homepage_url", N_("Homepage URL"), FALSE), + STRING_FIELD (E_CONTACT_BLOG_URL, EVC_X_BLOG_URL, "blog_url", N_("Weblog URL"), FALSE), + + /* Photo/Logo */ + STRUCT_FIELD (E_CONTACT_PHOTO, EVC_PHOTO, "photo", N_("Photo"), FALSE, photo_getter, photo_setter), + STRUCT_FIELD (E_CONTACT_LOGO, EVC_LOGO, "logo", N_("Logo"), FALSE, photo_getter, photo_setter), + + /* Contact categories */ +#if notyet + LIST_FIELD (E_CONTACT_CATEGORY_LIST, EVC_CATEGORIES, "category_list", N_("Category List"), FALSE), + SYNTH_STR_FIELD (E_CONTACT_CATEGORIES, "categories", N_("Categories"), FALSE), +#else + STRING_FIELD (E_CONTACT_CATEGORIES, EVC_CATEGORIES, "categories", N_("Categories"), FALSE), +#endif + + /* Collaboration fields */ + STRING_FIELD (E_CONTACT_CALENDAR_URI, EVC_CALURI, "caluri", N_("Calendar URI"), FALSE), + STRING_FIELD (E_CONTACT_FREEBUSY_URL, EVC_FBURL, "fburl", N_("Free/Busy URL"), FALSE), + STRING_FIELD (E_CONTACT_ICS_CALENDAR, EVC_ICSCALENDAR, "icscalendar", N_("ICS Calendar"), FALSE), + + /* Misc fields */ + STRING_FIELD (E_CONTACT_SPOUSE, EVC_X_SPOUSE, "spouse", N_("Spouse's Name"), FALSE), + STRING_FIELD (E_CONTACT_NOTE, EVC_NOTE, "note", N_("Note"), FALSE), + + STRUCT_FIELD (E_CONTACT_BIRTH_DATE, EVC_BDAY, "birth_date", N_("Birth Date"), FALSE, date_getter, date_setter), + STRUCT_FIELD (E_CONTACT_ANNIVERSARY, EVC_BDAY, "anniversary", N_("Anniversary"), FALSE, date_getter, date_setter), + + BOOLEAN_FIELD (E_CONTACT_IS_LIST, EVC_X_LIST, "list", N_("List"), FALSE), + BOOLEAN_FIELD (E_CONTACT_LIST_SHOW_ADDRESSES, EVC_X_LIST_SHOW_ADDRESSES, "list_show_addresses", N_("List Show Addresses"), FALSE) +}; + +#undef LIST_ELEM_STR_FIELD +#undef STRING_FIELD +#undef SYNTH_STR_FIELD +#undef LIST_FIELD +#undef STRUCT_FIELD + +static GObjectClass *parent_class; + +static void e_contact_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void e_contact_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +static void +e_contact_dispose (GObject *object) +{ + EContact *ec = E_CONTACT (object); + + if (!ec->priv) + return; + + /* XXX free instance specific stuff */ + + g_free (ec->priv); + ec->priv = NULL; + + if (G_OBJECT_CLASS (parent_class)->dispose) + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +e_contact_class_init (EContactClass *klass) +{ + GObjectClass *object_class; + int i; + + object_class = G_OBJECT_CLASS(klass); + + parent_class = g_type_class_ref (E_TYPE_VCARD); + + object_class->dispose = e_contact_dispose; + object_class->set_property = e_contact_set_property; + object_class->get_property = e_contact_get_property; + + for (i = 0; i < G_N_ELEMENTS (field_info); i ++) { + GParamSpec *pspec = NULL; + if (field_info[i].t & E_CONTACT_FIELD_TYPE_STRING) + pspec = g_param_spec_string (field_info[i].field_name, + _(field_info[i].pretty_name), + "" /* XXX blurb */, + NULL, + field_info[i].read_only ? G_PARAM_READABLE : G_PARAM_READWRITE); + else if (field_info[i].t & E_CONTACT_FIELD_TYPE_BOOLEAN) + pspec = g_param_spec_boolean (field_info[i].field_name, + _(field_info[i].pretty_name), + "" /* XXX blurb */, + FALSE, + field_info[i].read_only ? G_PARAM_READABLE : G_PARAM_READWRITE); + else + pspec = g_param_spec_pointer (field_info[i].field_name, + _(field_info[i].pretty_name), + "" /* XXX blurb */, + field_info[i].read_only ? G_PARAM_READABLE : G_PARAM_READWRITE); + + g_object_class_install_property (object_class, field_info[i].field_id, + pspec); + } +} + +static void +e_contact_init (EContact *ec) +{ + ec->priv = g_new0 (EContactPrivate, 1); +} + +GType +e_contact_get_type (void) +{ + static GType contact_type = 0; + + if (!contact_type) { + static const GTypeInfo contact_info = { + sizeof (EContactClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) e_contact_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EContact), + 0, /* n_preallocs */ + (GInstanceInitFunc) e_contact_init, + }; + + contact_type = g_type_register_static (E_TYPE_VCARD, "EContact", &contact_info, 0); + } + + return contact_type; +} + +static EVCardAttribute* +e_contact_get_first_attr (EContact *contact, const char *attr_name) +{ + GList *attrs, *l; + + attrs = e_vcard_get_attributes (E_VCARD (contact)); + + for (l = attrs; l; l = l->next) { + EVCardAttribute *attr = l->data; + const char *name, *group; + + group = e_vcard_attribute_get_group (attr); + name = e_vcard_attribute_get_name (attr); + + /* all the attributes we care about should be in group "" */ + if ((!group || !*group) && !strcasecmp (name, attr_name)) + return attr; + } + + return NULL; +} + + + +static void* +photo_getter (EContact *contact, EVCardAttribute *attr) +{ + if (attr) { + GList *values = e_vcard_attribute_get_values_decoded (attr); + + if (values && values->data) { + GString *s = values->data; + EContactPhoto *photo = g_new (EContactPhoto, 1); + + photo->length = s->len; + photo->data = g_malloc (photo->length); + memcpy (photo->data, s->str, photo->length); + + return photo; + } + } + + return NULL; +} + +static void +photo_setter (EContact *contact, EVCardAttribute *attr, void *data) +{ + EContactPhoto *photo = data; + const char *mime_type; + char *image_type = "X-EVOLUTION-UNKNOWN"; + + e_vcard_attribute_add_param_with_value (attr, + e_vcard_attribute_param_new (EVC_ENCODING), + "b"); + + mime_type = gnome_vfs_get_mime_type_for_data (photo->data, photo->length); + if (!strcmp (mime_type, "image/gif")) + image_type = "GIF"; + else if (!strcmp (mime_type, "image/jpeg")) + image_type = "JPEG"; + else if (!strcmp (mime_type, "image/png")) + image_type = "PNG"; + else if (!strcmp (mime_type, "image/tiff")) + image_type = "TIFF"; + /* i have no idea what these last 2 are.. :) */ + else if (!strcmp (mime_type, "image/ief")) + image_type = "IEF"; + else if (!strcmp (mime_type, "image/cgm")) + image_type = "CGM"; + + e_vcard_attribute_add_param_with_value (attr, + e_vcard_attribute_param_new (EVC_TYPE), + image_type); + + printf ("adding photo of type `%s' of length %d\n", image_type, photo->length); + e_vcard_attribute_add_value_decoded (attr, photo->data, photo->length); +} + + +static void* +fn_getter (EContact *contact, EVCardAttribute *attr) +{ + if (attr) { + GList *p = e_vcard_attribute_get_values (attr); + + return g_strdup (p && p->data ? p->data : ""); + } + else + return NULL; +} + +static void +fn_setter (EContact *contact, EVCardAttribute *attr, void *data) +{ + e_vcard_attribute_add_value (attr, (char*)data); + + attr = e_contact_get_first_attr (contact, EVC_N); + if (!attr) { + EContactName *name = e_contact_name_from_string ((char*)data); + + attr = e_vcard_attribute_new (NULL, EVC_N); + e_vcard_add_attribute (E_VCARD (contact), attr); + + /* call the setter directly */ + n_setter (contact, attr, name); + + e_contact_name_free (name); + } +} + + + +static void* +n_getter (EContact *contact, EVCardAttribute *attr) +{ + EContactName *name = g_new0 (EContactName, 1); + if (attr) { + GList *p = e_vcard_attribute_get_values (attr); + + name->family = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + name->given = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + name->additional = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + name->prefixes = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + name->suffixes = g_strdup (p && p->data ? p->data : ""); + } + + return name; +} + +static void +n_setter (EContact *contact, EVCardAttribute *attr, void *data) +{ + EContactName *name = data; + + e_vcard_attribute_add_value (attr, name->family); + e_vcard_attribute_add_value (attr, name->given); + e_vcard_attribute_add_value (attr, name->additional); + e_vcard_attribute_add_value (attr, name->prefixes); + e_vcard_attribute_add_value (attr, name->suffixes); + + /* now find the attribute for FileAs. if it's not present, fill it in */ + attr = e_contact_get_first_attr (contact, EVC_X_FILE_AS); + if (!attr) { + char *strings[3], **stringptr; + char *string; + attr = e_vcard_attribute_new (NULL, EVC_X_FILE_AS); + e_vcard_add_attribute (E_VCARD (contact), attr); + + stringptr = strings; + if (name->family && *name->family) + *(stringptr++) = name->family; + if (name->given && *name->given) + *(stringptr++) = name->given; + *stringptr = NULL; + string = g_strjoinv(", ", strings); + + e_vcard_attribute_add_value (attr, string); + g_free (string); + } + +} + + + +static void* +adr_getter (EContact *contact, EVCardAttribute *attr) +{ + if (attr) { + GList *p = e_vcard_attribute_get_values (attr); + EContactAddress *addr = g_new (EContactAddress, 1); + + addr->po = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + addr->ext = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + addr->street = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + addr->locality = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + addr->region = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + addr->code = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + addr->country = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next; + + return addr; + } + + return NULL; +} + +static void +adr_setter (EContact *contact, EVCardAttribute *attr, void *data) +{ + /* XXX */ + g_assert_not_reached (); +} + + + +static void* +date_getter (EContact *contact, EVCardAttribute *attr) +{ + if (attr) { + GList *p = e_vcard_attribute_get_values (attr); + EContactDate *date = e_contact_date_from_string (p && p->data ? (char*)p->data : ""); + + return date; + } + + return NULL; +} + +static void +date_setter (EContact *contact, EVCardAttribute *attr, void *data) +{ + EContactDate *date = data; + char *str = e_contact_date_to_string (date); + + e_vcard_attribute_add_value (attr, str); + g_free (str); +} + + + +/* Set_arg handler for the contact */ +static void +e_contact_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EContact *contact = E_CONTACT (object); + int i; + EContactFieldInfo *info = NULL; + + if (prop_id < 1 || prop_id >= E_CONTACT_FIELD_LAST) { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + return; + } + + + for (i = 0; i < G_N_ELEMENTS (field_info); i++) { + if (field_info[i].field_id == prop_id) { + info = &field_info[i]; + break; + } + } + + if (!info) { + g_warning ("unknown field %d", prop_id); + return; + } + + if (info->t & E_CONTACT_FIELD_TYPE_MULTI) { + GList *new_values = g_value_get_pointer (value); + GList *l; + + /* first we remove all attributes of the type we're + adding, then add new ones based on the values that + are passed in */ + e_vcard_remove_attributes (E_VCARD (contact), NULL, info->vcard_field_name); + + for (l = new_values; l; l = l->next) + e_vcard_add_attribute_with_value (E_VCARD (contact), + e_vcard_attribute_new (NULL, info->vcard_field_name), + (char*)l->data); + } + else if (info->t & E_CONTACT_FIELD_TYPE_SYNTHETIC) { + if (info->t & E_CONTACT_FIELD_TYPE_MULTI_ELEM) { + /* XXX this is kinda broken - we don't insert + insert padding elements if, e.g. the user + sets email 3 when email 1 and 2 don't + exist. But, if we *did* pad the lists we'd + end up with empty items in the vcard. I + dunno which is worse. */ + EVCardAttribute *attr = NULL; + gboolean found = FALSE; + int num_left = info->list_elem; + GList *attrs = e_vcard_get_attributes (E_VCARD (contact)); + GList *l; + + for (l = attrs; l; l = l->next) { + const char *name, *group; + + attr = l->data; + group = e_vcard_attribute_get_group (attr); + name = e_vcard_attribute_get_name (attr); + + /* all the attributes we care about should be in group "" */ + if ((!group || !*group) && !strcasecmp (name, info->vcard_field_name)) { + if (num_left-- == 0) { + found = TRUE; + break; + } + } + } + + if (found) { + /* we found it, overwrite it */ + e_vcard_attribute_remove_values (attr); + } + else { + /* we didn't find it - add a new attribute */ + attr = e_vcard_attribute_new (NULL, info->vcard_field_name); + e_vcard_add_attribute (E_VCARD (contact), attr); + } + + e_vcard_attribute_add_value (attr, g_value_get_string (value)); + } + else if (info->t & E_CONTACT_FIELD_TYPE_ATTR_TYPE) { + /* XXX this is kinda broken - we don't insert + insert padding elements if, e.g. the user + sets email 3 when email 1 and 2 don't + exist. But, if we *did* pad the lists we'd + end up with empty items in the vcard. I + dunno which is worse. */ + EVCardAttribute *attr = NULL; + gboolean found = FALSE; + int num_left = info->list_elem; + GList *attrs = e_vcard_get_attributes (E_VCARD (contact)); + GList *l; + const char *sval = g_value_get_string (value); + + for (l = attrs; l && !found; l = l->next) { + const char *name, *group; + gboolean found_needed1, found_needed2; + + if (!info->attr_type1) + found_needed1 = TRUE; + else + found_needed1 = FALSE; + + if (!info->attr_type2) + found_needed2 = TRUE; + else + found_needed2 = FALSE; + + attr = l->data; + group = e_vcard_attribute_get_group (attr); + name = e_vcard_attribute_get_name (attr); + + /* all the attributes we care about should be in group "" */ + if ((!group || !*group) && !strcasecmp (name, info->vcard_field_name)) { + GList *params; + + for (params = e_vcard_attribute_get_params (attr); params; params = params->next) { + EVCardAttributeParam *param = params->data; + const char *name = e_vcard_attribute_param_get_name (param); + + if (!strcasecmp (name, EVC_TYPE)) { + GList *values = e_vcard_attribute_param_get_values (param); + if (values && values->data) { + if (!found_needed1 && !strcasecmp ((char*)values->data, info->attr_type1)) + found_needed1 = TRUE; + else if (!found_needed2 && !strcasecmp ((char*)values->data, info->attr_type2)) + found_needed2 = TRUE; + } + } + + if (found_needed1 && found_needed2) { + if (num_left-- == 0) { + found = TRUE; + break; + } + } + } + } + } + + if (found) { + /* we found it, overwrite it */ + e_vcard_attribute_remove_values (attr); + } + else { + /* we didn't find it - add a new attribute */ + attr = e_vcard_attribute_new (NULL, info->vcard_field_name); + e_vcard_add_attribute (E_VCARD (contact), attr); + if (info->attr_type1) + e_vcard_attribute_add_param_with_value (attr, e_vcard_attribute_param_new (EVC_TYPE), + info->attr_type1); + if (info->attr_type2) + e_vcard_attribute_add_param_with_value (attr, e_vcard_attribute_param_new (EVC_TYPE), + info->attr_type2); + } + + if (sval && *sval) + e_vcard_attribute_add_value (attr, sval); + else + e_vcard_remove_attribute (E_VCARD (contact), attr); + } + else if (info->t & E_CONTACT_FIELD_TYPE_LIST_ELEM) { + EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name); + GList *values; + GList *p; + const char *sval = g_value_get_string (value); + + if (!attr) { + if (!sval || !*sval) + return; + + printf ("adding new %s\n", info->vcard_field_name); + + attr = e_vcard_attribute_new (NULL, info->vcard_field_name); + e_vcard_add_attribute (E_VCARD (contact), attr); + } + + values = e_vcard_attribute_get_values (attr); + p = g_list_nth (values, info->list_elem); + + if (p) { + g_free (p->data); + p->data = g_strdup (g_value_get_string (value)); + } + else { + /* there weren't enough elements in the list, pad it */ + int count = info->list_elem - g_list_length (values); + + while (count--) + e_vcard_attribute_add_value (attr, ""); + + e_vcard_attribute_add_value (attr, g_value_get_string (value)); + } + + } + } + else if (info->t & E_CONTACT_FIELD_TYPE_BOOLEAN) { + EVCardAttribute *attr; + + /* first we search for an attribute we can overwrite */ + attr = e_contact_get_first_attr (contact, info->vcard_field_name); + if (attr) { + printf ("setting %s to `%s'\n", info->vcard_field_name, g_value_get_string (value)); + e_vcard_attribute_remove_values (attr); + e_vcard_attribute_add_value (attr, g_value_get_boolean (value) ? "TRUE" : "FALSE"); + } + else { + /* and if we don't find one we create a new attribute */ + e_vcard_add_attribute_with_value (E_VCARD (contact), + e_vcard_attribute_new (NULL, info->vcard_field_name), + g_value_get_boolean (value) ? "TRUE" : "FALSE"); + } + } + else if (info->t & E_CONTACT_FIELD_TYPE_STRING) { + EVCardAttribute *attr; + const char *sval = g_value_get_string (value); + + /* first we search for an attribute we can overwrite */ + attr = e_contact_get_first_attr (contact, info->vcard_field_name); + if (attr) { + printf ("setting %s to `%s'\n", info->vcard_field_name, sval); + e_vcard_attribute_remove_values (attr); + if (sval) + e_vcard_attribute_add_value (attr, sval); + } + else if (sval) { + /* and if we don't find one we create a new attribute */ + e_vcard_add_attribute_with_value (E_VCARD (contact), + e_vcard_attribute_new (NULL, info->vcard_field_name), + g_value_get_string (value)); + } + } + else if (info->t & E_CONTACT_FIELD_TYPE_STRUCT) { + EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name); + void *data = g_value_get_pointer (value); + + if (attr) { + printf ("overwriting existing %s\n", info->vcard_field_name); + /* remove all existing values and parameters. + the setter will add the correct ones */ + e_vcard_attribute_remove_values (attr); + e_vcard_attribute_remove_params (attr); + } + else { + printf ("adding new %s\n", info->vcard_field_name); + attr = e_vcard_attribute_new (NULL, info->vcard_field_name); + + e_vcard_add_attribute (E_VCARD (contact), attr); + } + + info->struct_setter (contact, attr, data); + } + else { + g_warning ("unhandled attribute `%s'", info->vcard_field_name); + } +} + +static GList * +e_contact_get_email_list (EContact *contact) +{ + GList *rv = NULL; + GList *attrs, *l; + + attrs = e_vcard_get_attributes (E_VCARD (contact)); + + for (l = attrs; l; l = l->next) { + EVCardAttribute *attr = l->data; + const char *name, *group; + + group = e_vcard_attribute_get_group (attr); + name = e_vcard_attribute_get_name (attr); + + /* all the attributes we care about should be in group "" */ + if ((!group || !*group) && !strcasecmp (name, EVC_EMAIL)) { + GList *v = e_vcard_attribute_get_values (attr); + + rv = g_list_append (rv, v ? g_strdup (v->data) : NULL); + } + } + + return rv; +} + +static EVCardAttribute * +e_contact_find_attribute_with_types (EContact *contact, const char *attr_name, const char *type_needed1, const char *type_needed2, int nth) +{ + GList *l, *attrs; + gboolean found_needed1, found_needed2; + + attrs = e_vcard_get_attributes (E_VCARD (contact)); + + for (l = attrs; l; l = l->next) { + EVCardAttribute *attr = l->data; + const char *name, *group; + + if (!type_needed1) + found_needed1 = TRUE; + else + found_needed1 = FALSE; + + if (!type_needed2) + found_needed2 = TRUE; + else + found_needed2 = FALSE; + + group = e_vcard_attribute_get_group (attr); + name = e_vcard_attribute_get_name (attr); + + /* all the attributes we care about should be in group "" */ + if ((!group || !*group) && !strcasecmp (name, attr_name)) { + GList *params; + + for (params = e_vcard_attribute_get_params (attr); params; params = params->next) { + EVCardAttributeParam *param = params->data; + const char *name = e_vcard_attribute_param_get_name (param); + + if (!strcasecmp (name, EVC_TYPE)) { + GList *values = e_vcard_attribute_param_get_values (param); + if (values && values->data) { + if (!found_needed1 && !strcasecmp ((char*)values->data, type_needed1)) + found_needed1 = TRUE; + else if (!found_needed2 && !strcasecmp ((char*)values->data, type_needed2)) + found_needed2 = TRUE; + } + } + + if (found_needed1 && found_needed2) { + if (nth-- == 0) + return attr; + else + break; + } + } + } + } + + return NULL; +} + +static void +e_contact_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EContact *contact = E_CONTACT (object); + int i; + EContactFieldInfo *info = NULL; + + if (prop_id < 1 || prop_id >= E_CONTACT_FIELD_LAST) { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + return; + } + + for (i = 0; i < G_N_ELEMENTS (field_info); i++) { + if (field_info[i].field_id == prop_id) { + info = &field_info[i]; + break; + } + } + + if (!info) { + g_warning ("unknown field %d", prop_id); + return; + } + else if (info->t & E_CONTACT_FIELD_TYPE_BOOLEAN) { + EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name); + gboolean rv = FALSE; + + if (attr) { + GList *v = e_vcard_attribute_get_values (attr); + rv = v && v->data && !strcasecmp ((char*)v->data, "true"); + } + + g_value_set_boolean (value, rv); + } + else if (info->t & E_CONTACT_FIELD_TYPE_LIST) { + EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name); + + if (attr) + g_value_set_pointer (value, e_vcard_attribute_get_values (attr)); + } + else if (info->t & E_CONTACT_FIELD_TYPE_LIST_ELEM) { + if (info->t & E_CONTACT_FIELD_TYPE_STRING) { + GList *attrs, *l; + + attrs = e_vcard_get_attributes (E_VCARD (contact)); + + for (l = attrs; l; l = l->next) { + EVCardAttribute *attr = l->data; + const char *name, *group; + + group = e_vcard_attribute_get_group (attr); + name = e_vcard_attribute_get_name (attr); + + /* all the attributes we care about should be in group "" */ + if ((!group || !*group) && !strcasecmp (name, info->vcard_field_name)) { + GList *v; + int count; + + v = e_vcard_attribute_get_values (attr); + count = info->list_elem; + + v = g_list_nth (v, info->list_elem); + + g_value_set_string (value, v ? v->data : NULL); + } + } + } + } + else if (info->t & E_CONTACT_FIELD_TYPE_MULTI_ELEM) { + if (info->t & E_CONTACT_FIELD_TYPE_STRING) { + GList *attrs, *l; + + attrs = e_vcard_get_attributes (E_VCARD (contact)); + + for (l = attrs; l; l = l->next) { + EVCardAttribute *attr = l->data; + const char *name, *group; + + group = e_vcard_attribute_get_group (attr); + name = e_vcard_attribute_get_name (attr); + + /* all the attributes we care about should be in group "" */ + if ((!group || !*group) && !strcasecmp (name, info->vcard_field_name)) { + GList *v; + int count; + + v = e_vcard_attribute_get_values (attr); + count = info->list_elem; + + v = g_list_nth (v, info->list_elem); + + g_value_set_string (value, v ? v->data : NULL); + } + } + } + } + else if (info->t & E_CONTACT_FIELD_TYPE_ATTR_TYPE) { + EVCardAttribute *attr = e_contact_find_attribute_with_types (contact, info->vcard_field_name, info->attr_type1, info->attr_type2, info->list_elem); + + if (info->t & E_CONTACT_FIELD_TYPE_STRING) { + if (attr) { + GList *p = e_vcard_attribute_get_values (attr); + char *rv = p->data; + + g_value_set_string (value, rv); + } + else { + g_value_set_string (value, NULL); + } + } + else { /* struct */ + gpointer rv = info->struct_getter (contact, attr); + + g_value_set_pointer (value, rv); + } + + } + else if (info->t & E_CONTACT_FIELD_TYPE_STRUCT) { + EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name); + void *rv = NULL; + + if (attr) + rv = info->struct_getter (contact, attr); + + g_value_set_pointer (value, rv); + } + + else if (info->t & E_CONTACT_FIELD_TYPE_SYNTHETIC) { + switch (info->field_id) { + default: + g_warning ("unhandled synthetic field 0x%02x", info->field_id); + } + } + else { + GList *attrs, *l; + GList *rv = NULL; /* used for multi attribute lists */ + + attrs = e_vcard_get_attributes (E_VCARD (contact)); + + for (l = attrs; l; l = l->next) { + EVCardAttribute *attr = l->data; + const char *name, *group; + + group = e_vcard_attribute_get_group (attr); + name = e_vcard_attribute_get_name (attr); + + /* all the attributes we care about should be in group "" */ + if ((!group || !*group) && !strcasecmp (name, info->vcard_field_name)) { + GList *v; + v = e_vcard_attribute_get_values (attr); + + if (info->t & E_CONTACT_FIELD_TYPE_STRING) { + g_value_set_string (value, v ? v->data : NULL); + } + else { + rv = g_list_append (rv, v ? g_strdup (v->data) : NULL); + + g_value_set_pointer (value, rv); + } + } + } + } +} + + + +EContact* +e_contact_new (void) +{ + return e_contact_new_from_vcard (""); +} + +EContact* +e_contact_new_from_vcard (const char *vcard) +{ + EContact *contact = g_object_new (E_TYPE_CONTACT, NULL); + + e_vcard_construct (E_VCARD (contact), vcard); + + return contact; +} + +EContact* +e_contact_duplicate (EContact *contact) +{ + char *vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30); + EContact *c = e_contact_new_from_vcard (vcard); + + g_free (vcard); + + return c; +} + +const char * +e_contact_field_name (EContactField field_id) +{ + int i; + + g_return_val_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST, ""); + + for (i = 0; i < G_N_ELEMENTS (field_info); i ++) { + if (field_id == field_info[i].field_id) + return field_info[i].field_name; + } + + g_warning ("unknown field id %d", field_id); + return ""; +} + +const char * +e_contact_pretty_name (EContactField field_id) +{ + int i; + + g_return_val_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST, ""); + + for (i = 0; i < G_N_ELEMENTS (field_info); i ++) { + if (field_id == field_info[i].field_id) + return _(field_info[i].pretty_name); + } + + g_warning ("unknown field id %d", field_id); + return ""; +} + +EContactField +e_contact_field_id (const char *field_name) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS (field_info); i ++) { + if (!strcmp (field_info[i].field_name, field_name)) + return field_info[i].field_id; + } + + g_warning ("unknown field name `%s'", field_name); + return 0; +} + +gpointer +e_contact_get (EContact *contact, EContactField field_id) +{ + gpointer value; + + g_return_val_if_fail (contact && E_IS_CONTACT (contact), NULL); + g_return_val_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST, NULL); + + g_object_get (contact, + e_contact_field_name (field_id), &value, + NULL); + + return value; +} + +/* XXX this won't work for structure/list types... */ +static void +free_const_data (gpointer data, GObject *where_object_was) +{ + g_free (data); +} + +const gpointer +e_contact_get_const (EContact *contact, EContactField field_id) +{ + gpointer value; + + g_return_val_if_fail (E_IS_CONTACT (contact), NULL); + g_return_val_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST, NULL); + + value = e_contact_get (contact, field_id); + + g_object_weak_ref (G_OBJECT (contact), free_const_data, value); + + return value; +} + +void +e_contact_set (EContact *contact, EContactField field_id, gpointer value) +{ + printf ("e_contact_set (%p, %d, %p)\n", contact, field_id, value); + + g_return_if_fail (contact && E_IS_CONTACT (contact)); + g_return_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST); + + g_object_set (contact, + e_contact_field_name (field_id), value, + NULL); +} + +EContactName* +e_contact_name_new () +{ + return g_new0 (EContactName, 1); +} + +char * +e_contact_name_to_string(const EContactName *name) +{ + char *strings[6], **stringptr = strings; + + g_return_val_if_fail (name != NULL, NULL); + + if (name->prefixes && *name->prefixes) + *(stringptr++) = name->prefixes; + if (name->given && *name->given) + *(stringptr++) = name->given; + if (name->additional && *name->additional) + *(stringptr++) = name->additional; + if (name->family && *name->family) + *(stringptr++) = name->family; + if (name->suffixes && *name->suffixes) + *(stringptr++) = name->suffixes; + *stringptr = NULL; + return g_strjoinv(" ", strings); +} + +EContactName* +e_contact_name_from_string (const char *name_str) +{ + EContactName *name = e_contact_name_new(); + ENameWestern *western = e_name_western_parse (name_str); + + name->prefixes = g_strdup (western->prefix); + name->given = g_strdup (western->first ); + name->additional = g_strdup (western->middle); + name->family = g_strdup (western->last ); + name->suffixes = g_strdup (western->suffix); + + e_name_western_free(western); + + return name; +} + +EContactName* +e_contact_name_copy (EContactName *n) +{ + EContactName *name = e_contact_name_new(); + + name->prefixes = g_strdup (n->prefixes); + name->given = g_strdup (n->given); + name->additional = g_strdup (n->additional); + name->family = g_strdup (n->family); + name->suffixes = g_strdup (n->suffixes); + + return name; +} + +void +e_contact_name_free (EContactName *name) +{ + if (!name) + return; + + g_free (name->family); + g_free (name->given); + g_free (name->additional); + g_free (name->prefixes); + g_free (name->suffixes); + + g_free (name); +} + +EContactDate* +e_contact_date_new (void) +{ + return g_new0 (EContactDate, 1); +} + +EContactDate* +e_contact_date_from_string (const char *str) +{ + EContactDate* date = e_contact_date_new(); + int length; + + length = strlen(str); + + if (length == 10 ) { + date->year = str[0] * 1000 + str[1] * 100 + str[2] * 10 + str[3] - '0' * 1111; + date->month = str[5] * 10 + str[6] - '0' * 11; + date->day = str[8] * 10 + str[9] - '0' * 11; + } else if ( length == 8 ) { + date->year = str[0] * 1000 + str[1] * 100 + str[2] * 10 + str[3] - '0' * 1111; + date->month = str[4] * 10 + str[5] - '0' * 11; + date->day = str[6] * 10 + str[7] - '0' * 11; + } + + return date; +} + +char * +e_contact_date_to_string (EContactDate *dt) +{ + if (dt) + return g_strdup_printf ("%04d-%02d-%02d", + CLAMP(dt->year, 1000, 9999), + CLAMP(dt->month, 1, 12), + CLAMP(dt->day, 1, 31)); + else + return NULL; +} + +void +e_contact_date_free (EContactDate *dt) +{ + g_free (dt); +} + + +void +e_contact_photo_free (EContactPhoto *photo) +{ + if (!photo) + return; + + g_free (photo->data); + g_free (photo); +} + +void +e_contact_address_free (EContactAddress *address) +{ + if (!address) + return; + + g_free (address->address_format); + g_free (address->po); + g_free (address->ext); + g_free (address->street); + g_free (address->locality); + g_free (address->region); + g_free (address->code); + g_free (address->country); + + g_free (address); +} diff --git a/addressbook/backend/ebook/e-contact.h b/addressbook/backend/ebook/e-contact.h new file mode 100644 index 0000000000..8de02caa5f --- /dev/null +++ b/addressbook/backend/ebook/e-contact.h @@ -0,0 +1,227 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: + * Chris Toshok + * + * Copyright (C) 2003 Ximian, Inc. + */ + +#ifndef __E_CONTACT_H__ +#define __E_CONTACT_H__ + +#include +#include +#include +#include + +#define E_TYPE_CONTACT (e_contact_get_type ()) +#define E_CONTACT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CONTACT, EContact)) +#define E_CONTACT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CONTACT, EContactClass)) +#define E_IS_CONTACT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CONTACT)) +#define E_IS_CONTACT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CONTACT)) +#define E_CONTACT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CONTACT, EContactClass)) + +typedef struct _EContact EContact; +typedef struct _EContactClass EContactClass; +typedef struct _EContactPrivate EContactPrivate; + +typedef enum { + + E_CONTACT_UID = 1, /* string field */ + E_CONTACT_FILE_AS, /* string field */ + + /* Name fields */ + E_CONTACT_FULL_NAME, /* string field */ + E_CONTACT_GIVEN_NAME, /* synthetic string field */ + E_CONTACT_FAMILY_NAME, /* synthetic string field */ + E_CONTACT_NICKNAME, /* string field */ + + /* Email fields */ + E_CONTACT_EMAIL_1, /* synthetic string field */ + E_CONTACT_EMAIL_2, /* synthetic string field */ + E_CONTACT_EMAIL_3, /* synthetic string field */ + + E_CONTACT_MAILER, /* string field */ + + /* Address Labels */ + E_CONTACT_ADDRESS_LABEL_HOME, /* synthetic string field */ + E_CONTACT_ADDRESS_LABEL_WORK, /* synthetic string field */ + E_CONTACT_ADDRESS_LABEL_OTHER, /* synthetic string field */ + + /* Phone fields */ + E_CONTACT_PHONE_ASSISTANT, + E_CONTACT_PHONE_BUSINESS, + E_CONTACT_PHONE_BUSINESS_2, + E_CONTACT_PHONE_BUSINESS_FAX, + E_CONTACT_PHONE_CALLBACK, + E_CONTACT_PHONE_CAR, + E_CONTACT_PHONE_COMPANY, + E_CONTACT_PHONE_HOME, + E_CONTACT_PHONE_HOME_2, + E_CONTACT_PHONE_HOME_FAX, + E_CONTACT_PHONE_ISDN, + E_CONTACT_PHONE_MOBILE, + E_CONTACT_PHONE_OTHER, + E_CONTACT_PHONE_OTHER_FAX, + E_CONTACT_PHONE_PAGER, + E_CONTACT_PHONE_PRIMARY, + E_CONTACT_PHONE_RADIO, + E_CONTACT_PHONE_TELEX, + E_CONTACT_PHONE_TTYTDD, + + /* Organizational fields */ + E_CONTACT_ORG, /* string field */ + E_CONTACT_ORG_UNIT, /* string field */ + E_CONTACT_OFFICE, /* string field */ + E_CONTACT_TITLE, /* string field */ + E_CONTACT_ROLE, /* string field */ + E_CONTACT_MANAGER, /* string field */ + E_CONTACT_ASSISTANT, /* string field */ + + /* Web fields */ + E_CONTACT_HOMEPAGE_URL, /* string field */ + E_CONTACT_BLOG_URL, /* string field */ + + /* Contact categories */ + E_CONTACT_CATEGORIES, /* string field */ + + /* Collaboration fields */ + E_CONTACT_CALENDAR_URI, /* string field */ + E_CONTACT_FREEBUSY_URL, /* string field */ + E_CONTACT_ICS_CALENDAR, /* string field */ + + /* misc fields */ + E_CONTACT_SPOUSE, /* string field */ + E_CONTACT_NOTE, /* string field */ + + /* fields used for describing contact lists. a contact list + is just a contact with _IS_LIST set to true. the members + are listed in the _EMAIL field. */ + E_CONTACT_IS_LIST, /* boolean field */ + E_CONTACT_LIST_SHOW_ADDRESSES, /* boolean field */ + + /* Instant Messaging fields */ + E_CONTACT_IM_AIM, /* Multi-valued */ + E_CONTACT_IM_JABBER, /* Multi-valued */ + E_CONTACT_IM_YAHOO, /* Multi-valued */ + E_CONTACT_IM_MSN, /* Multi-valued */ + E_CONTACT_IM_ICQ, /* Multi-valued */ + + /* Address fields */ + E_CONTACT_ADDRESS, /* Multi-valued structured (EContactAddress) */ + E_CONTACT_ADDRESS_HOME, /* synthetic structured field (EContactAddress) */ + E_CONTACT_ADDRESS_WORK, /* synthetic structured field (EContactAddress) */ + E_CONTACT_ADDRESS_OTHER, /* synthetic structured field (EContactAddress) */ + + E_CONTACT_CATEGORY_LIST, /* multi-valued */ + + /* Photo/Logo */ + E_CONTACT_PHOTO, /* structured field (EContactPhoto) */ + E_CONTACT_LOGO, /* structured field (EContactPhoto) */ + + E_CONTACT_NAME, /* structured field (EContactName) */ + E_CONTACT_EMAIL, /* Multi-valued */ + + E_CONTACT_WANTS_HTML, /* boolean field */ + + E_CONTACT_BIRTH_DATE, /* structured field (EContactDate) */ + E_CONTACT_ANNIVERSARY, /* structured field (EContactDate) */ + + E_CONTACT_FIELD_LAST, + + /* useful constants */ + E_CONTACT_LAST_SIMPLE_STRING = E_CONTACT_NOTE, + E_CONTACT_FIRST_PHONE_ID = E_CONTACT_PHONE_ASSISTANT, + E_CONTACT_LAST_PHONE_ID = E_CONTACT_PHONE_TTYTDD, + E_CONTACT_FIRST_EMAIL_ID = E_CONTACT_EMAIL_1, + E_CONTACT_LAST_EMAIL_ID = E_CONTACT_EMAIL_3, + E_CONTACT_FIRST_ADDRESS_ID = E_CONTACT_ADDRESS_HOME, + E_CONTACT_LAST_ADDRESS_ID = E_CONTACT_ADDRESS_OTHER, + E_CONTACT_FIRST_LABEL_ID = E_CONTACT_ADDRESS_LABEL_HOME, + E_CONTACT_LAST_LABEL_ID = E_CONTACT_ADDRESS_LABEL_OTHER + +} EContactField; + +typedef struct { + char *family; + char *given; + char *additional; + char *prefixes; + char *suffixes; +} EContactName; + +typedef struct { + int length; + char *data; +} EContactPhoto; + +typedef struct { + char *address_format; /* the two letter country code that + determines the format/meaning of the + following fields */ + char *po; + char *ext; + char *street; + char *locality; + char *region; + char *code; + char *country; +} EContactAddress; + +typedef struct { + int year; + int month; + int day; +} EContactDate; + +struct _EContact { + EVCard parent; + + EContactPrivate *priv; +}; + +struct _EContactClass { + EVCardClass parent_class; + + /* Padding for future expansion */ + void (*_ebook_reserved0) (void); + void (*_ebook_reserved1) (void); + void (*_ebook_reserved2) (void); + void (*_ebook_reserved3) (void); + void (*_ebook_reserved4) (void); +}; + +GType e_contact_get_type (void); + +EContact* e_contact_new (void); +EContact* e_contact_new_from_vcard (const char *vcard); + +EContact* e_contact_duplicate (EContact *contact); + +gpointer e_contact_get (EContact *contact, EContactField field_id); +const gpointer e_contact_get_const (EContact *contact, EContactField field_id); +void e_contact_set (EContact *contact, EContactField field_id, gpointer value); + +/* misc functions for structured values */ +EContactDate *e_contact_date_new (void); +EContactDate *e_contact_date_from_string (const char *str); +char *e_contact_date_to_string (EContactDate *dt); + +EContactName *e_contact_name_new (void); +char *e_contact_name_to_string (const EContactName *name); +EContactName *e_contact_name_from_string (const char *name_str); +EContactName *e_contact_name_copy (EContactName *name); + + +/* destructors for structured values */ +void e_contact_date_free (EContactDate *date); +void e_contact_name_free (EContactName *name); +void e_contact_photo_free (EContactPhoto *photo); +void e_contact_address_free (EContactAddress *address); + + +const char* e_contact_field_name (EContactField field_id); +const char* e_contact_pretty_name (EContactField field_id); +EContactField e_contact_field_id (const char *field_name); + +#endif /* __E_CONTACT_H__ */ diff --git a/addressbook/backend/ebook/e-destination.h b/addressbook/backend/ebook/e-destination.h deleted file mode 100644 index acd6af1bc4..0000000000 --- a/addressbook/backend/ebook/e-destination.h +++ /dev/null @@ -1,140 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* - * e-destination.h - * - * Copyright (C) 2001 Ximian, Inc. - * - * Developed by Jon Trowbridge - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - */ - -#ifndef __E_DESTINATION_H__ -#define __E_DESTINATION_H__ - -#include -#include -#include -#include -#include - -#define E_TYPE_DESTINATION (e_destination_get_type ()) -#define E_DESTINATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_DESTINATION, EDestination)) -#define E_DESTINATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), E_TYPE_DESTINATION, EDestinationClass)) -#define E_IS_DESTINATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_DESTINATION)) -#define E_IS_DESTINATION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_DESTINATION)) -#define E_DESTINATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_DESTINATION, EDestinationClass)) - -typedef struct _EDestination EDestination; -typedef struct _EDestinationClass EDestinationClass; - -typedef void (*EDestinationCardCallback) (EDestination *dest, ECard *card, gpointer closure); - -struct _EDestinationPrivate; - -struct _EDestination { - GObject object; - - struct _EDestinationPrivate *priv; -}; - -struct _EDestinationClass { - GObjectClass parent_class; - - void (*changed) (EDestination *dest); - void (*cardified) (EDestination *dest); -}; - -GType e_destination_get_type (void); - - -EDestination *e_destination_new (void); -void e_destination_changed (EDestination *); -EDestination *e_destination_copy (const EDestination *); -void e_destination_clear (EDestination *); - -gboolean e_destination_is_empty (const EDestination *); -gboolean e_destination_is_valid (const EDestination *); -gboolean e_destination_equal (const EDestination *a, const EDestination *b); - -void e_destination_set_card (EDestination *, ECard *card, gint email_num); -void e_destination_set_book_uri (EDestination *, const gchar *uri); -void e_destination_set_card_uid (EDestination *, const gchar *uid, gint email_num); - -void e_destination_set_name (EDestination *, const gchar *name); -void e_destination_set_email (EDestination *, const gchar *email); - -void e_destination_set_html_mail_pref (EDestination *, gboolean); - -gboolean e_destination_contains_card (const EDestination *); -gboolean e_destination_from_card (const EDestination *); - -gboolean e_destination_is_auto_recipient (const EDestination *); -void e_destination_set_auto_recipient (EDestination *, gboolean value); - -void e_destination_use_card (EDestination *, EDestinationCardCallback cb, gpointer closure); - -ECard *e_destination_get_card (const EDestination *); -const gchar *e_destination_get_book_uri (const EDestination *); -const gchar *e_destination_get_card_uid (const EDestination *); -gint e_destination_get_email_num (const EDestination *); - -const gchar *e_destination_get_name (const EDestination *); /* "Jane Smith" */ -const gchar *e_destination_get_email (const EDestination *); /* "jane@assbarn.com" */ -const gchar *e_destination_get_address (const EDestination *);; /* "Jane Smith " (or a comma-sep set of such for a list) */ - -void e_destination_set_raw (EDestination *, const gchar *free_form_string); -const gchar *e_destination_get_textrep (const EDestination *, gboolean include_email); /* "Jane Smith" or "jane@assbarn.com" */ - -gboolean e_destination_is_evolution_list (const EDestination *); -gboolean e_destination_list_show_addresses (const EDestination *); - -/* If true, they want HTML mail. */ -gboolean e_destination_get_html_mail_pref (const EDestination *); - -gboolean e_destination_allow_cardification (const EDestination *); -void e_destination_set_allow_cardification (EDestination *, gboolean); -void e_destination_cardify (EDestination *, EBook *); -void e_destination_cardify_delayed (EDestination *, EBook *, gint delay); /* delay < 0: "default" */ -void e_destination_cancel_cardify (EDestination *); -gboolean e_destination_uncardify (EDestination *); - -gboolean e_destination_revert (EDestination *); - -gchar *e_destination_get_address_textv (EDestination **); - -xmlNodePtr e_destination_xml_encode (const EDestination *dest); -gboolean e_destination_xml_decode (EDestination *dest, xmlNodePtr node); - -gchar *e_destination_export (const EDestination *); -EDestination *e_destination_import (const gchar *str); - -gchar *e_destination_exportv (EDestination **); -EDestination **e_destination_importv (const gchar *str); - -EDestination **e_destination_list_to_vector_sized (GList *, int n); -EDestination **e_destination_list_to_vector (GList *); - -void e_destination_freev (EDestination **); - -void e_destination_touch (EDestination *); -void e_destination_touchv (EDestination **); - - -#endif /* __E_DESTINATION_H__ */ - diff --git a/addressbook/backend/ebook/e-vcard.c b/addressbook/backend/ebook/e-vcard.c index 62ebda9349..7ea1d9da84 100644 --- a/addressbook/backend/ebook/e-vcard.c +++ b/addressbook/backend/ebook/e-vcard.c @@ -1,5 +1,5 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* evcard.h +/* e-vcard.c * * Copyright (C) 2003 Ximian, Inc. * @@ -22,11 +22,18 @@ #include #include +#include #include #include "e-vcard.h" #define CRLF "\r\n" +typedef enum { + EVC_ENCODING_RAW, /* no encoding */ + EVC_ENCODING_BASE64, /* base64 */ + EVC_ENCODING_QP /* quoted-printable */ +} EVCardEncoding; + struct _EVCardPrivate { GList *attributes; }; @@ -36,6 +43,9 @@ struct _EVCardAttribute { char *name; GList *params; /* EVCardParam */ GList *values; + GList *decoded_values; + EVCardEncoding encoding; + gboolean encoding_set; }; struct _EVCardAttributeParam { @@ -45,6 +55,12 @@ struct _EVCardAttributeParam { static GObjectClass *parent_class; +static void _evc_base64_init(void); +static size_t _evc_base64_encode_step(unsigned char *in, size_t len, gboolean break_lines, unsigned char *out, int *state, int *save); +static size_t _evc_base64_decode_step(unsigned char *in, size_t len, unsigned char *out, int *state, unsigned int *save); +size_t _evc_base64_decode_simple (char *data, size_t len); +char *_evc_base64_encode_simple (const char *data, size_t len); + static void e_vcard_dispose (GObject *object) { @@ -73,6 +89,8 @@ e_vcard_class_init (EVCardClass *klass) parent_class = g_type_class_ref (G_TYPE_OBJECT); object_class->dispose = e_vcard_dispose; + + _evc_base64_init(); } static void @@ -229,9 +247,9 @@ read_attribute_value (EVCardAttribute *attr, char **p, gboolean quoted_printable g_warning ("invalid escape, passing it through"); str = g_string_append_c (str, '\\'); str = g_string_append_unichar (str, g_utf8_get_char(lp)); - lp = g_utf8_next_char(lp); break; } + lp = g_utf8_next_char(lp); } else if (*lp == ';') { e_vcard_attribute_add_value (attr, g_string_free (str, FALSE)); @@ -480,14 +498,16 @@ parse (EVCard *evc, const char *str) *end = '\0'; } +#if DEBUG_FOLDING printf ("BEFORE FOLDING:\n"); printf (str); - +#endif buf = fold_lines (buf); +#if DEBUG_FOLDING printf ("\n\nAFTER FOLDING:\n"); printf (buf); - +#endif p = buf; attr = read_attribute (&p); @@ -508,6 +528,8 @@ parse (EVCard *evc, const char *str) if (!attr || attr->group || g_ascii_strcasecmp (attr->name, "end")) { g_warning ("vcard ended without END:VCARD\n"); } + + g_free (buf); } static char* @@ -517,7 +539,7 @@ escape_string (const char *s) const char *p; /* Escape a string as described in RFC2426, section 5 */ - for (p = s; *p; p++) { + for (p = s; p && *p; p++) { switch (*p) { case '\n': str = g_string_append (str, "\\n"); @@ -579,24 +601,42 @@ unescape_string (const char *s) } #endif +void +e_vcard_construct (EVCard *evc, const char *str) +{ + if (*str) + parse (evc, str); +} + EVCard * e_vcard_new () { - return g_object_new (E_TYPE_VCARD, NULL); + return e_vcard_new_from_string (""); } EVCard * e_vcard_new_from_string (const char *str) { - EVCard *evc = e_vcard_new (); + EVCard *evc; - parse (evc, str); + g_return_val_if_fail (str, NULL); + + evc = g_object_new (E_TYPE_VCARD, NULL); + + e_vcard_construct (evc, str); return evc; } -char* -e_vcard_to_string (EVCard *evc) +static char* +e_vcard_to_string_vcard_21 (EVCard *evc) +{ + g_warning ("need to implement e_vcard_to_string_vcard_21"); + return g_strdup (""); +} + +static char* +e_vcard_to_string_vcard_30 (EVCard *evc) { GList *l; GList *v; @@ -680,6 +720,20 @@ e_vcard_to_string (EVCard *evc) return g_string_free (str, FALSE); } +char* +e_vcard_to_string (EVCard *evc, EVCardFormat format) +{ + switch (format) { + case EVC_FORMAT_VCARD_21: + return e_vcard_to_string_vcard_21 (evc); + case EVC_FORMAT_VCARD_30: + return e_vcard_to_string_vcard_30 (evc); + default: + g_warning ("invalid format specifier passed to e_vcard_to_string"); + return g_strdup (""); + } +} + void e_vcard_dump_structure (EVCard *evc) { @@ -732,24 +786,62 @@ e_vcard_attribute_new (const char *attr_group, const char *attr_name) void e_vcard_attribute_free (EVCardAttribute *attr) { - GList *p; - g_free (attr->group); g_free (attr->name); - g_list_foreach (attr->values, (GFunc)g_free, NULL); - g_list_free (attr->values); + e_vcard_attribute_remove_values (attr); + + e_vcard_attribute_remove_params (attr); + + g_free (attr); +} + +EVCardAttribute* +e_vcard_attribute_copy (EVCardAttribute *attr) +{ + EVCardAttribute *a = e_vcard_attribute_new (e_vcard_attribute_get_group (attr), + e_vcard_attribute_get_name (attr)); + GList *p; + + for (p = attr->values; p; p = p->next) + e_vcard_attribute_add_value (a, p->data); + + for (p = attr->params; p; p = p->next) + e_vcard_attribute_add_param (a, e_vcard_attribute_param_copy (p->data)); + + return a; +} + +void +e_vcard_remove_attributes (EVCard *evc, const char *attr_group, const char *attr_name) +{ + GList *attr; + + attr = evc->priv->attributes; + while (attr) { + GList *next_attr; + EVCardAttribute *a = attr->data; + + next_attr = attr->next; + + if (((!attr_group && !a->group) || !g_ascii_strcasecmp (attr_group, a->group)) && + ((!attr_name && !a->name) || !g_ascii_strcasecmp (attr_name, a->name))) { + + /* matches, remove/delete the attribute */ + evc->priv->attributes = g_list_remove_link (evc->priv->attributes, attr); - for (p = attr->params; p; p = p->next) { - EVCardAttributeParam *param = p->data; + e_vcard_attribute_free (a); + } - g_free (param->name); - g_list_foreach (param->values, (GFunc)g_free, NULL); - g_list_free (param->values); - g_free (param); + attr = next_attr; } +} - g_free (attr); +void +e_vcard_remove_attribute (EVCard *evc, EVCardAttribute *attr) +{ + evc->priv->attributes = g_list_remove (evc->priv->attributes, attr); + e_vcard_attribute_free (attr); } void @@ -790,6 +882,33 @@ e_vcard_attribute_add_value (EVCardAttribute *attr, const char *value) attr->values = g_list_append (attr->values, g_strdup (value)); } +void +e_vcard_attribute_add_value_decoded (EVCardAttribute *attr, const char *value, int len) +{ + switch (attr->encoding) { + case EVC_ENCODING_RAW: + g_warning ("can't add_value_decoded with an attribute using RAW encoding. you must set the ENCODING parameter first"); + break; + case EVC_ENCODING_BASE64: { + char *b64_data = _evc_base64_encode_simple (value, len); + GString *decoded = g_string_new_len (value, len); + + /* make sure the decoded list is up to date */ + e_vcard_attribute_get_values_decoded (attr); + + printf ("base64 encoded value: %s\n", b64_data); + printf ("original length: %d\n", len); + + attr->values = g_list_append (attr->values, b64_data); + attr->decoded_values = g_list_append (attr->decoded_values, decoded); + break; + } + case EVC_ENCODING_QP: + g_warning ("need to implement quoted printable decoding"); + break; + } +} + void e_vcard_attribute_add_values (EVCardAttribute *attr, ...) @@ -806,6 +925,21 @@ e_vcard_attribute_add_values (EVCardAttribute *attr, va_end (ap); } +void +e_vcard_attribute_remove_values (EVCardAttribute *attr) +{ + g_list_foreach (attr->values, (GFunc)g_free, NULL); + g_list_free (attr->values); + attr->values = NULL; +} + +void +e_vcard_attribute_remove_params (EVCardAttribute *attr) +{ + g_list_foreach (attr->params, (GFunc)e_vcard_attribute_param_free, NULL); + g_list_free (attr->params); + attr->params = NULL; +} EVCardAttributeParam* e_vcard_attribute_param_new (const char *name) @@ -820,16 +954,55 @@ void e_vcard_attribute_param_free (EVCardAttributeParam *param) { g_free (param->name); - g_list_foreach (param->values, (GFunc)g_free, NULL); - g_list_free (param->values); + + e_vcard_attribute_param_remove_values (param); + g_free (param); } +EVCardAttributeParam* +e_vcard_attribute_param_copy (EVCardAttributeParam *param) +{ + EVCardAttributeParam *p = e_vcard_attribute_param_new (e_vcard_attribute_param_get_name (param)); + GList *l; + + for (l = param->values; l; l = l->next) { + e_vcard_attribute_param_add_value (p, l->data); + } + + return p; +} + void e_vcard_attribute_add_param (EVCardAttribute *attr, EVCardAttributeParam *param) { attr->params = g_list_append (attr->params, param); + + /* we handle our special encoding stuff here */ + + if (!g_ascii_strcasecmp (param->name, EVC_ENCODING)) { + if (attr->encoding_set) { + g_warning ("ENCODING specified twice"); + return; + } + + if (param->values && param->values->data) { + if (!g_ascii_strcasecmp ((char*)param->values->data, "b")) + attr->encoding = EVC_ENCODING_BASE64; + else if (!g_ascii_strcasecmp ((char*)param->values->data, EVC_QUOTEDPRINTABLE)) + attr->encoding = EVC_ENCODING_QP; + else { + g_warning ("Unknown value `%s' for ENCODING parameter. values will be treated as raw", + (char*)param->values->data); + } + + attr->encoding_set = TRUE; + } + else { + g_warning ("ENCODING parameter added with no value"); + } + } } void @@ -882,6 +1055,14 @@ e_vcard_attribute_add_param_with_values (EVCardAttribute *attr, e_vcard_attribute_add_param (attr, param); } +void +e_vcard_attribute_param_remove_values (EVCardAttributeParam *param) +{ + g_list_foreach (param->values, (GFunc)g_free, NULL); + g_list_free (param->values); + param->values = NULL; +} + GList* e_vcard_get_attributes (EVCard *evcard) { @@ -906,6 +1087,33 @@ e_vcard_attribute_get_values (EVCardAttribute *attr) return attr->values; } +GList* +e_vcard_attribute_get_values_decoded (EVCardAttribute *attr) +{ + if (!attr->decoded_values) { + GList *l; + switch (attr->encoding) { + case EVC_ENCODING_RAW: + for (l = attr->values; l; l = l->next) + attr->decoded_values = g_list_append (attr->decoded_values, g_string_new ((char*)l->data)); + break; + case EVC_ENCODING_BASE64: + for (l = attr->values; l; l = l->next) { + char *decoded = g_strdup ((char*)l->data); + int len = _evc_base64_decode_simple (decoded, strlen (decoded)); + attr->decoded_values = g_list_append (attr->decoded_values, g_string_new_len (decoded, len)); + g_free (decoded); + } + break; + case EVC_ENCODING_QP: + g_warning ("need to implement quoted printable decoding"); + break; + } + } + + return attr->decoded_values; +} + GList* e_vcard_attribute_get_params (EVCardAttribute *attr) { @@ -923,3 +1131,237 @@ e_vcard_attribute_param_get_values (EVCardAttributeParam *param) { return param->values; } + + + +/* encoding/decoding stuff ripped from camel-mime-utils.c */ + +static char *_evc_base64_alphabet = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static unsigned char _evc_base64_rank[256]; + +static void +_evc_base64_init(void) +{ + int i; + + memset(_evc_base64_rank, 0xff, sizeof(_evc_base64_rank)); + for (i=0;i<64;i++) { + _evc_base64_rank[(unsigned int)_evc_base64_alphabet[i]] = i; + } + _evc_base64_rank['='] = 0; +} + +/* call this when finished encoding everything, to + flush off the last little bit */ +static size_t +_evc_base64_encode_close(unsigned char *in, size_t inlen, gboolean break_lines, unsigned char *out, int *state, int *save) +{ + int c1, c2; + unsigned char *outptr = out; + + if (inlen>0) + outptr += _evc_base64_encode_step(in, inlen, break_lines, outptr, state, save); + + c1 = ((unsigned char *)save)[1]; + c2 = ((unsigned char *)save)[2]; + +#if 0 + d(printf("mode = %d\nc1 = %c\nc2 = %c\n", + (int)((char *)save)[0], + (int)((char *)save)[1], + (int)((char *)save)[2])); +#endif + + switch (((char *)save)[0]) { + case 2: + outptr[2] = _evc_base64_alphabet[ ( (c2 &0x0f) << 2 ) ]; + g_assert(outptr[2] != 0); + goto skip; + case 1: + outptr[2] = '='; + skip: + outptr[0] = _evc_base64_alphabet[ c1 >> 2 ]; + outptr[1] = _evc_base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 )]; + outptr[3] = '='; + outptr += 4; + break; + } + if (break_lines) + *outptr++ = '\n'; + + *save = 0; + *state = 0; + + return outptr-out; +} + +/* + performs an 'encode step', only encodes blocks of 3 characters to the + output at a time, saves left-over state in state and save (initialise to + 0 on first invocation). +*/ +static size_t +_evc_base64_encode_step(unsigned char *in, size_t len, gboolean break_lines, unsigned char *out, int *state, int *save) +{ + register unsigned char *inptr, *outptr; + + if (len<=0) + return 0; + + inptr = in; + outptr = out; + +#if 0 + d(printf("we have %d chars, and %d saved chars\n", len, ((char *)save)[0])); +#endif + + if (len + ((char *)save)[0] > 2) { + unsigned char *inend = in+len-2; + register int c1, c2, c3; + register int already; + + already = *state; + + switch (((char *)save)[0]) { + case 1: c1 = ((unsigned char *)save)[1]; goto skip1; + case 2: c1 = ((unsigned char *)save)[1]; + c2 = ((unsigned char *)save)[2]; goto skip2; + } + + /* yes, we jump into the loop, no i'm not going to change it, it's beautiful! */ + while (inptr < inend) { + c1 = *inptr++; + skip1: + c2 = *inptr++; + skip2: + c3 = *inptr++; + *outptr++ = _evc_base64_alphabet[ c1 >> 2 ]; + *outptr++ = _evc_base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 ) ]; + *outptr++ = _evc_base64_alphabet[ ( (c2 &0x0f) << 2 ) | (c3 >> 6) ]; + *outptr++ = _evc_base64_alphabet[ c3 & 0x3f ]; + /* this is a bit ugly ... */ + if (break_lines && (++already)>=19) { + *outptr++='\n'; + already = 0; + } + } + + ((char *)save)[0] = 0; + len = 2-(inptr-inend); + *state = already; + } + +#if 0 + d(printf("state = %d, len = %d\n", + (int)((char *)save)[0], + len)); +#endif + + if (len>0) { + register char *saveout; + + /* points to the slot for the next char to save */ + saveout = & (((char *)save)[1]) + ((char *)save)[0]; + + /* len can only be 0 1 or 2 */ + switch(len) { + case 2: *saveout++ = *inptr++; + case 1: *saveout++ = *inptr++; + } + ((char *)save)[0]+=len; + } + +#if 0 + d(printf("mode = %d\nc1 = %c\nc2 = %c\n", + (int)((char *)save)[0], + (int)((char *)save)[1], + (int)((char *)save)[2])); +#endif + + return outptr-out; +} + + +/** + * base64_decode_step: decode a chunk of base64 encoded data + * @in: input stream + * @len: max length of data to decode + * @out: output stream + * @state: holds the number of bits that are stored in @save + * @save: leftover bits that have not yet been decoded + * + * Decodes a chunk of base64 encoded data + **/ +static size_t +_evc_base64_decode_step(unsigned char *in, size_t len, unsigned char *out, int *state, unsigned int *save) +{ + register unsigned char *inptr, *outptr; + unsigned char *inend, c; + register unsigned int v; + int i; + + inend = in+len; + outptr = out; + + /* convert 4 base64 bytes to 3 normal bytes */ + v=*save; + i=*state; + inptr = in; + while (inptr>16; + *outptr++ = v>>8; + *outptr++ = v; + i=0; + } + } + } + + *save = v; + *state = i; + + /* quick scan back for '=' on the end somewhere */ + /* fortunately we can drop 1 output char for each trailing = (upto 2) */ + i=2; + while (inptr>in && i) { + inptr--; + if (_evc_base64_rank[*inptr] != 0xff) { + if (*inptr == '=' && outptr>out) + outptr--; + i--; + } + } + + /* if i!= 0 then there is a truncation error! */ + return outptr-out; +} + +char * +_evc_base64_encode_simple (const char *data, size_t len) +{ + unsigned char *out; + int state = 0, outlen; + unsigned int save = 0; + + out = g_malloc (len * 4 / 3 + 5); + outlen = _evc_base64_encode_close ((unsigned char *)data, len, FALSE, + out, &state, &save); + out[outlen] = '\0'; + return (char *)out; +} + +size_t +_evc_base64_decode_simple (char *data, size_t len) +{ + int state = 0; + unsigned int save = 0; + + return _evc_base64_decode_step ((unsigned char *)data, len, + (unsigned char *)data, &state, &save); +} diff --git a/addressbook/backend/ebook/e-vcard.h b/addressbook/backend/ebook/e-vcard.h index 69e0a3e10b..cedc2b4c70 100644 --- a/addressbook/backend/ebook/e-vcard.h +++ b/addressbook/backend/ebook/e-vcard.h @@ -26,18 +26,56 @@ #include #include -#define EVC_FN "FN" -#define EVC_ORG "ORG" -#define EVC_URL "URL" -#define EVC_VERSION "VERSION" -#define EVC_REV "REV" -#define EVC_PRODID "PRODID" -#define EVC_TYPE "TYPE" -#define EVC_ADR "ADR" -#define EVC_TEL "TEL" - -#define EVC_ENCODING "ENCODING" +#define EVC_ADR "ADR" +#define EVC_BDAY "BDAY" +#define EVC_CALURI "CALURI" +#define EVC_CATEGORIES "CATEGORIES" +#define EVC_EMAIL "EMAIL" +#define EVC_ENCODING "ENCODING" +#define EVC_FBURL "FBURL" +#define EVC_FN "FN" +#define EVC_ICSCALENDAR "ICSCALENDAR" /* XXX should this be X-EVOLUTION-ICSCALENDAR? */ +#define EVC_LABEL "LABEL" +#define EVC_LOGO "LOGO" +#define EVC_MAILER "MAILER" +#define EVC_NICKNAME "NICKNAME" +#define EVC_N "N" +#define EVC_NOTE "NOTE" +#define EVC_ORG "ORG" +#define EVC_PHOTO "PHOTO" +#define EVC_PRODID "PRODID" #define EVC_QUOTEDPRINTABLE "QUOTED-PRINTABLE" +#define EVC_REV "REV" +#define EVC_ROLE "ROLE" +#define EVC_TEL "TEL" +#define EVC_TITLE "TITLE" +#define EVC_TYPE "TYPE" +#define EVC_UID "UID" +#define EVC_URL "URL" +#define EVC_VALUE "VALUE" +#define EVC_VERSION "VERSION" + +#define EVC_X_AIM "X-AIM" +#define EVC_X_ANNIVERSARY "X-EVOLUTION-ANNIVERSARY" +#define EVC_X_ASSISTANT "X-EVOLUTION-ASSISTANT" +#define EVC_X_BIRTHDAY "X-EVOLUTION-BIRTHDAY" +#define EVC_X_BLOG_URL "X-EVOLUTION-BLOG-URL" +#define EVC_X_FILE_AS "X-EVOLUTION-FILE-AS" +#define EVC_X_ICQ "X-ICQ" +#define EVC_X_JABBER "X-JABBER" +#define EVC_X_LIST_SHOW_ADDRESSES "X-EVOLUTION-LIST-SHOW_ADDRESSES" +#define EVC_X_LIST "X-EVOLUTION-LIST" +#define EVC_X_MANAGER "X-EVOLUTION-MANAGER" +#define EVC_X_MSN "X-MSN" +#define EVC_X_SPOUSE "X-EVOLUTION-SPOUSE" +#define EVC_X_WANTS_HTML "X-MOZILLA-HTML" +#define EVC_X_WANTS_HTML "X-MOZILLA-HTML" +#define EVC_X_YAHOO "X-YAHOO" + +typedef enum { + EVC_FORMAT_VCARD_21, + EVC_FORMAT_VCARD_30 +} EVCardFormat; #define E_TYPE_VCARD (e_vcard_get_type ()) #define E_VCARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_VCARD, EVCard)) @@ -60,28 +98,46 @@ struct _EVCard { struct _EVCardClass { GObjectClass parent_class; + + /* Padding for future expansion */ + void (*_ebook_reserved0) (void); + void (*_ebook_reserved1) (void); + void (*_ebook_reserved2) (void); + void (*_ebook_reserved3) (void); + void (*_ebook_reserved4) (void); }; GType e_vcard_get_type (void); + +void e_vcard_construct (EVCard *evc, const char *str); EVCard* e_vcard_new (void); EVCard* e_vcard_new_from_string (const char *str); -char* e_vcard_to_string (EVCard *evcard); + +char* e_vcard_to_string (EVCard *evc, EVCardFormat format); + /* mostly for debugging */ void e_vcard_dump_structure (EVCard *evc); /* attributes */ -EVCardAttribute *e_vcard_attribute_new (const char *attr_group, const char *attr_name); -void e_vcard_attribute_free (EVCardAttribute *attr); -void e_vcard_add_attribute (EVCard *evcard, EVCardAttribute *attr); -void e_vcard_add_attribute_with_value (EVCard *evcard, EVCardAttribute *attr, const char *value); -void e_vcard_add_attribute_with_values (EVCard *evcard, EVCardAttribute *attr, ...); -void e_vcard_attribute_add_value (EVCardAttribute *attr, const char *value); -void e_vcard_attribute_add_values (EVCardAttribute *attr, ...); +EVCardAttribute *e_vcard_attribute_new (const char *attr_group, const char *attr_name); +void e_vcard_attribute_free (EVCardAttribute *attr); +EVCardAttribute *e_vcard_attribute_copy (EVCardAttribute *attr); +void e_vcard_remove_attributes (EVCard *evcard, const char *attr_group, const char *attr_name); +void e_vcard_remove_attribute (EVCard *evcard, EVCardAttribute *attr); +void e_vcard_add_attribute (EVCard *evcard, EVCardAttribute *attr); +void e_vcard_add_attribute_with_value (EVCard *evcard, EVCardAttribute *attr, const char *value); +void e_vcard_add_attribute_with_values (EVCard *evcard, EVCardAttribute *attr, ...); +void e_vcard_attribute_add_value (EVCardAttribute *attr, const char *value); +void e_vcard_attribute_add_value_decoded (EVCardAttribute *attr, const char *value, int len); +void e_vcard_attribute_add_values (EVCardAttribute *attr, ...); +void e_vcard_attribute_remove_values (EVCardAttribute *attr); +void e_vcard_attribute_remove_params (EVCardAttribute *attr); /* attribute parameters */ EVCardAttributeParam* e_vcard_attribute_param_new (const char *param_name); void e_vcard_attribute_param_free (EVCardAttributeParam *param); +EVCardAttributeParam* e_vcard_attribute_param_copy (EVCardAttributeParam *param); void e_vcard_attribute_add_param (EVCardAttribute *attr, EVCardAttributeParam *param); void e_vcard_attribute_add_param_with_value (EVCardAttribute *attr, EVCardAttributeParam *param, const char *value); @@ -92,17 +148,18 @@ void e_vcard_attribute_param_add_value (EVCardAttributePa const char *value); void e_vcard_attribute_param_add_values (EVCardAttributeParam *param, ...); +void e_vcard_attribute_param_remove_values (EVCardAttributeParam *param); /* EVCard* accessors. nothing returned from these functions should be freed by the caller. */ GList* e_vcard_get_attributes (EVCard *evcard); const char* e_vcard_attribute_get_group (EVCardAttribute *attr); const char* e_vcard_attribute_get_name (EVCardAttribute *attr); -GList* e_vcard_attribute_get_values (EVCardAttribute *attr); +GList* e_vcard_attribute_get_values (EVCardAttribute *attr); /* GList elements are of type char* */ +GList* e_vcard_attribute_get_values_decoded (EVCardAttribute *attr); /* GList elements are of type GString* */ GList* e_vcard_attribute_get_params (EVCardAttribute *attr); const char* e_vcard_attribute_param_get_name (EVCardAttributeParam *param); GList* e_vcard_attribute_param_get_values (EVCardAttributeParam *param); - #endif /* _EVCARD_H */ diff --git a/addressbook/backend/ebook/test-client-list.c b/addressbook/backend/ebook/test-client-list.c deleted file mode 100644 index 6fa3d6b094..0000000000 --- a/addressbook/backend/ebook/test-client-list.c +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -#include - -#include -#include -#include -#include - -#include "e-book.h" - -static void -init_bonobo (int *argc, char **argv) -{ - if (bonobo_init (argc, argv) == FALSE) - g_error (_("Could not initialize Bonobo")); -} - -static void -get_cursor_cb (EBook *book, EBookStatus status, ECardCursor *cursor, gpointer closure) -{ - long length = e_card_cursor_get_length(cursor); - long i; - - printf ("Length: %d\n", (int) length); - for ( i = 0; i < length; i++ ) { - ECard *card = e_card_cursor_get_nth(cursor, i); - char *vcard = e_card_get_vcard_assume_utf8(card); - printf("[%s]\n", vcard); - g_free(vcard); - g_object_unref(card); - } -} - -static void -book_open_cb (EBook *book, EBookStatus status, gpointer closure) -{ - printf ("Book opened.\n"); - e_book_get_cursor(book, "", get_cursor_cb, NULL); -} - -static gboolean -ebook_create (gpointer data) -{ - EBook *book; - - book = e_book_new (); - - e_book_load_uri (book, "file:/tmp/test.db", book_open_cb, NULL); - - return FALSE; -} - -int -main (int argc, char **argv) -{ - gnome_program_init("test-client-list", "0.0", LIBGNOME_MODULE, argc, argv, NULL); - - init_bonobo (&argc, argv); - - g_idle_add (ebook_create, NULL); - - bonobo_main (); - - return 0; -} diff --git a/addressbook/backend/ebook/test-client.c b/addressbook/backend/ebook/test-client.c deleted file mode 100644 index 63461fb671..0000000000 --- a/addressbook/backend/ebook/test-client.c +++ /dev/null @@ -1,191 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -#include -#include -#include -#include -#include -#include -#include - -#include "e-book.h" -#include "e-book-util.h" - -#define TEST_VCARD \ -"BEGIN:VCARD\r\n" \ -"FN:Nat\r\n" \ -"N:Friedman;Nat;D;Mr.\r\n" \ -"BDAY:1977-08-06\r\n" \ -"TEL;WORK:617 679 1984\r\n" \ -"TEL;CELL:123 456 7890\r\n" \ -"EMAIL;INTERNET:nat@nat.org\r\n" \ -"EMAIL;INTERNET:nat@ximian.com\r\n" \ -"ADR;WORK;POSTAL:P.O. Box 101;;;Any Town;CA;91921-1234;\r\n" \ -"END:VCARD\r\n" \ -"\r\n" - -static CORBA_Environment ev; -static char *cardstr; - -static void -init_bonobo (int *argc, char **argv) -{ - if (bonobo_init (argc, argv) == FALSE) - g_error (_("Could not initialize Bonobo")); -} - -static void -get_cursor_cb (EBook *book, EBookStatus status, ECardCursor *cursor, gpointer closure) -{ - long length = e_card_cursor_get_length(cursor); - long i; - - /* we just added a card, so the length should be >1 */ - printf ("\n%s: %s(): Number of cards is %ld\n", - __FILE__, G_GNUC_FUNCTION, length); - if (length < 1) - printf ("*** Why isn't this above zero?? ***\n\n"); - - for ( i = 0; i < length; i++ ) { - ECard *card = e_card_cursor_get_nth(cursor, i); - char *vcard = e_card_get_vcard_assume_utf8(card); - printf("Get all cards callback: [%s]\n", vcard); - g_free(vcard); - g_object_unref(card); - } - - g_object_unref (book); - exit(0); -} - -static void -get_card_cb (EBook *book, EBookStatus status, ECard *card, gpointer closure) -{ - char *vcard; - - vcard = e_card_get_vcard_assume_utf8(card); - printf ("Card added: [%s]\n", vcard); - g_free(vcard); - - printf ("Getting cards..\n"); - e_book_get_cursor(book, "(contains \"x-evolution-any-field\" \"\")", get_cursor_cb, NULL); - printf ("Done getting all cards.\n"); -} - -static void -add_card_cb (EBook *book, EBookStatus status, const gchar *id, gpointer closure) -{ - GTimer *timer; - - printf ("Status: %d\n", status); - - printf ("Id: %s\n", id); - - timer = g_timer_new (); - g_timer_start (timer); - e_book_get_card (book, id, get_card_cb, closure); - g_timer_stop (timer); - printf ("%g\n", g_timer_elapsed (timer, NULL)); -} - -static void -get_fields_cb (EBook *book, EBookStatus status, EList *fields, gpointer closure) -{ - if (fields) { - EIterator *iter = e_list_get_iterator (fields); - - printf ("Supported fields:\n"); - - for (; e_iterator_is_valid (iter); e_iterator_next (iter)) { - printf (" %s\n", (char*)e_iterator_get (iter)); - } - - g_object_unref(fields); - } - else { - printf ("No supported fields?\n"); - } - - e_book_add_vcard(book, cardstr, add_card_cb, NULL); -} - - -static void -auth_user_cb (EBook *book, EBookStatus status, gpointer closure) -{ - printf ("user authenticated\n"); - e_book_get_supported_fields (book, get_fields_cb, closure); -} - -static void -book_open_cb (EBook *book, EBookStatus status, gpointer closure) -{ - e_book_authenticate_user (book, "username", "password", "auth_method", auth_user_cb, NULL); -} - -static gboolean -ebook_create (gpointer data) -{ - EBook *book; - - book = e_book_new (); - - if (!book) { - printf ("%s: %s(): Couldn't create EBook, bailing.\n", - __FILE__, - G_GNUC_FUNCTION); - return FALSE; - } - - - e_book_load_default_book (book, book_open_cb, NULL); - - return FALSE; -} - -static char * -read_file (char *name) -{ - int len; - char buff[65536]; - char line[1024]; - FILE *f; - - f = fopen (name, "r"); - if (f == NULL) - g_error ("Unable to open %s!\n", name); - - len = 0; - while (fgets (line, sizeof (line), f) != NULL) { - strcpy (buff + len, line); - len += strlen (line); - } - - fclose (f); - - return g_strdup (buff); -} - - -int -main (int argc, char **argv) -{ - - CORBA_exception_init (&ev); - - gnome_program_init("test-client", "0.0", LIBGNOME_MODULE, argc, argv, NULL); - - init_bonobo (&argc, argv); - - cardstr = NULL; - if (argc == 2) - cardstr = read_file (argv [1]); - - if (cardstr == NULL) - cardstr = TEST_VCARD; - - g_idle_add (ebook_create, NULL); - - bonobo_main (); - - return 0; -} diff --git a/addressbook/backend/ebook/tests/Makefile.am b/addressbook/backend/ebook/tests/Makefile.am index f17f979485..444d692e22 100644 --- a/addressbook/backend/ebook/tests/Makefile.am +++ b/addressbook/backend/ebook/tests/Makefile.am @@ -1 +1 @@ -SUBDIRS=vcard \ No newline at end of file +SUBDIRS=vcard ebook diff --git a/addressbook/backend/ebook/tests/ebook/.cvsignore b/addressbook/backend/ebook/tests/ebook/.cvsignore new file mode 100644 index 0000000000..8dbec11b01 --- /dev/null +++ b/addressbook/backend/ebook/tests/ebook/.cvsignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +test-date +test-ebook +test-changes +test-photo +test-string diff --git a/addressbook/backend/ebook/tests/ebook/Makefile.am b/addressbook/backend/ebook/tests/ebook/Makefile.am new file mode 100644 index 0000000000..7147690482 --- /dev/null +++ b/addressbook/backend/ebook/tests/ebook/Makefile.am @@ -0,0 +1,12 @@ + +TEST_LIBS=$(top_builddir)/addressbook/backend/ebook/libebook.la + +INCLUDES=-I$(srcdir)/../../.. @EVOLUTION_ADDRESSBOOK_CFLAGS@ + +noinst_PROGRAMS= test-changes test-date test-ebook test-photo test-string + +test_date_LDFLAGS=$(TEST_LIBS) +test_ebook_LDFLAGS=$(TEST_LIBS) +test_changes_LDFLAGS=$(TEST_LIBS) +test_photo_LDFLAGS=$(TEST_LIBS) +test_string_LDFLAGS=$(TEST_LIBS) diff --git a/addressbook/backend/ebook/tests/ebook/test-changes.c b/addressbook/backend/ebook/tests/ebook/test-changes.c new file mode 100644 index 0000000000..0c91f30cf4 --- /dev/null +++ b/addressbook/backend/ebook/tests/ebook/test-changes.c @@ -0,0 +1,89 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +#include "ebook/e-book.h" +#include +#include +#include + +#define NEW_VCARD "BEGIN:VCARD\n\ +X-EVOLUTION-FILE-AS:Toshok, Chris\n\ +FN:Chris Toshok\n\ +EMAIL;INTERNET:toshok@ximian.com\n\ +ORG:Ximian, Inc.;\n\ +END:VCARD" + +static char file_template[]="file:///tmp/change-test-XXXXXX"; + +int +main (int argc, char **argv) +{ + EBook *book; + gboolean status; + EContact *contact; + GList *changes; + GError *error = NULL; + EBookChange *change; + + gnome_program_init("test-changes", "0.0", LIBGNOME_MODULE, argc, argv, NULL); + + if (bonobo_init (&argc, argv) == FALSE) + g_error ("Could not initialize Bonobo"); + + mktemp (file_template); + + /* create a temp addressbook in /tmp */ + book = e_book_new (); + + printf ("loading addressbook\n"); + if (!e_book_load_uri (book, file_template, FALSE, &error)) { + printf ("failed to open addressbook: `%s': %s\n", file_template, error->message); + exit(0); + } + + /* get an initial change set */ + if (!e_book_get_changes (book, "changeidtest", &changes, &error)) { + printf ("failed to get changes: %s\n", error->message); + exit(0); + } + + /* make a change to the book */ + contact = e_contact_new_from_vcard (NEW_VCARD); + if (!e_book_add_contact (book, contact, &error)) { + printf ("failed to add new contact: %s\n", error->message); + exit(0); + } + + /* get another change set */ + if (!e_book_get_changes (book, "changeidtest", &changes, &error)) { + printf ("failed to get second set of changes: %s\n", error->message); + exit(0); + } + + /* make sure that 1 change has occurred */ + if (g_list_length (changes) != 1) { + printf ("got back %d changes, was expecting 1\n", g_list_length (changes)); + exit(0); + } + + change = changes->data; + if (change->change_type != E_BOOK_CHANGE_CARD_ADDED) { + printf ("was expecting a CARD_ADDED change, but didn't get it.\n"); + exit(0); + } + + printf ("got changed vcard back: %s\n", change->vcard); + + e_book_free_change_list (changes); + + + if (!e_book_remove (book, &error)) { + printf ("failed to remove book; %s\n", error->message); + exit(0); + } + + g_object_unref (book); + + bonobo_main_quit(); + + return 0; +} diff --git a/addressbook/backend/ebook/tests/ebook/test-date.c b/addressbook/backend/ebook/tests/ebook/test-date.c new file mode 100644 index 0000000000..afe37cf224 --- /dev/null +++ b/addressbook/backend/ebook/tests/ebook/test-date.c @@ -0,0 +1,36 @@ + +#include "ebook/e-book.h" +#include +#include +#include + +int +main (int argc, char **argv) +{ + EContact *contact; + EContactDate date, *dp; + + gnome_program_init("test-string", "0.0", LIBGNOME_MODULE, argc, argv, NULL); + + if (bonobo_init (&argc, argv) == FALSE) + g_error ("Could not initialize Bonobo"); + + contact = e_contact_new (); + + date.year = 1999; + date.month = 3; + date.day = 3; + + e_contact_set (contact, E_CONTACT_BIRTH_DATE, &date); + + printf ("vcard = \n%s\n", e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30)); + + dp = e_contact_get (contact, E_CONTACT_BIRTH_DATE); + + if (dp->year != date.year + || dp->month != date.month + || dp->day != date.day) + printf ("failed\n"); + else + printf ("passed\n"); +} diff --git a/addressbook/backend/ebook/tests/ebook/test-ebook.c b/addressbook/backend/ebook/tests/ebook/test-ebook.c new file mode 100644 index 0000000000..d78d9f3b6a --- /dev/null +++ b/addressbook/backend/ebook/tests/ebook/test-ebook.c @@ -0,0 +1,110 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +#include "ebook/e-book.h" +#include +#include +#include + +static void +print_email (EContact *contact) +{ + char *file_as = e_contact_get (contact, E_CONTACT_FILE_AS); + GList *emails, *e; + + printf ("Contact: %s\n", file_as); + printf ("Email addresses:\n"); + emails = e_contact_get (contact, E_CONTACT_EMAIL); + for (e = emails; e; e = e->next) { + EVCardAttribute *attr = e->data; + GList *values = e_vcard_attribute_get_values (attr); + printf ("\t%s\n", values && values->data ? (char*)values->data : ""); + e_vcard_attribute_free (attr); + } + g_list_free (emails); + + g_free (file_as); + + printf ("\n"); +} + +static void +print_all_emails (EBook *book) +{ + EBookQuery *query; + gboolean status; + GList *cards, *c; + + query = e_book_query_field_exists (E_CONTACT_FULL_NAME); + + status = e_book_get_contacts (book, query, &cards, NULL); + + e_book_query_unref (query); + + if (status == FALSE) { + printf ("error %d getting card list\n", status); + exit(0); + } + + for (c = cards; c; c = c->next) { + EContact *contact = E_CONTACT (c->data); + + print_email (contact); + + g_object_unref (contact); + } + g_list_free (cards); +} + +static void +print_one_email (EBook *book) +{ + EContact *contact; + GError *error = NULL; + + if (!e_book_get_contact (book, "pas-id-0002023", &contact, &error)) { + printf ("error %d getting card: %s\n", error->code, error->message); + g_clear_error (&error); + return; + } + + print_email (contact); + + g_object_unref (contact); +} + +int +main (int argc, char **argv) +{ + EBook *book; + gboolean status; + + gnome_program_init("test-ebook", "0.0", LIBGNOME_MODULE, argc, argv, NULL); + + if (bonobo_init (&argc, argv) == FALSE) + g_error ("Could not initialize Bonobo"); + + /* + ** the actual ebook foo + */ + + book = e_book_new (); + + printf ("loading addressbook\n"); + status = e_book_load_local_addressbook (book, NULL); + if (status == FALSE) { + printf ("failed to open local addressbook\n"); + exit(0); + } + + printf ("printing one contact\n"); + print_one_email (book); + + printf ("printing all contacts\n"); + print_all_emails (book); + + g_object_unref (book); + + bonobo_main_quit(); + + return 0; +} diff --git a/addressbook/backend/ebook/tests/ebook/test-photo.c b/addressbook/backend/ebook/tests/ebook/test-photo.c new file mode 100644 index 0000000000..cbd6817b37 --- /dev/null +++ b/addressbook/backend/ebook/tests/ebook/test-photo.c @@ -0,0 +1,59 @@ + +#include "ebook/e-book.h" +#include +#include +#include + +const char *photo_data = "/9j/4AAQSkZJRgABAQEARwBHAAD//gAXQ3JlYXRlZCB3aXRo\ +IFRoZSBHSU1Q/9sAQwAIBgYHBgUIBwcHCQkICgwUDQwLCwwZEhMPFB0aHx4dGhwcICQuJyAiLC\ +McHCg3KSwwMTQ0NB8nOT04MjwuMzQy/9sAQwEJCQkMCwwYDQ0YMiEcITIyMjIyMjIyMjIyMjIy\ +MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy/8AAEQgAMgAyAwEiAAIRAQMRAf\ +/EABsAAQACAwEBAAAAAAAAAAAAAAAHCAQFBgID/8QAMBAAAgEDAQYEBQQDAAAAAAAAAQIDAAQR\ +BQYSEyExQQdhcYEiI0JRkRQVMqFiguH/xAAaAQADAQEBAQAAAAAAAAAAAAAABAUCBgED/8QAIx\ +EAAgICAQQCAwAAAAAAAAAAAAECAwQRQRITITEUYQUiUf/aAAwDAQACEQMRAD8An+sHUtWtNKjV\ +rmQ7754cajLvjrgfbzPIdzWdVfds9pJb3XdQkMrcFZGj+HqY0bdVV9Tz/wBia+N9vbjvkaxMb5\ +E9N6SJB1HxLEEjJaWsUjD6QzSMPXdGB7E1zV74t63HINy1s4F7CWCTn77wrA0TY86jY3N1qsUk\ +6wxBxBDvYjLHkoUH4j3JP/a0V3s1CvF/QM9tKpw0THeU+TLkj8VLnmzT8y0n9FujBx5bioba/r\ +ZLWx3iPZ7RzLp95GtnqRGVTezHNjruH7/4n+67iqpq7Qi3uYWMMsNynfnE6sM8/Lr6VamFi0KM\ +epUE1Sx7XZHbI+fjxos1H0z3SlKYEjzISI2I64OKqsyu8sck2QYrmPjBvpIYg598Vauoh8VtlY\ +7JW2isoBwpPl6hGByZTyD+o6E+h7UtlVOcPHA/+PyI1Wal6Zp7vaC/06wnTTLtEeUDiKwzu4H8\ +vI9AM9Tiuctkng1Nnk1G5cOoYifB4nI/jB7VjWuoT21qPmwXUCHKlphHKvqG5N6g0/cLi/Rg88\ +FhbkbxlaUSu3kqpnn6kDzqGqbNdPB0XyK4/svZr9RVntL50GePdcKEDqzhVBx7sKtPpayppNos\ +xzKIlDHzxUFeG2zo2n2kivWhK6PpHwwoTnfk65J7kZyT9z5VYADAwKuYtfRA5zPv7tnjgUpSmR\ +EV8bq1hvbWW1uY1khlUo6MMhgeor7UoAje18FtmLe9eeQT3EXPcglkJRPbv71EWu7Dajp2o3MG\ +mlRCkjKQ30jPUe1WlrlNW0RptTleNB84DnjkD0P9VlxT4Nqck9pmn8JuFp2zo0cgCWFi2e7555\ +/NSHXLadso2m3sU0NxlV65HM+VdTW3rgwvsUpSvAFKUoAUxSlAClKUAKUpQB//2Q=="; + + +int +main (int argc, char **argv) +{ + EContact *contact; + EContactPhoto *photo, *new_photo; + + gnome_program_init("test-photo", "0.0", LIBGNOME_MODULE, argc, argv, NULL); + + if (bonobo_init (&argc, argv) == FALSE) + g_error ("Could not initialize Bonobo"); + + contact = e_contact_new (); + + photo = g_new (EContactPhoto, 1); + photo->data = g_strdup (photo_data); + photo->length = _evc_base64_decode_simple (photo->data, strlen (photo_data)); + + /* set the photo */ + e_contact_set (contact, E_CONTACT_PHOTO, photo); + + /* then get the photo */ + new_photo = e_contact_get (contact, E_CONTACT_PHOTO); + + /* and compare */ + if (new_photo->length != photo->length) + g_error ("photo lengths differ"); + + if (memcmp (new_photo->data, photo->data, photo->length)) + g_error ("photo data differs"); + + printf ("photo test passed\n"); +} diff --git a/addressbook/backend/ebook/tests/ebook/test-string.c b/addressbook/backend/ebook/tests/ebook/test-string.c new file mode 100644 index 0000000000..b7cdbb3720 --- /dev/null +++ b/addressbook/backend/ebook/tests/ebook/test-string.c @@ -0,0 +1,27 @@ + +#include "ebook/e-book.h" +#include +#include +#include + +#define TEST_ID "test-uid" + +int +main (int argc, char **argv) +{ + EContact *contact; + + gnome_program_init("test-string", "0.0", LIBGNOME_MODULE, argc, argv, NULL); + + if (bonobo_init (&argc, argv) == FALSE) + g_error ("Could not initialize Bonobo"); + + contact = e_contact_new (); + + e_contact_set (contact, E_CONTACT_UID, TEST_ID); + + if (!strcmp (e_contact_get_const (contact, E_CONTACT_UID), TEST_ID)) + printf ("passed\n"); + else + printf ("failed\n"); +} diff --git a/addressbook/backend/ebook/tests/vcard/Makefile.am b/addressbook/backend/ebook/tests/vcard/Makefile.am index ae16780095..7e57329e1d 100644 --- a/addressbook/backend/ebook/tests/vcard/Makefile.am +++ b/addressbook/backend/ebook/tests/vcard/Makefile.am @@ -1,6 +1,8 @@ -CFLAGS=-I$(srcdir)/../.. `pkg-config --cflags gobject-2.0` +TEST_LIBS=$(top_builddir)/addressbook/backend/ebook/libebook.la + +INCLUDES=-I$(srcdir)/../../.. @EVOLUTION_ADDRESSBOOK_CFLAGS@ noinst_PROGRAMS=dump-vcard -dump_vcard_LDFLAGS=$(top_builddir)/addressbook/backend/ebook/libevcard.la `pkg-config --libs gobject-2.0` +dump_vcard_LDFLAGS=$(TEST_LIBS) diff --git a/addressbook/backend/ebook/tests/vcard/dump-vcard.c b/addressbook/backend/ebook/tests/vcard/dump-vcard.c index 52dbf8a957..907a00efa7 100644 --- a/addressbook/backend/ebook/tests/vcard/dump-vcard.c +++ b/addressbook/backend/ebook/tests/vcard/dump-vcard.c @@ -1,7 +1,7 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ #include -#include "e-vcard.h" +#include "ebook/e-vcard.h" FILE *fp; -- cgit