evolution-3.6.4/addressbook/tools/evolution-addressbook-export-list-cards.c

No issues found

  1 /*
  2  * This program is free software; you can redistribute it and/or
  3  * modify it under the terms of the GNU Lesser General Public
  4  * License as published by the Free Software Foundation; either
  5  * version 2 of the License, or (at your option) version 3.
  6  *
  7  * This program is distributed in the hope that it will be useful,
  8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 10  * Lesser General Public License for more details.
 11  *
 12  * You should have received a copy of the GNU Lesser General Public
 13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 14  *
 15  *
 16  * Authors:
 17  *		Gilbert Fang <gilbert.fang@sun.com>
 18  *
 19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 20  *
 21  */
 22 
 23 #ifdef HAVE_CONFIG_H
 24 #include <config.h>
 25 #endif
 26 
 27 #include <stdlib.h>
 28 #include <string.h>
 29 #include <sys/types.h>
 30 #include <unistd.h>
 31 
 32 #include <glib/gi18n.h>
 33 #include <glib/gstdio.h>
 34 
 35 #include <libebook/libebook.h>
 36 
 37 #include "evolution-addressbook-export.h"
 38 
 39 #define COMMA_SEPARATOR ","
 40 
 41 typedef enum _CARD_FORMAT CARD_FORMAT;
 42 typedef enum _DeliveryAddressField DeliveryAddressField;
 43 typedef enum _EContactFieldCSV EContactFieldCSV;
 44 typedef struct _EContactCSVFieldData EContactCSVFieldData;
 45 
 46 enum _CARD_FORMAT
 47 {
 48 	CARD_FORMAT_CSV,
 49 	CARD_FORMAT_VCARD
 50 };
 51 
 52 enum _DeliveryAddressField
 53 {
 54 	DELIVERY_ADDRESS_STREET,
 55 	DELIVERY_ADDRESS_EXT,
 56 	DELIVERY_ADDRESS_LOCALITY,
 57 	DELIVERY_ADDRESS_REGION,
 58 	DELIVERY_ADDRESS_CODE,
 59 	DELIVERY_ADDRESS_COUNTRY
 60 };
 61 
 62 enum _EContactFieldCSV
 63 {
 64 	E_CONTACT_CSV_FILE_AS,
 65 	E_CONTACT_CSV_FULL_NAME,
 66 	E_CONTACT_CSV_EMAIL_1,
 67 	E_CONTACT_CSV_EMAIL_2,
 68 	E_CONTACT_CSV_EMAIL_3,
 69 	E_CONTACT_CSV_EMAIL_4,
 70 	E_CONTACT_CSV_PHONE_PRIMARY,
 71 	E_CONTACT_CSV_PHONE_ASSISTANT,
 72 	E_CONTACT_CSV_PHONE_BUSINESS,
 73 	E_CONTACT_CSV_PHONE_CALLBACK,
 74 	E_CONTACT_CSV_PHONE_COMPANY,
 75 	E_CONTACT_CSV_PHONE_HOME,
 76 	E_CONTACT_CSV_ORG,
 77 	/*E_CONTACT_CSV_ADDRESS_BUSINESS, */
 78 	E_CONTACT_CSV_ADDRESS_BUSINESS_STREET,
 79 	E_CONTACT_CSV_ADDRESS_BUSINESS_EXT,
 80 	E_CONTACT_CSV_ADDRESS_BUSINESS_CITY,
 81 	E_CONTACT_CSV_ADDRESS_BUSINESS_REGION,
 82 	E_CONTACT_CSV_ADDRESS_BUSINESS_POSTCODE,
 83 	E_CONTACT_CSV_ADDRESS_BUSINESS_COUNTRY,
 84 	/*E_CONTACT_CSV_ADDRESS_HOME, */
 85 	E_CONTACT_CSV_ADDRESS_HOME_STREET,
 86 	E_CONTACT_CSV_ADDRESS_HOME_EXT,
 87 	E_CONTACT_CSV_ADDRESS_HOME_CITY,
 88 	E_CONTACT_CSV_ADDRESS_HOME_REGION,
 89 	E_CONTACT_CSV_ADDRESS_HOME_POSTCODE,
 90 	E_CONTACT_CSV_ADDRESS_HOME_COUNTRY,
 91 	E_CONTACT_CSV_PHONE_MOBILE,
 92 	E_CONTACT_CSV_PHONE_CAR,
 93 	E_CONTACT_CSV_PHONE_BUSINESS_FAX,
 94 	E_CONTACT_CSV_PHONE_HOME_FAX,
 95 	E_CONTACT_CSV_PHONE_BUSINESS_2,
 96 	E_CONTACT_CSV_PHONE_HOME_2,
 97 	E_CONTACT_CSV_PHONE_ISDN,
 98 	E_CONTACT_CSV_PHONE_OTHER,
 99 	E_CONTACT_CSV_PHONE_OTHER_FAX,
100 	E_CONTACT_CSV_PHONE_PAGER,
101 	E_CONTACT_CSV_PHONE_RADIO,
102 	E_CONTACT_CSV_PHONE_TELEX,
103 	E_CONTACT_CSV_PHONE_TTYTDD,
104 	/*E_CONTACT_CSV_ADDRESS_OTHER, */
105 	E_CONTACT_CSV_ADDRESS_OTHER_STREET,
106 	E_CONTACT_CSV_ADDRESS_OTHER_EXT,
107 	E_CONTACT_CSV_ADDRESS_OTHER_CITY,
108 	E_CONTACT_CSV_ADDRESS_OTHER_REGION,
109 	E_CONTACT_CSV_ADDRESS_OTHER_POSTCODE,
110 	E_CONTACT_CSV_ADDRESS_OTHER_COUNTRY,
111 	E_CONTACT_CSV_HOMEPAGE_URL,
112 	E_CONTACT_CSV_ORG_UNIT,
113 	E_CONTACT_CSV_OFFICE,
114 	E_CONTACT_CSV_TITLE,
115 	E_CONTACT_CSV_ROLE,
116 	E_CONTACT_CSV_MANAGER,
117 	E_CONTACT_CSV_ASSISTANT,
118 	E_CONTACT_CSV_NICKNAME,
119 	E_CONTACT_CSV_SPOUSE,
120 	E_CONTACT_CSV_NOTE,
121 	E_CONTACT_CSV_CALENDAR_URI,
122 	E_CONTACT_CSV_FREEBUSY_URL,
123 	/*E_CONTACT_CSV_ANNIVERSARY, */
124 	E_CONTACT_CSV_ANNIVERSARY_YEAR,
125 	E_CONTACT_CSV_ANNIVERSARY_MONTH,
126 	E_CONTACT_CSV_ANNIVERSARY_DAY,
127 	/*E_CONTACT_CSV_BIRTH_DATE, */
128 	E_CONTACT_CSV_BIRTH_DATE_YEAR,
129 	E_CONTACT_CSV_BIRTH_DATE_MONTH,
130 	E_CONTACT_CSV_BIRTH_DATE_DAY,
131 	E_CONTACT_CSV_MAILER,
132 	E_CONTACT_CSV_NAME_OR_ORG,
133 	E_CONTACT_CSV_CATEGORIES,
134 	E_CONTACT_CSV_FAMILY_NAME,
135 	E_CONTACT_CSV_GIVEN_NAME,
136 	E_CONTACT_CSV_WANTS_HTML,
137 	E_CONTACT_CSV_IS_LIST,
138 	E_CONTACT_CSV_LAST
139 };
140 
141 typedef enum {
142 	DT_STRING,
143 	DT_BOOLEAN
144 } EContactCSVDataType;
145 
146 struct _EContactCSVFieldData
147 {
148 	gint csv_field;
149 	gint contact_field;
150 	const gchar *csv_name;
151 	EContactCSVDataType data_type;
152 };
153 
154 #define NOMAP -1
155 static EContactCSVFieldData csv_field_data[] = {
156 	{E_CONTACT_CSV_FILE_AS,		E_CONTACT_FILE_AS,	   "", DT_STRING},
157 	{E_CONTACT_CSV_FULL_NAME,	E_CONTACT_CSV_FULL_NAME,   "", DT_STRING},
158 	{E_CONTACT_CSV_EMAIL_1,		E_CONTACT_EMAIL_1,	   "", DT_STRING},
159 	{E_CONTACT_CSV_EMAIL_2,		E_CONTACT_EMAIL_2,	   "", DT_STRING},
160 	{E_CONTACT_CSV_EMAIL_3,		E_CONTACT_EMAIL_3,	   "", DT_STRING},
161 	{E_CONTACT_CSV_EMAIL_4,		E_CONTACT_EMAIL_4,	   "", DT_STRING},
162 	{E_CONTACT_CSV_PHONE_PRIMARY,	E_CONTACT_PHONE_PRIMARY,   "", DT_STRING},
163 	{E_CONTACT_CSV_PHONE_ASSISTANT,	E_CONTACT_PHONE_ASSISTANT, "", DT_STRING},
164 	{E_CONTACT_CSV_PHONE_BUSINESS,	E_CONTACT_PHONE_BUSINESS,  "", DT_STRING},
165 	{E_CONTACT_CSV_PHONE_CALLBACK,	E_CONTACT_PHONE_CALLBACK,  "", DT_STRING},
166 	{E_CONTACT_CSV_PHONE_COMPANY,	E_CONTACT_PHONE_COMPANY,   "", DT_STRING},
167 	{E_CONTACT_CSV_PHONE_HOME,	E_CONTACT_PHONE_HOME,	   "", DT_STRING},
168 	{E_CONTACT_CSV_ORG,		E_CONTACT_ORG,		   "", DT_STRING},
169 	/*E_CONTACT_CSV_ADDRESS_BUSINESS, */
170 	{E_CONTACT_CSV_ADDRESS_BUSINESS_STREET,	  NOMAP, "Business Address",	      DT_STRING},
171 	{E_CONTACT_CSV_ADDRESS_BUSINESS_EXT,	  NOMAP, "Business Address2",         DT_STRING},
172 	{E_CONTACT_CSV_ADDRESS_BUSINESS_CITY,	  NOMAP, "Business Address City",     DT_STRING},
173 	{E_CONTACT_CSV_ADDRESS_BUSINESS_REGION,	  NOMAP, "Business Address State",    DT_STRING},
174 	{E_CONTACT_CSV_ADDRESS_BUSINESS_POSTCODE, NOMAP, "Business Address PostCode", DT_STRING},
175 	{E_CONTACT_CSV_ADDRESS_BUSINESS_COUNTRY,  NOMAP, "Business Address Country",  DT_STRING},
176 	/*E_CONTACT_CSV_ADDRESS_HOME, */
177 	{E_CONTACT_CSV_ADDRESS_HOME_STREET,   NOMAP, "Home Address",          DT_STRING},
178 	{E_CONTACT_CSV_ADDRESS_HOME_EXT,      NOMAP, "Home Address2",         DT_STRING},
179 	{E_CONTACT_CSV_ADDRESS_HOME_CITY,     NOMAP, "Home Address City",     DT_STRING},
180 	{E_CONTACT_CSV_ADDRESS_HOME_REGION,   NOMAP, "Home Address State",    DT_STRING},
181 	{E_CONTACT_CSV_ADDRESS_HOME_POSTCODE, NOMAP, "Home Address PostCode", DT_STRING},
182 	{E_CONTACT_CSV_ADDRESS_HOME_COUNTRY,  NOMAP, "Home Address Country",  DT_STRING},
183 	{E_CONTACT_CSV_PHONE_MOBILE,	      E_CONTACT_PHONE_MOBILE,       "", DT_STRING},
184 	{E_CONTACT_CSV_PHONE_CAR,	      E_CONTACT_PHONE_CAR,          "", DT_STRING},
185 	{E_CONTACT_CSV_PHONE_BUSINESS_FAX,    E_CONTACT_PHONE_BUSINESS_FAX, "", DT_STRING},
186 	{E_CONTACT_CSV_PHONE_HOME_FAX,        E_CONTACT_PHONE_HOME_FAX,     "", DT_STRING},
187 	{E_CONTACT_CSV_PHONE_BUSINESS_2,      E_CONTACT_PHONE_BUSINESS_2,   "", DT_STRING},
188 	{E_CONTACT_CSV_PHONE_HOME_2,          E_CONTACT_PHONE_HOME_2,       "", DT_STRING},
189 	{E_CONTACT_CSV_PHONE_ISDN,            E_CONTACT_PHONE_ISDN,         "", DT_STRING},
190 	{E_CONTACT_CSV_PHONE_OTHER,           E_CONTACT_PHONE_OTHER,        "", DT_STRING},
191 	{E_CONTACT_CSV_PHONE_OTHER_FAX,       E_CONTACT_PHONE_OTHER_FAX,    "", DT_STRING},
192 	{E_CONTACT_CSV_PHONE_PAGER,           E_CONTACT_PHONE_PAGER,        "", DT_STRING},
193 	{E_CONTACT_CSV_PHONE_RADIO,           E_CONTACT_PHONE_RADIO,        "", DT_STRING},
194 	{E_CONTACT_CSV_PHONE_TELEX,           E_CONTACT_PHONE_TELEX,        "", DT_STRING},
195 	{E_CONTACT_CSV_PHONE_TTYTDD,          E_CONTACT_PHONE_TTYTDD,       "", DT_STRING},
196 	/*E_CONTACT_CSV_ADDRESS_OTHER, */
197 	{E_CONTACT_CSV_ADDRESS_OTHER_STREET,   NOMAP, "Other Address",          DT_STRING},
198 	{E_CONTACT_CSV_ADDRESS_OTHER_EXT,      NOMAP, "Other Address2",         DT_STRING},
199 	{E_CONTACT_CSV_ADDRESS_OTHER_CITY,     NOMAP, "Other Address City",     DT_STRING},
200 	{E_CONTACT_CSV_ADDRESS_OTHER_REGION,   NOMAP, "Other Address State",    DT_STRING},
201 	{E_CONTACT_CSV_ADDRESS_OTHER_POSTCODE, NOMAP, "Other Address PostCode", DT_STRING},
202 	{E_CONTACT_CSV_ADDRESS_OTHER_COUNTRY,  NOMAP, "Other Address Country",  DT_STRING},
203 	{E_CONTACT_CSV_HOMEPAGE_URL,           E_CONTACT_HOMEPAGE_URL, "", DT_STRING},
204 	{E_CONTACT_CSV_ORG_UNIT,               E_CONTACT_ORG_UNIT,     "", DT_STRING},
205 	{E_CONTACT_CSV_OFFICE,                 E_CONTACT_OFFICE,       "", DT_STRING},
206 	{E_CONTACT_CSV_TITLE,                  E_CONTACT_TITLE,        "", DT_STRING},
207 	{E_CONTACT_CSV_ROLE,                   E_CONTACT_ROLE,         "", DT_STRING},
208 	{E_CONTACT_CSV_MANAGER,                E_CONTACT_MANAGER,      "", DT_STRING},
209 	{E_CONTACT_CSV_ASSISTANT,              E_CONTACT_ASSISTANT,    "", DT_STRING},
210 	{E_CONTACT_CSV_NICKNAME,               E_CONTACT_NICKNAME,     "", DT_STRING},
211 	{E_CONTACT_CSV_SPOUSE,                 E_CONTACT_SPOUSE,       "", DT_STRING},
212 	{E_CONTACT_CSV_NOTE,                   E_CONTACT_NOTE,         "", DT_STRING},
213 	{E_CONTACT_CSV_CALENDAR_URI,           E_CONTACT_CALENDAR_URI, "", DT_STRING},
214 	{E_CONTACT_CSV_FREEBUSY_URL,           E_CONTACT_FREEBUSY_URL, "", DT_STRING},
215 	/*E_CONTACT_ANNIVERSARY, */
216 	{E_CONTACT_CSV_ANNIVERSARY_YEAR,       NOMAP, "Anniversary Year",  DT_STRING},
217 	{E_CONTACT_CSV_ANNIVERSARY_MONTH,      NOMAP, "Anniversary Month", DT_STRING},
218 	{E_CONTACT_CSV_ANNIVERSARY_DAY,        NOMAP, "Anniversary Day",   DT_STRING},
219 	/*E_CONTACT_BIRTH_DATE, */
220 	{E_CONTACT_CSV_BIRTH_DATE_YEAR,  NOMAP, "Birth Year",  DT_STRING},
221 	{E_CONTACT_CSV_BIRTH_DATE_MONTH, NOMAP, "Birth Month", DT_STRING},
222 	{E_CONTACT_CSV_BIRTH_DATE_DAY,   NOMAP, "Birth Day",   DT_STRING},
223 	{E_CONTACT_CSV_MAILER,           E_CONTACT_MAILER,      "", DT_STRING},
224 	{E_CONTACT_CSV_NAME_OR_ORG,      E_CONTACT_NAME_OR_ORG, "", DT_STRING},
225 	{E_CONTACT_CSV_CATEGORIES,       E_CONTACT_CATEGORIES,  "", DT_STRING},
226 	{E_CONTACT_CSV_FAMILY_NAME,      E_CONTACT_FAMILY_NAME, "", DT_STRING},
227 	{E_CONTACT_CSV_GIVEN_NAME,       E_CONTACT_GIVEN_NAME,  "", DT_STRING},
228 	{E_CONTACT_CSV_WANTS_HTML,       E_CONTACT_WANTS_HTML,  "", DT_BOOLEAN},
229 	{E_CONTACT_CSV_IS_LIST,          E_CONTACT_IS_LIST,     "", DT_BOOLEAN},
230 	{E_CONTACT_CSV_LAST,             NOMAP,                 "", DT_STRING}
231 
232 };
233 
234 static GSList *pre_defined_fields;
235 
236 /*function prototypes*/
237 gint e_contact_csv_get_contact_field (EContactFieldCSV csv_field);
238 gchar *e_contact_csv_get_name (EContactFieldCSV csv_field);
239 gchar *e_contact_csv_get (EContact * contact, EContactFieldCSV csv_field);
240 gchar *e_contact_csv_get_header_line (GSList * csv_all_fields);
241 gchar *e_contact_to_csv (EContact * contact, GSList * csv_all_fields);
242 gchar *e_contact_get_csv (EContact * contact, GSList * csv_all_fields);
243 gchar *delivery_address_get_sub_field (const EContactAddress * delivery_address, DeliveryAddressField sub_field);
244 gchar *check_null_pointer (gchar * orig);
245 gchar *escape_string (gchar * orig);
246 gint output_n_cards_file (FILE * outputfile, GSList *contacts, gint size, gint begin_no, CARD_FORMAT format);
247 static void fork_to_background (void);
248 void set_pre_defined_field (GSList ** pre_defined_fields);
249 
250 /* function declarations*/
251 gint
252 e_contact_csv_get_contact_field (EContactFieldCSV csv_field)
253 {
254 	return csv_field_data[csv_field].contact_field;
255 }
256 
257 static EContactCSVDataType
258 e_contact_csv_get_data_type (EContactFieldCSV csv_field)
259 {
260 	return csv_field_data[csv_field].data_type;
261 }
262 
263 gchar *
264 e_contact_csv_get_name (EContactFieldCSV csv_field)
265 {
266 	gint contact_field;
267 	gchar *name;
268 	gchar *quoted_name;
269 
270 	contact_field = e_contact_csv_get_contact_field (csv_field);
271 
272 	if (contact_field != NOMAP) {
273 		name = g_strdup (e_contact_field_name (contact_field));
274 	} else {
275 		name = g_strdup (csv_field_data[csv_field].csv_name);
276 	}
277 	quoted_name = escape_string (name);
278 	g_free (name);
279 	return quoted_name;
280 }
281 
282 gchar *
283 e_contact_csv_get (EContact *contact,
284                    EContactFieldCSV csv_field)
285 {
286 	gint contact_field;
287 	gchar *field_value;
288 	gchar *quoted_field_value;
289 
290 	EContactAddress *delivery_address = NULL;
291 	EContactDate *date;
292 
293 	contact_field = e_contact_csv_get_contact_field (csv_field);
294 
295 	if (contact_field != NOMAP) {
296 		field_value = e_contact_get (contact, contact_field);
297 		if (e_contact_csv_get_data_type (csv_field) == DT_BOOLEAN) {
298 			field_value = g_strdup ((GPOINTER_TO_INT (field_value)) ? "TRUE" : "FALSE");
299 		}
300 	} else {
301 		switch (csv_field) {
302 		case E_CONTACT_CSV_ADDRESS_HOME_STREET:
303 			delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_HOME);
304 			field_value = delivery_address_get_sub_field (delivery_address, DELIVERY_ADDRESS_STREET);
305 			break;
306 		case E_CONTACT_CSV_ADDRESS_HOME_EXT:
307 			delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_HOME);
308 			field_value = delivery_address_get_sub_field (delivery_address, DELIVERY_ADDRESS_EXT);
309 			break;
310 		case E_CONTACT_CSV_ADDRESS_HOME_CITY:
311 			delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_HOME);
312 			field_value = delivery_address_get_sub_field (delivery_address, DELIVERY_ADDRESS_LOCALITY);
313 			break;
314 		case E_CONTACT_CSV_ADDRESS_HOME_REGION:
315 			delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_HOME);
316 			field_value = delivery_address_get_sub_field (delivery_address, DELIVERY_ADDRESS_REGION);
317 			break;
318 		case E_CONTACT_CSV_ADDRESS_HOME_POSTCODE:
319 			delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_HOME);
320 			field_value = delivery_address_get_sub_field (delivery_address, DELIVERY_ADDRESS_CODE);
321 			break;
322 		case E_CONTACT_CSV_ADDRESS_HOME_COUNTRY:
323 			delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_HOME);
324 			field_value = delivery_address_get_sub_field (delivery_address, DELIVERY_ADDRESS_COUNTRY);
325 			break;
326 		case E_CONTACT_CSV_ADDRESS_BUSINESS_STREET:
327 			delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_WORK);
328 			field_value = delivery_address_get_sub_field (delivery_address, DELIVERY_ADDRESS_STREET);
329 			break;
330 		case E_CONTACT_CSV_ADDRESS_BUSINESS_EXT:
331 			delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_WORK);
332 			field_value = delivery_address_get_sub_field (delivery_address, DELIVERY_ADDRESS_EXT);
333 			break;
334 		case E_CONTACT_CSV_ADDRESS_BUSINESS_CITY:
335 			delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_WORK);
336 			field_value = delivery_address_get_sub_field (delivery_address, DELIVERY_ADDRESS_LOCALITY);
337 			break;
338 		case E_CONTACT_CSV_ADDRESS_BUSINESS_REGION:
339 			delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_WORK);
340 			field_value = delivery_address_get_sub_field (delivery_address, DELIVERY_ADDRESS_REGION);
341 			break;
342 		case E_CONTACT_CSV_ADDRESS_BUSINESS_POSTCODE:
343 			delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_WORK);
344 			field_value = delivery_address_get_sub_field (delivery_address, DELIVERY_ADDRESS_CODE);
345 			break;
346 		case E_CONTACT_CSV_ADDRESS_BUSINESS_COUNTRY:
347 			delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_WORK);
348 			field_value = delivery_address_get_sub_field (delivery_address, DELIVERY_ADDRESS_COUNTRY);
349 			break;
350 		case E_CONTACT_CSV_BIRTH_DATE_YEAR:
351 			date = e_contact_get (contact, E_CONTACT_BIRTH_DATE);
352 			if (date) {
353 				field_value = g_strdup_printf ("%04d", date->year);
354 				e_contact_date_free (date);
355 			}
356 			else {
357 				field_value = g_strdup ("");
358 			}
359 			break;
360 
361 		case E_CONTACT_CSV_BIRTH_DATE_MONTH:
362 			date = e_contact_get (contact, E_CONTACT_BIRTH_DATE);
363 			if (date) {
364 				field_value = g_strdup_printf ("%04d", date->month);
365 				e_contact_date_free (date);
366 			}
367 			else {
368 				field_value = g_strdup ("");
369 			}
370 			break;
371 
372 		case E_CONTACT_CSV_BIRTH_DATE_DAY:
373 			date = e_contact_get (contact, E_CONTACT_BIRTH_DATE);
374 			if (date) {
375 				field_value = g_strdup_printf ("%04d", date->day);
376 				e_contact_date_free (date);
377 			}
378 			else {
379 				field_value = g_strdup ("");
380 			}
381 			break;
382 
383 		default:
384 			field_value = g_strdup ("");
385 		}
386 	}
387 
388 	/*checking to avoid the NULL pointer */
389 	if (field_value == NULL)
390 		field_value =  g_strdup ("");
391 
392 	quoted_field_value = escape_string (field_value);
393 	g_free (field_value);
394 
395 	if (delivery_address)
396 		e_contact_address_free (delivery_address);
397 
398 	return quoted_field_value;
399 }
400 
401 gchar *
402 e_contact_csv_get_header_line (GSList *csv_all_fields)
403 {
404 
405 	guint field_number;
406 	gint csv_field;
407 	gchar **field_name_array;
408 	gchar *header_line;
409 
410 	gint loop_counter;
411 
412 	field_number = g_slist_length (csv_all_fields);
413 	field_name_array = g_new0 (gchar *, field_number + 1);
414 
415 	for (loop_counter = 0; loop_counter < field_number; loop_counter++) {
416 		csv_field = GPOINTER_TO_INT (g_slist_nth_data (csv_all_fields, loop_counter));
417 		*(field_name_array + loop_counter) = e_contact_csv_get_name (csv_field);
418 	}
419 
420 	header_line = g_strjoinv (COMMA_SEPARATOR, field_name_array);
421 
422 	for (loop_counter = 0; loop_counter < field_number; loop_counter++) {
423 		g_free (*(field_name_array + loop_counter));
424 	}
425 	g_free (field_name_array);
426 
427 	return header_line;
428 
429 }
430 
431 gchar *
432 e_contact_to_csv (EContact *contact,
433                   GSList *csv_all_fields)
434 {
435 	guint field_number;
436 	gint csv_field;
437 	gchar **field_value_array;
438 	gchar *aline;
439 
440 	gint loop_counter;
441 
442 	field_number = g_slist_length (csv_all_fields);
443 	field_value_array = g_new0 (gchar *, field_number + 1);
444 
445 	for (loop_counter = 0; loop_counter < field_number; loop_counter++) {
446 		csv_field = GPOINTER_TO_INT (g_slist_nth_data (csv_all_fields, loop_counter));
447 		*(field_value_array + loop_counter) = e_contact_csv_get (contact, csv_field);
448 	}
449 
450 	aline = g_strjoinv (COMMA_SEPARATOR, field_value_array);
451 
452 	for (loop_counter = 0; loop_counter < field_number; loop_counter++) {
453 		g_free (*(field_value_array + loop_counter));
454 	}
455 	g_free (field_value_array);
456 
457 	return aline;
458 
459 }
460 
461 gchar *
462 e_contact_get_csv (EContact *contact,
463                    GSList *csv_all_fields)
464 {
465 	gchar *aline;
466 
467 	aline = e_contact_to_csv (contact, csv_all_fields);
468 	return aline;
469 }
470 
471 gchar *
472 check_null_pointer (gchar *orig)
473 {
474 	gchar *result;
475 	if (orig == NULL)
476 		result = g_strdup ("");
477 	else
478 		result = g_strdup (orig);
479 	return result;
480 }
481 
482 gchar *
483 delivery_address_get_sub_field (const EContactAddress *address,
484                                 DeliveryAddressField sub_field)
485 {
486 	gchar *sub_field_value;
487 	gchar *str_temp, *str_temp_a;
488 	if (address != NULL) {
489 		switch (sub_field) {
490 		case DELIVERY_ADDRESS_STREET:
491 			str_temp_a = check_null_pointer (address->po);
492 			str_temp = check_null_pointer (address->street);
493 			sub_field_value = g_strdup_printf ("%s %s", str_temp_a, str_temp);
494 			g_free (str_temp);
495 			g_free (str_temp_a);
496 			break;
497 		case DELIVERY_ADDRESS_EXT:
498 			sub_field_value = check_null_pointer (address->ext);
499 			break;
500 		case DELIVERY_ADDRESS_LOCALITY:
501 			sub_field_value = check_null_pointer (address->locality);
502 			break;
503 		case DELIVERY_ADDRESS_REGION:
504 			sub_field_value = check_null_pointer (address->region);
505 			break;
506 		case DELIVERY_ADDRESS_CODE:
507 			sub_field_value = check_null_pointer (address->code);
508 			break;
509 		case DELIVERY_ADDRESS_COUNTRY:
510 			sub_field_value = check_null_pointer (address->country);
511 			break;
512 		default:
513 			sub_field_value = g_strdup ("");
514 		}
515 	} else {
516 		sub_field_value = g_strdup ("");
517 	}
518 	return sub_field_value;
519 }
520 
521 gchar *
522 escape_string (gchar *orig)
523 {
524 	const guchar *p;
525 	gchar *dest;
526 	gchar *q;
527 
528 	if (orig == NULL)
529 		return g_strdup ("\"\"");
530 
531 	p = (guchar *) orig;
532 	/* Each source byte needs maximally two destination chars (\n), and the extra 2 is for the leading and trailing '"' */
533 	q = dest = g_malloc (strlen (orig) * 2 + 1 + 2);
534 
535 	*q++ = '\"';
536 	while (*p)
537 	{
538 		switch (*p)
539 		{
540 		case '\n':
541 			*q++ = '\\';
542 			*q++ = 'n';
543 			break;
544 		case '\r':
545 			*q++ = '\\';
546 			*q++ = 'r';
547 			break;
548 		case '\\':
549 			*q++ = '\\';
550 			*q++ = '\\';
551 			break;
552 		case '"':
553 			*q++ = '"';
554 			*q++ = '"';
555 			break;
556 		default:
557 			*q++ = *p;
558 		}
559 		p++;
560 	}
561 
562 	*q++ = '\"';
563 	*q = 0;
564 
565 	return dest;
566 }
567 
568 gint
569 output_n_cards_file (FILE *outputfile,
570                      GSList *contacts,
571                      gint size,
572                      gint begin_no,
573                      CARD_FORMAT format)
574 {
575 	gint i;
576 	if (format == CARD_FORMAT_VCARD) {
577 		for (i = begin_no; i < size + begin_no; i++) {
578 			EContact *contact = g_slist_nth_data (contacts, i);
579 			gchar *vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
580 			fprintf (outputfile, "%s\n", vcard);
581 			g_free (vcard);
582 		}
583 	} else if (format == CARD_FORMAT_CSV) {
584 		gchar *csv_fields_name;
585 
586 		if (!pre_defined_fields)
587 			set_pre_defined_field (&pre_defined_fields);
588 
589 		csv_fields_name = e_contact_csv_get_header_line (pre_defined_fields);
590 		fprintf (outputfile, "%s\n", csv_fields_name);
591 		g_free (csv_fields_name);
592 
593 		for (i = begin_no; i < size + begin_no; i++) {
594 			EContact *contact = g_slist_nth_data (contacts, i);
595 			gchar *csv = e_contact_get_csv (contact, pre_defined_fields);
596 			fprintf (outputfile, "%s\n", csv);
597 			g_free (csv);
598 		}
599 	}
600 
601 	return SUCCESS;
602 
603 }
604 
605 static void
606 fork_to_background (void)
607 {
608 #ifndef G_OS_WIN32
609 	pid_t pid;
610 	pid = fork ();
611 	if (pid == -1) {
612 		/* ouch, fork() failed */
613 		perror ("fork");
614 		exit (-1);
615 	} else if (pid == 0) {
616 		/* child */
617 		/*contunue */
618 
619 	} else {
620 		/* parent exit,  note the use of _exit() instead of exit() */
621 		_exit (-1);
622 	}
623 #endif
624 }
625 
626 static void
627 action_list_cards (GSList *contacts,
628                    ActionContext *p_actctx)
629 {
630 	FILE *outputfile;
631 	long length;
632 	gint IsFirstOne;
633 	gint series_no;
634 	gchar *file_series_name;
635 	CARD_FORMAT format;
636 	gint size;
637 
638 	length = g_slist_length (contacts);
639 
640 	if (length <= 0) {
641 		g_warning ("Couldn't load addressbook correctly!!!! %s####", p_actctx->action_list_cards.addressbook_source_uid ?
642 				p_actctx->action_list_cards.addressbook_source_uid : "NULL");
643 		exit (-1);
644 	}
645 
646 	if (p_actctx->action_list_cards.async_mode == FALSE) {	/* normal mode */
647 
648 		if (p_actctx->action_list_cards.output_file == NULL) {
649 			outputfile = stdout;
650 		} else {
651 			/* fopen output file */
652 			if (!(outputfile = g_fopen (p_actctx->action_list_cards.output_file, "w"))) {
653 				g_warning (_("Can not open file"));
654 				exit (-1);
655 			}
656 		}
657 
658 		if (p_actctx->action_list_cards.IsVCard == TRUE)
659 			format = CARD_FORMAT_VCARD;
660 		else
661 			format = CARD_FORMAT_CSV;
662 
663 		output_n_cards_file (outputfile, contacts, length, 0, format);
664 
665 		if (p_actctx->action_list_cards.output_file != NULL) {
666 			fclose (outputfile);
667 		}
668 	}
669 
670 	/*async mode */
671 	else {
672 
673 		size = p_actctx->action_list_cards.file_size;
674 		IsFirstOne = TRUE;
675 		series_no = 0;
676 
677 		do {
678 			/* whether it is the last file */
679 			if ((series_no + 1) * size >= length) {	/*last one */
680 				file_series_name = g_strdup_printf ("%s.end", p_actctx->action_list_cards.output_file);
681 
682 			} else {	/*next one */
683 				file_series_name =
684 					g_strdup_printf ("%s.%04d", p_actctx->action_list_cards.output_file, series_no);
685 			}
686 
687 			if (!(outputfile = g_fopen (file_series_name, "w"))) {
688 				g_warning (_("Can not open file"));
689 				exit (-1);
690 			}
691 
692 			if (p_actctx->action_list_cards.IsVCard == TRUE)
693 				format = CARD_FORMAT_VCARD;
694 			else
695 				format = CARD_FORMAT_CSV;
696 			output_n_cards_file (outputfile, contacts, size, series_no * size, format);
697 
698 			fclose (outputfile);
699 
700 			series_no++;
701 
702 			if (IsFirstOne == TRUE) {
703 				fork_to_background ();
704 				IsFirstOne = FALSE;
705 			}
706 
707 		}
708 		while (series_no * size < length);
709 		g_free (file_series_name);
710 #ifdef G_OS_WIN32
711 		/* On Unix the parent exits already in
712 		 * fork_to_background(), but without fork() exit only
713 		 * after doing the job. XXX Is this correct?
714 		 */
715 		if (IsFirstOne == FALSE)
716 			_exit (-1);
717 #endif
718 	}
719 }
720 
721 void
722 set_pre_defined_field (GSList **pre_defined_fields)
723 {
724 	*pre_defined_fields = NULL;
725 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_GIVEN_NAME));
726 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_FAMILY_NAME));
727 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_FULL_NAME));
728 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_NICKNAME));
729 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_EMAIL_1));
730 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_EMAIL_2));
731 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_EMAIL_3));
732 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_EMAIL_4));
733 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_WANTS_HTML));
734 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_PHONE_BUSINESS));
735 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_PHONE_HOME));
736 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_PHONE_BUSINESS_FAX));
737 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_PHONE_PAGER));
738 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_PHONE_MOBILE));
739 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_ADDRESS_HOME_STREET));
740 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_ADDRESS_HOME_EXT));
741 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_ADDRESS_HOME_CITY));
742 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_ADDRESS_HOME_REGION));
743 	*pre_defined_fields =
744 		g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_ADDRESS_HOME_POSTCODE));
745 	*pre_defined_fields =
746 		g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_ADDRESS_HOME_COUNTRY));
747 	*pre_defined_fields =
748 		g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_ADDRESS_BUSINESS_STREET));
749 	*pre_defined_fields =
750 		g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_ADDRESS_BUSINESS_EXT));
751 	*pre_defined_fields =
752 		g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_ADDRESS_BUSINESS_CITY));
753 	*pre_defined_fields =
754 		g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_ADDRESS_BUSINESS_REGION));
755 	*pre_defined_fields =
756 		g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_ADDRESS_BUSINESS_POSTCODE));
757 	*pre_defined_fields =
758 		g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_ADDRESS_BUSINESS_COUNTRY));
759 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_TITLE));
760 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_OFFICE));
761 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_ORG));
762 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_HOMEPAGE_URL));
763 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_CALENDAR_URI));
764 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_BIRTH_DATE_YEAR));
765 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_BIRTH_DATE_MONTH));
766 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_BIRTH_DATE_DAY));
767 	*pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (E_CONTACT_CSV_NOTE));
768 }
769 
770 guint
771 action_list_cards_init (ESourceRegistry *registry,
772                         ActionContext *p_actctx)
773 {
774 	EBookClient *book_client;
775 	EBookQuery *query;
776 	ESource *source;
777 	GSList *contacts;
778 	const gchar *uid;
779 	gchar *query_str;
780 	GError *error = NULL;
781 
782 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FAILED);
783 
784 	uid = p_actctx->action_list_cards.addressbook_source_uid;
785 
786 	if (uid != NULL)
787 		source = e_source_registry_ref_source (registry, uid);
788 	else
789 		source = e_source_registry_ref_default_address_book (registry);
790 
791 	book_client = e_book_client_new (source, &error);
792 
793 	g_object_unref (source);
794 
795 	if (book_client != NULL)
796 		e_client_open_sync (E_CLIENT (book_client), TRUE, NULL, &error);
797 
798 	if (error != NULL) {
799 		g_warning (
800 			"Couldn't load addressbook %s: %s",
801 			p_actctx->action_list_cards.addressbook_source_uid ?
802 			p_actctx->action_list_cards.addressbook_source_uid :
803 			"'default'", error->message);
804 		if (book_client != NULL)
805 			g_object_unref (book_client);
806 		g_error_free (error);
807 		exit (-1);
808 	}
809 
810 	g_return_val_if_fail (E_IS_BOOK_CLIENT (book_client), FAILED);
811 
812 	query = e_book_query_any_field_contains ("");
813 	query_str = e_book_query_to_string (query);
814 	e_book_query_unref (query);
815 
816 	if (!e_book_client_get_contacts_sync (book_client, query_str, &contacts, NULL, &error))
817 		contacts = NULL;
818 
819 	action_list_cards (contacts, p_actctx);
820 
821 	g_slist_foreach (contacts, (GFunc) g_object_unref, NULL);
822 	g_slist_free (contacts);
823 	g_object_unref (book_client);
824 
825 	if (error) {
826 		g_warning ("Failed to get contacts: %s", error->message);
827 		g_error_free (error);
828 	}
829 
830 	return error ? FAILED : SUCCESS;
831 }