2004-11-06 [colin] 0.9.12cvs140.1
[claws.git] / src / importldif.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2001-2003 Match Grun
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Import LDIF address book data.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "defs.h"
29
30 #include <glib.h>
31 #include <gdk/gdkkeysyms.h>
32 #include <gtk/gtkwindow.h>
33 #include <gtk/gtksignal.h>
34 #include <gtk/gtklabel.h>
35 #include <gtk/gtkentry.h>
36 #include <gtk/gtktable.h>
37 #include <gtk/gtkbutton.h>
38
39 #include "intl.h"
40 #include "addrbook.h"
41 #include "addressbook.h"
42 #include "addressitem.h"
43 #include "gtkutils.h"
44 #include "stock_pixmap.h"
45 #include "prefs_common.h"
46 #include "manage_window.h"
47 #include "mgutils.h"
48 #include "ldif.h"
49 #include "utils.h"
50
51 #define IMPORTLDIF_GUESS_NAME      "LDIF Import"
52
53 #define PAGE_FILE_INFO             0
54 #define PAGE_ATTRIBUTES            1
55 #define PAGE_FINISH                2
56
57 #define IMPORTLDIF_WIDTH           390
58 #define IMPORTLDIF_HEIGHT          300
59
60 #define FIELDS_N_COLS              4
61 #define FIELDS_COL_WIDTH_RESERVED  10
62 #define FIELDS_COL_WIDTH_SELECT    10
63 #define FIELDS_COL_WIDTH_FIELD     140
64 #define FIELDS_COL_WIDTH_ATTRIB    140
65
66 typedef enum {
67         FIELD_COL_RESERVED = 0,
68         FIELD_COL_SELECT   = 1,
69         FIELD_COL_FIELD    = 2,
70         FIELD_COL_ATTRIB   = 3
71 } ImpLdif_FieldColPos;
72
73 /**
74  * LDIF dialog definition.
75  */
76 static struct _ImpLdif_Dlg {
77         GtkWidget *window;
78         GtkWidget *notebook;
79         GtkWidget *entryFile;
80         GtkWidget *entryName;
81         GtkWidget *clist_field;
82         GtkWidget *entryField;
83         GtkWidget *entryAttrib;
84         GtkWidget *checkSelect;
85         GtkWidget *btnModify;
86         GtkWidget *labelBook;
87         GtkWidget *labelFile;
88         GtkWidget *labelRecords;
89         GtkWidget *btnPrev;
90         GtkWidget *btnNext;
91         GtkWidget *btnCancel;
92         GtkWidget *statusbar;
93         gint      status_cid;
94         gint      rowIndSelect;
95         gint      rowCount;
96         gchar     *nameBook;
97         gchar     *fileName;
98         gboolean  cancelled;
99 } impldif_dlg;
100
101 static struct _AddressFileSelection _imp_ldif_file_selector_;
102 static AddressBookFile *_importedBook_;
103 static AddressIndex *_imp_addressIndex_;
104 static LdifFile *_ldifFile_ = NULL;
105
106 static GdkPixmap *markxpm;
107 static GdkBitmap *markxpmmask;
108
109 /**
110  * Structure of error message table.
111  */
112 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
113 struct _ErrMsgTableEntry {
114         gint    code;
115         gchar   *description;
116 };
117
118 static gchar *_errMsgUnknown_ = N_( "Unknown" );
119
120 /**
121  * Lookup table of error messages for general errors. Note that a NULL
122  * description signifies the end of the table.
123  */
124 static ErrMsgTableEntry _lutErrorsLDIF_[] = {
125         { MGU_SUCCESS,          N_("Success") },
126         { MGU_BAD_ARGS,         N_("Bad arguments") },
127         { MGU_NO_FILE,          N_("File not specified") },
128         { MGU_OPEN_FILE,        N_("Error opening file") },
129         { MGU_ERROR_READ,       N_("Error reading file") },
130         { MGU_EOF,              N_("End of file encountered") },
131         { MGU_OO_MEMORY,        N_("Error allocating memory") },
132         { MGU_BAD_FORMAT,       N_("Bad file format") },
133         { MGU_ERROR_WRITE,      N_("Error writing to file") },
134         { MGU_OPEN_DIRECTORY,   N_("Error opening directory") },
135         { MGU_NO_PATH,          N_("No path specified") },
136         { 0,                    NULL }
137 };
138
139 /**
140  * Lookup message for specified error code.
141  * \param lut  Lookup table.
142  * \param code Code to lookup.
143  * \return Description associated to code.
144  */
145 static gchar *imp_ldif_err2string( ErrMsgTableEntry lut[], gint code ) {
146         gchar *desc = NULL;
147         ErrMsgTableEntry entry;
148         gint i;
149
150         for( i = 0; ; i++ ) {
151                 entry = lut[ i ];
152                 if( entry.description == NULL ) break;
153                 if( entry.code == code ) {
154                         desc = entry.description;
155                         break;
156                 }
157         }
158         if( ! desc ) {
159                 desc = _errMsgUnknown_;
160         }
161         return desc;
162 }
163
164 /**
165  * Display message in status field.
166  * \param msg Message to display.
167  */
168 static void imp_ldif_status_show( gchar *msg ) {
169         if( impldif_dlg.statusbar != NULL ) {
170                 gtk_statusbar_pop( GTK_STATUSBAR(impldif_dlg.statusbar),
171                         impldif_dlg.status_cid );
172                 if( msg ) {
173                         gtk_statusbar_push(
174                                 GTK_STATUSBAR(impldif_dlg.statusbar),
175                                 impldif_dlg.status_cid, msg );
176                 }
177         }
178 }
179
180 /**
181  * Select and display status message appropriate for the page being displayed.
182  */
183 static void imp_ldif_message( void ) {
184         gchar *sMsg = NULL;
185         gint pageNum;
186
187         pageNum = gtk_notebook_get_current_page( GTK_NOTEBOOK(impldif_dlg.notebook) );
188         if( pageNum == PAGE_FILE_INFO ) {
189                 sMsg = _( "Please specify address book name and file to import." );
190         }
191         else if( pageNum == PAGE_ATTRIBUTES ) {
192                 sMsg = _( "Select and rename LDIF field names to import." );
193         }
194         else if( pageNum == PAGE_FINISH ) {
195                 sMsg = _( "File imported." );
196         }
197         imp_ldif_status_show( sMsg );
198 }
199
200 /**
201  * Update list with data for current row.
202  * \param clist List to update.
203  */
204 static void imp_ldif_update_row( GtkCList *clist ) {
205         Ldif_FieldRec *rec;
206         gchar *text[ FIELDS_N_COLS ];
207         gint row;
208
209         if( impldif_dlg.rowIndSelect < 0 ) return;
210         row = impldif_dlg.rowIndSelect;
211
212         rec = gtk_clist_get_row_data( clist, row );
213         text[ FIELD_COL_RESERVED ] = "";
214         text[ FIELD_COL_SELECT   ] = "";
215         text[ FIELD_COL_FIELD    ] = rec->tagName;
216         text[ FIELD_COL_ATTRIB   ] = rec->userName;
217
218         gtk_clist_freeze( clist );
219         gtk_clist_remove( clist, row );
220         if( row == impldif_dlg.rowCount - 1 ) {
221                 gtk_clist_append( clist, text );
222         }
223         else {
224                 gtk_clist_insert( clist, row, text );
225         }
226         if( rec->selected ) {
227                 gtk_clist_set_pixmap(
228                         clist, row, FIELD_COL_SELECT, markxpm, markxpmmask );
229         }
230         if( rec->reserved ) {
231                 gtk_clist_set_pixmap(
232                         clist, row, FIELD_COL_RESERVED, markxpm, markxpmmask );
233         }
234
235         gtk_clist_set_row_data( clist, row, rec );
236         gtk_clist_thaw( clist );
237 }
238
239 /**
240  * Load list with LDIF fields read from file.
241  * \param ldf LDIF control data.
242  */
243 static void imp_ldif_load_fields( LdifFile *ldf ) {
244         GtkCList *clist = GTK_CLIST(impldif_dlg.clist_field);
245         GList *node, *list;
246         gchar *text[ FIELDS_N_COLS ];
247
248         impldif_dlg.rowIndSelect = -1;
249         impldif_dlg.rowCount = 0;
250         if( ! ldf->accessFlag ) return;
251         gtk_clist_clear( clist );
252         list = ldif_get_fieldlist( ldf );
253         node = list;
254         while( node ) {
255                 Ldif_FieldRec *rec = node->data;
256                 gint row;
257
258                 text[ FIELD_COL_RESERVED ] = "";
259                 text[ FIELD_COL_SELECT   ] = "";
260                 text[ FIELD_COL_FIELD    ] = rec->tagName;
261                 text[ FIELD_COL_ATTRIB   ] = rec->userName;
262                 row = gtk_clist_append( clist, text );
263                 gtk_clist_set_row_data( clist, row, rec );
264                 if( rec->selected ) {
265                         gtk_clist_set_pixmap( clist, row,
266                                 FIELD_COL_SELECT, markxpm, markxpmmask );
267                 }
268                 if( rec->reserved ) {
269                         gtk_clist_set_pixmap( clist, row,
270                                 FIELD_COL_RESERVED, markxpm, markxpmmask );
271                 }
272                 impldif_dlg.rowCount++;
273                 node = g_list_next( node );
274         }
275         g_list_free( list );
276         list = NULL;
277         ldif_set_accessed( ldf, FALSE );
278 }
279
280 /**
281  * Callback function when list iterm selected.
282  * \param clist List widget.
283  * \param row   Row.
284  * \param col   Column.
285  * \param event Event object.
286  * \param data  User data.
287  */
288 static void imp_ldif_field_list_selected(
289                 GtkCList *clist, gint row, gint column, GdkEvent *event,
290                 gpointer data )
291 {
292         Ldif_FieldRec *rec = gtk_clist_get_row_data( clist, row );
293
294         impldif_dlg.rowIndSelect = row;
295         gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryAttrib), "" );
296         if( rec ) {
297                 /* Update widget contents */
298                 gtk_label_set_text(
299                         GTK_LABEL(impldif_dlg.entryField), rec->tagName );
300                 if( rec->userName )
301                         gtk_entry_set_text(
302                                 GTK_ENTRY(impldif_dlg.entryAttrib), rec->userName );
303                 gtk_toggle_button_set_active(
304                         GTK_TOGGLE_BUTTON( impldif_dlg.checkSelect),
305                         rec->selected );
306
307                 /* Disable widgets for reserved fields */
308                 gtk_widget_set_sensitive(
309                         impldif_dlg.entryAttrib, ! rec->reserved );
310                 gtk_widget_set_sensitive(
311                         impldif_dlg.checkSelect, ! rec->reserved );
312                 gtk_widget_set_sensitive(
313                         impldif_dlg.btnModify,   ! rec->reserved );
314         }
315         gtk_widget_grab_focus(impldif_dlg.entryAttrib);
316 }
317
318 /**
319  * Callback function to toggle selected LDIF field.
320  * \param clist List to update.
321  * \param event Event object.
322  * \param data  Data.
323  */
324 static gboolean imp_ldif_field_list_toggle(
325                 GtkCList *clist, GdkEventButton *event, gpointer data )
326 {
327         Ldif_FieldRec *rec;
328         gboolean toggle = FALSE;
329
330         if( ! event ) return FALSE;
331         if( impldif_dlg.rowIndSelect < 0 ) return FALSE;
332         if( event->button == 1 ) {
333                 /* If single click in select column */
334                 if( event->type == GDK_BUTTON_PRESS ) {
335                         gint x = event->x;
336                         gint y = event->y;
337                         gint row, col;
338
339                         gtk_clist_get_selection_info( clist, x, y, &row, &col );
340                         if( col != FIELD_COL_SELECT ) return FALSE;
341                         if( row > impldif_dlg.rowCount ) return FALSE;
342
343                         /* Set row */
344                         impldif_dlg.rowIndSelect = row;
345                         toggle = TRUE;
346                 }
347
348                 /* If double click anywhere in row */
349                 else if( event->type == GDK_2BUTTON_PRESS ) {
350                         toggle = TRUE;
351                 }
352         }
353         /* Toggle field selection */
354         if( toggle ) {
355                 rec = gtk_clist_get_row_data(
356                         clist, impldif_dlg.rowIndSelect );
357                 if( rec ) {
358                         ldif_field_toggle( rec );
359                         imp_ldif_update_row( clist );
360                 }
361         }
362         return FALSE;
363 }
364
365 /**
366  * Callback function to update LDIF field data from input fields.
367  * \param widget Widget (button).
368  * \param data   User data.
369  */
370 static void imp_ldif_modify_pressed( GtkWidget *widget, gpointer data ) {
371         GtkCList *clist = GTK_CLIST(impldif_dlg.clist_field);
372         Ldif_FieldRec *rec;
373         gint row;
374
375         if( impldif_dlg.rowIndSelect < 0 ) return;
376         row = impldif_dlg.rowIndSelect;
377         rec = gtk_clist_get_row_data( clist, impldif_dlg.rowIndSelect );
378
379         ldif_field_set_name( rec, gtk_editable_get_chars(
380                 GTK_EDITABLE(impldif_dlg.entryAttrib), 0, -1 ) );
381         ldif_field_set_selected( rec, gtk_toggle_button_get_active(
382                 GTK_TOGGLE_BUTTON( impldif_dlg.checkSelect) ) );
383         imp_ldif_update_row( clist );
384         gtk_clist_select_row( clist, row, 0 );
385         gtk_label_set_text( GTK_LABEL(impldif_dlg.entryField), "" );
386         gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryAttrib), "" );
387         gtk_toggle_button_set_active(
388                 GTK_TOGGLE_BUTTON( impldif_dlg.checkSelect), FALSE );
389 }
390
391 /**
392  * Test whether we can move off fields page.
393  * \return <i>TRUE</i> if OK to move off page.
394  */
395 static gboolean imp_ldif_field_move() {
396         gboolean retVal = FALSE;
397         gchar *newFile;
398         AddressBookFile *abf = NULL;
399
400         if( _importedBook_ ) {
401                 addrbook_free_book( _importedBook_ );
402         }
403
404         abf = addrbook_create_book();
405         addrbook_set_path( abf, _imp_addressIndex_->filePath );
406         addrbook_set_name( abf, impldif_dlg.nameBook );
407         newFile = addrbook_guess_next_file( abf );
408         addrbook_set_file( abf, newFile );
409         g_free( newFile );
410
411         /* Import data into file */
412         if( ldif_import_data( _ldifFile_, abf->addressCache ) == MGU_SUCCESS ) {
413                 addrbook_save_data( abf );
414                 _importedBook_ = abf;
415                 retVal = TRUE;
416         }
417         else {
418                 addrbook_free_book( abf );
419         }
420
421         return retVal;
422 }
423
424 /**
425  * Test whether we can move off file page.
426  * \return <i>TRUE</i> if OK to move off page.
427  */
428 static gboolean imp_ldif_file_move() {
429         gboolean retVal = FALSE;
430         gchar *sName;
431         gchar *sFile;
432         gchar *sMsg = NULL;
433         gboolean errFlag = FALSE;
434
435         sFile = gtk_editable_get_chars( GTK_EDITABLE(impldif_dlg.entryFile), 0, -1 );
436         g_strchug( sFile ); g_strchomp( sFile );
437
438         sName = gtk_editable_get_chars( GTK_EDITABLE(impldif_dlg.entryName), 0, -1 );
439         g_strchug( sName ); g_strchomp( sName );
440
441         g_free( impldif_dlg.nameBook );
442         g_free( impldif_dlg.fileName );
443         impldif_dlg.nameBook = sName;
444         impldif_dlg.fileName = sFile;
445
446         gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryFile), sFile );
447         gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryName), sName );
448
449         if( *sFile == '\0'|| strlen( sFile ) < 1 ) {
450                 sMsg = _( "Please select a file." );
451                 gtk_widget_grab_focus(impldif_dlg.entryFile);
452                 errFlag = TRUE;
453         }
454
455         if( *sName == '\0'|| strlen( sName ) < 1 ) {
456                 if( ! errFlag ) sMsg = _( "Address book name must be supplied." );
457                 gtk_widget_grab_focus(impldif_dlg.entryName);
458                 errFlag = TRUE;
459         }
460
461         if( ! errFlag ) {
462                 /* Read attribute list */
463                 ldif_set_file( _ldifFile_, sFile );
464                 if( ldif_read_tags( _ldifFile_ ) == MGU_SUCCESS ) {
465                         /* Load fields */
466                         /* ldif_print_file( _ldifFile_, stdout ); */
467                         imp_ldif_load_fields( _ldifFile_ );
468                         retVal = TRUE;
469                 }
470                 else {
471                         sMsg = _( "Error reading LDIF fields." );
472                 }
473         }
474         imp_ldif_status_show( sMsg );
475
476         return retVal;
477 }
478
479 /**
480  * Display finish page.
481  */
482 static void imp_ldif_finish_show() {
483         gchar *sMsg;
484         gchar *name;
485
486         name = gtk_editable_get_chars( GTK_EDITABLE(impldif_dlg.entryName), 0, -1 );
487         gtk_label_set_text( GTK_LABEL(impldif_dlg.labelBook), name );
488         g_free( name );
489         gtk_label_set_text( GTK_LABEL(impldif_dlg.labelFile), _ldifFile_->path );
490         gtk_label_set_text( GTK_LABEL(impldif_dlg.labelRecords), itos( _ldifFile_->importCount ) );
491         gtk_widget_set_sensitive( impldif_dlg.btnPrev, FALSE );
492         gtk_widget_set_sensitive( impldif_dlg.btnNext, FALSE );
493         if( _ldifFile_->retVal == MGU_SUCCESS ) {
494                 sMsg = _( "LDIF file imported successfully." );
495         }
496         else {
497                 sMsg = imp_ldif_err2string( _lutErrorsLDIF_, _ldifFile_->retVal );
498         }
499         imp_ldif_status_show( sMsg );
500         gtk_widget_grab_focus(impldif_dlg.btnCancel);
501 }
502
503 /**
504  * Callback function to select previous page.
505  * \param widget Widget (button).
506  */
507 static void imp_ldif_prev( GtkWidget *widget ) {
508         gint pageNum;
509
510         pageNum = gtk_notebook_get_current_page( GTK_NOTEBOOK(impldif_dlg.notebook) );
511         if( pageNum == PAGE_ATTRIBUTES ) {
512                 /* Goto file page stuff */
513                 gtk_notebook_set_current_page(
514                         GTK_NOTEBOOK(impldif_dlg.notebook), PAGE_FILE_INFO );
515                 gtk_widget_set_sensitive( impldif_dlg.btnPrev, FALSE );
516         }
517         imp_ldif_message();
518 }
519
520 /**
521  * Callback function to select next page.
522  * \param widget Widget (button).
523  */
524 static void imp_ldif_next( GtkWidget *widget ) {
525         gint pageNum;
526
527         pageNum = gtk_notebook_get_current_page( GTK_NOTEBOOK(impldif_dlg.notebook) );
528         if( pageNum == PAGE_FILE_INFO ) {
529                 /* Goto attributes stuff */
530                 if( imp_ldif_file_move() ) {
531                         gtk_notebook_set_current_page(
532                                 GTK_NOTEBOOK(impldif_dlg.notebook), PAGE_ATTRIBUTES );
533                         imp_ldif_message();
534                         gtk_widget_set_sensitive( impldif_dlg.btnPrev, TRUE );
535                 }
536                 else {
537                         gtk_widget_set_sensitive( impldif_dlg.btnPrev, FALSE );
538                 }
539         }
540         else if( pageNum == PAGE_ATTRIBUTES ) {
541                 /* Goto finish stuff */
542                 if( imp_ldif_field_move() ) {
543                         gtk_notebook_set_current_page(
544                                 GTK_NOTEBOOK(impldif_dlg.notebook), PAGE_FINISH );
545                         imp_ldif_finish_show();
546                 }
547         }
548 }
549
550 /**
551  * Callback function to cancel and close dialog.
552  * \param widget Widget (button).
553  * \param data   User data.
554  */
555 static void imp_ldif_cancel( GtkWidget *widget, gpointer data ) {
556         gint pageNum;
557
558         pageNum = gtk_notebook_get_current_page( GTK_NOTEBOOK(impldif_dlg.notebook) );
559         if( pageNum != PAGE_FINISH ) {
560                 impldif_dlg.cancelled = TRUE;
561         }
562         gtk_main_quit();
563 }
564
565 /**
566  * Callback function to accept LDIF file selection.
567  * \param widget Widget (button).
568  * \param data   User data.
569  */
570 static void imp_ldif_file_ok( GtkWidget *widget, gpointer data ) {
571         const gchar *sFile;
572         AddressFileSelection *afs;
573         GtkWidget *fileSel;
574
575         afs = ( AddressFileSelection * ) data;
576         fileSel = afs->fileSelector;
577         sFile = gtk_file_selection_get_filename( GTK_FILE_SELECTION(fileSel) );
578
579         afs->cancelled = FALSE;
580         gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryFile), sFile );
581         gtk_widget_hide( afs->fileSelector );
582         gtk_grab_remove( afs->fileSelector );
583         gtk_widget_grab_focus( impldif_dlg.entryFile );
584 }
585
586 /**
587  * Callback function to cancel LDIF file selection dialog.
588  * \param widget Widget (button).
589  * \param data   User data.
590  */
591 static void imp_ldif_file_cancel( GtkWidget *widget, gpointer data ) {
592         AddressFileSelection *afs = ( AddressFileSelection * ) data;
593         afs->cancelled = TRUE;
594         gtk_widget_hide( afs->fileSelector );
595         gtk_grab_remove( afs->fileSelector );
596         gtk_widget_grab_focus( impldif_dlg.entryFile );
597 }
598
599 /**
600  * Create LDIF file selection dialog.
601  * \param afs Address file selection data.
602  */
603 static void imp_ldif_file_select_create( AddressFileSelection *afs ) {
604         GtkWidget *fileSelector;
605
606         fileSelector = gtk_file_selection_new( _("Select LDIF File") );
607         gtk_file_selection_hide_fileop_buttons( GTK_FILE_SELECTION(fileSelector) );
608         g_signal_connect( G_OBJECT (GTK_FILE_SELECTION(fileSelector)->ok_button),
609                           "clicked", G_CALLBACK (imp_ldif_file_ok), ( gpointer ) afs );
610         g_signal_connect( G_OBJECT (GTK_FILE_SELECTION(fileSelector)->cancel_button),
611                           "clicked", G_CALLBACK (imp_ldif_file_cancel), ( gpointer ) afs );
612         afs->fileSelector = fileSelector;
613         afs->cancelled = TRUE;
614 }
615
616 /**
617  * Callback function to display LDIF file selection dialog.
618  */
619 static void imp_ldif_file_select( void ) {
620         gchar *sFile;
621         if( ! _imp_ldif_file_selector_.fileSelector )
622                 imp_ldif_file_select_create( & _imp_ldif_file_selector_ );
623
624         sFile = gtk_editable_get_chars( GTK_EDITABLE(impldif_dlg.entryFile), 0, -1 );
625         gtk_file_selection_set_filename(
626                 GTK_FILE_SELECTION( _imp_ldif_file_selector_.fileSelector ),
627                 sFile );
628         g_free( sFile );
629         gtk_widget_show( _imp_ldif_file_selector_.fileSelector );
630         gtk_grab_add( _imp_ldif_file_selector_.fileSelector );
631 }
632
633 /**
634  * Callback function to handle dialog close event.
635  * \param widget Widget (dialog).
636  * \param event  Event object.
637  * \param data   User data.
638  */
639 static gint imp_ldif_delete_event( GtkWidget *widget, GdkEventAny *event, gpointer data ) {
640         imp_ldif_cancel( widget, data );
641         return TRUE;
642 }
643
644 /**
645  * Callback function to respond to dialog key press events.
646  * \param widget Widget.
647  * \param event  Event object.
648  * \param data   User data.
649  */
650 static gboolean imp_ldif_key_pressed( GtkWidget *widget, GdkEventKey *event, gpointer data ) {
651         if (event && event->keyval == GDK_Escape) {
652                 imp_ldif_cancel( widget, data );
653         }
654         return FALSE;
655 }
656
657 /**
658  * Format notebook "file" page.
659  * \param pageNum Page (tab) number.
660  * \param pageLbl Page (tab) label.
661  */
662 static void imp_ldif_page_file( gint pageNum, gchar *pageLbl ) {
663         GtkWidget *vbox;
664         GtkWidget *table;
665         GtkWidget *label;
666         GtkWidget *entryFile;
667         GtkWidget *entryName;
668         GtkWidget *btnFile;
669         GtkTooltips *toolTip;
670         gint top;
671
672         vbox = gtk_vbox_new(FALSE, 8);
673         gtk_container_add( GTK_CONTAINER( impldif_dlg.notebook ), vbox );
674         gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
675
676         label = gtk_label_new( pageLbl );
677         gtk_widget_show( label );
678         gtk_notebook_set_tab_label(
679                 GTK_NOTEBOOK( impldif_dlg.notebook ),
680                 gtk_notebook_get_nth_page(
681                         GTK_NOTEBOOK( impldif_dlg.notebook ), pageNum ),
682                 label );
683
684         table = gtk_table_new(2, 3, FALSE);
685         gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
686         gtk_container_set_border_width( GTK_CONTAINER(table), 8 );
687         gtk_table_set_row_spacings(GTK_TABLE(table), 8);
688         gtk_table_set_col_spacings(GTK_TABLE(table), 8 );
689
690         /* First row */
691         top = 0;
692         label = gtk_label_new(_("Address Book"));
693         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1),
694                 GTK_FILL, 0, 0, 0);
695         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
696
697         entryName = gtk_entry_new();
698         gtk_table_attach(GTK_TABLE(table), entryName, 1, 2, top, (top + 1),
699                 GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
700
701         toolTip = gtk_tooltips_new();
702         gtk_tooltips_set_tip( toolTip, entryName, _( 
703                 "Specify the name for the address book that will " \
704                 "be created from the LDIF file data." ),
705                 NULL );
706
707         /* Second row */
708         top = 1;
709         label = gtk_label_new(_("File Name"));
710         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1),
711                 GTK_FILL, 0, 0, 0);
712         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
713
714         entryFile = gtk_entry_new();
715         gtk_table_attach(GTK_TABLE(table), entryFile, 1, 2, top, (top + 1),
716                 GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
717
718         toolTip = gtk_tooltips_new();
719         gtk_tooltips_set_tip( toolTip, entryFile,
720                 _( "The full file specification of the LDIF file to import." ),
721                 NULL );
722
723         btnFile = gtk_button_new_with_label( _(" ... "));
724         gtk_table_attach(GTK_TABLE(table), btnFile, 2, 3, top, (top + 1),
725                 GTK_FILL, 0, 3, 0);
726
727         toolTip = gtk_tooltips_new();
728         gtk_tooltips_set_tip( toolTip, btnFile,
729                 _( "Select the LDIF file to import." ),
730                 NULL );
731
732         gtk_widget_show_all(vbox);
733
734         /* Button handler */
735         g_signal_connect(G_OBJECT(btnFile), "clicked",
736                          G_CALLBACK(imp_ldif_file_select), NULL);
737
738         impldif_dlg.entryFile = entryFile;
739         impldif_dlg.entryName = entryName;
740 }
741
742 /**
743  * Format notebook fields page.
744  * \param pageNum Page (tab) number.
745  * \param pageLbl Page (tab) label.
746  */
747 static void imp_ldif_page_fields( gint pageNum, gchar *pageLbl ) {
748         GtkWidget *vbox;
749         GtkWidget *vboxt;
750         GtkWidget *vboxb;
751         GtkWidget *table;
752         GtkWidget *label;
753         GtkWidget *clist_swin;
754         GtkWidget *clist_field;
755         GtkWidget *entryField;
756         GtkWidget *entryAttrib;
757         GtkWidget *checkSelect;
758         GtkWidget *btnModify;
759         GtkWidget *eventBox;
760         GtkTooltips *toolTip;
761         gint top;
762
763         gchar *titles[ FIELDS_N_COLS ];
764         gint i;
765
766         titles[ FIELD_COL_RESERVED ] = _("R");
767         titles[ FIELD_COL_SELECT   ] = _("S");
768         titles[ FIELD_COL_FIELD    ] = _("LDIF Field Name");
769         titles[ FIELD_COL_ATTRIB   ] = _("Attribute Name");
770
771         vbox = gtk_vbox_new(FALSE, 8);
772         gtk_container_add( GTK_CONTAINER( impldif_dlg.notebook ), vbox );
773         gtk_container_set_border_width( GTK_CONTAINER (vbox), 4 );
774
775         label = gtk_label_new( pageLbl );
776         gtk_widget_show( label );
777         gtk_notebook_set_tab_label(
778                 GTK_NOTEBOOK( impldif_dlg.notebook ),
779                 gtk_notebook_get_nth_page(GTK_NOTEBOOK( impldif_dlg.notebook ), pageNum ),
780                 label );
781
782         /* Upper area - Field list */
783         vboxt = gtk_vbox_new( FALSE, 4 );
784         gtk_container_add( GTK_CONTAINER( vbox ), vboxt );
785
786         clist_swin = gtk_scrolled_window_new( NULL, NULL );
787         gtk_container_add( GTK_CONTAINER(vboxt), clist_swin );
788         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
789                                        GTK_POLICY_AUTOMATIC,
790                                        GTK_POLICY_AUTOMATIC);
791
792         clist_field = gtk_clist_new_with_titles( FIELDS_N_COLS, titles );
793         gtk_container_add( GTK_CONTAINER(clist_swin), clist_field );
794         gtk_clist_set_selection_mode(
795                 GTK_CLIST(clist_field), GTK_SELECTION_BROWSE );
796         gtk_clist_set_column_width( GTK_CLIST(clist_field),
797                 FIELD_COL_RESERVED, FIELDS_COL_WIDTH_RESERVED );
798         gtk_clist_set_column_width( GTK_CLIST(clist_field),
799                 FIELD_COL_SELECT, FIELDS_COL_WIDTH_SELECT );
800         gtk_clist_set_column_width( GTK_CLIST(clist_field),
801                 FIELD_COL_FIELD, FIELDS_COL_WIDTH_FIELD );
802         gtk_clist_set_column_width( GTK_CLIST(clist_field),
803                 FIELD_COL_ATTRIB, FIELDS_COL_WIDTH_ATTRIB );
804
805         /* Remove focus capability for column headers */
806         for( i = 0; i < FIELDS_N_COLS; i++ ) {
807                 GTK_WIDGET_UNSET_FLAGS(
808                         GTK_CLIST(clist_field)->column[i].button,
809                         GTK_CAN_FOCUS);
810         }
811
812         /* Lower area - Edit area */
813         vboxb = gtk_vbox_new( FALSE, 4 );
814         gtk_box_pack_end(GTK_BOX(vbox), vboxb, FALSE, FALSE, 2);
815
816         /* Data entry area */
817         table = gtk_table_new( 3, 3, FALSE);
818         gtk_box_pack_start(GTK_BOX(vboxb), table, FALSE, FALSE, 0);
819         gtk_table_set_row_spacings(GTK_TABLE(table), 4);
820         gtk_table_set_col_spacings(GTK_TABLE(table), 4);
821
822         /* First row */
823         top = 0;
824         label = gtk_label_new(_("LDIF Field"));
825         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1),
826                 GTK_FILL, 0, 0, 0);
827         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
828
829         entryField = gtk_label_new( "" );
830         gtk_misc_set_alignment(GTK_MISC(entryField), 0.01, 0.5);
831         gtk_table_attach(GTK_TABLE(table), entryField, 1, 3, top, (top + 1),
832                 GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
833
834         /* Second row */
835         ++top;
836         label = gtk_label_new(_("Attribute"));
837         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1),
838                 GTK_FILL, 0, 0, 0);
839         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
840
841         entryAttrib = gtk_entry_new();
842         gtk_table_attach(GTK_TABLE(table), entryAttrib, 1, 3, top, (top + 1),
843                 GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
844
845         toolTip = gtk_tooltips_new();
846         gtk_tooltips_set_tip( toolTip, entryAttrib,
847                 _( "The LDIF field can be renamed to the User Attribute name." ),
848                 NULL );
849
850         /* Next row */
851         ++top;
852         label = gtk_label_new( _( "???" ) );
853         /*
854         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1),
855                 GTK_FILL, 0, 0, 0);
856         */
857         gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
858
859         /*
860          * Use an event box to attach some help in the form of a tooltip.
861          * Tried this for the clist but it looked bad.
862          */
863         eventBox = gtk_event_box_new();
864         gtk_container_add( GTK_CONTAINER(eventBox), label );
865         gtk_table_attach(GTK_TABLE(table), eventBox, 0, 1, top, (top + 1),
866                 GTK_FILL, 0, 0, 0);
867
868         toolTip = gtk_tooltips_new();
869         gtk_tooltips_set_tip( toolTip, eventBox, _(
870                 "Choose the LDIF field that will be renamed or selected " \
871                 "for import in the list above. Reserved fields (marked " \
872                 "with a tick in the \"R\" column), are automatically " \
873                 "imported and cannot be renamed. A single click in the " \
874                 "Select (\"S\") column will select the field for import " \
875                 "with a tick. A single click anywhere in the row will " \
876                 "select that field for rename in the input area below " \
877                 "the list. A double click anywhere in the row will also " \
878                 "select the field for import."
879                 ), NULL );
880
881
882         checkSelect = gtk_check_button_new_with_label( _( "Select for Import" ) );
883         gtk_table_attach(GTK_TABLE(table), checkSelect, 1, 2, top, (top + 1),
884                 GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
885
886         toolTip = gtk_tooltips_new();
887         gtk_tooltips_set_tip( toolTip, checkSelect,
888                 _( "Select the LDIF field for import into the address book." ),
889                 NULL );
890
891         btnModify = gtk_button_new_with_label( _(" Modify "));
892         gtk_table_attach(GTK_TABLE(table), btnModify, 2, 3, top, (top + 1),
893                 GTK_FILL, 0, 3, 0);
894
895         toolTip = gtk_tooltips_new();
896         gtk_tooltips_set_tip( toolTip, btnModify,
897                 _( "This button will update the list above with the data supplied." ),
898                 NULL );
899
900         gtk_widget_show_all(vbox);
901
902         /* Event handlers */
903         g_signal_connect( G_OBJECT(clist_field), "select_row",
904                           G_CALLBACK(imp_ldif_field_list_selected), NULL );
905         g_signal_connect( G_OBJECT(clist_field), "button_press_event",
906                           G_CALLBACK(imp_ldif_field_list_toggle), NULL );
907         g_signal_connect( G_OBJECT(btnModify), "clicked",
908                           G_CALLBACK(imp_ldif_modify_pressed), NULL );
909
910         impldif_dlg.clist_field = clist_field;
911         impldif_dlg.entryField  = entryField;
912         impldif_dlg.entryAttrib = entryAttrib;
913         impldif_dlg.checkSelect = checkSelect;
914         impldif_dlg.btnModify   = btnModify;
915 }
916
917 /**
918  * Format notebook finish page.
919  * \param pageNum Page (tab) number.
920  * \param pageLbl Page (tab) label.
921  */
922 static void imp_ldif_page_finish( gint pageNum, gchar *pageLbl ) {
923         GtkWidget *vbox;
924         GtkWidget *table;
925         GtkWidget *label;
926         GtkWidget *labelBook;
927         GtkWidget *labelFile;
928         GtkWidget *labelRecs;
929         gint top;
930
931         vbox = gtk_vbox_new(FALSE, 8);
932         gtk_container_add( GTK_CONTAINER( impldif_dlg.notebook ), vbox );
933         gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
934
935         label = gtk_label_new( pageLbl );
936         gtk_widget_show( label );
937         gtk_notebook_set_tab_label(
938                 GTK_NOTEBOOK( impldif_dlg.notebook ),
939                 gtk_notebook_get_nth_page( GTK_NOTEBOOK( impldif_dlg.notebook ), pageNum ),
940                 label );
941
942         table = gtk_table_new(3, 2, FALSE);
943         gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
944         gtk_container_set_border_width( GTK_CONTAINER(table), 8 );
945         gtk_table_set_row_spacings(GTK_TABLE(table), 8);
946         gtk_table_set_col_spacings(GTK_TABLE(table), 8);
947
948         /* First row */
949         top = 0;
950         label = gtk_label_new( _( "Address Book :" ) );
951         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
952         gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
953
954         labelBook = gtk_label_new("");
955         gtk_table_attach(GTK_TABLE(table), labelBook, 1, 2, top, (top + 1), GTK_FILL, 0, 0, 0);
956         gtk_misc_set_alignment(GTK_MISC(labelBook), 0, 0.5);
957
958         /* Second row */
959         top++;
960         label = gtk_label_new( _( "File Name :" ) );
961         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
962         gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
963
964         labelFile = gtk_label_new("");
965         gtk_table_attach(GTK_TABLE(table), labelFile, 1, 2, top, (top + 1), GTK_FILL, 0, 0, 0);
966         gtk_misc_set_alignment(GTK_MISC(labelFile), 0, 0.5);
967
968         /* Third row */
969         top++;
970         label = gtk_label_new( _("Records Imported :") );
971         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
972         gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
973
974         labelRecs = gtk_label_new("");
975         gtk_table_attach(GTK_TABLE(table), labelRecs, 1, 2, top, (top + 1), GTK_FILL, 0, 0, 0);
976         gtk_misc_set_alignment(GTK_MISC(labelRecs), 0, 0.5);
977
978         impldif_dlg.labelBook    = labelBook;
979         impldif_dlg.labelFile    = labelFile;
980         impldif_dlg.labelRecords = labelRecs;
981 }
982
983 /**
984  * Create main dialog decorations (excluding notebook pages).
985  */
986 static void imp_ldif_dialog_create() {
987         GtkWidget *window;
988         GtkWidget *vbox;
989         GtkWidget *vnbox;
990         GtkWidget *notebook;
991         GtkWidget *hbbox;
992         GtkWidget *btnPrev;
993         GtkWidget *btnNext;
994         GtkWidget *btnCancel;
995         GtkWidget *hsbox;
996         GtkWidget *statusbar;
997
998         window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
999         gtk_widget_set_size_request(window, IMPORTLDIF_WIDTH, IMPORTLDIF_HEIGHT );
1000         gtk_container_set_border_width( GTK_CONTAINER(window), 0 );
1001         gtk_window_set_title( GTK_WINDOW(window), _("Import LDIF file into Address Book") );
1002         gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
1003         gtk_window_set_modal(GTK_WINDOW(window), TRUE); 
1004         g_signal_connect(G_OBJECT(window), "delete_event",
1005                          G_CALLBACK(imp_ldif_delete_event),
1006                          NULL );
1007         g_signal_connect(G_OBJECT(window), "key_press_event",
1008                          G_CALLBACK(imp_ldif_key_pressed),
1009                          NULL );
1010
1011         vbox = gtk_vbox_new(FALSE, 4);
1012         gtk_widget_show(vbox);
1013         gtk_container_add(GTK_CONTAINER(window), vbox);
1014
1015         vnbox = gtk_vbox_new(FALSE, 4);
1016         gtk_container_set_border_width(GTK_CONTAINER(vnbox), 4);
1017         gtk_widget_show(vnbox);
1018         gtk_box_pack_start(GTK_BOX(vbox), vnbox, TRUE, TRUE, 0);
1019
1020         /* Notebook */
1021         notebook = gtk_notebook_new();
1022         gtk_notebook_set_show_tabs( GTK_NOTEBOOK(notebook), FALSE );
1023         gtk_widget_show(notebook);
1024         gtk_box_pack_start(GTK_BOX(vnbox), notebook, TRUE, TRUE, 0);
1025         gtk_container_set_border_width(GTK_CONTAINER(notebook), 6);
1026
1027         /* Status line */
1028         hsbox = gtk_hbox_new(FALSE, 0);
1029         gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1030         statusbar = gtk_statusbar_new();
1031         gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1032
1033         /* Button panel */
1034         gtkut_button_set_create(&hbbox, &btnPrev, _( "Prev" ),
1035                                 &btnNext, _( "Next" ),
1036                                 &btnCancel, _( "Cancel" ) );
1037         gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1038         gtk_container_set_border_width(GTK_CONTAINER(hbbox), 2);
1039         gtk_widget_grab_default(btnNext);
1040
1041         /* Button handlers */
1042         g_signal_connect(G_OBJECT(btnPrev), "clicked",
1043                          G_CALLBACK(imp_ldif_prev), NULL);
1044         g_signal_connect(G_OBJECT(btnNext), "clicked",
1045                          G_CALLBACK(imp_ldif_next), NULL);
1046         g_signal_connect(G_OBJECT(btnCancel), "clicked",
1047                          G_CALLBACK(imp_ldif_cancel), NULL);
1048
1049         gtk_widget_show_all(vbox);
1050
1051         impldif_dlg.window     = window;
1052         impldif_dlg.notebook   = notebook;
1053         impldif_dlg.btnPrev    = btnPrev;
1054         impldif_dlg.btnNext    = btnNext;
1055         impldif_dlg.btnCancel  = btnCancel;
1056         impldif_dlg.statusbar  = statusbar;
1057         impldif_dlg.status_cid = gtk_statusbar_get_context_id(
1058                         GTK_STATUSBAR(statusbar), "Import LDIF Dialog" );
1059
1060 }
1061
1062 /**
1063  * Create import LDIF dialog.
1064  */
1065 static void imp_ldif_create() {
1066         imp_ldif_dialog_create();
1067         imp_ldif_page_file( PAGE_FILE_INFO, _( "File Info" ) );
1068         imp_ldif_page_fields( PAGE_ATTRIBUTES, _( "Attributes" ) );
1069         imp_ldif_page_finish( PAGE_FINISH, _( "Finish" ) );
1070         gtk_widget_show_all( impldif_dlg.window );
1071 }
1072
1073 /**
1074  * Import LDIF file.
1075  * \param  addrIndex Address index.
1076  * \return Address book file of imported data, or <i>NULL</i> if import
1077  *         was cancelled.
1078  */
1079 AddressBookFile *addressbook_imp_ldif( AddressIndex *addrIndex ) {
1080         _importedBook_ = NULL;
1081         _imp_addressIndex_ = addrIndex;
1082
1083         if( ! impldif_dlg.window )
1084                 imp_ldif_create();
1085         impldif_dlg.cancelled = FALSE;
1086         gtk_widget_show(impldif_dlg.window);
1087         manage_window_set_transient(GTK_WINDOW(impldif_dlg.window));
1088         gtk_widget_grab_default(impldif_dlg.btnNext);
1089
1090         gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryName), IMPORTLDIF_GUESS_NAME );
1091         gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryFile), "" );
1092         gtk_label_set_text( GTK_LABEL(impldif_dlg.entryField), "" );
1093         gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryAttrib), "" );
1094         gtk_clist_clear( GTK_CLIST(impldif_dlg.clist_field) );
1095         gtk_notebook_set_current_page( GTK_NOTEBOOK(impldif_dlg.notebook), PAGE_FILE_INFO );
1096         gtk_widget_set_sensitive( impldif_dlg.btnPrev, FALSE );
1097         gtk_widget_set_sensitive( impldif_dlg.btnNext, TRUE );
1098         stock_pixmap_gdk( impldif_dlg.window, STOCK_PIXMAP_MARK,
1099                           &markxpm, &markxpmmask );
1100         imp_ldif_message();
1101         gtk_widget_grab_focus(impldif_dlg.entryFile);
1102
1103         impldif_dlg.rowIndSelect = -1;
1104         impldif_dlg.rowCount = 0;
1105         g_free( impldif_dlg.nameBook );
1106         g_free( impldif_dlg.fileName );
1107         impldif_dlg.nameBook = NULL;
1108         impldif_dlg.fileName = NULL;
1109
1110         _ldifFile_ = ldif_create();
1111         gtk_main();
1112         gtk_widget_hide(impldif_dlg.window);
1113         ldif_free( _ldifFile_ );
1114         _ldifFile_ = NULL;
1115         _imp_addressIndex_ = NULL;
1116
1117         g_free( impldif_dlg.nameBook );
1118         g_free( impldif_dlg.fileName );
1119         impldif_dlg.nameBook = NULL;
1120         impldif_dlg.fileName = NULL;
1121
1122         if( impldif_dlg.cancelled == TRUE ) return NULL;
1123         return _importedBook_;
1124 }
1125
1126 /*
1127  * ============================================================================
1128  * End of Source.
1129  * ============================================================================
1130  */
1131