Import Mutt address book. Modified ImportLDIF into wizard.
authorMatch Grun <match@dimensional.com>
Mon, 29 Oct 2001 06:59:14 +0000 (06:59 +0000)
committerMatch Grun <match@dimensional.com>
Mon, 29 Oct 2001 06:59:14 +0000 (06:59 +0000)
src/Makefile.am
src/addressbook.c
src/importldif.c
src/importmutt.c [new file with mode: 0644]
src/importmutt.h [new file with mode: 0644]
src/ldif.c
src/ldif.h
src/mgutils.c
src/mgutils.h
src/mutt.c [new file with mode: 0644]
src/mutt.h [new file with mode: 0644]

index e83a5fdc11f9c9433dc1fc9a221bf029866c61c2..b027ff540652fa06c8a94bbf2a21dded3f2cdec0 100644 (file)
@@ -45,6 +45,8 @@ sylpheed_SOURCES = \
        vcard.c vcard.h \
        ldif.c ldif.h \
        importldif.c importldif.h \
+       mutt.c mutt.h \
+       importmutt.c importmutt.h \
        jpilot.c jpilot.h \
        syldap.c syldap.h \
        editbook.c editbook.h \
index 88ccdc142f4043369dc0843f9f971fe05d24bac7..73be2e10b34cd5fb222f262e317de773fcdec502 100644 (file)
@@ -75,6 +75,8 @@
 #include "editbook.h"
 #include "ldif.h"
 #include "importldif.h"
+#include "mutt.h"
+#include "importmutt.h"
 
 #ifdef USE_JPILOT
 #include "jpilot.h"
@@ -337,13 +339,14 @@ static void addressbook_list_select_clear (void);
 static void addressbook_list_select_add                (AddressObject *obj);
 static void addressbook_list_select_remove     (AddressObject *obj);
 
-static void addressbook_import_ldif_cb         (void);
+static void addressbook_import_ldif_cb         ();
+static void addressbook_import_mutt_cb         ();
 
 static GtkItemFactoryEntry addressbook_entries[] =
 {
        {N_("/_File"),                  NULL,           NULL, 0, "<Branch>"},
        {N_("/_File/New _Book"),        "<alt>B",       addressbook_new_book_cb,        0, NULL},
-       {N_("/_File/New _vCard"),       "<alt>D",       addressbook_new_vcard_cb,       0, NULL},
+       {N_("/_File/New _V-Card"),      "<alt>D",       addressbook_new_vcard_cb,       0, NULL},
 #ifdef USE_JPILOT
        {N_("/_File/New _J-Pilot"),     "<alt>J",       addressbook_new_jpilot_cb,      0, NULL},
 #endif
@@ -363,8 +366,9 @@ static GtkItemFactoryEntry addressbook_entries[] =
        {N_("/_Address/---"),           NULL,           NULL, 0, "<Separator>"},
        {N_("/_Address/_Edit"),         "<alt>Return",  addressbook_edit_address_cb,    0, NULL},
        {N_("/_Address/_Delete"),       NULL,           addressbook_delete_address_cb,  0, NULL},
-       {N_("/_Tools"),                 NULL,           NULL, 0, "<Branch>"},
-       {N_("/_Tools/Import _LDIF file"), NULL,         addressbook_import_ldif_cb,     0, NULL},
+       {N_("/_Tools/---"),             NULL,           NULL, 0, "<Separator>"},
+       {N_("/_Tools/Import _LDIF"),    NULL,           addressbook_import_ldif_cb,     0, NULL},
+       {N_("/_Tools/Import M_utt"),    NULL,           addressbook_import_mutt_cb,     0, NULL},
        {N_("/_Help"),                  NULL,           NULL, 0, "<LastBranch>"},
        {N_("/_Help/_About"),           NULL,           about_show, 0, NULL}
 };
@@ -377,10 +381,10 @@ static GtkItemFactoryEntry addressbook_entries[] =
        {N_("/_Edit/_Paste"),           "<ctl>V",       NULL,                           0, NULL},
        {N_("/_Tools"),                 NULL,           NULL, 0, "<Branch>"},
        {N_("/_Tools/Import _Mozilla"), NULL,           NULL,                           0, NULL},
-       {N_("/_Tools/Import _vCard"),   NULL,           NULL,                           0, NULL},
+       {N_("/_Tools/Import _V-Card"),  NULL,           NULL,                           0, NULL},
        {N_("/_Tools/---"),             NULL,           NULL, 0, "<Separator>"},
-       {N_("/_Tools/Export _LDIF file"), NULL,         NULL,                           0, NULL},
-       {N_("/_Tools/Export v_Card"),   NULL,           NULL,                           0, NULL},
+       {N_("/_Tools/Export _LDIF"),    NULL,           NULL,                           0, NULL},
+       {N_("/_Tools/Export V-_Card"),  NULL,           NULL,                           0, NULL},
 */
 
 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
@@ -1001,7 +1005,7 @@ static void addressbook_to_clicked(GtkButton *button, gpointer data)
 
 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
        menu_set_sensitive( addrbook.menu_factory, "/File/New Book",    sensitive );
-       menu_set_sensitive( addrbook.menu_factory, "/File/New vCard",  sensitive );
+       menu_set_sensitive( addrbook.menu_factory, "/File/New V-Card",  sensitive );
 #ifdef USE_JPILOT
        menu_set_sensitive( addrbook.menu_factory, "/File/New J-Pilot", sensitive );
 #endif
@@ -1878,7 +1882,7 @@ static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget
                /* Edit person - basic page */
                ItemPerson *person = ( ItemPerson * ) obj;
                if( addressbook_edit_person( abf, NULL, person, FALSE ) == NULL ) return;
-               gtk_ctree_select( ctree, addrbook.opened );
+               gtk_ctree_select( ctree, addrbook.opened);
                invalidate_address_completion();
                return;
        }
