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  */
imp_ldif_err2string(ErrMsgTableEntry lut[],gint code)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  */
imp_ldif_status_show(gchar * msg)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  */
imp_ldif_message(void)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  */
_populate_iter(GtkListStore * store,GtkTreeIter * iter,Ldif_FieldRec * rec)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  */
imp_ldif_load_fields(LdifFile * ldf)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  */
imp_ldif_field_move()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 
_update_selected_row()278 static void _update_selected_row()
279 {
280 	GtkTreeModel *model;
281 	GtkTreeIter iter;
282 	Ldif_FieldRec *rec;
283 
284 	rec = gtkut_tree_view_get_selected_pointer(
285 			GTK_TREE_VIEW(impldif_dlg.view_fields), FIELD_COL_PTR,
286 			&model, NULL, &iter);
287 	if (rec == NULL)
288 		return;
289 
290 	ldif_field_set_name(rec, gtk_entry_get_text(
291 				GTK_ENTRY(impldif_dlg.entryAttrib)));
292 	ldif_field_set_selected(rec, gtk_toggle_button_get_active(
293 				GTK_TOGGLE_BUTTON(impldif_dlg.checkSelect)));
294 
295 	_populate_iter(GTK_LIST_STORE(model), &iter, rec);
296 }
297 
imp_ldif_modify_pressed(GtkButton * widget,gpointer user_data)298 static void imp_ldif_modify_pressed(GtkButton *widget, gpointer user_data)
299 {
300 	_update_selected_row();
301 }
302 
imp_ldif_entryattrib_activate(GtkEntry * entry,gpointer user_data)303 static void imp_ldif_entryattrib_activate(GtkEntry *entry, gpointer user_data)
304 {
305 	_update_selected_row();
306 }
307 
308 /**
309  * Test whether we can move off file page.
310  * \return <i>TRUE</i> if OK to move off page.
311  */
imp_ldif_file_move()312 static gboolean imp_ldif_file_move() {
313 	gboolean retVal = FALSE;
314 	gchar *sName;
315 	gchar *sFile;
316 	gchar *sMsg = NULL;
317 	gboolean errFlag = FALSE;
318 
319 	sFile = gtk_editable_get_chars( GTK_EDITABLE(impldif_dlg.entryFile), 0, -1 );
320 	g_strstrip( sFile );
321 
322 	sName = gtk_editable_get_chars( GTK_EDITABLE(impldif_dlg.entryName), 0, -1 );
323 	g_strstrip( sName );
324 
325 	g_free( impldif_dlg.nameBook );
326 	g_free( impldif_dlg.fileName );
327 	impldif_dlg.nameBook = sName;
328 	impldif_dlg.fileName = sFile;
329 
330 	gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryFile), sFile );
331 	gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryName), sName );
332 
333 	if( *sFile == '\0' ) {
334 		sMsg = _( "Please select a file." );
335 		gtk_widget_grab_focus(impldif_dlg.entryFile);
336 		errFlag = TRUE;
337 	}
338 
339 	if( ! errFlag && *sName == '\0' ) {
340 		sMsg = _( "Address book name must be supplied." );
341 		gtk_widget_grab_focus(impldif_dlg.entryName);
342 		errFlag = TRUE;
343 	}
344 
345 	if( ! errFlag ) {
346 		/* Read attribute list */
347 		ldif_set_file( _ldifFile_, sFile );
348 		if( ldif_read_tags( _ldifFile_ ) == MGU_SUCCESS ) {
349 			/* Load fields */
350 			/* ldif_print_file( _ldifFile_, stdout ); */
351 			imp_ldif_load_fields( _ldifFile_ );
352 			retVal = TRUE;
353 		}
354 		else {
355 			sMsg = imp_ldif_err2string( _lutErrorsLDIF_, _ldifFile_->retVal );
356 		}
357 	}
358 	imp_ldif_status_show( sMsg );
359 
360 	return retVal;
361 }
362 
363 /**
364  * Display finish page.
365  */
imp_ldif_finish_show()366 static void imp_ldif_finish_show() {
367 	gchar *sMsg;
368 	gchar *name;
369 
370 	name = gtk_editable_get_chars( GTK_EDITABLE(impldif_dlg.entryName), 0, -1 );
371 	gtk_label_set_text( GTK_LABEL(impldif_dlg.labelBook), name );
372 	g_free( name );
373 	gtk_label_set_text( GTK_LABEL(impldif_dlg.labelFile), _ldifFile_->path );
374 	gtk_label_set_text( GTK_LABEL(impldif_dlg.labelRecords), itos( _ldifFile_->importCount ) );
375 	gtk_widget_set_sensitive( impldif_dlg.btnPrev, FALSE );
376 	gtk_widget_hide( impldif_dlg.btnNext );
377 	gtk_widget_show( impldif_dlg.btnProceed );
378 	gtk_widget_set_sensitive( impldif_dlg.btnProceed, FALSE );
379 	if( _ldifFile_->retVal == MGU_SUCCESS ) {
380 		sMsg = _( "LDIF file imported successfully." );
381 	}
382 	else {
383 		sMsg = imp_ldif_err2string( _lutErrorsLDIF_, _ldifFile_->retVal );
384 	}
385 	imp_ldif_status_show( sMsg );
386 	gtk_widget_grab_focus(impldif_dlg.btnCancel);
387 }
388 
389 /**
390  * Callback function to select previous page.
391  * \param widget Widget (button).
392  */
imp_ldif_prev(GtkWidget * widget)393 static void imp_ldif_prev( GtkWidget *widget ) {
394 	gint pageNum;
395 
396 	pageNum = gtk_notebook_get_current_page( GTK_NOTEBOOK(impldif_dlg.notebook) );
397 	if( pageNum == PAGE_ATTRIBUTES ) {
398 		/* Goto file page stuff */
399 		gtk_notebook_set_current_page(
400 			GTK_NOTEBOOK(impldif_dlg.notebook), PAGE_FILE_INFO );
401 		gtk_widget_set_sensitive( impldif_dlg.btnPrev, FALSE );
402 		gtk_widget_hide( impldif_dlg.btnProceed );
403 		gtk_widget_show( impldif_dlg.btnNext );
404 	}
405 	imp_ldif_message();
406 }
407 
408 /**
409  * Callback function to select next page.
410  * \param widget Widget (button).
411  */
imp_ldif_next(GtkWidget * widget)412 static void imp_ldif_next( GtkWidget *widget ) {
413 	gint pageNum;
414 
415 	pageNum = gtk_notebook_get_current_page( GTK_NOTEBOOK(impldif_dlg.notebook) );
416 	if( pageNum == PAGE_FILE_INFO ) {
417 		/* Goto attributes stuff */
418 		if( imp_ldif_file_move() ) {
419 			gtk_notebook_set_current_page(
420 				GTK_NOTEBOOK(impldif_dlg.notebook), PAGE_ATTRIBUTES );
421 			imp_ldif_message();
422 			gtk_widget_set_sensitive( impldif_dlg.btnPrev, TRUE );
423 			gtk_widget_hide( impldif_dlg.btnNext );
424 			gtk_widget_show( impldif_dlg.btnProceed );
425 			gtk_widget_set_sensitive( impldif_dlg.btnProceed, TRUE );
426 		}
427 		else {
428 			gtk_widget_set_sensitive( impldif_dlg.btnPrev, FALSE );
429 			_ldifFile_->dirtyFlag = TRUE;
430 		}
431 	}
432 	else if( pageNum == PAGE_ATTRIBUTES ) {
433 		/* Goto finish stuff */
434 		if( imp_ldif_field_move() ) {
435 			gtk_notebook_set_current_page(
436 				GTK_NOTEBOOK(impldif_dlg.notebook), PAGE_FINISH );
437 			gtk_button_set_label(GTK_BUTTON(impldif_dlg.btnCancel),
438 					     GTK_STOCK_CLOSE);
439 			imp_ldif_finish_show();
440 		}
441 	}
442 }
443 
444 /**
445  * Callback function to cancel and close dialog.
446  * \param widget Widget (button).
447  * \param data   User data.
448  */
imp_ldif_cancel(GtkWidget * widget,gpointer data)449 static void imp_ldif_cancel( GtkWidget *widget, gpointer data ) {
450 	gint pageNum;
451 
452 	pageNum = gtk_notebook_get_current_page( GTK_NOTEBOOK(impldif_dlg.notebook) );
453 	if( pageNum != PAGE_FINISH ) {
454 		impldif_dlg.cancelled = TRUE;
455 	}
456 	gtk_main_quit();
457 }
458 
459 
460 /**
461  * Create LDIF file selection dialog.
462  * \param afs Address file selection data.
463  */
imp_ldif_file_select_create(AddressFileSelection * afs)464 static void imp_ldif_file_select_create( AddressFileSelection *afs ) {
465 	gchar *file = filesel_select_file_open(_("Select LDIF File"), NULL);
466 
467 	if (file == NULL)
468 		afs->cancelled = TRUE;
469 	else {
470 		afs->cancelled = FALSE;
471 		gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryFile), file );
472 		g_free(file);
473 	}
474 }
475 
476 /**
477  * Callback function to display LDIF file selection dialog.
478  */
imp_ldif_file_select(void)479 static void imp_ldif_file_select( void ) {
480 	imp_ldif_file_select_create( & _imp_ldif_file_selector_ );
481 }
482 
483 /**
484  * Callback function to handle dialog close event.
485  * \param widget Widget (dialog).
486  * \param event  Event object.
487  * \param data   User data.
488  */
imp_ldif_delete_event(GtkWidget * widget,GdkEventAny * event,gpointer data)489 static gint imp_ldif_delete_event( GtkWidget *widget, GdkEventAny *event, gpointer data ) {
490 	imp_ldif_cancel( widget, data );
491 	return TRUE;
492 }
493 
494 /**
495  * Callback function to respond to dialog key press events.
496  * \param widget Widget.
497  * \param event  Event object.
498  * \param data   User data.
499  */
imp_ldif_key_pressed(GtkWidget * widget,GdkEventKey * event,gpointer data)500 static gboolean imp_ldif_key_pressed( GtkWidget *widget, GdkEventKey *event, gpointer data ) {
501 	if (event && event->keyval == GDK_KEY_Escape) {
502 		imp_ldif_cancel( widget, data );
503 	}
504 	return FALSE;
505 }
506 
507 /**
508  * Format notebook "file" page.
509  * \param pageNum Page (tab) number.
510  * \param pageLbl Page (tab) label.
511  */
imp_ldif_page_file(gint pageNum,gchar * pageLbl)512 static void imp_ldif_page_file( gint pageNum, gchar *pageLbl ) {
513 	GtkWidget *vbox;
514 	GtkWidget *table;
515 	GtkWidget *label;
516 	GtkWidget *entryFile;
517 	GtkWidget *entryName;
518 	GtkWidget *btnFile;
519 	gint top;
520 
521 	vbox = gtk_vbox_new(FALSE, 8);
522 	gtk_container_add( GTK_CONTAINER( impldif_dlg.notebook ), vbox );
523 	gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
524 
525 	label = gtk_label_new( pageLbl );
526 	gtk_widget_show( label );
527 	gtk_notebook_set_tab_label(
528 		GTK_NOTEBOOK( impldif_dlg.notebook ),
529 		gtk_notebook_get_nth_page(
530 			GTK_NOTEBOOK( impldif_dlg.notebook ), pageNum ),
531 		label );
532 
533 	table = gtk_table_new(2, 3, FALSE);
534 	gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
535 	gtk_container_set_border_width( GTK_CONTAINER(table), 8 );
536 	gtk_table_set_row_spacings(GTK_TABLE(table), 8);
537 	gtk_table_set_col_spacings(GTK_TABLE(table), 8 );
538 
539 	/* First row */
540 	top = 0;
541 	label = gtk_label_new(_("Address Book"));
542 	gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1),
543 		GTK_FILL, 0, 0, 0);
544 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
545 
546 	entryName = gtk_entry_new();
547 	gtk_table_attach(GTK_TABLE(table), entryName, 1, 2, top, (top + 1),
548 		GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
549 
550 	CLAWS_SET_TIP(entryName, _(
551 		"Specify the name for the address book that will " \
552 		"be created from the LDIF file data." ));
553 
554 	/* Second row */
555 	top = 1;
556 	label = gtk_label_new(_("File Name"));
557 	gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1),
558 		GTK_FILL, 0, 0, 0);
559 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
560 
561 	entryFile = gtk_entry_new();
562 	gtk_table_attach(GTK_TABLE(table), entryFile, 1, 2, top, (top + 1),
563 		GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
564 
565 	CLAWS_SET_TIP(entryFile,
566 		_( "The full file specification of the LDIF file to import." ));
567 
568 	btnFile = gtkut_get_browse_file_btn(_("B_rowse"));
569 	gtk_table_attach(GTK_TABLE(table), btnFile, 2, 3, top, (top + 1),
570 		GTK_FILL, 0, 3, 0);
571 
572 	CLAWS_SET_TIP(btnFile,
573 		_( "Select the LDIF file to import." ));
574 
575 	gtk_widget_show_all(vbox);
576 
577 	/* Button handler */
578 	g_signal_connect(G_OBJECT(btnFile), "clicked",
579 			 G_CALLBACK(imp_ldif_file_select), NULL);
580 
581 	impldif_dlg.entryFile = entryFile;
582 	impldif_dlg.entryName = entryName;
583 
584 }
585 
imp_ldif_field_list_cursor_changed(GtkTreeView * view,gpointer user_data)586 static void imp_ldif_field_list_cursor_changed(GtkTreeView *view,
587 		gpointer user_data)
588 {
589 	Ldif_FieldRec *rec;
590 
591 	gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryAttrib), "" );
592 
593 	rec = gtkut_tree_view_get_selected_pointer(view, FIELD_COL_PTR,
594 			NULL, NULL, NULL);
595 
596 	if( rec != NULL) {
597 		/* Update widget contents */
598 		gtk_label_set_text(
599 			GTK_LABEL(impldif_dlg.entryField), rec->tagName );
600 		if( rec->userName )
601 			gtk_entry_set_text(
602 				GTK_ENTRY(impldif_dlg.entryAttrib), rec->userName );
603 		gtk_toggle_button_set_active(
604 			GTK_TOGGLE_BUTTON(impldif_dlg.checkSelect),
605 			rec->selected );
606 
607 		/* Disable widgets for reserved fields */
608 		gtk_widget_set_sensitive(
609 			impldif_dlg.entryAttrib, ! rec->reserved );
610 		gtk_widget_set_sensitive(
611 			impldif_dlg.checkSelect, ! rec->reserved );
612 		gtk_widget_set_sensitive(
613 			impldif_dlg.btnModify,   ! rec->reserved );
614 	}
615 	gtk_widget_grab_focus(impldif_dlg.entryAttrib);
616 }
617 
imp_ldif_field_list_row_activated(GtkTreeView * view,GtkTreePath * path,GtkTreeViewColumn * col,gpointer user_data)618 static void imp_ldif_field_list_row_activated(GtkTreeView *view,
619 		GtkTreePath *path, GtkTreeViewColumn *col,
620 		gpointer user_data)
621 {
622 	GtkTreeModel *model = gtk_tree_view_get_model(view);
623 	GtkTreeIter iter;
624 	gboolean ok;
625 	Ldif_FieldRec *rec;
626 
627 	ok = gtk_tree_model_get_iter(model, &iter, path);
628 	if (!ok) {
629 		return; /* Huh? */
630 	}
631 
632 	gtk_tree_model_get(model, &iter, FIELD_COL_PTR, &rec, -1);
633 	cm_return_if_fail(rec != NULL);
634 
635 	/* Flip the "selected" state for the record, and update the
636 	 * "selected" column in the list view, as well as the
637 	 * "selected" checkbox. */
638 	ldif_field_toggle(rec);
639 	gtk_list_store_set(GTK_LIST_STORE(model), &iter,
640 			FIELD_COL_SELECT, rec->selected ? markxpm : NULL, -1);
641 	gtk_toggle_button_set_active(
642 		GTK_TOGGLE_BUTTON(impldif_dlg.checkSelect),
643 		rec->selected );
644 }
645 
646 /**
647  * Format notebook fields page.
648  * \param pageNum Page (tab) number.
649  * \param pageLbl Page (tab) label.
650  */
imp_ldif_page_fields(gint pageNum,gchar * pageLbl)651 static void imp_ldif_page_fields( gint pageNum, gchar *pageLbl ) {
652 	GtkWidget *vbox;
653 	GtkWidget *vboxt;
654 	GtkWidget *vboxb;
655 	GtkWidget *table;
656 	GtkWidget *label;
657 	GtkWidget *scrollwin;
658 	GtkWidget *view_fields;
659 	GtkWidget *entryField;
660 	GtkWidget *entryAttrib;
661 	GtkWidget *checkSelect;
662 	GtkWidget *btnModify;
663 	GtkWidget *eventBox;
664 	gint top;
665 	GtkListStore *store;
666 	GtkCellRenderer *rdr;
667 	GtkTreeViewColumn *col;
668 	GtkTreeSelection *sel;
669 
670 	vbox = gtk_vbox_new(FALSE, 8);
671 	gtk_container_add( GTK_CONTAINER( impldif_dlg.notebook ), vbox );
672 	gtk_container_set_border_width( GTK_CONTAINER (vbox), 4 );
673 
674 	label = gtk_label_new( pageLbl );
675 	gtk_widget_show( label );
676 	gtk_notebook_set_tab_label(
677 		GTK_NOTEBOOK( impldif_dlg.notebook ),
678 		gtk_notebook_get_nth_page(GTK_NOTEBOOK( impldif_dlg.notebook ), pageNum ),
679 		label );
680 
681 	/* Upper area - Field list */
682 	vboxt = gtk_vbox_new( FALSE, 4 );
683 	gtk_container_add( GTK_CONTAINER( vbox ), vboxt );
684 
685 	scrollwin = gtk_scrolled_window_new( NULL, NULL );
686 	gtk_container_add( GTK_CONTAINER(vboxt), scrollwin );
687 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
688 				       GTK_POLICY_AUTOMATIC,
689 				       GTK_POLICY_AUTOMATIC);
690 
691 	store = gtk_list_store_new(FIELDS_N_COLS,
692 			GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF,
693 			G_TYPE_STRING, G_TYPE_STRING,
694 			G_TYPE_POINTER,
695 			-1);
696 
697 	view_fields = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
698 	g_object_unref(store);
699 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view_fields), TRUE);
700 	gtk_tree_view_set_reorderable(GTK_TREE_VIEW(view_fields), FALSE);
701 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view_fields));
702 	gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
703 
704 	rdr = gtk_cell_renderer_pixbuf_new();
705 	col = gtk_tree_view_column_new_with_attributes(_("R"), rdr,
706 			"pixbuf", FIELD_COL_RESERVED, NULL);
707 	gtk_tree_view_column_set_min_width(col, FIELD_COL_RESERVED);
708 	gtk_tree_view_append_column(GTK_TREE_VIEW(view_fields), col);
709 
710 	col = gtk_tree_view_column_new_with_attributes(_("S"), rdr,
711 			"pixbuf", FIELD_COL_SELECT, NULL);
712 	gtk_tree_view_column_set_min_width(col, FIELD_COL_SELECT);
713 	gtk_tree_view_append_column(GTK_TREE_VIEW(view_fields), col);
714 
715 	rdr = gtk_cell_renderer_text_new();
716 	col = gtk_tree_view_column_new_with_attributes(_("LDIF Field Name"), rdr,
717 			"markup", FIELD_COL_FIELD, NULL);
718 	gtk_tree_view_column_set_min_width(col, FIELD_COL_FIELD);
719 	gtk_tree_view_append_column(GTK_TREE_VIEW(view_fields), col);
720 
721 	col = gtk_tree_view_column_new_with_attributes(_("Attribute Name"), rdr,
722 			"markup", FIELD_COL_ATTRIB, NULL);
723 	gtk_tree_view_column_set_min_width(col, FIELD_COL_ATTRIB);
724 	gtk_tree_view_append_column(GTK_TREE_VIEW(view_fields), col);
725 
726 	gtk_container_add( GTK_CONTAINER(scrollwin), view_fields );
727 
728 	/* Lower area - Edit area */
729 	vboxb = gtk_vbox_new( FALSE, 4 );
730 	gtk_box_pack_end(GTK_BOX(vbox), vboxb, FALSE, FALSE, 2);
731 
732 	/* Data entry area */
733 	table = gtk_table_new( 3, 3, FALSE);
734 	gtk_box_pack_start(GTK_BOX(vboxb), table, FALSE, FALSE, 0);
735 	gtk_table_set_row_spacings(GTK_TABLE(table), 4);
736 	gtk_table_set_col_spacings(GTK_TABLE(table), 4);
737 
738 	/* First row */
739 	top = 0;
740 	label = gtk_label_new(_("LDIF Field"));
741 	gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1),
742 		GTK_FILL, 0, 0, 0);
743 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
744 
745 	entryField = gtk_label_new( "" );
746 	gtk_misc_set_alignment(GTK_MISC(entryField), 0.01, 0.5);
747 	gtk_table_attach(GTK_TABLE(table), entryField, 1, 3, top, (top + 1),
748 		GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
749 
750 	/* Second row */
751 	++top;
752 	label = gtk_label_new(_("Attribute"));
753 	/*
754 	 * Use an event box to attach some help in the form of a tooltip.
755 	 * Tried this for the clist but it looked bad.
756 	 */
757 	eventBox = gtk_event_box_new();
758 	gtk_container_add( GTK_CONTAINER(eventBox), label );
759 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
760 	gtk_table_attach(GTK_TABLE(table), eventBox, 0, 1, top, (top + 1),
761 		GTK_FILL, 0, 0, 0);
762 
763 	CLAWS_SET_TIP(eventBox, _(
764 		"Choose the LDIF field that will be renamed or selected " \
765 		"for import in the list above. Reserved fields (marked " \
766 		"with a tick in the \"R\" column), are automatically " \
767 		"imported and cannot be renamed. A single click in the " \
768 		"Select (\"S\") column will select the field for import " \
769 		"with a tick. A single click anywhere in the row will " \
770 		"select that field for rename in the input area below " \
771 		"the list. A double click anywhere in the row will also " \
772 		"select the field for import."));
773 
774 	entryAttrib = gtk_entry_new();
775 	gtk_table_attach(GTK_TABLE(table), entryAttrib, 1, 3, top, (top + 1),
776 		GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
777 
778 	CLAWS_SET_TIP(entryAttrib,
779 		_( "The LDIF field can be renamed to the User Attribute name." ));
780 
781 	/* Next row */
782 	++top;
783 
784 	checkSelect = gtk_check_button_new_with_label( _( "Select for Import" ) );
785 	gtk_table_attach(GTK_TABLE(table), checkSelect, 1, 2, top, (top + 1),
786 		GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
787 
788 	CLAWS_SET_TIP(checkSelect,
789 		_( "Select the LDIF field for import into the address book." ));
790 
791 	btnModify = gtk_button_new_with_label( _(" Modify "));
792 	gtk_table_attach(GTK_TABLE(table), btnModify, 2, 3, top, (top + 1),
793 		GTK_FILL, 0, 3, 0);
794 
795 	CLAWS_SET_TIP(btnModify,
796 		_( "This button will update the list above with the data supplied." ));
797 
798 	gtk_widget_show_all(vbox);
799 
800 	/* Event handlers */
801 	g_signal_connect(G_OBJECT(view_fields), "cursor-changed",
802 			G_CALLBACK(imp_ldif_field_list_cursor_changed), NULL);
803 	g_signal_connect(G_OBJECT(view_fields), "row-activated",
804 			G_CALLBACK(imp_ldif_field_list_row_activated), NULL);
805 	g_signal_connect(G_OBJECT(btnModify), "clicked",
806 			G_CALLBACK(imp_ldif_modify_pressed), NULL );
807 	g_signal_connect(G_OBJECT(entryAttrib), "activate",
808 			G_CALLBACK(imp_ldif_entryattrib_activate), NULL);
809 
810 	impldif_dlg.view_fields = view_fields;
811 	impldif_dlg.entryField  = entryField;
812 	impldif_dlg.entryAttrib = entryAttrib;
813 	impldif_dlg.checkSelect = checkSelect;
814 	impldif_dlg.btnModify   = btnModify;
815 }
816 
817 /**
818  * Format notebook finish page.
819  * \param pageNum Page (tab) number.
820  * \param pageLbl Page (tab) label.
821  */
imp_ldif_page_finish(gint pageNum,gchar * pageLbl)822 static void imp_ldif_page_finish( gint pageNum, gchar *pageLbl ) {
823 	GtkWidget *vbox;
824 	GtkWidget *table;
825 	GtkWidget *label;
826 	GtkWidget *labelBook;
827 	GtkWidget *labelFile;
828 	GtkWidget *labelRecs;
829 	gint top;
830 
831 	vbox = gtk_vbox_new(FALSE, 8);
832 	gtk_container_add( GTK_CONTAINER( impldif_dlg.notebook ), vbox );
833 	gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
834 
835 	label = gtk_label_new( pageLbl );
836 	gtk_widget_show( label );
837 	gtk_notebook_set_tab_label(
838 		GTK_NOTEBOOK( impldif_dlg.notebook ),
839 		gtk_notebook_get_nth_page( GTK_NOTEBOOK( impldif_dlg.notebook ), pageNum ),
840 		label );
841 
842 	table = gtk_table_new(3, 2, FALSE);
843 	gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
844 	gtk_container_set_border_width( GTK_CONTAINER(table), 8 );
845 	gtk_table_set_row_spacings(GTK_TABLE(table), 8);
846 	gtk_table_set_col_spacings(GTK_TABLE(table), 8);
847 
848 	/* First row */
849 	top = 0;
850 	label = gtk_label_new( _( "Address Book:" ) );
851 	gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
852 	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
853 
854 	labelBook = gtk_label_new("");
855 	gtk_table_attach(GTK_TABLE(table), labelBook, 1, 2, top, (top + 1), GTK_FILL, 0, 0, 0);
856 	gtk_misc_set_alignment(GTK_MISC(labelBook), 0, 0.5);
857 
858 	/* Second row */
859 	top++;
860 	label = gtk_label_new( _( "File Name:" ) );
861 	gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
862 	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
863 
864 	labelFile = gtk_label_new("");
865 	gtk_table_attach(GTK_TABLE(table), labelFile, 1, 2, top, (top + 1), GTK_FILL, 0, 0, 0);
866 	gtk_misc_set_alignment(GTK_MISC(labelFile), 0, 0.5);
867 
868 	/* Third row */
869 	top++;
870 	label = gtk_label_new( _("Records Imported:") );
871 	gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
872 	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
873 
874 	labelRecs = gtk_label_new("");
875 	gtk_table_attach(GTK_TABLE(table), labelRecs, 1, 2, top, (top + 1), GTK_FILL, 0, 0, 0);
876 	gtk_misc_set_alignment(GTK_MISC(labelRecs), 0, 0.5);
877 
878 	impldif_dlg.labelBook    = labelBook;
879 	impldif_dlg.labelFile    = labelFile;
880 	impldif_dlg.labelRecords = labelRecs;
881 }
882 
883 /**
884  * Create main dialog decorations (excluding notebook pages).
885  */
imp_ldif_dialog_create()886 static void imp_ldif_dialog_create() {
887 	GtkWidget *window;
888 	GtkWidget *vbox;
889 	GtkWidget *vnbox;
890 	GtkWidget *notebook;
891 	GtkWidget *hbbox;
892 	GtkWidget *btnPrev;
893 	GtkWidget *btnNext;
894 	GtkWidget *btnProceed;
895 	GtkWidget *btnCancel;
896 	GtkWidget *hsbox;
897 	GtkWidget *statusbar;
898 
899 	window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "importldif");
900 	gtk_widget_set_size_request(window, IMPORTLDIF_WIDTH, IMPORTLDIF_HEIGHT );
901 	gtk_container_set_border_width( GTK_CONTAINER(window), 0 );
902 	gtk_window_set_title( GTK_WINDOW(window), _("Import LDIF file into Address Book") );
903 	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
904 	gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
905 	g_signal_connect(G_OBJECT(window), "delete_event",
906 			 G_CALLBACK(imp_ldif_delete_event),
907 			 NULL );
908 	g_signal_connect(G_OBJECT(window), "key_press_event",
909 			 G_CALLBACK(imp_ldif_key_pressed),
910 			 NULL );
911 
912 	vbox = gtk_vbox_new(FALSE, 4);
913 	gtk_widget_show(vbox);
914 	gtk_container_add(GTK_CONTAINER(window), vbox);
915 
916 	vnbox = gtk_vbox_new(FALSE, 4);
917 	gtk_container_set_border_width(GTK_CONTAINER(vnbox), 4);
918 	gtk_widget_show(vnbox);
919 	gtk_box_pack_start(GTK_BOX(vbox), vnbox, TRUE, TRUE, 0);
920 
921 	/* Notebook */
922 	notebook = gtk_notebook_new();
923 	gtk_notebook_set_show_tabs( GTK_NOTEBOOK(notebook), FALSE );
924 	gtk_widget_show(notebook);
925 	gtk_box_pack_start(GTK_BOX(vnbox), notebook, TRUE, TRUE, 0);
926 	gtk_container_set_border_width(GTK_CONTAINER(notebook), 6);
927 
928 	/* Status line */
929 	hsbox = gtk_hbox_new(FALSE, 0);
930 	gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
931 	statusbar = gtk_statusbar_new();
932 	gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
933 
934 	/* Button panel */
935 	gtkut_stock_button_set_create(&hbbox,
936 				      &btnCancel, GTK_STOCK_CANCEL,
937 				      &btnPrev, GTK_STOCK_GO_BACK,
938 				      &btnNext, GTK_STOCK_GO_FORWARD);
939 
940 	btnProceed = gtk_button_new_with_mnemonic(_("Proceed"));
941 	gtk_button_set_image(GTK_BUTTON(btnProceed),
942 			gtk_image_new_from_stock(GTK_STOCK_OK, GTK_ICON_SIZE_BUTTON));
943 	gtk_widget_set_can_default(btnProceed, TRUE);
944 	gtk_box_pack_start(GTK_BOX(hbbox), btnProceed, TRUE, TRUE, 0);
945 	gtk_widget_hide(btnProceed);
946 
947 	gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
948 	gtk_container_set_border_width(GTK_CONTAINER(hbbox), 2);
949 	gtk_widget_grab_default(btnNext);
950 
951 	/* Button handlers */
952 	g_signal_connect(G_OBJECT(btnPrev), "clicked",
953 			 G_CALLBACK(imp_ldif_prev), NULL);
954 	g_signal_connect(G_OBJECT(btnNext), "clicked",
955 			 G_CALLBACK(imp_ldif_next), NULL);
956 	g_signal_connect(G_OBJECT(btnProceed), "clicked",
957 			 G_CALLBACK(imp_ldif_next), NULL);
958 	g_signal_connect(G_OBJECT(btnCancel), "clicked",
959 			 G_CALLBACK(imp_ldif_cancel), NULL);
960 
961 	gtk_widget_show_all(vbox);
962 
963 	impldif_dlg.window     = window;
964 	impldif_dlg.notebook   = notebook;
965 	impldif_dlg.btnPrev    = btnPrev;
966 	impldif_dlg.btnNext    = btnNext;
967 	impldif_dlg.btnProceed = btnProceed;
968 	impldif_dlg.btnCancel  = btnCancel;
969 	impldif_dlg.statusbar  = statusbar;
970 	impldif_dlg.status_cid = gtk_statusbar_get_context_id(
971 			GTK_STATUSBAR(statusbar), "Import LDIF Dialog" );
972 
973 }
974 
975 /**
976  * Create import LDIF dialog.
977  */
imp_ldif_create()978 static void imp_ldif_create() {
979 	imp_ldif_dialog_create();
980 	imp_ldif_page_file( PAGE_FILE_INFO, _( "File Info" ) );
981 	imp_ldif_page_fields( PAGE_ATTRIBUTES, _( "Attributes" ) );
982 	imp_ldif_page_finish( PAGE_FINISH, _( "Finish" ) );
983 	gtk_widget_show_all( impldif_dlg.window );
984 }
985 
986 /**
987  * Import LDIF file.
988  * \param  addrIndex Address index.
989  * \return Address book file of imported data, or <i>NULL</i> if import
990  *         was cancelled.
991  */
addressbook_imp_ldif(AddressIndex * addrIndex)992 AddressBookFile *addressbook_imp_ldif( AddressIndex *addrIndex ) {
993 	GtkWidget *view;
994 	GtkTreeModel *model;
995 
996 	_importedBook_ = NULL;
997 	_imp_addressIndex_ = addrIndex;
998 
999 	if( ! impldif_dlg.window )
1000 		imp_ldif_create();
1001 
1002 	view = impldif_dlg.view_fields;
1003 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
1004 
1005 	gtk_button_set_label(GTK_BUTTON(impldif_dlg.btnCancel),
1006 			     GTK_STOCK_CANCEL);
1007 	gtk_widget_hide(impldif_dlg.btnProceed);
1008 	gtk_widget_show(impldif_dlg.btnNext);
1009 
1010 	impldif_dlg.cancelled = FALSE;
1011 	gtk_widget_show(impldif_dlg.window);
1012 	manage_window_set_transient(GTK_WINDOW(impldif_dlg.window));
1013 	gtk_widget_grab_default(impldif_dlg.btnNext);
1014 	gtk_window_set_modal(GTK_WINDOW(impldif_dlg.window), TRUE);
1015 
1016 	gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryName), IMPORTLDIF_GUESS_NAME );
1017 	gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryFile), "" );
1018 	gtk_label_set_text( GTK_LABEL(impldif_dlg.entryField), "" );
1019 	gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryAttrib), "" );
1020 	gtk_list_store_clear( GTK_LIST_STORE(model) );
1021 	gtk_notebook_set_current_page( GTK_NOTEBOOK(impldif_dlg.notebook), PAGE_FILE_INFO );
1022 	gtk_widget_set_sensitive( impldif_dlg.btnPrev, FALSE );
1023 	gtk_widget_set_sensitive( impldif_dlg.btnNext, TRUE );
1024 	stock_pixbuf_gdk(STOCK_PIXMAP_MARK, &markxpm );
1025 	imp_ldif_message();
1026 	gtk_widget_grab_focus(impldif_dlg.entryFile);
1027 
1028 	impldif_dlg.rowCount = 0;
1029 	g_free( impldif_dlg.nameBook );
1030 	g_free( impldif_dlg.fileName );
1031 	impldif_dlg.nameBook = NULL;
1032 	impldif_dlg.fileName = NULL;
1033 
1034 	_ldifFile_ = ldif_create();
1035 	gtk_main();
1036 	gtk_widget_hide(impldif_dlg.window);
1037 	gtk_window_set_modal(GTK_WINDOW(impldif_dlg.window), FALSE);
1038 	ldif_free( _ldifFile_ );
1039 	_ldifFile_ = NULL;
1040 	_imp_addressIndex_ = NULL;
1041 
1042 	g_free( impldif_dlg.nameBook );
1043 	g_free( impldif_dlg.fileName );
1044 	impldif_dlg.nameBook = NULL;
1045 	impldif_dlg.fileName = NULL;
1046 
1047 	if( impldif_dlg.cancelled == TRUE ) return NULL;
1048 	return _importedBook_;
1049 }
1050 
1051 /*
1052  * ============================================================================
1053  * End of Source.
1054  * ============================================================================
1055  */
1056 
1057