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