Python 2 EOL: migrate eud2gc.py to Python 3
[claws.git] / src / ldif.c
1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2001-2015 Match Grun and the Claws Mail team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
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.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 /*
20  * Functions necessary to access LDIF files (LDAP Data Interchange Format
21  * files).
22  */
23
24 #include <glib.h>
25 #include <glib/gi18n.h>
26 #include <string.h>
27 #include <sys/stat.h>
28
29 #include "mgutils.h"
30 #include "ldif.h"
31 #include "addritem.h"
32 #include "addrcache.h"
33
34 #include "utils.h"
35 #include "file-utils.h"
36
37 #define LDIF_SEP_TAG    ':'
38 #define LDIF_LANG_TAG   ';'
39
40 /**
41  * Create new object.
42  * \return Initialized LDIF file object.
43  */
44 LdifFile *ldif_create() {
45         LdifFile *ldifFile;
46         ldifFile = g_new0( LdifFile, 1 );
47         ldifFile->path = NULL;
48         ldifFile->file = NULL;
49         ldifFile->hashFields = g_hash_table_new( g_str_hash, g_str_equal );
50         ldifFile->tempList = NULL;
51         ldifFile->dirtyFlag = TRUE;
52         ldifFile->accessFlag = FALSE;
53         ldifFile->retVal = MGU_SUCCESS;
54         ldifFile->cbProgress = NULL;
55         ldifFile->importCount = 0;
56         return ldifFile;
57 }
58
59 /**
60  * Specify full file specification of LDIF file.
61  * \param ldifFile LDIF import control object.
62  * \param value    Value of access flag.
63  */
64 void ldif_set_file( LdifFile *ldifFile, const gchar *value ) {
65         cm_return_if_fail( ldifFile != NULL );
66
67         if( ldifFile->path ) {
68                 if( strcmp( ldifFile->path, value ) != 0 )
69                         ldifFile->dirtyFlag = TRUE;
70         }
71         else {
72                 ldifFile->dirtyFlag = TRUE;
73         }
74         ldifFile->path = mgu_replace_string( ldifFile->path, value );
75         g_strstrip( ldifFile->path );
76         ldifFile->importCount = 0;
77 }
78
79 /**
80  * Set the file access indicator.
81  * \param ldifFile LDIF import control object.
82  * \param value    File specification.
83  */
84 void ldif_set_accessed( LdifFile *ldifFile, const gboolean value ) {
85         cm_return_if_fail( ldifFile != NULL );
86         ldifFile->accessFlag = value;
87 }
88
89 /**
90  * Create field record object.
91  * \return Initialized LDIF field object.
92  */
93 static Ldif_FieldRec *ldif_create_fieldrec( const gchar *field ) {
94         Ldif_FieldRec *rec = g_new0( Ldif_FieldRec, 1 );
95         rec->tagName = g_strdup( field );
96         rec->userName = NULL;
97         rec->reserved = FALSE;
98         rec->selected = FALSE;
99         return rec;
100 }
101
102 /**
103  * Free field record object.
104  * \param rec LDIF field object.
105  */
106 static void ldif_free_fieldrec( Ldif_FieldRec *rec ) {
107         if( rec ) {
108                 g_free( rec->tagName );
109                 g_free( rec->userName );
110                 rec->tagName = NULL;
111                 rec->userName = NULL;
112                 rec->reserved = FALSE;
113                 rec->selected = FALSE;
114                 g_free( rec );
115         }
116 }
117
118 /**
119  * Set user name for field record.
120  * \param rec   LDIF field object.
121  * \param value User name to set. Note that reserved fields cannot be
122  *              named.
123  */
124 void ldif_field_set_name( Ldif_FieldRec *rec, const gchar *value ) {
125         cm_return_if_fail( rec != NULL );
126
127         if( ! rec->reserved ) {
128                 rec->userName = mgu_replace_string( rec->userName, value );
129                 g_strstrip( rec->userName );
130         }
131 }
132
133 /**
134  * Specify selection for field record.
135  * \param rec   LDIF field object.
136  * \param value Set to <i>TRUE</i> to select field. Note that reserved
137  *              fields cannot be unselected.
138  */
139 void ldif_field_set_selected( Ldif_FieldRec *rec, const gboolean value ) {
140         cm_return_if_fail( rec != NULL );
141
142         if( ! rec->reserved ) {
143                 rec->selected = value;
144         }
145 }
146
147 /**
148  * Toggle selection for field record. Note that reserved fields cannot be
149  * toggled.
150  * \param rec   LDIF field object.
151  */
152 void ldif_field_toggle( Ldif_FieldRec *rec ) {
153         cm_return_if_fail( rec != NULL );
154
155         if( ! rec->reserved ) {
156                 rec->selected = !rec->selected;
157         }
158 }
159
160 /**
161  * Free hash table entry visitor function.
162  * \param  key   Key.
163  * \param  value Value (the LDIF field record).
164  * \param  data  User data.
165  * \return <code>-1</code>.
166 */
167 static gint ldif_hash_free_vis( gpointer key, gpointer value, gpointer data ) {
168         ldif_free_fieldrec( ( Ldif_FieldRec * ) value );
169         return -1;
170 }
171
172 /**
173  * Free up object by releasing internal memory.
174  * \param ldifFile LDIF import control object.
175  */
176 void ldif_free( LdifFile *ldifFile ) {
177         cm_return_if_fail( ldifFile != NULL );
178
179         /* Close file */
180         if( ldifFile->file ) claws_fclose( ldifFile->file );
181
182         /* Free internal stuff */
183         g_free( ldifFile->path );
184
185         /* Free field list */
186         g_hash_table_foreach_remove( ldifFile->hashFields, ldif_hash_free_vis, NULL );
187         g_hash_table_destroy( ldifFile->hashFields );
188         ldifFile->hashFields = NULL;
189
190         /* Clear pointers */
191         ldifFile->file = NULL;
192         ldifFile->path = NULL;
193         ldifFile->retVal = MGU_SUCCESS;
194         ldifFile->tempList = NULL;
195         ldifFile->dirtyFlag = FALSE;
196         ldifFile->accessFlag = FALSE;
197         ldifFile->cbProgress = NULL;
198
199         /* Now release file object */
200         g_free( ldifFile );
201 }
202
203 /**
204  * Open file for read.
205  * \param  ldifFile LDIF import control object.
206  * \return <i>TRUE</i> if file opened successfully.
207  */
208 static gint ldif_open_file( LdifFile* ldifFile ) {
209         /* g_print( "Opening file\n" ); */
210         if( ldifFile->path ) {
211                 ldifFile->file = claws_fopen( ldifFile->path, "rb" );
212                 if( ! ldifFile->file ) {
213                         /* g_print( "can't open %s\n", ldifFile->path ); */
214                         ldifFile->retVal = MGU_OPEN_FILE;
215                         return ldifFile->retVal;
216                 }
217         }
218         else {
219                 /* g_print( "file not specified\n" ); */
220                 ldifFile->retVal = MGU_NO_FILE;
221                 return ldifFile->retVal;
222         }
223
224         /* Setup a buffer area */
225         ldifFile->retVal = MGU_SUCCESS;
226         return ldifFile->retVal;
227 }
228
229 /**
230  * Close file.
231  * \param  ldifFile LDIF import control object.
232  */
233 static void ldif_close_file( LdifFile *ldifFile ) {
234         cm_return_if_fail( ldifFile != NULL );
235         if( ldifFile->file ) claws_fclose( ldifFile->file );
236         ldifFile->file = NULL;
237 }
238
239 /**
240  * Read line of text from file.
241  * \param  ldifFile LDIF import control object.
242  * \return ptr to buffer where line starts.
243  */
244 static gchar *ldif_get_line( LdifFile *ldifFile ) {
245         gchar *buf = g_malloc(LDIFBUFSIZE);
246         gint ch;
247         int i = 0;
248         int cur_alloc = LDIFBUFSIZE;
249
250         if( claws_feof( ldifFile->file ) ) {
251                 g_free(buf);
252                 return NULL;
253         }
254
255         while( i < cur_alloc-1 ) {
256                 ch = fgetc( ldifFile->file );
257                 if (claws_ferror( ldifFile->file ))
258                         ldifFile->retVal = MGU_ERROR_READ;
259                 if( ch == '\0' || ch == EOF ) {
260                         if( i == 0 ) return NULL;
261                         break;
262                 }
263 #if HAVE_DOSISH_SYSTEM
264 #else
265                 if( ch == '\r' ) 
266                         continue;
267 #endif
268                 if( ch == '\n' ) 
269                         break;
270                 buf[i] = ch;
271                 i++;
272                 if (i == cur_alloc-1 && cur_alloc < LDIFBUFSIZE * 32) {
273                         cur_alloc += LDIFBUFSIZE;
274                         buf = g_realloc(buf, cur_alloc);
275                 }
276         }
277         buf[i] = '\0';
278
279         /* Return a copy of buffer */
280         return g_strdup( buf );
281 }
282
283 /**
284  * Parse tag name from line buffer.
285  * \param  line Buffer.
286  * \param  flag64 Base-64 encoder flag.
287  * \return Buffer containing the tag name, or NULL if no delimiter char found.
288  *         If a double delimiter (::) is found, flag64 is set.
289  */
290 static gchar *ldif_get_tagname( char* line, gboolean *flag64 ) {
291         gint len = 0;
292         gchar *tag = NULL;
293         gchar *lptr = line;
294         gchar *sptr = NULL;
295         
296         while( *lptr++ ) {
297                 /* Check for language tag */
298                 if( *lptr == LDIF_LANG_TAG ) {
299                         if( sptr == NULL ) sptr = lptr;
300                 }
301
302                 /* Check for delimiter */
303                 if( *lptr == LDIF_SEP_TAG ) {
304                         if( sptr ) {
305                                 len = sptr - line;
306                         }
307                         else {
308                                 len = lptr - line;
309                         }
310
311                         /* Base-64 encoding? */
312                         if( * ++lptr == LDIF_SEP_TAG ) *flag64 = TRUE;
313
314                         tag = g_strndup( line, len+1 );
315                         tag[ len ] = '\0';
316                         return tag;
317                 }
318         }
319         return tag;
320 }
321
322 /**
323  * Parse tag value from line buffer.
324  * \param  line Buffer.
325  * \return Buffer containing the tag value. Empty string is returned if
326  *         no delimiter char found.
327  */
328 static gchar *ldif_get_tagvalue( gchar* line ) {
329         gchar *value = NULL;
330         gchar *start = NULL;
331         gchar *lptr;
332         gint len = 0;
333
334         for( lptr = line; *lptr; lptr++ ) {
335                 if( *lptr == LDIF_SEP_TAG ) {
336                         if( ! start )
337                                 start = lptr + 1;
338                 }
339         }
340         if( start ) {
341                 if( *start == LDIF_SEP_TAG ) start++;
342                 len = lptr - start;
343                 value = g_strndup( start, len+1 );
344                 g_strstrip( value );
345         }
346         else {
347                 /* Ensure that we get an empty string */
348                 value = g_strndup( "", 1 );
349         }
350         value[ len ] = '\0';
351         return value;
352 }
353
354 /**
355  * Parsed address data record.
356  */
357 typedef struct _Ldif_ParsedRec_ Ldif_ParsedRec;
358 struct _Ldif_ParsedRec_ {
359         GSList *listCName;
360         GSList *listFName;
361         GSList *listLName;
362         GSList *listNName;
363         GSList *listAddress;
364         GSList *listID;
365         GSList *userAttr;
366 };
367
368 /**
369  * User attribute data record.
370  */
371 typedef struct _Ldif_UserAttr_ Ldif_UserAttr;
372 struct _Ldif_UserAttr_ {
373         gchar *name;
374         gchar *value;
375 };
376
377 /**
378  * Build an address list entry and append to list of address items in the
379  * address cache. Name is formatted as "<first-name> <last-name>".
380  * \param ldifFile LDIF import control object.
381  * \param rec      LDIF field object.
382  * \param cache    Address cache to be populated with data.
383  */
384 static void ldif_build_items(
385                 LdifFile *ldifFile, Ldif_ParsedRec *rec, AddressCache *cache )
386 {
387         GSList *nodeFirst;
388         GSList *nodeAddress;
389         GSList *nodeAttr;
390         gchar *firstName = NULL, *lastName = NULL, *fullName = NULL;
391         gchar *nickName = NULL;
392         gint iLen = 0, iLenT = 0;
393         ItemPerson *person;
394         ItemEMail *email;
395
396         nodeAddress = rec->listAddress;
397 //      if( nodeAddress == NULL ) return;
398
399         /* Find longest first name in list */
400         nodeFirst = rec->listFName;
401         while( nodeFirst ) {
402                 if( firstName == NULL ) {
403                         firstName = nodeFirst->data;
404                         iLen = strlen( firstName );
405                 }
406                 else {
407                         if( ( iLenT = strlen( nodeFirst->data ) ) > iLen ) {
408                                 firstName = nodeFirst->data;
409                                 iLen = iLenT;
410                         }
411                 }
412                 nodeFirst = g_slist_next( nodeFirst );
413         }
414
415         /* Format name */
416         if( rec->listLName ) {
417                 lastName = rec->listLName->data;
418         }
419
420         if( firstName ) {
421                 if( lastName ) {
422                         fullName = g_strdup_printf(
423                                 "%s %s", firstName, lastName );
424                 }
425                 else {
426                         fullName = g_strdup_printf( "%s", firstName );
427                 }
428         }
429         else {
430                 if( lastName ) {
431                         fullName = g_strdup_printf( "%s", lastName );
432                 }
433         }
434         
435         if (!fullName || strlen(fullName) == 0) {
436                 g_free(fullName);
437                 fullName = NULL;
438                 if (rec->listCName)
439                         fullName = g_strdup(rec->listCName->data);
440         }
441         
442         if( fullName ) {
443                 g_strstrip( fullName );
444         }
445
446         if( rec->listNName ) {
447                 nickName = rec->listNName->data;
448         }
449
450         person = addritem_create_item_person();
451         addritem_person_set_common_name( person, fullName );
452         addritem_person_set_first_name( person, firstName );
453         addritem_person_set_last_name( person, lastName );
454         addritem_person_set_nick_name( person, nickName );
455         addrcache_id_person( cache, person );
456         addrcache_add_person( cache, person );
457         ++ldifFile->importCount;
458
459         /* Add address item */
460         while( nodeAddress ) {
461                 email = addritem_create_item_email();
462                 addritem_email_set_address( email, nodeAddress->data );
463                 addrcache_id_email( cache, email );
464                 addrcache_person_add_email( cache, person, email );
465                 nodeAddress = g_slist_next( nodeAddress );
466         }
467         g_free( fullName );
468         fullName = firstName = lastName = NULL;
469
470         /* Add user attributes */
471         nodeAttr = rec->userAttr;
472         while( nodeAttr ) {
473                 Ldif_UserAttr *attr = nodeAttr->data;
474                 UserAttribute *attrib = addritem_create_attribute();
475                 addritem_attrib_set_name( attrib, attr->name );
476                 addritem_attrib_set_value( attrib, attr->value );
477                 addritem_person_add_attribute( person, attrib );
478                 nodeAttr = g_slist_next( nodeAttr );
479         }
480         nodeAttr = NULL;
481 }
482
483 /**
484  * Add selected field as user attribute.
485  * \param rec       LDIF field object.
486  * \param tagName   LDIF tag name.
487  * \param tagValue  Data value.
488  * \param hashField Hash table to populate.
489  */
490 static void ldif_add_user_attr(
491                 Ldif_ParsedRec *rec, gchar *tagName, gchar *tagValue,
492                 GHashTable *hashField )
493 {
494         Ldif_FieldRec *fld = NULL;
495         Ldif_UserAttr *attr = NULL;
496         gchar *name;
497
498         fld = g_hash_table_lookup( hashField, tagName );
499         if( fld ) {
500                 if( ! fld->selected ) return;
501
502                 name = fld->tagName;
503                 if( fld->userName ) {
504                         name = fld->userName;
505                 }
506                 attr = g_new0( Ldif_UserAttr, 1 );
507                 attr->name = g_strdup( name );
508                 attr->value = g_strdup( tagValue );
509                 rec->userAttr = g_slist_append( rec->userAttr, attr );
510         }
511 }
512
513 /**
514  * Add value to parsed data.
515  * \param rec       LDIF field object.
516  * \param tagName   LDIF tag name.
517  * \param tagValue  Data value.
518  * \param hashField Hash table to populate.
519  */
520 static void ldif_add_value(
521                Ldif_ParsedRec *rec, gchar *tagName, gchar *tagValue,
522                GHashTable *hashField )
523 {
524         gchar *nm, *val;
525
526         nm = g_utf8_strdown( tagName, -1 );
527         if( tagValue ) {
528                 val = g_strdup( tagValue );
529         }
530         else {
531                 val = g_strdup( "" );
532         }
533         g_strstrip( val );
534
535         if( g_utf8_collate( nm, g_utf8_strdown( LDIF_TAG_COMMONNAME, -1 ) ) == 0 ) {
536                 rec->listCName = g_slist_append( rec->listCName, val );
537         }
538         else if( g_utf8_collate( nm, g_utf8_strdown( LDIF_TAG_FIRSTNAME, -1 ) ) == 0 ) {
539                 rec->listFName = g_slist_append( rec->listFName, val );
540         }
541         else if( g_utf8_collate( nm, g_utf8_strdown( LDIF_TAG_LASTNAME, -1 ) ) == 0 ) {
542                 rec->listLName = g_slist_append( rec->listLName, val );
543         }
544         else if( g_utf8_collate( nm, g_utf8_strdown( LDIF_TAG_NICKNAME, -1 ) ) == 0 ) {
545                 rec->listNName = g_slist_append( rec->listNName, val );
546         }
547         else if( g_utf8_collate( nm, g_utf8_strdown( LDIF_TAG_EMAIL, -1 ) ) == 0 ) {
548                 rec->listAddress = g_slist_append( rec->listAddress, val );
549         }
550         else {
551                 /* Add field as user attribute */
552                 ldif_add_user_attr( rec, tagName, tagValue, hashField );
553         }
554         g_free( nm );
555 }
556
557 /**
558  * Clear parsed data record.
559  * \param rec LDIF field object.
560  */
561 static void ldif_clear_rec( Ldif_ParsedRec *rec ) {
562         GSList *list;
563
564         /* Free up user attributes */
565         list = rec->userAttr;
566         while( list ) {
567                 Ldif_UserAttr *attr = list->data;
568                 g_free( attr->name );
569                 g_free( attr->value );
570                 g_free( attr );
571                 list = g_slist_next( list );
572         }
573         g_slist_free( rec->userAttr );
574
575         g_slist_free( rec->listCName );
576         g_slist_free( rec->listFName );
577         g_slist_free( rec->listLName );
578         g_slist_free( rec->listNName );
579         g_slist_free( rec->listAddress );
580         g_slist_free( rec->listID );
581
582         rec->userAttr = NULL;
583         rec->listCName = NULL;
584         rec->listFName = NULL;
585         rec->listLName = NULL;
586         rec->listNName = NULL;
587         rec->listAddress = NULL;
588         rec->listID = NULL;
589 }
590
591 /**
592  * Read file data into address cache.
593  * Note that one LDIF record identifies one entity uniquely with the
594  * distinguished name (dn) tag. Each person can have multiple E-Mail
595  * addresses. Also, each person can have many common name (cn) tags.
596  *
597  * \param  ldifFile LDIF import control object.
598  * \param  cache    Address cache to be populated with data.
599  */
600 static void ldif_read_file( LdifFile *ldifFile, AddressCache *cache ) {
601         gchar *tagName = NULL, *tagValue = NULL;
602         gchar *lastTag = NULL, *fullValue = NULL;
603         GSList *listValue = NULL;
604         gboolean flagEOF = FALSE, flagEOR = FALSE;
605         gboolean flag64 = FALSE, last64 = FALSE;
606         Ldif_ParsedRec *rec;
607         long posEnd = 0L;
608         long posCur = 0L;
609         GHashTable *hashField;
610         gsize len;
611
612         hashField = ldifFile->hashFields;
613         rec = g_new0( Ldif_ParsedRec, 1 );
614         ldif_clear_rec( rec );
615
616         /* Find EOF for progress indicator */
617         fseek( ldifFile->file, 0L, SEEK_END );
618         posEnd = ftell( ldifFile->file );
619         fseek( ldifFile->file, 0L, SEEK_SET );
620
621         while( ! flagEOF ) {
622                 gchar *line =  ldif_get_line( ldifFile );
623
624                 posCur = ftell( ldifFile->file );
625                 if( ldifFile->cbProgress ) {
626                         /* Call progress indicator */
627                         ( ldifFile->cbProgress ) ( ldifFile, & posEnd, & posCur );
628                 }
629
630                 flag64 = FALSE;
631                 if( line == NULL ) {
632                         flagEOF = flagEOR = TRUE;
633                 }
634                 else if( *line == '\0' ) {
635                         flagEOR = TRUE;
636                 }
637
638                 if( flagEOR ) {
639                         /* EOR, Output address data */
640                         if( lastTag ) {
641                                 /* Save record */
642                                 fullValue = mgu_list_coalesce( listValue );
643                                 if (fullValue && last64) {
644                                         gchar *tmp = g_base64_decode_zero(fullValue, &len);
645                                         g_free(fullValue);
646                                         fullValue = tmp;
647                                 }
648
649                                 ldif_add_value( rec, lastTag, fullValue, hashField );
650                                 /* ldif_print_record( rec, stdout ); */
651                                 ldif_build_items( ldifFile, rec, cache );
652                                 ldif_clear_rec( rec );
653                                 g_free( lastTag );
654                                 g_slist_free_full( listValue, g_free );
655                                 g_free(fullValue);
656                                 lastTag = NULL;
657                                 listValue = NULL;
658                                 last64 = FALSE;
659                         }
660                 }
661                 if( line ) {
662                         flagEOR = FALSE;
663                         if( *line == ' ' ) {
664                                 /* Continuation line */
665                                 listValue = g_slist_append(
666                                         listValue, g_strdup( line+1 ) );
667                         }
668                         else if( *line == '=' ) {
669                                 /* Base-64 encoded continuation field */
670                                 listValue = g_slist_append(
671                                         listValue, g_strdup( line ) );
672                         }
673                         else {
674                                 /* Parse line */
675                                 tagName = ldif_get_tagname( line, &flag64 );
676                                 if( tagName ) {
677                                         tagValue = ldif_get_tagvalue( line );
678                                         if( tagValue ) {
679                                                 if( lastTag ) {
680                                                         /* Save data */
681                                                         fullValue =
682                                                                 mgu_list_coalesce( listValue );
683                                                         if (fullValue && last64) {
684                                                                 gchar *tmp = g_base64_decode_zero(fullValue, &len);
685                                                                 g_free(fullValue);
686                                                                 fullValue = tmp;
687                                                         }
688                                                         /* Base-64 encoded data */
689                                                         /*
690                                                         if( last64 ) {
691                                                                 ldif_dump_b64( fullValue );
692                                                         }
693                                                         */
694
695                                                         ldif_add_value(
696                                                                 rec, lastTag, fullValue,
697                                                                 hashField );
698                                                         g_free( lastTag );
699                                                         g_slist_free_full( listValue, g_free );
700                                                         lastTag = NULL;
701                                                         listValue = NULL;
702                                                 }
703
704                                                 lastTag = g_strdup( tagName );
705                                                 listValue = g_slist_append(
706                                                         listValue,
707                                                         g_strdup( tagValue ) );
708                                                 g_free( tagValue );
709                                                 last64 = flag64;
710                                         }
711                                         g_free( tagName );
712                                 }
713                         }
714                 }
715                 g_free( line );
716         }
717
718         /* Release data */
719         ldif_clear_rec( rec );
720         g_free( rec );
721         g_free( lastTag );
722         g_slist_free_full( listValue, g_free );
723 }
724
725 /**
726  * Add list of field names to hash table.
727  * \param table Hashtable.
728  * \param list  List of fields.
729  */
730 static void ldif_hash_add_list( GHashTable *table, GSList *list ) {
731         GSList *node = list;
732
733         /* mgu_print_list( list, stdout ); */
734         while( node ) {
735                 gchar *tag = node->data;
736                 if( ! g_hash_table_lookup( table, tag ) ) {
737                         Ldif_FieldRec *rec = NULL;
738                         gchar *key = g_utf8_strdown( tag, -1 );
739
740                         rec = ldif_create_fieldrec( tag );
741                         if( g_utf8_collate( key, LDIF_TAG_DN ) == 0 ) {
742                                 rec->reserved = rec->selected = TRUE;
743                                 rec->userName = g_strdup( "dn" );
744                         }
745                         else if( g_utf8_collate( key, g_utf8_strdown( LDIF_TAG_COMMONNAME, -1 ) ) == 0 ) {
746                                 rec->reserved = rec->selected = TRUE;
747                                 rec->userName = g_strdup( _( "Display Name" ) );
748                         }
749                         else if( g_utf8_collate( key, g_utf8_strdown( LDIF_TAG_FIRSTNAME, -1 ) ) == 0 ) {
750                                 rec->reserved = rec->selected = TRUE;
751                                 rec->userName = g_strdup( _( "First Name" ) );
752                         }
753                         else if( g_utf8_collate( key, g_utf8_strdown( LDIF_TAG_LASTNAME, -1 ) ) == 0 ) {
754                                 rec->reserved = rec->selected = TRUE;
755                                 rec->userName = g_strdup( _( "Last Name" ) );
756                         }
757                         else if( g_utf8_collate( key, g_utf8_strdown( LDIF_TAG_NICKNAME, -1 ) ) == 0 ) {
758                                 rec->reserved = rec->selected = TRUE;
759                                 rec->userName = g_strdup( _( "Nick Name" ) );
760                         }
761                         else if( g_utf8_collate( key, g_utf8_strdown( LDIF_TAG_EMAIL, -1 ) ) == 0 ) {
762                                 rec->reserved = rec->selected = TRUE;
763                                 rec->userName = g_strdup( _( "Email Address" ) );
764                         }
765                         g_hash_table_insert( table, key, rec );
766                 }
767                 node = g_slist_next( node );
768         }
769 }
770
771 /**
772  * Sorted list comparison function.
773  * \param  ptr1 First field.
774  * \param  ptr2 Second field.
775  * \return <code>-1, 0, +1</code> if first record less than, equal,
776  *         greater than second.
777  */
778 static gint ldif_field_compare( gconstpointer ptr1, gconstpointer ptr2 ) {
779         const Ldif_FieldRec *rec1 = ptr1;
780         const Ldif_FieldRec *rec2 = ptr2;
781
782         if( rec1->reserved ) {
783                 if( ! rec2->reserved ) {
784                         return +1;
785                 }
786         }
787         else {
788                 if( rec2->reserved ) {
789                         return -1;
790                 }
791         }
792         return g_utf8_collate( rec1->tagName, rec2->tagName );
793 }
794
795 /*
796  * Append hash table entry to list - visitor function.
797  * \param key   Key.
798  * \param value Data value.
799  * \param data  User data (the LDIF import control object).
800  */
801 static void ldif_hash2list_vis( gpointer key, gpointer value, gpointer data ) {
802         LdifFile *ldf = data;
803         ldf->tempList =
804                 g_list_insert_sorted( ldf->tempList, value, ldif_field_compare );
805 }
806
807 /**
808  * Read tag names for file data.
809  * \param  ldifFile LDIF import control object.
810  */
811 static void ldif_read_tag_list( LdifFile *ldifFile ) {
812         gchar *tagName = NULL;
813         GSList *listTags = NULL;
814         gboolean flagEOF = FALSE, flagEOR = FALSE, flagMail = FALSE;
815         gboolean flag64 = FALSE;
816         long posEnd = 0L;
817         long posCur = 0L;
818
819         /* Clear hash table */
820         g_hash_table_foreach_remove(
821                 ldifFile->hashFields, ldif_hash_free_vis, NULL );
822
823         /* Find EOF for progress indicator */
824         fseek( ldifFile->file, 0L, SEEK_END );
825         posEnd = ftell( ldifFile->file );
826         fseek( ldifFile->file, 0L, SEEK_SET );
827
828         if (posEnd == 0) {
829                 ldifFile->retVal = MGU_EOF;
830                 return;
831         }
832                 
833         /* Process file */
834         while( ! flagEOF ) {
835                 gchar *line = ldif_get_line( ldifFile );
836                 posCur = ftell( ldifFile->file );
837                 if( ldifFile->cbProgress ) {
838                         /* Call progress indicator */
839                         ( ldifFile->cbProgress ) ( ldifFile, & posEnd, & posCur );
840                 }
841
842                 flag64 = FALSE;
843                 if( line == NULL ) {
844                         flagEOF = flagEOR = TRUE;
845                 }
846                 else if( *line == '\0' ) {
847                         flagEOR = TRUE;
848                 }
849
850                 if( flagEOR ) {
851                         /* EOR, Output address data */
852                         /* Save field list to hash table */
853                         if( flagMail ) {
854                                 ldif_hash_add_list(
855                                         ldifFile->hashFields, listTags );
856                         }
857                         g_slist_free_full( listTags, g_free );
858                         listTags = NULL;
859                         flagMail = FALSE;
860                 }
861                 if( line ) {
862                         flagEOR = FALSE;
863                         if( *line == ' ' ) {
864                                 /* Continuation line */
865                         }
866                         else if( *line == '=' ) {
867                                 /* Base-64 encoded continuation field */
868                         }
869                         else {
870                                 /* Parse line */
871                                 tagName = ldif_get_tagname( line, &flag64 );
872                                 if( tagName ) {
873                                         /* Add tag to list */
874                                         listTags = g_slist_append( listTags, tagName );
875
876                                         if( g_utf8_collate(
877                                                 tagName, LDIF_TAG_EMAIL ) == 0 )
878                                         {
879                                                 flagMail = TRUE;
880                                         }
881                                 } else {
882                                         g_strstrip(line);
883                                         if (*line != '\0') {
884                                                 debug_print("ldif: bad format: '%s'\n", line);
885                                                 ldifFile->retVal = MGU_BAD_FORMAT;
886                                         }
887                                 }
888                         }
889                 }
890                 g_free( line );
891         }
892
893         /* Release data */
894         g_slist_free_full( listTags, g_free );
895         listTags = NULL;
896 }
897
898 /**
899  * Read file into list. Main entry point
900  * \param  ldifFile LDIF import control object.
901  * \param  cache    Address cache to load.
902  * \return Status code.
903  */
904 gint ldif_import_data( LdifFile *ldifFile, AddressCache *cache ) {
905         cm_return_val_if_fail( ldifFile != NULL, MGU_BAD_ARGS );
906         ldifFile->retVal = MGU_SUCCESS;
907         addrcache_clear( cache );
908         cache->dataRead = FALSE;
909         ldif_open_file( ldifFile );
910         if( ldifFile->retVal == MGU_SUCCESS ) {
911                 /* Read data into the cache */
912                 ldif_read_file( ldifFile, cache );
913                 ldif_close_file( ldifFile );
914
915                 /* Mark cache */
916                 cache->modified = FALSE;
917                 cache->dataRead = TRUE;
918         }
919         return ldifFile->retVal;
920 }
921
922 /**
923  * Process entire file reading list of unique fields. List of fields may be
924  * accessed with the <code>ldif_get_fieldlist()</code> function.
925  * \param  ldifFile LDIF import control object.
926  * \return Status code.
927  */
928 gint ldif_read_tags( LdifFile *ldifFile ) {
929         cm_return_val_if_fail( ldifFile != NULL, MGU_BAD_ARGS );
930         ldifFile->retVal = MGU_SUCCESS;
931         if( ldifFile->dirtyFlag ) {
932                 ldif_open_file( ldifFile );
933                 if( ldifFile->retVal == MGU_SUCCESS ) {
934                         /* Read data into the cache */
935                         ldif_read_tag_list( ldifFile );
936                         ldif_close_file( ldifFile );
937                         ldifFile->dirtyFlag = FALSE;
938                         ldifFile->accessFlag = TRUE;
939                 }
940         }
941         return ldifFile->retVal;
942 }
943
944 /**
945  * Return list of fields for LDIF file.
946  * \param  ldifFile LDIF import control object.
947  * \return Linked list of <code>Ldif_FieldRec</code> objects. This list may be
948  *         <code>g_free()</code>. Note that the objects in the list should not
949  *         be freed since they refer to objects inside the internal cache.
950  *         These objects will be freed when LDIF file object is freed.
951  */
952 GList *ldif_get_fieldlist( LdifFile *ldifFile ) {
953         GList *list = NULL;
954
955         cm_return_val_if_fail( ldifFile != NULL, NULL );
956         if( ldifFile->hashFields ) {
957                 ldifFile->tempList = NULL;
958                 g_hash_table_foreach( ldifFile->hashFields, ldif_hash2list_vis, ldifFile );
959                 list = ldifFile->tempList;
960                 ldifFile->tempList = NULL;
961         }
962         return list;
963 }
964
965 /**
966  * Output LDIF name-value pair to stream. Only non-empty names and values will
967  * be output to file.
968  * \param stream File output stream.
969  * \param name   Name.
970  * \param value  Data value.
971  * \return <i>TRUE</i> if data output.
972  */
973 gboolean ldif_write_value( FILE *stream, const gchar *name, const gchar *value ) {
974         if( name == NULL ) return FALSE;
975         if( value == NULL ) return FALSE;
976         if( strlen( name ) < 1 ) return FALSE;
977         if( strlen( value ) < 1 ) return FALSE;
978         fprintf( stream, "%s: ", name );
979         fprintf( stream, "%s\n", value );
980         return TRUE;
981 }
982
983 /**
984  * Output LDIF End of Record to stream.
985  * \param stream File output stream.
986  * \return <i>TRUE</i> if data output.
987  */
988 void ldif_write_eor( FILE *stream ) {
989         /* Simple but caller should not need to know how to end record. */
990         fprintf( stream, "\n" );
991 }
992
993 /*
994  * ============================================================================
995  * End of Source.
996  * ============================================================================
997  */
998