Included address harvester feature.
authorMatch Grun <match@dimensional.com>
Sat, 16 Mar 2002 07:07:34 +0000 (07:07 +0000)
committerMatch Grun <match@dimensional.com>
Sat, 16 Mar 2002 07:07:34 +0000 (07:07 +0000)
src/Makefile.am
src/addressbook.c
src/addressbook.h
src/addrgather.c [new file with mode: 0644]
src/addrgather.h [new file with mode: 0644]
src/addrharvest.c [new file with mode: 0644]
src/addrharvest.h [new file with mode: 0644]
src/mainwindow.c

index be7e0e3479895c44113c977b0d72fae0535c4183..6b0eedb5bbb155a6df087ff18c6c296ff84cb437 100644 (file)
@@ -64,6 +64,8 @@ sylpheed_SOURCES = \
        editldap.c editldap.h \
        editldap_basedn.c editldap_basedn.h \
        addressadd.c addressadd.h \
+       addrharvest.c addrharvest.h \
+       addrgather.c addrgather.h \
        filesel.c filesel.h \
        foldersel.c foldersel.h \
        statusbar.c statusbar.h \
index 1d50e2b06b340d21d2c903bbe6f933039442e1b2..79aa8b3f36bd3d8d699266f927baf1867538ae03 100644 (file)
@@ -94,6 +94,7 @@
 
 #include "addrselect.h"
 #include "addrclip.h"
+#include "addrgather.h"
 
 typedef enum
 {
@@ -3923,6 +3924,38 @@ static void addressbook_import_mutt_cb() {
        }
 }
 
+/*
+* Gather addresses.
+* Enter: folderItem Folder to import.
+*/
+void addressbook_gather( FolderItem *folderItem ) {
+       AddressDataSource *ds = NULL;
+       AdapterDSource *ads = NULL;
+       AddressBookFile *abf = NULL;
+       AdapterInterface *adapter;
+       GtkCTreeNode *newNode;
+
+       abf = addrgather_dlg_execute( folderItem, _addressIndex_ );
+       if( abf ) {
+               ds = addrindex_index_add_datasource(
+                       _addressIndex_, ADDR_IF_BOOK, abf );
+
+               adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
+               if( adapter ) {
+                       if( adapter->treeNode ) {
+                               ads = addressbook_create_ds_adapter(
+                                       ds, ADDR_BOOK, addrbook_get_name( abf ) );
+                               newNode = addressbook_add_object(
+                                               adapter->treeNode,
+                                               ADDRESS_OBJECT(ads) );
+                       }
+               }
+
+               /* Notify address completion */
+               invalidate_address_completion();
+       }
+}
+
 /*
 * End of Source.
 */
