2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2002-2009 Match Grun and the Claws Mail team
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.
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.
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/>.
21 * Dialog for gathering EMail addresses from mail folder.
31 #include <glib/gi18n.h>
32 #include <gdk/gdkkeysyms.h>
39 #include "foldersel.h"
41 #include "alertpanel.h"
42 #include "manage_window.h"
46 #include "addrharvest.h"
47 #include "addrindex.h"
55 #define FIELDS_N_COLS 2
56 #define FIELDS_COL_WIDTH_HEADER 100
57 #define FIELDS_COL_WIDTH_COUNT 140
59 #define MIN_FOLDER_SIZE 20
60 #define DFL_FOLDER_SIZE 50
70 static struct _AddrHarvest
{
73 GtkWidget
*labelFolder
;
75 GtkWidget
*checkHeader
[ NUM_FIELDS
];
76 GtkWidget
*spinbtnFolder
;
77 GtkWidget
*checkRecurse
;
85 GtkWidget
*clistCount
;
88 static AddressIndex
*_harv_addressIndex_
;
89 static AddressBookFile
*_harv_addressBook_
;
90 static gchar
*_harv_headerNames_
[] = {
98 static GList
*_harv_messageList_
;
100 static void addrgather_dlg_status_show( gchar
*msg
) {
101 if( addrgather_dlg
.statusbar
!= NULL
) {
102 gtk_statusbar_pop( GTK_STATUSBAR(addrgather_dlg
.statusbar
),
103 addrgather_dlg
.status_cid
);
106 GTK_STATUSBAR(addrgather_dlg
.statusbar
),
107 addrgather_dlg
.status_cid
, msg
);
112 static gint
addrgather_dlg_delete_event(
113 GtkWidget
*widget
, GdkEventAny
*event
, gpointer data
)
115 addrgather_dlg
.cancelled
= TRUE
;
120 static gboolean
addrgather_dlg_key_pressed(
121 GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
123 if( event
&& event
->keyval
== GDK_Escape
) {
124 addrgather_dlg
.cancelled
= TRUE
;
130 #define FMT_BUFSIZE 32
132 static gboolean
addrgather_dlg_harvest() {
134 gchar
*text
[ FIELDS_N_COLS
];
135 AddressHarvester
*harvester
;
136 AddressBookFile
*abf
;
139 gchar str
[ FMT_BUFSIZE
];
144 name
= gtk_editable_get_chars( GTK_EDITABLE(addrgather_dlg
.entryBook
), 0, -1 );
145 if( name
== NULL
|| strlen( name
) < 1 ) {
146 addrgather_dlg_status_show(
147 _( "Please specify name for address book." ) );
152 /* Create harvest helper */
153 harvester
= addrharvest_create();
154 addrharvest_set_path( harvester
, addrgather_dlg
.folderPath
);
156 for( i
= 0; i
< NUM_FIELDS
; i
++ ) {
157 addrharvest_set_header( harvester
, _harv_headerNames_
[i
],
158 gtk_toggle_button_get_active(
159 GTK_TOGGLE_BUTTON(addrgather_dlg
.checkHeader
[i
]) ) );
161 addrharvest_set_recurse( harvester
,
162 gtk_toggle_button_get_active(
163 GTK_TOGGLE_BUTTON( addrgather_dlg
.checkRecurse
) ) );
165 if( addrharvest_check_header( harvester
) == FALSE
) {
166 addrgather_dlg_status_show(
167 _( "Please select the mail headers to search." ) );
168 addrharvest_free( harvester
);
174 addrgather_dlg_status_show( _( "Collecting addresses..." ) );
176 sz
= gtk_spin_button_get_value_as_int(
177 GTK_SPIN_BUTTON( addrgather_dlg
.spinbtnFolder
) );
178 addrharvest_set_folder_size( harvester
, sz
);
180 /* Create address book */
181 abf
= addrbook_create_book();
182 addrbook_set_path( abf
, _harv_addressIndex_
->filePath
);
183 newFile
= addrbook_guess_next_file( abf
);
184 addrbook_set_file( abf
, newFile
);
185 addrbook_set_name( abf
, name
);
189 /* Harvest addresses */
191 harvester
, abf
->addressCache
, _harv_messageList_
);
192 addrbook_save_data( abf
);
193 _harv_addressBook_
= abf
;
195 /* Update summary count */
196 clist
= GTK_CMCLIST(addrgather_dlg
.clistCount
);
197 gtk_cmclist_clear( clist
);
198 for( i
= 0; i
< NUM_FIELDS
; i
++ ) {
199 cnt
= addrharvest_get_count( harvester
, _harv_headerNames_
[i
] );
204 sprintf( str
, "%d", cnt
);
206 text
[ FIELD_COL_HEADER
] = _harv_headerNames_
[i
];
207 text
[ FIELD_COL_COUNT
] = str
;
208 gtk_cmclist_append( clist
, text
);
211 addrharvest_free( harvester
);
213 addrgather_dlg_status_show(_("Addresses collected successfully."));
215 /* Display summary page */
216 gtk_notebook_set_current_page(
217 GTK_NOTEBOOK(addrgather_dlg
.notebook
), PAGE_FINISH
);
218 addrgather_dlg
.done
= TRUE
;
219 gtk_widget_set_sensitive( addrgather_dlg
.btnCancel
, FALSE
);
220 gtk_widget_grab_default( addrgather_dlg
.btnOk
);
225 static void addrgather_dlg_ok( GtkWidget
*widget
, gpointer data
) {
226 if(addrgather_dlg
.done
) {
227 addrgather_dlg
.done
= FALSE
;
231 if( addrgather_dlg_harvest() ) {
232 addrgather_dlg
.cancelled
= FALSE
;
236 static void addrgather_dlg_cancel( GtkWidget
*widget
, gpointer data
) {
240 #define PACK_CHECK_BUTTON(box, checkbtn, label) \
242 checkbtn = gtk_check_button_new_with_label(label); \
243 gtk_widget_show(checkbtn); \
244 gtk_box_pack_start(GTK_BOX(box), checkbtn, FALSE, TRUE, 0); \
248 * Create notebook page for mail headers.
249 * Enter: pageNum Page number.
250 * pageLbl Page label.
252 static void addrgather_page_fields(gint pageNum
, gchar
*pageLbl
)
259 GtkWidget
*labelFolder
;
260 GtkWidget
*entryBook
;
261 GtkWidget
*frameHeader
;
262 GtkWidget
*checkHeader
[NUM_FIELDS
];
263 GtkWidget
*spinbtnFolder
;
264 GtkObject
*adjFolder
;
265 GtkWidget
*checkRecurse
;
271 vbox
= gtk_vbox_new(FALSE
, 6);
272 gtk_container_add(GTK_CONTAINER(addrgather_dlg
.notebook
), vbox
);
273 gtk_container_set_border_width(GTK_CONTAINER(vbox
), 4);
276 label
= gtk_label_new(pageLbl
);
277 gtk_widget_show(label
);
278 gtk_notebook_set_tab_label(GTK_NOTEBOOK(addrgather_dlg
.notebook
),
279 gtk_notebook_get_nth_page(GTK_NOTEBOOK(addrgather_dlg
.notebook
),
282 /* Upper area - Field list */
283 table
= gtk_table_new(4, 2, FALSE
);
284 gtk_box_pack_start(GTK_BOX(vbox
), table
, FALSE
, FALSE
, 0);
285 gtk_table_set_row_spacings(GTK_TABLE(table
), 4);
286 gtk_table_set_col_spacings(GTK_TABLE(table
), 4);
290 label
= gtk_label_new(_("Current folder:"));
291 gtk_table_attach( GTK_TABLE(table
), label
, 0, 1, top
, (top
+ 1), GTK_FILL
, 0, 0, 0 );
292 gtk_misc_set_alignment( GTK_MISC(label
), 1.0, 0.5 );
294 labelFolder
= gtk_label_new("");
295 gtk_table_attach( GTK_TABLE(table
), labelFolder
, 1, 2, top
, (top
+ 1),
296 GTK_EXPAND
|GTK_SHRINK
|GTK_FILL
, 0, 0, 0 );
297 gtk_misc_set_alignment( GTK_MISC(labelFolder
), 0, 0.5 );
301 label
= gtk_label_new(_("Address book name:"));
302 gtk_table_attach( GTK_TABLE(table
), label
, 0, 1, top
, (top
+ 1), GTK_FILL
, 0, 0, 0 );
303 gtk_misc_set_alignment( GTK_MISC(label
), 1.0, 0.5 );
305 entryBook
= gtk_entry_new();
306 gtk_table_attach( GTK_TABLE(table
), entryBook
, 1, 2, top
, (top
+ 1),
307 GTK_EXPAND
|GTK_SHRINK
|GTK_FILL
, 0, 0, 0 );
311 label
= gtk_label_new(_("Address book folder size:"));
312 gtk_table_attach( GTK_TABLE(table
), label
, 0, 1, top
, (top
+ 1), GTK_FILL
, 0, 0, 0 );
313 gtk_misc_set_alignment( GTK_MISC(label
), 1.0, 0.5 );
315 _("Maximum amount of entries per folder within the newly created address book"));
317 hboxs
= gtk_hbox_new(FALSE
, 8);
318 adjFolder
= gtk_adjustment_new(DFL_FOLDER_SIZE
, MIN_FOLDER_SIZE
, G_MAXINT
, 1, 10, 0);
319 spinbtnFolder
= gtk_spin_button_new(GTK_ADJUSTMENT(adjFolder
), 1, 0);
320 gtk_box_pack_start(GTK_BOX(hboxs
), spinbtnFolder
, FALSE
, FALSE
, 0);
321 gtk_widget_set_size_request(spinbtnFolder
, 100, -1);
322 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spinbtnFolder
), TRUE
);
323 gtk_table_attach(GTK_TABLE(table
), hboxs
, 1, 2, top
, (top
+ 1), GTK_FILL
, 0, 0, 0);
324 CLAWS_SET_TIP(spinbtnFolder
,
325 _("Maximum amount of entries per folder within the newly created address book"));
329 frameHeader
= gtk_frame_new(_("Process these mail header fields"));
330 gtk_widget_show(frameHeader
);
331 gtk_table_attach(GTK_TABLE(table
), frameHeader
, 0, 2, top
, (top
+ 4), GTK_FILL
, 0, 0, 0);
332 gtk_frame_set_label_align(GTK_FRAME(frameHeader
), 0.01, 0.5);
335 vboxf
= gtk_vbox_new(FALSE
, 0);
336 gtk_widget_show(vboxf
);
337 gtk_container_add(GTK_CONTAINER(frameHeader
), vboxf
);
338 gtk_container_set_border_width(GTK_CONTAINER(vboxf
), 8);
340 for (i
= 0; i
< NUM_FIELDS
; i
++) {
341 PACK_CHECK_BUTTON(vboxf
, checkHeader
[i
], _harv_headerNames_
[i
]);
342 addrgather_dlg
.checkHeader
[i
] = checkHeader
[i
];
345 /* Recurse folders */
347 checkRecurse
= gtk_check_button_new_with_label( _("Include subfolders" ) );
348 gtk_table_attach( GTK_TABLE(table
), checkRecurse
, 0, 2, top
, (top
+ 1),
349 GTK_EXPAND
|GTK_SHRINK
|GTK_FILL
, 0, 0, 0 );
351 addrgather_dlg
.labelFolder
= labelFolder
;
352 addrgather_dlg
.entryBook
= entryBook
;
353 addrgather_dlg
.spinbtnFolder
= spinbtnFolder
;
354 addrgather_dlg
.checkRecurse
= checkRecurse
;
358 * Create notebook page for summary counts.
359 * Enter: pageNum Page number.
360 * pageLbl Page label.
362 static void addrgather_page_finish( gint pageNum
, gchar
*pageLbl
) {
365 GtkWidget
*clistSWin
;
366 GtkWidget
*clistCount
;
367 gchar
*titles
[ FIELDS_N_COLS
];
370 titles
[ FIELD_COL_HEADER
] = _("Header Name");
371 titles
[ FIELD_COL_COUNT
] = _("Address Count");
373 vbox
= gtk_vbox_new(FALSE
, 8);
374 gtk_container_add( GTK_CONTAINER( addrgather_dlg
.notebook
), vbox
);
375 gtk_container_set_border_width( GTK_CONTAINER (vbox
), 8 );
377 label
= gtk_label_new( pageLbl
);
378 gtk_widget_show( label
);
379 gtk_notebook_set_tab_label(
380 GTK_NOTEBOOK( addrgather_dlg
.notebook
),
381 gtk_notebook_get_nth_page( GTK_NOTEBOOK( addrgather_dlg
.notebook
), pageNum
),
385 clistSWin
= gtk_scrolled_window_new( NULL
, NULL
);
386 gtk_container_add( GTK_CONTAINER(vbox
), clistSWin
);
387 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clistSWin
),
388 GTK_POLICY_AUTOMATIC
,
389 GTK_POLICY_AUTOMATIC
);
391 clistCount
= gtk_cmclist_new_with_titles( FIELDS_N_COLS
, titles
);
392 gtk_container_add( GTK_CONTAINER(clistSWin
), clistCount
);
393 gtk_cmclist_set_selection_mode( GTK_CMCLIST(clistCount
), GTK_SELECTION_BROWSE
);
394 gtk_cmclist_set_column_width(
395 GTK_CMCLIST(clistCount
), FIELD_COL_HEADER
, FIELDS_COL_WIDTH_HEADER
);
396 gtk_cmclist_set_column_width(
397 GTK_CMCLIST(clistCount
), FIELD_COL_COUNT
, FIELDS_COL_WIDTH_COUNT
);
399 for( i
= 0; i
< FIELDS_N_COLS
; i
++ )
400 GTK_WIDGET_UNSET_FLAGS(GTK_CMCLIST(clistCount
)->column
[i
].button
, GTK_CAN_FOCUS
);
402 addrgather_dlg
.clistCount
= clistCount
;
406 * Create notebook page for warning message.
407 * Enter: pageNum Page number.
408 * pageLbl Page label.
410 static void addrgather_dlg_create(void)
415 GtkWidget
*btnCancel
;
416 GtkWidget
*statusbar
;
421 window
= gtkut_window_new(GTK_WINDOW_TOPLEVEL
, "addrgather");
422 gtk_widget_set_size_request(window
, 380, -1);
423 gtk_container_set_border_width(GTK_CONTAINER(window
), 4);
424 gtk_window_set_position(GTK_WINDOW(window
), GTK_WIN_POS_CENTER
);
425 gtk_window_set_resizable(GTK_WINDOW(window
), TRUE
);
426 gtk_window_set_modal(GTK_WINDOW(window
), TRUE
);
428 g_signal_connect(G_OBJECT(window
), "delete_event",
429 G_CALLBACK(addrgather_dlg_delete_event
), NULL
);
430 g_signal_connect(G_OBJECT(window
), "key_press_event",
431 G_CALLBACK(addrgather_dlg_key_pressed
), NULL
);
433 vbox
= gtk_vbox_new(FALSE
, 6);
434 gtk_container_add(GTK_CONTAINER(window
), vbox
);
437 notebook
= gtk_notebook_new();
438 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook
), FALSE
);
439 gtk_widget_show(notebook
);
440 gtk_box_pack_start(GTK_BOX(vbox
), notebook
, TRUE
, TRUE
, 0);
441 gtk_container_set_border_width(GTK_CONTAINER(notebook
), 6);
444 hsbox
= gtk_hbox_new(FALSE
, 0);
445 gtk_box_pack_end(GTK_BOX(vbox
), hsbox
, FALSE
, FALSE
, 0);
446 statusbar
= gtk_statusbar_new();
447 gtk_box_pack_start(GTK_BOX(hsbox
), statusbar
, TRUE
, TRUE
, 0);
450 gtkut_stock_button_set_create(&hbbox
, &btnCancel
, GTK_STOCK_CANCEL
,
451 &btnOk
, GTK_STOCK_OK
,
453 gtk_box_pack_end(GTK_BOX(vbox
), hbbox
, FALSE
, FALSE
, 0);
455 /* Signal handlers */
456 g_signal_connect(G_OBJECT(btnOk
), "clicked",
457 G_CALLBACK(addrgather_dlg_ok
), NULL
);
458 g_signal_connect(G_OBJECT(btnCancel
), "clicked",
459 G_CALLBACK(addrgather_dlg_cancel
), NULL
);
461 gtk_widget_show_all(vbox
);
463 addrgather_dlg
.window
= window
;
464 addrgather_dlg
.notebook
= notebook
;
465 addrgather_dlg
.btnOk
= btnOk
;
466 addrgather_dlg
.btnCancel
= btnCancel
;
467 addrgather_dlg
.statusbar
= statusbar
;
468 addrgather_dlg
.status_cid
= gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar
),
469 "Collect Email Address Dialog");
471 /* Create notebook pages */
472 addrgather_page_fields(PAGE_FIELDS
, _("Header Fields"));
473 addrgather_page_finish(PAGE_FINISH
, _("Finish"));
474 gtk_widget_show_all(addrgather_dlg
.window
);
478 * Harvest addresses main window.
479 * Enter: folderItem Source folder.
480 * addrIndex Address index.
481 * sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
482 * msgList List of message numbers, or NULL to process folder.
483 * Return: Populated address book file, or NULL if none created.
485 AddressBookFile
*addrgather_dlg_execute(FolderItem
*folderItem
, AddressIndex
*addrIndex
,
486 gboolean sourceInd
, GList
*msgList
)
490 _harv_addressIndex_
= addrIndex
;
491 _harv_addressBook_
= NULL
;
492 _harv_messageList_
= msgList
;
495 if (!addrgather_dlg
.window
)
496 addrgather_dlg_create();
498 addrgather_dlg
.done
= FALSE
;
500 gtk_notebook_set_current_page(GTK_NOTEBOOK(addrgather_dlg
.notebook
), PAGE_FIELDS
);
501 addrgather_dlg
.folderPath
= folder_item_get_path(folderItem
);
503 /* Setup some default values */
504 gtk_label_set_text(GTK_LABEL(addrgather_dlg
.labelFolder
), folderItem
->path
);
505 gtk_entry_set_text(GTK_ENTRY(addrgather_dlg
.entryBook
), folderItem
->path
);
507 for (i
= 0; i
< NUM_FIELDS
; i
++) {
508 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(addrgather_dlg
.checkHeader
[i
]),
510 if (g_utf8_collate(_harv_headerNames_
[i
], HEADER_FROM
) == 0)
511 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(addrgather_dlg
.checkHeader
[i
]),
515 gtk_widget_set_sensitive(addrgather_dlg
.btnOk
, TRUE
);
516 gtk_widget_grab_default(addrgather_dlg
.btnOk
);
518 /* Apply window title */
520 gtk_window_set_title(GTK_WINDOW(addrgather_dlg
.window
),
521 _("Collect email addresses from selected messages"));
522 gtk_widget_set_sensitive(addrgather_dlg
.checkRecurse
, FALSE
);
524 gtk_window_set_title(GTK_WINDOW(addrgather_dlg
.window
),
525 _("Collect email addresses from folder"));
526 gtk_widget_set_sensitive(addrgather_dlg
.checkRecurse
, TRUE
);
528 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(addrgather_dlg
.checkRecurse
), FALSE
);
530 addrgather_dlg_status_show("");
531 gtk_widget_show(addrgather_dlg
.window
);
533 gtk_widget_grab_focus(addrgather_dlg
.entryBook
);
534 manage_window_set_transient(GTK_WINDOW(addrgather_dlg
.window
));
537 g_free(addrgather_dlg
.folderPath
);
538 addrgather_dlg
.folderPath
= NULL
;
539 gtk_widget_hide(addrgather_dlg
.window
);
540 _harv_addressIndex_
= NULL
;
542 if (addrgather_dlg
.cancelled
== TRUE
)
545 return _harv_addressBook_
;