--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999,2000 Hiroyuki Yamamoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * Address item data.
+ */
+
+#ifndef __ADDRESSITEM_H__
+#define __ADDRESSITEM_H__
+
+#define ADDRESS_OBJECT(obj) ((AddressObject *)obj)
+#define ADDRESS_OBJECT_TYPE(obj) (ADDRESS_OBJECT(obj)->type)
+#define ADDRESS_ITEM(obj) ((AddressItem *)obj)
+
+#define ADDRESS_ITEM_CAT_UNKNOWN -1
+
+typedef struct _AddressObject AddressObject;
+typedef struct _AddressItem AddressItem;
+
+typedef enum
+{
+ ADDR_ITEM,
+ ADDR_GROUP,
+ ADDR_FOLDER,
+ ADDR_VCARD,
+ ADDR_JPILOT,
+ ADDR_CATEGORY,
+ ADDR_LDAP
+} AddressObjectType;
+
+struct _AddressObject
+{
+ AddressObjectType type;
+};
+
+struct _AddressItem
+{
+ AddressObject obj;
+
+ gchar *name;
+ gchar *address;
+ gchar *remarks;
+ gchar *externalID;
+ gint categoryID;
+};
+
+#endif /* __ADDRESSITEM_H__ */
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * Edit JPilot address book data.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef USE_JPILOT
+
+#include "defs.h"
+
+#include <glib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkhbbox.h>
+#include <gtk/gtkbutton.h>
+
+#include "intl.h"
+#include "addressbook.h"
+#include "prefs_common.h"
+#include "addressitem.h"
+#include "jpilot.h"
+
+#define ADDRESSBOOK_GUESS_JPILOT "MyJPilot"
+#define JPILOT_NUM_CUSTOM_LABEL 4
+
+static struct _JPilotEdit {
+ GtkWidget *window;
+ GtkWidget *name_entry;
+ GtkWidget *file_entry;
+ GtkWidget *custom_check[JPILOT_NUM_CUSTOM_LABEL];
+ GtkWidget *custom_label[JPILOT_NUM_CUSTOM_LABEL];
+ GtkWidget *ok_btn;
+ GtkWidget *cancel_btn;
+ GtkWidget *statusbar;
+ gint status_cid;
+} jpilotedit;
+
+static struct _AddressFileSelection jpilot_file_selector;
+
+/*
+* Edit functions.
+*/
+void edit_jpilot_status_show( gchar *msg ) {
+ if( jpilotedit.statusbar != NULL ) {
+ gtk_statusbar_pop( GTK_STATUSBAR(jpilotedit.statusbar), jpilotedit.status_cid );
+ if( msg ) {
+ gtk_statusbar_push( GTK_STATUSBAR(jpilotedit.statusbar), jpilotedit.status_cid, msg );
+ }
+ }
+}
+
+static gint edit_jpilot_delete_event( GtkWidget *widget, GdkEventAny *event, gboolean *cancelled ) {
+ *cancelled = TRUE;
+ gtk_main_quit();
+ return TRUE;
+}
+
+static void edit_jpilot_key_pressed( GtkWidget *widget, GdkEventKey *event, gboolean *cancelled ) {
+ if (event && event->keyval == GDK_Escape) {
+ *cancelled = TRUE;
+ gtk_main_quit();
+ }
+}
+
+static void edit_jpilot_ok( GtkWidget *widget, gboolean *cancelled ) {
+ *cancelled = FALSE;
+ gtk_main_quit();
+}
+
+static void edit_jpilot_cancel( GtkWidget *widget, gboolean *cancelled ) {
+ *cancelled = TRUE;
+ gtk_main_quit();
+}
+
+static void edit_jpilot_fill_check_box( JPilotFile *jpf ) {
+ gint i;
+ GList *node, *customLbl = NULL;
+ gchar *labelName;
+ gboolean done, checked;
+ for( i = 0; i < JPILOT_NUM_CUSTOM_LABEL; i++ ) {
+ gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( jpilotedit.custom_check[i] ), FALSE );
+ gtk_label_set_text( GTK_LABEL( jpilotedit.custom_label[i] ), "" );
+ }
+
+ done = FALSE;
+ i = 0;
+ customLbl = jpilot_load_custom_label( jpf, customLbl );
+ node = customLbl;
+ while( ! done ) {
+ if( node ) {
+ labelName = node->data;
+ gtk_label_set_text( GTK_LABEL( jpilotedit.custom_label[i] ), labelName );
+ checked = jpilot_test_custom_label( jpf, labelName );
+ gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( jpilotedit.custom_check[i] ), checked );
+ i++;
+ if( i >= JPILOT_NUM_CUSTOM_LABEL ) done = TRUE;
+ node = g_list_next( node );
+ }
+ else {
+ done = TRUE;
+ }
+ }
+ mgu_free_dlist( customLbl );
+ customLbl = NULL;
+}
+
+static void edit_jpilot_fill_check_box_new() {
+ gint i;
+ for( i = 0; i < JPILOT_NUM_CUSTOM_LABEL; i++ ) {
+ gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( jpilotedit.custom_check[i] ), FALSE );
+ gtk_label_set_text( GTK_LABEL( jpilotedit.custom_label[i] ), "" );
+ }
+}
+
+static void edit_jpilot_read_check_box( JPilotFile *pilotFile ) {
+ gint i;
+ gchar *labelName;
+ jpilot_clear_custom_labels( pilotFile );
+ for( i = 0; i < JPILOT_NUM_CUSTOM_LABEL; i++ ) {
+ if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(jpilotedit.custom_check[i]) ) ) {
+ labelName = g_strdup( GTK_LABEL(jpilotedit.custom_label[i])->label );
+ jpilot_add_custom_label( pilotFile, labelName );
+ }
+ }
+}
+
+static void edit_jpilot_file_check( void ) {
+ gint t;
+ gchar *sFile;
+ gchar *sMsg;
+ gboolean flg;
+
+ flg = FALSE;
+ sFile = gtk_editable_get_chars( GTK_EDITABLE(jpilotedit.file_entry), 0, -1 );
+ if( sFile ) {
+ g_strchomp( sFile ); g_strchug( sFile );
+ if( *sFile != '\0' ) {
+ // Attempt to read file
+ JPilotFile *jpf = jpilot_create_path( sFile );
+ t = jpilot_read_data( jpf );
+ if( t == MGU_SUCCESS ) {
+ // Set check boxes
+ edit_jpilot_fill_check_box( jpf );
+ flg = TRUE;
+ }
+ jpilot_free( jpf );
+ }
+ }
+ if( ! flg ) {
+ // Clear all check boxes
+ edit_jpilot_fill_check_box_new();
+ }
+ g_free( sFile );
+
+ // Display appropriate message
+ if( t == MGU_SUCCESS ) {
+ sMsg = "";
+ }
+ else if( t == MGU_BAD_FORMAT || t == MGU_OO_MEMORY ) {
+ sMsg = _("File does not appear to be JPilot format.");
+ }
+ else {
+ sMsg = _("Could not read file.");
+ }
+ edit_jpilot_status_show( sMsg );
+}
+
+static void edit_jpilot_file_ok( GtkWidget *widget, gpointer data ) {
+ gchar *sFile;
+ AddressFileSelection *afs;
+ GtkWidget *fileSel;
+
+ afs = ( AddressFileSelection * ) data;
+ fileSel = afs->fileSelector;
+ sFile = gtk_file_selection_get_filename( GTK_FILE_SELECTION(fileSel) );
+
+ afs->cancelled = FALSE;
+ gtk_entry_set_text( GTK_ENTRY(jpilotedit.file_entry), sFile );
+ gtk_widget_hide( afs->fileSelector );
+ gtk_grab_remove( afs->fileSelector );
+ edit_jpilot_file_check();
+ gtk_widget_grab_focus( jpilotedit.file_entry );
+}
+
+static void edit_jpilot_file_cancel( GtkWidget *widget, gpointer data ) {
+ AddressFileSelection *afs = ( AddressFileSelection * ) data;
+ afs->cancelled = TRUE;
+ gtk_widget_hide( afs->fileSelector );
+ gtk_grab_remove( afs->fileSelector );
+ gtk_widget_grab_focus( jpilotedit.file_entry );
+}
+
+static void edit_jpilot_file_select_create( AddressFileSelection *afs ) {
+ GtkWidget *fileSelector;
+
+ fileSelector = gtk_file_selection_new( _("Select JPilot File") );
+ gtk_file_selection_hide_fileop_buttons( GTK_FILE_SELECTION(fileSelector) );
+ gtk_signal_connect( GTK_OBJECT (GTK_FILE_SELECTION(fileSelector)->ok_button),
+ "clicked", GTK_SIGNAL_FUNC (edit_jpilot_file_ok), ( gpointer ) afs );
+ gtk_signal_connect( GTK_OBJECT (GTK_FILE_SELECTION(fileSelector)->cancel_button),
+ "clicked", GTK_SIGNAL_FUNC (edit_jpilot_file_cancel), ( gpointer ) afs );
+ afs->fileSelector = fileSelector;
+ afs->cancelled = TRUE;
+}
+
+static void edit_jpilot_file_select( void ) {
+ gchar *sFile;
+
+ if (! jpilot_file_selector.fileSelector )
+ edit_jpilot_file_select_create( & jpilot_file_selector );
+
+ sFile = gtk_editable_get_chars( GTK_EDITABLE(jpilotedit.file_entry), 0, -1 );
+ gtk_file_selection_set_filename( GTK_FILE_SELECTION( jpilot_file_selector.fileSelector ), sFile );
+ g_free( sFile );
+ gtk_widget_show( jpilot_file_selector.fileSelector );
+ gtk_grab_add( jpilot_file_selector.fileSelector );
+}
+
+static void addressbook_edit_jpilot_create( gboolean *cancelled ) {
+ GtkWidget *window;
+ GtkWidget *vbox;
+ GtkWidget *table;
+ GtkWidget *label;
+ GtkWidget *name_entry;
+ GtkWidget *file_entry;
+ GtkWidget *vbox_custom;
+ GtkWidget *frame_custom;
+ GtkWidget *custom_check[JPILOT_NUM_CUSTOM_LABEL];
+ GtkWidget *custom_label[JPILOT_NUM_CUSTOM_LABEL];
+ GtkWidget *hlbox;
+ GtkWidget *hbbox;
+ GtkWidget *hsep;
+ GtkWidget *ok_btn;
+ GtkWidget *cancel_btn;
+ GtkWidget *check_btn;
+ GtkWidget *file_btn;
+ GtkWidget *hsbox;
+ GtkWidget *statusbar;
+ gint top, i;
+
+ window = gtk_window_new(GTK_WINDOW_DIALOG);
+ gtk_widget_set_usize(window, 450, -1);
+ gtk_container_set_border_width(GTK_CONTAINER(window), 0);
+ gtk_window_set_title(GTK_WINDOW(window), _("Edit JPilot Entry"));
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+ gtk_window_set_modal(GTK_WINDOW(window), TRUE);
+ gtk_signal_connect(GTK_OBJECT(window), "delete_event",
+ GTK_SIGNAL_FUNC(edit_jpilot_delete_event),
+ cancelled);
+ gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
+ GTK_SIGNAL_FUNC(edit_jpilot_key_pressed),
+ cancelled);
+
+ vbox = gtk_vbox_new(FALSE, 8);
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+ gtk_container_set_border_width( GTK_CONTAINER(vbox), 0 );
+
+ table = gtk_table_new(2 + JPILOT_NUM_CUSTOM_LABEL, 3, FALSE);
+ gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
+ gtk_container_set_border_width( GTK_CONTAINER(table), 8 );
+ gtk_table_set_row_spacings(GTK_TABLE(table), 8);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 8);
+
+ // First row
+ top = 0;
+ label = gtk_label_new(_("Name"));
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+ name_entry = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(table), name_entry, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+ check_btn = gtk_button_new_with_label( _(" Check File "));
+ gtk_table_attach(GTK_TABLE(table), check_btn, 2, 3, top, (top + 1), GTK_FILL, 0, 3, 0);
+
+ // Second row
+ top = 1;
+ label = gtk_label_new(_("File"));
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+ file_entry = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(table), file_entry, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+ file_btn = gtk_button_new_with_label( _(" ... "));
+ gtk_table_attach(GTK_TABLE(table), file_btn, 2, 3, top, (top + 1), GTK_FILL, 0, 3, 0);
+
+ // Third row
+ top = 2;
+ frame_custom = gtk_frame_new(_("Additional e-Mail address item(s)"));
+ gtk_table_attach(GTK_TABLE(table), frame_custom, 1, 2, top, (top + JPILOT_NUM_CUSTOM_LABEL), GTK_FILL, 0, 0, 0);
+
+ // Now do custom labels.
+ vbox_custom = gtk_vbox_new (FALSE, 8);
+ for( i = 0; i < JPILOT_NUM_CUSTOM_LABEL; i++ ) {
+ hlbox = gtk_hbox_new( FALSE, 0 );
+ custom_check[i] = gtk_check_button_new();
+ custom_label[i] = gtk_label_new( "" );
+ gtk_box_pack_start( GTK_BOX(hlbox), custom_check[i], FALSE, FALSE, 0 );
+ gtk_box_pack_start( GTK_BOX(hlbox), custom_label[i], TRUE, TRUE, 0 );
+ gtk_box_pack_start( GTK_BOX(vbox_custom), hlbox, TRUE, TRUE, 0 );
+ gtk_misc_set_alignment(GTK_MISC(custom_label[i]), 0, 0.5);
+ top++;
+ }
+ gtk_container_add (GTK_CONTAINER (frame_custom), vbox_custom);
+ gtk_container_set_border_width( GTK_CONTAINER(vbox_custom), 8 );
+
+ // Status line
+ hsbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
+ statusbar = gtk_statusbar_new();
+ gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
+
+ // Button panel
+ gtkut_button_set_create(&hbbox, &ok_btn, _("OK"),
+ &cancel_btn, _("Cancel"), NULL, NULL);
+ gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
+ gtk_container_set_border_width( GTK_CONTAINER(hbbox), 0 );
+ gtk_widget_grab_default(ok_btn);
+
+ hsep = gtk_hseparator_new();
+ gtk_box_pack_end(GTK_BOX(vbox), hsep, FALSE, FALSE, 0);
+
+ gtk_signal_connect(GTK_OBJECT(ok_btn), "clicked",
+ GTK_SIGNAL_FUNC(edit_jpilot_ok), cancelled);
+ gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked",
+ GTK_SIGNAL_FUNC(edit_jpilot_cancel), cancelled);
+ gtk_signal_connect(GTK_OBJECT(file_btn), "clicked",
+ GTK_SIGNAL_FUNC(edit_jpilot_file_select), NULL);
+ gtk_signal_connect(GTK_OBJECT(check_btn), "clicked",
+ GTK_SIGNAL_FUNC(edit_jpilot_file_check), NULL);
+
+ gtk_widget_show_all(vbox);
+
+ jpilotedit.window = window;
+ jpilotedit.name_entry = name_entry;
+ jpilotedit.file_entry = file_entry;
+ jpilotedit.ok_btn = ok_btn;
+ jpilotedit.cancel_btn = cancel_btn;
+ jpilotedit.statusbar = statusbar;
+ jpilotedit.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Edit JPilot Dialog" );
+ for( i = 0; i < JPILOT_NUM_CUSTOM_LABEL; i++ ) {
+ jpilotedit.custom_check[i] = custom_check[i];
+ jpilotedit.custom_label[i] = custom_label[i];
+ }
+}
+
+AddressJPilot *addressbook_edit_jpilot( AddressJPilot *jpilot ) {
+ static gboolean cancelled;
+ gchar *sName;
+ gchar *sFile;
+ JPilotFile *jpf;
+ gboolean fin;
+
+ if (!jpilotedit.window)
+ addressbook_edit_jpilot_create(&cancelled);
+ gtk_widget_grab_focus(jpilotedit.ok_btn);
+ gtk_widget_grab_focus(jpilotedit.name_entry);
+ gtk_widget_show(jpilotedit.window);
+ manage_window_set_transient(GTK_WINDOW(jpilotedit.window));
+
+ edit_jpilot_status_show( "" );
+ if( jpilot ) {
+ jpf = jpilot->pilotFile;
+ if (jpf->name)
+ gtk_entry_set_text(GTK_ENTRY(jpilotedit.name_entry), jpf->name);
+ if (jpf->path)
+ gtk_entry_set_text(GTK_ENTRY(jpilotedit.file_entry), jpf->path);
+ gtk_window_set_title( GTK_WINDOW(jpilotedit.window), _("Edit JPilot Entry"));
+ edit_jpilot_fill_check_box( jpf );
+ }
+ else {
+ gchar *guessFile = jpilot_find_pilotdb();
+ gtk_entry_set_text(GTK_ENTRY(jpilotedit.name_entry), ADDRESSBOOK_GUESS_JPILOT );
+ gtk_entry_set_text(GTK_ENTRY(jpilotedit.file_entry), guessFile );
+ gtk_window_set_title( GTK_WINDOW(jpilotedit.window), _("Add New JPilot Entry"));
+ edit_jpilot_fill_check_box_new();
+ // Attempt to load labels
+ if( *guessFile != '\0' ) {
+ edit_jpilot_file_check();
+ }
+ }
+
+ gtk_main();
+ gtk_widget_hide(jpilotedit.window);
+ if (cancelled == TRUE) return NULL;
+
+ fin = FALSE;
+ sName = gtk_editable_get_chars( GTK_EDITABLE(jpilotedit.name_entry), 0, -1 );
+ sFile = gtk_editable_get_chars( GTK_EDITABLE(jpilotedit.file_entry), 0, -1 );
+ if( *sName == '\0' ) fin = TRUE;
+ if( *sFile == '\0' ) fin = TRUE;
+
+ if( ! fin ) {
+ if( ! jpilot ) {
+ jpilot = g_new0(AddressJPilot, 1);
+ ADDRESS_OBJECT_TYPE(jpilot) = ADDR_JPILOT;
+ jpf = jpilot_create();
+ jpilot->pilotFile = jpf;
+ }
+ g_free( jpilot->name );
+ jpilot->name = g_strdup( sName );
+ jpilot_set_name( jpf, sName );
+ jpilot_set_file( jpf, sFile );
+ edit_jpilot_read_check_box( jpf );
+ }
+ g_free( sName );
+ g_free( sFile );
+
+ return jpilot;
+}
+
+#endif /* USE_JPILOT */
+
+/*
+* End of Source.
+*/
+
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * Edit JPilot address book data.
+ */
+
+#ifndef __EDITJPILOT_H__
+#define __EDITJPILOT_H__
+
+#ifdef USE_JPILOT
+
+// Function prototypes
+AddressJPilot *addressbook_edit_jpilot( AddressJPilot *jpilot );
+
+#endif /* USE_JPILOT */
+
+#endif /* __EDITJPILOT_H__ */
+
+/*
+* End of Source.
+*/
+
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * Edit VCard address book data.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef USE_LDAP
+
+#include "defs.h"
+
+#include <glib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtktable.h>
+#include <gtk/gtkbutton.h>
+
+#include "intl.h"
+#include "addressbook.h"
+#include "prefs_common.h"
+#include "menu.h"
+#include "addressitem.h"
+#include "syldap.h"
+#include "editldap_basedn.h"
+
+#define ADDRESSBOOK_GUESS_LDAP_NAME "MyServer"
+#define ADDRESSBOOK_GUESS_LDAP_SERVER "localhost"
+
+#define LDAPEDIT_TABLE_ROWS 6
+#define LDAPEDIT_TABLE_COLS 3
+
+static struct _LDAPEdit {
+ GtkWidget *window;
+ GtkWidget *notebook;
+ GtkWidget *ok_btn;
+ GtkWidget *cancel_btn;
+ GtkWidget *statusbar;
+ gint status_cid;
+ GtkWidget *entry_name;
+ GtkWidget *entry_server;
+ GtkWidget *spinbtn_port;
+ GtkWidget *entry_baseDN;
+ GtkWidget *spinbtn_timeout;
+ GtkWidget *entry_bindDN;
+ GtkWidget *entry_bindPW;
+ GtkWidget *entry_criteria;
+ GtkWidget *spinbtn_maxentry;
+} ldapedit;
+
+/*
+* Edit functions.
+*/
+void edit_ldap_status_show( gchar *msg ) {
+ if( ldapedit.statusbar != NULL ) {
+ gtk_statusbar_pop( GTK_STATUSBAR(ldapedit.statusbar), ldapedit.status_cid );
+ if( msg ) {
+ gtk_statusbar_push( GTK_STATUSBAR(ldapedit.statusbar), ldapedit.status_cid, msg );
+ }
+ }
+}
+
+static void edit_ldap_ok( GtkWidget *widget, gboolean *cancelled ) {
+ *cancelled = FALSE;
+ gtk_main_quit();
+}
+
+static void edit_ldap_cancel( GtkWidget *widget, gboolean *cancelled ) {
+ *cancelled = TRUE;
+ gtk_main_quit();
+}
+
+static gint edit_ldap_delete_event( GtkWidget *widget, GdkEventAny *event, gboolean *cancelled ) {
+ *cancelled = TRUE;
+ gtk_main_quit();
+ return TRUE;
+}
+
+static void edit_ldap_key_pressed( GtkWidget *widget, GdkEventKey *event, gboolean *cancelled ) {
+ if (event && event->keyval == GDK_Escape) {
+ *cancelled = TRUE;
+ gtk_main_quit();
+ }
+}
+
+static void edit_ldap_switch_page( GtkWidget *widget ) {
+ edit_ldap_status_show( "" );
+}
+
+static void edit_ldap_server_check( void ) {
+ gchar *sHost, *sBind, *sPass;
+ gint iPort, iTime;
+ gchar *sMsg;
+ gchar *sBaseDN = NULL;
+ gint iBaseDN = 0;
+ gboolean flg;
+
+ edit_ldap_status_show( "" );
+ flg = FALSE;
+ sHost = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_server), 0, -1 );
+ sBind = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_bindDN), 0, -1 );
+ sPass = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_bindPW), 0, -1 );
+ iPort = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( ldapedit.spinbtn_port ) );
+ iTime = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( ldapedit.spinbtn_timeout ) );
+ g_strchomp( sHost ); g_strchug( sHost );
+ g_strchomp( sBind ); g_strchug( sBind );
+ g_strchomp( sPass ); g_strchug( sPass );
+ if( *sHost != '\0' ) {
+ // Test connection to server
+ if( syldap_test_connect_s( sHost, iPort ) ) {
+ // Attempt to read base DN
+ GList *baseDN = syldap_read_basedn_s( sHost, iPort, sBind, sPass, iTime );
+ if( baseDN ) {
+ GList *node = baseDN;
+ while( node ) {
+ ++iBaseDN;
+ if( ! sBaseDN ) {
+ sBaseDN = g_strdup( node->data );
+ }
+ node = g_list_next( node );
+ }
+ mgu_free_dlist( baseDN );
+ baseDN = node = NULL;
+ }
+ flg = TRUE;
+ }
+ }
+ g_free( sHost );
+ g_free( sBind );
+ g_free( sPass );
+
+ if( sBaseDN ) {
+ // Load search DN
+ gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_baseDN), sBaseDN);
+ g_free( sBaseDN );
+ }
+
+ // Display appropriate message
+ if( flg ) {
+ sMsg = _( "Connected successfully to server" );
+ }
+ else {
+ sMsg = _( "Could not connect to server" );
+ }
+ edit_ldap_status_show( sMsg );
+}
+
+static void edit_ldap_basedn_select( void ) {
+ gchar *sHost, *sBind, *sPass, *sBase;
+ gint iPort, iTime;
+ gchar *selectDN;
+
+ sHost = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_server), 0, -1 );
+ sBase = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_baseDN), 0, -1 );
+ sBind = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_bindDN), 0, -1 );
+ sPass = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_bindPW), 0, -1 );
+ iPort = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( ldapedit.spinbtn_port ) );
+ iTime = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( ldapedit.spinbtn_timeout ) );
+ g_strchomp( sHost ); g_strchug( sHost );
+ g_strchomp( sBind ); g_strchug( sBind );
+ g_strchomp( sPass ); g_strchug( sPass );
+ selectDN = edit_ldap_basedn_selection( sHost, iPort, sBase, iTime, sBind, sPass );
+ if( selectDN ) {
+ gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_baseDN), selectDN);
+ g_free( selectDN );
+ selectDN = NULL;
+ }
+ g_free( sHost );
+ g_free( sBase );
+ g_free( sBind );
+ g_free( sPass );
+}
+
+static void edit_ldap_search_reset( void ) {
+ gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_criteria), SYLDAP_DFL_CRITERIA );
+}
+
+static void addressbook_edit_ldap_dialog_create( gboolean *cancelled ) {
+ GtkWidget *window;
+ GtkWidget *vbox;
+ GtkWidget *notebook;
+ GtkWidget *hbbox;
+ GtkWidget *ok_btn;
+ GtkWidget *cancel_btn;
+ GtkWidget *hsbox;
+ GtkWidget *statusbar;
+
+ window = gtk_window_new(GTK_WINDOW_DIALOG);
+ gtk_widget_set_usize(window, 450, -1);
+ gtk_container_set_border_width(GTK_CONTAINER(window), 0);
+ gtk_window_set_title(GTK_WINDOW(window), _("Edit LDAP Server"));
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+ gtk_window_set_modal(GTK_WINDOW(window), TRUE);
+ gtk_signal_connect(GTK_OBJECT(window), "delete_event",
+ GTK_SIGNAL_FUNC(edit_ldap_delete_event),
+ cancelled);
+ gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
+ GTK_SIGNAL_FUNC(edit_ldap_key_pressed),
+ cancelled);
+
+ vbox = gtk_vbox_new( FALSE, 6 );
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), BORDER_WIDTH);
+ gtk_widget_show( vbox );
+ gtk_container_add( GTK_CONTAINER( window ), vbox );
+
+ // Notebook
+ notebook = gtk_notebook_new();
+ gtk_widget_show( notebook );
+ gtk_box_pack_start( GTK_BOX( vbox ), notebook, TRUE, TRUE, 0 );
+ gtk_container_set_border_width( GTK_CONTAINER( notebook ), 6 );
+
+ // Status line
+ hsbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
+ statusbar = gtk_statusbar_new();
+ gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
+
+ // Button panel
+ gtkut_button_set_create(&hbbox, &ok_btn, _("OK"),
+ &cancel_btn, _("Cancel"), NULL, NULL);
+ gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
+ gtk_widget_grab_default(ok_btn);
+
+ gtk_signal_connect(GTK_OBJECT(ok_btn), "clicked",
+ GTK_SIGNAL_FUNC(edit_ldap_ok), cancelled);
+ gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked",
+ GTK_SIGNAL_FUNC(edit_ldap_cancel), cancelled);
+ gtk_signal_connect(GTK_OBJECT(notebook), "switch_page",
+ GTK_SIGNAL_FUNC(edit_ldap_switch_page), NULL );
+
+ gtk_widget_show_all(vbox);
+
+ ldapedit.window = window;
+ ldapedit.notebook = notebook;
+ ldapedit.ok_btn = ok_btn;
+ ldapedit.cancel_btn = cancel_btn;
+ ldapedit.statusbar = statusbar;
+ ldapedit.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Edit LDAP Server Dialog" );
+}
+
+void addressbook_edit_ldap_page_basic( gint pageNum, gchar *pageLbl ) {
+ GtkWidget *vbox;
+ GtkWidget *table;
+ GtkWidget *label;
+ GtkWidget *entry_name;
+ GtkWidget *entry_server;
+ GtkWidget *hbox_spin;
+ GtkObject *spinbtn_port_adj;
+ GtkWidget *spinbtn_port;
+ GtkWidget *entry_baseDN;
+ GtkWidget *check_btn;
+ GtkWidget *lookdn_btn;
+ gint top;
+
+ vbox = gtk_vbox_new( FALSE, 8 );
+ gtk_widget_show( vbox );
+ gtk_container_add( GTK_CONTAINER( ldapedit.notebook ), vbox );
+ gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
+
+ label = gtk_label_new( pageLbl );
+ gtk_widget_show( label );
+ gtk_notebook_set_tab_label(
+ GTK_NOTEBOOK( ldapedit.notebook ),
+ gtk_notebook_get_nth_page( GTK_NOTEBOOK( ldapedit.notebook ), pageNum ), label );
+
+ table = gtk_table_new( LDAPEDIT_TABLE_ROWS, LDAPEDIT_TABLE_COLS, FALSE);
+ gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
+ gtk_container_set_border_width( GTK_CONTAINER(table), 8 );
+ gtk_table_set_row_spacings(GTK_TABLE(table), 8);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 8);
+
+ // First row
+ top = 0;
+ label = gtk_label_new(_("Name"));
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+ entry_name = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(table), entry_name, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+ // Next row
+ ++top;
+ label = gtk_label_new(_("Hostname"));
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+ entry_server = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(table), entry_server, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+ // Next row
+ ++top;
+ label = gtk_label_new(_("Port"));
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+ hbox_spin = gtk_hbox_new (FALSE, 8);
+ spinbtn_port_adj = gtk_adjustment_new (389, 1, 65535, 100, 1000, 1000);
+ spinbtn_port = gtk_spin_button_new(GTK_ADJUSTMENT (spinbtn_port_adj), 1, 0);
+ gtk_box_pack_start (GTK_BOX (hbox_spin), spinbtn_port, FALSE, FALSE, 0);
+ gtk_widget_set_usize (spinbtn_port, 64, -1);
+ gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbtn_port), TRUE);
+ gtk_table_attach(GTK_TABLE(table), hbox_spin, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+ check_btn = gtk_button_new_with_label( _(" Check Server "));
+ gtk_table_attach(GTK_TABLE(table), check_btn, 2, 3, top, (top + 1), GTK_FILL, 0, 3, 0);
+
+ // Next row
+ ++top;
+ label = gtk_label_new(_("Search Base"));
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+ entry_baseDN = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(table), entry_baseDN, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+ lookdn_btn = gtk_button_new_with_label( _(" ... "));
+ gtk_table_attach(GTK_TABLE(table), lookdn_btn, 2, 3, top, (top + 1), GTK_FILL, 0, 3, 0);
+
+ gtk_signal_connect(GTK_OBJECT(check_btn), "clicked",
+ GTK_SIGNAL_FUNC(edit_ldap_server_check), NULL);
+ gtk_signal_connect(GTK_OBJECT(lookdn_btn), "clicked",
+ GTK_SIGNAL_FUNC(edit_ldap_basedn_select), NULL);
+
+ gtk_widget_show_all(vbox);
+
+ ldapedit.entry_name = entry_name;
+ ldapedit.entry_server = entry_server;
+ ldapedit.spinbtn_port = spinbtn_port;
+ ldapedit.entry_baseDN = entry_baseDN;
+}
+
+void addressbook_edit_ldap_page_extended( gint pageNum, gchar *pageLbl ) {
+ GtkWidget *vbox;
+ GtkWidget *table;
+ GtkWidget *label;
+ GtkWidget *entry_bindDN;
+ GtkWidget *entry_bindPW;
+ GtkWidget *entry_criteria;
+ GtkWidget *hbox_spin;
+ GtkObject *spinbtn_timeout_adj;
+ GtkWidget *spinbtn_timeout;
+ GtkObject *spinbtn_maxentry_adj;
+ GtkWidget *spinbtn_maxentry;
+ GtkWidget *reset_btn;
+ gint top;
+
+ vbox = gtk_vbox_new( FALSE, 8 );
+ gtk_widget_show( vbox );
+ gtk_container_add( GTK_CONTAINER( ldapedit.notebook ), vbox );
+ gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
+
+ label = gtk_label_new( pageLbl );
+ gtk_widget_show( label );
+ gtk_notebook_set_tab_label(
+ GTK_NOTEBOOK( ldapedit.notebook ),
+ gtk_notebook_get_nth_page( GTK_NOTEBOOK( ldapedit.notebook ), pageNum ), label );
+
+ table = gtk_table_new( LDAPEDIT_TABLE_ROWS, LDAPEDIT_TABLE_COLS, FALSE);
+ gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
+ gtk_container_set_border_width( GTK_CONTAINER(table), 8 );
+ gtk_table_set_row_spacings(GTK_TABLE(table), 8);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 8);
+
+ // First row
+ top = 0;
+ label = gtk_label_new(_("Search Criteria"));
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+ entry_criteria = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(table), entry_criteria, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+ reset_btn = gtk_button_new_with_label( _(" Reset "));
+ gtk_table_attach(GTK_TABLE(table), reset_btn, 2, 3, top, (top + 1), GTK_FILL, 0, 3, 0);
+
+ // Next row
+ ++top;
+ label = gtk_label_new(_("Bind DN"));
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+ entry_bindDN = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(table), entry_bindDN, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+ // Next row
+ ++top;
+ label = gtk_label_new(_("Bind Password"));
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+ entry_bindPW = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(table), entry_bindPW, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+ // Next row
+ ++top;
+ label = gtk_label_new(_("Timeout (secs)"));
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+ hbox_spin = gtk_hbox_new (FALSE, 8);
+ spinbtn_timeout_adj = gtk_adjustment_new (0, 0, 300, 1, 10, 10);
+ spinbtn_timeout = gtk_spin_button_new(GTK_ADJUSTMENT (spinbtn_timeout_adj), 1, 0);
+ gtk_box_pack_start (GTK_BOX (hbox_spin), spinbtn_timeout, FALSE, FALSE, 0);
+ gtk_widget_set_usize (spinbtn_timeout, 64, -1);
+ gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbtn_timeout), TRUE);
+ gtk_table_attach(GTK_TABLE(table), hbox_spin, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+ // Next row
+ ++top;
+ label = gtk_label_new(_("Maximum Entries"));
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+ hbox_spin = gtk_hbox_new (FALSE, 8);
+ spinbtn_maxentry_adj = gtk_adjustment_new (0, 0, 500, 1, 10, 10);
+ spinbtn_maxentry = gtk_spin_button_new(GTK_ADJUSTMENT (spinbtn_maxentry_adj), 1, 0);
+ gtk_box_pack_start (GTK_BOX (hbox_spin), spinbtn_maxentry, FALSE, FALSE, 0);
+ gtk_widget_set_usize (spinbtn_maxentry, 64, -1);
+ gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbtn_maxentry), TRUE);
+ gtk_table_attach(GTK_TABLE(table), hbox_spin, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+ gtk_signal_connect(GTK_OBJECT(reset_btn), "clicked",
+ GTK_SIGNAL_FUNC(edit_ldap_search_reset), NULL);
+
+ gtk_widget_show_all(vbox);
+
+ ldapedit.entry_criteria = entry_criteria;
+ ldapedit.entry_bindDN = entry_bindDN;
+ ldapedit.entry_bindPW = entry_bindPW;
+ ldapedit.spinbtn_timeout = spinbtn_timeout;
+ ldapedit.spinbtn_maxentry = spinbtn_maxentry;
+}
+
+static void addressbook_edit_ldap_create( gboolean *cancelled ) {
+ gint page = 0;
+ addressbook_edit_ldap_dialog_create( cancelled );
+ addressbook_edit_ldap_page_basic( page++, _( "Basic" ) );
+ addressbook_edit_ldap_page_extended( page++, _( "Extended" ) );
+ gtk_widget_show_all( ldapedit.window );
+}
+
+void edit_ldap_set_optmenu( GtkOptionMenu *optmenu, const gint value ) {
+ GList *cur;
+ GtkWidget *menu;
+ GtkWidget *menuitem;
+ gint menuVal;
+ gint n = 0;
+
+ g_return_if_fail(menu != NULL);
+
+ menu = gtk_option_menu_get_menu(optmenu);
+ for( cur = GTK_MENU_SHELL(menu)->children; cur != NULL; cur = cur->next ) {
+ menuitem = GTK_WIDGET(cur->data);
+ menuVal = GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(menuitem)));
+ if( menuVal == value ) {
+ gtk_option_menu_set_history(optmenu, n);
+ return;
+ }
+ n++;
+ }
+ gtk_option_menu_set_history(optmenu, 0);
+}
+
+gint edit_ldap_get_optmenu( GtkOptionMenu *optmenu ) {
+ GtkWidget *menu;
+ GtkWidget *menuitem;
+ g_return_if_fail(menu != NULL);
+ menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu));
+ menuitem = gtk_menu_get_active(GTK_MENU(menu));
+ return GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(menuitem)));
+}
+
+AddressLDAP *addressbook_edit_ldap( AddressLDAP *ldapi ) {
+ static gboolean cancelled;
+ gchar *sName, *sHost, *sBase, *sBind, *sPass, *sCrit;
+ gint iPort, iMaxE, iTime, iMail, iName;
+ SyldapServer *server;
+ gboolean fin;
+
+ if (!ldapedit.window)
+ addressbook_edit_ldap_create(&cancelled);
+ gtk_notebook_set_page( GTK_NOTEBOOK(ldapedit.notebook), 0 );
+ gtk_widget_grab_focus(ldapedit.ok_btn);
+ gtk_widget_grab_focus(ldapedit.entry_name);
+ gtk_widget_show(ldapedit.window);
+ manage_window_set_transient(GTK_WINDOW(ldapedit.window));
+
+ edit_ldap_status_show( "" );
+ if( ldapi ) {
+ server = ldapi->ldapServer;
+ if (server->name)
+ gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_name), server->name);
+ if (server->hostName)
+ gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_server), server->hostName);
+ gtk_spin_button_set_value( GTK_SPIN_BUTTON( ldapedit.spinbtn_port ), server->port );
+ gtk_spin_button_set_value( GTK_SPIN_BUTTON( ldapedit.spinbtn_timeout ), server->timeOut );
+ if (server->baseDN)
+ gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_baseDN), server->baseDN);
+ if (server->searchCriteria)
+ gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_criteria), server->searchCriteria);
+ if (server->bindDN)
+ gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_bindDN), server->bindDN);
+ if (server->bindPass)
+ gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_bindPW), server->bindPass);
+ gtk_spin_button_set_value( GTK_SPIN_BUTTON( ldapedit.spinbtn_maxentry ), server->maxEntries );
+ gtk_window_set_title( GTK_WINDOW(ldapedit.window), _("Edit LDAP Server"));
+ }
+ else {
+ gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_name), ADDRESSBOOK_GUESS_LDAP_NAME );
+ gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_server), ADDRESSBOOK_GUESS_LDAP_SERVER );
+ gtk_spin_button_set_value( GTK_SPIN_BUTTON( ldapedit.spinbtn_port ), SYLDAP_DFL_PORT );
+ gtk_spin_button_set_value( GTK_SPIN_BUTTON( ldapedit.spinbtn_timeout ), SYLDAP_DFL_TIMEOUT );
+ gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_baseDN), "");
+ gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_criteria), SYLDAP_DFL_CRITERIA );
+ gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_bindDN), "");
+ gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_bindPW), "");
+ gtk_spin_button_set_value( GTK_SPIN_BUTTON( ldapedit.spinbtn_maxentry ), SYLDAP_MAX_ENTRIES );
+ gtk_window_set_title( GTK_WINDOW(ldapedit.window), _("Add New LDAP Server"));
+ }
+
+ gtk_main();
+ gtk_widget_hide(ldapedit.window);
+ if (cancelled == TRUE) return NULL;
+
+ fin = FALSE;
+ sName = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_name), 0, -1 );
+ sHost = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_server), 0, -1 );
+ iPort = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( ldapedit.spinbtn_port ) );
+ iTime = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( ldapedit.spinbtn_timeout ) );
+ sBase = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_baseDN), 0, -1 );
+ sCrit = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_criteria), 0, -1 );
+ sBind = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_bindDN), 0, -1 );
+ sPass = gtk_editable_get_chars( GTK_EDITABLE(ldapedit.entry_bindPW), 0, -1 );
+ iMaxE = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( ldapedit.spinbtn_maxentry ) );
+
+ if( *sName == '\0' ) fin = TRUE;
+ if( *sHost == '\0' ) fin = TRUE;
+ if( *sBase == '\0' ) fin = TRUE;
+
+ if( ! fin ) {
+ if( ! ldapi ) {
+ ldapi = g_new0(AddressLDAP, 1);
+ ADDRESS_OBJECT_TYPE(ldapi) = ADDR_LDAP;
+ server = syldap_create();
+ ldapi->ldapServer = server;
+ }
+ g_free( ldapi->name );
+ ldapi->name = g_strdup( sName );
+ syldap_set_name( server, sName );
+ syldap_set_host( server, sHost );
+ syldap_set_port( server, iPort );
+ syldap_set_base_dn( server, sBase );
+ syldap_set_bind_dn( server, sBind );
+ syldap_set_bind_password( server, sPass );
+ syldap_set_search_criteria( server, sCrit );
+ syldap_set_max_entries( server, iMaxE );
+ syldap_set_timeout( server, iTime );
+ }
+ g_free( sName );
+ g_free( sHost );
+ g_free( sBase );
+ g_free( sBind );
+ g_free( sPass );
+ g_free( sCrit );
+
+ return ldapi;
+}
+
+#endif /* USE_LDAP */
+
+/*
+* End of Source.
+*/
+
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * Edit VCard address book data.
+ */
+
+#ifndef __EDITLDAP_H__
+#define __EDITLDAP_H__
+
+#ifdef USE_LDAP
+
+// Function prototypes
+AddressLDAP *addressbook_edit_ldap( AddressLDAP *ldapi );
+
+#endif /* USE_LDAP */
+
+#endif /* __EDITLDAP_H__ */
+
+/*
+* End of Source.
+*/
+
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * LDAP Base DN selection dialog.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef USE_LDAP
+
+#include "defs.h"
+
+#include <glib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkhbbox.h>
+#include <gtk/gtkbutton.h>
+
+#include "intl.h"
+#include "prefs_common.h"
+#include "syldap.h"
+
+static struct _LDAPEdit_basedn {
+ GtkWidget *window;
+ GtkWidget *host_label;
+ GtkWidget *port_label;
+ GtkWidget *basedn_entry;
+ GtkWidget *basedn_list;
+ GtkWidget *ok_btn;
+ GtkWidget *cancel_btn;
+ GtkWidget *statusbar;
+ gint status_cid;
+} ldapedit_basedn;
+
+static gboolean ldapedit_basedn_cancelled;
+static gboolean ldapedit_basedn_bad_server;
+
+/*
+* Edit functions.
+*/
+void edit_ldap_bdn_status_show( gchar *msg ) {
+ if( ldapedit_basedn.statusbar != NULL ) {
+ gtk_statusbar_pop( GTK_STATUSBAR(ldapedit_basedn.statusbar), ldapedit_basedn.status_cid );
+ if( msg ) {
+ gtk_statusbar_push( GTK_STATUSBAR(ldapedit_basedn.statusbar), ldapedit_basedn.status_cid, msg );
+ }
+ }
+}
+
+static gint edit_ldap_bdn_delete_event( GtkWidget *widget, GdkEventAny *event, gboolean *cancelled ) {
+ ldapedit_basedn_cancelled = TRUE;
+ gtk_main_quit();
+ return TRUE;
+}
+
+static void edit_ldap_bdn_key_pressed( GtkWidget *widget, GdkEventKey *event, gboolean *cancelled ) {
+ if (event && event->keyval == GDK_Escape) {
+ ldapedit_basedn_cancelled = TRUE;
+ gtk_main_quit();
+ }
+}
+
+static void edit_ldap_bdn_ok( GtkWidget *widget, gboolean *cancelled ) {
+ ldapedit_basedn_cancelled = FALSE;
+ gtk_main_quit();
+}
+
+static void edit_ldap_bdn_cancel( GtkWidget *widget, gboolean *cancelled ) {
+ ldapedit_basedn_cancelled = TRUE;
+ gtk_main_quit();
+}
+
+static void edit_ldap_bdn_list_select( GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer data ) {
+ gchar **text;
+ if( gtk_clist_get_text( clist, row, 0, text ) ) {
+ if( *text ) {
+ gtk_entry_set_text(GTK_ENTRY(ldapedit_basedn.basedn_entry), *text );
+ }
+ }
+}
+
+static void edit_ldap_bdn_list_button( GtkCList *clist, GdkEventButton *event, gpointer data ) {
+ if( ! event ) return;
+ if( event->button == 1 ) {
+ if( event->type == GDK_2BUTTON_PRESS ) {
+ ldapedit_basedn_cancelled = FALSE;
+ gtk_main_quit();
+ }
+ }
+}
+
+static void edit_ldap_bdn_create() {
+ GtkWidget *window;
+ GtkWidget *vbox;
+ GtkWidget *table;
+ GtkWidget *label;
+ GtkWidget *host_label;
+ GtkWidget *port_label;
+ GtkWidget *basedn_label;
+ GtkWidget *basedn_list;
+ GtkWidget *vlbox;
+ GtkWidget *lwindow;
+ GtkWidget *basedn_entry;
+ GtkWidget *hlbox;
+ GtkWidget *hbbox;
+ GtkWidget *hsep;
+ GtkWidget *ok_btn;
+ GtkWidget *cancel_btn;
+ GtkWidget *check_btn;
+ GtkWidget *file_btn;
+ GtkWidget *hsbox;
+ GtkWidget *statusbar;
+ gint top;
+
+ window = gtk_window_new(GTK_WINDOW_DIALOG);
+ gtk_widget_set_usize(window, 300, 270);
+ gtk_container_set_border_width(GTK_CONTAINER(window), 0);
+ gtk_window_set_title(GTK_WINDOW(window), _("Edit LDAP - Select Search Base"));
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+ gtk_window_set_modal(GTK_WINDOW(window), TRUE);
+ gtk_signal_connect(GTK_OBJECT(window), "delete_event",
+ GTK_SIGNAL_FUNC(edit_ldap_bdn_delete_event), NULL );
+ gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
+ GTK_SIGNAL_FUNC(edit_ldap_bdn_key_pressed), NULL );
+
+ vbox = gtk_vbox_new(FALSE, 8);
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+ gtk_container_set_border_width( GTK_CONTAINER(vbox), 0 );
+
+ table = gtk_table_new(3, 2, FALSE);
+ gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
+ gtk_container_set_border_width( GTK_CONTAINER(table), 8 );
+ gtk_table_set_row_spacings(GTK_TABLE(table), 8);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 8);
+
+ // First row
+ top = 0;
+ label = gtk_label_new(_("Hostname"));
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+ host_label = gtk_label_new("");
+ gtk_table_attach(GTK_TABLE(table), host_label, 1, 2, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(host_label), 0, 0.5);
+
+ // Second row
+ top = 1;
+ label = gtk_label_new(_("Port"));
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+
+ port_label = gtk_label_new("");
+ gtk_table_attach(GTK_TABLE(table), port_label, 1, 2, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(port_label), 0, 0.5);
+
+ // Third row
+ top = 2;
+ label = gtk_label_new(_("Search Base"));
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+ basedn_entry = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(table), basedn_entry, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+ // Basedn list
+ vlbox = gtk_vbox_new(FALSE, 8);
+ gtk_box_pack_start(GTK_BOX(vbox), vlbox, TRUE, TRUE, 0);
+ gtk_container_set_border_width( GTK_CONTAINER(vlbox), 8 );
+
+ lwindow = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(lwindow),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_ALWAYS);
+ gtk_box_pack_start(GTK_BOX(vlbox), lwindow, TRUE, TRUE, 0);
+
+ basedn_list = gtk_clist_new(1);
+ gtk_container_add(GTK_CONTAINER(lwindow), basedn_list);
+ gtk_clist_column_titles_show( GTK_CLIST(basedn_list) );
+ gtk_clist_set_column_title( GTK_CLIST(basedn_list), 0, _( "Available Search Base(s)" ) );
+ gtk_clist_set_selection_mode(GTK_CLIST(basedn_list), GTK_SELECTION_BROWSE);
+
+ // Status line
+ hsbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
+ statusbar = gtk_statusbar_new();
+ gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
+
+ // Button panel
+ gtkut_button_set_create(&hbbox, &ok_btn, _("OK"),
+ &cancel_btn, _("Cancel"), NULL, NULL);
+ gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
+ gtk_container_set_border_width( GTK_CONTAINER(hbbox), 0 );
+ gtk_widget_grab_default(ok_btn);
+
+ hsep = gtk_hseparator_new();
+ gtk_box_pack_end(GTK_BOX(vbox), hsep, FALSE, FALSE, 0);
+
+ gtk_signal_connect(GTK_OBJECT(ok_btn), "clicked",
+ GTK_SIGNAL_FUNC(edit_ldap_bdn_ok), NULL);
+ gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked",
+ GTK_SIGNAL_FUNC(edit_ldap_bdn_cancel), NULL);
+ gtk_signal_connect(GTK_OBJECT(basedn_list), "select_row",
+ GTK_SIGNAL_FUNC(edit_ldap_bdn_list_select), NULL);
+ gtk_signal_connect(GTK_OBJECT(basedn_list), "button_press_event",
+ GTK_SIGNAL_FUNC(edit_ldap_bdn_list_button), NULL);
+
+ gtk_widget_show_all(vbox);
+
+ ldapedit_basedn.window = window;
+ ldapedit_basedn.host_label = host_label;
+ ldapedit_basedn.port_label = port_label;
+ ldapedit_basedn.basedn_entry = basedn_entry;
+ ldapedit_basedn.basedn_list = basedn_list;
+ ldapedit_basedn.ok_btn = ok_btn;
+ ldapedit_basedn.cancel_btn = cancel_btn;
+ ldapedit_basedn.statusbar = statusbar;
+ ldapedit_basedn.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Edit LDAP Select Base DN" );
+}
+
+void edit_ldap_bdn_load_data( const gchar *hostName, const gint iPort, const gint tov, const gchar* bindDN,
+ const gchar *bindPW ) {
+ gchar *sHost;
+ gchar *sMsg = NULL;
+ gchar sPort[20];
+ gboolean flgConn;
+ gboolean flgDN;
+
+ edit_ldap_status_show( "" );
+ gtk_clist_clear(GTK_CLIST(ldapedit_basedn.basedn_list));
+ ldapedit_basedn_bad_server = TRUE;
+ flgConn = flgDN = FALSE;
+ sHost = g_strdup( hostName );
+ sprintf( sPort, "%d", iPort );
+ gtk_label_set_text(GTK_LABEL(ldapedit_basedn.host_label), hostName);
+ gtk_label_set_text(GTK_LABEL(ldapedit_basedn.port_label), sPort);
+ if( *sHost != '\0' ) {
+ // Test connection to server
+ if( syldap_test_connect_s( sHost, iPort ) ) {
+ // Attempt to read base DN
+ GList *baseDN = syldap_read_basedn_s( sHost, iPort, bindDN, bindPW, tov );
+ if( baseDN ) {
+ GList *node = baseDN;
+ gchar *sBase[2];
+ sBase[1] = NULL;
+ while( node ) {
+ sBase[0] = g_strdup( node->data );
+ gtk_clist_append(GTK_CLIST(ldapedit_basedn.basedn_list), sBase);
+ node = g_list_next( node );
+ flgDN = TRUE;
+ }
+ mgu_free_dlist( baseDN );
+ baseDN = node = NULL;
+ sBase[0] = NULL;
+ }
+ ldapedit_basedn_bad_server = FALSE;
+ flgConn = TRUE;
+ }
+ }
+ g_free( sHost );
+
+ // Display appropriate message
+ if( flgConn ) {
+ if( ! flgDN ) {
+ sMsg = _( "Could not read Search Base(s) from server - please set manually" );
+ }
+ }
+ else {
+ sMsg = _( "Could not connect to server" );
+ }
+ edit_ldap_bdn_status_show( sMsg );
+}
+
+gchar *edit_ldap_basedn_selection( const gchar *hostName, const gint port, gchar *baseDN, const gint tov,
+ const gchar* bindDN, const gchar *bindPW ) {
+ gchar *retVal = NULL;
+
+ ldapedit_basedn_cancelled = FALSE;
+ if( ! ldapedit_basedn.window ) edit_ldap_bdn_create();
+ gtk_widget_grab_focus(ldapedit_basedn.ok_btn);
+ gtk_widget_show(ldapedit_basedn.window);
+ manage_window_set_transient(GTK_WINDOW(ldapedit_basedn.window));
+
+ edit_ldap_bdn_status_show( "" );
+ edit_ldap_bdn_load_data( hostName, port, tov, bindDN, bindPW );
+ gtk_widget_show(ldapedit_basedn.window);
+
+// sprintf( sPort, "%d", port );
+// gtk_label_set_text(GTK_LABEL(ldapedit_basedn.host_label), hostName);
+// gtk_label_set_text(GTK_LABEL(ldapedit_basedn.port_label), sPort);
+ gtk_entry_set_text(GTK_ENTRY(ldapedit_basedn.basedn_entry), baseDN);
+
+ gtk_main();
+ gtk_widget_hide(ldapedit_basedn.window);
+ if( ldapedit_basedn_cancelled ) return NULL;
+// if( cancelled == TRUE ) return NULL;
+ if( ldapedit_basedn_bad_server ) return NULL;
+
+ retVal = g_strdup( gtk_editable_get_chars( GTK_EDITABLE(ldapedit_basedn.basedn_entry), 0, -1 ) );
+ g_strchomp( retVal ); g_strchug( retVal );
+ if( *retVal == '\0' ) {
+ g_free( retVal );
+ retVal = NULL;
+ }
+ return retVal;
+}
+
+#endif /* USE_LDAP */
+
+/*
+* End of Source.
+*/
+
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * Edit VCard address book data.
+ */
+
+#ifndef __EDITLDAP_BASEDN_H__
+#define __EDITLDAP_BASEDN_H__
+
+#ifdef USE_LDAP
+
+// Function prototypes
+gchar *edit_ldap_basedn_selection( const gchar *hostName, const gint port, gchar *baseDN, const gint tov,
+ const gchar* bindDN, const gchar *bindPW );
+
+#endif /* USE_LDAP */
+
+#endif /* __EDITLDAP_BASEDN_H__ */
+
+/*
+* End of Source.
+*/
+
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * Edit VCard address book data.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "defs.h"
+
+#include <glib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtktable.h>
+#include <gtk/gtkbutton.h>
+
+#include "intl.h"
+#include "addressbook.h"
+#include "prefs_common.h"
+#include "addressitem.h"
+#include "vcard.h"
+
+#define ADDRESSBOOK_GUESS_VCARD "MyGnomeCard"
+
+static struct _VCardEdit {
+ GtkWidget *window;
+ GtkWidget *name_entry;
+ GtkWidget *file_entry;
+ GtkWidget *ok_btn;
+ GtkWidget *cancel_btn;
+ GtkWidget *statusbar;
+ gint status_cid;
+} vcardedit;
+
+static struct _AddressFileSelection vcard_file_selector;
+
+/*
+* Edit functions.
+*/
+void edit_vcard_status_show( gchar *msg ) {
+ if( vcardedit.statusbar != NULL ) {
+ gtk_statusbar_pop( GTK_STATUSBAR(vcardedit.statusbar), vcardedit.status_cid );
+ if( msg ) {
+ gtk_statusbar_push( GTK_STATUSBAR(vcardedit.statusbar), vcardedit.status_cid, msg );
+ }
+ }
+}
+
+static void edit_vcard_ok( GtkWidget *widget, gboolean *cancelled ) {
+ *cancelled = FALSE;
+ gtk_main_quit();
+}
+
+static void edit_vcard_cancel( GtkWidget *widget, gboolean *cancelled ) {
+ *cancelled = TRUE;
+ gtk_main_quit();
+}
+
+static void edit_vcard_file_check( void ) {
+ gint t;
+ gchar *sFile;
+ gchar *sMsg;
+
+ sFile = gtk_editable_get_chars( GTK_EDITABLE(vcardedit.file_entry), 0, -1 );
+ t = vcard_test_read_file( sFile );
+ g_free( sFile );
+ if( t == MGU_SUCCESS ) {
+ sMsg = "";
+ }
+ else if( t == MGU_BAD_FORMAT ) {
+ sMsg = _("File does not appear to be VCard format.");
+ }
+ else {
+ sMsg = _("Could not read file.");
+ }
+ edit_vcard_status_show( sMsg );
+}
+
+static void edit_vcard_file_ok( GtkWidget *widget, gpointer data ) {
+ gchar *sFile;
+ AddressFileSelection *afs;
+ GtkWidget *fileSel;
+
+ afs = ( AddressFileSelection * ) data;
+ fileSel = afs->fileSelector;
+ sFile = gtk_file_selection_get_filename( GTK_FILE_SELECTION(fileSel) );
+
+ afs->cancelled = FALSE;
+ gtk_entry_set_text( GTK_ENTRY(vcardedit.file_entry), sFile );
+ gtk_widget_hide( afs->fileSelector );
+ gtk_grab_remove( afs->fileSelector );
+ edit_vcard_file_check();
+ gtk_widget_grab_focus( vcardedit.file_entry );
+}
+
+static void edit_vcard_file_cancel( GtkWidget *widget, gpointer data ) {
+ AddressFileSelection *afs = ( AddressFileSelection * ) data;
+ afs->cancelled = TRUE;
+ gtk_widget_hide( afs->fileSelector );
+ gtk_grab_remove( afs->fileSelector );
+ gtk_widget_grab_focus( vcardedit.file_entry );
+}
+
+static void edit_vcard_file_select_create( AddressFileSelection *afs ) {
+ GtkWidget *fileSelector;
+
+ fileSelector = gtk_file_selection_new( _("Select VCard File") );
+ gtk_file_selection_hide_fileop_buttons( GTK_FILE_SELECTION(fileSelector) );
+ gtk_signal_connect( GTK_OBJECT (GTK_FILE_SELECTION(fileSelector)->ok_button),
+ "clicked", GTK_SIGNAL_FUNC (edit_vcard_file_ok), ( gpointer ) afs );
+ gtk_signal_connect( GTK_OBJECT (GTK_FILE_SELECTION(fileSelector)->cancel_button),
+ "clicked", GTK_SIGNAL_FUNC (edit_vcard_file_cancel), ( gpointer ) afs );
+ afs->fileSelector = fileSelector;
+ afs->cancelled = TRUE;
+}
+
+static void edit_vcard_file_select( void ) {
+ gchar *sFile;
+
+ if (! vcard_file_selector.fileSelector )
+ edit_vcard_file_select_create( & vcard_file_selector );
+
+ sFile = gtk_editable_get_chars( GTK_EDITABLE(vcardedit.file_entry), 0, -1 );
+ gtk_file_selection_set_filename( GTK_FILE_SELECTION( vcard_file_selector.fileSelector ), sFile );
+ g_free( sFile );
+ gtk_widget_show( vcard_file_selector.fileSelector );
+ gtk_grab_add( vcard_file_selector.fileSelector );
+}
+
+static gint edit_vcard_delete_event( GtkWidget *widget, GdkEventAny *event, gboolean *cancelled ) {
+ *cancelled = TRUE;
+ gtk_main_quit();
+ return TRUE;
+}
+
+static void edit_vcard_key_pressed( GtkWidget *widget, GdkEventKey *event, gboolean *cancelled ) {
+ if (event && event->keyval == GDK_Escape) {
+ *cancelled = TRUE;
+ gtk_main_quit();
+ }
+}
+
+static void addressbook_edit_vcard_create( gboolean *cancelled ) {
+ GtkWidget *window;
+ GtkWidget *vbox;
+ GtkWidget *table;
+ GtkWidget *label;
+ GtkWidget *name_entry;
+ GtkWidget *file_entry;
+ GtkWidget *hbbox;
+ GtkWidget *hsep;
+ GtkWidget *ok_btn;
+ GtkWidget *cancel_btn;
+ GtkWidget *check_btn;
+ GtkWidget *file_btn;
+ GtkWidget *statusbar;
+ GtkWidget *hsbox;
+ gint top;
+
+ window = gtk_window_new(GTK_WINDOW_DIALOG);
+ gtk_widget_set_usize(window, 450, -1);
+ gtk_container_set_border_width( GTK_CONTAINER(window), 0 );
+ gtk_window_set_title(GTK_WINDOW(window), _("Edit VCard Entry"));
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+ gtk_window_set_modal(GTK_WINDOW(window), TRUE);
+ gtk_signal_connect(GTK_OBJECT(window), "delete_event",
+ GTK_SIGNAL_FUNC(edit_vcard_delete_event),
+ cancelled);
+ gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
+ GTK_SIGNAL_FUNC(edit_vcard_key_pressed),
+ cancelled);
+
+ vbox = gtk_vbox_new(FALSE, 8);
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+ gtk_container_set_border_width( GTK_CONTAINER(vbox), 0 );
+
+ table = gtk_table_new(2, 3, FALSE);
+ gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
+ gtk_container_set_border_width( GTK_CONTAINER(table), 8 );
+ gtk_table_set_row_spacings(GTK_TABLE(table), 8);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 8 );
+
+ // First row
+ top = 0;
+ label = gtk_label_new(_("Name"));
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+ name_entry = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(table), name_entry, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+ check_btn = gtk_button_new_with_label( _(" Check File "));
+ gtk_table_attach(GTK_TABLE(table), check_btn, 2, 3, top, (top + 1), GTK_FILL, 0, 3, 0);
+
+ // Second row
+ top = 1;
+ label = gtk_label_new(_("File"));
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+ file_entry = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(table), file_entry, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+ file_btn = gtk_button_new_with_label( _(" ... "));
+ gtk_table_attach(GTK_TABLE(table), file_btn, 2, 3, top, (top + 1), GTK_FILL, 0, 3, 0);
+
+ // Status line
+ hsbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
+ statusbar = gtk_statusbar_new();
+ gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
+
+ // Button panel
+ gtkut_button_set_create(&hbbox, &ok_btn, _("OK"),
+ &cancel_btn, _("Cancel"), NULL, NULL);
+ gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
+ gtk_container_set_border_width( GTK_CONTAINER(hbbox), 0 );
+ gtk_widget_grab_default(ok_btn);
+
+ hsep = gtk_hseparator_new();
+ gtk_box_pack_end(GTK_BOX(vbox), hsep, FALSE, FALSE, 0);
+
+ gtk_signal_connect(GTK_OBJECT(ok_btn), "clicked",
+ GTK_SIGNAL_FUNC(edit_vcard_ok), cancelled);
+ gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked",
+ GTK_SIGNAL_FUNC(edit_vcard_cancel), cancelled);
+ gtk_signal_connect(GTK_OBJECT(file_btn), "clicked",
+ GTK_SIGNAL_FUNC(edit_vcard_file_select), NULL);
+ gtk_signal_connect(GTK_OBJECT(check_btn), "clicked",
+ GTK_SIGNAL_FUNC(edit_vcard_file_check), NULL);
+
+ gtk_widget_show_all(vbox);
+
+ vcardedit.window = window;
+ vcardedit.name_entry = name_entry;
+ vcardedit.file_entry = file_entry;
+ vcardedit.ok_btn = ok_btn;
+ vcardedit.cancel_btn = cancel_btn;
+ vcardedit.statusbar = statusbar;
+ vcardedit.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Edit VCard Dialog" );
+}
+
+AddressVCard *addressbook_edit_vcard( AddressVCard *vcard ) {
+ static gboolean cancelled;
+ gchar *sName;
+ gchar *sFile;
+ VCardFile *vcf;
+ gboolean fin;
+
+ if (!vcardedit.window)
+ addressbook_edit_vcard_create(&cancelled);
+ gtk_widget_grab_focus(vcardedit.ok_btn);
+ gtk_widget_grab_focus(vcardedit.name_entry);
+ gtk_widget_show(vcardedit.window);
+ manage_window_set_transient(GTK_WINDOW(vcardedit.window));
+
+ edit_vcard_status_show( "" );
+ if( vcard ) {
+ vcf = vcard->cardFile;
+ if (vcf->name)
+ gtk_entry_set_text(GTK_ENTRY(vcardedit.name_entry), vcf->name);
+ if (vcf->path)
+ gtk_entry_set_text(GTK_ENTRY(vcardedit.file_entry), vcf->path);
+ gtk_window_set_title( GTK_WINDOW(vcardedit.window), _("Edit VCard Entry"));
+ }
+ else {
+ gtk_entry_set_text(GTK_ENTRY(vcardedit.name_entry), ADDRESSBOOK_GUESS_VCARD );
+ gtk_entry_set_text(GTK_ENTRY(vcardedit.file_entry), vcard_find_gnomecard() );
+ gtk_window_set_title( GTK_WINDOW(vcardedit.window), _("Add New VCard Entry"));
+ }
+
+ gtk_main();
+ gtk_widget_hide(vcardedit.window);
+ if (cancelled == TRUE) return NULL;
+
+ fin = FALSE;
+ sName = gtk_editable_get_chars( GTK_EDITABLE(vcardedit.name_entry), 0, -1 );
+ sFile = gtk_editable_get_chars( GTK_EDITABLE(vcardedit.file_entry), 0, -1 );
+ if( *sName == '\0' ) fin = TRUE;
+ if( *sFile == '\0' ) fin = TRUE;
+
+ if( ! fin ) {
+ if( ! vcard ) {
+ vcard = g_new0(AddressVCard, 1);
+ ADDRESS_OBJECT_TYPE(vcard) = ADDR_VCARD;
+ vcf = vcard_create();
+ vcard->cardFile = vcf;
+ }
+ g_free( vcard->name );
+ vcard->name = g_strdup( sName );
+ vcard_set_name( vcf, sName );
+ vcard_set_file( vcf, sFile );
+ }
+ g_free( sName );
+ g_free( sFile );
+
+ return vcard;
+}
+
+/*
+* End of Source.
+*/
+
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * Edit VCard address book data.
+ */
+
+#ifndef __EDITVCARD_H__
+#define __EDITVCARD_H__
+
+// Function prototypes
+AddressVCard *addressbook_edit_vcard( AddressVCard *vcard );
+
+#endif /* __EDITVCARD_H__ */
+
+/*
+* End of Source.
+*/
+
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * Functions necessary to access JPilot database files.
+ * JPilot is Copyright(c) by Judd Montgomery.
+ * Visit http://www.jpilot.org for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef USE_JPILOT
+
+#include <time.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+
+#include <pi-args.h>
+#include <pi-appinfo.h>
+#include <pi-address.h>
+
+#include "mgutils.h"
+#include "jpilot.h"
+
+#define JPILOT_DBHOME_DIR ".jpilot"
+#define JPILOT_DBHOME_FILE "AddressDB.pdb"
+#define PILOT_LINK_LIB_NAME "libpisock.so"
+
+#define IND_LABEL_LASTNAME 0 // Index of last name in address data
+#define IND_LABEL_FIRSTNAME 1 // Index of first name in address data
+#define IND_PHONE_EMAIL 4 // Index of E-Mail address in phone labels
+#define OFFSET_PHONE_LABEL 3 // Offset to phone data in address data
+#define IND_CUSTOM_LABEL 14 // Offset to custom label names
+#define NUM_CUSTOM_LABEL 4 // Number of custom labels
+
+typedef struct _JPilotCategory JPilotCategory;
+struct _JPilotCategory {
+ AddressItem *category;
+ GList *addressList;
+ gint count;
+};
+
+/*
+* Specify name to be used.
+*/
+void jpilot_set_name( JPilotFile* pilotFile, const gchar *name ) {
+ if( pilotFile->name ) g_free( pilotFile->name );
+ if( name ) pilotFile->name = g_strdup( name );
+}
+
+/*
+* Specify file to be used.
+*/
+void jpilot_set_file( JPilotFile* pilotFile, const gchar *path ) {
+ g_return_if_fail( pilotFile != NULL );
+ mgu_refresh_cache( pilotFile->addressCache );
+ pilotFile->readMetadata = FALSE;
+
+ /* Copy file path */
+ if( pilotFile->path ) g_free( pilotFile->path );
+ if( path ) pilotFile->path = g_strdup( path );
+}
+
+/*
+* Create new pilot file object.
+*/
+JPilotFile *jpilot_create() {
+ JPilotFile *pilotFile;
+ pilotFile = g_new( JPilotFile, 1 );
+ pilotFile->name = NULL;
+ pilotFile->path = NULL;
+ pilotFile->file = NULL;
+ pilotFile->addressCache = mgu_create_cache();
+ pilotFile->readMetadata = FALSE;
+ pilotFile->customLabels = NULL;
+ pilotFile->labelInd = NULL;
+ pilotFile->retVal = MGU_SUCCESS;
+ pilotFile->categoryList = NULL;
+ pilotFile->catAddrList = NULL;
+ return pilotFile;
+}
+
+/*
+* Create new pilot file object for specified file.
+*/
+JPilotFile *jpilot_create_path( const gchar *path ) {
+ JPilotFile *pilotFile;
+ pilotFile = jpilot_create();
+ jpilot_set_file( pilotFile, path );
+ return pilotFile;
+}
+
+/*
+* Test whether file was modified since last access.
+* Return: TRUE if file was modified.
+*/
+gboolean jpilot_get_modified( JPilotFile *pilotFile ) {
+ g_return_if_fail( pilotFile != NULL );
+ return mgu_check_file( pilotFile->addressCache, pilotFile->path );
+}
+
+/*
+* Free up custom label list.
+*/
+void jpilot_clear_custom_labels( JPilotFile *pilotFile ) {
+ GSList *node;
+ g_return_if_fail( pilotFile != NULL );
+
+ // Release custom labels
+ mgu_free_list( pilotFile->customLabels );
+ pilotFile->customLabels = NULL;
+
+ // Release indexes
+ node = pilotFile->labelInd;
+ while( node ) {
+ node->data = NULL;
+ node = g_slist_next( node );
+ }
+ g_slist_free( pilotFile->labelInd );
+ pilotFile->labelInd = NULL;
+
+ // Force a fresh read
+ mgu_refresh_cache( pilotFile->addressCache );
+}
+
+/*
+* Append a custom label, representing an E-Mail address field to the
+* custom label list.
+*/
+void jpilot_add_custom_label( JPilotFile *pilotFile, const gchar *labelName ) {
+ g_return_if_fail( pilotFile != NULL );
+
+ if( labelName ) {
+ gchar *labelCopy = g_strdup( labelName );
+ g_strstrip( labelCopy );
+ if( *labelCopy == '\0' ) {
+ g_free( labelCopy );
+ }
+ else {
+ pilotFile->customLabels = g_slist_append( pilotFile->customLabels, labelCopy );
+ // Force a fresh read
+ mgu_refresh_cache( pilotFile->addressCache );
+ }
+ }
+}
+
+/*
+* Get list of custom labels.
+* Return: List of labels. Must use g_free() when done.
+*/
+GList *jpilot_get_custom_labels( JPilotFile *pilotFile ) {
+ GList *retVal = NULL;
+ GSList *node;
+ g_return_if_fail( pilotFile != NULL );
+ node = pilotFile->customLabels;
+ while( node ) {
+ retVal = g_list_append( retVal, g_strdup( node->data ) );
+ node = g_slist_next( node );
+ }
+ return retVal;
+}
+
+/*
+* Free up pilot file object by releasing internal memory.
+*/
+void jpilot_free( JPilotFile *pilotFile ) {
+ g_return_if_fail( pilotFile != NULL );
+
+ /* Free internal stuff */
+ g_free( pilotFile->path );
+
+ // Release custom labels
+ jpilot_clear_custom_labels( pilotFile );
+
+ /* Clear cache */
+ mgu_clear_cache( pilotFile->addressCache );
+ mgu_free_cache( pilotFile->addressCache );
+ mgu_free_dlist( pilotFile->categoryList );
+ pilotFile->addressCache = NULL;
+ pilotFile->readMetadata = FALSE;
+ pilotFile->categoryList = NULL;
+ pilotFile->catAddrList = NULL;
+
+ /* Now release file object */
+ g_free( pilotFile );
+}
+
+/*
+* Refresh internal variables to force a file read.
+*/
+void jpilot_force_refresh( JPilotFile *pilotFile ) {
+ mgu_refresh_cache( pilotFile->addressCache );
+}
+
+/*
+* Print category address list for specified category.
+*/
+void jpilot_print_category( JPilotCategory *jpcat, FILE *stream ) {
+ fprintf( stream, "category: %s : count: %d\n", jpcat->category->name, jpcat->count );
+ if( jpcat->addressList ) {
+ mgu_print_address_list( jpcat->addressList, stream );
+ }
+ fprintf( stream, "=========================================\n" );
+}
+
+/*
+* Print address list for all categories.
+*/
+void jpilot_print_category_list( GList *catAddrList, FILE *stream ) {
+ GList *node;
+ JPilotCategory *jpcat;
+ if( catAddrList == NULL ) return;
+
+ fprintf( stream, "Address list by category\n" );
+ node = catAddrList;
+ while( node ) {
+ jpcat = node->data;
+ jpilot_print_category( jpcat, stream );
+ node = g_list_next( node );
+ }
+}
+
+/*
+* Print object to specified stream.
+*/
+void jpilot_print_file( JPilotFile *pilotFile, FILE *stream ) {
+ GSList *node;
+ g_return_if_fail( pilotFile != NULL );
+ fprintf( stream, "JPilotFile:\n" );
+ fprintf( stream, "file spec: '%s'\n", pilotFile->path );
+ fprintf( stream, " metadata: %s\n", pilotFile->readMetadata ? "yes" : "no" );
+ fprintf( stream, " ret val: %d\n", pilotFile->retVal );
+
+ node = pilotFile->customLabels;
+ while( node ) {
+ fprintf( stream, " c label: %s\n", node->data );
+ node = g_slist_next( node );
+ }
+
+ node = pilotFile->labelInd;
+ while( node ) {
+ fprintf( stream, " labelind: %d\n", GPOINTER_TO_INT(node->data) );
+ node = g_slist_next( node );
+ }
+
+ mgu_print_cache( pilotFile->addressCache, stream );
+ jpilot_print_category_list( pilotFile->catAddrList, stream );
+}
+
+// Shamelessly copied from JPilot (libplugin.c)
+static unsigned int bytes_to_bin(unsigned char *bytes, unsigned int num_bytes) {
+ unsigned int i, n;
+ n=0;
+ for (i=0;i<num_bytes;i++) {
+ n = n*256+bytes[i];
+ }
+ return n;
+}
+
+// Shamelessly copied from JPilot (utils.c)
+/*These next 2 functions were copied from pi-file.c in the pilot-link app */
+/* Exact value of "Jan 1, 1970 0:00:00 GMT" - "Jan 1, 1904 0:00:00 GMT" */
+#define PILOT_TIME_DELTA (unsigned)(2082844800)
+
+time_t pilot_time_to_unix_time ( unsigned long raw_time ) {
+ return (time_t)(raw_time - PILOT_TIME_DELTA);
+}
+
+// Shamelessly copied from JPilot (libplugin.c)
+static int raw_header_to_header(RawDBHeader *rdbh, DBHeader *dbh) {
+ unsigned long temp;
+ strncpy(dbh->db_name, rdbh->db_name, 31);
+ dbh->db_name[31] = '\0';
+ dbh->flags = bytes_to_bin(rdbh->flags, 2);
+ dbh->version = bytes_to_bin(rdbh->version, 2);
+ temp = bytes_to_bin(rdbh->creation_time, 4);
+ dbh->creation_time = pilot_time_to_unix_time(temp);
+ temp = bytes_to_bin(rdbh->modification_time, 4);
+ dbh->modification_time = pilot_time_to_unix_time(temp);
+ temp = bytes_to_bin(rdbh->backup_time, 4);
+ dbh->backup_time = pilot_time_to_unix_time(temp);
+ dbh->modification_number = bytes_to_bin(rdbh->modification_number, 4);
+ dbh->app_info_offset = bytes_to_bin(rdbh->app_info_offset, 4);
+ dbh->sort_info_offset = bytes_to_bin(rdbh->sort_info_offset, 4);
+ strncpy(dbh->type, rdbh->type, 4);
+ dbh->type[4] = '\0';
+ strncpy(dbh->creator_id, rdbh->creator_id, 4);
+ dbh->creator_id[4] = '\0';
+ strncpy(dbh->unique_id_seed, rdbh->unique_id_seed, 4);
+ dbh->unique_id_seed[4] = '\0';
+ dbh->next_record_list_id = bytes_to_bin(rdbh->next_record_list_id, 4);
+ dbh->number_of_records = bytes_to_bin(rdbh->number_of_records, 2);
+ return 0;
+}
+
+// Shamelessly copied from JPilot (libplugin.c)
+/*returns 1 if found */
+/* 0 if eof */
+static int find_next_offset( mem_rec_header *mem_rh, long fpos,
+ unsigned int *next_offset, unsigned char *attrib, unsigned int *unique_id )
+{
+ mem_rec_header *temp_mem_rh;
+ unsigned char found = 0;
+ unsigned long found_at;
+
+ found_at=0xFFFFFF;
+ for (temp_mem_rh=mem_rh; temp_mem_rh; temp_mem_rh = temp_mem_rh->next) {
+ if ((temp_mem_rh->offset > fpos) && (temp_mem_rh->offset < found_at)) {
+ found_at = temp_mem_rh->offset;
+ /* *attrib = temp_mem_rh->attrib; */
+ /* *unique_id = temp_mem_rh->unique_id; */
+ }
+ if ((temp_mem_rh->offset == fpos)) {
+ found = 1;
+ *attrib = temp_mem_rh->attrib;
+ *unique_id = temp_mem_rh->unique_id;
+ }
+ }
+ *next_offset = found_at;
+ return found;
+}
+
+// Shamelessly copied from JPilot (libplugin.c)
+static void free_mem_rec_header(mem_rec_header **mem_rh) {
+ mem_rec_header *h, *next_h;
+ for (h=*mem_rh; h; h=next_h) {
+ next_h=h->next;
+ free(h);
+ }
+ *mem_rh = NULL;
+}
+
+// Shamelessly copied from JPilot (libplugin.c)
+int jpilot_free_db_list( GList **br_list ) {
+ GList *temp_list, *first;
+ buf_rec *br;
+
+ /* Go to first entry in the list */
+ first=NULL;
+ for( temp_list = *br_list; temp_list; temp_list = temp_list->prev ) {
+ first = temp_list;
+ }
+ for (temp_list = first; temp_list; temp_list = temp_list->next) {
+ if (temp_list->data) {
+ br=temp_list->data;
+ if (br->buf) {
+ free(br->buf);
+ temp_list->data=NULL;
+ }
+ free(br);
+ }
+ }
+ g_list_free(*br_list);
+ *br_list=NULL;
+ return 0;
+}
+
+// Shamelessly copied from JPilot (libplugin.c)
+// Read file size.
+int jpilot_get_info_size( FILE *in, int *size ) {
+ RawDBHeader rdbh;
+ DBHeader dbh;
+ unsigned int offset;
+ record_header rh;
+
+ fseek(in, 0, SEEK_SET);
+ fread(&rdbh, sizeof(RawDBHeader), 1, in);
+ if (feof(in)) {
+ // fprintf( stderr, "error reading file in 'jpilot_get_info_size'\n" );
+ return MGU_EOF;
+ }
+
+ raw_header_to_header(&rdbh, &dbh);
+ if (dbh.app_info_offset==0) {
+ *size=0;
+ return MGU_SUCCESS;
+ }
+ if (dbh.sort_info_offset!=0) {
+ *size = dbh.sort_info_offset - dbh.app_info_offset;
+ return MGU_SUCCESS;
+ }
+ if (dbh.number_of_records==0) {
+ fseek(in, 0, SEEK_END);
+ *size=ftell(in) - dbh.app_info_offset;
+ return MGU_SUCCESS;
+ }
+
+ fread(&rh, sizeof(record_header), 1, in);
+ offset = ((rh.Offset[0]*256+rh.Offset[1])*256+rh.Offset[2])*256+rh.Offset[3];
+ *size=offset - dbh.app_info_offset;
+
+ return MGU_SUCCESS;
+}
+
+// Read address file into address list. Based on JPilot's
+// libplugin.c (jp_get_app_info)
+gint jpilot_get_file_info( JPilotFile *pilotFile, unsigned char **buf, int *buf_size ) {
+ FILE *in;
+ int num;
+ unsigned int rec_size;
+ RawDBHeader rdbh;
+ DBHeader dbh;
+
+ if( ( !buf_size ) || ( ! buf ) ) {
+ return MGU_BAD_ARGS;
+ }
+
+ *buf = NULL;
+ *buf_size=0;
+
+ if( pilotFile->path ) {
+ in = fopen( pilotFile->path, "r" );
+ if( !in ) {
+ // fprintf( stderr, "can't open %s\n", pilotFile->path );
+ return MGU_OPEN_FILE;
+ }
+ }
+ else {
+ // fprintf( stderr, "file not specified\n" );
+ return MGU_NO_FILE;
+ }
+
+ num = fread( &rdbh, sizeof( RawDBHeader ), 1, in );
+ if( num != 1 ) {
+ if( ferror(in) ) {
+ // fprintf( stderr, "error reading %s\n", pilotFile->path );
+ fclose(in);
+ return MGU_ERROR_READ;
+ }
+ }
+ if (feof(in)) {
+ fclose(in);
+ return MGU_EOF;
+ }
+
+ // Convert header into something recognizable
+ raw_header_to_header(&rdbh, &dbh);
+
+ num = jpilot_get_info_size(in, &rec_size);
+ if (num) {
+ fclose(in);
+ return MGU_ERROR_READ;
+ }
+
+ fseek(in, dbh.app_info_offset, SEEK_SET);
+ *buf = ( char * ) malloc(rec_size);
+ if (!(*buf)) {
+ // fprintf( stderr, "jpilot_get_file_info(): Out of memory\n" );
+ fclose(in);
+ return MGU_OO_MEMORY;
+ }
+ num = fread(*buf, rec_size, 1, in);
+ if (num != 1) {
+ if (ferror(in)) {
+ fclose(in);
+ free(*buf);
+ // fprintf( stderr, "Error reading %s\n", pilotFile->path );
+ return MGU_ERROR_READ;
+ }
+ }
+ fclose(in);
+
+ *buf_size = rec_size;
+
+ return MGU_SUCCESS;
+}
+
+#define FULLNAME_BUFSIZE 256
+#define EMAIL_BUFSIZE 256
+// Read address file into address cache. Based on JPilot's
+// jp_read_DB_files (from libplugin.c)
+gint jpilot_read_cache( JPilotFile *pilotFile ) {
+ FILE *in;
+ char *buf;
+ int num_records, recs_returned, i, num, r;
+ unsigned int offset, prev_offset, next_offset, rec_size;
+ int out_of_order;
+ long fpos; /*file position indicator */
+ unsigned char attrib;
+ unsigned int unique_id;
+ gint cat_id;
+ mem_rec_header *mem_rh, *temp_mem_rh, *last_mem_rh;
+ record_header rh;
+ RawDBHeader rdbh;
+ DBHeader dbh;
+ gint retVal;
+ struct Address addr;
+ struct AddressAppInfo *ai;
+ char **addrEnt;
+ int inum, k;
+ gchar fullName[ FULLNAME_BUFSIZE ];
+ gchar bufEMail[ EMAIL_BUFSIZE ];
+ gchar* extID;
+ AddressItem *addrItem = NULL;
+ int *indPhoneLbl;
+ char *labelEntry;
+ GSList *node;
+
+ retVal = MGU_SUCCESS;
+ mem_rh = last_mem_rh = NULL;
+ recs_returned = 0;
+
+ // Pointer to address metadata.
+ ai = & pilotFile->addrInfo;
+
+ // Open file for read
+ if( pilotFile->path ) {
+ in = fopen( pilotFile->path, "r" );
+ if( !in ) {
+ // fprintf( stderr, "can't open %s\n", pilotFile->path );
+ return MGU_OPEN_FILE;
+ }
+ }
+ else {
+ // fprintf( stderr, "file not specified\n" );
+ return MGU_NO_FILE;
+ }
+
+ /* Read the database header */
+ num = fread(&rdbh, sizeof(RawDBHeader), 1, in);
+ if (num != 1) {
+ if (ferror(in)) {
+ // fprintf( stderr, "error reading '%s'\n", pilotFile->path );
+ fclose(in);
+ return MGU_ERROR_READ;
+ }
+ if (feof(in)) {
+ return MGU_EOF;
+ }
+ }
+
+ raw_header_to_header(&rdbh, &dbh);
+
+ /*Read each record entry header */
+ num_records = dbh.number_of_records;
+ out_of_order = 0;
+ prev_offset = 0;
+
+ for (i=1; i<num_records+1; i++) {
+ num = fread( &rh, sizeof( record_header ), 1, in );
+ if (num != 1) {
+ if (ferror(in)) {
+ // fprintf( stderr, "error reading '%s'\n", pilotFile->path );
+ retVal = MGU_ERROR_READ;
+ break;
+ }
+ if (feof(in)) {
+ return MGU_EOF;
+ }
+ }
+
+ offset = ((rh.Offset[0]*256+rh.Offset[1])*256+rh.Offset[2])*256+rh.Offset[3];
+ if (offset < prev_offset) {
+ out_of_order = 1;
+ }
+ prev_offset = offset;
+
+ temp_mem_rh = (mem_rec_header *)malloc(sizeof(mem_rec_header));
+ if (!temp_mem_rh) {
+ // fprintf( stderr, "jpilot_read_db_file(): Out of memory 1\n" );
+ retVal = MGU_OO_MEMORY;
+ break;
+ }
+
+ temp_mem_rh->next = NULL;
+ temp_mem_rh->rec_num = i;
+ temp_mem_rh->offset = offset;
+ temp_mem_rh->attrib = rh.attrib;
+ temp_mem_rh->unique_id = (rh.unique_ID[0]*256+rh.unique_ID[1])*256+rh.unique_ID[2];
+
+ if (mem_rh == NULL) {
+ mem_rh = temp_mem_rh;
+ last_mem_rh = temp_mem_rh;
+ }
+ else {
+ last_mem_rh->next = temp_mem_rh;
+ last_mem_rh = temp_mem_rh;
+ }
+
+ } // for( ;; )
+
+ temp_mem_rh = mem_rh;
+
+ if (num_records) {
+ if (out_of_order) {
+ find_next_offset(mem_rh, 0, &next_offset, &attrib, &unique_id);
+ }
+ else {
+ if (mem_rh) {
+ next_offset = mem_rh->offset;
+ attrib = mem_rh->attrib;
+ unique_id = mem_rh->unique_id;
+ }
+ }
+ fseek(in, next_offset, SEEK_SET);
+
+ // Now go load all records
+ while(!feof(in)) {
+ struct CategoryAppInfo *cat = & ai->category;
+ fpos = ftell(in);
+ if (out_of_order) {
+ find_next_offset(mem_rh, fpos, &next_offset, &attrib, &unique_id);
+ }
+ else {
+ next_offset = 0xFFFFFF;
+ if (temp_mem_rh) {
+ attrib = temp_mem_rh->attrib;
+ unique_id = temp_mem_rh->unique_id;
+ cat_id = attrib & 0x0F;
+ if (temp_mem_rh->next) {
+ temp_mem_rh = temp_mem_rh->next;
+ next_offset = temp_mem_rh->offset;
+ }
+ }
+ }
+ rec_size = next_offset - fpos;
+
+ buf = ( char * ) malloc(rec_size);
+ if (!buf) break;
+ num = fread(buf, rec_size, 1, in);
+ if ((num != 1)) {
+ if (ferror(in)) {
+ // fprintf( stderr, "Error reading %s 5\n", pilotFile );
+ free(buf);
+ retVal = MGU_ERROR_READ;
+ break;
+ }
+ }
+
+ // Retrieve address
+ inum = unpack_Address( & addr, buf, rec_size );
+ if( inum > 0 ) {
+ addrEnt = addr.entry;
+
+ *fullName = *bufEMail = '\0';
+ if( addrEnt[ IND_LABEL_FIRSTNAME ] ) {
+ strcat( fullName, addrEnt[ IND_LABEL_FIRSTNAME ] );
+ }
+
+ if( addrEnt[ IND_LABEL_LASTNAME ] ) {
+ strcat( fullName, " " );
+ strcat( fullName, addrEnt[ IND_LABEL_LASTNAME ] );
+ }
+ g_strchug( fullName );
+ g_strchomp( fullName );
+ extID = g_strdup_printf( "%d", unique_id );
+
+ // Add entry for each email address listed under phone labels.
+ indPhoneLbl = addr.phoneLabel;
+ for( k = 0; k < JPILOT_NUM_ADDR_PHONE; k++ ) {
+ int ind;
+ ind = indPhoneLbl[k];
+ // fprintf( stdout, "%d : %d : %20s : %s\n", k, ind, ai->phoneLabels[ind], addrEnt[3+k] );
+ if( indPhoneLbl[k] == IND_PHONE_EMAIL ) {
+ labelEntry = addrEnt[ OFFSET_PHONE_LABEL + k ];
+ if( labelEntry ) {
+ strcpy( bufEMail, labelEntry );
+ g_strchug( bufEMail );
+ g_strchomp( bufEMail );
+
+ addrItem = mgu_create_address();
+ addrItem->name = g_strdup( fullName );
+ addrItem->address = g_strdup( bufEMail );
+ addrItem->remarks = g_strdup( "" );
+ addrItem->externalID = g_strdup( extID );
+ addrItem->categoryID = cat_id;
+ mgu_add_cache( pilotFile->addressCache, addrItem );
+ }
+ }
+ }
+
+ // Add entry for each custom label
+ node = pilotFile->labelInd;
+ while( node ) {
+ gint ind;
+ ind = GPOINTER_TO_INT( node->data );
+ if( ind > -1 ) {
+ // fprintf( stdout, "%d : %20s : %s\n", ind, ai->labels[ind], addrEnt[ind] );
+ labelEntry = addrEnt[ind];
+ if( labelEntry ) {
+ strcpy( bufEMail, labelEntry );
+ g_strchug( bufEMail );
+ g_strchomp( bufEMail );
+
+ addrItem = mgu_create_address();
+ addrItem->name = g_strdup( fullName );
+ addrItem->address = g_strdup( bufEMail );
+ addrItem->remarks = g_strdup( ai->labels[ind] );
+ addrItem->externalID = g_strdup( extID );
+ addrItem->categoryID = cat_id;
+ mgu_add_cache( pilotFile->addressCache, addrItem );
+ }
+
+ }
+
+ node = g_slist_next( node );
+ }
+
+ g_free( extID );
+ extID = NULL;
+ }
+ recs_returned++;
+ }
+ }
+ fclose(in);
+ free_mem_rec_header(&mem_rh);
+ return retVal;
+}
+
+/*
+* Read metadata from file.
+*/
+gint jpilot_read_metadata( JPilotFile *pilotFile ) {
+ gint retVal;
+ unsigned int rec_size;
+ unsigned char *buf;
+ int num;
+
+ g_return_if_fail( pilotFile != NULL );
+
+ pilotFile->readMetadata = FALSE;
+
+ // Read file info
+ retVal = jpilot_get_file_info( pilotFile, &buf, &rec_size);
+ if( retVal != MGU_SUCCESS ) {
+ pilotFile->retVal = retVal;
+ return pilotFile->retVal;
+ }
+
+ num = unpack_AddressAppInfo( &pilotFile->addrInfo, buf, rec_size );
+ if( buf ) {
+ free(buf);
+ }
+ if( num <= 0 ) {
+ // fprintf( stderr, "error reading '%s'\n", pilotFile->path );
+ pilotFile->retVal = MGU_ERROR_READ;
+ return pilotFile->retVal;
+ }
+
+ pilotFile->readMetadata = TRUE;
+ pilotFile->retVal = MGU_SUCCESS;
+ return pilotFile->retVal;
+}
+
+/*
+* Setup labels and indexes from metadata.
+* Return: TRUE is setup successfully.
+*/
+gboolean jpilot_setup_labels( JPilotFile *pilotFile ) {
+ gboolean retVal = FALSE;
+ struct AddressAppInfo *ai;
+ GSList *node;
+
+ g_return_if_fail( pilotFile != NULL );
+
+ // Release indexes
+ node = pilotFile->labelInd;
+ while( node ) {
+ node->data = NULL;
+ node = g_slist_next( node );
+ }
+ pilotFile->labelInd = NULL;
+
+ if( pilotFile->readMetadata ) {
+ ai = & pilotFile->addrInfo;
+ node = pilotFile->customLabels;
+ while( node ) {
+ gchar *lbl, *labelName;
+ int i;
+ gint ind;
+ ind = -1;
+ lbl = node->data;
+ for( i = 0; i < JPILOT_NUM_LABELS; i++ ) {
+ labelName = ai->labels[i];
+ if( g_strcasecmp( labelName, lbl ) == 0 ) {
+ ind = i;
+ break;
+ }
+ }
+ pilotFile->labelInd = g_slist_append( pilotFile->labelInd, GINT_TO_POINTER(ind) );
+ node = g_slist_next( node );
+ }
+ retVal = TRUE;
+ }
+ return retVal;
+}
+
+/*
+* Load list with character strings of label names.
+*/
+GSList *jpilot_load_label( JPilotFile *pilotFile, GSList *labelList ) {
+ int i;
+ g_return_if_fail( pilotFile != NULL );
+ if( pilotFile->readMetadata ) {
+ struct AddressAppInfo *ai = & pilotFile->addrInfo;
+ for( i = 0; i < JPILOT_NUM_LABELS; i++ ) {
+ gchar *labelName = ai->labels[i];
+ if( labelName ) {
+ labelList = g_slist_append( labelList, g_strdup( labelName ) );
+ }
+ else {
+ labelList = g_slist_append( labelList, g_strdup( "" ) );
+ }
+ }
+ }
+ return labelList;
+}
+
+/*
+* Return category name for specified category ID.
+* Enter: Category ID.
+* Return: Name, or empty string if not invalid ID. Name should be g_free() when done.
+*/
+gchar *jpilot_get_category_name( JPilotFile *pilotFile, gint catID ) {
+ gchar *catName = NULL;
+ g_return_if_fail( pilotFile != NULL );
+ if( pilotFile->readMetadata ) {
+ struct AddressAppInfo *ai = & pilotFile->addrInfo;
+ struct CategoryAppInfo *cat = & ai->category;
+ if( catID < 0 || catID > JPILOT_NUM_CATEG ) {
+ }
+ else {
+ catName = g_strdup( cat->name[catID] );
+ }
+ }
+ if( ! catName ) catName = g_strdup( "" );
+ return catName;
+}
+
+/*
+* Load list with character strings of phone label names.
+*/
+GSList *jpilot_load_phone_label( JPilotFile *pilotFile, GSList *labelList ) {
+ int i;
+ g_return_if_fail( pilotFile != NULL );
+ if( pilotFile->readMetadata ) {
+ struct AddressAppInfo *ai = & pilotFile->addrInfo;
+ for( i = 0; i < JPILOT_NUM_PHONELABELS; i++ ) {
+ gchar *labelName = ai->phoneLabels[i];
+ if( labelName ) {
+ labelList = g_slist_append( labelList, g_strdup( labelName ) );
+ }
+ else {
+ labelList = g_slist_append( labelList, g_strdup( "" ) );
+ }
+ }
+ }
+ return labelList;
+}
+
+/*
+* Load list with character strings of label names. Only none blank names
+* are loaded.
+*/
+GList *jpilot_load_custom_label( JPilotFile *pilotFile, GList *labelList ) {
+ int i;
+ g_return_if_fail( pilotFile != NULL );
+
+ if( pilotFile->readMetadata ) {
+ struct AddressAppInfo *ai = & pilotFile->addrInfo;
+ for( i = 0; i < NUM_CUSTOM_LABEL; i++ ) {
+ gchar *labelName = ai->labels[i+IND_CUSTOM_LABEL];
+ if( labelName ) {
+ g_strchomp( labelName );
+ g_strchug( labelName );
+ if( *labelName != '\0' ) {
+ labelList = g_list_append( labelList, g_strdup( labelName ) );
+ }
+ }
+ }
+ }
+ return labelList;
+}
+
+/*
+* Load list with character strings of category names.
+*/
+GSList *jpilot_get_category_list( JPilotFile *pilotFile ) {
+ GSList *catList = NULL;
+ int i;
+ g_return_if_fail( pilotFile != NULL );
+ if( pilotFile->readMetadata ) {
+ struct AddressAppInfo *ai = & pilotFile->addrInfo;
+ struct CategoryAppInfo *cat = & ai->category;
+ for( i = 0; i < JPILOT_NUM_CATEG; i++ ) {
+ gchar *catName = cat->name[i];
+ if( catName ) {
+ catList = g_slist_append( catList, g_strdup( catName ) );
+ }
+ else {
+ catList = g_slist_append( catList, g_strdup( "" ) );
+ }
+ }
+ }
+ return catList;
+}
+
+/*
+* Free category address list.
+*/
+void jpilot_free_address_list( JPilotFile *pilotFile ) {
+ GList *addrList;
+ g_return_if_fail( pilotFile != NULL );
+
+ addrList = pilotFile->catAddrList;
+ while( addrList ) {
+ JPilotCategory *jpcat = addrList->data;
+ mgu_free_address( jpcat->category );
+ mgu_free_address_list( jpcat->addressList );
+ jpcat->category = NULL;
+ jpcat->addressList = NULL;
+ jpcat->count = 0;
+ g_free( jpcat );
+ jpcat = NULL;
+ addrList->data = NULL;
+ addrList = g_list_next( addrList );
+ }
+ pilotFile->catAddrList = NULL;
+}
+
+/*
+* Move data from address list and group into category address list.
+*/
+void jpilot_load_category_items( JPilotFile *pilotFile ) {
+ JPilotCategory *jpcat[ 1 + JPILOT_NUM_CATEG ];
+ struct AddressAppInfo *ai = & pilotFile->addrInfo;
+ struct CategoryAppInfo *cat = & ai->category;
+ AddressItem *itemCat;
+ GList *addrList;
+ int i;
+
+ // Create array for data by category
+ for( i = 0; i < 1 + JPILOT_NUM_CATEG; i++ ) {
+ itemCat = mgu_create_address_item( ADDR_CATEGORY );
+ itemCat->categoryID = i;
+ jpcat[i] = g_new( JPilotCategory, 1 );
+ jpcat[i]->category = itemCat;
+ jpcat[i]->addressList = NULL;
+ jpcat[i]->count = 0;
+ if( i < JPILOT_NUM_CATEG ) {
+ gchar *catName = cat->name[i];
+ if( catName && strlen( catName ) > 0 ) {
+ itemCat->name = g_strdup( catName );
+ }
+ }
+ }
+
+ // Process address list moving data to category
+ addrList = pilotFile->addressCache->addressList;
+ while( addrList ) {
+ GList *addrLink;
+ AddressItem *item;
+ item = addrList->data;
+ i = item->categoryID;
+ if( i < 0 || i > JPILOT_NUM_CATEG ) i = JPILOT_NUM_CATEG; // Position at end of array
+
+ // Add item to category list
+ addrLink = jpcat[i]->addressList;
+ addrLink = g_list_append( addrLink, item );
+ jpcat[i]->addressList = addrLink;
+ jpcat[i]->count++;
+
+ // Clear from cache list
+ addrList->data = NULL;
+ addrList = g_list_next( addrList );
+ }
+
+ // Remove entries from address cache
+ mgu_clear_cache_null( pilotFile->addressCache );
+
+/*
+ printf( "dump jpcArray[]...\n" );
+ for( i = 0; i < 1 + JPILOT_NUM_CATEG; i++ ) {
+ jpilot_print_category( jpcat[i], stdout );
+ }
+*/
+
+ // Free up existing category address list
+ jpilot_free_address_list( pilotFile );
+
+ // Move categories from array to category address list
+ addrList = NULL;
+ for( i = 0; i < 1 + JPILOT_NUM_CATEG; i++ ) {
+ if( jpcat[i]->count > 0 ) {
+ itemCat = jpcat[i]->category;
+ if( ! itemCat->name ) {
+ // Create a category name
+ itemCat->name = g_strdup_printf( "? %d", itemCat->categoryID );
+ }
+ }
+ addrList = g_list_append( addrList, jpcat[i] );
+ jpcat[i] = NULL;
+ }
+ pilotFile->catAddrList = addrList;
+
+ // jpilot_print_category_list( pilotFile->catAddrList, stdout );
+
+}
+
+/*
+* Build linked list of address items for each category.
+*/
+GList *jpilot_build_category_list( JPilotFile *pilotFile ) {
+ GList *catList = NULL;
+ GList *node;
+ node = pilotFile->catAddrList;
+ while( node ) {
+ JPilotCategory *jpcat = node->data;
+ AddressItem *catItem = jpcat->category;
+
+ catItem = jpcat->category;
+ if( jpcat->count > 0 || catItem->name ) {
+ AddressItem *itemNew = mgu_copy_address_item( catItem );
+ if( itemNew ) {
+ catList = g_list_append( catList, itemNew );
+ }
+ }
+ node = g_list_next( node );
+ }
+ mgu_free_address_list( pilotFile->categoryList );
+ pilotFile->categoryList = catList;
+ // mgu_print_address_list( catList, stdout );
+ return catList;
+}
+
+// ============================================================================================
+/*
+* Read file into list. Main entry point
+* Return: TRUE if file read successfully.
+*/
+// ============================================================================================
+gint jpilot_read_data( JPilotFile *pilotFile ) {
+ g_return_if_fail( pilotFile != NULL );
+ pilotFile->retVal = MGU_SUCCESS;
+ if( mgu_check_file( pilotFile->addressCache, pilotFile->path ) ) {
+ mgu_clear_cache( pilotFile->addressCache );
+ jpilot_read_metadata( pilotFile );
+ if( pilotFile->retVal == MGU_SUCCESS ) {
+ jpilot_setup_labels( pilotFile );
+ pilotFile->retVal = jpilot_read_cache( pilotFile );
+ if( pilotFile->retVal == MGU_SUCCESS ) {
+ mgu_mark_cache( pilotFile->addressCache, pilotFile->path );
+ pilotFile->addressCache->modified = FALSE;
+ pilotFile->addressCache->dataRead = TRUE;
+ }
+ jpilot_load_category_items( pilotFile );
+ jpilot_build_category_list( pilotFile );
+ }
+ }
+ return pilotFile->retVal;
+}
+
+/*
+* Return linked list of address items for loaded category names.
+*/
+GList *jpilot_get_category_items( JPilotFile *pilotFile ) {
+ g_return_if_fail( pilotFile != NULL );
+ return pilotFile->categoryList;
+}
+
+/*
+* Return address list for specified category.
+*/
+GList *jpilot_get_address_list_cat( JPilotFile *pilotFile, const gint catID ) {
+ GList *addrList = NULL, *node;
+ g_return_if_fail( pilotFile != NULL );
+
+ node = pilotFile->catAddrList;
+ while( node ) {
+ JPilotCategory *jpcat = node->data;
+ AddressItem *catItem = jpcat->category;
+ if( catItem->categoryID == catID ) {
+ addrList = jpcat->addressList;
+ break;
+ }
+ node = g_list_next( node );
+ }
+ return addrList;
+}
+
+/*
+* Return linked list of address items.
+*/
+GList *jpilot_get_address_list( JPilotFile *pilotFile ) {
+ g_return_if_fail( pilotFile != NULL );
+ return pilotFile->addressCache->addressList;
+}
+
+/*
+* Check label list for specified label.
+*/
+gint jpilot_check_label( struct AddressAppInfo *ai, gchar *lblCheck ) {
+ int i;
+ gchar *lblName;
+ if( lblCheck == NULL ) return -1;
+ if( strlen( lblCheck ) < 1 ) return -1;
+ for( i = 0; i < JPILOT_NUM_LABELS; i++ ) {
+ lblName = ai->labels[i];
+ if( lblName ) {
+ if( strlen( lblName ) ) {
+ if( g_strcasecmp( lblName, lblCheck ) == 0 ) return i;
+ }
+ }
+ }
+ return -2;
+}
+
+/*
+* Validate that all parameters specified.
+* Return: TRUE if data is good.
+*/
+gboolean jpilot_validate( const JPilotFile *pilotFile ) {
+ gboolean retVal;
+ g_return_if_fail( pilotFile != NULL );
+
+ retVal = TRUE;
+ if( pilotFile->path ) {
+ if( strlen( pilotFile->path ) < 1 ) retVal = FALSE;
+ }
+ else {
+ retVal = FALSE;
+ }
+ if( pilotFile->name ) {
+ if( strlen( pilotFile->name ) < 1 ) retVal = FALSE;
+ }
+ else {
+ retVal = FALSE;
+ }
+ return retVal;
+}
+
+#define WORK_BUFLEN 1024
+
+/*
+* Attempt to find a valid JPilot file.
+* Return: Filename, or home directory if not found, or empty string if
+* no home. Filename should be g_free() when done.
+*/
+gchar *jpilot_find_pilotdb( void ) {
+ gchar *homedir;
+ gchar str[ WORK_BUFLEN ];
+ gint len;
+ FILE *fp;
+
+ homedir = g_get_home_dir();
+ if( ! homedir ) return g_strdup( "" );
+
+ strcpy( str, homedir );
+ len = strlen( str );
+ if( len > 0 ) {
+ if( str[ len-1 ] != G_DIR_SEPARATOR ) {
+ str[ len ] = G_DIR_SEPARATOR;
+ str[ ++len ] = '\0';
+ }
+ }
+ strcat( str, JPILOT_DBHOME_DIR );
+ strcat( str, G_DIR_SEPARATOR_S );
+ strcat( str, JPILOT_DBHOME_FILE );
+
+ // Attempt to open\e
+ if( ( fp = fopen( str, "r" ) ) != NULL ) {
+ fclose( fp );
+ }
+ else {
+ // Truncate filename
+ str[ len ] = '\0';
+ }
+ return g_strdup( str );
+}
+
+/*
+* Attempt to read file, testing for valid JPilot format.
+* Return: TRUE if file appears to be valid format.
+*/
+gint jpilot_test_read_file( const gchar *fileSpec ) {
+ JPilotFile *pilotFile;
+ gint retVal;
+ if( fileSpec ) {
+ pilotFile = jpilot_create_path( fileSpec );
+ retVal = jpilot_read_metadata( pilotFile );
+ jpilot_free( pilotFile );
+ pilotFile = NULL;
+ }
+ else {
+ retVal = MGU_NO_FILE;
+ }
+ return retVal;
+}
+
+/*
+* Check whether label is in custom labels.
+* Return: TRUE if found.
+*/
+gboolean jpilot_test_custom_label( JPilotFile *pilotFile, const gchar *labelName ) {
+ gboolean retVal;
+ GSList *node;
+ g_return_if_fail( pilotFile != NULL );
+
+ retVal = FALSE;
+ if( labelName ) {
+ node = pilotFile->customLabels;
+ while( node ) {
+ if( g_strcasecmp( labelName, node->data ) == 0 ) {
+ retVal = TRUE;
+ break;
+ }
+ node = g_slist_next( node );
+ }
+ }
+ return retVal;
+}
+
+/*
+* Test whether pilot link library installed.
+* Return: TRUE if library available.
+*/
+gboolean jpilot_test_pilot_lib() {
+ void *handle, *fun;
+
+ handle = dlopen( PILOT_LINK_LIB_NAME, RTLD_LAZY );
+ if( ! handle ) {
+ return FALSE;
+ }
+
+ // Test for symbols we need
+ fun = dlsym( handle, "unpack_Address" );
+ if( ! fun ) {
+ dlclose( handle );
+ return FALSE;
+ }
+
+ fun = dlsym( handle, "unpack_AddressAppInfo" );
+ if( ! fun ) {
+ dlclose( handle );
+ return FALSE;
+ }
+ dlclose( handle );
+ return TRUE;
+}
+
+#endif /* USE_JPILOT */
+
+/*
+* End of Source.
+*/
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * Definitions for accessing JPilot database files.
+ * JPilot is Copyright(c) by Judd Montgomery.
+ * Visit http://www.jpilot.org for more details.
+ */
+
+#ifndef __JPILOT_H__
+#define __JPILOT_H__
+
+#ifdef USE_JPILOT
+
+#include <pi-address.h>
+
+#include <time.h>
+#include <stdio.h>
+#include <glib.h>
+
+#include "mgutils.h"
+
+typedef struct _JPilotFile JPilotFile;
+
+struct _JPilotFile {
+ gchar *name;
+ FILE *file;
+ gchar *path;
+ AddressCache *addressCache;
+ struct AddressAppInfo addrInfo;
+ gboolean readMetadata;
+ GSList *customLabels;
+ GSList *labelInd;
+ gint retVal;
+ GList *categoryList;
+ GList *catAddrList;
+};
+
+// Limits
+#define JPILOT_NUM_LABELS 22 // Number of labels
+#define JPILOT_NUM_PHONELABELS 8 // Number of phone number labels
+#define JPILOT_NUM_CATEG 16 // Number of categories
+#define JPILOT_LEN_LABEL 15 // Max length of label
+#define JPILOT_LEN_CATEG 15 // Max length of category
+#define JPILOT_NUM_ADDR_PHONE 5 // Number of phone entries a person can have
+
+// Shamelessly copied from JPilot (libplugin.h)
+typedef struct {
+ unsigned char db_name[32];
+ unsigned char flags[2];
+ unsigned char version[2];
+ unsigned char creation_time[4];
+ unsigned char modification_time[4];
+ unsigned char backup_time[4];
+ unsigned char modification_number[4];
+ unsigned char app_info_offset[4];
+ unsigned char sort_info_offset[4];
+ unsigned char type[4];/*Database ID */
+ unsigned char creator_id[4];/*Application ID */
+ unsigned char unique_id_seed[4];
+ unsigned char next_record_list_id[4];
+ unsigned char number_of_records[2];
+} RawDBHeader;
+
+// Shamelessly copied from JPilot (libplugin.h)
+typedef struct {
+ char db_name[32];
+ unsigned int flags;
+ unsigned int version;
+ time_t creation_time;
+ time_t modification_time;
+ time_t backup_time;
+ unsigned int modification_number;
+ unsigned int app_info_offset;
+ unsigned int sort_info_offset;
+ char type[5];/*Database ID */
+ char creator_id[5];/*Application ID */
+ char unique_id_seed[5];
+ unsigned int next_record_list_id;
+ unsigned int number_of_records;
+} DBHeader;
+
+// Shamelessly copied from JPilot (libplugin.h)
+typedef struct {
+ unsigned char Offset[4]; /*4 bytes offset from BOF to record */
+ unsigned char attrib;
+ unsigned char unique_ID[3];
+} record_header;
+
+// Shamelessly copied from JPilot (libplugin.h)
+typedef struct mem_rec_header_s {
+ unsigned int rec_num;
+ unsigned int offset;
+ unsigned int unique_id;
+ unsigned char attrib;
+ struct mem_rec_header_s *next;
+} mem_rec_header;
+
+// Shamelessly copied from JPilot (libplugin.h)
+#define SPENT_PC_RECORD_BIT 256
+
+typedef enum {
+ PALM_REC = 100L,
+ MODIFIED_PALM_REC = 101L,
+ DELETED_PALM_REC = 102L,
+ NEW_PC_REC = 103L,
+ DELETED_PC_REC = SPENT_PC_RECORD_BIT + 104L,
+ DELETED_DELETED_PALM_REC = SPENT_PC_RECORD_BIT + 105L
+} PCRecType;
+
+// Shamelessly copied from JPilot (libplugin.h)
+typedef struct {
+ PCRecType rt;
+ unsigned int unique_id;
+ unsigned char attrib;
+ void *buf;
+ int size;
+} buf_rec;
+
+/* Function prototypes */
+JPilotFile *jpilot_create();
+JPilotFile *jpilot_create_path( const gchar *path );
+void jpilot_free( JPilotFile *pilotFile );
+void jpilot_force_refresh( JPilotFile *pilotFile );
+gboolean jpilot_get_modified( JPilotFile *pilotFile );
+void jpilot_print_file( JPilotFile *jpilotFile, FILE *stream );
+void jpilot_print_list( GSList *list, FILE *stream );
+gint jpilot_read_file( JPilotFile *pilotFile );
+
+GList *jpilot_get_address_list( JPilotFile *pilotFile );
+GSList *jpilot_load_label( JPilotFile *pilotFile, GSList *labelList );
+GSList *jpilot_get_category_list( JPilotFile *pilotFile );
+gchar *jpilot_get_category_name( JPilotFile *pilotFile, gint catID );
+GSList *jpilot_load_phone_label( JPilotFile *pilotFile, GSList *labelList );
+GList *jpilot_load_custom_label( JPilotFile *pilotFile, GList *labelList );
+
+GList *jpilot_get_category_items( JPilotFile *pilotFile );
+GList *jpilot_get_address_list_cat( JPilotFile *pilotFile, const gint catID );
+
+void jpilot_set_file( JPilotFile* pilotFile, const gchar *path );
+gboolean jpilot_validate( const JPilotFile *pilotFile );
+gchar *jpilot_find_pilotdb( void );
+gint jpilot_test_read_data( const gchar *fileSpec );
+
+void jpilot_clear_custom_labels( JPilotFile *pilotFile );
+void jpilot_add_custom_label( JPilotFile *pilotFile, const gchar *labelName );
+GList *jpilot_get_custom_labels( JPilotFile *pilotFile );
+gboolean jpilot_test_custom_label( JPilotFile *pilotFile, const gchar *labelName );
+gboolean jpilot_setup_labels( JPilotFile *pilotFile );
+gboolean jpilot_test_pilot_lib();
+
+#endif /* USE_JPILOT */
+
+#endif /* __JPILOT_H__ */
+
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * General functions for create common address book entries.
+ */
+
+#include <sys/stat.h>
+#include <stdio.h>
+#include <glib.h>
+
+#include "addressitem.h"
+#include "mgutils.h"
+
+/*
+* Create new address item.
+*/
+AddressItem *mgu_create_address_item( AddressObjectType type ) {
+ AddressItem *item;
+ item = g_new( AddressItem, 1 );
+ ADDRESS_OBJECT(item)->type = type;
+ item->name = NULL;
+ item->address = NULL;
+ item->remarks = NULL;
+ item->externalID = NULL;
+ item->categoryID = ADDRESS_ITEM_CAT_UNKNOWN;
+ return item;
+}
+
+/*
+* Create new address item.
+*/
+AddressItem *mgu_create_address( void ) {
+ AddressItem *item;
+ item = g_new( AddressItem, 1 );
+ ADDRESS_OBJECT(item)->type = ADDR_ITEM;
+ item->name = NULL;
+ item->address = NULL;
+ item->remarks = NULL;
+ item->externalID = NULL;
+ item->categoryID = ADDRESS_ITEM_CAT_UNKNOWN;
+ return item;
+}
+
+/*
+* Create copy of specified address item.
+*/
+AddressItem *mgu_copy_address_item( AddressItem *item ) {
+ AddressItem *itemNew = NULL;
+ if( item ) {
+ itemNew = mgu_create_address_item( ADDRESS_OBJECT(item)->type );
+ itemNew->name = g_strdup( item->name );
+ itemNew->address = g_strdup( item->address );
+ itemNew->remarks = g_strdup( item->remarks );
+ itemNew->externalID = g_strdup( item->externalID );
+ itemNew->categoryID = item->categoryID;
+ }
+ return itemNew;
+}
+
+/*
+* Free address item.
+*/
+void mgu_free_address( AddressItem *item ) {
+ g_return_if_fail( item != NULL );
+
+ /* Free internal stuff */
+ g_free( item->name );
+ g_free( item->address );
+ g_free( item->remarks );
+ g_free( item->externalID );
+ item->name = NULL;
+ item->address = NULL;
+ item->remarks = NULL;
+ item->externalID = NULL;
+ item->categoryID = ADDRESS_ITEM_CAT_UNKNOWN;
+
+ /* Now release item */
+ g_free( item );
+}
+
+/*
+* Refresh internal variables to force a reload.
+*/
+void mgu_refresh_cache( AddressCache *cache ) {
+ cache->dataRead = FALSE;
+ cache->modified = TRUE;
+ cache->modifyTime = 0;
+}
+
+/*
+* Free up address list.
+*/
+void mgu_free_address_list( GList *addrList ) {
+ AddressItem *item;
+ GList *node;
+
+ /* Free data in the list */
+ node = addrList;
+ while( node ) {
+ item = node->data;
+ mgu_free_address( item );
+ node->data = NULL;
+ node = g_list_next( node );
+ }
+
+ /* Now release linked list object */
+ g_list_free( addrList );
+}
+
+/*
+* Clear the cache.
+*/
+void mgu_clear_cache( AddressCache *cache ) {
+ AddressItem *item;
+ GList *node;
+ g_return_if_fail( cache != NULL );
+
+ /* Free data in the list */
+ mgu_free_address_list( cache->addressList );
+ cache->addressList = NULL;
+ mgu_refresh_cache( cache );
+}
+
+/*
+* Clear the cache by setting pointers to NULL and free list.
+* Note that individual items are not free'd.
+*/
+void mgu_clear_cache_null( AddressCache *cache ) {
+ GList *node;
+ g_return_if_fail( cache != NULL );
+
+ /* Free data in the list */
+ node = cache->addressList;
+ while( node ) {
+ node->data = NULL;
+ node = g_list_next( node );
+ }
+
+ /* Now release linked list object */
+ g_list_free( cache->addressList );
+ cache->addressList = NULL;
+}
+
+/*
+* Create new cache.
+*/
+AddressCache *mgu_create_cache( void ) {
+ AddressCache *cache;
+ cache = g_new( AddressCache, 1 );
+ cache->addressList = NULL;
+ cache->dataRead = FALSE;
+ cache->modified = FALSE;
+ cache->modifyTime = 0;
+ return cache;
+}
+
+/*
+* Create new address item.
+*/
+void mgu_free_cache( AddressCache *cache ) {
+ mgu_clear_cache( cache );
+ cache->addressList = NULL;
+}
+
+/*
+* Print address item.
+*/
+void mgu_print_address( AddressItem *item, FILE *stream ) {
+ g_return_if_fail( item != NULL );
+ fprintf( stream, "addr item:\n" );
+ fprintf( stream, "\tname: '%s'\n", item->name );
+ fprintf( stream, "\taddr: '%s'\n", item->address );
+ fprintf( stream, "\trems: '%s'\n", item->remarks );
+ fprintf( stream, "\tid : '%s'\n", item->externalID );
+ fprintf( stream, "\tcatg: '%d'\n", item->categoryID );
+ fprintf( stream, "---\n" );
+}
+
+/*
+* Print linked list containing address item(s).
+*/
+void mgu_print_address_list( GList *addrList, FILE *stream ) {
+ GList *node;
+ g_return_if_fail( addrList != NULL );
+
+ /* Now process the list */
+ node = addrList;
+ while( node ) {
+ gpointer *gptr = node->data;
+ AddressItem *item = ( AddressItem * ) gptr;
+ mgu_print_address( item, stream );
+ node = g_list_next( node );
+ }
+}
+
+/*
+* Print address cache.
+*/
+void mgu_print_cache( AddressCache *cache, FILE *stream ) {
+ GList *node;
+ g_return_if_fail( cache != NULL );
+ fprintf( stream, "AddressCache:\n" );
+ fprintf( stream, "modified : %s\n", cache->modified ? "yes" : "no" );
+ fprintf( stream, "data read: %s\n", cache->dataRead ? "yes" : "no" );
+
+ /* Now process the list */
+ node = cache->addressList;
+ while( node ) {
+ gpointer *gptr;
+ AddressItem *item;
+ gptr = node->data;
+ item = ( AddressItem * ) gptr;
+ mgu_print_address( item, stream );
+ node = g_list_next( node );
+ }
+}
+
+/*
+* Dump linked list of character strings (for debug).
+*/
+void mgu_print_list( GSList *list, FILE *stream ) {
+ GSList *node = list;
+ while( node ) {
+ fprintf( stream, "\t- >%s<\n", node->data );
+ node = g_slist_next( node );
+ }
+}
+
+/*
+* Dump linked list of character strings (for debug).
+*/
+void mgu_print_dlist( GList *list, FILE *stream ) {
+ GList *node = list;
+ while( node ) {
+ fprintf( stream, "\t- >%s<\n", node->data );
+ node = g_list_next( node );
+ }
+}
+
+/*
+* Check whether file has changed by comparing with cache.
+* return: TRUE if file has changed.
+*/
+gboolean mgu_check_file( AddressCache *cache, gchar *path ) {
+ gboolean retVal;
+ struct stat filestat;
+ retVal = TRUE;
+ if( path ) {
+ if( 0 == lstat( path, &filestat ) ) {
+ if( filestat.st_mtime == cache->modifyTime ) retVal = FALSE;
+ }
+ }
+ return retVal;
+}
+
+/*
+* Save file time to cache.
+* return: TRUE if time marked.
+*/
+gboolean mgu_mark_cache( AddressCache *cache, gchar *path ) {
+ gboolean retVal = FALSE;
+ struct stat filestat;
+ if( path ) {
+ if( 0 == lstat( path, &filestat ) ) {
+ cache->modifyTime = filestat.st_mtime;
+ retVal = TRUE;
+ }
+ }
+ return retVal;
+}
+
+/*
+* Free linked list of character strings.
+*/
+void mgu_free_list( GSList *list ) {
+ GSList *node = list;
+ while( node ) {
+ g_free( node->data );
+ node->data = NULL;
+ node = g_slist_next( node );
+ }
+ g_slist_free( list );
+}
+
+/*
+* Free linked list of character strings.
+*/
+void mgu_free_dlist( GList *list ) {
+ GList *node = list;
+ while( node ) {
+ g_free( node->data );
+ node->data = NULL;
+ node = g_list_next( node );
+ }
+ g_list_free( list );
+}
+
+/*
+* Coalesce linked list of characaters into one long string.
+*/
+gchar *mgu_list_coalesce( GSList *list ) {
+ gchar *str = NULL;
+ gchar *buf = NULL;
+ gchar *start = NULL;
+ GSList *node = NULL;
+ gint len;
+
+ if( ! list ) return NULL;
+
+ // Calculate maximum length of text
+ len = 0;
+ node = list;
+ while( node ) {
+ str = node->data;
+ len += 1 + strlen( str );
+ node = g_slist_next( node );
+ }
+
+ // Create new buffer.
+ buf = g_new( gchar, len+1 );
+ start = buf;
+ node = list;
+ while( node ) {
+ str = node->data;
+ len = strlen( str );
+ strcpy( start, str );
+ start += len;
+ node = g_slist_next( node );
+ }
+ return buf;
+}
+
+/*
+* Add address item to cache.
+*/
+void mgu_add_cache( AddressCache *cache, AddressItem *addrItem ) {
+ cache->addressList = g_list_append( cache->addressList, addrItem );
+ cache->modified = TRUE;
+}
+
+struct mgu_error_entry {
+ gint e_code;
+ gchar *e_reason;
+};
+
+static const struct mgu_error_entry mgu_error_list[] = {
+ { MGU_SUCCESS, "Success" },
+ { MGU_BAD_ARGS, "Bad arguments" },
+ { MGU_NO_FILE, "File not specified" },
+ { MGU_OPEN_FILE, "Error opening file" },
+ { MGU_ERROR_READ, "Error reading file" },
+ { MGU_EOF, "End of file encountered" },
+ { MGU_OO_MEMORY, "Error allocating memory" },
+ { MGU_BAD_FORMAT, "Bad file format" },
+ { MGU_LDAP_CONNECT, "Error connecting to LDAP server" },
+ { MGU_LDAP_INIT, "Error initializing LDAP" },
+ { MGU_LDAP_BIND, "Error binding to LDAP server" },
+ { MGU_LDAP_SEARCH, "Error searching LDAP database" },
+ { MGU_LDAP_TIMEOUT, "Timeout performing LDAP operation" },
+ { MGU_LDAP_CRITERIA, "Error in LDAP search criteria" },
+ { MGU_LDAP_CRITERIA, "Error in LDAP search criteria" },
+ { MGU_LDAP_NOENTRIES, "No LDAP entries found for search criteria" },
+ { -999, NULL }
+};
+
+static const struct mgu_error_entry *mgu_error_find( gint err ) {
+ gint i;
+ for ( i = 0; mgu_error_list[i].e_code != -999; i++ ) {
+ if ( err == mgu_error_list[i].e_code )
+ return & mgu_error_list[i];
+ }
+ return NULL;
+}
+
+/*
+* Return error message for specified error code.
+*/
+gchar *mgu_error2string( gint err ) {
+ const struct mgu_error_entry *e;
+ e = mgu_error_find( err );
+ return ( e != NULL ) ? e->e_reason : "Unknown error";
+}
+
+/*
+* End of Source.
+*/
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * General definitions for common address book entries.
+ */
+
+#ifndef __MGUTILS_H__
+#define __MGUTILS_H__
+
+#include <time.h>
+#include <stdio.h>
+#include <glib.h>
+
+#include "addressitem.h"
+
+// Error codes
+#define MGU_SUCCESS 0
+#define MGU_BAD_ARGS -1
+#define MGU_NO_FILE -2
+#define MGU_OPEN_FILE -3
+#define MGU_ERROR_READ -4
+#define MGU_EOF -5
+#define MGU_OO_MEMORY -6
+#define MGU_BAD_FORMAT -7
+#define MGU_LDAP_CONNECT -8
+#define MGU_LDAP_INIT -9
+#define MGU_LDAP_BIND -10
+#define MGU_LDAP_SEARCH -11
+#define MGU_LDAP_TIMEOUT -12
+#define MGU_LDAP_CRITERIA -13
+#define MGU_LDAP_NOENTRIES -14
+
+// Address cache
+typedef struct _AddressCache AddressCache;
+struct _AddressCache {
+ GList *addressList;
+ gboolean dataRead;
+ gboolean modified;
+ time_t modifyTime;
+};
+
+// Function prototypes
+AddressItem *mgu_create_address_item( AddressObjectType type );
+AddressItem *mgu_create_address( void );
+AddressItem *mgu_copy_address_item( AddressItem *item );
+void mgu_free_address( AddressItem *item );
+void mgu_free_address_list( GList *addrList );
+void mgu_refresh_cache( AddressCache *cache );
+void mgu_clear_cache( AddressCache *cache );
+void mgu_clear_cache_null( AddressCache *cache );
+AddressCache *mgu_create_cache( void );
+void mgu_free_cache( AddressCache *cache );
+void mgu_print_address( AddressItem *item, FILE *stream );
+void mgu_print_address_list( GList *addrList, FILE *stream );
+void mgu_print_cache( AddressCache *cache, FILE *stream );
+void mgu_print_list( GSList *list, FILE *stream );
+void mgu_print_dlist( GList *list, FILE *stream );
+gboolean mgu_check_file( AddressCache *cache, gchar *path );
+gboolean mgu_mark_cache( AddressCache *cache, gchar *path );
+void mgu_free_list( GSList *list );
+void mgu_free_dlist( GList *list );
+gchar *mgu_list_coalesce( GSList *list );
+void mgu_add_cache( AddressCache *cache, AddressItem *addrItem );
+gchar *mgu_error2string( gint err );
+
+#endif /* __MGUTILS_H__ */
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * Functions necessary to access LDAP servers.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef USE_LDAP
+
+#include <sys/time.h>
+#include <glib.h>
+#include <ldap.h>
+#include <lber.h>
+#include <pthread.h>
+#include <dlfcn.h>
+
+#include "mgutils.h"
+#include "syldap.h"
+
+/*
+* Specify name to be used.
+*/
+void syldap_set_name( SyldapServer* ldapServer, const gchar *value ) {
+ if( ldapServer->name ) g_free( ldapServer->name );
+ if( value ) ldapServer->name = g_strdup( value );
+ g_strstrip( ldapServer->name );
+}
+
+/*
+* Specify hostname to be used.
+*/
+void syldap_set_host( SyldapServer* ldapServer, const gchar *value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+
+ if( ldapServer->hostName ) g_free( ldapServer->hostName );
+ if( value ) ldapServer->hostName = g_strdup( value );
+ g_strstrip( ldapServer->hostName );
+}
+
+/*
+* Specify port to be used.
+*/
+void syldap_set_port( SyldapServer* ldapServer, const gint value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+
+ if( value > 0 ) {
+ ldapServer->port = value;
+ }
+ else {
+ ldapServer->port = SYLDAP_DFL_PORT;
+ }
+}
+
+/*
+* Specify base DN to be used.
+*/
+void syldap_set_base_dn( SyldapServer* ldapServer, const gchar *value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+
+ if( ldapServer->baseDN ) g_free( ldapServer->baseDN );
+ if( value ) ldapServer->baseDN = g_strdup( value );
+ g_strstrip( ldapServer->baseDN );
+}
+
+/*
+* Specify bind DN to be used.
+*/
+void syldap_set_bind_dn( SyldapServer* ldapServer, const gchar *value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+
+ if( ldapServer->bindDN ) g_free( ldapServer->bindDN );
+ if( value ) ldapServer->bindDN = g_strdup( value );
+ g_strstrip( ldapServer->bindDN );
+}
+
+/*
+* Specify bind password to be used.
+*/
+void syldap_set_bind_password( SyldapServer* ldapServer, const gchar *value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+
+ if( ldapServer->bindPass ) g_free( ldapServer->bindPass );
+ if( value ) ldapServer->bindPass = g_strdup( value );
+ g_strstrip( ldapServer->bindPass );
+}
+
+/*
+* Specify search criteria to be used.
+*/
+void syldap_set_search_criteria( SyldapServer* ldapServer, const gchar *value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+
+ if( ldapServer->searchCriteria ) g_free( ldapServer->searchCriteria );
+ if( value ) ldapServer->searchCriteria = g_strdup( value );
+ g_strstrip( ldapServer->searchCriteria );
+ ldapServer->newSearch = TRUE;
+}
+
+/*
+* Specify search value to be searched for.
+*/
+void syldap_set_search_value( SyldapServer* ldapServer, const gchar *value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+
+ if( ldapServer->searchValue ) g_free( ldapServer->searchValue );
+ if( value ) ldapServer->searchValue = g_strdup( value );
+ g_strstrip( ldapServer->searchValue );
+ ldapServer->newSearch = TRUE;
+}
+
+/*
+* Specify maximum number of entries to retrieve.
+*/
+void syldap_set_max_entries( SyldapServer* ldapServer, const gint value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+ if( value > 0 ) {
+ ldapServer->maxEntries = value;
+ }
+ else {
+ ldapServer->maxEntries = SYLDAP_MAX_ENTRIES;
+ }
+}
+
+/*
+* Specify timeout value for LDAP operation (in seconds).
+*/
+void syldap_set_timeout( SyldapServer* ldapServer, const gint value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+ if( value > 0 ) {
+ ldapServer->timeOut = value;
+ }
+ else {
+ ldapServer->timeOut = SYLDAP_DFL_TIMEOUT;
+ }
+}
+
+/*
+* Register a callback function. When called, the function will be passed
+* this object as an argument.
+*/
+void syldap_set_callback( SyldapServer *ldapServer, void *func ) {
+ ldapServer->callBack = func;
+}
+
+/*
+* Create new LDAP server interface object.
+*/
+SyldapServer *syldap_create() {
+ SyldapServer *ldapServer;
+ ldapServer = g_new( SyldapServer, 1 );
+ ldapServer->name = NULL;
+ ldapServer->hostName = NULL;
+ ldapServer->port = SYLDAP_DFL_PORT;
+ ldapServer->baseDN = NULL;
+ ldapServer->bindDN = NULL;
+ ldapServer->bindPass = NULL;
+ ldapServer->searchCriteria = NULL;
+ ldapServer->searchValue = NULL;
+ ldapServer->entriesRead = 0;
+ ldapServer->maxEntries = SYLDAP_MAX_ENTRIES;
+ ldapServer->timeOut = SYLDAP_DFL_TIMEOUT;
+ ldapServer->newSearch = TRUE;
+ ldapServer->addressCache = mgu_create_cache();
+ ldapServer->thread = NULL;
+ ldapServer->busyFlag = FALSE;
+ ldapServer->retVal = MGU_SUCCESS;
+ ldapServer->callBack = NULL;
+ return ldapServer;
+}
+
+/*
+* Refresh internal variables to force a file read.
+*/
+void syldap_force_refresh( SyldapServer *ldapServer ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+ ldapServer->newSearch = TRUE;
+}
+
+/*
+* Free up LDAP server interface object by releasing internal memory.
+*/
+void syldap_free( SyldapServer *ldapServer ) {
+ g_return_if_fail( ldapServer != NULL );
+
+ ldapServer->callBack = NULL;
+ // fprintf( stdout, "freeing... SyldapServer\n" );
+
+ /* Free internal stuff */
+ g_free( ldapServer->name );
+ g_free( ldapServer->hostName );
+ g_free( ldapServer->baseDN );
+ g_free( ldapServer->bindDN );
+ g_free( ldapServer->bindPass );
+ g_free( ldapServer->searchCriteria );
+ g_free( ldapServer->searchValue );
+
+ ldapServer->port = 0;
+ ldapServer->entriesRead = 0;
+ ldapServer->maxEntries = 0;
+ ldapServer->newSearch = FALSE;
+
+ /* Clear cache */
+ mgu_clear_cache( ldapServer->addressCache );
+ mgu_free_cache( ldapServer->addressCache );
+
+ // Clear pointers
+ ldapServer->name = NULL;
+ ldapServer->hostName = NULL;
+ ldapServer->baseDN = NULL;
+ ldapServer->bindDN = NULL;
+ ldapServer->bindPass = NULL;
+ ldapServer->searchCriteria = NULL;
+ ldapServer->searchValue = NULL;
+ ldapServer->addressCache = NULL;
+ ldapServer->thread = NULL;
+ ldapServer->busyFlag = FALSE;
+ ldapServer->retVal = MGU_SUCCESS;
+
+ /* Now release file object */
+ g_free( ldapServer );
+
+ // fprintf( stdout, "freeing... SyldapServer done\n" );
+
+}
+
+/*
+* Display object to specified stream.
+*/
+void syldap_print_data( SyldapServer *ldapServer, FILE *stream ) {
+ GSList *node;
+ g_return_if_fail( ldapServer != NULL );
+ fprintf( stream, "SyldapServer:\n" );
+ fprintf( stream, " name: '%s'\n", ldapServer->name );
+ fprintf( stream, "host name: '%s'\n", ldapServer->hostName );
+ fprintf( stream, " port: %d\n", ldapServer->port );
+ fprintf( stream, " base dn: '%s'\n", ldapServer->baseDN );
+ fprintf( stream, " bind dn: '%s'\n", ldapServer->bindDN );
+ fprintf( stream, "bind pass: '%s'\n", ldapServer->bindPass );
+ fprintf( stream, " criteria: '%s'\n", ldapServer->searchCriteria );
+ fprintf( stream, "searchval: '%s'\n", ldapServer->searchValue );
+ fprintf( stream, "max entry: %d\n", ldapServer->maxEntries );
+ fprintf( stream, " num read: %d\n", ldapServer->entriesRead );
+ fprintf( stream, " ret val: %d\n", ldapServer->retVal );
+ mgu_print_cache( ldapServer->addressCache, stream );
+}
+
+/*
+* Display object to specified stream.
+*/
+void syldap_print_short( SyldapServer *ldapServer, FILE *stream ) {
+ GSList *node;
+ g_return_if_fail( ldapServer != NULL );
+ fprintf( stream, "SyldapServer:\n" );
+ fprintf( stream, " name: '%s'\n", ldapServer->name );
+ fprintf( stream, "host name: '%s'\n", ldapServer->hostName );
+ fprintf( stream, " port: %d\n", ldapServer->port );
+ fprintf( stream, " base dn: '%s'\n", ldapServer->baseDN );
+ fprintf( stream, " bind dn: '%s'\n", ldapServer->bindDN );
+ fprintf( stream, "bind pass: '%s'\n", ldapServer->bindPass );
+ fprintf( stream, " criteria: '%s'\n", ldapServer->searchCriteria );
+ fprintf( stream, "searchval: '%s'\n", ldapServer->searchValue );
+ fprintf( stream, "max entry: %d\n", ldapServer->maxEntries );
+ fprintf( stream, " num read: %d\n", ldapServer->entriesRead );
+ fprintf( stream, " ret val: %d\n", ldapServer->retVal );
+}
+
+/*
+* Build an address list entry and append to list of address items. Name is formatted
+* as it appears in the common name (cn) attribute.
+*/
+void syldap_build_items_cn( SyldapServer *ldapServer, GSList *listName, GSList *listAddr ) {
+ AddressItem *addrItem = NULL;
+ GSList *nodeName = listName;
+ while( nodeName ) {
+ GSList *nodeAddress = listAddr;
+ while( nodeAddress ) {
+ addrItem = mgu_create_address();
+ addrItem->name = g_strdup( nodeName->data );
+ addrItem->address = g_strdup( nodeAddress->data );
+ addrItem->remarks = g_strdup( "" );
+ mgu_add_cache( ldapServer->addressCache, addrItem );
+ nodeAddress = g_slist_next( nodeAddress );
+ ldapServer->entriesRead++;
+ }
+ nodeName = g_slist_next( nodeName );
+ }
+ addrItem = NULL;
+}
+
+/*
+* Build an address list entry and append to list of address items. Name is formatted
+* as "<first-name> <last-name>".
+*/
+void syldap_build_items_fl( SyldapServer *ldapServer, GSList *listAddr, GSList *listFirst, GSList *listLast ) {
+ AddressItem *addrItem = NULL;
+ GSList *nodeFirst = listFirst;
+ GSList *nodeAddress = listAddr;
+ gchar *firstName = NULL, *lastName = NULL, *fullName = NULL;
+ gint iLen = 0, iLenT = 0;
+
+ // Find longest first name in list
+ while( nodeFirst ) {
+ if( firstName == NULL ) {
+ firstName = nodeFirst->data;
+ iLen = strlen( firstName );
+ }
+ else {
+ if( ( iLenT = strlen( nodeFirst->data ) ) > iLen ) {
+ firstName = nodeFirst->data;
+ iLen = iLenT;
+ }
+ }
+ nodeFirst = g_slist_next( nodeFirst );
+ }
+
+ // Format name
+ if( listLast ) {
+ lastName = listLast->data;
+ }
+
+ if( firstName ) {
+ if( lastName ) {
+ fullName = g_strdup_printf( "%s %s", firstName, lastName );
+ }
+ else {
+ fullName = g_strdup_printf( "%s", firstName );
+ }
+ }
+ else {
+ if( lastName ) {
+ fullName = g_strdup_printf( "%s", lastName );
+ }
+ }
+ if( fullName ) {
+ g_strchug( fullName ); g_strchomp( fullName );
+ }
+
+ // Add address item
+ while( nodeAddress ) {
+ addrItem = mgu_create_address();
+ if( fullName ) {
+ addrItem->name = g_strdup( fullName );
+ }
+ else {
+ addrItem->name = g_strdup( "" );
+ }
+ addrItem->address = g_strdup( nodeAddress->data );
+ addrItem->remarks = g_strdup( "" );
+ mgu_add_cache( ldapServer->addressCache, addrItem );
+
+ nodeAddress = g_slist_next( nodeAddress );
+ ldapServer->entriesRead++;
+ }
+ g_free( fullName );
+ fullName = firstName = lastName = NULL;
+ addrItem = NULL;
+}
+
+/*
+* Add all attribute values to a list.
+*/
+GSList *syldap_add_list_values( LDAP *ld, LDAPMessage *entry, char *attr ) {
+ GSList *list = NULL;
+ gint i;
+ char **vals;
+ if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
+ for( i = 0; vals[i] != NULL; i++ ) {
+ // printf( "lv\t%s: %s\n", attr, vals[i] );
+ list = g_slist_append( list, g_strdup( vals[i] ) );
+ }
+ }
+ ldap_value_free( vals );
+ return list;
+}
+
+/*
+* Add a single attribute value to a list.
+*/
+GSList *syldap_add_single_value( LDAP *ld, LDAPMessage *entry, char *attr ) {
+ GSList *list = NULL;
+ char **vals;
+ if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
+ if( vals[0] != NULL ) {
+ // printf( "sv\t%s: %s\n", attr, vals[0] );
+ list = g_slist_append( list, g_strdup( vals[0] ) );
+ }
+ }
+ ldap_value_free( vals );
+ return list;
+}
+
+/*
+* Free linked lists of character strings.
+*/
+void syldap_free_lists( GSList *listName, GSList *listAddr, GSList *listID, GSList *listDN, GSList *listFirst, GSList *listLast ) {
+ mgu_free_list( listName );
+ mgu_free_list( listAddr );
+ mgu_free_list( listID );
+ mgu_free_list( listDN );
+ mgu_free_list( listFirst );
+ mgu_free_list( listLast );
+}
+
+/*
+* Check parameters that are required for a search. This should
+* be called before performing a search.
+* Return: TRUE if search criteria appear OK.
+*/
+gboolean syldap_check_search( SyldapServer *ldapServer ) {
+ g_return_if_fail( ldapServer != NULL );
+ ldapServer->retVal = MGU_LDAP_CRITERIA;
+
+ // Test search criteria
+ if( ldapServer->searchCriteria == NULL ) {
+ return FALSE;
+ }
+ if( strlen( ldapServer->searchCriteria ) < 1 ) {
+ return FALSE;
+ }
+
+ if( ldapServer->searchValue == NULL ) {
+ return FALSE;
+ }
+ if( strlen( ldapServer->searchValue ) < 1 ) {
+ return FALSE;
+ }
+
+ ldapServer->retVal = MGU_SUCCESS;
+ return TRUE;
+}
+
+/*
+* Perform the LDAP search, reading LDAP entries into cache.
+* Note that one LDAP entry can have multiple values for many of its
+* attributes. If these attributes are E-Mail addresses; these are
+* broken out into separate address items. For any other attribute,
+* only the first occurrence is read.
+*/
+gint syldap_search( SyldapServer *ldapServer ) {
+ LDAP *ld;
+ LDAPMessage *result, *e;
+ char *attribs[10];
+ char *attribute;
+ gchar *criteria;
+ BerElement *ber;
+ int rc, cnt;
+ GSList *listName = NULL, *listAddress = NULL, *listID = NULL;
+ GSList *listFirst = NULL, *listLast = NULL, *listDN = NULL;
+ struct timeval timeout;
+ gboolean entriesFound = FALSE;
+
+ g_return_if_fail( ldapServer != NULL );
+
+ ldapServer->retVal = MGU_SUCCESS;
+ if( ! syldap_check_search( ldapServer ) ) {
+ return ldapServer->retVal;
+ }
+
+ // Set timeout
+ timeout.tv_sec = ldapServer->timeOut;
+ timeout.tv_usec = 0L;
+
+ ldapServer->entriesRead = 0;
+ if( ( ld = ldap_init( ldapServer->hostName, ldapServer->port ) ) == NULL ) {
+ ldapServer->retVal = MGU_LDAP_INIT;
+ return ldapServer->retVal;
+ }
+
+ // printf( "connected to LDAP host %s on port %d\n", ldapServer->hostName, ldapServer->port );
+
+ // Bind to the server, if required
+ if( ldapServer->bindDN ) {
+ if( * ldapServer->bindDN != '\0' ) {
+ // printf( "binding...\n" );
+ rc = ldap_simple_bind_s( ld, ldapServer->bindDN, ldapServer->bindPass );
+ // printf( "rc=%d\n", rc );
+ if( rc != LDAP_SUCCESS ) {
+ // printf( "LDAP Error: ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
+ ldap_unbind( ld );
+ ldapServer->retVal = MGU_LDAP_BIND;
+ return ldapServer->retVal;
+ }
+ }
+ }
+
+ // Define all attributes we are interested in.
+ attribs[0] = SYLDAP_ATTR_DN;
+ attribs[1] = SYLDAP_ATTR_COMMONNAME;
+ attribs[2] = SYLDAP_ATTR_GIVENNAME;
+ attribs[3] = SYLDAP_ATTR_SURNAME;
+ attribs[4] = SYLDAP_ATTR_EMAIL;
+ attribs[5] = SYLDAP_ATTR_UID;
+ attribs[6] = NULL;
+
+ // Create LDAP search string and apply search criteria
+ criteria = g_strdup_printf( ldapServer->searchCriteria, ldapServer->searchValue );
+ rc = ldap_search_ext_s( ld, ldapServer->baseDN, LDAP_SCOPE_SUBTREE, criteria, attribs, 0, NULL, NULL,
+ &timeout, 0, &result );
+ g_free( criteria );
+ criteria = NULL;
+ if( rc == LDAP_TIMEOUT ) {
+ ldap_unbind( ld );
+ ldapServer->retVal = MGU_LDAP_TIMEOUT;
+ return ldapServer->retVal;
+ }
+ if( rc != LDAP_SUCCESS ) {
+ // printf( "LDAP Error: ldap_search_st: %s\n", ldap_err2string( rc ) );
+ ldap_unbind( ld );
+ ldapServer->retVal = MGU_LDAP_SEARCH;
+ return ldapServer->retVal;
+ }
+
+ // printf( "Total results are: %d\n", ldap_count_entries( ld, result ) );
+
+ // Clear the cache if we have new entries, otherwise leave untouched.
+ if( ldap_count_entries( ld, result ) > 0 ) {
+ mgu_clear_cache( ldapServer->addressCache );
+ }
+
+ // Process results
+ ldapServer->entriesRead = 0;
+ for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
+ entriesFound = TRUE;
+ if( ldapServer->entriesRead >= ldapServer->maxEntries ) break;
+ // printf( "DN: %s\n", ldap_get_dn( ld, e ) );
+
+ // Process all attributes
+ for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
+ attribute = ldap_next_attribute( ld, e, ber ) ) {
+ if( strcasecmp( attribute, SYLDAP_ATTR_COMMONNAME ) == 0 ) {
+ listName = syldap_add_list_values( ld, e, attribute );
+ }
+ if( strcasecmp( attribute, SYLDAP_ATTR_EMAIL ) == 0 ) {
+ listAddress = syldap_add_list_values( ld, e, attribute );
+ }
+ if( strcasecmp( attribute, SYLDAP_ATTR_UID ) == 0 ) {
+ listID = syldap_add_single_value( ld, e, attribute );
+ }
+ if( strcasecmp( attribute, SYLDAP_ATTR_GIVENNAME ) == 0 ) {
+ listFirst = syldap_add_list_values( ld, e, attribute );
+ }
+ if( strcasecmp( attribute, SYLDAP_ATTR_SURNAME ) == 0 ) {
+ listLast = syldap_add_single_value( ld, e, attribute );
+ }
+ if( strcasecmp( attribute, SYLDAP_ATTR_DN ) == 0 ) {
+ listDN = syldap_add_single_value( ld, e, attribute );
+ }
+ }
+
+ // Free memory used to store attribute
+ ldap_memfree( attribute );
+
+ // Format and add items to cache
+ syldap_build_items_fl( ldapServer, listAddress, listFirst, listLast );
+
+ // Free up
+ syldap_free_lists( listName, listAddress, listID, listDN, listFirst, listLast );
+ listName = listAddress = listID = listFirst = listLast = listDN = NULL;
+
+ if( ber != NULL ) {
+ ber_free( ber, 0 );
+ }
+ }
+
+ syldap_free_lists( listName, listAddress, listID, listDN, listFirst, listLast );
+ listName = listAddress = listID = listFirst = listLast = listDN = NULL;
+
+ // Free up and disconnect
+ ldap_msgfree( result );
+ ldap_unbind( ld );
+ ldapServer->newSearch = FALSE;
+ if( entriesFound ) {
+ ldapServer->retVal = MGU_SUCCESS;
+ }
+ else {
+ ldapServer->retVal = MGU_LDAP_NOENTRIES;
+ }
+ return ldapServer->retVal;
+}
+
+// ============================================================================================
+/*
+* Read data into list. Main entry point
+* Return: TRUE if file read successfully.
+*/
+// ============================================================================================
+gint syldap_read_data( SyldapServer *ldapServer ) {
+ g_return_if_fail( ldapServer != NULL );
+
+ pthread_detach( pthread_self() );
+ if( ldapServer->newSearch ) {
+ // Read data into the list
+ syldap_search( ldapServer );
+
+ // Mark cache
+ ldapServer->addressCache->modified = FALSE;
+ ldapServer->addressCache->dataRead = TRUE;
+ }
+
+ // Callback
+ ldapServer->busyFlag = FALSE;
+ if( ldapServer->callBack ) {
+ sched_yield();
+ ( ldapServer->callBack )( ldapServer );
+ }
+ ldapServer->thread = NULL;
+ pthread_exit( NULL );
+ return ldapServer->retVal;
+}
+
+// ============================================================================================
+/*
+* Cancel read with thread.
+*/
+// ============================================================================================
+void syldap_cancel_read( SyldapServer *ldapServer ) {
+ g_return_if_fail( ldapServer != NULL );
+ if( ldapServer->thread ) {
+printf( "thread cancelled\n" );
+ pthread_cancel( *ldapServer->thread );
+ }
+ ldapServer->thread = NULL;
+ ldapServer->busyFlag = FALSE;
+}
+
+// ============================================================================================
+/*
+* Read data into list using a background thread.
+* Return: TRUE if file read successfully. Callback function will be
+* notified when search is complete.
+*/
+// ============================================================================================
+gint syldap_read_data_th( SyldapServer *ldapServer ) {
+ pthread_t thread;
+ g_return_if_fail( ldapServer != NULL );
+
+ ldapServer->busyFlag = FALSE;
+ syldap_check_search( ldapServer );
+ if( ldapServer->retVal == MGU_SUCCESS ) {
+ ldapServer->busyFlag = TRUE;
+ ldapServer->thread = &thread;
+ pthread_create( ldapServer->thread, NULL, (void *) &syldap_read_data, (void *) ldapServer );
+ }
+ return ldapServer->retVal;
+}
+
+/*
+* Return link list of address items.
+* Return: TRUE if file read successfully.
+*/
+GList *syldap_get_address_list( const SyldapServer *ldapServer ) {
+ g_return_if_fail( ldapServer != NULL );
+ return ldapServer->addressCache->addressList;
+}
+
+#define SYLDAP_TEST_FILTER "(objectclass=*)"
+#define SYLDAP_SEARCHBASE_V2 "cn=config"
+#define SYLDAP_SEARCHBASE_V3 ""
+#define SYLDAP_V2_TEST_ATTR "database"
+#define SYLDAP_V3_TEST_ATTR "namingcontexts"
+
+/*
+* Attempt to discover the base DN for the server.
+* Enter:
+* host Host name
+* port Port number
+* bindDN Bind DN (optional).
+* bindPW Bind PW (optional).
+* tov Timeout value (seconds), or 0 for none, default 30 secs.
+* Return: List of Base DN's, or NULL if could not read. Base DN should
+* be g_free() when done.
+*/
+GList *syldap_read_basedn_s( const gchar *host, const gint port, const gchar *bindDN, const gchar *bindPW, const gint tov ) {
+ GList *baseDN = NULL;
+ LDAP *ld;
+ int rc, i;
+ LDAPMessage *result, *e;
+ char *attribs[10];
+ BerElement *ber;
+ char *attribute;
+ char **vals;
+ struct timeval timeout;
+
+ if( host == NULL ) return baseDN;
+ if( port < 1 ) return baseDN;
+
+ // Set timeout
+ timeout.tv_usec = 0L;
+ if( tov > 0 ) {
+ timeout.tv_sec = tov;
+ }
+ else {
+ timeout.tv_sec = 30L;
+ }
+
+ // Connect to server.
+ if( ( ld = ldap_init( host, port ) ) == NULL ) {
+ return baseDN;
+ }
+
+ // Bind to the server, if required
+ if( bindDN ) {
+ if( *bindDN != '\0' ) {
+ rc = ldap_simple_bind_s( ld, bindDN, bindPW );
+ if( rc != LDAP_SUCCESS ) {
+ // printf( "LDAP Error: ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
+ ldap_unbind( ld );
+ return baseDN;
+ }
+ }
+ }
+
+ // Test for LDAP version 3
+ attribs[0] = SYLDAP_V3_TEST_ATTR;
+ attribs[1] = NULL;
+ rc = ldap_search_ext_s( ld, SYLDAP_SEARCHBASE_V3, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER, attribs,
+ 0, NULL, NULL, &timeout, 0, &result );
+ if( rc == LDAP_SUCCESS ) {
+ // Process entries
+ for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
+ // printf( "DN: %s\n", ldap_get_dn( ld, e ) );
+
+ // Process attributes
+ for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
+ attribute = ldap_next_attribute( ld, e, ber ) ) {
+ if( strcasecmp( attribute, SYLDAP_V3_TEST_ATTR ) == 0 ) {
+ if( ( vals = ldap_get_values( ld, e, attribute ) ) != NULL ) {
+ for( i = 0; vals[i] != NULL; i++ ) {
+ // printf( "\t%s: %s\n", attribute, vals[i] );
+ baseDN = g_list_append( baseDN, g_strdup( vals[i] ) );
+ }
+ }
+ ldap_value_free( vals );
+ }
+ }
+ ldap_memfree( attribute );
+ if( ber != NULL ) {
+ ber_free( ber, 0 );
+ }
+ }
+ ldap_msgfree( result );
+ }
+ else {
+ }
+
+ if( baseDN == NULL ) {
+ // Test for LDAP version 2
+ attribs[0] = NULL;
+ rc = ldap_search_ext_s( ld, SYLDAP_SEARCHBASE_V2, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER, attribs,
+ 0, NULL, NULL, &timeout, 0, &result );
+ if( rc == LDAP_SUCCESS ) {
+ // Process entries
+ for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
+ // if( baseDN ) break;
+ // printf( "DN: %s\n", ldap_get_dn( ld, e ) );
+
+ // Process attributes
+ for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
+ attribute = ldap_next_attribute( ld, e, ber ) ) {
+ // if( baseDN ) break;
+ if( strcasecmp( attribute, SYLDAP_V2_TEST_ATTR ) == 0 ) {
+ if( ( vals = ldap_get_values( ld, e, attribute ) ) != NULL ) {
+ for( i = 0; vals[i] != NULL; i++ ) {
+ char *ch;
+ // Strip the 'ldb:' from the front of the value
+ ch = ( char * ) strchr( vals[i], ':' );
+ if( ch ) {
+ gchar *bn = g_strdup( ++ch );
+ g_strchomp( bn );
+ g_strchug( bn );
+ baseDN = g_list_append( baseDN, g_strdup( bn ) );
+ }
+ }
+ }
+ ldap_value_free( vals );
+ }
+ }
+ ldap_memfree( attribute );
+ if( ber != NULL ) {
+ ber_free( ber, 0 );
+ }
+ }
+ ldap_msgfree( result );
+ }
+ }
+ ldap_unbind( ld );
+ return baseDN;
+}
+
+/*
+* Attempt to discover the base DN for the server.
+* Enter: ldapServer Server to test.
+* Return: List of Base DN's, or NULL if could not read. Base DN should
+* be g_free() when done. Return code set in ldapServer.
+*/
+GList *syldap_read_basedn( SyldapServer *ldapServer ) {
+ GList *baseDN = NULL;
+ LDAP *ld;
+ int rc, i;
+ LDAPMessage *result, *e;
+ char *attribs[10];
+ BerElement *ber;
+ char *attribute;
+ char **vals;
+ struct timeval timeout;
+
+ ldapServer->retVal = MGU_BAD_ARGS;
+ if( ldapServer == NULL ) return baseDN;
+ if( ldapServer->hostName == NULL ) return baseDN;
+ if( ldapServer->port < 1 ) return baseDN;
+
+ // Set timeout
+ timeout.tv_usec = 0L;
+ if( ldapServer->timeOut > 0 ) {
+ timeout.tv_sec = ldapServer->timeOut;
+ }
+ else {
+ timeout.tv_sec = 30L;
+ }
+
+ // Connect to server.
+ if( ( ld = ldap_init( ldapServer->hostName, ldapServer->port ) ) == NULL ) {
+ ldapServer->retVal = MGU_LDAP_INIT;
+ return baseDN;
+ }
+
+ // Bind to the server, if required
+ if( ldapServer->bindDN ) {
+ if( *ldapServer->bindDN != '\0' ) {
+ rc = ldap_simple_bind_s( ld, ldapServer->bindDN, ldapServer->bindPass );
+ if( rc != LDAP_SUCCESS ) {
+ //printf( "LDAP Error: ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
+ ldap_unbind( ld );
+ ldapServer->retVal = MGU_LDAP_BIND;
+ return baseDN;
+ }
+ }
+ }
+
+ ldapServer->retVal = MGU_LDAP_SEARCH;
+
+ // Test for LDAP version 3
+ attribs[0] = SYLDAP_V3_TEST_ATTR;
+ attribs[1] = NULL;
+ rc = ldap_search_ext_s( ld, SYLDAP_SEARCHBASE_V3, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER, attribs,
+ 0, NULL, NULL, &timeout, 0, &result );
+ if( rc == LDAP_SUCCESS ) {
+ // Process entries
+ for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
+ // printf( "DN: %s\n", ldap_get_dn( ld, e ) );
+
+ // Process attributes
+ for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
+ attribute = ldap_next_attribute( ld, e, ber ) ) {
+ if( strcasecmp( attribute, SYLDAP_V3_TEST_ATTR ) == 0 ) {
+ if( ( vals = ldap_get_values( ld, e, attribute ) ) != NULL ) {
+ for( i = 0; vals[i] != NULL; i++ ) {
+ // printf( "\t%s: %s\n", attribute, vals[i] );
+ baseDN = g_list_append( baseDN, g_strdup( vals[i] ) );
+ }
+ }
+ ldap_value_free( vals );
+ }
+ }
+ ldap_memfree( attribute );
+ if( ber != NULL ) {
+ ber_free( ber, 0 );
+ }
+ }
+ ldap_msgfree( result );
+ ldapServer->retVal = MGU_SUCCESS;
+ }
+ else if( rc == LDAP_TIMEOUT ) {
+ ldapServer->retVal = MGU_LDAP_TIMEOUT;
+ }
+
+ if( baseDN == NULL ) {
+ // Test for LDAP version 2
+ attribs[0] = NULL;
+ rc = ldap_search_ext_s( ld, SYLDAP_SEARCHBASE_V2, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER, attribs,
+ 0, NULL, NULL, &timeout, 0, &result );
+ if( rc == LDAP_SUCCESS ) {
+ // Process entries
+ for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
+ // if( baseDN ) break;
+ // printf( "DN: %s\n", ldap_get_dn( ld, e ) );
+
+ // Process attributes
+ for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
+ attribute = ldap_next_attribute( ld, e, ber ) ) {
+ // if( baseDN ) break;
+ if( strcasecmp( attribute, SYLDAP_V2_TEST_ATTR ) == 0 ) {
+ if( ( vals = ldap_get_values( ld, e, attribute ) ) != NULL ) {
+ for( i = 0; vals[i] != NULL; i++ ) {
+ char *ch;
+ // Strip the 'ldb:' from the front of the value
+ ch = ( char * ) strchr( vals[i], ':' );
+ if( ch ) {
+ gchar *bn = g_strdup( ++ch );
+ g_strchomp( bn );
+ g_strchug( bn );
+ baseDN = g_list_append( baseDN, g_strdup( bn ) );
+ }
+ }
+ }
+ ldap_value_free( vals );
+ }
+ }
+ ldap_memfree( attribute );
+ if( ber != NULL ) {
+ ber_free( ber, 0 );
+ }
+ }
+ ldap_msgfree( result );
+ ldapServer->retVal = MGU_SUCCESS;
+ }
+ else if( rc == LDAP_TIMEOUT ) {
+ ldapServer->retVal = MGU_LDAP_TIMEOUT;
+ }
+ }
+ ldap_unbind( ld );
+
+ return baseDN;
+}
+
+/*
+* Attempt to connect to the server.
+* Enter:
+* host Host name
+* port Port number
+* Return: TRUE if connected successfully.
+*/
+gboolean syldap_test_connect_s( const gchar *host, const gint port ) {
+ gboolean retVal = FALSE;
+ LDAP *ld;
+ if( host == NULL ) return retVal;
+ if( port < 1 ) return retVal;
+ if( ( ld = ldap_open( host, port ) ) != NULL ) {
+ retVal = TRUE;
+ }
+ if( ld != NULL ) {
+ ldap_unbind( ld );
+ }
+ return retVal;
+}
+
+/*
+* Attempt to connect to the server.
+* Enter: ldapServer Server to test.
+* Return: TRUE if connected successfully. Return code set in ldapServer.
+*/
+gboolean syldap_test_connect( SyldapServer *ldapServer ) {
+ gboolean retVal = FALSE;
+ LDAP *ld;
+ ldapServer->retVal = MGU_BAD_ARGS;
+ if( ldapServer == NULL ) return retVal;
+ if( ldapServer->hostName == NULL ) return retVal;
+ if( ldapServer->port < 1 ) return retVal;
+ ldapServer->retVal = MGU_LDAP_INIT;
+ if( ( ld = ldap_open( ldapServer->hostName, ldapServer->port ) ) != NULL ) {
+ ldapServer->retVal = MGU_SUCCESS;
+ retVal = TRUE;
+ }
+ if( ld != NULL ) {
+ ldap_unbind( ld );
+ }
+ return retVal;
+}
+
+#define LDAP_LINK_LIB_NAME_1 "libldap.so"
+#define LDAP_LINK_LIB_NAME_2 "liblber.so"
+#define LDAP_LINK_LIB_NAME_3 "libresolv.so"
+#define LDAP_LINK_LIB_NAME_4 "libpthread.so"
+
+/*
+* Test whether LDAP libraries installed.
+* Return: TRUE if library available.
+*/
+gboolean syldap_test_ldap_lib() {
+ void *handle, *fun;
+
+ // Get library
+ handle = dlopen( LDAP_LINK_LIB_NAME_1, RTLD_LAZY );
+ if( ! handle ) {
+ return FALSE;
+ }
+
+ // Test for symbols we need
+ fun = dlsym( handle, "ldap_init" );
+ if( ! fun ) {
+ dlclose( handle );
+ return FALSE;
+ }
+ dlclose( handle ); handle = NULL; fun = NULL;
+
+ handle = dlopen( LDAP_LINK_LIB_NAME_2, RTLD_LAZY );
+ if( ! handle ) {
+ return FALSE;
+ }
+ fun = dlsym( handle, "ber_init" );
+ if( ! fun ) {
+ dlclose( handle );
+ return FALSE;
+ }
+ dlclose( handle ); handle = NULL; fun = NULL;
+
+ handle = dlopen( LDAP_LINK_LIB_NAME_3, RTLD_LAZY );
+ if( ! handle ) {
+ return FALSE;
+ }
+ fun = dlsym( handle, "res_query" );
+ if( ! fun ) {
+ dlclose( handle );
+ return FALSE;
+ }
+ dlclose( handle ); handle = NULL; fun = NULL;
+
+ handle = dlopen( LDAP_LINK_LIB_NAME_4, RTLD_LAZY );
+ if( ! handle ) {
+ return FALSE;
+ }
+ fun = dlsym( handle, "pthread_create" );
+ if( ! fun ) {
+ dlclose( handle );
+ return FALSE;
+ }
+ dlclose( handle ); handle = NULL; fun = NULL;
+
+ return TRUE;
+}
+
+#endif /* USE_LDAP */
+
+/*
+* End of Source.
+*/
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * Definitions necessary to access LDAP servers.
+ */
+
+#ifndef __SYLDAP_H__
+#define __SYLDAP_H__
+
+#ifdef USE_LDAP
+
+#include <glib.h>
+#include <pthread.h>
+
+#include "mgutils.h"
+
+#define SYLDAP_DFL_PORT 389
+#define SYLDAP_MAX_ENTRIES 20
+#define SYLDAP_DFL_TIMEOUT 30
+#define SYLDAP_DFL_CRITERIA "(&(mail=*)(cn=%s*))"
+
+#define SYLDAP_ATTR_DN "dn"
+#define SYLDAP_ATTR_COMMONNAME "cn"
+#define SYLDAP_ATTR_GIVENNAME "givenName"
+#define SYLDAP_ATTR_SURNAME "sn"
+#define SYLDAP_ATTR_EMAIL "mail"
+#define SYLDAP_ATTR_UID "uid"
+
+// VCard object
+typedef struct _SyldapServer SyldapServer;
+struct _SyldapServer {
+ gchar *name;
+ gchar *hostName;
+ gint port;
+ gchar *baseDN;
+ gchar *bindDN;
+ gchar *bindPass;
+ gchar *searchCriteria;
+ gchar *searchValue;
+ gint entriesRead;
+ gint maxEntries;
+ gint timeOut;
+ gboolean newSearch;
+ AddressCache *addressCache;
+ gint retVal;
+ pthread_t *thread;
+ gboolean busyFlag;
+ void (*callBack)( void * );
+};
+
+/* Function prototypes */
+void syldap_set_name( SyldapServer* ldapServer, const gchar *value );
+void syldap_set_host( SyldapServer* ldapServer, const gchar *value );
+void syldap_set_port( SyldapServer* ldapServer, const gint value );
+void syldap_set_base_dn( SyldapServer* ldapServer, const gchar *value );
+void syldap_set_bind_dn( SyldapServer* ldapServer, const gchar *value );
+void syldap_set_bind_password( SyldapServer* ldapServer, const gchar *value );
+void syldap_set_search_criteria( SyldapServer* ldapServer, const gchar *value );
+void syldap_set_search_value( SyldapServer* ldapServer, const gchar *value );
+void syldap_set_max_entries( SyldapServer* ldapServer, const gint value );
+void syldap_set_timeout( SyldapServer* ldapServer, const gint value );
+void syldap_set_callback( SyldapServer *ldapServer, void *func );
+void syldap_force_refresh( SyldapServer *ldapServer );
+SyldapServer *syldap_create();
+void syldap_free( SyldapServer *ldapServer );
+void syldap_print_data( SyldapServer *ldapServer, FILE *stream );
+gboolean syldap_check_search( SyldapServer *ldapServer );
+gint syldap_read_data( SyldapServer *ldapServer );
+gint syldap_read_data_th( SyldapServer *ldapServer );
+void syldap_cancel_read( SyldapServer *ldapServer );
+GList *syldap_get_address_list( const SyldapServer *ldapServer );
+GList *syldap_read_basedn_s( const gchar *host, const gint port, const gchar *bindDN, const gchar *bindPW, const gint tov );
+GList *syldap_read_basedn( SyldapServer *ldapServer );
+gboolean syldap_test_connect_s( const gchar *host, const gint port );
+gboolean syldap_test_connect( SyldapServer *ldapServer );
+gboolean syldap_test_ldap_lib();
+
+#endif /* USE_LDAP */
+
+#endif /* __SYLDAP_H__ */
+
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * Functions necessary to access VCard files. VCard files are used
+ * by GnomeCard for addressbook, and Netscape for sending business
+ * card information. Refer to RFC2426 for more information.
+ */
+
+#include <sys/stat.h>
+#include <glib.h>
+
+#include "mgutils.h"
+#include "vcard.h"
+
+#define GNOMECARD_DIR ".gnome"
+#define GNOMECARD_FILE "GnomeCard"
+#define GNOMECARD_SECTION "[file]"
+#define GNOMECARD_PARAM "open"
+
+#define VCARD_TEST_LINES 200
+
+/*
+* Specify name to be used.
+*/
+void vcard_set_name( VCardFile* cardFile, const gchar *name ) {
+ /* Copy file name */
+ if( cardFile->name ) g_free( cardFile->name );
+ if( name ) cardFile->name = g_strdup( name );
+ g_strstrip( cardFile->name );
+}
+
+/*
+* Specify file to be used.
+*/
+void vcard_set_file( VCardFile* cardFile, const gchar *path ) {
+ mgu_refresh_cache( cardFile->addressCache );
+
+ /* Copy file path */
+ if( cardFile->path ) g_free( cardFile->path );
+ if( path ) cardFile->path = g_strdup( path );
+ g_strstrip( cardFile->path );
+}
+
+/*
+* Create new cardfile object.
+*/
+VCardFile *vcard_create() {
+ VCardFile *cardFile;
+ cardFile = g_new( VCardFile, 1 );
+ cardFile->name = NULL;
+ cardFile->path = NULL;
+ cardFile->file = NULL;
+ cardFile->bufptr = cardFile->buffer;
+ cardFile->addressCache = mgu_create_cache();
+ cardFile->retVal = MGU_SUCCESS;
+ return cardFile;
+}
+
+/*
+* Refresh internal variables to force a file read.
+*/
+void vcard_force_refresh( VCardFile *cardFile ) {
+ mgu_refresh_cache( cardFile->addressCache );
+}
+
+/*
+* Create new cardfile object for specified file.
+*/
+VCardFile *vcard_create_path( const gchar *path ) {
+ VCardFile *cardFile;
+ cardFile = vcard_create();
+ vcard_set_file(cardFile, path );
+ return cardFile;
+}
+
+/*
+* Free up cardfile object by releasing internal memory.
+*/
+void vcard_free( VCardFile *cardFile ) {
+ g_return_if_fail( cardFile != NULL );
+
+ // fprintf( stdout, "freeing... VCardFile\n" );
+
+ /* Close file */
+ if( cardFile->file ) fclose( cardFile->file );
+
+ /* Free internal stuff */
+ g_free( cardFile->name );
+ g_free( cardFile->path );
+
+ /* Clear cache */
+ mgu_clear_cache( cardFile->addressCache );
+ mgu_free_cache( cardFile->addressCache );
+
+ // Clear pointers
+ cardFile->file = NULL;
+ cardFile->name = NULL;
+ cardFile->path = NULL;
+ cardFile->addressCache = NULL;
+ cardFile->retVal = MGU_SUCCESS;
+
+ /* Now release file object */
+ g_free( cardFile );
+
+ // fprintf( stdout, "freeing... VCardFile done\n" );
+
+}
+
+/*
+* Display object to specified stream.
+*/
+void vcard_print_file( VCardFile *cardFile, FILE *stream ) {
+ GSList *node;
+ g_return_if_fail( cardFile != NULL );
+ fprintf( stream, "VCardFile:\n" );
+ fprintf( stream, " name: '%s'\n", cardFile->name );
+ fprintf( stream, "file spec: '%s'\n", cardFile->path );
+ fprintf( stream, " ret val: %d\n", cardFile->retVal );
+ mgu_print_cache( cardFile->addressCache, stream );
+}
+
+/*
+* Open file for read.
+* return: TRUE if file opened successfully.
+*/
+gint vcard_open_file( VCardFile* cardFile ) {
+ g_return_if_fail( cardFile != NULL );
+
+ // fprintf( stdout, "Opening file\n" );
+ cardFile->addressCache->dataRead = FALSE;
+ if( cardFile->path ) {
+ cardFile->file = fopen( cardFile->path, "r" );
+ if( ! cardFile->file ) {
+ // fprintf( stderr, "can't open %s\n", cardFile->path );
+ cardFile->retVal = MGU_OPEN_FILE;
+ return cardFile->retVal;
+ }
+ }
+ else {
+ // fprintf( stderr, "file not specified\n" );
+ cardFile->retVal = MGU_NO_FILE;
+ return cardFile->retVal;
+ }
+
+ /* Setup a buffer area */
+ cardFile->buffer[0] = '\0';
+ cardFile->bufptr = cardFile->buffer;
+ cardFile->retVal = MGU_SUCCESS;
+ return cardFile->retVal;
+}
+
+/*
+* Close file.
+*/
+void vcard_close_file( VCardFile *cardFile ) {
+ g_return_if_fail( cardFile != NULL );
+ if( cardFile->file ) fclose( cardFile->file );
+ cardFile->file = NULL;
+}
+
+/*
+* Read line of text from file.
+* Return: ptr to buffer where line starts.
+*/
+gchar *vcard_read_line( VCardFile *cardFile ) {
+ while( *cardFile->bufptr == '\n' || *cardFile->bufptr == '\0' ) {
+ if( fgets( cardFile->buffer, VCARDBUFSIZE, cardFile->file ) == NULL )
+ return NULL;
+ g_strstrip( cardFile->buffer );
+ cardFile->bufptr = cardFile->buffer;
+ }
+ return cardFile->bufptr;
+}
+
+/*
+* Read line of text from file.
+* Return: ptr to buffer where line starts.
+*/
+gchar *vcard_get_line( VCardFile *cardFile ) {
+ gchar buf[ VCARDBUFSIZE ];
+ gchar *start, *end;
+ gint len;
+
+ if (vcard_read_line( cardFile ) == NULL ) {
+ buf[0] = '\0';
+ return;
+ }
+
+ /* Copy into private buffer */
+ start = cardFile->bufptr;
+ len = strlen( start );
+ end = start + len;
+ strncpy( buf, start, len );
+ buf[ len ] = '\0';
+ g_strstrip(buf);
+ cardFile->bufptr = end + 1;
+
+ /* Return a copy of buffer */
+ return g_strdup( buf );
+}
+
+/*
+* Free linked lists of character strings.
+*/
+void vcard_free_lists( GSList *listName, GSList *listAddr, GSList *listRem, GSList* listID ) {
+ mgu_free_list( listName );
+ mgu_free_list( listAddr );
+ mgu_free_list( listRem );
+ mgu_free_list( listID );
+}
+
+/*
+* Read quoted-printable text, which may span several lines into one long string.
+* Param: cardFile - object.
+* Param: tagvalue - will be placed into the linked list.
+*/
+gchar *vcard_read_qp( VCardFile *cardFile, char *tagvalue ) {
+ GSList *listQP = NULL;
+ gint len = 0;
+ gchar *line = tagvalue;
+ while( line ) {
+ listQP = g_slist_append( listQP, line );
+ len = strlen( line ) - 1;
+ if( len > 0 ) {
+ if( line[ len ] != '=' ) break;
+ line[ len ] = '\0';
+ }
+ line = vcard_get_line( cardFile );
+ }
+
+ // Coalesce linked list into one long buffer.
+ line = mgu_list_coalesce( listQP );
+
+ // Clean up
+ mgu_free_list( listQP );
+ listQP = NULL;
+ return line;
+}
+
+/*
+* Parse tag name from line buffer.
+* Return: Buffer containing the tag name, or NULL if no delimiter char found.
+*/
+gchar *vcard_get_tagname( char* line, gchar dlm ) {
+ gint len = 0;
+ gchar *tag = NULL;
+ gchar *lptr = line;
+ while( *lptr++ ) {
+ if( *lptr == dlm ) {
+ len = lptr - line;
+ tag = g_strndup( line, len+1 );
+ tag[ len ] = '\0';
+ g_strdown( tag );
+ return tag;
+ }
+ }
+ return tag;
+}
+
+/*
+* Parse tag value from line buffer.
+* Return: Buffer containing the tag value. Empty string is returned if
+* no delimiter char found.
+*/
+gchar *vcard_get_tagvalue( gchar* line, gchar dlm ) {
+ gchar *value = NULL;
+ gchar *start = NULL;
+ gchar *lptr;
+ gint len = 0;
+
+ for( lptr = line; *lptr; lptr++ ) {
+ if( *lptr == dlm ) {
+ if( ! start )
+ start = lptr + 1;
+ }
+ }
+ if( start ) {
+ len = lptr - start;
+ value = g_strndup( start, len+1 );
+ }
+ else {
+ // Ensure that we get an empty string
+ value = g_strndup( "", 1 );
+ }
+ value[ len ] = '\0';
+ return value;
+}
+
+/*
+* Dump linked lists of character strings (for debug).
+*/
+void vcard_dump_lists( GSList *listName, GSList *listAddr, GSList *listRem, GSList *listID, FILE *stream ) {
+ fprintf( stream, "dump name\n" );
+ fprintf( stream, "------------\n" );
+ mgu_print_list( listName, stdout );
+ fprintf( stream, "dump address\n" );
+ fprintf( stream, "------------\n" );
+ mgu_print_list( listAddr, stdout );
+ fprintf( stream, "dump remarks\n" );
+ fprintf( stdout, "------------\n" );
+ mgu_print_list( listRem, stdout );
+ fprintf( stream, "dump id\n" );
+ fprintf( stdout, "------------\n" );
+ mgu_print_list( listID, stdout );
+}
+
+/*
+* Build an address list entry and append to list of address items.
+*/
+void vcard_build_items( VCardFile *cardFile, GSList *listName, GSList *listAddr, GSList *listRem, GSList *listID ) {
+ AddressItem *addrItem = NULL;
+ GSList *nodeName = listName;
+ GSList *nodeID = listID;
+ while( nodeName ) {
+ GSList *nodeAddress = listAddr;
+ GSList *nodeRemarks = listRem;
+ while( nodeAddress ) {
+ addrItem = mgu_create_address();
+ addrItem->name = g_strdup( nodeName->data );
+ addrItem->address = g_strdup( nodeAddress->data );
+ if( nodeRemarks ) {
+ if( nodeRemarks->data ) {
+ if( g_strcasecmp( nodeRemarks->data, "internet" ) == 0 ) {
+ // Trivially exclude this one (appears for most records)
+ addrItem->remarks = g_strdup( "" );
+ }
+ else {
+ addrItem->remarks = g_strdup( nodeRemarks->data );
+ }
+ }
+ else {
+ addrItem->remarks = g_strdup( "" );
+ }
+ }
+ else {
+ addrItem->remarks = g_strdup( "" );
+ }
+/*
+ if( nodeID ) {
+ if( nodeID->data ) {
+ addrItem->externalID = g_strdup( nodeID->data );
+ }
+ else {
+ addrItem->externalID = g_strdup( "" );
+ }
+ }
+ else {
+ addrItem->externalID = g_strdup( "" );
+ }
+*/
+ mgu_add_cache( cardFile->addressCache, addrItem );
+
+ nodeAddress = g_slist_next( nodeAddress );
+ nodeRemarks = g_slist_next( nodeRemarks );
+ }
+ nodeName = g_slist_next( nodeName );
+ nodeID = g_slist_next( nodeID );
+ }
+ addrItem = NULL;
+}
+
+// Unescape characters in quoted-printable string.
+void vcard_unescape_qp( gchar *value ) {
+ gchar *ptr, *src, *dest;
+ int d, v;
+ char ch;
+ gboolean gotch;
+ ptr = value;
+ while( *ptr ) {
+ gotch = FALSE;
+ if( *ptr == '=' ) {
+ v = 0;
+ ch = *(ptr + 1);
+ if( ch ) {
+ if( ch > '0' && ch < '8' ) v = ch - '0';
+ }
+ d = -1;
+ ch = *(ptr + 2);
+ if( ch ) {
+ if( ch > '\x60' ) ch -= '\x20';
+ if( ch > '0' && ch < ' ' ) d = ch - '0';
+ d = ch - '0';
+ if( d > 9 ) d -= 7;
+ if( d > -1 && d < 16 ) {
+ v = ( 16 * v ) + d;
+ gotch = TRUE;
+ }
+ }
+ }
+ if( gotch ) {
+ // Replace = with char and move down in buffer
+ *ptr = v;
+ src = ptr + 3;
+ dest = ptr + 1;
+ while( *src ) {
+ *dest++ = *src++;
+ }
+ *dest = '\0';
+ }
+ ptr++;
+ }
+}
+
+/*
+* Read file into cache.
+* Note that one VCard can have multiple E-Mail addresses (MAIL tags);
+* these are broken out into separate address items. An address item
+* is generated for the person identified by FN tag and each EMAIL tag.
+* If a sub-type is included in the EMAIL entry, this will be used as
+* the Remarks member. Also note that it is possible for one VCard
+* entry to have multiple FN tags; this might not make sense. However,
+* it will generate duplicate address entries for each person listed.
+*/
+void vcard_read_cache( VCardFile *cardFile ) {
+ gchar *tagtemp = NULL, *tagname = NULL, *tagvalue = NULL, *tagtype = NULL, *tagrest = NULL;
+ GSList *listName = NULL, *listAddress = NULL, *listRemarks = NULL, *listID = NULL;
+ GSList *listQP = NULL;
+
+ for( ;; ) {
+ gchar *line = vcard_get_line( cardFile );
+ if( line == NULL ) break;
+
+ // fprintf( stdout, "%s\n", line );
+
+ /* Parse line */
+ tagtemp = vcard_get_tagname( line, VCARD_SEP_TAG );
+ if( tagtemp ) {
+ // fprintf( stdout, "\ttemp: %s\n", tagtemp );
+ tagvalue = vcard_get_tagvalue( line, VCARD_SEP_TAG );
+ tagname = vcard_get_tagname( tagtemp, VCARD_SEP_TYPE );
+ tagtype = vcard_get_tagvalue( tagtemp, VCARD_SEP_TYPE );
+ if( tagname == NULL ) {
+ tagname = tagtemp;
+ tagtemp = NULL;
+ }
+
+ // fprintf( stdout, "\tname: %s\n", tagname );
+ // fprintf( stdout, "\ttype: %s\n", tagtype );
+ // fprintf( stdout, "\tvalue: %s\n", tagvalue );
+
+ if( tagvalue ) {
+ if( g_strcasecmp( tagtype, VCARD_TYPE_QP ) == 0 ) {
+ // Quoted-Printable: could span multiple lines
+ tagvalue = vcard_read_qp( cardFile, tagvalue );
+ vcard_unescape_qp( tagvalue );
+ // fprintf( stdout, "QUOTED-PRINTABLE !!! final\n>%s<\n", tagvalue );
+ }
+
+ if( g_strcasecmp( tagname, VCARD_TAG_START ) == 0 && g_strcasecmp( tagvalue, VCARD_NAME ) == 0 ) {
+ // fprintf( stdout, "start card\n" );
+ vcard_free_lists( listName, listAddress, listRemarks, listID );
+ listName = listAddress = listRemarks = listID = NULL;
+ }
+ if( g_strcasecmp( tagname, VCARD_TAG_FULLNAME ) == 0 ) {
+ // fprintf( stdout, "- full name: %s\n", tagvalue );
+ listName = g_slist_append( listName, g_strdup( tagvalue ) );
+ }
+ if( g_strcasecmp( tagname, VCARD_TAG_EMAIL ) == 0 ) {
+ // fprintf( stdout, "- address: %s\n", tagvalue );
+ listAddress = g_slist_append( listAddress, g_strdup( tagvalue ) );
+ listRemarks = g_slist_append( listRemarks, g_strdup( tagtype ) );
+ }
+ if( g_strcasecmp( tagname, VCARD_TAG_UID ) == 0 ) {
+ // fprintf( stdout, "- id: %s\n", tagvalue );
+ listID = g_slist_append( listID, g_strdup( tagvalue ) );
+ }
+ if( g_strcasecmp( tagname, VCARD_TAG_END ) == 0 && g_strcasecmp( tagvalue, VCARD_NAME ) == 0 ) {
+ // VCard is complete
+ // fprintf( stdout, "end card\n--\n" );
+ // vcard_dump_lists( listName, listAddress, listRemarks, listID, stdout );
+ vcard_build_items( cardFile, listName, listAddress, listRemarks, listID );
+ vcard_free_lists( listName, listAddress, listRemarks, listID );
+ listName = listAddress = listRemarks = listID = NULL;
+ }
+ g_free( tagvalue );
+ }
+ g_free( tagname );
+ g_free( tagtype );
+ }
+ }
+
+ // Free lists
+ vcard_free_lists( listName, listAddress, listRemarks, listID );
+ listName = listAddress = listRemarks = listID = NULL;
+}
+
+// ============================================================================================
+/*
+* Read file into list. Main entry point
+* Return: TRUE if file read successfully.
+*/
+// ============================================================================================
+gint vcard_read_data( VCardFile *cardFile ) {
+ g_return_if_fail( cardFile != NULL );
+ cardFile->retVal = MGU_SUCCESS;
+ if( mgu_check_file( cardFile->addressCache, cardFile->path ) ) {
+ mgu_clear_cache( cardFile->addressCache );
+ vcard_open_file( cardFile );
+ if( cardFile->retVal == MGU_SUCCESS ) {
+ // Read data into the list
+ vcard_read_cache( cardFile );
+ vcard_close_file( cardFile );
+
+ // Mark cache
+ mgu_mark_cache( cardFile->addressCache, cardFile->path );
+ cardFile->addressCache->modified = FALSE;
+ cardFile->addressCache->dataRead = TRUE;
+ }
+ }
+ return cardFile->retVal;
+}
+
+/*
+* Return link list of address items.
+* Return: TRUE if file read successfully.
+*/
+GList *vcard_get_address_list( VCardFile *cardFile ) {
+ g_return_if_fail( cardFile != NULL );
+ return cardFile->addressCache->addressList;
+}
+
+/*
+* Validate that all parameters specified.
+* Return: TRUE if data is good.
+*/
+gboolean vcard_validate( const VCardFile *cardFile ) {
+ gboolean retVal;
+ g_return_if_fail( cardFile != NULL );
+
+ retVal = TRUE;
+ if( cardFile->path ) {
+ if( strlen( cardFile->path ) < 1 ) retVal = FALSE;
+ }
+ else {
+ retVal = FALSE;
+ }
+ if( cardFile->name ) {
+ if( strlen( cardFile->name ) < 1 ) retVal = FALSE;
+ }
+ else {
+ retVal = FALSE;
+ }
+ return retVal;
+}
+
+#define WORK_BUFLEN 1024
+
+/*
+* Attempt to find a valid GnomeCard file.
+* Return: Filename, or home directory if not found. Filename should
+* be g_free() when done.
+*/
+gchar *vcard_find_gnomecard( void ) {
+ gchar *homedir;
+ gchar buf[ WORK_BUFLEN ];
+ gchar str[ WORK_BUFLEN ];
+ gchar *fileSpec;
+ gint len, lenlbl, i;
+ FILE *fp;
+
+ homedir = g_get_home_dir();
+ if( ! homedir ) return NULL;
+
+ strcpy( str, homedir );
+ len = strlen( str );
+ if( len > 0 ) {
+ if( str[ len-1 ] != G_DIR_SEPARATOR ) {
+ str[ len ] = G_DIR_SEPARATOR;
+ str[ ++len ] = '\0';
+ }
+ }
+ strcat( str, GNOMECARD_DIR );
+ strcat( str, G_DIR_SEPARATOR_S );
+ strcat( str, GNOMECARD_FILE );
+
+ fileSpec = NULL;
+ if( ( fp = fopen( str, "r" ) ) != NULL ) {
+ // Read configuration file
+ lenlbl = strlen( GNOMECARD_SECTION );
+ while( fgets( buf, sizeof( buf ), fp ) != NULL ) {
+ if( 0 == g_strncasecmp( buf, GNOMECARD_SECTION, lenlbl ) ) {
+ break;
+ }
+ }
+
+ while( fgets( buf, sizeof( buf ), fp ) != NULL ) {
+ g_strchomp( buf );
+ if( buf[0] == '[' ) break;
+ for( i = 0; i < lenlbl; i++ ) {
+ if( buf[i] == '=' ) {
+ if( 0 == g_strncasecmp( buf, GNOMECARD_PARAM, i ) ) {
+ fileSpec = g_strdup( buf + i + 1 );
+ g_strstrip( fileSpec );
+ }
+ }
+ }
+ }
+ fclose( fp );
+ }
+
+ if( fileSpec == NULL ) {
+ // Use the home directory
+ str[ len ] = '\0';
+ fileSpec = g_strdup( str );
+ }
+
+ return fileSpec;
+}
+
+/*
+* Attempt to read file, testing for valid VCard format.
+* Return: TRUE if file appears to be valid format.
+*/
+gint vcard_test_read_file( const gchar *fileSpec ) {
+ gboolean haveStart;
+ gchar *tagtemp = NULL, *tagname = NULL, *tagvalue = NULL, *tagtype = NULL, *tagrest = NULL, *line;
+ VCardFile *cardFile;
+ gint retVal, lines;
+
+ if( ! fileSpec ) return MGU_NO_FILE;
+
+ cardFile = vcard_create_path( fileSpec );
+ cardFile->retVal = MGU_SUCCESS;
+ vcard_open_file( cardFile );
+ if( cardFile->retVal == MGU_SUCCESS ) {
+ cardFile->retVal = MGU_BAD_FORMAT;
+ haveStart = FALSE;
+ lines = VCARD_TEST_LINES;
+ while( lines > 0 ) {
+ lines--;
+ if( ( line = vcard_get_line( cardFile ) ) == NULL ) break;
+
+ /* Parse line */
+ tagtemp = vcard_get_tagname( line, VCARD_SEP_TAG );
+ if( tagtemp ) {
+ tagvalue = vcard_get_tagvalue( line, VCARD_SEP_TAG );
+ tagname = vcard_get_tagname( tagtemp, VCARD_SEP_TYPE );
+ tagtype = vcard_get_tagvalue( tagtemp, VCARD_SEP_TYPE );
+ if( tagname == NULL ) {
+ tagname = tagtemp;
+ tagtemp = NULL;
+ }
+
+ if( tagvalue ) {
+ if( g_strcasecmp( tagtype, VCARD_TYPE_QP ) == 0 ) {
+ // Quoted-Printable: could span multiple lines
+ tagvalue = vcard_read_qp( cardFile, tagvalue );
+ vcard_unescape_qp( tagvalue );
+ }
+
+ if( g_strcasecmp( tagname, VCARD_TAG_START ) == 0 && g_strcasecmp( tagvalue, VCARD_NAME ) == 0 ) {
+ haveStart = TRUE;
+ }
+ if( g_strcasecmp( tagname, VCARD_TAG_END ) == 0 && g_strcasecmp( tagvalue, VCARD_NAME ) == 0 ) {
+ // VCard is complete
+ if( haveStart ) cardFile->retVal = MGU_SUCCESS;
+ }
+ g_free( tagvalue );
+ }
+ g_free( tagname );
+ g_free( tagtype );
+ }
+ }
+ vcard_close_file( cardFile );
+ }
+ retVal = cardFile->retVal;
+ vcard_free( cardFile );
+ cardFile = NULL;
+ return retVal;
+}
+
+/*
+* End of Source.
+*/
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * Definitions necessary to access VCard files. VCard files are used
+ * by GnomeCard for addressbook, and Netscape for sending business
+ * card information. Refer to RFC2426 for more information.
+ */
+
+#ifndef __VCARD_H__
+#define __VCARD_H__
+
+#include <time.h>
+#include <stdio.h>
+#include <glib.h>
+
+#include "mgutils.h"
+
+#define VCARDBUFSIZE 1024
+
+#define VCARD_TAG_START "begin"
+#define VCARD_TAG_END "end"
+#define VCARD_NAME "vcard"
+
+#define VCARD_TAG_FULLNAME "fn"
+#define VCARD_TAG_NAME "n"
+#define VCARD_TAG_EMAIL "email"
+#define VCARD_TAG_UID "uid"
+
+#define VCARD_TYPE_QP "quoted-printable"
+
+#define VCARD_SEP_TAG ':'
+#define VCARD_SEP_TYPE ';'
+
+/*
+// Typical VCard entry:
+//
+// BEGIN:VCARD
+// FN:Axle Rose
+// N:Rose;Axle;D;Ms;Jnr
+// REV:2001-04-22T03:52:05
+// ADR;HOME:;;777 Lexington Avenue;Denver;CO;80299;USA
+// ADR;POSTAL:P O Box 777;;;Denver;CO;80298;Usa
+// TEL;HOME:303-555-1234
+// EMAIL;AOL:axlerose@aol.com
+// EMAIL;INTERNET:axlerose@netscape.net
+// TITLE:Janitor
+// ORG:The Company
+// URL:http://www.axlerose.com
+// END:VCARD
+*/
+
+// VCard object
+typedef struct _VCardFile VCardFile;
+struct _VCardFile {
+ gchar *name;
+ FILE *file;
+ gchar *path;
+ AddressCache *addressCache;
+ gchar buffer[ VCARDBUFSIZE ];
+ gchar *bufptr;
+ gint retVal;
+};
+
+/* Function prototypes */
+VCardFile *vcard_create();
+VCardFile *vcard_create_path( const gchar *path );
+void vcard_force_refresh( VCardFile *cardFile );
+void vcard_free( VCardFile *cardFile );
+gint vcard_read_data( VCardFile *cardFile );
+GList *vcard_get_address_list( VCardFile *cardFile );
+gboolean vcard_validate( const VCardFile *cardFile );
+gchar *vcard_find_gnomecard( void );
+gint vcard_test_read_file( const gchar *fileSpec );
+
+#endif /* __VCARD_H__ */