/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ #include <config.h> #include <sys/stat.h> #include <utime.h> #include <unistd.h> #include <pwd.h> #include <signal.h> #include <errno.h> #include <pi-source.h> #include <pi-socket.h> #include <pi-file.h> #include <pi-dlp.h> #include <libgnorba/gnorba.h> #include <libgnorba/gnome-factory.h> #include <pi-version.h> #include <gpilotd/gnome-pilot-conduit.h> #include <gpilotd/gnome-pilot-conduit-standard-abs.h> #include <address-conduit.h> #include "ebook/e-book-types.h" #include <bonobo.h> GnomePilotConduit * conduit_get_gpilot_conduit (guint32); void conduit_destroy_gpilot_conduit (GnomePilotConduit*); void local_record_from_ecard (AddressbookLocalRecord *local, ECard *ecard); #define CONDUIT_VERSION "0.1" #ifdef G_LOG_DOMAIN #undef G_LOG_DOMAIN #endif #define G_LOG_DOMAIN "addressconduit" /* #define SUPPORT_ARCHIVING 1 */ #define NEED_OAF_INIT_HACK 1 #define DEBUG_ADDRESSBOOKCONDUIT 1 #ifdef DEBUG_ADDRESSBOOKCONDUIT #define show_exception(e) g_warning ("Exception: %s\n", CORBA_exception_id (e)) #define LOG(e...) g_log(G_LOG_DOMAIN,G_LOG_LEVEL_MESSAGE, e) #else #define show_exception(e) #define LOG(e...) #endif #define WARN(e...) g_log(G_LOG_DOMAIN,G_LOG_LEVEL_WARNING, e) #define INFO(e...) g_log(G_LOG_DOMAIN,G_LOG_LEVEL_MESSAGE, e) #define catch_ret_val(_env,ret) \ if (_env._major != CORBA_NO_EXCEPTION) { \ g_log(G_LOG_DOMAIN,G_LOG_LEVEL_MESSAGE,"%s:%d: Caught exception",__FILE__,__LINE__); \ g_warning ("Exception: %s\n", CORBA_exception_id (&(_env))); \ CORBA_exception_free(&(_env)); \ return ret; \ } static void status_cb (EBook *ebook, EBookStatus status, gpointer closure) { (*(EBookStatus*)closure) = status; gtk_main_quit(); } /* Destroys any data allocated by gcalconduit_load_configuration and deallocates the given configuration. */ static void conduit_destroy_configuration(AddressbookConduitCfg **c) { g_return_if_fail(c!=NULL); g_return_if_fail(*c!=NULL); //g_free(*c); FIX ME *c = NULL; } /* Given a AddressbookConduitContext**, allocates the structure */ static void conduit_new_context(AddressbookConduitContext **ctxt, AddressbookConduitCfg *c) { *ctxt = g_new0(AddressbookConduitContext,1); g_assert(ctxt!=NULL); (*ctxt)->cfg = c; CORBA_exception_init (&((*ctxt)->ev)); } /* Destroys any data allocated by conduit_new_context and deallocates its data. */ static void conduit_destroy_context(AddressbookConduitContext **ctxt) { g_return_if_fail(ctxt!=NULL); g_return_if_fail(*ctxt!=NULL); if ((*ctxt)->cfg!=NULL) conduit_destroy_configuration(&((*ctxt)->cfg)); g_free(*ctxt); *ctxt = NULL; } static void cursor_cb (EBook *book, EBookStatus status, ECardCursor *cursor, gpointer closure) { AddressbookConduitContext *ctxt = (AddressbookConduitContext*)closure; if (status == E_BOOK_STATUS_SUCCESS) { long length; int i; // ctxt->cursor = cursor; ctxt->address_load_success = TRUE; length = e_card_cursor_get_length (cursor); ctxt->cards = NULL; for (i = 0; i < length; i ++) ctxt->cards = g_list_append (ctxt->cards, e_card_cursor_get_nth (cursor, i)); gtk_main_quit(); /* end the sub event loop */ } else { WARN (_("BLARG\n")); gtk_main_quit(); /* end the sub event loop */ } } static void book_open_cb (EBook *book, EBookStatus status, gpointer closure) { AddressbookConduitContext *ctxt = (AddressbookConduitContext*)closure; if (status == E_BOOK_STATUS_SUCCESS) { e_book_get_cursor (book, "(contains \"full_name\" \"\")", cursor_cb, ctxt); } else { WARN (_("BLARG\n")); gtk_main_quit(); /* end the sub event loop */ } } static int start_address_server (GnomePilotConduitStandardAbs *conduit, AddressbookConduitContext *ctxt) { gchar *uri, *path; g_return_val_if_fail(conduit!=NULL,-2); g_return_val_if_fail(ctxt!=NULL,-2); ctxt->ebook = e_book_new (); path = g_concat_dir_and_file (g_get_home_dir (), "evolution/local/Contacts/addressbook.db"); uri = g_strdup_printf ("file://%s", path); g_free (path); e_book_load_uri (ctxt->ebook, uri, book_open_cb, ctxt); /* run a sub event loop to turn ebook's async loading into a synchronous call */ gtk_main (); g_free (uri); if (ctxt->address_load_success) return 0; return -1; } /* * converts a ECard to a AddressbookLocalRecord */ void local_record_from_ecard(AddressbookLocalRecord *local, ECard *ecard) { guint32 current_status; g_return_if_fail(local!=NULL); g_return_if_fail(ecard!=NULL); local->ecard = ecard; local->local.ID = local->ecard->pilot_id; gtk_object_get (GTK_OBJECT(ecard), "pilot_status", ¤t_status, NULL); switch(current_status) { case E_CARD_PILOT_STATUS_NONE: local->local.attr = GnomePilotRecordNothing; break; case E_CARD_PILOT_STATUS_MOD: local->local.attr = GnomePilotRecordModified; break; case E_CARD_PILOT_STATUS_DEL: local->local.attr = GnomePilotRecordDeleted; break; } /* Records without a pilot_id are new */ if(local->local.ID == 0) local->local.attr = GnomePilotRecordNew; local->local.secret = 0; #if 0 if(obj->class!=NULL) if(strcmp(obj->class,"PRIVATE")==0) local->local.secret = 1; #endif local->local.archived = 0; } static ECard * get_ecard_by_pilot_id (GList *card_list, recordid_t id) { GList *l; for (l = card_list; l; l = l->next) { guint32 pilot_id; ECard *card = l->data; if (!card) continue; gtk_object_get (GTK_OBJECT(card), "pilot_id", &pilot_id, NULL); if (pilot_id == id) return card; } return NULL; } /* * Given a PilotRecord, find the matching record in * the addressbook. If no match, return NULL */ static AddressbookLocalRecord * find_record_in_ebook(GnomePilotConduitStandardAbs *conduit, PilotRecord *remote, AddressbookConduitContext *ctxt) { AddressbookLocalRecord *loc; ECard *ecard; g_return_val_if_fail(conduit!=NULL,NULL); g_return_val_if_fail(remote!=NULL,NULL); LOG ("requesting %ld", remote->ID); ecard = get_ecard_by_pilot_id (ctxt->cards, remote->ID); if (NULL != ecard) { LOG ("Found"); loc = g_new0(AddressbookLocalRecord,1); /* memory allocated in new_from_string is freed in free_match */ local_record_from_ecard (loc, ecard); return loc; } INFO ("Object did not exist"); return NULL; } static ECard * ecard_from_remote_record(AddressbookConduitContext *ctxt, PilotRecord *remote) { struct Address address; ECard *ecard; ECardSimple *simple; int i; char *string; char *stringparts[4]; char *commaparts[3]; char *spaceparts[3]; char *commastring, *spacestring; g_return_val_if_fail(remote!=NULL,NULL); memset (&address, 0, sizeof (struct Address)); unpack_Address (&address, remote->record, remote->length); ecard = e_card_new(""); simple = e_card_simple_new(ecard); #define get(pilotprop) \ (address.entry [(pilotprop)]) #define check(pilotprop) \ (address.entry [(pilotprop)] && *address.entry [(pilotprop)]) i = 0; if (check(entryFirstname)) stringparts[i++] = get(entryFirstname); if (check(entryLastname)) stringparts[i++] = get(entryLastname); stringparts[i] = NULL; string = g_strjoinv(" ", stringparts); e_card_simple_set(simple, E_CARD_SIMPLE_FIELD_FULL_NAME, string); g_free(string); i = 0; if (check (entryAddress)) spaceparts[i++] = get (entryAddress); if (check (entryZip)) spaceparts[i++] = get (entryZip); spaceparts[i] = 0; spacestring = g_strjoinv(" ", spaceparts); i = 0; if (check (entryCity)) commaparts[i++] = get (entryCity); if (spacestring && *spacestring) commaparts[i++] = spacestring; commaparts[i] = 0; commastring = g_strjoinv(", ", commaparts); i = 0; if (check (entryAddress)) stringparts[i++] = get (entryAddress); if (commastring && *commastring) stringparts[i++] = commastring; if (check (entryCountry)) stringparts[i++] = get (entryCountry); stringparts[i] = NULL; string = g_strjoinv("\n", stringparts); e_card_simple_set(simple, E_CARD_SIMPLE_FIELD_ADDRESS_HOME, string); g_free(spacestring); g_free(commastring); g_free(string); if (check (entryTitle)) e_card_simple_set(simple, E_CARD_SIMPLE_FIELD_TITLE, get (entryTitle)); if (check (entryCompany)) e_card_simple_set(simple, E_CARD_SIMPLE_FIELD_ORG, get (entryCompany)); for (i = entryPhone1; i <= entryPhone5; i ++) { if (address.entry [i] && *(address.entry [i])) { char *phonelabel = ctxt->ai.phoneLabels[address.phoneLabel[i - entryPhone1]]; if (!strcmp (phonelabel, "E-mail")) e_card_simple_set(simple, E_CARD_SIMPLE_FIELD_EMAIL, address.entry[i]); else if (!strcmp (phonelabel, "Home")) e_card_simple_set(simple, E_CARD_SIMPLE_FIELD_PHONE_HOME, address.entry[i]); else if (!strcmp (phonelabel, "Work")) e_card_simple_set(simple, E_CARD_SIMPLE_FIELD_PHONE_BUSINESS, address.entry[i]); else if (!strcmp (phonelabel, "Fax")) e_card_simple_set(simple, E_CARD_SIMPLE_FIELD_PHONE_BUSINESS_FAX, address.entry[i]); else if (!strcmp (phonelabel, "Other")) e_card_simple_set(simple, E_CARD_SIMPLE_FIELD_PHONE_OTHER, address.entry[i]); else if (!strcmp (phonelabel, "Main")) e_card_simple_set(simple, E_CARD_SIMPLE_FIELD_PHONE_PRIMARY, address.entry[i]); else if (!strcmp (phonelabel, "Pager")) e_card_simple_set(simple, E_CARD_SIMPLE_FIELD_PHONE_PAGER, address.entry[i]); else if (!strcmp (phonelabel, "Mobile")) e_card_simple_set(simple, E_CARD_SIMPLE_FIELD_PHONE_MOBILE, address.entry[i]); } } #undef get #undef set free_Address(&address); gtk_object_set (GTK_OBJECT(ecard), "pilot_id", remote->ID, NULL); gtk_object_unref(GTK_OBJECT(simple)); return ecard; } static ECard* merge_ecard_with_remote_record (AddressbookConduitContext *ctxt, ECard *ecard, PilotRecord *remote) { return ecard; } typedef struct { EBookStatus status; char *id; } add_card_cons; static void add_card_cb (EBook *ebook, EBookStatus status, const char *id, gpointer closure) { add_card_cons *cons = (add_card_cons*)closure; cons->status = status; cons->id = g_strdup (id); gtk_main_quit(); } static gint update_record (GnomePilotConduitStandardAbs *conduit, PilotRecord *remote, AddressbookConduitContext *ctxt) { struct Address address; ECard *ecard; add_card_cons cons; g_return_val_if_fail(remote!=NULL,-1); memset (&address, 0, sizeof (struct Address)); unpack_Address (&address, remote->record, remote->length); LOG ("requesting %ld [%s %s]", remote->ID, address.entry[entryFirstname], address.entry[entryLastname]); printf ("requesting %ld [%s %s]\n", remote->ID, address.entry[entryFirstname], address.entry[entryLastname]); ecard = get_ecard_by_pilot_id (ctxt->cards, remote->ID); if (ecard == NULL) { LOG ("Object did not exist, creating a new one"); printf ("Object did not exist, creating a new one\n"); ecard = ecard_from_remote_record (ctxt, remote); /* add the ecard to the server */ e_book_add_card (ctxt->ebook, ecard, add_card_cb, &cons); gtk_main(); /* enter sub mainloop */ if (cons.status == E_BOOK_STATUS_SUCCESS) { ctxt->cards = g_list_append (ctxt->cards, e_book_get_card (ctxt->ebook, cons.id)); g_free (cons.id); } else WARN ("update_record: failed to add card to ebook\n"); } else { EBookStatus commit_status; ecard = merge_ecard_with_remote_record (ctxt, ecard, remote); e_book_commit_card (ctxt->ebook, ecard, status_cb, &commit_status); gtk_main (); /* enter sub mainloop */ if (commit_status != E_BOOK_STATUS_SUCCESS) WARN ("update_record: failed to update card in ebook\n"); } free_Address(&address); return 0; } #if 0 static void check_for_slow_setting (GnomePilotConduit *c, AddressbookConduitContext *ctxt) { GList *uids; unsigned long int entry_number; uids = cal_client_get_uids (ctxt->client, CALOBJ_TYPE_ADDRESS); entry_number = g_list_length (uids); LOG (_("Address holds %ld address entries"), entry_number); /* If the local base is empty, do a slow sync */ if (entry_number == 0) { GnomePilotConduitStandard *conduit; conduit = GNOME_PILOT_CONDUIT_STANDARD (c); gnome_pilot_conduit_standard_set_slow (conduit); } } #endif /* 0 */ static gint pre_sync (GnomePilotConduit *c, GnomePilotDBInfo *dbi, AddressbookConduitContext *ctxt) { int l; unsigned char *buf; GnomePilotConduitStandardAbs *conduit; conduit = GNOME_PILOT_CONDUIT_STANDARD_ABS(c); g_message ("Evolution Addressbook Conduit v.%s",CONDUIT_VERSION); ctxt->ebook = NULL; if (start_address_server (GNOME_PILOT_CONDUIT_STANDARD_ABS(c), ctxt) != 0) { WARN(_("Could not start addressbook server")); gnome_pilot_conduit_error(GNOME_PILOT_CONDUIT(c), _("Could not start addressbook server")); return -1; } /* Set the counters for the progress bar crap */ gtk_object_set_data (GTK_OBJECT(c),"dbinfo",dbi); /* load_records(c); */ buf = (unsigned char*)g_malloc(0xffff); if((l=dlp_ReadAppBlock(dbi->pilot_socket,dbi->db_handle,0,(unsigned char *)buf,0xffff)) < 0) { WARN(_("Could not read pilot's Address application block")); WARN("dlp_ReadAppBlock(...) = %d",l); gnome_pilot_conduit_error(GNOME_PILOT_CONDUIT(c), _("Could not read pilot's Address application block")); return -1; } unpack_AddressAppInfo(&(ctxt->ai),buf,l); g_free(buf); #if 0 check_for_slow_setting(c,ctxt); #else /* for now just always use the slow sync method */ gnome_pilot_conduit_standard_set_slow (GNOME_PILOT_CONDUIT_STANDARD (c)); #endif return 0; } /** * Find (if possible) the local record which matches * the given PilotRecord. * if successfull, return non-zero and set *local to * a non-null value (the located local record), * otherwise return 0 and set *local = NULL; */ static gint match_record (GnomePilotConduitStandardAbs *conduit, AddressbookLocalRecord **local, PilotRecord *remote, AddressbookConduitContext *ctxt) { LOG ("in match_record"); g_return_val_if_fail(local!=NULL,-1); g_return_val_if_fail(remote!=NULL,-1); *local = find_record_in_ebook(conduit,remote,ctxt); if (*local==NULL) return -1; return 0; } /** * Free the data allocated by a previous match_record call. * If successfull, return non-zero and ser *local=NULL, otherwise * return 0. */ static gint free_match (GnomePilotConduitStandardAbs *conduit, AddressbookLocalRecord **local, AddressbookConduitContext *ctxt) { LOG ("entering free_match"); g_return_val_if_fail(local!=NULL,-1); g_return_val_if_fail(*local!=NULL,-1); g_free(*local); *local = NULL; return 0; } #if SUPPORT_ARCHIVING /* Move to archive and set status to Nothing */ static gint archive_local (GnomePilotConduitStandardAbs *conduit, AddressbookLocalRecord *local, AddressbookConduitContext *ctxt) { LOG ("entering archive_local"); g_return_val_if_fail(local!=NULL,-1); return -1; } /* ** used when copying information from the pilot to the desktop. if ** the archived flag is set to true in the PilotRecord, this method is ** called. ** ** Store in archive and set status to Nothing */ static gint archive_remote (GnomePilotConduitStandardAbs *conduit, AddressbookLocalRecord *local, PilotRecord *remote, AddressbookConduitContext *ctxt) { LOG ("entering archive_remote"); //g_return_val_if_fail(remote!=NULL,-1); //g_return_val_if_fail(local!=NULL,-1); return -1; } /* ** Called when copying records to the pilot. ** ** XXX more here. */ static gint clear_status_archive_local (GnomePilotConduitStandardAbs *conduit, AddressbookLocalRecord *local, AddressbookConduitContext *ctxt) { LOG ("entering clear_status_archive_local"); g_return_val_if_fail(local!=NULL,-1); return -1; } /* ** presumably used to set the archived flag on a local record. not ** actually used in the gnome-pilot source. */ static gint set_archived (GnomePilotConduitStandardAbs *conduit, AddressbookLocalRecord *local, gint archived, AddressbookConduitContext *ctxt) { LOG ("entering set_archived"); g_return_val_if_fail(local!=NULL,-1); g_assert(local->ecard!=NULL); local->local.archived = archived; update_address_entry_in_repository (conduit, local->ical, ctxt); return 0; } #endif /* ** used when copying information from the pilot to the desktop. if ** the archived flags and deleted flags are not set to true in the ** PilotRecord, this method is called. ** ** Store and set status to Nothing */ static gint store_remote (GnomePilotConduitStandardAbs *conduit, PilotRecord *remote, AddressbookConduitContext *ctxt) { LOG ("entering store_remote"); g_return_val_if_fail(remote!=NULL,-1); remote->attr = GnomePilotRecordNothing; return update_record(conduit,remote,ctxt); } /* ** Used when looping over records on the local side of things. ** function should maintain state such that *local moves along the ** list of records. ** ** return value is 0 if we're done, 1 to continue iterating, and -1 on ** error. */ static gint iterate (GnomePilotConduitStandardAbs *conduit, AddressbookLocalRecord **local, AddressbookConduitContext *ctxt) { static GList *iterator; static int num; g_return_val_if_fail(local!=NULL,-1); if (*local==NULL) { LOG ("beginning iteration"); iterator = ctxt->cards; num = 0; LOG ("iterating over %d records", g_list_length (ctxt->cards)); *local = g_new0(AddressbookLocalRecord, 1); local_record_from_ecard (*local, (ECard*)iterator->data); } else { /* printf ("continuing iteration\n"); */ num++; if(g_list_next(iterator)==NULL) { LOG ("ending"); /** free stuff allocated for iteration */ g_free((*local)); LOG ("iterated over %d records", num); /* ends iteration */ (*local) = NULL; return 0; } else { iterator = g_list_next (iterator); local_record_from_ecard (*local,(ECard*)(iterator->data)); } } return 1; } /* ** similar to iterate, except the list of records we iterate over have ** to have FLAG set and ARCHIVE should match the state of the local ** record. ** ** return value is 0 if we're done, 1 to continue iterating, and -1 on ** error. */ static gint iterate_specific (GnomePilotConduitStandardAbs *conduit, AddressbookLocalRecord **local, gint flag, gint archived, AddressbookConduitContext *ctxt) { #ifdef DEBUG_ADDRESSBOOKCONDUIT { gchar *tmp; switch (flag) { case GnomePilotRecordNothing: tmp = g_strdup("RecordNothing"); break; case GnomePilotRecordModified: tmp = g_strdup("RecordModified"); break; case GnomePilotRecordDeleted: tmp = g_strdup("RecordDeleted"); break; case GnomePilotRecordNew: tmp = g_strdup("RecordNew"); break; default: tmp = g_strdup_printf("0x%x",flag); break; } printf ("entering iterate_specific(flag = %s)\n", tmp); g_free(tmp); } #endif g_return_val_if_fail(local!=NULL,-1); /* iterate until a record meets the criteria */ while(gnome_pilot_conduit_standard_abs_iterate(conduit,(LocalRecord**)local)) { if((*local)==NULL) break; #if SUPPORT_ARCHIVING if(archived && ((*local)->local.archived==archived)) break; #endif if(((*local)->local.attr == flag)) break; } return (*local)==NULL?0:1; } /* ** actually remove the records flagged as deleted from the local ** store. ** ** XXX return value isn't checked by gnome-pilot source. */ static gint purge (GnomePilotConduitStandardAbs *conduit, AddressbookConduitContext *ctxt) { GList *it; gint retval = 0; for (it=ctxt->cards; it;) { guint32 current_status; gtk_object_get (GTK_OBJECT (it->data), "pilot_status", ¤t_status, NULL); if (current_status == E_CARD_PILOT_STATUS_DEL) { EBookStatus remove_status; e_book_remove_card (ctxt->ebook, it->data, status_cb, &remove_status); gtk_main(); /* enter sub loop */ if (remove_status == E_BOOK_STATUS_SUCCESS) { GList *l = it; it = g_list_next (it); gtk_object_unref (GTK_OBJECT (it->data)); ctxt->cards = g_list_remove_link(ctxt->cards, l); g_list_free_1 (l); } else { retval = -1; it = g_list_next (it); } } else it = g_list_next (it); } return retval; } /* ** sets the value of the status flag on the local record (deleted, ** nothing, modified, etc.) ** ** XXX return value not checked by gnome-pilot source. */ static gint set_status (GnomePilotConduitStandardAbs *conduit, AddressbookLocalRecord *local, gint status, AddressbookConduitContext *ctxt) { EBookStatus commit_status; guint32 ecard_status; LOG ("entering set_status(status=%d)",status); g_return_val_if_fail(local!=NULL,-1); g_assert(local->ecard!=NULL); local->local.attr = status; switch(status) { case GnomePilotRecordDeleted: ecard_status = E_CARD_PILOT_STATUS_DEL; break; case GnomePilotRecordNew: case GnomePilotRecordModified: ecard_status = E_CARD_PILOT_STATUS_MOD; break; default: ecard_status = E_CARD_PILOT_STATUS_NONE; break; } gtk_object_set (GTK_OBJECT (local->ecard), "pilot_status", ecard_status, NULL); e_book_commit_card (ctxt->ebook, local->ecard, status_cb, &commit_status); gtk_main (); /* enter sub loop */ if (commit_status != E_BOOK_STATUS_SUCCESS) { WARN (_("Error while communicating with address server")); } return 0; } /* ** used when writing a record to the pilot. the id is the one ** assigned to the remote record. storing it in the local record ** makes it easier to match up local and remote records later on. ** ** this should not change the state of the local entry to modified. ** ** XXX return value not checked by gnome-pilot source. */ static gint set_pilot_id (GnomePilotConduitStandardAbs *conduit, AddressbookLocalRecord *local, guint32 ID, AddressbookConduitContext *ctxt) { EBookStatus commit_status; LOG ("entering set_pilot_id(id=%d)",ID); g_return_val_if_fail(local!=NULL,-1); g_assert(local->ecard!=NULL); local->local.ID = ID; gtk_object_set (GTK_OBJECT(local->ecard), "pilot_id", local->local.ID, NULL); e_book_commit_card (ctxt->ebook, local->ecard, status_cb, &commit_status); gtk_main (); /* enter sub loop */ if (commit_status == E_BOOK_STATUS_SUCCESS) { return 0; } else { WARN ("set_pilot_id failed.\n"); return -1; } } static int get_phone_label_by_name (struct AddressAppInfo *ai, const char *name) { int i; for (i = 0; i < 8 /* the number of pilot address labels */; i ++) { if (!strcmp(name, ai->phoneLabels[i])) return i; } WARN ("couldn't find pilot label '%s'.\n", name); return 0; } static int get_phone_label_by_flag (struct AddressAppInfo *ai, int flags) { char *label_to_find; if (flags & E_CARD_PHONE_PREF) label_to_find = "Main"; else if (flags & E_CARD_PHONE_WORK) label_to_find = "Work"; else if (flags & E_CARD_PHONE_HOME) label_to_find = "Home"; else if (flags & E_CARD_PHONE_FAX) label_to_find = "Fax"; else if (flags & E_CARD_PHONE_PAGER) label_to_find = "Pager"; else if (flags & E_CARD_PHONE_CELL) label_to_find = "Mobile"; else label_to_find = "Other"; return get_phone_label_by_name (ai, label_to_find); } /* ** used to convert between a local record and a remote record. memory ** allocated during this process should be freed in free_transmit ** below. ** ** XXX return value not checked by gnome-pilot source, but setting ** *remote to NULL triggers an error. */ static gint transmit (GnomePilotConduitStandardAbs *conduit, AddressbookLocalRecord *local, PilotRecord **remote, AddressbookConduitContext *ctxt) { PilotRecord *p; ECardName *ecard_name; EList *ecard_phones; EList *ecard_emails; char *ecard_org, *ecard_note, *ecard_title; int phone_entry = entryPhone1; LOG ("entering transmit"); g_return_val_if_fail(local!=NULL,-1); g_return_val_if_fail(remote!=NULL,-1); g_assert(local->ecard!=NULL); p = g_new0(PilotRecord,1); p->ID = local->local.ID; p->attr = local->local.attr; p->archived = local->local.archived; p->secret = local->local.secret; local->address = g_new0(struct Address,1); gtk_object_get (GTK_OBJECT (local->ecard), "name", &ecard_name, "org", &ecard_org, "note", &ecard_note, "title", &ecard_title, "phone", &ecard_phones, "email", &ecard_emails, NULL); /* use strdup instead of g_strdup since free_transmit uses free, not g_free. */ if (ecard_name) { if (ecard_name->given) local->address->entry [ entryFirstname ] = strdup (ecard_name->given); if (ecard_name->family) local->address->entry [ entryLastname ] = strdup (ecard_name->family); // e_card_name_free (ecard_name); } if (ecard_org) { local->address->entry [ entryCompany ] = strdup (ecard_org); } if (ecard_title) { local->address->entry [ entryTitle ] = strdup (ecard_title); } if (ecard_emails) { EIterator *iterator = e_list_get_iterator (ecard_emails); char *email; if ((email = (char *)e_iterator_get(iterator))) { local->address->phoneLabel[phone_entry - entryPhone1] = get_phone_label_by_name (&ctxt->ai, "E-mail"); local->address->entry [ phone_entry ] = strdup (email); phone_entry++; } } if (ecard_phones) { int phone_entry = entryPhone1; EIterator *iterator = e_list_get_iterator (ecard_phones); ECardPhone *phone; while ((phone = (ECardPhone*)e_iterator_get(iterator))) { local->address->phoneLabel[phone_entry - entryPhone1] = get_phone_label_by_flag (&ctxt->ai, phone->flags); local->address->entry [ phone_entry ] = strdup (phone->number); /* only store a maximum of 5 numbers (4 if there was an email address) */ if (phone_entry == entryPhone5) break; if (e_iterator_next (iterator) == FALSE) break; phone_entry++; } } if (ecard_note) { local->address->entry [ entryNote ] = strdup (ecard_note); } #if 0 printf ("transmitting address to pilot [%s] complete=%d/%ld\n", local->ical->summary==NULL?"NULL":local->ical->summary, local->address->complete, local->ical->completed); #endif /* Generate pilot record structure */ p->record = g_new0(char,0xffff); p->length = pack_Address(local->address,p->record,0xffff); *remote = p; return 0; } /* ** free memory allocated in the transmit signal. ** ** XXX return value not checked. */ static gint free_transmit (GnomePilotConduitStandardAbs *conduit, AddressbookLocalRecord *local, PilotRecord **remote, AddressbookConduitContext *ctxt) { LOG ("entering free_transmit"); g_return_val_if_fail(local!=NULL,-1); g_return_val_if_fail(remote!=NULL,-1); free_Address(local->address); g_free((*remote)->record); *remote = NULL; return 0; } /* ** used when synching. compare the local and remove record data and ** determine equality. ** ** retval is similar to strcmp: 0 for equality, anything else for ** inequality (no ordering is imposed). */ static gint compare (GnomePilotConduitStandardAbs *conduit, AddressbookLocalRecord *local, PilotRecord *remote, AddressbookConduitContext *ctxt) { #if 0 /* used by the quick compare */ PilotRecord *remoteOfLocal; int err; int retval; g_message ("entering compare"); printf ("entering compare\n"); g_return_val_if_fail (local!=NULL,-1); g_return_val_if_fail (remote!=NULL,-1); err = transmit(conduit,local,&remoteOfLocal,ctxt); if (err != 0) return err; retval = 0; if (remote->length == remoteOfLocal->length) { if (memcmp(remoteOfLocal->record,remote->record,remote->length)!=0) { g_message("compare failed on contents"); printf ("compare failed on contents\n"); retval = 1; /* debug spew */ { struct Address foolocal; struct Address fooremote; unpack_Address (&foolocal, remoteOfLocal->record, remoteOfLocal->length); unpack_Address (&fooremote, remote->record, remote->length); printf (" local:[%d %ld %d %d '%s' '%s']\n", foolocal.indefinite, mktime (& foolocal.due), foolocal.priority, foolocal.complete, foolocal.description, foolocal.note); printf ("remote:[%d %ld %d %d '%s' '%s']\n", fooremote.indefinite, mktime (& fooremote.due), fooremote.priority, fooremote.complete, fooremote.description, fooremote.note); } } } else { g_message("compare failed on length"); printf("compare failed on length\n"); retval = 1; } free_transmit(conduit,local,&remoteOfLocal,ctxt); return retval; #endif /* 0 */ return 0; } /* ** XXX not actually called from the gnome-pilot source */ static gint compare_backup (GnomePilotConduitStandardAbs *conduit, AddressbookLocalRecord *local, PilotRecord *remote, AddressbookConduitContext *ctxt) { LOG ("entering compare_backup"); g_return_val_if_fail(local!=NULL,-1); g_return_val_if_fail(remote!=NULL,-1); return -1; } /* ** used when copying from the pilot. ** ** delete all records in the local database. this doesn't actually ** remove the records, merely sets their status to DELETED. ** ** return value is < 0 on error, >= 0 on success. */ static gint delete_all (GnomePilotConduitStandardAbs *conduit, AddressbookConduitContext *ctxt) { GList *it; for (it=ctxt->cards; it; it = g_list_next (it)) { gtk_object_set (GTK_OBJECT (it->data), "pilot_status", E_CARD_PILOT_STATUS_DEL, NULL); } return 0; } #ifdef NEED_OAF_INIT_HACK static ORBit_MessageValidationResult accept_all_cookies (CORBA_unsigned_long request_id, CORBA_Principal *principal, CORBA_char *operation) { /* allow ALL cookies */ return ORBIT_MESSAGE_ALLOW_ALL; } #endif GnomePilotConduit * conduit_get_gpilot_conduit (guint32 pilotId) { GtkObject *retval; AddressbookConduitCfg *cfg; AddressbookConduitContext *ctxt; printf ("in address's conduit_get_gpilot_conduit\n"); #ifdef NEED_OAF_INIT_HACK #ifndef NO_WARNINGS #warning "need a better way to do this" #endif /* we need to find wombat with oaf, so make sure oaf is initialized here. once the desktop is converted to oaf and gpilotd is built with oaf, this can go away */ if (! oaf_is_initialized ()) { char *argv[ 1 ] = {"hi"}; oaf_init (1, argv); if (bonobo_init (CORBA_OBJECT_NIL, CORBA_OBJECT_NIL, CORBA_OBJECT_NIL) == FALSE) g_error (_("Could not initialize Bonobo")); ORBit_set_request_validation_handler (accept_all_cookies); } #endif retval = gnome_pilot_conduit_standard_abs_new ("AddressDB", 0x61646472); g_assert (retval != NULL); gnome_pilot_conduit_construct(GNOME_PILOT_CONDUIT(retval),"AddressConduit"); conduit_load_configuration(&cfg,pilotId); gtk_object_set_data (retval,"addressconduit_cfg",cfg); conduit_new_context(&ctxt,cfg); gtk_object_set_data(GTK_OBJECT(retval),"addressconduit_context",ctxt); gtk_signal_connect (retval, "match_record", (GtkSignalFunc) match_record, ctxt); gtk_signal_connect (retval, "free_match", (GtkSignalFunc) free_match, ctxt); #ifdef SUPPORT_ARCHIVING gtk_signal_connect (retval, "archive_local", (GtkSignalFunc) archive_local, ctxt); gtk_signal_connect (retval, "archive_remote", (GtkSignalFunc) archive_remote, ctxt); gtk_signal_connect (retval, "set_archived", (GtkSignalFunc) set_archived, ctxt); gtk_signal_connect (retval, "clear_status_archive_local", (GtkSignalFunc) clear_status_archive_local, ctxt); #endif gtk_signal_connect (retval, "store_remote", (GtkSignalFunc) store_remote, ctxt); gtk_signal_connect (retval, "iterate", (GtkSignalFunc) iterate, ctxt); gtk_signal_connect (retval, "iterate_specific", (GtkSignalFunc) iterate_specific, ctxt); gtk_signal_connect (retval, "purge", (GtkSignalFunc) purge, ctxt); gtk_signal_connect (retval, "set_status", (GtkSignalFunc) set_status, ctxt); gtk_signal_connect (retval, "set_pilot_id", (GtkSignalFunc) set_pilot_id, ctxt); gtk_signal_connect (retval, "compare", (GtkSignalFunc) compare, ctxt); gtk_signal_connect (retval, "compare_backup", (GtkSignalFunc) compare_backup, ctxt); gtk_signal_connect (retval, "free_transmit", (GtkSignalFunc) free_transmit, ctxt); gtk_signal_connect (retval, "delete_all", (GtkSignalFunc) delete_all, ctxt); gtk_signal_connect (retval, "transmit", (GtkSignalFunc) transmit, ctxt); gtk_signal_connect (retval, "pre_sync", (GtkSignalFunc) pre_sync, ctxt); return GNOME_PILOT_CONDUIT (retval); } void conduit_destroy_gpilot_conduit (GnomePilotConduit *conduit) { AddressbookConduitCfg *cc; AddressbookConduitContext *ctxt; cc = GET_CONDUITCFG(conduit); ctxt = GET_CONDUITCONTEXT(conduit); if (ctxt->ebook != NULL) { gtk_object_unref (GTK_OBJECT (ctxt->ebook)); } conduit_destroy_configuration (&cc); conduit_destroy_context (&ctxt); gtk_object_destroy (GTK_OBJECT (conduit)); }