Add a wrapper function to decode base64, returning a null-terminated string.
[claws.git] / src / ldif.c
index 60c277cabe94b53bf13162ed992e80e457ec6c59..3bc227b0c2cd01f9ebdd04f05f30148c0b1df630 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001-2003 Match Grun
+ * Copyright (C) 2001-2012 Match Grun and the Claws Mail team
  *
  * 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
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -13,8 +13,8 @@
  * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
  */
 
 /*
@@ -32,7 +32,6 @@
 #include "addritem.h"
 #include "addrcache.h"
 
-#include "base64.h"
 #include "utils.h"
 
 #define        LDIF_SEP_TAG    ':'
@@ -47,7 +46,6 @@ LdifFile *ldif_create() {
        ldifFile = g_new0( LdifFile, 1 );
        ldifFile->path = NULL;
        ldifFile->file = NULL;
-       ldifFile->bufptr = ldifFile->buffer;
        ldifFile->hashFields = g_hash_table_new( g_str_hash, g_str_equal );
        ldifFile->tempList = NULL;
        ldifFile->dirtyFlag = TRUE;
@@ -64,7 +62,7 @@ LdifFile *ldif_create() {
  * \param value    Value of access flag.
  */
 void ldif_set_file( LdifFile *ldifFile, const gchar *value ) {
-       g_return_if_fail( ldifFile != NULL );
+       cm_return_if_fail( ldifFile != NULL );
 
        if( ldifFile->path ) {
                if( strcmp( ldifFile->path, value ) != 0 )
@@ -84,27 +82,10 @@ void ldif_set_file( LdifFile *ldifFile, const gchar *value ) {
  * \param value    File specification.
  */
 void ldif_set_accessed( LdifFile *ldifFile, const gboolean value ) {
-       g_return_if_fail( ldifFile != NULL );
+       cm_return_if_fail( ldifFile != NULL );
        ldifFile->accessFlag = value;
 }
 
-/**
- * Register a progress indicator callback function.
- *
- * \param ldifFile LDIF import control object.
- * \param func     Function to be called. When called, the function will be
- *                 passed the following arguments:
- *
- * <ul>
- * <li>LdifFile object,</li>
- * <li>File size (long),</li>
- * <li>Current position (long)</li>
- * </ul>
- */
-void ldif_set_callback( LdifFile *ldifFile, void *func ) {
-       ldifFile->cbProgress = func;
-}
-
 /**
  * Create field record object.
  * \return Initialized LDIF field object.
@@ -141,7 +122,7 @@ static void ldif_free_fieldrec( Ldif_FieldRec *rec ) {
  *              named.
  */
 void ldif_field_set_name( Ldif_FieldRec *rec, const gchar *value ) {
-       g_return_if_fail( rec != NULL );
+       cm_return_if_fail( rec != NULL );
 
        if( ! rec->reserved ) {
                rec->userName = mgu_replace_string( rec->userName, value );
@@ -156,7 +137,7 @@ void ldif_field_set_name( Ldif_FieldRec *rec, const gchar *value ) {
  *              fields cannot be unselected.
  */
 void ldif_field_set_selected( Ldif_FieldRec *rec, const gboolean value ) {
-       g_return_if_fail( rec != NULL );
+       cm_return_if_fail( rec != NULL );
 
        if( ! rec->reserved ) {
                rec->selected = value;
@@ -169,7 +150,7 @@ void ldif_field_set_selected( Ldif_FieldRec *rec, const gboolean value ) {
  * \param rec   LDIF field object.
  */
 void ldif_field_toggle( Ldif_FieldRec *rec ) {
-       g_return_if_fail( rec != NULL );
+       cm_return_if_fail( rec != NULL );
 
        if( ! rec->reserved ) {
                rec->selected = !rec->selected;
@@ -185,8 +166,6 @@ void ldif_field_toggle( Ldif_FieldRec *rec ) {
 */
 static gint ldif_hash_free_vis( gpointer key, gpointer value, gpointer data ) {
        ldif_free_fieldrec( ( Ldif_FieldRec * ) value );
-       value = NULL;
-       key = NULL;
        return -1;
 }
 
@@ -195,7 +174,7 @@ static gint ldif_hash_free_vis( gpointer key, gpointer value, gpointer data ) {
  * \param ldifFile LDIF import control object.
  */
 void ldif_free( LdifFile *ldifFile ) {
-       g_return_if_fail( ldifFile != NULL );
+       cm_return_if_fail( ldifFile != NULL );
 
        /* Close file */
        if( ldifFile->file ) fclose( ldifFile->file );
@@ -221,69 +200,28 @@ void ldif_free( LdifFile *ldifFile ) {
        g_free( ldifFile );
 }
 
-/**
- * Display field record.
- * \param rec    LDIF field object.
- * \param stream File output stream.
- */
-void ldif_print_fieldrec( Ldif_FieldRec *rec, FILE *stream ) {
-       fprintf( stream, "\ttag:\t%s", rec->reserved ? "yes" : "no" );
-       fprintf( stream, "\t%s", rec->selected ? "yes" : "no" );
-       fprintf( stream, "\t:%s:\t:%s:\n", rec->userName, rec->tagName );
-}
-
-/**
- * Display field record.
- * \param key   Key.
- * \param value Value (the LDIF field record).
- * \param data  User data (file output stream).
- * 
- */
-static void ldif_print_file_vis( gpointer key, gpointer value, gpointer data ) {
-       Ldif_FieldRec *rec = value;
-       FILE *stream = data;
-       ldif_print_fieldrec( rec, stream );
-}
-
-/**
- * Display object to specified stream.
- * \param ldifFile LDIF import control object.
- * \param stream   File output stream.
- */
-void ldif_print_file( LdifFile *ldifFile, FILE *stream ) {
-       g_return_if_fail( ldifFile != NULL );
-       fprintf( stream, "LDIF File:\n" );
-       fprintf( stream, "file spec: '%s'\n", ldifFile->path );
-       fprintf( stream, "  ret val: %d\n",   ldifFile->retVal );
-       fprintf( stream, "   fields: {\n" );
-       g_hash_table_foreach( ldifFile->hashFields, ldif_print_file_vis, stream );
-       fprintf( stream, "} ---\n" );
-}
-
 /**
  * Open file for read.
  * \param  ldifFile LDIF import control object.
  * \return <i>TRUE</i> if file opened successfully.
  */
 static gint ldif_open_file( LdifFile* ldifFile ) {
-       /* printf( "Opening file\n" ); */
+       /* g_print( "Opening file\n" ); */
        if( ldifFile->path ) {
                ldifFile->file = g_fopen( ldifFile->path, "rb" );
                if( ! ldifFile->file ) {
-                       /* printf( "can't open %s\n", ldifFile->path ); */
+                       /* g_print( "can't open %s\n", ldifFile->path ); */
                        ldifFile->retVal = MGU_OPEN_FILE;
                        return ldifFile->retVal;
                }
        }
        else {
-               /* printf( "file not specified\n" ); */
+               /* g_print( "file not specified\n" ); */
                ldifFile->retVal = MGU_NO_FILE;
                return ldifFile->retVal;
        }
 
        /* Setup a buffer area */
-       ldifFile->buffer[0] = '\0';
-       ldifFile->bufptr = ldifFile->buffer;
        ldifFile->retVal = MGU_SUCCESS;
        return ldifFile->retVal;
 }
@@ -293,7 +231,7 @@ static gint ldif_open_file( LdifFile* ldifFile ) {
  * \param  ldifFile LDIF import control object.
  */
 static void ldif_close_file( LdifFile *ldifFile ) {
-       g_return_if_fail( ldifFile != NULL );
+       cm_return_if_fail( ldifFile != NULL );
        if( ldifFile->file ) fclose( ldifFile->file );
        ldifFile->file = NULL;
 }
@@ -304,15 +242,20 @@ static void ldif_close_file( LdifFile *ldifFile ) {
  * \return ptr to buffer where line starts.
  */
 static gchar *ldif_get_line( LdifFile *ldifFile ) {
-       gchar buf[ LDIFBUFSIZE ];
+       gchar *buf = g_malloc(LDIFBUFSIZE);
        gint ch;
        int i = 0;
+       int cur_alloc = LDIFBUFSIZE;
 
-       if( feof( ldifFile->file ) ) 
+       if( feof( ldifFile->file ) ) {
+               g_free(buf);
                return NULL;
+       }
 
-       while( i < LDIFBUFSIZE-1 ) {
+       while( i < cur_alloc-1 ) {
                ch = fgetc( ldifFile->file );
+               if (ferror( ldifFile->file ))
+                       ldifFile->retVal = MGU_ERROR_READ;
                if( ch == '\0' || ch == EOF ) {
                        if( i == 0 ) return NULL;
                        break;
@@ -326,6 +269,10 @@ static gchar *ldif_get_line( LdifFile *ldifFile ) {
                        break;
                buf[i] = ch;
                i++;
+               if (i == cur_alloc-1 && cur_alloc < LDIFBUFSIZE * 32) {
+                       cur_alloc += LDIFBUFSIZE;
+                       buf = g_realloc(buf, cur_alloc);
+               }
        }
        buf[i] = '\0';
 
@@ -345,7 +292,7 @@ static gchar *ldif_get_tagname( char* line, gboolean *flag64 ) {
        gchar *tag = NULL;
        gchar *lptr = line;
        gchar *sptr = NULL;
-
+       
        while( *lptr++ ) {
                /* Check for language tag */
                if( *lptr == LDIF_LANG_TAG ) {
@@ -366,8 +313,7 @@ static gchar *ldif_get_tagname( char* line, gboolean *flag64 ) {
 
                        tag = g_strndup( line, len+1 );
                        tag[ len ] = '\0';
-                       g_strdown( tag );
-                       return tag;
+                        return tag;
                }
        }
        return tag;
@@ -448,7 +394,7 @@ static void ldif_build_items(
        ItemEMail *email;
 
        nodeAddress = rec->listAddress;
-       if( nodeAddress == NULL ) return;
+//     if( nodeAddress == NULL ) return;
 
        /* Find longest first name in list */
        nodeFirst = rec->listFName;
@@ -577,8 +523,7 @@ static void ldif_add_value(
 {
        gchar *nm, *val;
 
-       nm = g_strdup( tagName );
-       g_strdown( nm );
+       nm = g_utf8_strdown( tagName, -1 );
        if( tagValue ) {
                val = g_strdup( tagValue );
        }
@@ -587,19 +532,19 @@ static void ldif_add_value(
        }
        g_strstrip( val );
 
-       if( g_utf8_collate( nm, LDIF_TAG_COMMONNAME ) == 0 ) {
+       if( g_utf8_collate( nm, g_utf8_strdown( LDIF_TAG_COMMONNAME, -1 ) ) == 0 ) {
                rec->listCName = g_slist_append( rec->listCName, val );
        }
-       else if( g_utf8_collate( nm, LDIF_TAG_FIRSTNAME ) == 0 ) {
+       else if( g_utf8_collate( nm, g_utf8_strdown( LDIF_TAG_FIRSTNAME, -1 ) ) == 0 ) {
                rec->listFName = g_slist_append( rec->listFName, val );
        }
-       else if( g_utf8_collate( nm, LDIF_TAG_LASTNAME ) == 0 ) {
+       else if( g_utf8_collate( nm, g_utf8_strdown( LDIF_TAG_LASTNAME, -1 ) ) == 0 ) {
                rec->listLName = g_slist_append( rec->listLName, val );
        }
-       else if( g_utf8_collate( nm, LDIF_TAG_NICKNAME ) == 0 ) {
+       else if( g_utf8_collate( nm, g_utf8_strdown( LDIF_TAG_NICKNAME, -1 ) ) == 0 ) {
                rec->listNName = g_slist_append( rec->listNName, val );
        }
-       else if( g_utf8_collate( nm, LDIF_TAG_EMAIL ) == 0 ) {
+       else if( g_utf8_collate( nm, g_utf8_strdown( LDIF_TAG_EMAIL, -1 ) ) == 0 ) {
                rec->listAddress = g_slist_append( rec->listAddress, val );
        }
        else {
@@ -643,45 +588,6 @@ static void ldif_clear_rec( Ldif_ParsedRec *rec ) {
        rec->listID = NULL;
 }
 
-#if 0
-/**
- * Print parsed data.
- * \param rec    LDIF field object.
- * \param stream Output stream.
- */
-static void ldif_print_record( Ldif_ParsedRec *rec, FILE *stream ) {
-       GSList *list;
-
-       fprintf( stream, "LDIF Parsed Record:\n" );
-       fprintf( stream, "common name:" );
-       mgu_print_list( rec->listCName, stream );
-       if( ! rec->listCName ) fprintf( stream, "\n" );
-       fprintf( stream, "first name:" );
-       mgu_print_list( rec->listFName, stream );
-       if( ! rec->listFName ) fprintf( stream, "\n" );
-       fprintf( stream, "last name:" );
-       mgu_print_list( rec->listLName, stream );
-       if( ! rec->listLName ) fprintf( stream, "\n" );
-       fprintf( stream, "nick name:" );
-       mgu_print_list( rec->listNName, stream );
-       if( ! rec->listNName ) fprintf( stream, "\n" );
-       fprintf( stream, "address:" );
-       mgu_print_list( rec->listAddress, stream );
-       if( ! rec->listAddress ) fprintf( stream, "\n" );
-       fprintf( stream, "id:" );
-       mgu_print_list( rec->listID, stream );
-       if( ! rec->listID ) fprintf( stream, "\n" );
-
-       list = rec->userAttr;
-       while( list ) {
-               Ldif_UserAttr *attr = list->data;
-               fprintf( stream, "n/v:\t%s:\t:%s:\n", attr->name, attr->value );
-               list = g_slist_next( list );
-       }
-       list = NULL;
-}
-#endif
-
 /**
  * Read file data into address cache.
  * Note that one LDIF record identifies one entity uniquely with the
@@ -701,6 +607,8 @@ static void ldif_read_file( LdifFile *ldifFile, AddressCache *cache ) {
        long posEnd = 0L;
        long posCur = 0L;
        GHashTable *hashField;
+       gchar *out;
+       gsize len;
 
        hashField = ldifFile->hashFields;
        rec = g_new0( Ldif_ParsedRec, 1 );
@@ -734,22 +642,10 @@ static void ldif_read_file( LdifFile *ldifFile, AddressCache *cache ) {
                                /* Save record */
                                fullValue = mgu_list_coalesce( listValue );
                                if (fullValue && last64) {
-                                       gchar *out = g_malloc(strlen(fullValue));
-                                       int len = 0;
-                                       if ((len = base64_decode(out, fullValue,
-                                                       strlen(fullValue))) >= 0) {
-                                               g_free(fullValue);
-                                               fullValue = out;
-                                               fullValue[len] = '\0';
-                                       } else
-                                               g_free(out);
-                               }
-                               /* Base-64 encoded data */
-                               /*
-                               if( last64 ) {
-                                       ldif_dump_b64( fullValue );
+                                       gchar *tmp = g_base64_decode_zero(fullValue, &len);
+                                       g_free(fullValue);
+                                       fullValue = tmp;
                                }
-                               */
 
                                ldif_add_value( rec, lastTag, fullValue, hashField );
                                /* ldif_print_record( rec, stdout ); */
@@ -757,6 +653,7 @@ static void ldif_read_file( LdifFile *ldifFile, AddressCache *cache ) {
                                ldif_clear_rec( rec );
                                g_free( lastTag );
                                mgu_free_list( listValue );
+                               g_free(fullValue);
                                lastTag = NULL;
                                listValue = NULL;
                                last64 = FALSE;
@@ -785,15 +682,9 @@ static void ldif_read_file( LdifFile *ldifFile, AddressCache *cache ) {
                                                        fullValue =
                                                                mgu_list_coalesce( listValue );
                                                        if (fullValue && last64) {
-                                                               gchar *out = g_malloc(strlen(fullValue));
-                                                               int len = 0;
-                                                               if ((len = base64_decode(out, fullValue,
-                                                                               strlen(fullValue))) >= 0) {
-                                                                       g_free(fullValue);
-                                                                       fullValue = out;
-                                                                       fullValue[len] = '\0';
-                                                               } else
-                                                                       g_free(out);
+                                                               gchar *tmp = g_base64_decode_zero(fullValue, &len);
+                                                               g_free(fullValue);
+                                                               fullValue = tmp;
                                                        }
                                                        /* Base-64 encoded data */
                                                        /*
@@ -809,7 +700,6 @@ static void ldif_read_file( LdifFile *ldifFile, AddressCache *cache ) {
                                                        mgu_free_list( listValue );
                                                        lastTag = NULL;
                                                        listValue = NULL;
-                                                       last64 = FALSE;
                                                }
 
                                                lastTag = g_strdup( tagName );
@@ -846,32 +736,32 @@ static void ldif_hash_add_list( GHashTable *table, GSList *list ) {
                gchar *tag = node->data;
                if( ! g_hash_table_lookup( table, tag ) ) {
                        Ldif_FieldRec *rec = NULL;
-                       gchar *key = g_strdup( tag );
+                       gchar *key = g_utf8_strdown( tag, -1 );
 
                        rec = ldif_create_fieldrec( tag );
-                       if( g_utf8_collate( tag, LDIF_TAG_DN ) == 0 ) {
+                       if( g_utf8_collate( key, LDIF_TAG_DN ) == 0 ) {
                                rec->reserved = rec->selected = TRUE;
                                rec->userName = g_strdup( "dn" );
                        }
-                       else if( g_utf8_collate( tag, LDIF_TAG_COMMONNAME ) == 0 ) {
+                       else if( g_utf8_collate( key, g_utf8_strdown( LDIF_TAG_COMMONNAME, -1 ) ) == 0 ) {
                                rec->reserved = rec->selected = TRUE;
                                rec->userName = g_strdup( _( "Display Name" ) );
                        }
-                       else if( g_utf8_collate( tag, LDIF_TAG_FIRSTNAME ) == 0 ) {
+                       else if( g_utf8_collate( key, g_utf8_strdown( LDIF_TAG_FIRSTNAME, -1 ) ) == 0 ) {
                                rec->reserved = rec->selected = TRUE;
                                rec->userName = g_strdup( _( "First Name" ) );
                        }
-                       else if( g_utf8_collate( tag, LDIF_TAG_LASTNAME ) == 0 ) {
+                       else if( g_utf8_collate( key, g_utf8_strdown( LDIF_TAG_LASTNAME, -1 ) ) == 0 ) {
                                rec->reserved = rec->selected = TRUE;
                                rec->userName = g_strdup( _( "Last Name" ) );
                        }
-                       else if( g_utf8_collate( tag, LDIF_TAG_NICKNAME ) == 0 ) {
+                       else if( g_utf8_collate( key, g_utf8_strdown( LDIF_TAG_NICKNAME, -1 ) ) == 0 ) {
                                rec->reserved = rec->selected = TRUE;
                                rec->userName = g_strdup( _( "Nick Name" ) );
                        }
-                       else if( g_utf8_collate( tag, LDIF_TAG_EMAIL ) == 0 ) {
+                       else if( g_utf8_collate( key, g_utf8_strdown( LDIF_TAG_EMAIL, -1 ) ) == 0 ) {
                                rec->reserved = rec->selected = TRUE;
-                               rec->userName = g_strdup( _( "E-Mail Address" ) );
+                               rec->userName = g_strdup( _( "Email Address" ) );
                        }
                        g_hash_table_insert( table, key, rec );
                }
@@ -936,6 +826,11 @@ static void ldif_read_tag_list( LdifFile *ldifFile ) {
        posEnd = ftell( ldifFile->file );
        fseek( ldifFile->file, 0L, SEEK_SET );
 
+       if (posEnd == 0) {
+               ldifFile->retVal = MGU_EOF;
+               return;
+       }
+               
        /* Process file */
        while( ! flagEOF ) {
                gchar *line = ldif_get_line( ldifFile );
@@ -984,6 +879,12 @@ static void ldif_read_tag_list( LdifFile *ldifFile ) {
                                        {
                                                flagMail = TRUE;
                                        }
+                               } else {
+                                       g_strstrip(line);
+                                       if (*line != '\0') {
+                                               debug_print("ldif: bad format: '%s'\n", line);
+                                               ldifFile->retVal = MGU_BAD_FORMAT;
+                                       }
                                }
                        }
                }
@@ -1002,7 +903,7 @@ static void ldif_read_tag_list( LdifFile *ldifFile ) {
  * \return Status code.
  */
 gint ldif_import_data( LdifFile *ldifFile, AddressCache *cache ) {
-       g_return_val_if_fail( ldifFile != NULL, MGU_BAD_ARGS );
+       cm_return_val_if_fail( ldifFile != NULL, MGU_BAD_ARGS );
        ldifFile->retVal = MGU_SUCCESS;
        addrcache_clear( cache );
        cache->dataRead = FALSE;
@@ -1026,7 +927,7 @@ gint ldif_import_data( LdifFile *ldifFile, AddressCache *cache ) {
  * \return Status code.
  */
 gint ldif_read_tags( LdifFile *ldifFile ) {
-       g_return_val_if_fail( ldifFile != NULL, MGU_BAD_ARGS );
+       cm_return_val_if_fail( ldifFile != NULL, MGU_BAD_ARGS );
        ldifFile->retVal = MGU_SUCCESS;
        if( ldifFile->dirtyFlag ) {
                ldif_open_file( ldifFile );
@@ -1052,7 +953,7 @@ gint ldif_read_tags( LdifFile *ldifFile ) {
 GList *ldif_get_fieldlist( LdifFile *ldifFile ) {
        GList *list = NULL;
 
-       g_return_val_if_fail( ldifFile != NULL, NULL );
+       cm_return_val_if_fail( ldifFile != NULL, NULL );
        if( ldifFile->hashFields ) {
                ldifFile->tempList = NULL;
                g_hash_table_foreach( ldifFile->hashFields, ldif_hash2list_vis, ldifFile );