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