2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2006 Match Grun and the Sylpheed-Claws team
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * Export address book to LDIF file.
33 #include <glib/gi18n.h>
37 #include "exportldif.h"
42 #ifdef MKDIR_TAKES_ONE_ARG
44 #define mkdir(a,b) mkdir(a)
47 #define DFL_DIR_SYLPHEED_OUT "sylpheed-out"
48 #define DFL_FILE_SYLPHEED_OUT "addressbook.ldif"
50 #define FMT_BUFSIZE 2048
51 #define XML_BUFSIZE 2048
53 /* Settings - properties */
54 #define EXML_PROPFILE_NAME "exportldif.xml"
55 #define EXMLPROP_DIRECTORY "directory"
56 #define EXMLPROP_FILE "file"
57 #define EXMLPROP_SUFFIX "suffix"
58 #define EXMLPROP_RDN_INDEX "rdn"
59 #define EXMLPROP_USE_DN "use-dn"
60 #define EXMLPROP_EXCL_EMAIL "exclude-mail"
62 static gchar *_attrName_UID_ = "uid";
63 static gchar *_attrName_DName_ = "cn";
64 static gchar *_attrName_EMail_ = "mail";
67 * Create initialized LDIF export control object.
68 * \return Initialized export control data.
70 ExportLdifCtl *exportldif_create( void ) {
71 ExportLdifCtl *ctl = g_new0( ExportLdifCtl, 1 );
74 ctl->dirOutput = NULL;
77 ctl->rdnIndex = EXPORT_LDIF_ID_UID;
79 ctl->excludeEMail = TRUE;
80 ctl->retVal = MGU_SUCCESS;
82 ctl->settingsFile = g_strconcat(
83 get_rc_dir(), G_DIR_SEPARATOR_S, EXML_PROPFILE_NAME, NULL );
89 * Free up object by releasing internal memory.
90 * \return ctl Export control data.
92 void exportldif_free( ExportLdifCtl *ctl ) {
93 g_return_if_fail( ctl != NULL );
96 g_free( ctl->fileLdif );
97 g_free( ctl->dirOutput );
98 g_free( ctl->suffix );
99 g_free( ctl->settingsFile );
103 ctl->dirOutput = NULL;
104 ctl->fileLdif = NULL;
106 ctl->rdnIndex = EXPORT_LDIF_ID_UID;
108 ctl->excludeEMail = FALSE;
109 ctl->retVal = MGU_SUCCESS;
112 /* Now release object */
117 * Print control object.
118 * \param ctl Export control data.
119 * \param stream Output stream.
121 void exportldif_print( ExportLdifCtl *ctl, FILE *stream ) {
122 fprintf( stream, "ExportLdifCtl:\n" );
123 fprintf( stream, " path: %s\n", ctl->path );
124 fprintf( stream, "directory: %s\n", ctl->dirOutput );
125 fprintf( stream, " file: %s\n", ctl->fileLdif );
126 fprintf( stream, " suffix: %s\n", ctl->suffix );
127 fprintf( stream, " rdn: %d\n", ctl->rdnIndex );
128 fprintf( stream, " use DN: %s\n", ctl->useDN ? "y" : "n" );
129 fprintf( stream, " ex EMail: %s\n", ctl->excludeEMail ? "y" : "n" );
130 fprintf( stream, " settings: %s\n", ctl->settingsFile );
134 * Specify directory where LDIF files are created.
135 * \param ctl Export control data.
136 * \param value Full directory path.
138 void exportldif_set_output_dir( ExportLdifCtl *ctl, const gchar *value ) {
139 g_return_if_fail( ctl != NULL );
140 ctl->dirOutput = mgu_replace_string( ctl->dirOutput, value );
141 g_strstrip( ctl->dirOutput );
145 * Specify full file specification of LDIF file.
146 * \param ctl Export control data.
147 * \param value Full file specification.
149 void exportldif_set_path( ExportLdifCtl *ctl, const gchar *value ) {
150 g_return_if_fail( ctl != NULL );
151 ctl->path = mgu_replace_string( ctl->path, value );
152 g_strstrip( ctl->path );
156 * Specify file name of LDIF file.
157 * \param ctl Export control data.
158 * \param value File name.
160 void exportldif_set_file_ldif( ExportLdifCtl *ctl, const gchar *value ) {
161 g_return_if_fail( ctl != NULL );
162 ctl->fileLdif = mgu_replace_string( ctl->fileLdif, value );
163 g_strstrip( ctl->fileLdif );
167 * Specify suffix to be used for creating DN entries.
168 * \param ctl Export control data.
169 * \param value Suffix.
171 void exportldif_set_suffix( ExportLdifCtl *ctl, const char *value ) {
172 g_return_if_fail( ctl != NULL );
173 ctl->suffix = mgu_replace_string( ctl->suffix, value );
174 g_strstrip( ctl->suffix );
178 * Specify index of variable to be used for creating RDN entries.
179 * \param ctl Export control data.
180 * \param value Index to variable, as follows:
182 * <li><code>EXPORT_LDIF_ID_UID</code> - Use Sylpheed UID.</li>
183 * <li><code>EXPORT_LDIF_ID_DNAME</code> - Use Sylpheed display name.</li>
184 * <li><code>EXPORT_LDIF_ID_EMAIL</code> - Use first Email address.</li>
187 void exportldif_set_rdn( ExportLdifCtl *ctl, const gint value ) {
188 g_return_if_fail( ctl != NULL );
189 ctl->rdnIndex = value;
193 * Specify that <code>DN</code> attribute, if present, should be used as the
195 * \param ctl Export control data.
196 * \param value <i>TRUE</i> if DN should be used.
198 void exportldif_set_use_dn( ExportLdifCtl *ctl, const gboolean value ) {
199 g_return_if_fail( ctl != NULL );
204 * Specify that records without E-Mail addresses should be excluded.
205 * \param ctl Export control data.
206 * \param value <i>TRUE</i> if records without E-Mail should be excluded.
208 void exportldif_set_exclude_email( ExportLdifCtl *ctl, const gboolean value ) {
209 g_return_if_fail( ctl != NULL );
210 ctl->excludeEMail = value;
214 * Format LDAP value name with no embedded commas.
215 * \param value Data value to format.
216 * \return Formatted string, should be freed after use.
218 static gchar *exportldif_fmt_value( gchar *value ) {
224 /* Duplicate incoming value */
225 dest = dupval = g_strdup( value );
227 /* Copy characters, ignoring commas */
242 * Build DN for entry.
243 * \param ctl Export control data.
244 * \param person Person to format.
245 * \return Formatted DN entry.
247 static gchar *exportldif_fmt_dn(
248 ExportLdifCtl *ctl, const ItemPerson *person )
250 gchar buf[ FMT_BUFSIZE ];
251 gchar *retVal = NULL;
254 gchar *dupval = NULL;
258 if( ctl->rdnIndex == EXPORT_LDIF_ID_UID ) {
259 attr = _attrName_UID_;
260 value = ADDRITEM_ID( person );
262 else if( ctl->rdnIndex == EXPORT_LDIF_ID_DNAME ) {
263 attr = _attrName_DName_;
264 value = ADDRITEM_NAME( person );
265 dupval = exportldif_fmt_value( value );
267 else if( ctl->rdnIndex == EXPORT_LDIF_ID_EMAIL ) {
270 node = person->listEMail;
272 ItemEMail *email = node->data;
274 attr = _attrName_EMail_;
275 value = email->address;
276 dupval = exportldif_fmt_value( value );
283 if( strlen( value ) > 0 ) {
287 /* Format and free duplicated value */
288 strcat( buf, dupval );
292 /* Use original value */
293 strcat( buf, value );
298 if( strlen( ctl->suffix ) > 0 ) {
300 strcat( buf, ctl->suffix );
304 retVal = g_strdup( buf );
312 * Find DN by searching attribute list.
313 * \param ctl Export control data.
314 * \param person Person to format.
315 * \return Formatted DN entry, should be freed after use.
317 static gchar *exportldif_find_dn(
318 ExportLdifCtl *ctl, const ItemPerson *person )
320 gchar *retVal = NULL;
323 node = person->listAttrib;
325 UserAttribute *attrib = node->data;
327 node = g_list_next( node );
328 if( g_utf8_collate( attrib->name, LDIF_TAG_DN ) == 0 ) {
329 retVal = g_strdup( attrib->value );
337 * Format E-Mail entries for person.
338 * \param person Person to format.
339 * \param stream Output stream.
340 * \return <i>TRUE</i> if entry formatted.
342 static gboolean exportldif_fmt_email( const ItemPerson *person, FILE *stream ) {
343 gboolean retVal = FALSE;
346 node = person->listEMail;
348 ItemEMail *email = node->data;
350 node = g_list_next( node );
351 ldif_write_value( stream, LDIF_TAG_EMAIL, email->address );
358 * Test for E-Mail entries for person.
359 * \param person Person to test.
360 * \return <i>TRUE</i> if person has E-Mail address.
362 static gboolean exportldif_test_email( const ItemPerson *person )
364 gboolean retVal = FALSE;
367 node = person->listEMail;
369 ItemEMail *email = node->data;
371 node = g_list_next( node );
372 if( email->address ) {
373 if( strlen( email->address ) > 0 ) {
384 * Format persons in an address book folder.
385 * \param ctl Export control data.
386 * \param stream Output stream.
387 * \param folder Folder to format.
388 * \return <i>TRUE</i> if no persons were formatted.
390 static gboolean exportldif_fmt_person(
391 ExportLdifCtl *ctl, FILE *stream, const ItemFolder *folder )
393 gboolean retVal = TRUE;
396 if( folder->listPerson == NULL ) return retVal;
398 node = folder->listPerson;
400 AddrItemObject *aio = node->data;
401 node = g_list_next( node );
403 if( aio && aio->type == ITEMTYPE_PERSON ) {
404 ItemPerson *person = ( ItemPerson * ) aio;
405 gboolean classPerson = FALSE;
406 gboolean classInetP = FALSE;
409 /* Check for E-Mail */
410 if( exportldif_test_email( person ) ) {
414 /* Bail if no E-Mail address */
415 if( ctl->excludeEMail ) continue;
420 dn = exportldif_find_dn( ctl, person );
423 dn = exportldif_fmt_dn( ctl, person );
425 if( dn == NULL ) continue;
426 ldif_write_value( stream, LDIF_TAG_DN, dn );
430 * Test for schema requirements. This is a simple
431 * test and does not trap all LDAP schema errors.
432 * These can be detected when the LDIF file is
433 * loaded into an LDAP server.
435 if( person->lastName ) {
436 if( strlen( person->lastName ) > 0 ) {
443 ldif_write_value( stream,
444 LDIF_TAG_OBJECTCLASS, LDIF_CLASS_PERSON );
447 ldif_write_value( stream,
448 LDIF_TAG_OBJECTCLASS, LDIF_CLASS_INET_PERSON );
451 /* Format person attributes */
453 stream, LDIF_TAG_COMMONNAME, ADDRITEM_NAME( person ) );
455 stream, LDIF_TAG_LASTNAME, person->lastName );
457 stream, LDIF_TAG_FIRSTNAME, person->firstName );
459 stream, LDIF_TAG_NICKNAME, person->nickName );
462 exportldif_fmt_email( person, stream );
465 ldif_write_eor( stream );
475 * Format an address book folder.
476 * \param ctl Export control data.
477 * \param stream Output stream.
478 * \param folder Folder to format.
479 * \return <i>TRUE</i> if no persons were formatted.
481 static void exportldif_fmt_folder(
482 ExportLdifCtl *ctl, FILE *stream, const ItemFolder *folder )
486 /* Export entries in this folder */
487 exportldif_fmt_person( ctl, stream, folder );
489 /* Export entries in sub-folders */
490 node = folder->listFolder;
492 AddrItemObject *aio = node->data;
494 node = g_list_next( node );
495 if( aio && aio->type == ITEMTYPE_FOLDER ) {
496 ItemFolder *subFolder = ( ItemFolder * ) aio;
497 exportldif_fmt_folder( ctl, stream, subFolder );
503 * Export address book to LDIF file.
504 * \param ctl Export control data.
505 * \param cache Address book/data source cache.
508 void exportldif_process( ExportLdifCtl *ctl, AddressCache *cache )
510 ItemFolder *rootFolder;
513 ldifFile = g_fopen( ctl->path, "wb" );
515 /* Cannot open file */
516 ctl->retVal = MGU_OPEN_FILE;
520 rootFolder = cache->rootFolder;
521 exportldif_fmt_folder( ctl, ldifFile, rootFolder );
523 ctl->retVal = MGU_SUCCESS;
527 * Build full export file specification.
528 * \param ctl Export control data.
530 static void exportldif_build_filespec( ExportLdifCtl *ctl ) {
533 fileSpec = g_strconcat(
534 ctl->dirOutput, G_DIR_SEPARATOR_S, ctl->fileLdif, NULL );
535 ctl->path = mgu_replace_string( ctl->path, fileSpec );
540 * Parse directory and filename from full export file specification.
541 * \param ctl Export control data.
542 * \param fileSpec File spec.
544 void exportldif_parse_filespec( ExportLdifCtl *ctl, gchar *fileSpec ) {
546 gchar *base = g_path_get_basename(fileSpec);
549 mgu_replace_string( ctl->fileLdif, base );
551 t = g_path_get_dirname( fileSpec );
552 ctl->dirOutput = mgu_replace_string( ctl->dirOutput, t );
554 ctl->path = mgu_replace_string( ctl->path, fileSpec );
558 * Test whether output directory exists.
559 * \param ctl Export control data.
560 * \return TRUE if exists.
562 gboolean exportldif_test_dir( ExportLdifCtl *ctl ) {
567 if((dp = opendir( ctl->dirOutput )) != NULL) {
575 * Create output directory.
576 * \param ctl Export control data.
577 * \return TRUE if directory created.
579 gboolean exportldif_create_dir( ExportLdifCtl *ctl ) {
580 gboolean retVal = FALSE;
583 if( mkdir( ctl->dirOutput, S_IRWXU ) == 0 ) {
587 ctl->rcCreate = errno;
593 * Retrieve create directory error message.
594 * \param ctl Export control data.
597 gchar *exportldif_get_create_msg( ExportLdifCtl *ctl ) {
600 if( ctl->rcCreate == EEXIST ) {
601 msg = _( "Name already exists but is not a directory." );
603 else if( ctl->rcCreate == EACCES ) {
604 msg = _( "No permissions to create directory." );
606 else if( ctl->rcCreate == ENAMETOOLONG ) {
607 msg = _( "Name is too long." );
610 msg = _( "Not specified." );
616 * Set default values.
617 * \param ctl Export control data.
619 static void exportldif_default_values( ExportLdifCtl *ctl ) {
623 g_get_home_dir(), G_DIR_SEPARATOR_S,
624 DFL_DIR_SYLPHEED_OUT, NULL );
626 ctl->dirOutput = mgu_replace_string( ctl->dirOutput, str );
630 mgu_replace_string( ctl->fileLdif, DFL_FILE_SYLPHEED_OUT );
631 ctl->suffix = mgu_replace_string( ctl->suffix, "" );
633 ctl->rdnIndex = EXPORT_LDIF_ID_UID;
635 ctl->retVal = MGU_SUCCESS;
639 * Load settings from XML properties file.
640 * \param ctl Export control data.
642 void exportldif_load_settings( ExportLdifCtl *ctl ) {
645 gchar buf[ XML_BUFSIZE ];
647 props = xmlprops_create();
648 xmlprops_set_path( props, ctl->settingsFile );
649 rc = xmlprops_load_file( props );
653 xmlprops_get_property_s( props, EXMLPROP_DIRECTORY, buf );
654 ctl->dirOutput = mgu_replace_string( ctl->dirOutput, buf );
657 xmlprops_get_property_s( props, EXMLPROP_FILE, buf );
658 ctl->fileLdif = mgu_replace_string( ctl->fileLdif, buf );
661 xmlprops_get_property_s( props, EXMLPROP_SUFFIX, buf );
662 ctl->suffix = mgu_replace_string( ctl->suffix, buf );
665 xmlprops_get_property_i( props, EXMLPROP_RDN_INDEX );
667 xmlprops_get_property_b( props, EXMLPROP_USE_DN );
669 xmlprops_get_property_b( props, EXMLPROP_EXCL_EMAIL );
672 /* Set default values */
673 exportldif_default_values( ctl );
675 exportldif_build_filespec( ctl );
676 /* exportldif_print( ctl, stdout ); */
678 xmlprops_free( props );
682 * Save settings to XML properties file.
683 * \param ctl Export control data.
685 void exportldif_save_settings( ExportLdifCtl *ctl ) {
688 props = xmlprops_create();
689 xmlprops_set_path( props, ctl->settingsFile );
691 xmlprops_set_property( props, EXMLPROP_DIRECTORY, ctl->dirOutput );
692 xmlprops_set_property( props, EXMLPROP_FILE, ctl->fileLdif );
693 xmlprops_set_property( props, EXMLPROP_SUFFIX, ctl->suffix );
694 xmlprops_set_property_i( props, EXMLPROP_RDN_INDEX, ctl->rdnIndex );
695 xmlprops_set_property_b( props, EXMLPROP_USE_DN, ctl->useDN );
696 xmlprops_set_property_b( props, EXMLPROP_EXCL_EMAIL, ctl->excludeEMail );
697 xmlprops_save_file( props );
698 xmlprops_free( props );
702 * ============================================================================
704 * ============================================================================