+2002-04-01 [match] 0.7.4claws60
+
+ * src/pine.[ch]
+ * src/importpine.[ch]
+ * src/addressbook.c
+ import Pine address book.
+
2002-04-01 [match] 0.7.4claws60
* src/addrharvest.[ch]
MICRO_VERSION=4
INTERFACE_AGE=0
BINARY_AGE=0
-EXTRA_VERSION=claws60
+EXTRA_VERSION=claws61
VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION$EXTRA_VERSION
dnl set $target
src/import.c
src/importldif.c
src/importmutt.c
+src/importpine.c
src/inc.c
src/inputdialog.c
src/jpilot.c
src/news.c
src/nntp.c
src/passphrase.c
+src/pine.c
src/pop.c
src/prefs.c
src/prefs_account.c
importldif.c importldif.h \
mutt.c mutt.h \
importmutt.c importmutt.h \
+ pine.c pine.h \
+ importpine.c importpine.h \
jpilot.c jpilot.h \
syldap.c syldap.h \
editbook.c editbook.h \
#include "importldif.h"
#include "mutt.h"
#include "importmutt.h"
+#include "pine.h"
+#include "importpine.h"
#ifdef USE_JPILOT
#include "jpilot.h"
static void addressbook_import_ldif_cb ( void );
static void addressbook_import_mutt_cb ( void );
+static void addressbook_import_pine_cb ( void );
static void addressbook_clip_cut_cb ( void );
static void addressbook_clip_copy_cb ( void );
static void addressbook_clip_paste_cb ( void );
{N_("/_Tools/---"), NULL, NULL, 0, "<Separator>"},
{N_("/_Tools/Import _LDIF file"), NULL, addressbook_import_ldif_cb, 0, NULL},
{N_("/_Tools/Import M_utt file"), NULL, addressbook_import_mutt_cb, 0, NULL},
+ {N_("/_Tools/Import _Pine file"), NULL, addressbook_import_pine_cb, 0, NULL},
{N_("/_Help"), NULL, NULL, 0, "<LastBranch>"},
{N_("/_Help/_About"), NULL, about_show, 0, NULL}
};
}
}
+/*
+* Import Pine file.
+*/
+static void addressbook_import_pine_cb() {
+ AddressDataSource *ds = NULL;
+ AdapterDSource *ads = NULL;
+ AddressBookFile *abf = NULL;
+ AdapterInterface *adapter;
+ GtkCTreeNode *newNode;
+
+ adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
+ if( adapter ) {
+ if( adapter->treeNode ) {
+ abf = addressbook_imp_pine( _addressIndex_ );
+ if( abf ) {
+ ds = addrindex_index_add_datasource(
+ _addressIndex_, ADDR_IF_BOOK, abf );
+ ads = addressbook_create_ds_adapter(
+ ds, ADDR_BOOK, NULL );
+ addressbook_ads_set_name(
+ ads, addrbook_get_name( abf ) );
+ newNode = addressbook_add_object(
+ adapter->treeNode,
+ ADDRESS_OBJECT(ads) );
+ if( newNode ) {
+ gtk_ctree_select(
+ GTK_CTREE(addrbook.ctree),
+ newNode );
+ addrbook.treeSelected = newNode;
+ }
+
+ /* Notify address completion */
+ invalidate_address_completion();
+ }
+ }
+ }
+}
+
/*
* Gather addresses.
* Enter: folderItem Folder to import.
--- /dev/null
+/*
+ * 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.
+ */
+
+/*
+ * Import Pine address book data.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "defs.h"
+
+#include <glib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtktable.h>
+#include <gtk/gtkbutton.h>
+
+#include "intl.h"
+#include "addrbook.h"
+#include "addressbook.h"
+#include "addressitem.h"
+#include "gtkutils.h"
+#include "prefs_common.h"
+#include "manage_window.h"
+#include "mgutils.h"
+#include "pine.h"
+
+#define IMPORTPINE_GUESS_NAME "Pine Import"
+
+static struct _ImpPine_Dlg {
+ GtkWidget *window;
+ GtkWidget *file_entry;
+ GtkWidget *name_entry;
+ GtkWidget *ok_btn;
+ GtkWidget *cancel_btn;
+ GtkWidget *statusbar;
+ gint status_cid;
+} imppine_dlg;
+
+static struct _AddressFileSelection _imp_pine_file_selector_;
+static AddressBookFile *_importedBook_;
+static AddressIndex *_imp_addressIndex_;
+
+/*
+* Edit functions.
+*/
+void imp_pine_status_show( gchar *msg ) {
+ if( imppine_dlg.statusbar != NULL ) {
+ gtk_statusbar_pop( GTK_STATUSBAR(imppine_dlg.statusbar), imppine_dlg.status_cid );
+ if( msg ) {
+ gtk_statusbar_push( GTK_STATUSBAR(imppine_dlg.statusbar), imppine_dlg.status_cid, msg );
+ }
+ }
+}
+
+static gboolean imp_pine_import_file( gchar *sName, gchar *sFile ) {
+ gboolean retVal = FALSE;
+ gchar *newFile;
+ AddressBookFile *abf = NULL;
+ PineFile *pdf = NULL;
+
+ if( _importedBook_ ) {
+ addrbook_free_book( _importedBook_ );
+ }
+
+ abf = addrbook_create_book();
+ addrbook_set_path( abf, _imp_addressIndex_->filePath );
+ addrbook_set_name( abf, sName );
+ newFile = addrbook_guess_next_file( abf );
+ addrbook_set_file( abf, newFile );
+ g_free( newFile );
+
+ /* Import data from file */
+ pdf = pine_create();
+ pine_set_file( pdf, sFile );
+ if( pine_import_data( pdf, abf->addressCache ) == MGU_SUCCESS ) {
+ addrbook_save_data( abf );
+ _importedBook_ = abf;
+ retVal = TRUE;
+ }
+ else {
+ addrbook_free_book( abf );
+ }
+
+ return retVal;
+}
+
+static void imp_pine_ok( GtkWidget *widget, gboolean *cancelled ) {
+ gchar *sName;
+ gchar *sFile;
+ gchar *sMsg = NULL;
+ gboolean errFlag = FALSE;
+
+ sFile = gtk_editable_get_chars( GTK_EDITABLE(imppine_dlg.file_entry), 0, -1 );
+ g_strchug( sFile ); g_strchomp( sFile );
+ gtk_entry_set_text( GTK_ENTRY(imppine_dlg.file_entry), sFile );
+
+ sName = gtk_editable_get_chars( GTK_EDITABLE(imppine_dlg.name_entry), 0, -1 );
+ g_strchug( sName ); g_strchomp( sName );
+ gtk_entry_set_text( GTK_ENTRY(imppine_dlg.name_entry), sName );
+
+ if( *sFile == '\0'|| strlen( sFile ) < 1 ) {
+ sMsg = _( "Please select a file." );
+ errFlag = TRUE;
+ }
+
+ if( *sName == '\0'|| strlen( sName ) < 1 ) {
+ if( ! errFlag ) sMsg = _( "Address book name must be supplied." );
+ errFlag = TRUE;
+ }
+
+ if( errFlag ) {
+ imp_pine_status_show( sMsg );
+ }
+ else {
+ /* Import the file */
+ if( imp_pine_import_file( sName, sFile ) ) {
+ *cancelled = FALSE;
+ gtk_main_quit();
+ }
+ else {
+ imp_pine_status_show( _( "Error importing Pine file." ) );
+ }
+ }
+
+ g_free( sFile );
+ g_free( sName );
+
+}
+
+static void imp_pine_cancel( GtkWidget *widget, gboolean *cancelled ) {
+ *cancelled = TRUE;
+ gtk_main_quit();
+}
+
+static void imp_pine_file_ok( GtkWidget *widget, gpointer data ) {
+ gchar *sFile;
+ AddressFileSelection *afs;
+ GtkWidget *fileSel;
+
+ afs = ( AddressFileSelection * ) data;
+ fileSel = afs->fileSelector;
+ sFile = gtk_file_selection_get_filename( GTK_FILE_SELECTION(fileSel) );
+
+ afs->cancelled = FALSE;
+ gtk_entry_set_text( GTK_ENTRY(imppine_dlg.file_entry), sFile );
+ gtk_widget_hide( afs->fileSelector );
+ gtk_grab_remove( afs->fileSelector );
+ gtk_widget_grab_focus( imppine_dlg.file_entry );
+ imp_pine_status_show( _( "Please select a file to import." ) );
+}
+
+static void imp_pine_file_cancel( GtkWidget *widget, gpointer data ) {
+ AddressFileSelection *afs = ( AddressFileSelection * ) data;
+ afs->cancelled = TRUE;
+ gtk_widget_hide( afs->fileSelector );
+ gtk_grab_remove( afs->fileSelector );
+ gtk_widget_grab_focus( imppine_dlg.file_entry );
+}
+
+static void imp_pine_file_select_create( AddressFileSelection *afs ) {
+ GtkWidget *fileSelector;
+
+ fileSelector = gtk_file_selection_new( _("Select Pine File") );
+ gtk_file_selection_hide_fileop_buttons( GTK_FILE_SELECTION(fileSelector) );
+ gtk_signal_connect( GTK_OBJECT (GTK_FILE_SELECTION(fileSelector)->ok_button),
+ "clicked", GTK_SIGNAL_FUNC (imp_pine_file_ok), ( gpointer ) afs );
+ gtk_signal_connect( GTK_OBJECT (GTK_FILE_SELECTION(fileSelector)->cancel_button),
+ "clicked", GTK_SIGNAL_FUNC (imp_pine_file_cancel), ( gpointer ) afs );
+ afs->fileSelector = fileSelector;
+ afs->cancelled = TRUE;
+}
+
+static void imp_pine_file_select( void ) {
+ gchar *sFile;
+ if (! _imp_pine_file_selector_.fileSelector )
+ imp_pine_file_select_create( & _imp_pine_file_selector_ );
+
+ sFile = gtk_editable_get_chars( GTK_EDITABLE(imppine_dlg.file_entry), 0, -1 );
+ gtk_file_selection_set_filename( GTK_FILE_SELECTION( _imp_pine_file_selector_.fileSelector ), sFile );
+ g_free( sFile );
+ gtk_widget_show( _imp_pine_file_selector_.fileSelector );
+ gtk_grab_add( _imp_pine_file_selector_.fileSelector );
+}
+
+static gint imp_pine_delete_event( GtkWidget *widget, GdkEventAny *event, gboolean *cancelled ) {
+ *cancelled = TRUE;
+ gtk_main_quit();
+ return TRUE;
+}
+
+static void imp_pine_key_pressed( GtkWidget *widget, GdkEventKey *event, gboolean *cancelled ) {
+ if (event && event->keyval == GDK_Escape) {
+ *cancelled = TRUE;
+ gtk_main_quit();
+ }
+}
+
+static void imp_pine_create( gboolean *cancelled ) {
+ GtkWidget *window;
+ GtkWidget *vbox;
+ GtkWidget *table;
+ GtkWidget *label;
+ GtkWidget *file_entry;
+ GtkWidget *name_entry;
+ GtkWidget *hbbox;
+ GtkWidget *hsep;
+ GtkWidget *ok_btn;
+ GtkWidget *cancel_btn;
+ GtkWidget *file_btn;
+ GtkWidget *statusbar;
+ GtkWidget *hsbox;
+ gint top;
+
+ window = gtk_window_new(GTK_WINDOW_DIALOG);
+ gtk_widget_set_usize(window, 450, -1);
+ gtk_container_set_border_width( GTK_CONTAINER(window), 0 );
+ gtk_window_set_title( GTK_WINDOW(window), _("Import Pine file into Address Book") );
+ 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(imp_pine_delete_event),
+ cancelled);
+ gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
+ GTK_SIGNAL_FUNC(imp_pine_key_pressed),
+ cancelled);
+
+ vbox = gtk_vbox_new(FALSE, 8);
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+ gtk_container_set_border_width( GTK_CONTAINER(vbox), 0 );
+
+ table = gtk_table_new(2, 3, 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(_("Name"));
+ 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);
+
+ name_entry = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(table), name_entry, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+ /* Second row */
+ top = 1;
+ label = gtk_label_new(_("File"));
+ 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);
+
+ file_entry = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(table), file_entry, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+
+ file_btn = gtk_button_new_with_label( _(" ... "));
+ gtk_table_attach(GTK_TABLE(table), file_btn, 2, 3, top, (top + 1), GTK_FILL, 0, 3, 0);
+
+ /* 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, &ok_btn, _("OK"),
+ &cancel_btn, _("Cancel"), NULL, NULL);
+ gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
+ gtk_container_set_border_width( GTK_CONTAINER(hbbox), 0 );
+ gtk_widget_grab_default(ok_btn);
+
+ hsep = gtk_hseparator_new();
+ gtk_box_pack_end(GTK_BOX(vbox), hsep, FALSE, FALSE, 0);
+
+ gtk_signal_connect(GTK_OBJECT(ok_btn), "clicked",
+ GTK_SIGNAL_FUNC(imp_pine_ok), cancelled);
+ gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked",
+ GTK_SIGNAL_FUNC(imp_pine_cancel), cancelled);
+ gtk_signal_connect(GTK_OBJECT(file_btn), "clicked",
+ GTK_SIGNAL_FUNC(imp_pine_file_select), NULL);
+
+ gtk_widget_show_all(vbox);
+
+ imppine_dlg.window = window;
+ imppine_dlg.file_entry = file_entry;
+ imppine_dlg.name_entry = name_entry;
+ imppine_dlg.ok_btn = ok_btn;
+ imppine_dlg.cancel_btn = cancel_btn;
+ imppine_dlg.statusbar = statusbar;
+ imppine_dlg.status_cid = gtk_statusbar_get_context_id(
+ GTK_STATUSBAR(statusbar), "Import Pine Dialog" );
+}
+
+AddressBookFile *addressbook_imp_pine( AddressIndex *addrIndex ) {
+ static gboolean cancelled;
+ gchar *pineFile;
+
+ _importedBook_ = NULL;
+ _imp_addressIndex_ = addrIndex;
+
+ if( ! imppine_dlg.window )
+ imp_pine_create(&cancelled);
+ gtk_widget_grab_focus(imppine_dlg.ok_btn);
+ gtk_widget_grab_focus(imppine_dlg.file_entry);
+ gtk_widget_show(imppine_dlg.window);
+ manage_window_set_transient(GTK_WINDOW(imppine_dlg.window));
+
+ imp_pine_status_show( _( "Please select a file to import." ) );
+ pineFile = pine_find_file();
+ gtk_entry_set_text( GTK_ENTRY(imppine_dlg.name_entry), IMPORTPINE_GUESS_NAME );
+ gtk_entry_set_text( GTK_ENTRY(imppine_dlg.file_entry), pineFile );
+ g_free( pineFile );
+ pineFile = NULL;
+
+ gtk_main();
+ gtk_widget_hide(imppine_dlg.window);
+ _imp_addressIndex_ = NULL;
+
+ if (cancelled == TRUE) return NULL;
+ return _importedBook_;
+}
+
+/*
+* End of Source.
+*/
+
--- /dev/null
+/*
+ * 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.
+ */
+
+/*
+ * Import Pine data.
+ */
+
+#ifndef __IMPORT_PINE_H__
+#define __IMPORT_PINE_H__
+
+/* Function prototypes */
+AddressBookFile *addressbook_imp_pine( AddressIndex *addrIndex );
+
+#endif /* __IMPORT_PINE_H__ */
+
+/*
+* End of Source.
+*/
+
--- /dev/null
+/*
+ * 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 necessary to access Pine address book file.
+ */
+
+#include <sys/stat.h>
+#include <glib.h>
+#include <string.h>
+
+#include "utils.h"
+#include "mgutils.h"
+#include "pine.h"
+#include "addritem.h"
+#include "addrcache.h"
+
+#define PINE_HOME_FILE ".addressbook"
+#define PINEBUFSIZE 2048
+#define CHAR_QUOTE '\"'
+#define CHAR_APOS '\''
+#define CHAR_COMMA ','
+#define CHAR_AT '@'
+
+/*
+* Create new object.
+*/
+PineFile *pine_create() {
+ PineFile *pineFile;
+ pineFile = g_new0( PineFile, 1 );
+ pineFile->path = NULL;
+ pineFile->file = NULL;
+ pineFile->retVal = MGU_SUCCESS;
+ pineFile->uniqTable = g_hash_table_new( g_str_hash, g_str_equal );
+ pineFile->cbProgress = NULL;
+ return pineFile;
+}
+
+/*
+* Properties...
+*/
+void pine_set_file( PineFile* pineFile, const gchar *value ) {
+ g_return_if_fail( pineFile != NULL );
+ pineFile->path = mgu_replace_string( pineFile->path, value );
+ g_strstrip( pineFile->path );
+}
+
+/*
+* Register a callback function. When called, the function will be passed
+* the following arguments:
+* PineFile object,
+* File size (long),
+* Current position (long)
+* This can be used for a progress indicator.
+*/
+void pine_set_callback( PineFile *pineFile, void *func ) {
+ pineFile->cbProgress = func;
+}
+
+/*
+ * Free key in table.
+ */
+static gint pine_free_table_vis( gpointer key, gpointer value, gpointer data ) {
+ g_free( key );
+ key = NULL;
+ value = NULL;
+ return TRUE;
+}
+
+/*
+* Free up object by releasing internal memory.
+*/
+void pine_free( PineFile *pineFile ) {
+ g_return_if_fail( pineFile != NULL );
+
+ /* Close file */
+ if( pineFile->file ) fclose( pineFile->file );
+
+ /* Free internal stuff */
+ g_free( pineFile->path );
+
+ /* Free unique address table */
+ g_hash_table_freeze( pineFile->uniqTable );
+ g_hash_table_foreach_remove( pineFile->uniqTable, pine_free_table_vis, NULL );
+ g_hash_table_thaw( pineFile->uniqTable );
+ g_hash_table_destroy( pineFile->uniqTable );
+
+ /* Clear pointers */
+ pineFile->file = NULL;
+ pineFile->path = NULL;
+ pineFile->retVal = MGU_SUCCESS;
+ pineFile->uniqTable = NULL;
+ pineFile->cbProgress = NULL;
+
+ /* Now release file object */
+ g_free( pineFile );
+}
+
+/*
+ * Display object to specified stream.
+ * Enter: pineFile File object.
+ * stream File..
+ */
+void pine_print_file( PineFile *pineFile, FILE *stream ) {
+ g_return_if_fail( pineFile != NULL );
+ fprintf( stream, "Pine File:\n" );
+ fprintf( stream, "file spec: '%s'\n", pineFile->path );
+ fprintf( stream, " ret val: %d\n", pineFile->retVal );
+}
+
+/*
+ * Open file for read.
+ * Enter: pineFile File object.
+ * return: TRUE if file opened successfully.
+ */
+static gint pine_open_file( PineFile* pineFile ) {
+ if( pineFile->path ) {
+ pineFile->file = fopen( pineFile->path, "rb" );
+ if( ! pineFile->file ) {
+ pineFile->retVal = MGU_OPEN_FILE;
+ return pineFile->retVal;
+ }
+ }
+ else {
+ /* printf( "file not specified\n" ); */
+ pineFile->retVal = MGU_NO_FILE;
+ return pineFile->retVal;
+ }
+
+ /* Setup a buffer area */
+ pineFile->retVal = MGU_SUCCESS;
+ return pineFile->retVal;
+}
+
+/*
+ * Close file.
+ * Enter: pineFile File object.
+ */
+static void pine_close_file( PineFile *pineFile ) {
+ g_return_if_fail( pineFile != NULL );
+ if( pineFile->file ) fclose( pineFile->file );
+ pineFile->file = NULL;
+}
+
+/*
+ * Read line of text from file.
+ * Enter: pineFile File object.
+ * Return: Copy of buffer. Should be g_free'd when done.
+ */
+static gchar *pine_read_line( PineFile *pineFile ) {
+ gchar buf[ PINEBUFSIZE ];
+ gchar ch;
+ gchar *ptr;
+
+ if( feof( pineFile->file ) ) return NULL;
+
+ ptr = buf;
+ while( TRUE ) {
+ *ptr = '\0';
+ ch = fgetc( pineFile->file );
+ if( ch == '\0' || ch == EOF ) {
+ if( *buf == '\0' ) return NULL;
+ break;
+ }
+ if( ch == '\n' ) {
+ break;
+ }
+ *ptr = ch;
+ ptr++;
+ }
+
+ /* Copy into private buffer */
+ return g_strdup( buf );
+}
+
+/*
+ * Parsed address data.
+ */
+typedef struct _Pine_ParsedRec_ Pine_ParsedRec;
+struct _Pine_ParsedRec_ {
+ gchar *nickName;
+ gchar *name;
+ gchar *address;
+ gchar *fcc;
+ gchar *comments;
+ gboolean isGroup;
+ GSList *listName;
+ GSList *listAddr;
+};
+
+/*
+ * Free data record.
+ * Enter: rec Data record.
+ */
+static pine_free_rec( Pine_ParsedRec *rec ) {
+ if( rec ) {
+ g_free( rec->nickName );
+ g_free( rec->name );
+ g_free( rec->address );
+ g_free( rec->fcc );
+ g_free( rec->comments );
+ mgu_clear_slist( rec->listName );
+ mgu_clear_slist( rec->listAddr );
+ g_slist_free( rec->listName );
+ g_slist_free( rec->listAddr );
+ rec->nickName = NULL;
+ rec->name = NULL;
+ rec->address = NULL;
+ rec->fcc = NULL;
+ rec->comments = NULL;
+ rec->isGroup = FALSE;
+ g_free( rec );
+ }
+}
+
+/*
+ * Print data record.
+ * Enter: rec Data record.
+ * stream File.
+ */
+static void pine_print_rec( Pine_ParsedRec *rec, FILE *stream ) {
+ fprintf( stream, "nick :%s:\n", rec->nickName );
+ fprintf( stream, "name :%s:\n", rec->name );
+ fprintf( stream, "addr :%s:\n", rec->address );
+ fprintf( stream, "fcc :%s:\n", rec->fcc );
+ fprintf( stream, "comm :%s:\n", rec->comments );
+ fprintf( stream, "group:%s:\n", rec->isGroup ? "yes" : "no" );
+}
+
+/*
+ * Clean name.
+ */
+static void pine_clean_name( Pine_ParsedRec *rec ) {
+ gchar *p;
+
+ p = rec->name;
+ if( p == NULL ) return;
+ if( *p == '\0' ) return;
+
+ g_strstrip( rec->name );
+ if( *p == CHAR_APOS || *p == CHAR_QUOTE ) {
+ return;
+ }
+
+ /* If embedded comma present, surround match with quotes */
+ while( *p ) {
+ if( *p == CHAR_COMMA ) {
+ p = g_strdup_printf( "\"%s\"", rec->name );
+ g_free( rec->name );
+ rec->name = p;
+ return;
+ }
+ p++;
+ }
+}
+
+/*
+ * Parse pine address record.
+ * Enter: buf Address record buffer.
+ * Return: Data record.
+ */
+static Pine_ParsedRec *pine_parse_record( gchar *buf ) {
+ Pine_ParsedRec *rec;
+ gchar *p, *f;
+ gint pos, len, i;
+ gchar *tmp[5];
+
+ for( i = 0; i < 5; i++ )
+ tmp[i] = NULL;
+
+ /* Extract tab separated values */
+ rec = NULL;
+ pos = 0;
+ p = f = buf;
+ while( *p ) {
+ if( *p == '\t' ) {
+ len = p - f;
+ if( len > 0 ) {
+ tmp[ pos ] = g_strndup( f, len );
+ f = p;
+ f++;
+ }
+ pos++;
+ }
+ p++;
+ }
+
+ /* Extract last value */
+ len = p - f;
+ if( len > 0 ) {
+ tmp[ pos++ ] = g_strndup( f, len );
+ }
+
+ /* Populate record */
+ if( pos > 0 ) {
+ rec = g_new0( Pine_ParsedRec, 1 );
+ rec->isGroup = FALSE;
+ for( i = 0; i < pos; i++ ) {
+ f = tmp[i];
+ if( f ) {
+ g_strstrip( f );
+ }
+ if( i == 0 ) rec->nickName = f;
+ else if( i == 1 ) rec->name = f;
+ else if( i == 2 ) rec->address = f;
+ else if( i == 3 ) rec->fcc = f;
+ else if( i == 4 ) rec->comments = f;
+ tmp[i] = NULL;
+ }
+
+ if( rec->address != NULL ) {
+ /* Strip leading/trailing parens */
+ p = rec->address;
+ if( *p == '(' ) {
+ len = strlen( p ) - 1;
+ *p = ' ';
+ *(p + len) = ' ';
+ rec->isGroup = TRUE;
+ }
+ }
+ }
+
+ return rec;
+}
+
+/*
+ * 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 *pine_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 */
+ mgu_str_ltc2space( name, '\"', '\"' );
+ mgu_str_ltc2space( name, '\'', '\'' );
+ mgu_str_ltc2space( name, '\"', '\"' );
+ mgu_str_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;
+}
+
+/*
+ * Parse address list.
+ * Enter: pineFile Pine control data.
+ * cache Address cache.
+ * rec Data record.
+ */
+static void pine_parse_address( PineFile *pineFile, AddressCache *cache, Pine_ParsedRec *rec ) {
+ const gchar *buf;
+ gchar addr[ PINEBUFSIZE ];
+ const gchar *bp;
+ const gchar *ep;
+ gchar *atCh;
+ gchar *name;
+ gint len;
+
+ buf = rec->address;
+ while( atCh = strchr( buf, CHAR_AT ) ) {
+ name = pine_parse_name( buf, atCh, &bp, &ep );
+ len = ( size_t ) ( ep - bp );
+ strncpy( addr, bp, len );
+ addr[ len ] = '\0';
+ extract_address( addr );
+
+ if( name == NULL ) name = g_strdup( "" );
+ rec->listName = g_slist_append( rec->listName, name );
+ rec->listAddr = g_slist_append( rec->listAddr, g_strdup( addr ) );
+
+ buf = ep;
+ if( atCh == ep ) {
+ buf++;
+ }
+ }
+}
+
+/*
+ * Insert person and address into address cache.
+ * Enter: pineFile Pine control data.
+ * cache Address cache.
+ * address E-Mail address.
+ * name Name.
+ * remarks Remarks.
+ * Return: E-Mail object, either inserted or found in hash table.
+ */
+static ItemEMail *pine_insert_table(
+ PineFile *pineFile, AddressCache *cache, gchar *address,
+ gchar *name, gchar *remarks )
+{
+ ItemPerson *person;
+ ItemEMail *email;
+ gchar *key;
+
+ /* Test whether address already in hash table */
+ key = g_strdup( address );
+ g_strdown( key );
+ email = g_hash_table_lookup( pineFile->uniqTable, key );
+
+ if( email == NULL ) {
+ /* No - create person */
+ person = addritem_create_item_person();
+ addritem_person_set_common_name( person, name );
+ addrcache_id_person( cache, person );
+ addrcache_add_person( cache, person );
+
+ /* Add email for person */
+ email = addritem_create_item_email();
+ addritem_email_set_address( email, address );
+ addritem_email_set_remarks( email, remarks );
+ addrcache_id_email( cache, email );
+ addrcache_person_add_email( cache, person, email );
+
+ /* Insert entry */
+ g_hash_table_insert( pineFile->uniqTable, key, email );
+ }
+ else {
+ /* Yes - update person with longest name */
+ person = ( ItemPerson * ) ADDRITEM_PARENT(email);
+ if( strlen( name ) > strlen( ADDRITEM_NAME(person) ) ) {
+ addritem_person_set_common_name( person, name );
+ }
+
+ /* Free up */
+ g_free( key );
+ }
+
+ return email;
+}
+
+/*
+ * Parse address line adn build address items.
+ * Enter: pineFile Pine control data.
+ * cache Address cache to load.
+ * line Address record.
+ */
+static void pine_build_items( PineFile *pineFile, AddressCache *cache, gchar *line ) {
+ Pine_ParsedRec *rec;
+ GSList *nodeAddr, *nodeName;
+ ItemGroup *group;
+ ItemEMail *email;
+
+ rec = pine_parse_record( line );
+ if( rec ) {
+ pine_clean_name( rec );
+ pine_parse_address( pineFile, cache, rec );
+ /* pine_print_rec( rec, stdout ); */
+ /* printf( "=========\n" ); */
+
+ if( rec->isGroup ) {
+ /* Create group */
+ group = addritem_create_item_group();
+ addritem_group_set_name( group, rec->nickName );
+ addrcache_id_group( cache, group );
+ addrcache_add_group( cache, group );
+
+ /* Add email to group */
+ nodeName = rec->listName;
+ nodeAddr = rec->listAddr;
+ while( nodeAddr ) {
+ email = pine_insert_table(
+ pineFile, cache, nodeAddr->data,
+ nodeName->data, "" );
+
+ /* Add email to group */
+ addritem_group_add_email( group, email );
+
+ nodeAddr = g_slist_next( nodeAddr );
+ nodeName = g_slist_next( nodeName );
+ }
+ }
+ else {
+ email = pine_insert_table(
+ pineFile, cache, rec->address,
+ rec->name, rec->comments );
+ }
+
+ pine_free_rec( rec );
+ }
+}
+
+/*
+ * Read file data into address cache.
+ * Enter: pineFile Pine control data.
+ * cache Address cache to load.
+ */
+static void pine_read_file( PineFile *pineFile, AddressCache *cache ) {
+ GSList *listValue = NULL;
+ gboolean flagEOF = FALSE, flagProc = FALSE, flagDone = FALSE;
+ gchar *line = NULL, *lineValue = NULL;
+ long posEnd = 0L;
+ long posCur = 0L;
+
+ /* Find EOF for progress indicator */
+ fseek( pineFile->file, 0L, SEEK_END );
+ posEnd = ftell( pineFile->file );
+ fseek( pineFile->file, 0L, SEEK_SET );
+
+ flagProc = FALSE;
+ while( ! flagDone ) {
+ if( flagEOF ) {
+ flagDone = TRUE;
+ flagProc = TRUE;
+ }
+ else {
+ line = pine_read_line( pineFile );
+ }
+
+ posCur = ftell( pineFile->file );
+ if( pineFile->cbProgress ) {
+ /* Call progress indicator */
+ ( pineFile->cbProgress ) ( pineFile, & posEnd, & posCur );
+ }
+
+ /* Add line to list */
+ if( line == NULL ) {
+ flagEOF = TRUE;
+ }
+ else {
+ /* Check for continuation line (1 space only) */
+ if( *line == ' ' ) {
+ g_strchug( line );
+ listValue = g_slist_append(
+ listValue, g_strdup( line ) );
+ flagProc = FALSE;
+ }
+ else {
+ flagProc = TRUE;
+ }
+ }
+
+ if( flagProc ) {
+ if( listValue != NULL ) {
+ /* Process list */
+ lineValue = mgu_list_coalesce( listValue );
+ if( lineValue ) {
+ pine_build_items(
+ pineFile, cache, lineValue );
+ }
+ g_free( lineValue );
+ lineValue = NULL;
+ mgu_free_list( listValue );
+ listValue = NULL;
+ }
+ if( line != NULL ) {
+ /* Append to list */
+ listValue = g_slist_append(
+ listValue, g_strdup( line ) );
+ }
+ }
+
+ g_free( line );
+ line = NULL;
+ }
+
+ /* Release data */
+ mgu_free_list( listValue );
+ listValue = NULL;
+}
+
+/*
+ * ============================================================================================
+ * Read file into list. Main entry point
+ * Enter: pineFile Pine control data.
+ * cache Address cache to load.
+ * Return: Status code.
+ * ============================================================================================
+ */
+gint pine_import_data( PineFile *pineFile, AddressCache *cache ) {
+ g_return_val_if_fail( pineFile != NULL, MGU_BAD_ARGS );
+ g_return_val_if_fail( cache != NULL, MGU_BAD_ARGS );
+
+ pineFile->retVal = MGU_SUCCESS;
+ addrcache_clear( cache );
+ cache->dataRead = FALSE;
+ pine_open_file( pineFile );
+ if( pineFile->retVal == MGU_SUCCESS ) {
+ /* Read data into the cache */
+ pine_read_file( pineFile, cache );
+ pine_close_file( pineFile );
+
+ /* Mark cache */
+ cache->modified = FALSE;
+ cache->dataRead = TRUE;
+ }
+ return pineFile->retVal;
+}
+
+#define WORK_BUFLEN 1024
+
+/*
+ * Attempt to find a Pine addressbook file.
+ * Return: Filename, or home directory if not found, or empty string if
+ * no home. Filename should be g_free() when done.
+ */
+gchar *pine_find_file( void ) {
+ gchar *homedir;
+ gchar str[ WORK_BUFLEN ];
+ gint len;
+ FILE *fp;
+
+ homedir = g_get_home_dir();
+ if( ! homedir ) return g_strdup( "" );
+
+ strcpy( str, homedir );
+ len = strlen( str );
+ if( len > 0 ) {
+ if( str[ len-1 ] != G_DIR_SEPARATOR ) {
+ str[ len ] = G_DIR_SEPARATOR;
+ str[ ++len ] = '\0';
+ }
+ }
+ strcat( str, PINE_HOME_FILE );
+
+ /* Attempt to open */
+ if( ( fp = fopen( str, "rb" ) ) != NULL ) {
+ fclose( fp );
+ }
+ else {
+ /* Truncate filename */
+ str[ len ] = '\0';
+ }
+ return g_strdup( str );
+}
+
+/*
+* End of Source.
+*/
+
--- /dev/null
+/*
+ * 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 necessary to access Pine addressbook files. These are
+ * used by the Pine E-Mail client.
+ */
+
+#ifndef __PINE_H__
+#define __PINE_H__
+
+#include <stdio.h>
+#include <glib.h>
+
+#include "addrcache.h"
+
+/*
+* Typical Pine simple entry:
+*
+* nick-name \t friendly-name \t email-address \t fcc \t comments
+*
+* Or for a distribution list:
+*
+* group-name \t friendly-name \t ( email, email, ... ) \t fcc \t comments
+*
+* The record is may span several lines if longer than about 80 characters.
+* Pine formats subsequent line with exactly 3 spaces to indicate that the
+* line is a continuation.
+*
+* An example:
+*
+* axe \t Axel Rose \t axelrose@aol.com \t \t Guitar player
+* \t Axel Rose \t axelrose@aol.com \t \t Guitarist
+* evilaxis \t \t (bgates@hotmail.com,shoebomber@empire.com) \t \t Axis of Evil
+*
+*/
+
+/* Pine file object */
+typedef struct _PineFile PineFile;
+struct _PineFile {
+ FILE *file;
+ gchar *path;
+ gint retVal;
+ GHashTable *uniqTable;
+ void (*cbProgress)( void *, void *, void * );
+};
+
+/* Function prototypes */
+PineFile *pine_create ( void );
+void pine_set_file ( PineFile* pineFile, const gchar *value );
+void pine_free ( PineFile *pineFile );
+gint pine_import_data ( PineFile *pineFile, AddressCache *cache );
+gchar *pine_find_file ( void );
+
+#endif /* __PINE_H__ */
+