@@ -2702,7 +2706,7 @@ static void addressbook_delete_object(AddressObject *obj) {
        if (!obj) return;
 
        /* Remove data source. */
-       printf( "Delete obj type : %d\n", obj->type );
+       /* printf( "Delete obj type : %d\n", obj->type ); */
 
        ads = ADAPTER_DSOURCE(obj);
        if( ads == NULL ) return;
@@ -3124,19 +3128,19 @@ void addrbookctl_build_map( GtkWidget *window ) {
        g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
        _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
 
-       /* vCard */
+       /* V-Card */
        atci = g_new0( AddressTypeControlItem, 1 );
        atci->objectType = ADDR_VCARD;
        atci->interfaceType = ADDR_IF_VCARD;
        atci->showInTree = TRUE;
        atci->treeExpand = TRUE;
        atci->treeLeaf = TRUE;
-       atci->displayName = _( "vCard" );
+       atci->displayName = _( "V-Card" );
        atci->iconXpm = vcardxpm;
        atci->maskXpm = vcardxpmmask;
        atci->iconXpmOpen = vcardxpm;
        atci->maskXpmOpen = vcardxpmmask;
-       atci->menuCommand = "/File/New vCard";
+       atci->menuCommand = "/File/New V-Card";
        g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
        _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
 
@@ -3465,24 +3469,60 @@ static void addressbook_import_ldif_cb() {
        GtkCTreeNode *newNode;
 
        adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
-       if ( !adapter || !adapter->treeNode ) return;
+       if( adapter ) {
+               if( adapter->treeNode ) {
+                       abf = addressbook_imp_ldif( _addressIndex_ );
+                       if( abf ) {
+                               ds = addrindex_index_add_datasource( _addressIndex_, ADDR_IF_BOOK, abf );
+                               ads = addressbook_create_ds_adapter( ds, ADDR_BOOK, NULL );
+                               addressbook_ads_set_name( ads, abf->name );
+                               newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
+                               if( newNode ) {
+                                       gtk_ctree_select( GTK_CTREE(addrbook.ctree), newNode );
+                                       addrbook.treeSelected = newNode;
+                               }
+
+                               /* Notify address completion */
+                               invalidate_address_completion();
+                       }
+               }
+       }
 
-       abf = addressbook_imp_ldif( _addressIndex_ );
-       if ( !abf ) return;
+}
 
-       ds = addrindex_index_add_datasource( _addressIndex_, ADDR_IF_BOOK, abf );
-       ads = addressbook_create_ds_adapter( ds, ADDR_BOOK, NULL );
-       addressbook_ads_set_name( ads, abf->name );
-       newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
-       if ( newNode ) {
-               gtk_ctree_select( GTK_CTREE(addrbook.ctree), newNode );
-               addrbook.treeSelected = newNode;
+/*
+* Import MUTT file.
+*/
+static void addressbook_import_mutt_cb() {
+       AddressDataSource *ds = NULL;
+       AdapterDSource *ads = NULL;
+       AddressBookFile *abf = NULL;
+       AdapterInterface *adapter;
+       GtkCTreeNode *newNode;
+
+       adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
+       if( adapter ) {
+               if( adapter->treeNode ) {
+                       abf = addressbook_imp_mutt( _addressIndex_ );
+                       if( abf ) {
+                               ds = addrindex_index_add_datasource( _addressIndex_, ADDR_IF_BOOK, abf );
+                               ads = addressbook_create_ds_adapter( ds, ADDR_BOOK, NULL );
+                               addressbook_ads_set_name( ads, abf->name );
+                               newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
+                               if( newNode ) {
+                                       gtk_ctree_select( GTK_CTREE(addrbook.ctree), newNode );
+                                       addrbook.treeSelected = newNode;
+                               }
+
+                               /* Notify address completion */
+                               invalidate_address_completion();
+                       }
+               }
        }
 
-       /* Notify address completion */
-       invalidate_address_completion();
 }
 
 /*
 * End of Source.
 */
+
index 2307eb9590f78141cd03650f2365065084c65988..4539c2eb9faa6f7de267a9bb7ad967f00661f300 100644 (file)
 #include "mgutils.h"
 #include "ldif.h"
 
+#include "pixmaps/mark.xpm"
+
 #define IMPORTLDIF_GUESS_NAME "LDIF Import"
 
+#define PAGE_FILE_INFO             0
+#define PAGE_ATTRIBUTES            1
+#define PAGE_FINISH                2
+
+#define IMPORTLDIF_WIDTH           380
+#define IMPORTLDIF_HEIGHT          300
+
+#define FIELDS_N_COLS              3
+#define FIELDS_COL_WIDTH_SELECT    10
+#define FIELDS_COL_WIDTH_FIELD     140
+#define FIELDS_COL_WIDTH_ATTRIB    140
+
+typedef enum {
+       FIELD_COL_SELECT  = 0,
+       FIELD_COL_FIELD   = 1,
+       FIELD_COL_ATTRIB  = 2
+} ImpLdif_FieldColPos;
+
 static struct _ImpLdif_Dlg {
        GtkWidget *window;
+       GtkWidget *notebook;
        GtkWidget *file_entry;
        GtkWidget *name_entry;
-       GtkWidget *ok_btn;
-       GtkWidget *cancel_btn;
+       GtkWidget *clist_field;
+       GtkWidget *name_ldif;
+       GtkWidget *name_attrib;
+       GtkWidget *check_select;
+       GtkWidget *labelBook;
+       GtkWidget *labelFile;
+       GtkWidget *labelRecords;
+       GtkWidget *btnPrev;
+       GtkWidget *btnNext;
+       GtkWidget *btnCancel;
        GtkWidget *statusbar;
-       gint status_cid;
+       gint      status_cid;
+       gint      rowIndSelect;
+       gint      rowCount;
+       gchar     *nameBook;
+       gchar     *fileName;
+       gboolean  cancelled;
 } impldif_dlg;
 
 static struct _AddressFileSelection _imp_ldif_file_selector_;
 static AddressBookFile *_importedBook_;
 static AddressIndex *_imp_addressIndex_;
+static LdifFile *_ldifFile_ = NULL;
 
-/*
-* Edit functions.
-*/
-void imp_ldif_status_show( gchar *msg ) {
+static GdkPixmap *markxpm;
+static GdkBitmap *markxpmmask;
+
+static void imp_ldif_status_show( gchar *msg ) {
        if( impldif_dlg.statusbar != NULL ) {
                gtk_statusbar_pop( GTK_STATUSBAR(impldif_dlg.statusbar), impldif_dlg.status_cid );
                if( msg ) {
@@ -74,6 +109,23 @@ void imp_ldif_status_show( gchar *msg ) {
        }
 }
 
+static void imp_ldif_message( void ) {
+       gchar *sMsg = NULL;
+       gint pageNum;
+
+       pageNum = gtk_notebook_current_page( GTK_NOTEBOOK(impldif_dlg.notebook) );
+       if( pageNum == PAGE_FILE_INFO ) {
+               sMsg = _( "Please specify address book name and file to import." );
+       }
+       else if( pageNum == PAGE_ATTRIBUTES ) {
+               sMsg = _( "Select and rename LDIF field names to import." );
+       }
+       else if( pageNum == PAGE_FINISH ) {
+               sMsg = _( "File imported." );
+       }
+       imp_ldif_status_show( sMsg );
+}
+
 static gchar *imp_ldif_guess_file( AddressBookFile *abf ) {
        gchar *newFile = NULL;
        GList *fileList = NULL;
@@ -88,11 +140,123 @@ static gchar *imp_ldif_guess_file( AddressBookFile *abf ) {
        return newFile;
 }
 
-static gboolean imp_ldif_import_file( gchar *sName, gchar *sFile ) {
+static void imp_ldif_update_row( GtkCList *clist ) {
+       Ldif_FieldRec *rec;
+       gchar *text[ FIELDS_N_COLS ];
+       gint row;
+
+       if( impldif_dlg.rowIndSelect < 0 ) return;
+       row = impldif_dlg.rowIndSelect;
+
+       rec = gtk_clist_get_row_data( clist, row );
+       text[ FIELD_COL_SELECT ] = "";
+       text[ FIELD_COL_FIELD  ] = rec->tagName;
+       text[ FIELD_COL_ATTRIB ] = rec->userName;
+
+       gtk_clist_freeze( clist );
+       gtk_clist_remove( clist, row );
+       if( row == impldif_dlg.rowCount - 1 ) {
+               gtk_clist_append( clist, text );
+       }
+       else {
+               gtk_clist_insert( clist, row, text );
+       }
+       if( rec->selected )
+               gtk_clist_set_pixmap( clist, row, FIELD_COL_SELECT, markxpm, markxpmmask );
+
+       gtk_clist_set_row_data( clist, row, rec );
+       gtk_clist_thaw( clist );
+}
+
+static void imp_ldif_load_fields( LdifFile *ldf ) {
+       GtkCList *clist = GTK_CLIST(impldif_dlg.clist_field);
+       GList *node, *list;
+       gchar *text[ FIELDS_N_COLS ];
+
+       impldif_dlg.rowIndSelect = -1;
+       impldif_dlg.rowCount = 0;
+       if( ! ldf->accessFlag ) return;
+       gtk_clist_clear( clist );
+       list = ldif_get_fieldlist( ldf );
+       node = list;
+       while( node ) {
+               Ldif_FieldRec *rec = node->data;
+               gint row;
+
+               if( ! rec->reserved ) {
+                       text[ FIELD_COL_SELECT ] = "";
+                       text[ FIELD_COL_FIELD  ] = rec->tagName;
+                       text[ FIELD_COL_ATTRIB ] = rec->userName;
+                       row = gtk_clist_append( clist, text );
+                       gtk_clist_set_row_data( clist, row, rec );
+                       if( rec->selected )
+                               gtk_clist_set_pixmap( clist, row, FIELD_COL_SELECT, markxpm, markxpmmask );
+                       impldif_dlg.rowCount++;
+               }
+               node = g_list_next( node );
+       }
+       g_list_free( list );
+       list = NULL;
+       ldif_set_accessed( ldf, FALSE );
+}
+
+static void imp_ldif_field_list_selected( GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer data ) {
+       Ldif_FieldRec *rec = gtk_clist_get_row_data( clist, row );
+
+       impldif_dlg.rowIndSelect = row;
+       gtk_entry_set_text( GTK_ENTRY(impldif_dlg.name_attrib), "" );
+       if( rec ) {
+               gtk_label_set_text( GTK_LABEL(impldif_dlg.name_ldif), rec->tagName );
+               if( rec->userName )
+                       gtk_entry_set_text( GTK_ENTRY(impldif_dlg.name_attrib), rec->userName );
+               gtk_toggle_button_set_active(
+                       GTK_TOGGLE_BUTTON( impldif_dlg.check_select),
+                       rec->selected );
+       }
+       gtk_widget_grab_focus(impldif_dlg.name_attrib);
+}
+
+static void imp_ldif_field_list_toggle( GtkCList *clist, GdkEventButton *event, gpointer data ) {
+       if( ! event ) return;
+       if( impldif_dlg.rowIndSelect < 0 ) return;
+       if( event->button = 1 ) {
+               if( event->type == GDK_2BUTTON_PRESS ) {
+                       Ldif_FieldRec *rec = gtk_clist_get_row_data( clist, impldif_dlg.rowIndSelect );
+                       if( rec ) {
+                               rec->selected = ! rec->selected;
+                               imp_ldif_update_row( clist );
+                       }
+               }
+       }
+}
+
+static void imp_ldif_modify_pressed( GtkWidget *widget, gpointer data ) {
+       GtkCList *clist = GTK_CLIST(impldif_dlg.clist_field);
+       Ldif_FieldRec *rec;
+       gint row;
+
+       if( impldif_dlg.rowIndSelect < 0 ) return;
+       row = impldif_dlg.rowIndSelect;
+       rec = gtk_clist_get_row_data( clist, impldif_dlg.rowIndSelect );
+
+       g_free( rec->userName );
+       rec->userName = g_strdup( gtk_editable_get_chars( GTK_EDITABLE(impldif_dlg.name_attrib), 0, -1 ) );
+       rec->selected = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( impldif_dlg.check_select) );
+       imp_ldif_update_row( clist );
+       gtk_clist_select_row( clist, row, 0 );
+       gtk_label_set_text( GTK_LABEL(impldif_dlg.name_ldif), "" );
+       gtk_entry_set_text( GTK_ENTRY(impldif_dlg.name_attrib), "" );
+       gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( impldif_dlg.check_select), FALSE );
+}
+
+/*
+* Move off fields page.
+* return: TRUE if OK to move off page.
+*/
+static gboolean imp_ldif_field_move() {
        gboolean retVal = FALSE;
        gchar *newFile;
        AddressBookFile *abf = NULL;
-       LdifFile *ldf = NULL;
 
        if( _importedBook_ ) {
                addrbook_free_book( _importedBook_ );
@@ -100,15 +264,13 @@ static gboolean imp_ldif_import_file( gchar *sName, gchar *sFile ) {
 
        abf = addrbook_create_book();
        addrbook_set_path( abf, _imp_addressIndex_->filePath );
-       addrbook_set_name( abf, sName );
+       addrbook_set_name( abf, impldif_dlg.nameBook );
        newFile = imp_ldif_guess_file( abf );
        addrbook_set_file( abf, newFile );
        g_free( newFile );
 
-       // Import data into file
-       ldf = ldif_create();
-       ldif_set_file( ldf, sFile );
-       if( ldif_import_data( ldf, abf->addressCache ) == MGU_SUCCESS ) {
+       /* Import data into file */
+       if( ldif_import_data( _ldifFile_, abf->addressCache ) == MGU_SUCCESS ) {
                addrbook_save_data( abf );
                abf->dirtyFlag = TRUE;
                _importedBook_ = abf;
@@ -121,7 +283,12 @@ static gboolean imp_ldif_import_file( gchar *sName, gchar *sFile ) {
        return retVal;
 }
 
-static void imp_ldif_ok( GtkWidget *widget, gboolean *cancelled ) {
+/*
+* Move off fields page.
+* return: TRUE if OK to move off page.
+*/
+static gboolean imp_ldif_file_move() {
+       gboolean retVal = FALSE;
        gchar *sName;
        gchar *sFile;
        gchar *sMsg = NULL;
@@ -129,43 +296,119 @@ static void imp_ldif_ok( GtkWidget *widget, gboolean *cancelled ) {
 
        sFile = gtk_editable_get_chars( GTK_EDITABLE(impldif_dlg.file_entry), 0, -1 );
        g_strchug( sFile ); g_strchomp( sFile );
-       gtk_entry_set_text( GTK_ENTRY(impldif_dlg.file_entry), sFile );
 
        sName = gtk_editable_get_chars( GTK_EDITABLE(impldif_dlg.name_entry), 0, -1 );
        g_strchug( sName ); g_strchomp( sName );
+
+       g_free( impldif_dlg.nameBook );
+       g_free( impldif_dlg.fileName );
+       impldif_dlg.nameBook = sName;
+       impldif_dlg.fileName = sFile;
+
+       gtk_entry_set_text( GTK_ENTRY(impldif_dlg.file_entry), sFile );
        gtk_entry_set_text( GTK_ENTRY(impldif_dlg.name_entry), sName );
 
        if( *sFile == '\0'|| strlen( sFile ) < 1 ) {
                sMsg = _( "Please select a file." );
+               gtk_widget_grab_focus(impldif_dlg.file_entry);
                errFlag = TRUE;
        }
 
        if( *sName == '\0'|| strlen( sName ) < 1 ) {
                if( ! errFlag ) sMsg = _( "Address book name must be supplied." );
+               gtk_widget_grab_focus(impldif_dlg.name_entry);
                errFlag = TRUE;
        }
 
-       if( errFlag ) {
-               imp_ldif_status_show( sMsg );
-       }
-       else {
-               /* Import the file */
-               if( imp_ldif_import_file( sName, sFile ) ) {
-                       *cancelled = FALSE;
-                       gtk_main_quit();
+       if( errFlag ) {
+               /* Read attribute list */
+               ldif_set_file( _ldifFile_, sFile );
+               if( ldif_read_tags( _ldifFile_ ) == MGU_SUCCESS ) {
+                       /* Load fields */
+                       // ldif_print_file( _ldifFile_, stdout );
+                       imp_ldif_load_fields( _ldifFile_ );
+                       retVal = TRUE;
                }
                else {
-                       imp_ldif_status_show( _( "Error importing LDIF file." ) );
+                       sMsg = _( "Error reading LDIF fields." );
                }
        }
+       imp_ldif_status_show( sMsg );
 
-       g_free( sFile );
-       g_free( sName );
+       return retVal;
+}
 
+/*
+ * Display finish page.
+ */
+static void imp_ldif_finish_show() {
+       gchar *recs;
+       gchar *sMsg;
+
+       recs = g_strdup_printf( "%d", _ldifFile_->importCount );
+       gtk_label_set_text( GTK_LABEL(impldif_dlg.labelBook),
+               gtk_editable_get_chars( GTK_EDITABLE(impldif_dlg.name_entry), 0, -1 ) );
+       gtk_label_set_text( GTK_LABEL(impldif_dlg.labelFile), _ldifFile_->path );
+       gtk_label_set_text( GTK_LABEL(impldif_dlg.labelRecords), recs );
+       g_free( recs );
+       gtk_widget_set_sensitive( impldif_dlg.btnPrev, FALSE );
+       gtk_widget_set_sensitive( impldif_dlg.btnNext, FALSE );
+       if( _ldifFile_->retVal == MGU_SUCCESS ) {
+               sMsg = _( "LDIF file imported successfully." );
+       }
+       else {
+               sMsg = mgu_error2string( _ldifFile_->retVal );
+       }
+       imp_ldif_status_show( sMsg );
+       gtk_widget_grab_focus(impldif_dlg.btnCancel);
 }
 
-static void imp_ldif_cancel( GtkWidget *widget, gboolean *cancelled ) {
-       *cancelled = TRUE;
+static void imp_ldif_prev( GtkWidget *widget ) {
+       gint pageNum;
+
+       pageNum = gtk_notebook_current_page( GTK_NOTEBOOK(impldif_dlg.notebook) );
+       if( pageNum == PAGE_ATTRIBUTES ) {
+               /* Goto file page stuff */
+               gtk_notebook_set_page(
+                       GTK_NOTEBOOK(impldif_dlg.notebook), PAGE_FILE_INFO );
+               gtk_widget_set_sensitive( impldif_dlg.btnPrev, FALSE );
+       }
+       imp_ldif_message();
+}
+
+static void imp_ldif_next( GtkWidget *widget ) {
+       gint pageNum;
+
+       pageNum = gtk_notebook_current_page( GTK_NOTEBOOK(impldif_dlg.notebook) );
+       if( pageNum == PAGE_FILE_INFO ) {
+               /* Goto attributes stuff */
+               if( imp_ldif_file_move() ) {
+                       gtk_notebook_set_page(
+                               GTK_NOTEBOOK(impldif_dlg.notebook), PAGE_ATTRIBUTES );
+                       imp_ldif_message();
+                       gtk_widget_set_sensitive( impldif_dlg.btnPrev, TRUE );
+               }
+               else {
+                       gtk_widget_set_sensitive( impldif_dlg.btnPrev, FALSE );
+               }
+       }
+       else if( pageNum == PAGE_ATTRIBUTES ) {
+               /* Goto finish stuff */
+               if( imp_ldif_field_move() ) {
+                       gtk_notebook_set_page(
+                               GTK_NOTEBOOK(impldif_dlg.notebook), PAGE_FINISH );
+                       imp_ldif_finish_show();
+               }
+       }
+}
+
+static void imp_ldif_cancel( GtkWidget *widget, gpointer data ) {
+       gint pageNum;
+
+       pageNum = gtk_notebook_current_page( GTK_NOTEBOOK(impldif_dlg.notebook) );
+       if( pageNum != PAGE_FINISH ) {
+               impldif_dlg.cancelled = TRUE;
+       }
        gtk_main_quit();
 }
 
@@ -199,20 +442,22 @@ static void imp_ldif_file_select_create( AddressFileSelection *afs ) {
        fileSelector = gtk_file_selection_new( _("Select LDIF 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 (imp_ldif_file_ok), ( gpointer ) afs );
+               "clicked", GTK_SIGNAL_FUNC (imp_ldif_file_ok), ( gpointer ) afs );
        gtk_signal_connect( GTK_OBJECT (GTK_FILE_SELECTION(fileSelector)->cancel_button),
-                             "clicked", GTK_SIGNAL_FUNC (imp_ldif_file_cancel), ( gpointer ) afs );
+               "clicked", GTK_SIGNAL_FUNC (imp_ldif_file_cancel), ( gpointer ) afs );
        afs->fileSelector = fileSelector;
        afs->cancelled = TRUE;
 }
 
 static void imp_ldif_file_select( void ) {
        gchar *sFile;
-       if (! _imp_ldif_file_selector_.fileSelector )
+       if! _imp_ldif_file_selector_.fileSelector )
                imp_ldif_file_select_create( & _imp_ldif_file_selector_ );
 
        sFile = gtk_editable_get_chars( GTK_EDITABLE(impldif_dlg.file_entry), 0, -1 );
-       gtk_file_selection_set_filename( GTK_FILE_SELECTION( _imp_ldif_file_selector_.fileSelector ), sFile );
+       gtk_file_selection_set_filename(
+               GTK_FILE_SELECTION( _imp_ldif_file_selector_.fileSelector ),
+               sFile );
        g_free( sFile );
        gtk_widget_show( _imp_ldif_file_selector_.fileSelector );
        gtk_grab_add( _imp_ldif_file_selector_.fileSelector );
@@ -224,15 +469,13 @@ static gint imp_ldif_delete_event( GtkWidget *widget, GdkEventAny *event, gboole
        return TRUE;
 }
 
-static void imp_ldif_key_pressed( GtkWidget *widget, GdkEventKey *event, gboolean *cancelled ) {
+static void imp_ldif_key_pressed( GtkWidget *widget, GdkEventKey *event, gpointer data ) {
        if (event && event->keyval == GDK_Escape) {
-               *cancelled = TRUE;
-               gtk_main_quit();
+               imp_ldif_cancel( widget, data );
        }
 }
 
-static void imp_ldif_create( gboolean *cancelled ) {
-       GtkWidget *window;
+static void imp_ldif_page_file( gint pageNum, gchar *pageLbl ) {
        GtkWidget *vbox;
        GtkWidget *table;
        GtkWidget *label;
@@ -240,29 +483,21 @@ static void imp_ldif_create( gboolean *cancelled ) {
        GtkWidget *name_entry;
        GtkWidget *hbbox;
        GtkWidget *hsep;
-       GtkWidget *ok_btn;
-       GtkWidget *cancel_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), _("Import LDIF file into Address Book") );
-       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(imp_ldif_delete_event),
-                          cancelled);
-       gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
-                          GTK_SIGNAL_FUNC(imp_ldif_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 );
+       gtk_container_add( GTK_CONTAINER( impldif_dlg.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( impldif_dlg.notebook ),
+               gtk_notebook_get_nth_page(
+                       GTK_NOTEBOOK( impldif_dlg.notebook ), pageNum ),
+               label );
 
        table = gtk_table_new(2, 3, FALSE);
        gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
@@ -272,80 +507,340 @@ static void imp_ldif_create( gboolean *cancelled ) {
 
        // 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);
+       label = gtk_label_new(_("Address Book"));
+       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);
+       gtk_table_attach(GTK_TABLE(table), name_entry, 1, 2, top, (top + 1),
+               GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 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);
+       label = gtk_label_new(_("File 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);
 
        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);
+       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);
+       gtk_table_attach(GTK_TABLE(table), file_btn, 2, 3, top, (top + 1),
+               GTK_FILL, 0, 3, 0);
 
-       // Status line
+       gtk_widget_show_all(vbox);
+
+       /* Button handler */
+       gtk_signal_connect(GTK_OBJECT(file_btn), "clicked",
+                          GTK_SIGNAL_FUNC(imp_ldif_file_select), NULL);
+
+       impldif_dlg.file_entry = file_entry;
+       impldif_dlg.name_entry = name_entry;
+}
+
+static void imp_ldif_page_fields( gint pageNum, gchar *pageLbl ) {
+       GtkWidget *vbox;
+       GtkWidget *vboxt;
+       GtkWidget *vboxb;
+       GtkWidget *buttonMod;
+
+       GtkWidget *table;
+       GtkWidget *label;
+       GtkWidget *clist_swin;
+       GtkWidget *clist_field;
+       GtkWidget *name_ldif;
+       GtkWidget *name_attrib;
+       GtkWidget *check_select;
+       gint top;
+
+       gchar *titles[ FIELDS_N_COLS ] =
+               { _("S"), _("LDIF Field"), _("Attribute Name") };
+       gint i;
+
+       vbox = gtk_vbox_new(FALSE, 8);
+       gtk_container_add( GTK_CONTAINER( impldif_dlg.notebook ), vbox );
+       gtk_container_set_border_width( GTK_CONTAINER (vbox), 4 );
+
+       label = gtk_label_new( pageLbl );
+       gtk_widget_show( label );
+       gtk_notebook_set_tab_label(
+               GTK_NOTEBOOK( impldif_dlg.notebook ),
+               gtk_notebook_get_nth_page(GTK_NOTEBOOK( impldif_dlg.notebook ), pageNum ),
+               label );
+
+       /* Upper area - Field list */
+       vboxt = gtk_vbox_new( FALSE, 4 );
+       gtk_container_add( GTK_CONTAINER( vbox ), vboxt );
+
+       clist_swin = gtk_scrolled_window_new( NULL, NULL );
+       gtk_container_add( GTK_CONTAINER(vboxt), clist_swin );
+       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
+                                      GTK_POLICY_AUTOMATIC,
+                                      GTK_POLICY_ALWAYS);
+
+       clist_field = gtk_clist_new_with_titles( FIELDS_N_COLS, titles );
+       gtk_container_add( GTK_CONTAINER(clist_swin), clist_field );
+       gtk_clist_set_selection_mode( GTK_CLIST(clist_field), GTK_SELECTION_BROWSE );
+       gtk_clist_set_column_width(
+                       GTK_CLIST(clist_field), FIELD_COL_SELECT, FIELDS_COL_WIDTH_SELECT );
+       gtk_clist_set_column_width(
+                       GTK_CLIST(clist_field), FIELD_COL_FIELD, FIELDS_COL_WIDTH_FIELD );
+       gtk_clist_set_column_width(
+                       GTK_CLIST(clist_field), FIELD_COL_ATTRIB, FIELDS_COL_WIDTH_ATTRIB );
+
+       for( i = 0; i < FIELDS_N_COLS; i++ )
+               GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist_field)->column[i].button, GTK_CAN_FOCUS);
+
+       /* Lower area - Edit area */
+       vboxb = gtk_vbox_new( FALSE, 4 );
+       gtk_box_pack_end(GTK_BOX(vbox), vboxb, FALSE, FALSE, 2);
+
+       /* Data entry area */
+       table = gtk_table_new( 3, 3, FALSE);
+       gtk_box_pack_start(GTK_BOX(vboxb), table, FALSE, FALSE, 0);
+       gtk_table_set_row_spacings(GTK_TABLE(table), 4);
+       gtk_table_set_col_spacings(GTK_TABLE(table), 4);
+
+       /* First row */
+       top = 0;
+       label = gtk_label_new(_("LDIF Field"));
+       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_ldif = gtk_label_new( "" );
+       gtk_misc_set_alignment(GTK_MISC(name_ldif), 0.01, 0.5);
+       gtk_table_attach(GTK_TABLE(table), name_ldif, 1, 3, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+       /* Second row */
+       ++top;
+       label = gtk_label_new(_("Attribute"));
+       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_attrib = gtk_entry_new();
+       gtk_table_attach(GTK_TABLE(table), name_attrib, 1, 3, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+       /* Next row */
+       ++top;
+       label = gtk_label_new(_("Select"));
+       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);
+
+       check_select = gtk_check_button_new();
+       gtk_table_attach(GTK_TABLE(table), check_select, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+       buttonMod = gtk_button_new_with_label( _("Modify"));
+       gtk_table_attach(GTK_TABLE(table), buttonMod, 2, 3, top, (top + 1), GTK_FILL, 0, 3, 0);
+
+       gtk_widget_show_all(vbox);
+
+       /* Event handlers */
+       gtk_signal_connect( GTK_OBJECT(clist_field), "select_row",
+                       GTK_SIGNAL_FUNC(imp_ldif_field_list_selected), NULL );
+       gtk_signal_connect( GTK_OBJECT(clist_field), "button_press_event",
+                       GTK_SIGNAL_FUNC(imp_ldif_field_list_toggle), NULL );
+       gtk_signal_connect( GTK_OBJECT(buttonMod), "clicked",
+                       GTK_SIGNAL_FUNC(imp_ldif_modify_pressed), NULL );
+
+       impldif_dlg.clist_field  = clist_field;
+       impldif_dlg.name_ldif    = name_ldif;
+       impldif_dlg.name_attrib  = name_attrib;
+       impldif_dlg.check_select = check_select;
+}
+
+static void imp_ldif_page_finish( gint pageNum, gchar *pageLbl ) {
+       GtkWidget *vbox;
+       GtkWidget *table;
+       GtkWidget *label;
+       GtkWidget *labelBook;
+       GtkWidget *labelFile;
+       GtkWidget *labelRecs;
+       GtkWidget *hbbox;
+       GtkWidget *hsep;
+       GtkWidget *file_btn;
+       GtkWidget *hsbox;
+       gint top;
+
+       vbox = gtk_vbox_new(FALSE, 8);
+       gtk_container_add( GTK_CONTAINER( impldif_dlg.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( impldif_dlg.notebook ),
+               gtk_notebook_get_nth_page( GTK_NOTEBOOK( impldif_dlg.notebook ), pageNum ), label );
+
+       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(_("Address Book :"));
+       gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+       gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+
+       labelBook = gtk_label_new(_(""));
+       gtk_table_attach(GTK_TABLE(table), labelBook, 1, 2, top, (top + 1), GTK_FILL, 0, 0, 0);
+       gtk_misc_set_alignment(GTK_MISC(labelBook), 0, 0.5);
+
+       /* Second row */
+       top++;
+       label = gtk_label_new(_("File 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), 1, 0.5);
+
+       labelFile = gtk_label_new(_(""));
+       gtk_table_attach(GTK_TABLE(table), labelFile, 1, 2, top, (top + 1), GTK_FILL, 0, 0, 0);
+       gtk_misc_set_alignment(GTK_MISC(labelFile), 0, 0.5);
+
+       /* Third row */
+       top++;
+       label = gtk_label_new(_("Records :"));
+       gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+       gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+
+       labelRecs = gtk_label_new(_(""));
+       gtk_table_attach(GTK_TABLE(table), labelRecs, 1, 2, top, (top + 1), GTK_FILL, 0, 0, 0);
+       gtk_misc_set_alignment(GTK_MISC(labelRecs), 0, 0.5);
+
+       impldif_dlg.labelBook    = labelBook;
+       impldif_dlg.labelFile    = labelFile;
+       impldif_dlg.labelRecords = labelRecs;
+}
+
+static void imp_ldif_dialog_create() {
+       GtkWidget *window;
+       GtkWidget *vbox;
+       GtkWidget *vnbox;
+       GtkWidget *notebook;
+       GtkWidget *hbbox;
+       GtkWidget *hsep;
+       GtkWidget *btnPrev;
+       GtkWidget *btnNext;
+       GtkWidget *btnCancel;
+       GtkWidget *hsbox;
+       GtkWidget *statusbar;
+
+       window = gtk_window_new(GTK_WINDOW_DIALOG);
+       gtk_widget_set_usize(window, IMPORTLDIF_WIDTH, IMPORTLDIF_HEIGHT );
+       gtk_container_set_border_width( GTK_CONTAINER(window), 0 );
+       gtk_window_set_title( GTK_WINDOW(window), _("Import LDIF file into Address Book") );
+       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(imp_ldif_delete_event),
+                          NULL );
+       gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
+                          GTK_SIGNAL_FUNC(imp_ldif_key_pressed),
+                          NULL );
+
+       vbox = gtk_vbox_new(FALSE, 4);
+       gtk_widget_show(vbox);
+       gtk_container_add(GTK_CONTAINER(window), vbox);
+
+       vnbox = gtk_vbox_new(FALSE, 4);
+       gtk_container_set_border_width(GTK_CONTAINER(vnbox), 4);
+       gtk_widget_show(vnbox);
+       gtk_box_pack_start(GTK_BOX(vbox), vnbox, TRUE, TRUE, 0);
+
+       /* Notebook */
+       notebook = gtk_notebook_new();
+       gtk_notebook_set_show_tabs( GTK_NOTEBOOK(notebook), FALSE );
+       gtk_widget_show(notebook);
+       gtk_box_pack_start(GTK_BOX(vnbox), 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);
+       /* Button panel */
+       gtkut_button_set_create( &hbbox, &btnPrev, _( "Prev" ),
+                       &btnNext, _( "Next" ), &btnCancel, _( "Dismiss" ) );
        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);
+       gtk_widget_grab_default(btnNext);
 
-       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(imp_ldif_ok), cancelled);
-       gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked",
-                          GTK_SIGNAL_FUNC(imp_ldif_cancel), cancelled);
-       gtk_signal_connect(GTK_OBJECT(file_btn), "clicked",
-                          GTK_SIGNAL_FUNC(imp_ldif_file_select), NULL);
+       /* Button handlers */
+       gtk_signal_connect(GTK_OBJECT(btnPrev), "clicked",
+                          GTK_SIGNAL_FUNC(imp_ldif_prev), NULL);
+       gtk_signal_connect(GTK_OBJECT(btnNext), "clicked",
+                          GTK_SIGNAL_FUNC(imp_ldif_next), NULL);
+       gtk_signal_connect(GTK_OBJECT(btnCancel), "clicked",
+                          GTK_SIGNAL_FUNC(imp_ldif_cancel), NULL);
 
        gtk_widget_show_all(vbox);
 
        impldif_dlg.window     = window;
-       impldif_dlg.file_entry = file_entry;
-       impldif_dlg.name_entry = name_entry;
-       impldif_dlg.ok_btn     = ok_btn;
-       impldif_dlg.cancel_btn = cancel_btn;
+       impldif_dlg.notebook   = notebook;
+       impldif_dlg.btnPrev    = btnPrev;
+       impldif_dlg.btnNext    = btnNext;
+       impldif_dlg.btnCancel  = btnCancel;
        impldif_dlg.statusbar  = statusbar;
-       impldif_dlg.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Import LDIF Dialog" );
+       impldif_dlg.status_cid = gtk_statusbar_get_context_id(
+                       GTK_STATUSBAR(statusbar), "Import LDIF Dialog" );
+
 }
 
-AddressBookFile *addressbook_imp_ldif( AddressIndex *addrIndex ) {
-       static gboolean cancelled;
+static void imp_ldif_create() {
+       imp_ldif_dialog_create();
+       imp_ldif_page_file( PAGE_FILE_INFO, _( "File Info" ) );
+       imp_ldif_page_fields( PAGE_ATTRIBUTES, _( "Attributes" ) );
+       imp_ldif_page_finish( PAGE_FINISH, _( "Finish" ) );
+       gtk_widget_show_all( impldif_dlg.window );
+}
 
+AddressBookFile *addressbook_imp_ldif( AddressIndex *addrIndex ) {
        _importedBook_ = NULL;
        _imp_addressIndex_ = addrIndex;
 
        if( ! impldif_dlg.window )
-               imp_ldif_create(&cancelled);
-       gtk_widget_grab_focus(impldif_dlg.ok_btn);
-       gtk_widget_grab_focus(impldif_dlg.file_entry);
+               imp_ldif_create();
+       impldif_dlg.cancelled = FALSE;
        gtk_widget_show(impldif_dlg.window);
        manage_window_set_transient(GTK_WINDOW(impldif_dlg.window));
+       gtk_widget_grab_default(impldif_dlg.btnNext);
 
-       imp_ldif_status_show( "" );
        gtk_entry_set_text( GTK_ENTRY(impldif_dlg.name_entry), IMPORTLDIF_GUESS_NAME );
+       gtk_entry_set_text( GTK_ENTRY(impldif_dlg.file_entry), "" );
+       gtk_label_set_text( GTK_LABEL(impldif_dlg.name_ldif), "" );
+       gtk_entry_set_text( GTK_ENTRY(impldif_dlg.name_attrib), "" );
+       gtk_clist_clear( GTK_CLIST(impldif_dlg.clist_field) );
+       gtk_notebook_set_page( GTK_NOTEBOOK(impldif_dlg.notebook), PAGE_FILE_INFO );
+       gtk_widget_set_sensitive( impldif_dlg.btnPrev, FALSE );
+       gtk_widget_set_sensitive( impldif_dlg.btnNext, TRUE );
+       PIXMAP_CREATE( impldif_dlg.window, markxpm, markxpmmask, mark_xpm);
+       imp_ldif_message();
+       gtk_widget_grab_focus(impldif_dlg.file_entry);
 
+       impldif_dlg.rowIndSelect = -1;
+       impldif_dlg.rowCount = 0;
+       g_free( impldif_dlg.nameBook );
+       g_free( impldif_dlg.fileName );
+       impldif_dlg.nameBook = NULL;
+       impldif_dlg.fileName = NULL;
+
+       _ldifFile_ = ldif_create();
        gtk_main();
        gtk_widget_hide(impldif_dlg.window);
+       ldif_free( _ldifFile_ );
+       _ldifFile_ = NULL;
        _imp_addressIndex_ = NULL;
 
-       if (cancelled == TRUE) return NULL;
+       g_free( impldif_dlg.nameBook );
+       g_free( impldif_dlg.fileName );
+       impldif_dlg.nameBook = NULL;
+       impldif_dlg.fileName = NULL;
+
+       if( impldif_dlg.cancelled == TRUE ) return NULL;
        return _importedBook_;
 }
 
diff --git a/src/importmutt.c b/src/importmutt.c
new file mode 100644 (file)
index 0000000..953a83e
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * 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.
+ */
+
+/*
+ * Import Mutt 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 "addrbook.h"
+#include "addressbook.h"
+#include "addressitem.h"
+#include "gtkutils.h"
+#include "prefs_common.h"
+#include "manage_window.h"
+#include "mgutils.h"
+#include "mutt.h"
+
+#define IMPORTMUTT_GUESS_NAME "MUTT Import"
+
+static struct _ImpMutt_Dlg {
+       GtkWidget *window;
+       GtkWidget *file_entry;
+       GtkWidget *name_entry;
+       GtkWidget *ok_btn;
+       GtkWidget *cancel_btn;
+       GtkWidget *statusbar;
+       gint status_cid;
+} impmutt_dlg;
+
+static struct _AddressFileSelection _imp_mutt_file_selector_;
+static AddressBookFile *_importedBook_;
+static AddressIndex *_imp_addressIndex_;
+
+/*
+* Edit functions.
+*/
+void imp_mutt_status_show( gchar *msg ) {
+       if( impmutt_dlg.statusbar != NULL ) {
+               gtk_statusbar_pop( GTK_STATUSBAR(impmutt_dlg.statusbar), impmutt_dlg.status_cid );
+               if( msg ) {
+                       gtk_statusbar_push( GTK_STATUSBAR(impmutt_dlg.statusbar), impmutt_dlg.status_cid, msg );
+               }
+       }
+}
+
+static gchar *imp_mutt_guess_file( AddressBookFile *abf ) {
+       gchar *newFile = NULL;
+       GList *fileList = NULL;
+       gint fileNum = 1;
+       fileList = addrbook_get_bookfile_list( abf );
+       if( fileList ) {
+               fileNum = 1 + abf->maxValue;
+       }
+       newFile = addrbook_gen_new_file_name( fileNum );
+       g_list_free( fileList );
+       fileList = NULL;
+       return newFile;
+}
+
+static gboolean imp_mutt_import_file( gchar *sName, gchar *sFile ) {
+       gboolean retVal = FALSE;
+       gchar *newFile;
+       AddressBookFile *abf = NULL;
+       MuttFile *mdf = NULL;
+
+       if( _importedBook_ ) {
+               addrbook_free_book( _importedBook_ );
+       }
+
+       abf = addrbook_create_book();
+       addrbook_set_path( abf, _imp_addressIndex_->filePath );
+       addrbook_set_name( abf, sName );
+       newFile = imp_mutt_guess_file( abf );
+       addrbook_set_file( abf, newFile );
+       g_free( newFile );
+
+       /* Import data from file */
+       mdf = mutt_create();
+       mutt_set_file( mdf, sFile );
+       if( mutt_import_data( mdf, abf->addressCache ) == MGU_SUCCESS ) {
+               addrbook_save_data( abf );
+               abf->dirtyFlag = TRUE;
+               _importedBook_ = abf;
+               retVal = TRUE;
+       }
+       else {
+               addrbook_free_book( abf );
+       }
+
+       return retVal;
+}
+
+static void imp_mutt_ok( GtkWidget *widget, gboolean *cancelled ) {
+       gchar *sName;
+       gchar *sFile;
+       gchar *sMsg = NULL;
+       gboolean errFlag = FALSE;
+
+       sFile = gtk_editable_get_chars( GTK_EDITABLE(impmutt_dlg.file_entry), 0, -1 );
+       g_strchug( sFile ); g_strchomp( sFile );
+       gtk_entry_set_text( GTK_ENTRY(impmutt_dlg.file_entry), sFile );
+
+       sName = gtk_editable_get_chars( GTK_EDITABLE(impmutt_dlg.name_entry), 0, -1 );
+       g_strchug( sName ); g_strchomp( sName );
+       gtk_entry_set_text( GTK_ENTRY(impmutt_dlg.name_entry), sName );
+
+       if( *sFile == '\0'|| strlen( sFile ) < 1 ) {
+               sMsg = _( "Please select a file." );
+               errFlag = TRUE;
+       }
+
+       if( *sName == '\0'|| strlen( sName ) < 1 ) {
+               if( ! errFlag ) sMsg = _( "Address book name must be supplied." );
+               errFlag = TRUE;
+       }
+
+       if( errFlag ) {
+               imp_mutt_status_show( sMsg );
+       }
+       else {
+               /* Import the file */
+               if( imp_mutt_import_file( sName, sFile ) ) {
+                       *cancelled = FALSE;
+                       gtk_main_quit();
+               }
+               else {
+                       imp_mutt_status_show( _( "Error importing MUTT file." ) );
+               }
+       }
+
+       g_free( sFile );
+       g_free( sName );
+
+}
+
+static void imp_mutt_cancel( GtkWidget *widget, gboolean *cancelled ) {
+       *cancelled = TRUE;
+       gtk_main_quit();
+}
+
+static void imp_mutt_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(impmutt_dlg.file_entry), sFile );
+       gtk_widget_hide( afs->fileSelector );
+       gtk_grab_remove( afs->fileSelector );
+       gtk_widget_grab_focus( impmutt_dlg.file_entry );
+       imp_mutt_status_show( _( "Please select a file to import." ) );
+}
+
+static void imp_mutt_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( impmutt_dlg.file_entry );
+}
+
+static void imp_mutt_file_select_create( AddressFileSelection *afs ) {
+       GtkWidget *fileSelector;
+
+       fileSelector = gtk_file_selection_new( _("Select MUTT 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 (imp_mutt_file_ok), ( gpointer ) afs );
+       gtk_signal_connect( GTK_OBJECT (GTK_FILE_SELECTION(fileSelector)->cancel_button),
+                             "clicked", GTK_SIGNAL_FUNC (imp_mutt_file_cancel), ( gpointer ) afs );
+       afs->fileSelector = fileSelector;
+       afs->cancelled = TRUE;
+}
+
+static void imp_mutt_file_select( void ) {
+       gchar *sFile;
+       if (! _imp_mutt_file_selector_.fileSelector )
+               imp_mutt_file_select_create( & _imp_mutt_file_selector_ );
+
+       sFile = gtk_editable_get_chars( GTK_EDITABLE(impmutt_dlg.file_entry), 0, -1 );
+       gtk_file_selection_set_filename( GTK_FILE_SELECTION( _imp_mutt_file_selector_.fileSelector ), sFile );
+       g_free( sFile );
+       gtk_widget_show( _imp_mutt_file_selector_.fileSelector );
+       gtk_grab_add( _imp_mutt_file_selector_.fileSelector );
+}
+
+static gint imp_mutt_delete_event( GtkWidget *widget, GdkEventAny *event, gboolean *cancelled ) {
+       *cancelled = TRUE;
+       gtk_main_quit();
+       return TRUE;
+}
+
+static void imp_mutt_key_pressed( GtkWidget *widget, GdkEventKey *event, gboolean *cancelled ) {
+       if (event && event->keyval == GDK_Escape) {
+               *cancelled = TRUE;
+               gtk_main_quit();
+       }
+}
+
+static void imp_mutt_create( gboolean *cancelled ) {
+       GtkWidget *window;
+       GtkWidget *vbox;
+       GtkWidget *table;
+       GtkWidget *label;
+       GtkWidget *file_entry;
+       GtkWidget *name_entry;
+       GtkWidget *hbbox;
+       GtkWidget *hsep;
+       GtkWidget *ok_btn;
+       GtkWidget *cancel_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), _("Import MUTT file into Address Book") );
+       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(imp_mutt_delete_event),
+                          cancelled);
+       gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
+                          GTK_SIGNAL_FUNC(imp_mutt_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);
+
+       // 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(imp_mutt_ok), cancelled);
+       gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked",
+                          GTK_SIGNAL_FUNC(imp_mutt_cancel), cancelled);
+       gtk_signal_connect(GTK_OBJECT(file_btn), "clicked",
+                          GTK_SIGNAL_FUNC(imp_mutt_file_select), NULL);
+
+       gtk_widget_show_all(vbox);
+
+       impmutt_dlg.window     = window;
+       impmutt_dlg.file_entry = file_entry;
+       impmutt_dlg.name_entry = name_entry;
+       impmutt_dlg.ok_btn     = ok_btn;
+       impmutt_dlg.cancel_btn = cancel_btn;
+       impmutt_dlg.statusbar  = statusbar;
+       impmutt_dlg.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Import Mutt Dialog" );
+}
+
+AddressBookFile *addressbook_imp_mutt( AddressIndex *addrIndex ) {
+       static gboolean cancelled;
+       gchar *muttFile;
+
+       _importedBook_ = NULL;
+       _imp_addressIndex_ = addrIndex;
+
+       if( ! impmutt_dlg.window )
+               imp_mutt_create(&cancelled);
+       gtk_widget_grab_focus(impmutt_dlg.ok_btn);
+       gtk_widget_grab_focus(impmutt_dlg.file_entry);
+       gtk_widget_show(impmutt_dlg.window);
+       manage_window_set_transient(GTK_WINDOW(impmutt_dlg.window));
+
+       imp_mutt_status_show( _( "Please select a file to import." ) );
+       muttFile = mutt_find_file();
+       gtk_entry_set_text( GTK_ENTRY(impmutt_dlg.name_entry), IMPORTMUTT_GUESS_NAME );
+       gtk_entry_set_text( GTK_ENTRY(impmutt_dlg.file_entry), muttFile );
+       g_free( muttFile );
+       muttFile = NULL;
+
+       gtk_main();
+       gtk_widget_hide(impmutt_dlg.window);
+       _imp_addressIndex_ = NULL;
+
+       if (cancelled == TRUE) return NULL;
+       return _importedBook_;
+}
+
+/*
+* End of Source.
+*/
+
diff --git a/src/importmutt.h b/src/importmutt.h
new file mode 100644 (file)
index 0000000..b87dc87
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+/*
+ * Import MUTT data.
+ */
+
+#ifndef __IMPORT_MUTT_H__
+#define __IMPORT_MUTT_H__
+
+// Function prototypes
+AddressBookFile *addressbook_imp_mutt( AddressIndex *addrIndex );
+
+#endif /* __IMPORT_MUTT_H__ */
+
+/*
+* End of Source.
+*/
+
index 056159f251f239a35e1f0d3885c8f7d2c78aa094..cd1cc38d20c58cf27ef4278921bdc18616a7606f 100644 (file)
@@ -18,7 +18,8 @@
  */
 
 /*
- * Functions necessary to access LDIF files (LDAP Data Interchange Format files).
+ * Functions necessary to access LDIF files (LDAP Data Interchange Format
+ * files).
  */
 
 #include <sys/stat.h>
 #include "addritem.h"
 #include "addrcache.h"
 
+#include "base64.h"
+
 /*
-* Create new cardfile object.
+* Create new object.
 */
 LdifFile *ldif_create() {
        LdifFile *ldifFile;
@@ -38,21 +41,89 @@ LdifFile *ldif_create() {
        ldifFile->path = NULL;
        ldifFile->file = NULL;
        ldifFile->bufptr = ldifFile->buffer;
+       ldifFile->hashFields = g_hash_table_new( g_str_hash, g_str_equal );
+       ldifFile->tempList = NULL;
+       ldifFile->dirtyFlag = TRUE;
+       ldifFile->accessFlag = FALSE;
        ldifFile->retVal = MGU_SUCCESS;
+       ldifFile->cbProgress = NULL;
+       ldifFile->importCount = 0;
        return ldifFile;
 }
 
 /*
 * Properties...
 */
-void ldif_set_file( LdifFileldifFile, const gchar *value ) {
+void ldif_set_file( LdifFile *ldifFile, const gchar *value ) {
        g_return_if_fail( ldifFile != NULL );
+
+       if( ldifFile->path ) {
+               if( strcmp( ldifFile->path, value ) != 0 )
+                       ldifFile->dirtyFlag = TRUE;
+       }
+       else {
+               ldifFile->dirtyFlag = TRUE;
+       }
        ldifFile->path = mgu_replace_string( ldifFile->path, value );
        g_strstrip( ldifFile->path );
+       ldifFile->importCount = 0;
+}
+void ldif_set_accessed( LdifFile *ldifFile, const gboolean value ) {
+       g_return_if_fail( ldifFile != NULL );
+       ldifFile->accessFlag = value;
+}
+
+/*
+* Register a callback function. When called, the function will be passed
+* the following arguments:
+*      LdifFile object,
+*      File size (long),
+*      Current position (long)
+* This can be used for a progress indicator.
+*/
+void ldif_set_callback( LdifFile *ldifFile, void *func ) {
+       ldifFile->cbProgress = func;
+}
+
+/*
+* Create field record object.
+*/
+static Ldif_FieldRec *ldif_create_fieldrec( gchar *field ) {
+       Ldif_FieldRec *rec = g_new0( Ldif_FieldRec, 1 );
+       rec->tagName = g_strdup( field );
+       rec->userName = NULL;
+       rec->reserved = FALSE;
+       rec->selected = FALSE;
+       return rec;
+}
+
+/*
+* Free field record object.
+*/
+static void ldif_free_fieldrec( Ldif_FieldRec *rec ) {
+       if( rec ) {
+               g_free( rec->tagName );
+               g_free( rec->userName );
+               rec->tagName = NULL;
+               rec->userName = NULL;
+               rec->reserved = FALSE;
+               rec->selected = FALSE;
+               g_free( rec );
+       }
+}
+
+/*
+* Free hash table entry visitor function.
+*/
+static gint ldif_hash_free_vis( gpointer key, gpointer value, gpointer data ) {
+       ldif_free_fieldrec( ( Ldif_FieldRec * ) value );
+       value = NULL;
+       key = NULL;
+       return -1;
 }
 
 /*
-* Free up cardfile object by releasing internal memory.
+* Free up object by releasing internal memory.
 */
 void ldif_free( LdifFile *ldifFile ) {
        g_return_if_fail( ldifFile != NULL );
@@ -63,14 +134,41 @@ void ldif_free( LdifFile *ldifFile ) {
        /* Free internal stuff */
        g_free( ldifFile->path );
 
+       /* Free field list */
+       g_hash_table_foreach_remove( ldifFile->hashFields, ldif_hash_free_vis, NULL );
+       g_hash_table_destroy( ldifFile->hashFields );
+       ldifFile->hashFields = NULL;
+
        /* Clear pointers */
        ldifFile->file = NULL;
        ldifFile->path = NULL;
        ldifFile->retVal = MGU_SUCCESS;
+       ldifFile->tempList = NULL;
+       ldifFile->dirtyFlag = FALSE;
+       ldifFile->accessFlag = FALSE;
+       ldifFile->cbProgress = NULL;
 
        /* Now release file object */
        g_free( ldifFile );
+}
 
+/*
+* Display field record.
+*/
+void ldif_print_fieldrec( Ldif_FieldRec *rec, FILE *stream ) {
+       fprintf( stream, "\ttag:\t%s", rec->reserved ? "yes" : "no" );
+       fprintf( stream, "\t%s", rec->selected ? "yes" : "no" );
+       fprintf( stream, "\t:%s:\t:%s:\n", rec->userName, rec->tagName );
+}
+
+/*
+* Display field record.
+ * 
+*/
+static void ldif_print_file_vis( gpointer key, gpointer value, gpointer data ) {
+       Ldif_FieldRec *rec = value;
+       FILE *stream = data;
+       ldif_print_fieldrec( rec, stream );
 }
 
 /*
@@ -81,6 +179,9 @@ void ldif_print_file( LdifFile *ldifFile, FILE *stream ) {
        fprintf( stream, "LDIF File:\n" );
        fprintf( stream, "file spec: '%s'\n", ldifFile->path );
        fprintf( stream, "  ret val: %d\n",   ldifFile->retVal );
+       fprintf( stream, "   fields: {\n" );
+       g_hash_table_foreach( ldifFile->hashFields, ldif_print_file_vis, stream );
+       fprintf( stream, "} ---\n" );
 }
 
 /*
@@ -138,26 +239,50 @@ static gchar *ldif_get_line( LdifFile *ldifFile ) {
                        if( *buf == '\0' ) return NULL;
                        break;
                }
+#if HAVE_DOSISH_SYSTEM
+#else
+               if( ch == '\r' ) continue;
+#endif
                if( ch == '\n' ) break;
                *ptr = ch;
                ptr++;
        }
 
-       /* Copy into private buffer */
+       /* Return a copy of buffer */
        return g_strdup( buf );
 }
 
 /*
 * Parse tag name from line buffer.
+* Enter: line   Buffer.
+*        flag64 Base-64 encoder flag.
 * Return: Buffer containing the tag name, or NULL if no delimiter char found.
+* If a double delimiter (::) is found, flag64 is set.
 */
-static gchar *ldif_get_tagname( char* line, gchar dlm ) {
+static gchar *ldif_get_tagname( char* line, gboolean *flag64 ) {
        gint len = 0;
        gchar *tag = NULL;
        gchar *lptr = line;
+       gchar *sptr = NULL;
+
        while( *lptr++ ) {
-               if( *lptr == dlm ) {
-                       len = lptr - line;
+               /* Check for language tag */
+               if( *lptr == LDIF_LANG_TAG ) {
+                       if( sptr == NULL ) sptr = lptr;
+               }
+
+               /* Check for delimiter */
+               if( *lptr == LDIF_SEP_TAG ) {
+                       if( sptr ) {
+                               len = sptr - line;
+                       }
+                       else {
+                               len = lptr - line;
+                       }
+
+                       /* Base-64 encoding? */
+                       if( * ++lptr == LDIF_SEP_TAG ) *flag64 = TRUE;
+
                        tag = g_strndup( line, len+1 );
                        tag[ len ] = '\0';
                        g_strdown( tag );
@@ -169,24 +294,27 @@ static gchar *ldif_get_tagname( char* line, gchar dlm ) {
 
 /*
 * Parse tag value from line buffer.
+* Enter: line   Buffer.
 * Return: Buffer containing the tag value. Empty string is returned if
 * no delimiter char found.
 */
-static gchar *ldif_get_tagvalue( gchar* line, gchar dlm ) {
+static gchar *ldif_get_tagvalue( gchar* line ) {
        gchar *value = NULL;
        gchar *start = NULL;
        gchar *lptr;
        gint len = 0;
 
        for( lptr = line; *lptr; lptr++ ) {
-               if( *lptr == dlm ) {
+               if( *lptr == LDIF_SEP_TAG ) {
                        if( ! start )
                                start = lptr + 1;
                }
        }
        if( start ) {
+               if( *start == LDIF_SEP_TAG ) start++;
                len = lptr - start;
                value = g_strndup( start, len+1 );
+               g_strstrip( value );
        }
        else {
                /* Ensure that we get an empty string */
@@ -214,6 +342,9 @@ static void ldif_dump_lists( GSList *listName, GSList *listAddr, GSList *listRem
        mgu_print_list( listID, stdout );
 }
 
+/*
+* Parsed address data.
+*/
 typedef struct _Ldif_ParsedRec_ Ldif_ParsedRec;
 struct _Ldif_ParsedRec_ {
        GSList *listCName;
@@ -222,6 +353,16 @@ struct _Ldif_ParsedRec_ {
        GSList *listNName;
        GSList *listAddress;
        GSList *listID;
+       GSList *userAttr;
+};
+
+/*
+* User attribute data.
+*/
+typedef struct _Ldif_UserAttr_ Ldif_UserAttr;
+struct _Ldif_UserAttr_ {
+       gchar *name;
+       gchar *value;
 };
 
 /*
@@ -231,6 +372,7 @@ struct _Ldif_ParsedRec_ {
 static void ldif_build_items( LdifFile *ldifFile, Ldif_ParsedRec *rec, AddressCache *cache ) {
        GSList *nodeFirst;
        GSList *nodeAddress;
+       GSList *nodeAttr;
        gchar *firstName = NULL, *lastName = NULL, *fullName = NULL, *nickName = NULL;
        gint iLen = 0, iLenT = 0;
        ItemPerson *person;
@@ -288,6 +430,7 @@ static void ldif_build_items( LdifFile *ldifFile, Ldif_ParsedRec *rec, AddressCa
        addritem_person_set_nick_name( person, nickName );
        addrcache_id_person( cache, person );
        addrcache_add_person( cache, person );
+       ++ldifFile->importCount;
 
        /* Add address item */
        while( nodeAddress ) {
@@ -300,9 +443,48 @@ static void ldif_build_items( LdifFile *ldifFile, Ldif_ParsedRec *rec, AddressCa
        g_free( fullName );
        fullName = firstName = lastName = NULL;
 
+       /* Add user attributes */
+       nodeAttr = rec->userAttr;
+       while( nodeAttr ) {
+               Ldif_UserAttr *attr = nodeAttr->data;
+               UserAttribute *attrib = addritem_create_attribute();
+               addritem_attrib_set_name( attrib, attr->name );
+               addritem_attrib_set_value( attrib, attr->value );
+               addritem_person_add_attribute( person, attrib );
+               nodeAttr = g_slist_next( nodeAttr );
+       }
+       nodeAttr = NULL;
 }
 
-static void ldif_add_value( Ldif_ParsedRec *rec, gchar *tagName, gchar *tagValue ) {
+/*
+* Add selected field as user attribute.
+*/
+static void ldif_add_user_attr( Ldif_ParsedRec *rec, gchar *tagName, gchar *tagValue, GHashTable *hashField ) {
+       Ldif_FieldRec *fld = NULL;
+       Ldif_UserAttr *attr = NULL;
+       gchar *name;
+       gchar *value;
+
+       fld = g_hash_table_lookup( hashField, tagName );
+       if( fld ) {
+               if( fld->reserved ) return;
+               if( ! fld->selected ) return;
+
+               name = fld->tagName;
+               if( fld->userName ) {
+                       name = fld->userName;
+               }
+               attr = g_new0( Ldif_UserAttr, 1 );
+               attr->name = g_strdup( name );
+               attr->value = g_strdup( tagValue );
+               rec->userAttr = g_slist_append( rec->userAttr, attr );
+       }
+}
+
+/*
+* Add value to parsed data.
+*/
+static void ldif_add_value( Ldif_ParsedRec *rec, gchar *tagName, gchar *tagValue, GHashTable *hashField ) {
        gchar *nm, *val;
 
        nm = g_strdup( tagName );
@@ -314,31 +496,53 @@ static void ldif_add_value( Ldif_ParsedRec *rec, gchar *tagName, gchar *tagValue
                val = g_strdup( "" );
        }
        g_strstrip( val );
-       if( strcmp( nm, LDIF_TAG_COMMONNAME ) == 0 ) {
+       if( g_strcasecmp( nm, LDIF_TAG_COMMONNAME ) == 0 ) {
                rec->listCName = g_slist_append( rec->listCName, val );
        }
-       else if( strcmp( nm, LDIF_TAG_FIRSTNAME ) == 0 ) {
+       else if( g_strcasecmp( nm, LDIF_TAG_FIRSTNAME ) == 0 ) {
                rec->listFName = g_slist_append( rec->listFName, val );
        }
-       else if( strcmp( nm, LDIF_TAG_LASTNAME ) == 0 ) {
+       else if( g_strcasecmp( nm, LDIF_TAG_LASTNAME ) == 0 ) {
                rec->listLName = g_slist_append( rec->listLName, val );
        }
-       else if( strcmp( nm, LDIF_TAG_NICKNAME ) == 0 ) {
+       else if( g_strcasecmp( nm, LDIF_TAG_NICKNAME ) == 0 ) {
                rec->listNName = g_slist_append( rec->listNName, val );
        }
-       else if( strcmp( nm, LDIF_TAG_EMAIL ) == 0 ) {
+       else if( g_strcasecmp( nm, LDIF_TAG_EMAIL ) == 0 ) {
                rec->listAddress = g_slist_append( rec->listAddress, val );
        }
+       else {
+               /* Add field as user attribute */
+               ldif_add_user_attr( rec, tagName, tagValue, hashField );
+       }
        g_free( nm );
 }
 
+/*
+* Clear parsed data.
+*/
 static void ldif_clear_rec( Ldif_ParsedRec *rec ) {
+       GSList *list;
+
+       /* Free up user attributes */
+       list = rec->userAttr;
+       while( list ) {
+               Ldif_UserAttr *attr = list->data;
+               g_free( attr->name );
+               g_free( attr->value );
+               g_free( attr );
+               list = g_slist_next( list );
+       }
+       g_slist_free( rec->userAttr );
+
        g_slist_free( rec->listCName );
        g_slist_free( rec->listFName );
        g_slist_free( rec->listLName );
        g_slist_free( rec->listNName );
        g_slist_free( rec->listAddress );
        g_slist_free( rec->listID );
+
+       rec->userAttr = NULL;
        rec->listCName = NULL;
        rec->listFName = NULL;
        rec->listLName = NULL;
@@ -347,29 +551,59 @@ static void ldif_clear_rec( Ldif_ParsedRec *rec ) {
        rec->listID = NULL;
 }
 
-#if 0
+/*
+* Print parsed data.
+*/
 static void ldif_print_record( Ldif_ParsedRec *rec, FILE *stream ) {
-       fprintf( stdout, "LDIF Parsed Record:\n" );
-       fprintf( stdout, "common name:" );
-       mgu_print_list( rec->listCName, stdout );
-       if( ! rec->listCName ) fprintf( stdout, "\n" );
-       fprintf( stdout, "first name:" );
-       mgu_print_list( rec->listFName, stdout );
-       if( ! rec->listFName ) fprintf( stdout, "\n" );
-       fprintf( stdout, "last name:" );
-       mgu_print_list( rec->listLName, stdout );
-       if( ! rec->listLName ) fprintf( stdout, "\n" );
-       fprintf( stdout, "nick name:" );
-       mgu_print_list( rec->listNName, stdout );
-       if( ! rec->listNName ) fprintf( stdout, "\n" );
-       fprintf( stdout, "address:" );
-       mgu_print_list( rec->listAddress, stdout );
-       if( ! rec->listAddress ) fprintf( stdout, "\n" );
-       fprintf( stdout, "id:" );
-       mgu_print_list( rec->listID, stdout );
-       if( ! rec->listID ) fprintf( stdout, "\n" );
+       GSList *list;
+
+       fprintf( stream, "LDIF Parsed Record:\n" );
+       fprintf( stream, "common name:" );
+       mgu_print_list( rec->listCName, stream );
+       if( ! rec->listCName ) fprintf( stream, "\n" );
+       fprintf( stream, "first name:" );
+       mgu_print_list( rec->listFName, stream );
+       if( ! rec->listFName ) fprintf( stream, "\n" );
+       fprintf( stream, "last name:" );
+       mgu_print_list( rec->listLName, stream );
+       if( ! rec->listLName ) fprintf( stream, "\n" );
+       fprintf( stream, "nick name:" );
+       mgu_print_list( rec->listNName, stream );
+       if( ! rec->listNName ) fprintf( stream, "\n" );
+       fprintf( stream, "address:" );
+       mgu_print_list( rec->listAddress, stream );
+       if( ! rec->listAddress ) fprintf( stream, "\n" );
+       fprintf( stream, "id:" );
+       mgu_print_list( rec->listID, stream );
+       if( ! rec->listID ) fprintf( stream, "\n" );
+
+       list = rec->userAttr;
+       while( list ) {
+               Ldif_UserAttr *attr = list->data;
+               fprintf( stream, "n/v:\t%s:\t:%s:\n", attr->name, attr->value );
+               list = g_slist_next( list );
+       }
+       list = NULL;
+}
+
+static void ldif_dump_b64( gchar *buf ) {
+       Base64Decoder *decoder = NULL;
+       gchar outBuf[8192];
+       gint len;
+
+       printf( "base-64 : inbuf : %s\n", buf );
+       decoder = base64_decoder_new();
+       len = base64_decoder_decode( decoder, buf, outBuf );
+       if (len < 0) {
+               printf( "base-64 : Bad BASE64 content\n" );
+       }
+       else {
+               outBuf[len] = '\0';
+               printf( "base-64 : %d : %s\n\n", len, outBuf );
+       }
+       base64_decoder_free( decoder );
+       decoder = NULL;
 }
-#endif
 
 /*
 * Read file data into address cache.
@@ -382,13 +616,31 @@ static void ldif_read_file( LdifFile *ldifFile, AddressCache *cache ) {
        gchar *lastTag = NULL, *fullValue = NULL;
        GSList *listValue = NULL;
        gboolean flagEOF = FALSE, flagEOR = FALSE;
+       gboolean flag64 = FALSE, last64 = FALSE;
        Ldif_ParsedRec *rec;
+       long posEnd = 0L;
+       long posCur = 0L;
+       GHashTable *hashField;
 
+       hashField = ldifFile->hashFields;
        rec = g_new0( Ldif_ParsedRec, 1 );
        ldif_clear_rec( rec );
 
+       /* Find EOF for progress indicator */
+       fseek( ldifFile->file, 0L, SEEK_END );
+       posEnd = ftell( ldifFile->file );
+       fseek( ldifFile->file, 0L, SEEK_SET );
+
        while( ! flagEOF ) {
                gchar *line =  ldif_get_line( ldifFile );
+
+               posCur = ftell( ldifFile->file );
+               if( ldifFile->cbProgress ) {
+                       /* Call progress indicator */
+                       ( ldifFile->cbProgress ) ( ldifFile, & posEnd, & posCur );
+               }
+
+               flag64 = FALSE;
                if( line == NULL ) {
                        flagEOF = flagEOR = TRUE;
                }
@@ -401,7 +653,15 @@ static void ldif_read_file( LdifFile *ldifFile, AddressCache *cache ) {
                        if( lastTag ) {
                                /* Save record */
                                fullValue = mgu_list_coalesce( listValue );
-                               ldif_add_value( rec, lastTag, fullValue );
+
+                               /* Base-64 encoded data */
+                               /*
+                               if( last64 ) {
+                                       ldif_dump_b64( fullValue );
+                               }
+                               */
+
+                               ldif_add_value( rec, lastTag, fullValue, hashField );
                                /* ldif_print_record( rec, stdout ); */
                                ldif_build_items( ldifFile, rec, cache );
                                ldif_clear_rec( rec );
@@ -409,6 +669,7 @@ static void ldif_read_file( LdifFile *ldifFile, AddressCache *cache ) {
                                mgu_free_list( listValue );
                                lastTag = NULL;
                                listValue = NULL;
+                               last64 = FALSE;
                        }
                }
                if( line ) {
@@ -418,34 +679,43 @@ static void ldif_read_file( LdifFile *ldifFile, AddressCache *cache ) {
                                listValue = g_slist_append( listValue, g_strdup( line+1 ) );
                        }
                        else if( *line == '=' ) {
-                               /* Base-64 binary encode field */
+                               /* Base-64 encoded continuation field */
                                listValue = g_slist_append( listValue, g_strdup( line ) );
                        }
                        else {
                                /* Parse line */
-                               tagName = ldif_get_tagname( line, LDIF_SEP_TAG );
+                               tagName = ldif_get_tagname( line, &flag64 );
                                if( tagName ) {
-                                       tagValue = ldif_get_tagvalue( line, LDIF_SEP_TAG );
+                                       tagValue = ldif_get_tagvalue( line );
                                        if( tagValue ) {
                                                if( lastTag ) {
                                                        /* Save data */
                                                        fullValue = mgu_list_coalesce( listValue );
-                                                       ldif_add_value( rec, lastTag, fullValue );
+                                                       /* Base-64 encoded data */
+                                                       /*
+                                                       if( last64 ) {
+                                                               ldif_dump_b64( fullValue );
+                                                       }
+                                                       */
+
+                                                       ldif_add_value( rec, lastTag, fullValue, hashField );
                                                        g_free( lastTag );
                                                        mgu_free_list( listValue );
                                                        lastTag = NULL;
                                                        listValue = NULL;
+                                                       last64 = FALSE;
                                                }
 
                                                lastTag = g_strdup( tagName );
                                                listValue = g_slist_append( listValue, g_strdup( tagValue ) );
                                                g_free( tagValue );
+                                               last64 = flag64;
                                        }
                                        g_free( tagName );
                                }
                        }
                }
-
+               g_free( line );
        }
 
        /* Release data */
@@ -453,16 +723,142 @@ static void ldif_read_file( LdifFile *ldifFile, AddressCache *cache ) {
        g_free( rec );
        g_free( lastTag );
        mgu_free_list( listValue );
+}
+
+/*
+* Add list of field names to hash table.
+*/
+static void ldif_hash_add_list( GHashTable *table, GSList *list ) {
+       GSList *node = list;
+
+       /* mgu_print_list( list, stdout ); */
+       while( node ) {
+               gchar *tag = node->data;
+               if( ! g_hash_table_lookup( table, tag ) ) {
+                       Ldif_FieldRec *rec = NULL;
+                       gchar *key = g_strdup( tag );
+
+                       rec = ldif_create_fieldrec( tag );
+                       if( g_strcasecmp( tag, LDIF_TAG_COMMONNAME ) == 0 ) {
+                               rec->reserved = TRUE;
+                       }
+                       else if( g_strcasecmp( tag, LDIF_TAG_FIRSTNAME ) == 0 ) {
+                               rec->reserved = TRUE;
+                       }
+                       else if( g_strcasecmp( tag, LDIF_TAG_LASTNAME ) == 0 ) {
+                               rec->reserved = TRUE;
+                       }
+                       else if( g_strcasecmp( tag, LDIF_TAG_NICKNAME ) == 0 ) {
+                               rec->reserved = TRUE;
+                       }
+                       else if( g_strcasecmp( tag, LDIF_TAG_EMAIL ) == 0 ) {
+                               rec->reserved = TRUE;
+                       }
+                       g_hash_table_insert( table, key, rec );
+               }
+               node = g_slist_next( node );
+       }
+}
+
+/*
+* Sorted list comparison function.
+*/
+static int ldif_field_compare( gconstpointer ptr1, gconstpointer ptr2 ) {
+       const Ldif_FieldRec *rec1 = ptr1;
+       const Ldif_FieldRec *rec2 = ptr2;
+       return strcasecmp(rec1->tagName, rec2->tagName );
+}
+
+/*
+* Append hash table entry to list - visitor function.
+*/
+static void ldif_hash2list_vis( gpointer key, gpointer value, gpointer data ) {
+       LdifFile *ldf = data;
+       ldf->tempList = g_list_insert_sorted( ldf->tempList, value, ldif_field_compare );
+}
+
+/*
+* Read tag names for file data.
+*/
+static void ldif_read_tag_list( LdifFile *ldifFile ) {
+       gchar *tagName = NULL;
+       GSList *listTags = NULL;
+       gboolean flagEOF = FALSE, flagEOR = FALSE, flagMail = FALSE;
+       gboolean flag64 = FALSE;
+       long posEnd = 0L;
+       long posCur = 0L;
+
+       /* Clear hash table */
+       g_hash_table_foreach_remove( ldifFile->hashFields, ldif_hash_free_vis, NULL );
+
+       /* Find EOF for progress indicator */
+       fseek( ldifFile->file, 0L, SEEK_END );
+       posEnd = ftell( ldifFile->file );
+       fseek( ldifFile->file, 0L, SEEK_SET );
+
+       /* Process file */
+       while( ! flagEOF ) {
+               gchar *line = ldif_get_line( ldifFile );
+
+               posCur = ftell( ldifFile->file );
+               if( ldifFile->cbProgress ) {
+                       /* Call progress indicator */
+                       ( ldifFile->cbProgress ) ( ldifFile, & posEnd, & posCur );
+               }
+
+               flag64 = FALSE;
+               if( line == NULL ) {
+                       flagEOF = flagEOR = TRUE;
+               }
+               else if( *line == '\0' ) {
+                       flagEOR = TRUE;
+               }
+
+               if( flagEOR ) {
+                       /* EOR, Output address data */
+                       /* Save field list to hash table */
+                       if( flagMail ) {
+                               ldif_hash_add_list( ldifFile->hashFields, listTags );
+                       }
+                       mgu_free_list( listTags );
+                       listTags = NULL;
+                       flagMail = FALSE;
+               }
+               if( line ) {
+                       flagEOR = FALSE;
+                       if( *line == ' ' ) {
+                               /* Continuation line */
+                       }
+                       else if( *line == '=' ) {
+                               /* Base-64 encoded continuation field */
+                       }
+                       else {
+                               /* Parse line */
+                               tagName = ldif_get_tagname( line, &flag64 );
+                               if( tagName ) {
+                                       /* Add tag to list */
+                                       listTags = g_slist_append( listTags, tagName );
+                                       if( g_strcasecmp( tagName, LDIF_TAG_EMAIL ) == 0 ) {
+                                               flagMail = TRUE;
+                                       }
+                               }
+                       }
+               }
+               g_free( line );
+       }
 
+       /* Release data */
+       mgu_free_list( listTags );
+       listTags = NULL;
 }
 
 /*
-* ============================================================================================
+* ============================================================================
 * Read file into list. Main entry point
 * Enter:  ldifFile LDIF control data.
 *         cache    Address cache to load.
 * Return: Status code.
-* ============================================================================================
+* ============================================================================
 */
 gint ldif_import_data( LdifFile *ldifFile, AddressCache *cache ) {
        g_return_val_if_fail( ldifFile != NULL, MGU_BAD_ARGS );
@@ -482,6 +878,51 @@ gint ldif_import_data( LdifFile *ldifFile, AddressCache *cache ) {
        return ldifFile->retVal;
 }
 
+/*
+* ============================================================================
+* Process entire file reading list of unique fields. List of fields may be
+* accessed with the ldif_get_fieldlist() function.
+* Enter:  ldifFile LDIF control data.
+* Return: Status code.
+* ============================================================================
+*/
+gint ldif_read_tags( LdifFile *ldifFile ) {
+       g_return_val_if_fail( ldifFile != NULL, MGU_BAD_ARGS );
+       ldifFile->retVal = MGU_SUCCESS;
+       if( ldifFile->dirtyFlag ) {
+               ldif_open_file( ldifFile );
+               if( ldifFile->retVal == MGU_SUCCESS ) {
+                       /* Read data into the cache */
+                       ldif_read_tag_list( ldifFile );
+                       ldif_close_file( ldifFile );
+                       ldifFile->dirtyFlag = FALSE;
+                       ldifFile->accessFlag = TRUE;
+               }
+       }
+       return ldifFile->retVal;
+}
+
+/*
+* Return list of fields for LDIF file.
+* Enter: ldifFile LdifFile object.
+* Return: Linked list of Ldif_FieldRec objects. This list may be g_free'd.
+* Note that the objects in the list should not be freed since they refer to
+* objects inside the internal cache. These objects will be freed when
+* LDIF file object is freed.
+*/
+GList *ldif_get_fieldlist( LdifFile *ldifFile ) {
+       GList *list = NULL;
+
+       g_return_val_if_fail( ldifFile != NULL, NULL );
+       if( ldifFile->hashFields ) {
+               ldifFile->tempList = NULL;
+               g_hash_table_foreach( ldifFile->hashFields, ldif_hash2list_vis, ldifFile );
+               list = ldifFile->tempList;
+               ldifFile->tempList = NULL;
+       }
+       return list;
+}
+
 /*
 * End of Source.
 */
index 71c1350ff6eadfeadeef711e40cb810ff3cfaea7..5ec2643c4761bf84984c13ba1404e4b036628899 100644 (file)
  */
 
 /*
- * 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.
+ * Definitions necessary to access LDIF files (LDAP Data Interchange Format
+ * files). These files are used to load LDAP servers and to interchange data
+ * between servers. They are also used by several E-Mail client programs and
+ * other programs as a means of interchange address book data.
  */
 
 #ifndef __LDIF_H__
 #include <stdio.h>
 #include <glib.h>
 
-#include "addritem.h"
 #include "addrcache.h"
 
 #define LDIFBUFSIZE         2048
 
+/* Reserved tag names - for address book import */
 #define        LDIF_TAG_COMMONNAME "cn"
 #define        LDIF_TAG_FIRSTNAME  "givenname"
 #define        LDIF_TAG_LASTNAME   "sn"
@@ -41,6 +42,7 @@
 #define        LDIF_TAG_EMAIL      "mail"
 
 #define        LDIF_SEP_TAG        ':'
+#define        LDIF_LANG_TAG       ';'
 
 /*
 // Typical LDIF entry (similar to that generated by Netscape):
 // objectclass: top
 // objectclass: person
 //
-// Note that first entry is always dn. Empty line defines end of record.
+// Note that first entry is always dn. An empty line defines end of
+// record. Note that attribute names are case insensitive. There may
+// also be several occurrences of an attribute, for example, as
+// illustrated for "mail" and "objectclass" attributes. LDIF files
+// can also use binary data using base-64 encoding.
 //
 */
 
-/* VCard object */
+/* LDIF file object */
 typedef struct _LdifFile LdifFile;
 struct _LdifFile {
-       FILE         *file;
-       gchar        *path;
-       gchar        *bufptr;
-       gchar        buffer[ LDIFBUFSIZE ];
-       /* AddressCache *addressCache; */
-       gint         retVal;
+       FILE       *file;
+       gchar      *path;
+       gchar      *bufptr;
+       gchar      buffer[ LDIFBUFSIZE ];
+       gint       retVal;
+       GHashTable *hashFields;
+       GList      *tempList;
+       gboolean   dirtyFlag;
+       gboolean   accessFlag;
+       void       (*cbProgress)( void *, void *, void * );
+       gint       importCount;
+};
+
+/* Field list structure */
+typedef struct _Ldif_FieldRec_ Ldif_FieldRec;
+struct _Ldif_FieldRec_ {
+       gchar *tagName;
+       gchar *userName;
+       gboolean reserved;
+       gboolean selected;
 };
 
 /* Function prototypes */
-LdifFile *ldif_create  ( void );
-void ldif_set_file     ( LdifFile* ldifFile, const gchar *value );
-void ldif_free         ( LdifFile *ldifFile );
-gint ldif_import_data  ( LdifFile *ldifFile, AddressCache *cache );
+LdifFile *ldif_create          ( void );
+void ldif_set_file             ( LdifFile* ldifFile, const gchar *value );
+void ldif_set_accessed         ( LdifFile* ldifFile, const gboolean value );
+void ldif_set_callback         ( LdifFile *ldifFile, void *func );
+void ldif_free                 ( LdifFile *ldifFile );
+void ldif_print_fieldrec       ( Ldif_FieldRec *rec, FILE *stream );
+void ldif_print_file           ( LdifFile *ldifFile, FILE *stream );
+gint ldif_import_data          ( LdifFile *ldifFile, AddressCache *cache );
+gint ldif_read_tags            ( LdifFile *ldifFile );
+GList *ldif_get_fieldlist      ( LdifFile *ldifFile );
 
 #endif /* __LDIF_H__ */
 
index 40961de293f1370f1c8957cb1eaf41306029382a..d3b99c165162cdee22c1a176959a05e12f620696 100644 (file)
@@ -214,6 +214,68 @@ gchar *mgu_email_check_empty( gchar *address ) {
        return retVal;
 }
 
+/*
+* Parse string into linked list. Whitespace is used as a delimiter in parsing.
+* Strings are parsed until maxTokens - 1 is reached. The remainder of the
+* input string is copied into last element of list.
+* Enter: line      String to parse.
+*        maxTokens Maximum number of tokens to parse.
+*        tokenCnt  If arg supplied, update with count of number of token parsed.
+* Return: Linked list. The list contents should be g_free'd and list should
+* freed when done.
+*/
+GList *mgu_parse_string( gchar *line, const gint maxTokens, gint *tokenCnt ) {
+       gchar *ptr, *pStart, *pFound, *str;
+       gint  args = 0;
+       GList *list = NULL;
+       gboolean done = FALSE;
+
+       if( tokenCnt ) *tokenCnt = 0;
+       if( line == NULL ) return NULL;
+       if( maxTokens < 1 ) return NULL;
+
+       ptr = line;
+       while( ! done ) {
+               args++;
+               /* Skip over leading spaces */
+               while( *ptr ) {
+                       if( ! isspace( *ptr ) ) break;
+                       ptr++;  
+               }
+
+               /* Find terminating space */
+               pFound = NULL;
+               pStart = ptr;
+               while( *ptr ) {
+                       if( isspace( *ptr ) ) {
+                               pFound = pStart;
+                               break;
+                       }
+                       ptr++;
+               }
+
+               if( pFound ) {
+                       if( args == maxTokens ) {
+                               /* Rest of string */
+                               str = g_strdup( pStart );
+                               done = TRUE;
+                       }
+                       else {
+                               /* Extract part of string */
+                               str = g_strndup( pStart, ptr - pFound );
+                       }
+               }
+               else {
+                       /* Nothing there - treat as rest of string */
+                       str = g_strdup( pStart );
+                       done = TRUE;
+               }
+               list = g_list_append( list, str );
+       }
+       if( tokenCnt ) *tokenCnt = args;
+       return list;
+}
+
 /*
 * End of Source.
 */
index 626bf75c9be9c8245525d6bfb8d032868602b18c..b960389d2fb17402f5709726e110dbb7ad21d644 100644 (file)
@@ -58,5 +58,6 @@ gchar *mgu_replace_string     ( gchar *str, const gchar *value );
 void mgu_clear_slist           ( GSList *list );
 void mgu_clear_list            ( GList *list );
 gchar *mgu_email_check_empty   ( gchar *address );
+GList *mgu_parse_string                ( gchar *line, const gint maxTokens, gint *tokenCnt );
 
 #endif /* __MGUTILS_H__ */
diff --git a/src/mutt.c b/src/mutt.c
new file mode 100644 (file)
index 0000000..c8f443b
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * 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 MUTT address book file.
+ */
+
+#include <sys/stat.h>
+#include <glib.h>
+
+#include "mgutils.h"
+#include "mutt.h"
+#include "addritem.h"
+#include "addrcache.h"
+
+#define MUTT_HOME_FILE  ".muttrc"
+
+/*
+* Create new object.
+*/
+MuttFile *mutt_create() {
+       MuttFile *muttFile;
+       muttFile = g_new0( MuttFile, 1 );
+       muttFile->path = NULL;
+       muttFile->file = NULL;
+       muttFile->bufptr = muttFile->buffer;
+       muttFile->retVal = MGU_SUCCESS;
+       muttFile->cbProgress = NULL;
+       return muttFile;
+}
+
+/*
+* Properties...
+*/
+void mutt_set_file( MuttFile* muttFile, const gchar *value ) {
+       g_return_if_fail( muttFile != NULL );
+       muttFile->path = mgu_replace_string( muttFile->path, value );
+       g_strstrip( muttFile->path );
+}
+
+/*
+* Register a callback function. When called, the function will be passed
+* the following arguments:
+*      MuttFile object,
+*      File size (long),
+*      Current position (long)
+* This can be used for a progress indicator.
+*/
+void mutt_set_callback( MuttFile *muttFile, void *func ) {
+       muttFile->cbProgress = func;
+}
+
+/*
+* Free up object by releasing internal memory.
+*/
+void mutt_free( MuttFile *muttFile ) {
+       g_return_if_fail( muttFile != NULL );
+
+       /* Close file */
+       if( muttFile->file ) fclose( muttFile->file );
+
+       /* Free internal stuff */
+       g_free( muttFile->path );
+
+       /* Clear pointers */
+       muttFile->file = NULL;
+       muttFile->path = NULL;
+       muttFile->retVal = MGU_SUCCESS;
+       muttFile->cbProgress = NULL;
+
+       /* Now release file object */
+       g_free( muttFile );
+}
+
+/*
+* Display object to specified stream.
+*/
+void mutt_print_file( MuttFile *muttFile, FILE *stream ) {
+       g_return_if_fail( muttFile != NULL );
+       fprintf( stream, "MUTT File:\n" );
+       fprintf( stream, "file spec: '%s'\n", muttFile->path );
+       fprintf( stream, "  ret val: %d\n",   muttFile->retVal );
+}
+
+/*
+* Open file for read.
+* return: TRUE if file opened successfully.
+*/
+static gint mutt_open_file( MuttFile* muttFile ) {
+       /* printf( "Opening file\n" ); */
+       if( muttFile->path ) {
+               muttFile->file = fopen( muttFile->path, "r" );
+               if( ! muttFile->file ) {
+                       /* printf( "can't open %s\n", muttFile->path ); */
+                       muttFile->retVal = MGU_OPEN_FILE;
+                       return muttFile->retVal;
+               }
+       }
+       else {
+               /* printf( "file not specified\n" ); */
+               muttFile->retVal = MGU_NO_FILE;
+               return muttFile->retVal;
+       }
+
+       /* Setup a buffer area */
+       muttFile->buffer[0] = '\0';
+       muttFile->bufptr = muttFile->buffer;
+       muttFile->retVal = MGU_SUCCESS;
+       return muttFile->retVal;
+}
+
+/*
+* Close file.
+*/
+static void mutt_close_file( MuttFile *muttFile ) {
+       g_return_if_fail( muttFile != NULL );
+       if( muttFile->file ) fclose( muttFile->file );
+       muttFile->file = NULL;
+}
+
+/*
+* Read line of text from file.
+* Enter: muttFile File object.
+*        flagCont Continuation flag, set if back-slash character at EOL.
+* Return: ptr to buffer where line starts.
+*/
+static gchar *mutt_get_line( MuttFile *muttFile, gboolean *flagCont ) {
+       gchar buf[ MUTTBUFSIZE ];
+       gchar ch, lch;
+       gchar *ptr, *lptr;
+
+       *flagCont = FALSE;
+       if( feof( muttFile->file ) ) return NULL;
+
+       ptr = buf;
+       lch = '\0';
+       lptr = NULL;
+       while( TRUE ) {
+               *ptr = '\0';
+               ch = fgetc( muttFile->file );
+               if( ch == '\0' || ch == EOF ) {
+                       if( *buf == '\0' ) return NULL;
+                       break;
+               }
+               if( ch == '\n' ) {
+                       if( lch == '\\' ) {
+                               /* Replace backslash with NULL */
+                               if( lptr ) *lptr = '\0';
+                               *flagCont = TRUE;
+                       }
+                       break;
+               }
+               *ptr = ch;
+               lptr = ptr;
+               lch = ch;
+               ptr++;
+       }
+
+       /* Copy into private buffer */
+       return g_strdup( buf );
+}
+
+/*
+* Parsed address data.
+*/
+typedef struct _Mutt_ParsedRec_ Mutt_ParsedRec;
+struct _Mutt_ParsedRec_ {
+       gchar *address;
+       gchar *name;
+};
+
+static mutt_free_rec( Mutt_ParsedRec *rec ) {
+       if( rec ) {
+               g_free( rec->address );
+               g_free( rec->name );
+               rec->address = NULL;
+               rec->name = NULL;
+               g_free( rec );
+       }
+}
+
+void mutt_print_rec( Mutt_ParsedRec *rec, FILE *stream ) {
+       fprintf( stream, "\taddr: %s\tname: %s\n", rec->address, rec->name );
+}
+
+/*
+* Parse recipient list for each address.
+* Enter: rcpList   Recipients extracted from file.
+*        addrCount Updated with recipient count.
+* Return: Linked list of recipients.
+*/
+static GSList *mutt_parse_rcplist( gchar *rcpList, gint *addrCount ) {
+       gchar *ptr, *pStart, *pEnd, *pAddr, *pName, *address, *name;
+       gchar ch;
+       GSList *list;
+       Mutt_ParsedRec *rec;
+       gint  cnt;
+
+       list = NULL;
+       cnt = 0;
+       pStart = rcpList;
+       while( *pStart ) {
+               ptr = pStart;
+               address = name = NULL;
+               pName = pAddr = NULL;
+               /* Chew up spaces */
+               while( *ptr ) {
+                       if( ! isspace( *ptr ) ) break;
+                       ptr++;
+               }
+
+               /* Find address */
+               while( *ptr ) {
+                       ch = *ptr;
+                       if( ch == '(' ) {
+                               pAddr = pName = ptr;
+                               break;
+                       }
+                       if( ch == ',' ) {
+                               pAddr = ptr;
+                               ptr++;
+                               break;
+                       }
+                       if( isspace( ch ) ) {
+                               pAddr = ptr;
+                               break;
+                       }
+                       ptr++;
+               }
+
+               /* Extract address */
+               if( pAddr ) {
+                       address = g_strndup( pStart, pAddr - pStart );
+               }
+               else {
+                       address = g_strdup( pStart );
+               }
+               g_strstrip( address );
+
+               /* Chew up spaces */
+               while( *ptr ) {
+                       ch = *ptr;
+                       if( ch == '(' ) {
+                               pName = ptr;
+                               break;
+                       }
+                       if( ch == ',' ) {
+                               ptr++;
+                               break;
+                       }
+                       ptr++;
+                       if( isspace( ch ) ) continue;
+               }
+               pStart = ptr;
+       
+               /* Extract name (if any) */
+               if( pName ) {
+                       /* Look for closing parens */
+                       pName++;
+                       pEnd = NULL;
+                       ptr = pName;
+                       while( *ptr ) {
+                               if( *ptr == ')' ) {
+                                       pEnd = ptr;
+                                       break;
+                               }
+                               ptr++;
+                       }
+                       if( pEnd ) {
+                               name = g_strndup( pName, pEnd - pName );
+                               pEnd++;
+                               if( *pEnd ) pEnd++;
+                       }
+                       else {
+                               name = g_strdup( pName );
+                       }
+                       g_strstrip( name );
+                       pStart = pEnd;
+               }
+               else {
+                       name = g_strdup( "" );
+               }
+
+               /* New record */
+               rec = g_new0( Mutt_ParsedRec, 1 );
+               rec->address = address;
+               rec->name = name;
+               list = g_slist_append( list, rec );
+
+               cnt++;
+
+               /* mutt_print_rec( rec, stdout ); */
+       }
+       *addrCount = cnt;
+       return list;
+}
+
+/*
+* Build address book entries.
+* Enter: aliasName Alias,
+*        listAddr  List of address items.
+*        addrCount Address list count.
+*        cache     Cache to update.
+*/
+static void mutt_build_address(
+               gchar *aliasName, GSList *listAddr, gint addrCount,
+               AddressCache *cache )
+{
+       GSList *node = NULL;
+       ItemPerson *person;
+       ItemEMail *email;
+       ItemGroup *group;
+       Mutt_ParsedRec *rec;
+
+       email = NULL;
+       group = NULL;
+       if( listAddr != NULL && addrCount > 1 ) {
+               group = addritem_create_item_group();
+               addritem_group_set_name( group, aliasName );
+               addrcache_id_group( cache, group );
+               addrcache_add_group( cache, group );
+       }
+
+       node = listAddr;
+       while( node ) {
+               rec = node->data;
+
+               /* Create person */
+               person = addritem_create_item_person();
+               addritem_person_set_common_name( person, rec->name );
+               addrcache_id_person( cache, person );
+               addrcache_add_person( cache, person );
+               if( addrCount < 2 ) {
+                       addritem_person_set_nick_name( person, aliasName );
+               }
+
+               /* Add email for person */
+               email = addritem_create_item_email();
+               addritem_email_set_address( email, rec->address );
+               addrcache_id_email( cache, email );
+               addrcache_person_add_email( cache, person, email );
+
+               /* Add email to group */
+               if( group ) {
+                       addritem_group_add_email( group, email );
+               }
+
+               mutt_free_rec( rec );
+               rec = NULL;
+
+               node = g_slist_next( node );
+       }
+}
+
+/*
+* Parse address line adn build address items.
+* Enter: line  Data record.
+*        cache Address cache.
+*/
+static void mutt_build_items( gchar *line, AddressCache *cache ) {
+       GList *list, *node;
+       gint tCount, aCount;
+       gchar *aliasTag, *aliasName, *recipient;
+       GSList *addrList;
+
+       /* printf( "\nBUILD >%s<\n", line ); */
+       list = mgu_parse_string( line,  3, &tCount );
+       if( tCount < 3 ) {
+               if( list ) {
+                       mgu_free_dlist( list );
+                       list = NULL;
+               }
+               return;
+       }
+
+       aliasTag = list->data;
+       node = g_list_next( list );
+       aliasName = node->data;
+       node = g_list_next( node );
+       recipient = node->data;
+
+       addrList = NULL;
+       if( strcmp( aliasTag, "alias" ) == 0 ) {
+               aCount = 0;
+               /* printf( "aliasName :%s:\n", aliasName ); */
+               /* printf( "recipient :%s:\n", recipient ); */
+               addrList = mutt_parse_rcplist( recipient, &aCount );
+               /* printf( "---\n" ); */
+               mutt_build_address( aliasName, addrList, aCount, cache );
+       }
+
+       mgu_free_dlist( list );
+       list = NULL;
+
+}
+
+/*
+* Read file data into address cache.
+*/
+static void mutt_read_file( MuttFile *muttFile, AddressCache *cache ) {
+       GSList *listValue = NULL;
+       gboolean flagEOF = FALSE, flagCont = FALSE, lastCont = FALSE;
+       gchar *line =  NULL, *lineValue = NULL;
+       long posEnd = 0L;
+       long posCur = 0L;
+
+       /* Find EOF for progress indicator */
+       fseek( muttFile->file, 0L, SEEK_END );
+       posEnd = ftell( muttFile->file );
+       fseek( muttFile->file, 0L, SEEK_SET );
+
+       while( ! flagEOF ) {
+               flagCont = FALSE;
+               line =  mutt_get_line( muttFile, &flagCont );
+
+               posCur = ftell( muttFile->file );
+               if( muttFile->cbProgress ) {
+                       /* Call progress indicator */
+                       ( muttFile->cbProgress ) ( muttFile, & posEnd, & posCur );
+               }
+
+               if( line == NULL ) flagEOF = TRUE;
+               if( ! lastCont ) {
+                       /* Save data */
+                       lineValue = mgu_list_coalesce( listValue );
+                       if( lineValue ) {
+                               mutt_build_items( lineValue, cache );
+                       }
+                       g_free( lineValue );
+                       lineValue = NULL;
+                       mgu_free_list( listValue );
+                       listValue = NULL;
+               }
+               lastCont = flagCont;
+
+               /* Add line to list */
+               listValue = g_slist_append( listValue, g_strdup( line ) );
+
+               g_free( line );
+               line = NULL;
+       }
+
+       /* Release data */
+       mgu_free_list( listValue );
+       listValue = NULL;
+}
+
+/*
+* ============================================================================================
+* Read file into list. Main entry point
+* Enter:  muttFile MUTT control data.
+*         cache    Address cache to load.
+* Return: Status code.
+* ============================================================================================
+*/
+gint mutt_import_data( MuttFile *muttFile, AddressCache *cache ) {
+       g_return_val_if_fail( muttFile != NULL, MGU_BAD_ARGS );
+       g_return_val_if_fail( cache != NULL, MGU_BAD_ARGS );
+       muttFile->retVal = MGU_SUCCESS;
+       addrcache_clear( cache );
+       cache->dataRead = FALSE;
+       mutt_open_file( muttFile );
+       if( muttFile->retVal == MGU_SUCCESS ) {
+               /* Read data into the cache */
+               mutt_read_file( muttFile, cache );
+               mutt_close_file( muttFile );
+
+               /* Mark cache */
+               cache->modified = FALSE;
+               cache->dataRead = TRUE;
+       }
+       return muttFile->retVal;
+}
+
+#define WORK_BUFLEN 1024
+
+/*
+* Attempt to find a Mutt file.
+* Return: Filename, or home directory if not found, or empty string if
+* no home. Filename should be g_free() when done.
+*/
+gchar *mutt_find_file( 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, MUTT_HOME_FILE );
+
+       /* Attempt to open */
+       if( ( fp = fopen( str, "r" ) ) != NULL ) {
+               fclose( fp );
+       }
+       else {
+               /* Truncate filename */
+               str[ len ] = '\0';
+       }
+       return g_strdup( str );
+}
+
+/*
+* End of Source.
+*/
+
diff --git a/src/mutt.h b/src/mutt.h
new file mode 100644 (file)
index 0000000..63d2279
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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 MUTT addressbook files. These are
+ * used by the MUTT E-Mail client.
+ */
+
+#ifndef __MUTT_H__
+#define __MUTT_H__
+
+#include <stdio.h>
+#include <glib.h>
+
+#include "addrcache.h"
+
+#define MUTTBUFSIZE         2048
+
+#define        MUTT_TAG_ALIAS      "alias"
+
+/*
+// Typical MUTT entry:
+//
+// alias alias-name email-address (friendly-name) [, email-address (friendly-name) ...]
+//
+// The alias-name maybe the name of an individual or the name of a group
+// comprising many individuals. The alias name should not contain the space,
+// comma (,) or at (@) character. The friendly-name is optional. A back-slash
+// character at end-of-line may be used as a continuation character.
+//
+// An example:
+// 
+// alias myhome  axel@axelrose.com (Axel Rose)
+// alias axe     axelrose@aol.com  (The Axe)
+// alias buddies esr@wheres-my-mail.com (Eric Raymond), bgates@hotmail.com (Oops Lost It)
+//
+*/
+
+/* MUTT file object */
+typedef struct _MuttFile MuttFile;
+struct _MuttFile {
+       FILE  *file;
+       gchar *path;
+       gchar *bufptr;
+       gchar buffer[ MUTTBUFSIZE ];
+       gint  retVal;
+       void  (*cbProgress)( void *, void *, void * );
+};
+
+/* Function prototypes */
+MuttFile *mutt_create  ( void );
+void mutt_set_file     ( MuttFile* muttFile, const gchar *value );
+void mutt_free         ( MuttFile *muttFile );
+gint mutt_import_data  ( MuttFile *muttFile, AddressCache *cache );
+gchar *mutt_find_file  ( void );
+
+#endif /* __MUTT_H__ */
+