index 767747873f8ec45fc34a8c80c2331c5e1a902e8b..744a58aeef0aa440d09742de5b9f7f62fa5ad0a6 100644 (file)
@@ -40,4 +40,6 @@ gboolean addressbook_add_contact      ( const gchar   *name,
 
 gboolean addressbook_load_completion   ( gint (*callBackFunc) ( const gchar *, const gchar * ) );
 
+void addressbook_gather                        ( FolderItem *folderItem );
+
 #endif /* __ADDRESSBOOK_H__ */
diff --git a/src/addrgather.c b/src/addrgather.c
new file mode 100644 (file)
index 0000000..1000f61
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2002 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+* Dialog for gathering EMail addresses from mail folder.
+*/
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "defs.h"
+
+#include <glib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtktable.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkhbbox.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkfilesel.h>
+#include <gtk/gtksignal.h>
+
+#include "intl.h"
+#include "main.h"
+#include "inc.h"
+#include "mbox.h"
+#include "filesel.h"
+#include "foldersel.h"
+#include "gtkutils.h"
+#include "alertpanel.h"
+#include "manage_window.h"
+#include "folder.h"
+#include "utils.h"
+
+#include "addrharvest.h"
+#include "addrindex.h"
+#include "addrbook.h"
+
+#define PAGE_WARNING    0
+#define PAGE_FIELDS     1
+#define PAGE_FINISH     2
+
+#define NUM_FIELDS      6
+
+#define FIELDS_N_COLS              2
+#define FIELDS_COL_WIDTH_HEADER    100
+#define FIELDS_COL_WIDTH_COUNT     140
+
+#define MIN_FOLDER_SIZE 20
+#define DFL_FOLDER_SIZE 50
+
+typedef enum {
+       FIELD_COL_HEADER = 0,
+       FIELD_COL_COUNT  = 1
+} AddrGather_FieldColPos;
+
+/*
+* The dialog.
+*/
+static struct _AddrGather_Dlg_ {
+       GtkWidget *window;
+       GtkWidget *notebook;
+       GtkWidget *labelFolder;
+       GtkWidget *entryBook;
+       GtkWidget *checkHeader[ NUM_FIELDS ];
+       GtkWidget *spinbtnFolder;
+       GtkWidget *btnOk;
+       GtkWidget *btnCancel;
+       GtkWidget *statusbar;
+       gint      status_cid;
+       gboolean  cancelled;
+       gchar     *folderPath;
+       GtkWidget *clistCount;
+} addrgather_dlg;
+
+static AddressIndex *_harv_addressIndex_;
+static AddressBookFile *_harv_addressBook_;
+static gchar *_harv_headerNames_[] = {
+       HEADER_FROM,
+       HEADER_REPLY_TO,
+       HEADER_SENDER,
+       HEADER_TO,
+       HEADER_CC,
+       HEADER_ERRORS_TO
+};
+
+void addrgather_dlg_status_show( gchar *msg ) {
+       if( addrgather_dlg.statusbar != NULL ) {
+               gtk_statusbar_pop( GTK_STATUSBAR(addrgather_dlg.statusbar),
+                       addrgather_dlg.status_cid );
+               if( msg ) {
+                       gtk_statusbar_push(
+                               GTK_STATUSBAR(addrgather_dlg.statusbar),
+                               addrgather_dlg.status_cid, msg );
+               }
+       }
+}
+
+static gint addrgather_dlg_delete_event(
+       GtkWidget *widget, GdkEventAny *event, gpointer data )
+{
+       addrgather_dlg.cancelled = TRUE;
+       gtk_main_quit();
+       return TRUE;
+}
+
+static void addrgather_dlg_key_pressed(
+       GtkWidget *widget, GdkEventKey *event, gpointer data )
+{
+       if( event && event->keyval == GDK_Escape ) {
+               addrgather_dlg.cancelled = TRUE;
+               gtk_main_quit();
+       }
+}
+
+#define FMT_BUFSIZE 32
+
+static gboolean addrgather_dlg_harvest() {
+       GtkCList *clist;
+       gchar *text[ FIELDS_N_COLS ];
+       AddressHarvester *harvester;
+       AddressBookFile *abf;
+       gchar *name;
+       gchar *newFile;
+       gchar str[ FMT_BUFSIZE ];
+       gint cnt;
+       gint i;
+       gint sz;
+
+       name = gtk_editable_get_chars( GTK_EDITABLE(addrgather_dlg.entryBook), 0, -1 );
+       if( name == NULL || strlen( name ) < 1 ) {
+               addrgather_dlg_status_show(
+                       _( "Please specify name for address book." ) );
+               g_free( name );
+               return FALSE;
+       }
+
+       /* Create harvest helper */
+       harvester = addrharvest_create();
+       addrharvest_set_path( harvester, addrgather_dlg.folderPath );
+
+       for( i = 0; i < NUM_FIELDS; i++ ) {
+               addrharvest_set_header( harvester, _harv_headerNames_[i],
+               gtk_toggle_button_get_active(
+                       GTK_TOGGLE_BUTTON(addrgather_dlg.checkHeader[i]) ) );
+       }
+
+       if( addrharvest_check_header( harvester ) == FALSE ) {
+               addrgather_dlg_status_show(
+                       _( "Please select the mail headers to search." ) );
+               addrharvest_free( harvester );
+               return FALSE;
+       }
+
+       sz = gtk_spin_button_get_value_as_int(
+               GTK_SPIN_BUTTON( addrgather_dlg.spinbtnFolder ) );
+       addrharvest_set_folder_size( harvester, sz );
+
+       /* Create address book */
+       abf = addrbook_create_book();
+       addrbook_set_path( abf, _harv_addressIndex_->filePath );
+       newFile = addrbook_guess_next_file( abf );
+       addrbook_set_file( abf, newFile );
+       addrbook_set_name( abf, name );
+       g_free( newFile );
+       g_free( name );
+
+       /* Harvest addresses */
+       addrharvest_harvest( harvester, abf->addressCache );
+       addrbook_save_data( abf );
+       _harv_addressBook_ = abf;
+
+       /* Update summary count */
+       clist = GTK_CLIST(addrgather_dlg.clistCount);
+       gtk_clist_clear( clist );
+       for( i = 0; i < NUM_FIELDS; i++ ) {
+               cnt = addrharvest_get_count( harvester, _harv_headerNames_[i] );
+               if( cnt < 1 ) {
+                       strcpy( str, "-" );
+               }
+               else {
+                       sprintf( str, "%d", cnt );
+               }
+               text[ FIELD_COL_HEADER ] = _harv_headerNames_[i];
+               text[ FIELD_COL_COUNT  ] = str;
+               gtk_clist_append( clist, text );
+       }
+
+       addrharvest_free( harvester );
+
+       addrgather_dlg_status_show( _("Addresses gathered successfully.") );
+
+       /* Display summary page */
+       gtk_notebook_set_page(
+               GTK_NOTEBOOK(addrgather_dlg.notebook), PAGE_FINISH );
+       gtk_widget_set_sensitive( addrgather_dlg.btnOk, FALSE );
+       gtk_widget_grab_default( addrgather_dlg.btnCancel );
+
+       return TRUE;
+}
+
+static void addrgather_dlg_ok( GtkWidget *widget, gpointer data ) {
+       if( addrgather_dlg_harvest() ) {
+               addrgather_dlg.cancelled = FALSE;
+       }
+}
+
+static void addrgather_dlg_cancel( GtkWidget *widget, gpointer data ) {
+       gtk_main_quit();
+}
+
+#define PACK_CHECK_BUTTON(box, chkbtn, label) \
+{ \
+       chkbtn = gtk_check_button_new_with_label(label); \
+       gtk_widget_show(chkbtn); \
+       gtk_box_pack_start(GTK_BOX(box), chkbtn, FALSE, TRUE, 0); \
+}
+
+/*
+ * Create notebook page for warning message.
+ * Enter: pageNum Page number.
+ *        pageLbl Page label.
+ */
+static void addrgather_page_warning( gint pageNum, gchar *pageLbl ) {
+       GtkWidget *vbox;
+       GtkWidget *table;
+       GtkWidget *label;
+       gint top;
+
+       vbox = gtk_vbox_new(FALSE, 8);
+       gtk_container_add( GTK_CONTAINER( addrgather_dlg.notebook ), vbox );
+       gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
+
+       label = gtk_label_new( pageLbl );
+       gtk_widget_show( label );
+       gtk_notebook_set_tab_label(
+               GTK_NOTEBOOK( addrgather_dlg.notebook ),
+               gtk_notebook_get_nth_page( GTK_NOTEBOOK( addrgather_dlg.notebook ), pageNum ),
+               label );
+
+       table = gtk_table_new(3, 2, FALSE);
+       gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
+       gtk_container_set_border_width( GTK_CONTAINER(table), 8 );
+       gtk_table_set_row_spacings(GTK_TABLE(table), 8);
+       gtk_table_set_col_spacings(GTK_TABLE(table), 8 );
+
+       /* First row */
+       top = 0;
+       label = gtk_label_new(_(""));
+       gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+       gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+       /* First row */
+       top++;
+       label = gtk_label_new(_("No folder was selected."));
+       gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+       gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+       /* Second row */
+       top++;
+       label = gtk_label_new(_("Please select a folder to process from the folder list."));
+       gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
+       gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+}
+
+/*
+ * Create notebook page for mail headers.
+ * Enter: pageNum Page number.
+ *        pageLbl Page label.
+ */
+static void addrgather_page_fields( gint pageNum, gchar *pageLbl ) {
+       GtkWidget *vbox;
+       GtkWidget *vboxf;
+       GtkWidget *hboxs;
+       GtkWidget *table;
+       GtkWidget *label;
+       GtkWidget *labelFolder;
+       GtkWidget *entryBook;
+       GtkWidget *frameHeader;
+       GtkWidget *checkHeader[ NUM_FIELDS ];
+       GtkWidget *spinbtnFolder;
+       GtkObject *adjFolder;
+       gint top;
+       gint i;
+
+       /* Container */
+       vbox = gtk_vbox_new(FALSE, 8);
+       gtk_container_add( GTK_CONTAINER( addrgather_dlg.notebook ), vbox );
+       gtk_container_set_border_width( GTK_CONTAINER (vbox), 4 );
+
+       /* Notebook page */
+       label = gtk_label_new( pageLbl );
+       gtk_widget_show( label );
+       gtk_notebook_set_tab_label(
+               GTK_NOTEBOOK( addrgather_dlg.notebook ),
+               gtk_notebook_get_nth_page( GTK_NOTEBOOK( addrgather_dlg.notebook ), pageNum ),
+               label );
+
+       /* Upper area - Field list */
+       table = gtk_table_new( 4, 2, FALSE);
+       gtk_box_pack_start( GTK_BOX(vbox), table, FALSE, FALSE, 0 );
+       gtk_container_set_border_width( GTK_CONTAINER(table), 8 );
+       gtk_table_set_row_spacings( GTK_TABLE(table), 8 );
+       gtk_table_set_col_spacings( GTK_TABLE(table), 8 );
+
+       /* First row */
+       top = 0;
+       label = gtk_label_new( _("Folder :") );
+       gtk_table_attach( GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0 );
+       gtk_misc_set_alignment( GTK_MISC(label), 1.0, 0.5 );
+
+       labelFolder = gtk_label_new( "" );
+       gtk_table_attach( GTK_TABLE(table), labelFolder, 1, 2, top, (top + 1),
+               GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0 );
+       gtk_misc_set_alignment( GTK_MISC(labelFolder), 0, 0.5 );
+
+       /* Second row */
+       top = 1;
+       label = gtk_label_new( _("Address Book :") );
+       gtk_table_attach( GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0 );
+       gtk_misc_set_alignment( GTK_MISC(label), 1.0, 0.5 );
+
+       entryBook = gtk_entry_new();
+       gtk_table_attach( GTK_TABLE(table), entryBook, 1, 2, top, (top + 1),
+               GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0 );
+
+       /* Third row */
+       top = 2;
+       label = gtk_label_new( _("Folder Size :") );
+       gtk_table_attach( GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0 );
+       gtk_misc_set_alignment( GTK_MISC(label), 1.0, 0.5 );
+
+       hboxs = gtk_hbox_new( FALSE, 8 );
+       adjFolder =
+               gtk_adjustment_new( DFL_FOLDER_SIZE, MIN_FOLDER_SIZE, G_MAXINT, 1, 10, 100 );
+       spinbtnFolder = gtk_spin_button_new( GTK_ADJUSTMENT(adjFolder), 1, 0 );
+       gtk_box_pack_start( GTK_BOX(hboxs), spinbtnFolder, FALSE, FALSE, 0);
+       gtk_widget_set_usize( spinbtnFolder, 100, -1);
+       gtk_spin_button_set_numeric( GTK_SPIN_BUTTON(spinbtnFolder), TRUE );
+       gtk_table_attach( GTK_TABLE(table), hboxs, 1, 2, top, (top + 1), GTK_FILL, 0, 0, 0 );
+
+       /* Fourth row */
+       top = 3;
+       frameHeader = gtk_frame_new( _("Process these mail header fields") );
+       gtk_widget_show( frameHeader );
+       gtk_table_attach( GTK_TABLE(table), frameHeader, 0, 2, top, (top + 4), GTK_FILL, 0, 0, 0 );
+       gtk_frame_set_label_align( GTK_FRAME(frameHeader), 0.01, 0.5 );
+
+       /* Check boxes */
+       vboxf = gtk_vbox_new( FALSE, 0 );
+       gtk_widget_show( vboxf );
+       gtk_container_add( GTK_CONTAINER( frameHeader ), vboxf );
+       gtk_container_set_border_width (GTK_CONTAINER( vboxf ), 8);
+
+       for( i = 0; i < NUM_FIELDS; i++ ) {
+               PACK_CHECK_BUTTON( vboxf, checkHeader[i], _harv_headerNames_[i] );
+               addrgather_dlg.checkHeader[i] = checkHeader[i];
+       }
+
+       addrgather_dlg.labelFolder   = labelFolder;
+       addrgather_dlg.entryBook     = entryBook;
+       addrgather_dlg.spinbtnFolder = spinbtnFolder;
+}
+
+/*
+ * Create notebook page for summary counts.
+ * Enter: pageNum Page number.
+ *        pageLbl Page label.
+ */
+static void addrgather_page_finish( gint pageNum, gchar *pageLbl ) {
+       GtkWidget *label;
+       GtkWidget *vbox;
+       GtkWidget *clistSWin;
+       GtkWidget *clistCount;
+       gchar *titles[ FIELDS_N_COLS ];
+       gint i;
+
+       titles[ FIELD_COL_HEADER ] = _("Header Name");
+       titles[ FIELD_COL_COUNT  ] = _("Address Count");
+
+       vbox = gtk_vbox_new(FALSE, 8);
+       gtk_container_add( GTK_CONTAINER( addrgather_dlg.notebook ), vbox );
+       gtk_container_set_border_width( GTK_CONTAINER (vbox), 8 );
+
+       label = gtk_label_new( pageLbl );
+       gtk_widget_show( label );
+       gtk_notebook_set_tab_label(
+               GTK_NOTEBOOK( addrgather_dlg.notebook ),
+               gtk_notebook_get_nth_page( GTK_NOTEBOOK( addrgather_dlg.notebook ), pageNum ),
+               label );
+
+       /* Summary count */
+       clistSWin = gtk_scrolled_window_new( NULL, NULL );
+       gtk_container_add( GTK_CONTAINER(vbox), clistSWin );
+       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clistSWin),
+                                      GTK_POLICY_AUTOMATIC,
+                                      GTK_POLICY_ALWAYS);
+
+       clistCount = gtk_clist_new_with_titles( FIELDS_N_COLS, titles );
+       gtk_container_add( GTK_CONTAINER(clistSWin), clistCount );
+       gtk_clist_set_selection_mode( GTK_CLIST(clistCount), GTK_SELECTION_BROWSE );
+       gtk_clist_set_column_width(
+                       GTK_CLIST(clistCount), FIELD_COL_HEADER, FIELDS_COL_WIDTH_HEADER );
+       gtk_clist_set_column_width(
+                       GTK_CLIST(clistCount), FIELD_COL_COUNT, FIELDS_COL_WIDTH_COUNT );
+
+       for( i = 0; i < FIELDS_N_COLS; i++ )
+               GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clistCount)->column[i].button, GTK_CAN_FOCUS);
+
+       addrgather_dlg.clistCount = clistCount;
+}
+
+/*
+ * Create notebook page for warning message.
+ * Enter: pageNum Page number.
+ *        pageLbl Page label.
+ */
+static void addrgather_dlg_create( void ) {
+       GtkWidget *window;
+       GtkWidget *notebook;
+       GtkWidget *btnOk;
+       GtkWidget *btnCancel;
+       GtkWidget *statusbar;
+       GtkWidget *vbox;
+       GtkWidget *vnbox;
+       GtkWidget *hbbox;
+       GtkWidget *hsbox;
+
+       window = gtk_window_new( GTK_WINDOW_DIALOG );
+       gtk_widget_set_usize( window, 380, -1 );
+       gtk_container_set_border_width(GTK_CONTAINER(window), 0);
+       gtk_window_set_title( GTK_WINDOW(window), _("Gather E-Mail Addresses") );
+       gtk_window_set_position( GTK_WINDOW(window), GTK_WIN_POS_CENTER );
+       gtk_window_set_modal( GTK_WINDOW(window), TRUE );       
+       gtk_signal_connect( GTK_OBJECT(window), "delete_event",
+               GTK_SIGNAL_FUNC( addrgather_dlg_delete_event ), NULL );
+       gtk_signal_connect( GTK_OBJECT(window), "key_press_event",
+               GTK_SIGNAL_FUNC( addrgather_dlg_key_pressed ), NULL );
+
+       vbox = gtk_vbox_new( FALSE, 8 );
+       gtk_container_add( GTK_CONTAINER(window), vbox );
+       gtk_container_set_border_width( GTK_CONTAINER(vbox), 0 );
+
+       vnbox = gtk_vbox_new(FALSE, 4);
+       gtk_container_set_border_width(GTK_CONTAINER(vnbox), 4);
+       gtk_widget_show(vnbox);
+       gtk_box_pack_start(GTK_BOX(vbox), vnbox, TRUE, TRUE, 0);
+
+       /* Notebook */
+       notebook = gtk_notebook_new();
+       gtk_notebook_set_show_tabs( GTK_NOTEBOOK(notebook), FALSE );
+       gtk_widget_show(notebook);
+       gtk_box_pack_start(GTK_BOX(vnbox), notebook, TRUE, TRUE, 0);
+       gtk_container_set_border_width(GTK_CONTAINER(notebook), 6);
+
+       /* Status line */
+       hsbox = gtk_hbox_new( FALSE, 0 );
+       gtk_box_pack_end( GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH );
+       statusbar = gtk_statusbar_new();
+       gtk_box_pack_start( GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH );
+
+       /* Button panel */
+       gtkut_button_set_create( &hbbox, &btnOk, _("OK"),
+               &btnCancel, _("Cancel"), NULL, NULL );
+       gtk_box_pack_end( GTK_BOX(vbox), hbbox, FALSE, FALSE, 0 );
+       gtk_container_set_border_width( GTK_CONTAINER(hbbox), 0 );
+
+       /* Signal handlers */
+       gtk_signal_connect( GTK_OBJECT(btnOk), "clicked",
+               GTK_SIGNAL_FUNC(addrgather_dlg_ok), NULL );
+       gtk_signal_connect( GTK_OBJECT(btnCancel), "clicked",
+               GTK_SIGNAL_FUNC(addrgather_dlg_cancel), NULL );
+
+       gtk_widget_show_all( vbox );
+       addrgather_dlg.window     = window;
+       addrgather_dlg.notebook   = notebook;
+       addrgather_dlg.btnOk      = btnOk;
+       addrgather_dlg.btnCancel  = btnCancel;
+       addrgather_dlg.statusbar  = statusbar;
+       addrgather_dlg.status_cid = gtk_statusbar_get_context_id(
+               GTK_STATUSBAR(statusbar), "Gather E-Mail Address Dialog" );
+
+       /* Create notebook pages */
+       addrgather_page_warning( PAGE_WARNING, _( "Warning" ) );
+       addrgather_page_fields( PAGE_FIELDS, _( "Header Fields" ) );
+       addrgather_page_finish( PAGE_FINISH, _( "Finish" ) );
+       gtk_widget_show_all( addrgather_dlg.window );
+}
+
+/*
+* Gather addresses main window.
+* Enter: folderItem Source folder.
+*        addrIndex  Address index.
+* Return: Populated address book file, or NULL if none created.
+*/
+AddressBookFile *addrgather_dlg_execute( FolderItem *folderItem, AddressIndex *addrIndex ) {
+       gboolean errFlag;
+       gint i;
+
+       _harv_addressIndex_ = addrIndex;
+       _harv_addressBook_ = NULL;
+
+       /* Create dialog */
+       if( ! addrgather_dlg.window ) {
+               addrgather_dlg_create();
+       }
+
+       errFlag = TRUE;
+       if( folderItem && folderItem->path ) {
+               gtk_notebook_set_page(
+                       GTK_NOTEBOOK(addrgather_dlg.notebook), PAGE_FIELDS );
+               addrgather_dlg.folderPath = folder_item_get_path( folderItem );
+
+               /* Setup some default values */
+               gtk_label_set_text(
+                       GTK_LABEL(addrgather_dlg.labelFolder), folderItem->path );
+               gtk_entry_set_text(
+                       GTK_ENTRY(addrgather_dlg.entryBook), folderItem->path );
+
+               for( i = 0; i < NUM_FIELDS; i++ ) {
+                       gtk_toggle_button_set_active(
+                               GTK_TOGGLE_BUTTON(addrgather_dlg.checkHeader[i]),
+                               FALSE );
+                       if( g_strcasecmp( _harv_headerNames_[i], HEADER_FROM ) == 0 ) {
+                               gtk_toggle_button_set_active(
+                                       GTK_TOGGLE_BUTTON(addrgather_dlg.checkHeader[i]),
+                                       TRUE );
+                       }
+               }
+
+               gtk_widget_set_sensitive( addrgather_dlg.btnOk, TRUE );
+               gtk_widget_grab_default( addrgather_dlg.btnOk );
+               errFlag = FALSE;
+       }
+       else {
+               gtk_notebook_set_page(
+                       GTK_NOTEBOOK(addrgather_dlg.notebook), PAGE_WARNING );
+               gtk_widget_set_sensitive( addrgather_dlg.btnOk, FALSE );
+               gtk_widget_grab_default( addrgather_dlg.btnCancel );
+       }
+
+       addrgather_dlg_status_show( "" );
+       gtk_widget_show( addrgather_dlg.window );
+
+       gtk_widget_grab_focus( addrgather_dlg.entryBook );
+       manage_window_set_transient( GTK_WINDOW(addrgather_dlg.window) );
+       gtk_main();
+
+       if( ! errFlag ) {
+               g_free( addrgather_dlg.folderPath );
+               addrgather_dlg.folderPath = NULL;
+       }
+       gtk_widget_hide( addrgather_dlg.window );
+       _harv_addressIndex_ = NULL;
+
+       if( addrgather_dlg.cancelled == TRUE ) return NULL;
+
+       return _harv_addressBook_;
+}
+
+/*
+* End of Source.
+*/
+
+
diff --git a/src/addrgather.h b/src/addrgather.h
new file mode 100644 (file)
index 0000000..53aa2b3
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2002 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Gather addresses.
+ */
+
+#ifndef __ADDR_GATHER_H__
+#define __ADDR_GATHER_H__
+
+/* Function prototypes */
+AddressBookFile *addrgather_dlg_execute( FolderItem *folderItem,
+                                        AddressIndex *addrIndex );
+
+#endif /* __ADDR_GATHER_H__ */
+
+/*
+* End of Source.
+*/
+
diff --git a/src/addrharvest.c b/src/addrharvest.c
new file mode 100644 (file)
index 0000000..a182925
--- /dev/null
@@ -0,0 +1,682 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2002 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Functions for an E-Mail address harvester.
+ * Code still needs some work. Address parsing not strictly correct.
+ */
+
+#include <sys/stat.h>
+#include <dirent.h>
+#include <glib.h>
+#include <string.h>
+
+#include "utils.h"
+#include "mgutils.h"
+#include "addrharvest.h"
+#include "addritem.h"
+
+/* Mail header names of interest */
+static gchar *_headerFrom_     = HEADER_FROM;
+static gchar *_headerReplyTo_  = HEADER_REPLY_TO;
+static gchar *_headerSender_   = HEADER_SENDER;
+static gchar *_headerErrorsTo_ = HEADER_ERRORS_TO;
+static gchar *_headerCC_       = HEADER_CC;
+static gchar *_headerTo_       = HEADER_TO;
+
+static gchar *_emptyString_ = "";
+
+#define MSG_BUFFSIZE    8192
+#define DFL_FOLDER_SIZE 20
+
+/*
+ * Header entry.
+ */
+typedef struct _HeaderEntry HeaderEntry;
+struct _HeaderEntry {
+       gchar      *header;
+       gboolean   selected;
+       ItemFolder *folder;
+       gint       count;
+};
+
+/*
+ * Build header table entry.
+ * Enter: harvester Harvester object.
+ *        name      Header name.
+ */
+static void *addrharvest_build_entry(
+               AddressHarvester* harvester, gchar *name )
+{
+       HeaderEntry *entry;
+
+       entry = g_new0( HeaderEntry, 1 );
+       entry->header = name;
+       entry->selected = FALSE;
+       entry->folder = NULL;
+       entry->count = 0;
+       harvester->headerTable = g_list_append( harvester->headerTable, entry );
+}
+
+static void addrharvest_print_hdrentry( HeaderEntry *entry, FILE *stream ) {
+       fprintf( stream, "Header Entry\n" );
+       fprintf( stream, "    name : %s\n", entry->header );
+       fprintf( stream, "selected : %s\n", entry->selected ? "yes" : "no" );
+}
+
+/*
+ * Free key in table.
+ */
+static gint addrharvest_free_table_vis( gpointer key, gpointer value, gpointer data ) {
+       g_free( key );
+       key = NULL;
+       value = NULL;
+       return TRUE;
+}
+
+/*
+ * Free lookup table.
+ */
+static void addrharvest_free_table( AddressHarvester* harvester ) {
+       GList *node;
+       HeaderEntry *entry;
+
+       /* Free header list */
+       node = harvester->headerTable;
+       while( node ) {
+               entry = ( HeaderEntry * ) node->data;
+               entry->header = NULL;
+               entry->selected = FALSE;
+               entry->folder = NULL;
+               entry->count = 0;
+               g_free( entry );
+               node = g_list_next( node );
+       }
+       g_list_free( harvester->headerTable );
+       harvester->headerTable = NULL;
+
+       /* Free duplicate table */
+       g_hash_table_freeze( harvester->dupTable );
+       g_hash_table_foreach_remove( harvester->dupTable, addrharvest_free_table_vis, NULL );
+       g_hash_table_thaw( harvester->dupTable );
+       g_hash_table_destroy( harvester->dupTable );
+       harvester->dupTable = NULL;
+}
+
+/*
+* Create new object.
+* Return: Harvester.
+*/
+AddressHarvester *addrharvest_create( void ) {
+       AddressHarvester *harvester;
+
+       harvester = g_new0( AddressHarvester, 1 );
+       harvester->path = NULL;
+       harvester->bufptr = harvester->buffer;
+       harvester->dupTable = g_hash_table_new( g_str_hash, g_str_equal );
+       harvester->folderSize = DFL_FOLDER_SIZE;
+       harvester->retVal = MGU_SUCCESS;
+
+       /* Build header table */
+       harvester->headerTable = NULL;
+       addrharvest_build_entry( harvester, _headerFrom_ );
+       addrharvest_build_entry( harvester, _headerReplyTo_ );
+       addrharvest_build_entry( harvester, _headerSender_ );
+       addrharvest_build_entry( harvester, _headerErrorsTo_ );
+       addrharvest_build_entry( harvester, _headerCC_ );
+       addrharvest_build_entry( harvester, _headerTo_ );
+
+       return harvester;
+}
+
+/*
+* Properties...
+*/
+/*
+ * Specify path to folder that will be harvested.
+ * Entry: harvester Harvester object.
+ *        value     Full directory path.
+ */
+void addrharvest_set_path( AddressHarvester* harvester, const gchar *value ) {
+       g_return_if_fail( harvester != NULL );
+       harvester->path = mgu_replace_string( harvester->path, value );
+       g_strstrip( harvester->path );
+}
+
+/*
+ * Specify maximum folder size.
+ * Entry: harvester Harvester object.
+ *        value     Folder size.
+ */
+void addrharvest_set_folder_size( AddressHarvester* harvester, const gint value ) {
+       g_return_if_fail( harvester != NULL );
+       if( value > 0 ) {
+               harvester->folderSize = value;
+       }
+}
+
+/*
+ * Search (case insensitive) for header entry with specified name.
+ * Enter: harvester Harvester.
+ *        name      Header name.
+ * Return: Header, or NULL if not found.
+ */
+static HeaderEntry *addrharvest_find( 
+       AddressHarvester* harvester, const gchar *name ) {
+       HeaderEntry *retVal;
+       GList *node;
+
+       retVal = NULL;
+       node = harvester->headerTable;
+       while( node ) {
+               HeaderEntry *entry;
+
+               entry = node->data;
+               if( g_strcasecmp( entry->header, name ) == 0 ) {
+                       retVal = entry;
+                       break;
+               }
+               node = g_list_next( node );
+       }
+       return retVal;
+}
+
+/*
+ * Set selection for specified heaader.
+ * Enter: harvester Harvester.
+ *        name      Header name.
+ *        value     Value to set.
+ */
+void addrharvest_set_header(
+       AddressHarvester* harvester, const gchar *name, const gboolean value )
+{
+       HeaderEntry *entry;
+
+       g_return_if_fail( harvester != NULL );
+       entry = addrharvest_find( harvester, name );
+       if( entry != NULL ) {
+               entry->selected = value;
+       }
+}
+
+/*
+ * Get address count
+ * Enter: harvester Harvester.
+ *        name      Header name.
+ * Return: Address count, or -1 if header not found.
+ */
+gint addrharvest_get_count(
+       AddressHarvester* harvester, const gchar *name )
+{
+       HeaderEntry *entry;
+       gint count;
+
+       count = -1;
+       g_return_val_if_fail( harvester != NULL, count );
+       entry = addrharvest_find( harvester, name );
+       if( entry != NULL ) {
+               count = entry->count;
+       }
+       return count;
+}
+
+/*
+* Free up object by releasing internal memory.
+* Enter: harvester Harvester.
+*/
+void addrharvest_free( AddressHarvester *harvester ) {
+       g_return_if_fail( harvester != NULL );
+
+       /* Free internal stuff */
+       addrharvest_free_table( harvester );
+       g_free( harvester->path );
+
+       /* Clear pointers */
+       harvester->path = NULL;
+       harvester->retVal = MGU_SUCCESS;
+       harvester->headerTable = NULL;
+
+       harvester->folderSize = 0;
+
+       /* Now release object */
+       g_free( harvester );
+}
+
+/*
+* Display object to specified stream.
+* Enter: harvester Harvester.
+*        stream    Output stream.
+*/
+void addrharvest_print( AddressHarvester *harvester, FILE *stream ) {
+       GList *node;
+       HeaderEntry *entry;
+
+       g_return_if_fail( harvester != NULL );
+       fprintf( stream, "Address Harvester:\n" );
+       fprintf( stream, " file path: '%s'\n", harvester->path );
+       fprintf( stream, "max folder: %d'\n", harvester->folderSize );
+
+       node = harvester->headerTable;
+       while( node ) {
+               entry = node->data;
+               fprintf( stream, "   header: %s", entry->header );
+               fprintf( stream, "\t: %s", entry->selected ? "yes" : "no" );
+               fprintf( stream, "\t: %d\n", entry->count );
+               node = g_list_next( node );
+       }
+       fprintf( stream, "  ret val: %d\n", harvester->retVal );
+}
+
+#ifdef STANDALONE
+gint to_number(const gchar *nstr) {
+       register const gchar *p;
+       if (*nstr == '\0') return -1;
+       for( p = nstr; *p != '\0'; p++ )
+               if (!isdigit(*p)) return -1;
+       return atoi(nstr);
+}
+#endif
+
+/*
+ * Replace leading and trailing characters (quotes) in input string
+ * with spaces. Only matching non-blank characters that appear at both
+ * start and end of string are replaces. Control characters are also
+ * replaced with spaces.
+ * Enter: str String to process.
+ *        ch  Character to remove.
+ */
+static void addrutil_strip_char( gchar *str, gchar ch ) {
+       gchar *as;
+       gchar *ae;
+
+       /* Search forwards for first non-space match */
+       as = str;
+       ae = -1 + str + strlen( str );
+       while( as < ae ) {
+               if( *as != ' ' ) {
+                       if( *as == ch ) {
+                               /* Search backwards from end for match */
+                               while( ae > as ) {
+                                       if( *ae != ' ' ) {
+                                               if( *ae == ch ) {
+                                                       *as = ' ';
+                                                       *ae = ' ';
+                                                       return;
+                                               }
+                                               if( *ae < 32 ) {
+                                                       *ae = ' ';
+                                               }
+                                               else if( *ae == 127 ) {
+                                                       *ae = ' ';
+                                               }
+                                               else {
+                                                       return;
+                                               }
+                                       }
+                                       ae--;
+                               }
+                       }
+                       if( *as < 32 ) {
+                               *as = ' ';
+                       }
+                       else if( *as == 127 ) {
+                               *as = ' ';
+                       }
+                       else {
+                               return;
+                       }
+               }
+               as++;
+       }
+       return;
+}
+
+/*
+ * Remove backslash character from input string.
+ * Enter: str String to process.
+ */
+static void addrutil_unescape( gchar *str ) {
+       gchar *p;
+       gint ilen;
+
+       p = str;
+       while( *p ) {
+               if( *p == '\\' ) {
+                       ilen = strlen( p + 1 );
+                       memmove( p, p + 1, ilen );
+               }
+               p++;
+       }
+}
+
+/*
+ * Parse name from email address string.
+ * Enter: buf Start address of buffer to process (not modified).
+ *        atp Pointer to email at (@) character.
+ *        ap  Pointer to start of email address returned.
+ *        ep  Pointer to end of email address returned.
+ * Return: Parsed name or NULL if not present. This should be g_free'd
+ * when done.
+ */
+static gchar *addrutil_parse_name(
+               const gchar *buf, const gchar *atp, const gchar **ap,
+               const gchar **ep )
+{
+       gchar *name;
+       const gchar *pos;
+       const gchar *tmp;
+       const gchar *bp;
+       gint ilen;
+
+       name = NULL;
+       *ap = NULL;
+       *ep = NULL;
+
+       /* Find first non-separator char */
+       bp = buf;
+       while( TRUE ) {
+               if( strchr( ",; \n\r", *bp ) == NULL ) break;
+               bp++;
+       }
+
+       /* Search back for start of name */
+       tmp = atp;
+       pos = atp;
+       while( pos >= bp ) {
+               tmp = pos;
+               if( *pos == '<' ) {
+                       /* Found start of address/end of name part */
+                       ilen = -1 + ( size_t ) ( pos - bp );
+                       name = g_strndup( bp, ilen + 1 );
+                       *(name + ilen + 1) = '\0';
+
+                       /* Remove leading trailing quotes and spaces */
+                       addrutil_strip_char( name, '\"' );
+                       addrutil_strip_char( name, '\'' );
+                       addrutil_strip_char( name, '\"' );
+                       addrutil_unescape( name );
+                       g_strstrip( name );
+                       break;
+               }
+               pos--;
+       }
+       *ap = tmp;
+
+       /* Search forward for end of address */
+       pos = atp + 1;
+       while( TRUE ) {
+               if( *pos == '>' ) {
+                       pos++;
+                       break;
+               }
+               if( strchr( ",; \'\n\r", *pos ) ) break;
+               pos++;
+       }
+       *ep = pos;
+
+       return name;
+
+}
+
+/*
+ * Insert address into cache.
+ * Enter: harvester Harvester object.
+ *        entry     Header object.
+ *        cache     Address cache to load.
+ *        name      Name.
+ *        address   eMail address.
+ * Return: Person inserted.
+ */
+static ItemPerson *addrharvest_insert_cache(
+               AddressHarvester *harvester, HeaderEntry *entry,
+               AddressCache *cache, const gchar *name,
+               const gchar *address )
+{
+       ItemPerson *person;
+       ItemFolder *folder;
+       gchar *folderName;
+       gboolean newFolder;
+       gint cnt;
+
+       newFolder = FALSE;
+       folder = entry->folder;
+       if( folder == NULL ) {
+               newFolder = TRUE;       /* No folder yet */
+       }
+       if( entry->count % harvester->folderSize == 0 ) {
+               newFolder = TRUE;       /* Folder is full */
+       }
+
+       if( newFolder ) {
+               cnt = 1 + ( entry->count / harvester->folderSize );
+               folderName = g_strdup_printf( "%s (%d)", entry->header, cnt );
+               folder = addritem_create_item_folder();
+               addritem_folder_set_name( folder, folderName );
+               addritem_folder_set_remarks( folder, "" );
+               addrcache_id_folder( cache, folder );
+               addrcache_add_folder( cache, folder );
+               entry->folder = folder;
+               g_free( folderName );
+       }
+
+       person = addrcache_add_contact( cache, folder, name, address, "" );
+       entry->count++;
+       return person;
+}
+
+#define ATCHAR "@"
+
+/*
+ * Parse address from header buffer creating address in cache.
+ * Enter: harvester Harvester object.
+ *        entry     Header object.
+ *        cache     Address cache to load.
+ *        hdrBuf    Pointer to header buffer.
+ */
+static void addrharvest_parse_address(
+               AddressHarvester *harvester, HeaderEntry *entry,
+               AddressCache *cache, const gchar *hdrBuf )
+{
+       gchar addr[ MSG_BUFFSIZE ];
+       const gchar *bp;
+       const gchar *ep;
+       gchar *atCh;
+       gchar *name;
+       gchar *value;
+       gchar *key;
+       gint addrLen;
+       ItemPerson *person;
+
+       /* printf( "hdrBuf    :%s:\n", hdrBuf ); */
+       /* Search for an address */
+       while( atCh = strcasestr( hdrBuf, ATCHAR ) ) {
+               name = addrutil_parse_name( hdrBuf, atCh, &bp, &ep );
+               addrLen = ( size_t ) ( ep - bp );
+               strncpy( addr, bp, addrLen );
+               addr[ addrLen ] = '\0';
+               extract_address( addr );
+               /* printf( "name/addr :%s:\t:%s:\n", addr, name ); */
+               hdrBuf = ep;
+               if( atCh == ep ) {
+                       hdrBuf++;
+               }
+               if( strlen( addr ) > 0 ) {
+                       if( name == NULL ) {
+                               name = g_strdup( _emptyString_ );
+                       }
+                       g_strdown( addr );
+                       /* printf( "name/addr :%s:\t:%s:\n", addr, name ); */
+                       person = g_hash_table_lookup(
+                                       harvester->dupTable, addr );
+                       if( person ) {
+                               /* Use longest name */
+                               value = ADDRITEM_NAME(person);
+                               if( strlen( name ) > strlen( value ) ) {
+                                       addritem_person_set_common_name(
+                                               person, name );
+                               }
+                       }
+                       else {
+                               /* Insert entry */
+                               key = g_strdup( addr );
+                               person = addrharvest_insert_cache(
+                                       harvester, entry, cache, name, addr );
+                               g_hash_table_insert(
+                                       harvester->dupTable, key, person );
+                       }
+               }
+               g_free( name );
+       }
+}
+
+/*
+ * Read specified file into address book.
+ * Enter:  harvester Harvester object.
+ *         fileName  File to read.
+ *         cache     Address cache to load.
+ * Return: Status.
+ */
+static gint addrharvest_readfile(
+               AddressHarvester *harvester, const gchar *fileName,
+               AddressCache *cache )
+{
+       gint retVal;
+       FILE *msgFile;
+       gchar buf[ MSG_BUFFSIZE ], tmp[ MSG_BUFFSIZE ];
+       HeaderEntry *entry;
+
+       msgFile = fopen( fileName, "r" );
+       if( ! msgFile ) {
+               /* Cannot open file */
+               retVal = MGU_OPEN_FILE;
+               return retVal;
+       }
+
+       for( ;; ) {
+               gint val;
+               gchar *p;
+
+               val = procheader_get_one_field( buf, sizeof(buf), msgFile, NULL );
+               if( val == -1 ) {
+                       break;
+               }
+               conv_unmime_header( tmp, sizeof(tmp), buf, NULL );
+               if(( p = strchr( tmp, ':' ) ) != NULL ) {
+                       const gchar *hdr;
+
+                       *p = '\0';
+                       hdr = p + 1;
+                       entry = addrharvest_find( harvester, tmp );
+                       if( entry && entry->selected ) {
+                               addrharvest_parse_address(
+                                       harvester, entry, cache, hdr );
+                       }
+               }
+       }
+
+       fclose( msgFile );
+       return MGU_SUCCESS;
+}
+
+#undef ATCHAR
+
+/*
+ * ============================================================================
+ * Read all files in specified directory into address book.
+ * Enter:  harvester Harvester object.
+ *         cache     Address cache to load.
+ * Return: Status.
+ * ============================================================================
+ */
+gint addrharvest_harvest( AddressHarvester *harvester, AddressCache *cache ) {
+       gint retVal;
+       DIR *dp;
+       struct dirent *d;
+       struct stat s;
+       gint num;
+
+       retVal = MGU_BAD_ARGS;
+       g_return_val_if_fail( harvester != NULL, retVal );
+       g_return_val_if_fail( cache != NULL, retVal );
+       g_return_val_if_fail( harvester->path != NULL, retVal );
+
+       /* Clear cache */
+       addrcache_clear( cache );
+       cache->dataRead = FALSE;
+
+       if( chdir( harvester->path ) < 0 ) {
+               printf( "Error changing dir\n" );
+               return retVal;
+       }
+
+       if( ( dp = opendir( harvester->path ) ) == NULL ) {
+               printf( "Error opening dir\n" );
+               return retVal;
+       }
+
+       while( ( d = readdir( dp ) ) != NULL ) {
+               stat( d->d_name, &s );
+               if( S_ISREG( s.st_mode ) ) {
+                       if( ( num = to_number( d->d_name ) ) >= 0 ) {
+                               addrharvest_readfile( harvester, d->d_name, cache );
+                       }
+               }
+       }
+
+       closedir( dp );
+
+       /* Mark cache */
+       cache->modified = FALSE;
+       cache->dataRead = TRUE;
+
+       return retVal;
+}
+
+/*
+ * ============================================================================
+ * Test whether any headers have been selected for processing.
+ * Enter:  harvester Harvester object.
+ * Return: TRUE if a header was selected, FALSE if none were selected.
+ * ============================================================================
+ */
+gboolean addrharvest_check_header( AddressHarvester *harvester ) {
+       gboolean retVal;
+       GList *node;
+
+       retVal = FALSE;
+       g_return_val_if_fail( harvester != NULL, retVal );
+
+       node = harvester->headerTable;
+       while( node ) {
+               HeaderEntry *entry;
+
+               entry = ( HeaderEntry * ) node->data;
+               if( entry->selected ) return TRUE;
+               node = g_list_next( node );
+       }
+       return retVal;
+}
+
+/*
+ * ============================================================================
+ * End of Source.
+ * ============================================================================
+ */
+
+
diff --git a/src/addrharvest.h b/src/addrharvest.h
new file mode 100644 (file)
index 0000000..3d64688
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2002 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Definitions for an E-Mail address harvester.
+ */
+
+#ifndef __ADDRHARVEST_H__
+#define __ADDRHARVEST_H__
+
+#include <stdio.h>
+#include <glib.h>
+#include "addrbook.h"
+
+/* Headers that will be recognized */
+#define HEADER_FROM      "From"
+#define HEADER_REPLY_TO  "Reply-to"
+#define HEADER_SENDER    "Sender"
+#define HEADER_ERRORS_TO "Errors-to"
+#define HEADER_CC        "Cc"
+#define HEADER_TO        "To"
+
+#define MESSAGEBUFSIZE   2048
+
+/* Harvester file object */
+typedef struct _AddressHarvester AddressHarvester;
+struct _AddressHarvester {
+       GList      *headerTable;
+       gchar      *path;
+       gchar      *bufptr;
+       GHashTable *dupTable;
+       gint       folderSize;
+       gchar      buffer[ MESSAGEBUFSIZE ];
+       gint       retVal;
+};
+
+/* Function prototypes */
+AddressHarvester *addrharvest_create   ( void );
+void addrharvest_free                  ( AddressHarvester *harvester );
+void addrharvest_set_path              ( AddressHarvester *harvester,
+                                         const gchar *value );
+void addrharvest_set_folder_size       ( AddressHarvester* harvester,
+                                         const gint value );
+void addrharvest_set_header            ( AddressHarvester* harvester,
+                                         const gchar *name,
+                                         const gboolean value );
+gint addrharvest_get_count             ( AddressHarvester* harvester,
+                                         const gchar *name );
+void addrharvest_print                 ( AddressHarvester *harvester,
+                                         FILE *stream );
+gint addrharvest_harvest               ( AddressHarvester *harvester,
+                                         AddressCache *cache );
+gboolean addrharvest_check_header      ( AddressHarvester *harvester );
+
+#endif /* __ADDRHARVEST_H__ */
+
index ceedab367905fce943eaf5a2399181fccd2388e5..2fcaddb32c7a46de6a15f89a484ab92c90c7e2f7 100644 (file)
@@ -457,6 +457,10 @@ static void key_pressed (GtkWidget *widget,
 
 static void set_toolbar_style(MainWindow *mainwin);
 
+static void addr_gather_cb      ( MainWindow  *mainwin,
+                                  guint       action,
+                                  GtkWidget   *widget );
+
 #define  SEPARATE_ACTION  667
 
 static GtkItemFactoryEntry mainwin_entries[] =
@@ -473,6 +477,7 @@ static GtkItemFactoryEntry mainwin_entries[] =
        {N_("/_File/_Import mbox file..."),     NULL, import_mbox_cb, 0, NULL},
        {N_("/_File/_Export to mbox file..."),  NULL, export_mbox_cb, 0, NULL},
        {N_("/_File/Empty _trash"),             "<shift>D", empty_trash_cb, 0, NULL},
+       {N_("/_File/_Gather addresses..."),     NULL, addr_gather_cb, 0, NULL},
        {N_("/_File/---"),                      NULL, NULL, 0, "<Separator>"},
        {N_("/_File/_Save as..."),              "<control>S", save_as_cb, 0, NULL},
        {N_("/_File/_Print..."),                NULL, print_cb, 0, NULL},
@@ -1548,6 +1553,7 @@ void main_window_set_menu_sensitive(MainWindow *mainwin)
                {"/File/Import mbox file..."   , M_UNLOCKED},
                {"/File/Export to mbox file...", M_UNLOCKED},
                {"/File/Empty trash"           , M_UNLOCKED},
+               {"/File/Gather addresses...", M_SINGLE_TARGET_EXIST|M_UNLOCKED},
                {"/File/Save as...", M_SINGLE_TARGET_EXIST|M_UNLOCKED},
                {"/File/Print..."  , M_TARGET_EXIST|M_UNLOCKED},
                /* {"/File/Close", M_UNLOCKED}, */
@@ -3089,3 +3095,14 @@ static void set_toolbar_style(MainWindow *mainwin)
        }
 }
 
+static void addr_gather_cb( MainWindow *mainwin,
+                           guint action,
+                           GtkWidget *widget )
+{
+       addressbook_gather( mainwin->summaryview->folder_item );
+}
+
+/*
+* End of Source.
+*/
+