2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2003 Match Grun
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * Export address book to LDIF file.
30 #include <glib/gi18n.h>
34 #include "exportldif.h"
38 #define DFL_DIR_SYLPHEED_OUT "sylpheed-out"
39 #define DFL_FILE_SYLPHEED_OUT "addressbook.ldif"
41 #define FMT_BUFSIZE 2048
42 #define XML_BUFSIZE 2048
44 /* Settings - properties */
45 #define EXML_PROPFILE_NAME "exportldif.xml"
46 #define EXMLPROP_DIRECTORY "directory"
47 #define EXMLPROP_FILE "file"
48 #define EXMLPROP_SUFFIX "suffix"
49 #define EXMLPROP_RDN_INDEX "rdn"
50 #define EXMLPROP_USE_DN "use-dn"
51 #define EXMLPROP_EXCL_EMAIL "exclude-mail"
53 static gchar *_attrName_UID_ = "uid";
54 static gchar *_attrName_DName_ = "cn";
55 static gchar *_attrName_EMail_ = "mail";
58 * Create initialized LDIF export control object.
59 * \return Initialized export control data.
61 ExportLdifCtl *exportldif_create( void ) {
62 ExportLdifCtl *ctl = g_new0( ExportLdifCtl, 1 );
65 ctl->dirOutput = NULL;
68 ctl->rdnIndex = EXPORT_LDIF_ID_UID;
70 ctl->excludeEMail = TRUE;
71 ctl->retVal = MGU_SUCCESS;
73 ctl->settingsFile = g_strconcat(
74 get_rc_dir(), G_DIR_SEPARATOR_S, EXML_PROPFILE_NAME, NULL );
80 * Free up object by releasing internal memory.
81 * \return ctl Export control data.
83 void exportldif_free( ExportLdifCtl *ctl ) {
84 g_return_if_fail( ctl != NULL );
87 g_free( ctl->fileLdif );
88 g_free( ctl->dirOutput );
89 g_free( ctl->suffix );
90 g_free( ctl->settingsFile );
94 ctl->dirOutput = NULL;
97 ctl->rdnIndex = EXPORT_LDIF_ID_UID;
99 ctl->excludeEMail = FALSE;
100 ctl->retVal = MGU_SUCCESS;
103 /* Now release object */
108 * Print control object.
109 * \param ctl Export control data.
110 * \param stream Output stream.
112 void exportldif_print( ExportLdifCtl *ctl, FILE *stream ) {
113 fprintf( stream, "ExportLdifCtl:\n" );
114 fprintf( stream, " path: %s\n", ctl->path );
115 fprintf( stream, "directory: %s\n", ctl->dirOutput );
116 fprintf( stream, " file: %s\n", ctl->fileLdif );
117 fprintf( stream, " suffix: %s\n", ctl->suffix );
118 fprintf( stream, " rdn: %d\n", ctl->rdnIndex );
119 fprintf( stream, " use DN: %s\n", ctl->useDN ? "y" : "n" );
120 fprintf( stream, " ex EMail: %s\n", ctl->excludeEMail ? "y" : "n" );
121 fprintf( stream, " settings: %s\n", ctl->settingsFile );
125 * Specify directory where LDIF files are created.
126 * \param ctl Export control data.
127 * \param value Full directory path.
129 void exportldif_set_output_dir( ExportLdifCtl *ctl, const gchar *value ) {
130 g_return_if_fail( ctl != NULL );
131 ctl->dirOutput = mgu_replace_string( ctl->dirOutput, value );
132 g_strstrip( ctl->dirOutput );
136 * Specify full file specification of LDIF file.
137 * \param ctl Export control data.
138 * \param value Full file specification.
140 void exportldif_set_path( ExportLdifCtl *ctl, const gchar *value ) {
141 g_return_if_fail( ctl != NULL );
142 ctl->path = mgu_replace_string( ctl->path, value );
143 g_strstrip( ctl->path );
147 * Specify file name of LDIF file.
148 * \param ctl Export control data.
149 * \param value File name.
151 void exportldif_set_file_ldif( ExportLdifCtl *ctl, const gchar *value ) {
152 g_return_if_fail( ctl != NULL );
153 ctl->fileLdif = mgu_replace_string( ctl->fileLdif, value );
154 g_strstrip( ctl->fileLdif );
158 * Specify suffix to be used for creating DN entries.
159 * \param ctl Export control data.
160 * \param value Suffix.
162 void exportldif_set_suffix( ExportLdifCtl *ctl, const char *value ) {
163 g_return_if_fail( ctl != NULL );
164 ctl->suffix = mgu_replace_string( ctl->suffix, value );
165 g_strstrip( ctl->suffix );
169 * Specify index of variable to be used for creating RDN entries.
170 * \param ctl Export control data.
171 * \param value Index to variable, as follows:
173 * <li><code>EXPORT_LDIF_ID_UID</code> - Use Sylpheed UID.</li>
174 * <li><code>EXPORT_LDIF_ID_DNAME</code> - Use Sylpheed display name.</li>
175 * <li><code>EXPORT_LDIF_ID_EMAIL</code> - Use first E-Mail address.</li>
178 void exportldif_set_rdn( ExportLdifCtl *ctl, const gint value ) {
179 g_return_if_fail( ctl != NULL );
180 ctl->rdnIndex = value;
184 * Specify that <code>DN</code> attribute, if present, should be used as the
186 * \param ctl Export control data.
187 * \param value <i>TRUE</i> if DN should be used.
189 void exportldif_set_use_dn( ExportLdifCtl *ctl, const gboolean value ) {
190 g_return_if_fail( ctl != NULL );
195 * Specify that records without E-Mail addresses should be excluded.
196 * \param ctl Export control data.
197 * \param value <i>TRUE</i> if records without E-Mail should be excluded.
199 void exportldif_set_exclude_email( ExportLdifCtl *ctl, const gboolean value ) {
200 g_return_if_fail( ctl != NULL );
201 ctl->excludeEMail = value;
205 * Format LDAP value name with no embedded commas.
206 * \param value Data value to format.
207 * \return Formatted string, should be freed after use.
209 static gchar *exportldif_fmt_value( gchar *value ) {
215 /* Duplicate incoming value */
216 dest = dupval = g_strdup( value );
218 /* Copy characters, ignoring commas */
233 * Build DN for entry.
234 * \param ctl Export control data.
235 * \param person Person to format.
236 * \return Formatted DN entry.
238 static gchar *exportldif_fmt_dn(
239 ExportLdifCtl *ctl, const ItemPerson *person )
241 gchar buf[ FMT_BUFSIZE ];
242 gchar *retVal = NULL;
245 gchar *dupval = NULL;
249 if( ctl->rdnIndex == EXPORT_LDIF_ID_UID ) {
250 attr = _attrName_UID_;
251 value = ADDRITEM_ID( person );
253 else if( ctl->rdnIndex == EXPORT_LDIF_ID_DNAME ) {
254 attr = _attrName_DName_;
255 value = ADDRITEM_NAME( person );
256 dupval = exportldif_fmt_value( value );
258 else if( ctl->rdnIndex == EXPORT_LDIF_ID_EMAIL ) {
261 node = person->listEMail;
263 ItemEMail *email = node->data;
265 attr = _attrName_EMail_;
266 value = email->address;
267 dupval = exportldif_fmt_value( value );
274 if( strlen( value ) > 0 ) {
278 /* Format and free duplicated value */
279 strcat( buf, dupval );
283 /* Use original value */
284 strcat( buf, value );
289 if( strlen( ctl->suffix ) > 0 ) {
291 strcat( buf, ctl->suffix );
295 retVal = g_strdup( buf );
303 * Find DN by searching attribute list.
304 * \param ctl Export control data.
305 * \param person Person to format.
306 * \return Formatted DN entry, should be freed after use.
308 static gchar *exportldif_find_dn(
309 ExportLdifCtl *ctl, const ItemPerson *person )
311 gchar *retVal = NULL;
314 node = person->listAttrib;
316 UserAttribute *attrib = node->data;
318 node = g_list_next( node );
319 if( g_utf8_collate( attrib->name, LDIF_TAG_DN ) == 0 ) {
320 retVal = g_strdup( attrib->value );
328 * Format E-Mail entries for person.
329 * \param person Person to format.
330 * \param stream Output stream.
331 * \return <i>TRUE</i> if entry formatted.
333 static gboolean exportldif_fmt_email( const ItemPerson *person, FILE *stream ) {
334 gboolean retVal = FALSE;
337 node = person->listEMail;
339 ItemEMail *email = node->data;
341 node = g_list_next( node );
342 ldif_write_value( stream, LDIF_TAG_EMAIL, email->address );
349 * Test for E-Mail entries for person.
350 * \param person Person to test.
351 * \return <i>TRUE</i> if person has E-Mail address.
353 static gboolean exportldif_test_email( const ItemPerson *person )
355 gboolean retVal = FALSE;
358 node = person->listEMail;
360 ItemEMail *email = node->data;
362 node = g_list_next( node );
363 if( email->address ) {
364 if( strlen( email->address ) > 0 ) {
375 * Format persons in an address book folder.
376 * \param ctl Export control data.
377 * \param stream Output stream.
378 * \param folder Folder to format.
379 * \return <i>TRUE</i> if no persons were formatted.
381 static gboolean exportldif_fmt_person(
382 ExportLdifCtl *ctl, FILE *stream, const ItemFolder *folder )
384 gboolean retVal = TRUE;
387 if( folder->listPerson == NULL ) return retVal;
389 node = folder->listPerson;
391 AddrItemObject *aio = node->data;
392 node = g_list_next( node );
394 if( aio && aio->type == ITEMTYPE_PERSON ) {
395 ItemPerson *person = ( ItemPerson * ) aio;
396 gboolean classPerson = FALSE;
397 gboolean classInetP = FALSE;
400 /* Check for E-Mail */
401 if( exportldif_test_email( person ) ) {
405 /* Bail if no E-Mail address */
406 if( ctl->excludeEMail ) continue;
411 dn = exportldif_find_dn( ctl, person );
414 dn = exportldif_fmt_dn( ctl, person );
416 if( dn == NULL ) continue;
417 ldif_write_value( stream, LDIF_TAG_DN, dn );
421 * Test for schema requirements. This is a simple
422 * test and does not trap all LDAP schema errors.
423 * These can be detected when the LDIF file is
424 * loaded into an LDAP server.
426 if( person->lastName ) {
427 if( strlen( person->lastName ) > 0 ) {
434 ldif_write_value( stream,
435 LDIF_TAG_OBJECTCLASS, LDIF_CLASS_PERSON );
438 ldif_write_value( stream,
439 LDIF_TAG_OBJECTCLASS, LDIF_CLASS_INET_PERSON );
442 /* Format person attributes */
444 stream, LDIF_TAG_COMMONNAME, ADDRITEM_NAME( person ) );
446 stream, LDIF_TAG_LASTNAME, person->lastName );
448 stream, LDIF_TAG_FIRSTNAME, person->firstName );
450 stream, LDIF_TAG_NICKNAME, person->nickName );
453 exportldif_fmt_email( person, stream );
456 ldif_write_eor( stream );
466 * Format an address book folder.
467 * \param ctl Export control data.
468 * \param stream Output stream.
469 * \param folder Folder to format.
470 * \return <i>TRUE</i> if no persons were formatted.
472 static void exportldif_fmt_folder(
473 ExportLdifCtl *ctl, FILE *stream, const ItemFolder *folder )
477 /* Export entries in this folder */
478 exportldif_fmt_person( ctl, stream, folder );
480 /* Export entries in sub-folders */
481 node = folder->listFolder;
483 AddrItemObject *aio = node->data;
485 node = g_list_next( node );
486 if( aio && aio->type == ITEMTYPE_FOLDER ) {
487 ItemFolder *subFolder = ( ItemFolder * ) aio;
488 exportldif_fmt_folder( ctl, stream, subFolder );
494 * Export address book to LDIF file.
495 * \param ctl Export control data.
496 * \param cache Address book/data source cache.
499 void exportldif_process( ExportLdifCtl *ctl, AddressCache *cache )
501 ItemFolder *rootFolder;
504 ldifFile = g_fopen( ctl->path, "wb" );
506 /* Cannot open file */
507 ctl->retVal = MGU_OPEN_FILE;
511 rootFolder = cache->rootFolder;
512 exportldif_fmt_folder( ctl, ldifFile, rootFolder );
514 ctl->retVal = MGU_SUCCESS;
518 * Build full export file specification.
519 * \param ctl Export control data.
521 static void exportldif_build_filespec( ExportLdifCtl *ctl ) {
524 fileSpec = g_strconcat(
525 ctl->dirOutput, G_DIR_SEPARATOR_S, ctl->fileLdif, NULL );
526 ctl->path = mgu_replace_string( ctl->path, fileSpec );
531 * Parse directory and filename from full export file specification.
532 * \param ctl Export control data.
533 * \param fileSpec File spec.
535 void exportldif_parse_filespec( ExportLdifCtl *ctl, gchar *fileSpec ) {
537 gchar *base = g_path_get_basename(fileSpec);
540 mgu_replace_string( ctl->fileLdif, base );
542 t = g_path_get_dirname( fileSpec );
543 ctl->dirOutput = mgu_replace_string( ctl->dirOutput, t );
545 ctl->path = mgu_replace_string( ctl->path, fileSpec );
549 * Test whether output directory exists.
550 * \param ctl Export control data.
551 * \return TRUE if exists.
553 gboolean exportldif_test_dir( ExportLdifCtl *ctl ) {
558 if((dp = opendir( ctl->dirOutput )) != NULL) {
566 * Create output directory.
567 * \param ctl Export control data.
568 * \return TRUE if directory created.
570 gboolean exportldif_create_dir( ExportLdifCtl *ctl ) {
571 gboolean retVal = FALSE;
574 if( mkdir( ctl->dirOutput, S_IRWXU ) == 0 ) {
578 ctl->rcCreate = errno;
584 * Retrieve create directory error message.
585 * \param ctl Export control data.
588 gchar *exportldif_get_create_msg( ExportLdifCtl *ctl ) {
591 if( ctl->rcCreate == EEXIST ) {
592 msg = _( "Name already exists but is not a directory." );
594 else if( ctl->rcCreate == EACCES ) {
595 msg = _( "No permissions to create directory." );
597 else if( ctl->rcCreate == ENAMETOOLONG ) {
598 msg = _( "Name is too long." );
601 msg = _( "Not specified." );
607 * Set default values.
608 * \param ctl Export control data.
610 static void exportldif_default_values( ExportLdifCtl *ctl ) {
614 g_get_home_dir(), G_DIR_SEPARATOR_S,
615 DFL_DIR_SYLPHEED_OUT, NULL );
617 ctl->dirOutput = mgu_replace_string( ctl->dirOutput, str );
621 mgu_replace_string( ctl->fileLdif, DFL_FILE_SYLPHEED_OUT );
622 ctl->suffix = mgu_replace_string( ctl->suffix, "" );
624 ctl->rdnIndex = EXPORT_LDIF_ID_UID;
626 ctl->retVal = MGU_SUCCESS;
630 * Load settings from XML properties file.
631 * \param ctl Export control data.
633 void exportldif_load_settings( ExportLdifCtl *ctl ) {
636 gchar buf[ XML_BUFSIZE ];
638 props = xmlprops_create();
639 xmlprops_set_path( props, ctl->settingsFile );
640 rc = xmlprops_load_file( props );
644 xmlprops_get_property_s( props, EXMLPROP_DIRECTORY, buf );
645 ctl->dirOutput = mgu_replace_string( ctl->dirOutput, buf );
648 xmlprops_get_property_s( props, EXMLPROP_FILE, buf );
649 ctl->fileLdif = mgu_replace_string( ctl->fileLdif, buf );
652 xmlprops_get_property_s( props, EXMLPROP_SUFFIX, buf );
653 ctl->suffix = mgu_replace_string( ctl->suffix, buf );
656 xmlprops_get_property_i( props, EXMLPROP_RDN_INDEX );
658 xmlprops_get_property_b( props, EXMLPROP_USE_DN );
660 xmlprops_get_property_b( props, EXMLPROP_EXCL_EMAIL );
663 /* Set default values */
664 exportldif_default_values( ctl );
666 exportldif_build_filespec( ctl );
667 /* exportldif_print( ctl, stdout ); */
669 xmlprops_free( props );
673 * Save settings to XML properties file.
674 * \param ctl Export control data.
676 void exportldif_save_settings( ExportLdifCtl *ctl ) {
679 props = xmlprops_create();
680 xmlprops_set_path( props, ctl->settingsFile );
682 xmlprops_set_property( props, EXMLPROP_DIRECTORY, ctl->dirOutput );
683 xmlprops_set_property( props, EXMLPROP_FILE, ctl->fileLdif );
684 xmlprops_set_property( props, EXMLPROP_SUFFIX, ctl->suffix );
685 xmlprops_set_property_i( props, EXMLPROP_RDN_INDEX, ctl->rdnIndex );
686 xmlprops_set_property_b( props, EXMLPROP_USE_DN, ctl->useDN );
687 xmlprops_set_property_b( props, EXMLPROP_EXCL_EMAIL, ctl->excludeEMail );
688 xmlprops_save_file( props );
689 xmlprops_free( props );
693 * ============================================================================
695 * ============================================================================