2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001 Match Grun
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 2 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, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * Functions necessary to access MUTT address book file.
32 #include "addrcache.h"
34 #define MUTT_HOME_FILE ".muttrc"
35 #define MUTTBUFSIZE 2048
36 #define MUTT_TAG_ALIAS "alias"
41 MuttFile *mutt_create() {
43 muttFile = g_new0( MuttFile, 1 );
44 muttFile->path = NULL;
45 muttFile->file = NULL;
46 muttFile->retVal = MGU_SUCCESS;
47 muttFile->uniqTable = g_hash_table_new( g_str_hash, g_str_equal );
48 muttFile->cbProgress = NULL;
55 void mutt_set_file( MuttFile* muttFile, const gchar *value ) {
56 g_return_if_fail( muttFile != NULL );
57 muttFile->path = mgu_replace_string( muttFile->path, value );
58 g_strstrip( muttFile->path );
62 * Register a callback function. When called, the function will be passed
63 * the following arguments:
66 * Current position (long)
67 * This can be used for a progress indicator.
69 void mutt_set_callback( MuttFile *muttFile, void *func ) {
70 muttFile->cbProgress = func;
76 static gint mutt_free_table_vis( gpointer key, gpointer value, gpointer data ) {
84 * Free up object by releasing internal memory.
86 void mutt_free( MuttFile *muttFile ) {
87 g_return_if_fail( muttFile != NULL );
90 if( muttFile->file ) fclose( muttFile->file );
92 /* Free internal stuff */
93 g_free( muttFile->path );
95 /* Free unique address table */
96 g_hash_table_freeze( muttFile->uniqTable );
97 g_hash_table_foreach_remove( muttFile->uniqTable, mutt_free_table_vis, NULL );
98 g_hash_table_thaw( muttFile->uniqTable );
99 g_hash_table_destroy( muttFile->uniqTable );
102 muttFile->file = NULL;
103 muttFile->path = NULL;
104 muttFile->retVal = MGU_SUCCESS;
105 muttFile->uniqTable = NULL;
106 muttFile->cbProgress = NULL;
108 /* Now release file object */
113 * Display object to specified stream.
115 void mutt_print_file( MuttFile *muttFile, FILE *stream ) {
116 g_return_if_fail( muttFile != NULL );
117 fprintf( stream, "MUTT File:\n" );
118 fprintf( stream, "file spec: '%s'\n", muttFile->path );
119 fprintf( stream, " ret val: %d\n", muttFile->retVal );
123 * Open file for read.
124 * return: TRUE if file opened successfully.
126 static gint mutt_open_file( MuttFile* muttFile ) {
127 if( muttFile->path ) {
128 muttFile->file = fopen( muttFile->path, "rb" );
129 if( ! muttFile->file ) {
130 muttFile->retVal = MGU_OPEN_FILE;
131 return muttFile->retVal;
135 /* printf( "file not specified\n" ); */
136 muttFile->retVal = MGU_NO_FILE;
137 return muttFile->retVal;
140 /* Setup a buffer area */
141 muttFile->retVal = MGU_SUCCESS;
142 return muttFile->retVal;
148 static void mutt_close_file( MuttFile *muttFile ) {
149 g_return_if_fail( muttFile != NULL );
150 if( muttFile->file ) fclose( muttFile->file );
151 muttFile->file = NULL;
155 * Read line of text from file.
156 * Enter: muttFile File object.
157 * flagCont Continuation flag, set if back-slash character at EOL.
158 * Return: ptr to buffer where line starts.
160 static gchar *mutt_get_line( MuttFile *muttFile, gboolean *flagCont ) {
161 gchar buf[ MUTTBUFSIZE ];
166 if( feof( muttFile->file ) ) return NULL;
173 ch = fgetc( muttFile->file );
174 if( ch == '\0' || ch == EOF ) {
175 if( *buf == '\0' ) return NULL;
180 /* Replace backslash with NULL */
181 if( lptr ) *lptr = '\0';
192 /* Copy into private buffer */
193 return g_strdup( buf );
197 * Parsed address data.
199 typedef struct _Mutt_ParsedRec_ Mutt_ParsedRec;
200 struct _Mutt_ParsedRec_ {
207 * Enter: rec Data record.
209 static void mutt_free_rec( Mutt_ParsedRec *rec ) {
211 g_free( rec->address );
221 * Enter: rec Data record.
223 */void mutt_print_rec( Mutt_ParsedRec *rec, FILE *stream ) {
224 fprintf( stream, "\taddr: %s\tname: %s\n", rec->address, rec->name );
228 * Parse recipient list for each address.
229 * Enter: rcpList Recipients extracted from file.
230 * addrCount Updated with recipient count.
231 * Return: Linked list of recipients.
233 static GSList *mutt_parse_rcplist( gchar *rcpList, gint *addrCount ) {
234 gchar *ptr, *pStart, *pEnd, *pAddr, *pName, *address, *name;
245 address = name = NULL;
246 pName = pAddr = NULL;
249 if( ! isspace( *ptr ) ) break;
265 if( isspace( ch ) ) {
272 /* Extract address */
274 address = g_strndup( pStart, pAddr - pStart );
277 address = g_strdup( pStart );
279 g_strstrip( address );
293 if( isspace( ch ) ) continue;
297 /* Extract name (if any) */
299 /* Look for closing parens */
311 name = g_strndup( pName, pEnd - pName );
316 name = g_strdup( pName );
322 name = g_strdup( "" );
326 rec = g_new0( Mutt_ParsedRec, 1 );
327 rec->address = address;
329 list = g_slist_append( list, rec );
332 /* mutt_print_rec( rec, stdout ); */
339 * Insert person and address into address cache.
340 * Enter: muttFile MUTT control data.
341 * cache Address cache.
342 * address E-Mail address.
344 * Return: E-Mail object, either inserted or found in hash table.
346 static ItemEMail *mutt_insert_table(
347 MuttFile *muttFile, AddressCache *cache, gchar *address,
354 /* Test whether address already in hash table */
355 key = g_strdup( address );
357 email = g_hash_table_lookup( muttFile->uniqTable, key );
359 if( email == NULL ) {
360 /* No - create person */
361 person = addritem_create_item_person();
362 addritem_person_set_common_name( person, name );
363 addrcache_id_person( cache, person );
364 addrcache_add_person( cache, person );
366 /* Add email for person */
367 email = addritem_create_item_email();
368 addritem_email_set_address( email, address );
369 addrcache_id_email( cache, email );
370 addrcache_person_add_email( cache, person, email );
373 g_hash_table_insert( muttFile->uniqTable, key, email );
376 /* Yes - update person with longest name */
377 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
378 if( strlen( name ) > strlen( ADDRITEM_NAME(person) ) ) {
379 addritem_person_set_common_name( person, name );
390 * Build address book entries.
391 * Enter: muttFile MUTT control data.
392 * cache Address cache.
394 * listAddr List of address items.
395 * addrCount Address list count.
397 static void mutt_build_address(
398 MuttFile *muttFile, AddressCache *cache,
399 gchar *aliasName, GSList *listAddr, gint addrCount )
407 if( listAddr != NULL && addrCount > 1 ) {
408 group = addritem_create_item_group();
409 addritem_group_set_name( group, aliasName );
410 addrcache_id_group( cache, group );
411 addrcache_add_group( cache, group );
419 /* Insert person/email */
420 email = mutt_insert_table(
421 muttFile, cache, rec->address, rec->name );
423 /* Add email to group */
425 addritem_group_add_email( group, email );
428 mutt_free_rec( rec );
429 node = g_slist_next( node );
434 * Parse address line adn build address items.
435 * Enter: muttFile MUTT control data.
436 * cache Address cache.
439 static void mutt_build_items( MuttFile *muttFile, AddressCache *cache, gchar *line ) {
442 gchar *aliasTag, *aliasName, *recipient;
445 /* printf( "\nBUILD >%s<\n", line ); */
446 list = mgu_parse_string( line, 3, &tCount );
449 mgu_free_dlist( list );
455 aliasTag = list->data;
456 node = g_list_next( list );
457 aliasName = node->data;
458 node = g_list_next( node );
459 recipient = node->data;
462 if( strcmp( aliasTag, MUTT_TAG_ALIAS ) == 0 ) {
464 /* printf( "aliasName :%s:\n", aliasName ); */
465 /* printf( "recipient :%s:\n", recipient ); */
466 addrList = mutt_parse_rcplist( recipient, &aCount );
467 /* printf( "---\n" ); */
468 mutt_build_address( muttFile, cache, aliasName, addrList, aCount );
471 mgu_free_dlist( list );
477 * Read file data into address cache.
478 * Enter: muttFile MUTT control data.
479 * cache Address cache.
481 static void mutt_read_file( MuttFile *muttFile, AddressCache *cache ) {
482 GSList *listValue = NULL;
483 gboolean flagEOF = FALSE, flagCont = FALSE, lastCont = FALSE;
484 gchar *line = NULL, *lineValue = NULL;
488 /* Find EOF for progress indicator */
489 fseek( muttFile->file, 0L, SEEK_END );
490 posEnd = ftell( muttFile->file );
491 fseek( muttFile->file, 0L, SEEK_SET );
495 line = mutt_get_line( muttFile, &flagCont );
497 posCur = ftell( muttFile->file );
498 if( muttFile->cbProgress ) {
499 /* Call progress indicator */
500 ( muttFile->cbProgress ) ( muttFile, & posEnd, & posCur );
503 if( line == NULL ) flagEOF = TRUE;
506 lineValue = mgu_list_coalesce( listValue );
508 mutt_build_items( muttFile, cache, lineValue );
512 mgu_free_list( listValue );
517 /* Add line to list */
518 listValue = g_slist_append( listValue, g_strdup( line ) );
525 mgu_free_list( listValue );
530 * ============================================================================================
531 * Read file into list. Main entry point
532 * Enter: muttFile MUTT control data.
533 * cache Address cache to load.
534 * Return: Status code.
535 * ============================================================================================
537 gint mutt_import_data( MuttFile *muttFile, AddressCache *cache ) {
538 g_return_val_if_fail( muttFile != NULL, MGU_BAD_ARGS );
539 g_return_val_if_fail( cache != NULL, MGU_BAD_ARGS );
540 muttFile->retVal = MGU_SUCCESS;
541 addrcache_clear( cache );
542 cache->dataRead = FALSE;
543 mutt_open_file( muttFile );
544 if( muttFile->retVal == MGU_SUCCESS ) {
545 /* Read data into the cache */
546 mutt_read_file( muttFile, cache );
547 mutt_close_file( muttFile );
550 cache->modified = FALSE;
551 cache->dataRead = TRUE;
553 return muttFile->retVal;
556 #define WORK_BUFLEN 1024
559 * Attempt to find a Mutt file.
560 * Return: Filename, or home directory if not found, or empty string if
561 * no home. Filename should be g_free() when done.
563 gchar *mutt_find_file( void ) {
564 const gchar *homedir;
565 gchar str[ WORK_BUFLEN ];
569 homedir = g_get_home_dir();
570 if( ! homedir ) return g_strdup( "" );
572 strcpy( str, homedir );
575 if( str[ len-1 ] != G_DIR_SEPARATOR ) {
576 str[ len ] = G_DIR_SEPARATOR;
580 strcat( str, MUTT_HOME_FILE );
582 /* Attempt to open */
583 if( ( fp = fopen( str, "rb" ) ) != NULL ) {
587 /* Truncate filename */
590 return g_strdup( str );