1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_connectivity.hxx"
30 
31 #include "MacabRecords.hxx"
32 #include "MacabRecord.hxx"
33 #include "MacabHeader.hxx"
34 #include "macabutilities.hxx"
35 
36 #include <premac.h>
37 #include <Carbon/Carbon.h>
38 #include <AddressBook/ABAddressBookC.h>
39 #include <postmac.h>
40 #include <com/sun/star/util/DateTime.hpp>
41 
42 using namespace connectivity::macab;
43 using namespace com::sun::star::util;
44 
45 // -------------------------------------------------------------------------
46 MacabRecords::MacabRecords(const ABAddressBookRef _addressBook, MacabHeader *_header, MacabRecord **_records, sal_Int32 _numRecords)
47 {
48 	/* Variables passed in... */
49 	header = _header;
50 	recordsSize = _numRecords;
51 	currentRecord = _numRecords;
52 	records = _records;
53 	addressBook = _addressBook;
54 
55 	/* Default variables... */
56 	recordType = kABPersonRecordType;
57 
58 	/* Variables constructed... */
59 	bootstrap_CF_types();
60 	bootstrap_requiredProperties();
61 }
62 
63 // -------------------------------------------------------------------------
64 /* Creates a MacabRecords from another: copies the length, name, and
65  * address book of the original, but the header or the records themselves.
66  * The idea is that the only reason to copy a MacabRecords is to create
67  * a filtered version of it, which can have the same length (to avoid
68  * resizing) and will work from the same base addressbook, but might have
69  * entirey different values and even (possibly in the future) a different
70  * header.
71  */
72 MacabRecords::MacabRecords(const MacabRecords *_copy)
73 {
74 	/* Variables passed in... */
75 	recordsSize = _copy->recordsSize;
76 	addressBook = _copy->addressBook;
77 	m_sName = _copy->m_sName;
78 
79 	/* Default variables... */
80 	currentRecord = 0;
81 	header = NULL;
82 	records = new MacabRecord *[recordsSize];
83 	recordType = kABPersonRecordType;
84 
85 	/* Variables constructed... */
86 	bootstrap_CF_types();
87 	bootstrap_requiredProperties();
88 }
89 
90 // -------------------------------------------------------------------------
91 MacabRecords::MacabRecords(const ABAddressBookRef _addressBook)
92 {
93 	/* Variables passed in... */
94 	addressBook = _addressBook;
95 
96 	/* Default variables... */
97 	recordsSize = 0;
98 	currentRecord = 0;
99 	records = NULL;
100 	header = NULL;
101 	recordType = kABPersonRecordType;
102 
103 	/* Variables constructed... */
104 	bootstrap_CF_types();
105 	bootstrap_requiredProperties();
106 }
107 
108 // -------------------------------------------------------------------------
109 void MacabRecords::initialize()
110 {
111 
112 	/* Make sure everything is NULL before initializing. (We usually just
113 	 * initialize after we use the constructor that takes only a
114 	 * MacabAddressBook, so these variables will most likely already be
115 	 * NULL.
116 	 */
117 	if(records != NULL)
118 	{
119 		sal_Int32 i;
120 
121 		for(i = 0; i < recordsSize; i++)
122 			delete records[i];
123 
124 		delete [] records;
125 	}
126 
127 	if(header != NULL)
128 		delete header;
129 
130 	/* We can handle both default record Address Book record types in
131 	 * this method, though only kABPersonRecordType is ever used.
132 	 */
133 	CFArrayRef allRecords;
134 	if(CFStringCompare(recordType, kABPersonRecordType, 0) == kCFCompareEqualTo)
135 		allRecords = ABCopyArrayOfAllPeople(addressBook);
136 	else
137 		allRecords = ABCopyArrayOfAllGroups(addressBook);
138 
139 	ABRecordRef record;
140 	sal_Int32 i;
141 	recordsSize = (sal_Int32) CFArrayGetCount(allRecords);
142 	records = new MacabRecord *[recordsSize];
143 
144 	/* First, we create the header... */
145 	header = createHeaderForRecordType(allRecords, recordType);
146 
147 	/* Then, we create each of the records... */
148 	for(i = 0; i < recordsSize; i++)
149 	{
150 		record = (ABRecordRef) CFArrayGetValueAtIndex(allRecords, i);
151 		records[i] = createMacabRecord(record, header, recordType);
152 	}
153 	currentRecord = recordsSize;
154 
155 	CFRelease(allRecords);
156 }
157 
158 // -------------------------------------------------------------------------
159 MacabRecords::~MacabRecords()
160 {
161 }
162 
163 // -------------------------------------------------------------------------
164 void MacabRecords::setHeader(MacabHeader *_header)
165 {
166 	if(header != NULL)
167 		delete header;
168 	header = _header;
169 }
170 
171 // -------------------------------------------------------------------------
172 MacabHeader *MacabRecords::getHeader() const
173 {
174 	return header;
175 }
176 
177 // -------------------------------------------------------------------------
178 /* Inserts a MacabRecord at a given location. If there is already a
179  * MacabRecord at that location, return it.
180  */
181 MacabRecord *MacabRecords::insertRecord(MacabRecord *_newRecord, const sal_Int32 _location)
182 {
183 	MacabRecord *oldRecord;
184 
185 	/* If the location is greater than the current allocated size of this
186 	 * MacabRecords, allocate more space.
187 	 */
188 	if(_location >= recordsSize)
189 	{
190 		sal_Int32 i;
191 		MacabRecord **newRecordsArray = new MacabRecord *[_location+1];
192 		for(i = 0; i < recordsSize; i++)
193 		{
194 			newRecordsArray[i] = records[i];
195 		}
196 		delete [] records;
197 		records = newRecordsArray;
198 	}
199 
200 	/* Remember: currentRecord refers to one above the highest existing
201 	 * record (i.e., it refers to where to place the next record if a
202 	 * location is not given).
203 	 */
204 	if(_location >= currentRecord)
205 		currentRecord = _location+1;
206 
207 	oldRecord = records[_location];
208 	records[_location] = _newRecord;
209 	return oldRecord;
210 }
211 
212 // -------------------------------------------------------------------------
213 /* Insert a record at the next available place. */
214 void MacabRecords::insertRecord(MacabRecord *_newRecord)
215 {
216 	insertRecord(_newRecord, currentRecord);
217 }
218 
219 // -------------------------------------------------------------------------
220 MacabRecord *MacabRecords::getRecord(const sal_Int32 _location) const
221 {
222 	if(_location >= recordsSize)
223 		return NULL;
224 	return records[_location];
225 }
226 
227 // -------------------------------------------------------------------------
228 macabfield *MacabRecords::getField(const sal_Int32 _recordNumber, const sal_Int32 _columnNumber) const
229 {
230 	if(_recordNumber >= recordsSize)
231 		return NULL;
232 
233 	MacabRecord *record = records[_recordNumber];
234 
235 	if(_columnNumber < 0 || _columnNumber >= record->getSize())
236 		return NULL;
237 
238 	return record->get(_columnNumber);
239 }
240 
241 // -------------------------------------------------------------------------
242 macabfield *MacabRecords::getField(const sal_Int32 _recordNumber, const ::rtl::OUString _columnName) const
243 {
244 	if(header != NULL)
245 	{
246 		sal_Int32 columnNumber = header->getColumnNumber(_columnName);
247 		if(columnNumber == -1)
248 			return NULL;
249 
250 		return getField(_recordNumber, columnNumber);
251 	}
252 	else
253 	{
254 		// error: shouldn't access field with null header!
255 		return NULL;
256 	}
257 }
258 
259 // -------------------------------------------------------------------------
260 sal_Int32 MacabRecords::getFieldNumber(const ::rtl::OUString _columnName) const
261 {
262 	if(header != NULL)
263 		return header->getColumnNumber(_columnName);
264 	else
265 		// error: shouldn't access field with null header!
266 		return -1;
267 }
268 
269 // -------------------------------------------------------------------------
270 /* Create the lcl_CFTypes array -- we need this because there is no
271  * way to get the ABType of an object from the object itself, and the
272  * function ABTypeOfProperty can't handle multiple levels of data
273  * (e.g., it can tell us that "address" is of type
274  * kABDictionaryProperty, but it cannot tell us that all of the keys
275  * and values in the dictionary have type kABStringProperty. On the
276  * other hand, we _can_ get the CFType out of any object.
277  * Unfortunately, all information about CFTypeIDs comes with the
278  * warning that they change between releases, so we build them
279  * ourselves here. (The one that we can't build is for multivalues,
280  * e.g., kABMultiStringProperty. All of these appear to have the
281  * same type: 1, but there is no function that I've found to give
282  * us that dynamically in case that number ever changes.
283  */
284 void MacabRecords::bootstrap_CF_types()
285 {
286 	lcl_CFTypesLength = 6;
287 	lcl_CFTypes = new lcl_CFType[lcl_CFTypesLength];
288 
289 	lcl_CFTypes[0].cf = CFNumberGetTypeID();
290 	lcl_CFTypes[0].ab = kABIntegerProperty;
291 
292 	lcl_CFTypes[1].cf = CFStringGetTypeID();
293 	lcl_CFTypes[1].ab = kABStringProperty;
294 
295 	lcl_CFTypes[2].cf = CFDateGetTypeID();
296 	lcl_CFTypes[2].ab = kABDateProperty;
297 
298 	lcl_CFTypes[3].cf = CFArrayGetTypeID();
299 	lcl_CFTypes[3].ab = kABArrayProperty;
300 
301 	lcl_CFTypes[4].cf = CFDictionaryGetTypeID();
302 	lcl_CFTypes[4].ab = kABDictionaryProperty;
303 
304 	lcl_CFTypes[5].cf = CFDataGetTypeID();
305 	lcl_CFTypes[5].ab = kABDataProperty;
306 }
307 
308 // -------------------------------------------------------------------------
309 /* This is based on the possible fields required in the mail merge template
310  * in sw. If the fields possible there change, it would be optimal to
311  * change these fields as well.
312  */
313 void MacabRecords::bootstrap_requiredProperties()
314 {
315 	numRequiredProperties = 7;
316 	requiredProperties = new CFStringRef[numRequiredProperties];
317 	requiredProperties[0] = kABTitleProperty;
318 	requiredProperties[1] = kABFirstNameProperty;
319 	requiredProperties[2] = kABLastNameProperty;
320 	requiredProperties[3] = kABOrganizationProperty;
321 	requiredProperties[4] = kABAddressProperty;
322 	requiredProperties[5] = kABPhoneProperty;
323 	requiredProperties[6] = kABEmailProperty;
324 }
325 
326 // -------------------------------------------------------------------------
327 /* Create the header for a given record type and a given array of records.
328  * Because the array of records and the record type are given, if you want
329  * to, you can run this method on the members of a group, or on any other
330  * filtered list of people and get a header relevant to them (e.g., if
331  * they only have home addresses, the work address fields won't show up).
332  */
333 MacabHeader *MacabRecords::createHeaderForRecordType(const CFArrayRef _records, const CFStringRef _recordType) const
334 {
335 	/* We have two types of properties for a given record type, nonrequired
336 	 * and required. Required properties are ones that will show up whether
337 	 * or not they are empty. Nonrequired properties will only show up if
338 	 * at least one record in the set has that property filled. The reason
339 	 * is that some properties, like the kABTitleProperty are required by
340 	 * the mail merge wizard (in module sw) but are by default not shown in
341 	 * the Mac OS X address book, so they would be weeded out at this stage
342 	 * and not shown if they were not required.
343 	 *
344 	 * Note: with the addition of required properties, I am not sure that
345 	 * this method still works for kABGroupRecordType (since the required
346 	 * properites are all for kABPersonRecordType).
347 	 *
348 	 * Note: required properties are constructed in the method
349 	 * bootstrap_requiredProperties() (above).
350 	 */
351 	CFArrayRef allProperties = ABCopyArrayOfPropertiesForRecordType(addressBook, _recordType);
352 	CFStringRef *nonRequiredProperties;
353 	sal_Int32 numRecords = (sal_Int32) CFArrayGetCount(_records);
354 	sal_Int32 numProperties = (sal_Int32) CFArrayGetCount(allProperties);
355 	sal_Int32 numNonRequiredProperties = numProperties - numRequiredProperties;
356 
357 	/* While searching through the properties for required properties, these
358 	 * sal_Bools will keep track of what we have found.
359 	 */
360 	sal_Bool bFoundProperty;
361 	sal_Bool bFoundRequiredProperties[numRequiredProperties];
362 
363 
364 	/* We have three MacabHeaders: headerDataForProperty is where we
365 	 * store the result of createHeaderForProperty(), which return a
366 	 * MacabHeader for a single property. lcl_header is where we store
367 	 * the MacabHeader that we are constructing. And, nonRequiredHeader
368 	 * is where we construct the MacabHeader for non-required properties,
369 	 * so that we can sort them before adding them to lcl_header.
370 	 */
371 	MacabHeader *headerDataForProperty;
372 	MacabHeader *lcl_header = new MacabHeader();
373 	MacabHeader *nonRequiredHeader = new MacabHeader();
374 
375 	/* Other variables... */
376 	sal_Int32 i, j, k;
377 	ABRecordRef record;
378 	CFStringRef property;
379 
380 
381 	/* Allocate and initialize... */
382 	nonRequiredProperties = new CFStringRef[numNonRequiredProperties];
383 	k = 0;
384 	for(i = 0; i < numRequiredProperties; i++)
385 		bFoundRequiredProperties[i] = sal_False;
386 
387 	/* Determine the non-required properties... */
388 	for(i = 0; i < numProperties; i++)
389 	{
390 		property = (CFStringRef) CFArrayGetValueAtIndex(allProperties, i);
391 		bFoundProperty = sal_False;
392 		for(j = 0; j < numRequiredProperties; j++)
393 		{
394 			if(CFEqual(property, requiredProperties[j]))
395 			{
396 				bFoundProperty = sal_True;
397 				bFoundRequiredProperties[j] = sal_True;
398 				break;
399 			}
400 		}
401 
402 		if(bFoundProperty == sal_False)
403 		{
404 			/* If we have found too many non-required properties */
405 			if(k == numNonRequiredProperties)
406 			{
407 				k++; // so that the OSL_ENSURE below fails
408 				break;
409 			}
410 			nonRequiredProperties[k] = property;
411 			k++;
412 		}
413 	}
414 
415 	// Somehow, we got too many or too few non-requird properties...
416 	// Most likely, one of the required properties no longer exists, which
417 	// we also test later.
418 	OSL_ENSURE(k == numNonRequiredProperties, "MacabRecords::createHeaderForRecordType: Found an unexpected number of non-required properties");
419 
420 	/* Fill the header with required properties first... */
421 	for(i = 0; i < numRequiredProperties; i++)
422 	{
423 		if(bFoundRequiredProperties[i] == sal_True)
424 		{
425 			/* The order of these matters (we want all address properties
426 			 * before any phone properties, or else things will look weird),
427 			 * so we get all possibilitities for each property, going through
428 			 * each record, and then go onto the next property.
429 			 * (Note: the reason that we have to go through all records
430 			 * in the first place is that properties like address, phone, and
431 			 * e-mail are multi-value properties with an unknown number of
432 			 * values. A user could specify thirteen different kinds of
433 			 * e-mail addresses for one of her or his contacts, and we need to
434 			 * get all of them.
435 			 */
436 			for(j = 0; j < numRecords; j++)
437 			{
438 				record = (ABRecordRef) CFArrayGetValueAtIndex(_records, j);
439 				headerDataForProperty = createHeaderForProperty(record,requiredProperties[i],_recordType,sal_True);
440 				if(headerDataForProperty != NULL)
441 				{
442 					(*lcl_header) += headerDataForProperty;
443 					delete headerDataForProperty;
444 				}
445 			}
446 		}
447 		else
448 		{
449 			// Couldn't find a required property...
450 			OSL_ENSURE(false, ::rtl::OString("MacabRecords::createHeaderForRecordType: could not find required property: ") +
451 						::rtl::OUStringToOString(CFStringToOUString(requiredProperties[i]), RTL_TEXTENCODING_ASCII_US));
452 		}
453 	}
454 
455 	/* And now, non-required properties... */
456 	for(i = 0; i < numRecords; i++)
457 	{
458 		record = (ABRecordRef) CFArrayGetValueAtIndex(_records, i);
459 
460 		for(j = 0; j < numNonRequiredProperties; j++)
461 		{
462 			property = nonRequiredProperties[j];
463 			headerDataForProperty = createHeaderForProperty(record,property,_recordType,sal_False);
464 			if(headerDataForProperty != NULL)
465 			{
466 				(*nonRequiredHeader) += headerDataForProperty;
467 				delete headerDataForProperty;
468 			}
469 		}
470 
471 	}
472 	nonRequiredHeader->sortRecord();
473 
474 	(*lcl_header) += nonRequiredHeader;
475 	delete nonRequiredHeader;
476 
477 	CFRelease(allProperties);
478 	delete [] nonRequiredProperties;
479 
480 	return lcl_header;
481 }
482 
483 // -------------------------------------------------------------------------
484 /* Create a header for a single property. Basically, this method gets
485  * the property's value and type and then calls another method of
486  * the same name to do the dirty work.
487  */
488 MacabHeader *MacabRecords::createHeaderForProperty(const ABRecordRef _record, const CFStringRef _propertyName, const CFStringRef _recordType, const sal_Bool _isPropertyRequired) const
489 {
490 	// local variables
491 	CFStringRef localizedPropertyName;
492 	CFTypeRef propertyValue;
493 	ABPropertyType propertyType;
494 	MacabHeader *result;
495 
496 	/* Get the property's value */
497 	propertyValue = ABRecordCopyValue(_record,_propertyName);
498 	if(propertyValue == NULL && _isPropertyRequired == sal_False)
499 		return NULL;
500 
501 	propertyType = ABTypeOfProperty(addressBook, _recordType, _propertyName);
502 	localizedPropertyName = ABCopyLocalizedPropertyOrLabel(_propertyName);
503 
504 	result = createHeaderForProperty(propertyType, propertyValue, localizedPropertyName);
505 
506 	if(propertyValue != NULL)
507 		CFRelease(propertyValue);
508 
509 	return result;
510 }
511 
512 // -------------------------------------------------------------------------
513 /* Create a header for a single property. This method is recursive
514  * because a single property might contain several sub-properties that
515  * we also want to treat singly.
516  */
517 MacabHeader *MacabRecords::createHeaderForProperty(const ABPropertyType _propertyType, const CFTypeRef _propertyValue, const CFStringRef _propertyName) const
518 {
519 	macabfield **headerNames = NULL;
520 	sal_Int32 length = 0;
521 
522 	switch(_propertyType)
523 	{
524 		/* Scalars */
525 		case kABStringProperty:
526 		case kABRealProperty:
527 		case kABIntegerProperty:
528 		case kABDateProperty:
529 			length = 1;
530 			headerNames = new macabfield *[1];
531 			headerNames[0] = new macabfield;
532 			headerNames[0]->value = _propertyName;
533 			headerNames[0]->type = _propertyType;
534 			break;
535 
536 		/* Multi-scalars */
537 		case kABMultiIntegerProperty:
538 		case kABMultiDateProperty:
539 		case kABMultiStringProperty:
540 		case kABMultiRealProperty:
541 		case kABMultiDataProperty:
542 			/* For non-scalars, we can only get more information if the property
543 			 * actually exists.
544 			 */
545 			if(_propertyValue != NULL)
546 			{
547 			sal_Int32 i;
548 
549 			sal_Int32 multiLength = ABMultiValueCount((ABMutableMultiValueRef) _propertyValue);
550 			CFStringRef multiLabel, localizedMultiLabel;
551 			::rtl::OUString multiLabelString;
552 			::rtl::OUString multiPropertyString;
553 			::rtl::OUString headerNameString;
554 			ABPropertyType multiType = (ABPropertyType) (ABMultiValuePropertyType((ABMutableMultiValueRef) _propertyValue) - 0x100);
555 
556 			length = multiLength;
557 			headerNames = new macabfield *[multiLength];
558 			multiPropertyString = CFStringToOUString(_propertyName);
559 
560 			/* Go through each element, and - since each element is a scalar -
561 			 * just create a new macabfield for it.
562 			 */
563 			for(i = 0; i < multiLength; i++)
564 			{
565 				multiLabel = ABMultiValueCopyLabelAtIndex((ABMutableMultiValueRef) _propertyValue, i);
566 				localizedMultiLabel = ABCopyLocalizedPropertyOrLabel(multiLabel);
567 				multiLabelString = CFStringToOUString(localizedMultiLabel);
568 				CFRelease(multiLabel);
569 				CFRelease(localizedMultiLabel);
570 				headerNameString = multiPropertyString + ::rtl::OUString::createFromAscii(": ") + fixLabel(multiLabelString);
571 				headerNames[i] = new macabfield;
572 				headerNames[i]->value = OUStringToCFString(headerNameString);
573 				headerNames[i]->type = multiType;
574 			}
575 			}
576 			break;
577 
578 		/* Multi-array or dictionary */
579 		case kABMultiArrayProperty:
580 		case kABMultiDictionaryProperty:
581 			/* For non-scalars, we can only get more information if the property
582 			 * actually exists.
583 			 */
584 			if(_propertyValue != NULL)
585 			{
586 				sal_Int32 i,j,k;
587 
588 				// Total number of multi-array or multi-dictionary elements.
589 				sal_Int32 multiLengthFirstLevel = ABMultiValueCount((ABMutableMultiValueRef) _propertyValue);
590 
591 				/* Total length, including the length of each element (e.g., if
592 				 * this multi-dictionary contains three dictionaries, and each
593 				 * dictionary has four elements, this variable will be twelve,
594 				 * whereas multiLengthFirstLevel will be three.
595 				 */
596 				sal_Int32 multiLengthSecondLevel = 0;
597 
598 				CFStringRef multiLabel, localizedMultiLabel;
599 				CFTypeRef multiValue;
600 				::rtl::OUString multiLabelString;
601 				::rtl::OUString multiPropertyString;
602 				MacabHeader **multiHeaders = new MacabHeader *[multiLengthFirstLevel];
603 				ABPropertyType multiType = (ABPropertyType) (ABMultiValuePropertyType((ABMutableMultiValueRef) _propertyValue) - 0x100);
604 
605 				multiPropertyString = CFStringToOUString(_propertyName);
606 
607 				/* Go through each element - since each element can really
608 				 * contain anything, we run this method again on each element
609 				 * and store the resulting MacabHeader (in the multiHeaders
610 				 * array). Then, all we'll have to do is combine the MacabHeaders
611 				 * into a single one.
612 				 */
613 				for(i = 0; i < multiLengthFirstLevel; i++)
614 				{
615 					/* label */
616 					multiLabel = ABMultiValueCopyLabelAtIndex((ABMutableMultiValueRef) _propertyValue, i);
617 					multiValue = ABMultiValueCopyValueAtIndex((ABMutableMultiValueRef) _propertyValue, i);
618 					if(multiValue && multiLabel)
619 					{
620 						localizedMultiLabel = ABCopyLocalizedPropertyOrLabel(multiLabel);
621 						multiLabelString = multiPropertyString + ::rtl::OUString::createFromAscii(": ") + fixLabel(CFStringToOUString(localizedMultiLabel));
622 						CFRelease(multiLabel);
623 						CFRelease(localizedMultiLabel);
624 						multiLabel = OUStringToCFString(multiLabelString);
625 						multiHeaders[i] = createHeaderForProperty(multiType, multiValue, multiLabel);
626 						if (!multiHeaders[i])
627 							multiHeaders[i] = new MacabHeader();
628 						multiLengthSecondLevel += multiHeaders[i]->getSize();
629 					}
630 					else
631 					{
632 						multiHeaders[i] = new MacabHeader();
633 					}
634 					if(multiValue)
635 						CFRelease(multiValue);
636 				}
637 
638 				/* We now have enough information to create our final MacabHeader.
639 				 * We go through each field of each header and add it to the
640 				 * headerNames array (which is what is used below to construct
641 				 * the MacabHeader we return).
642 				 */
643 				length = multiLengthSecondLevel;
644 				headerNames = new macabfield *[multiLengthSecondLevel];
645 
646 				for(i = 0, j = 0, k = 0; i < multiLengthSecondLevel; i++,k++)
647 				{
648 					while(multiHeaders[j]->getSize() == k)
649 					{
650 						j++;
651 						k = 0;
652 					}
653 
654 					headerNames[i] = multiHeaders[j]->copy(k);
655 				}
656 				for(i = 0; i < multiLengthFirstLevel; i++)
657 					delete multiHeaders[i];
658 
659 				delete [] multiHeaders;
660 			}
661 			break;
662 
663 		/* Dictionary */
664 		case kABDictionaryProperty:
665 			/* For non-scalars, we can only get more information if the property
666 			 * actually exists.
667 			 */
668 			if(_propertyValue != NULL)
669 			{
670 			/* Assume all keys are strings */
671 			sal_Int32 numRecords = (sal_Int32) CFDictionaryGetCount((CFDictionaryRef) _propertyValue);
672 
673 			/* The only method for getting info out of a CFDictionary, of both
674 			 * keys and values, is to all of them all at once, so these
675 			 * variables will hold them.
676 			 */
677 			CFStringRef *dictKeys;
678 			CFTypeRef *dictValues;
679 
680 			sal_Int32 i,j,k;
681 			::rtl::OUString dictKeyString, propertyNameString;
682 			ABPropertyType dictType;
683 			MacabHeader **dictHeaders = new MacabHeader *[numRecords];
684 			::rtl::OUString dictLabelString;
685 			CFStringRef dictLabel, localizedDictKey;
686 
687 			/* Get the keys and values */
688 			dictKeys = (CFStringRef *) malloc(sizeof(CFStringRef)*numRecords);
689 			dictValues = (CFTypeRef *) malloc(sizeof(CFTypeRef)*numRecords);
690 			CFDictionaryGetKeysAndValues((CFDictionaryRef) _propertyValue, (const void **) dictKeys, (const void **) dictValues);
691 
692 			propertyNameString = CFStringToOUString(_propertyName);
693 
694 			length = 0;
695 			/* Go through each element - assuming that the key is a string but
696 			 * that the value could be anything. Since the value could be
697 			 * anything, we can't assume that it is scalar (it could even be
698 			 * another dictionary), so we attempt to get its type using
699 			 * the method getABTypeFromCFType and then run this method
700 			 * recursively on that element, storing the MacabHeader that
701 			 * results. Then, we just combine all of the MacabHeaders into
702 			 * one.
703 			 */
704 			for(i = 0; i < numRecords; i++)
705 			{
706 				dictType = (ABPropertyType) getABTypeFromCFType( CFGetTypeID(dictValues[i]) );
707 				localizedDictKey = ABCopyLocalizedPropertyOrLabel(dictKeys[i]);
708 				dictKeyString = CFStringToOUString(localizedDictKey);
709 				dictLabelString = propertyNameString + ::rtl::OUString::createFromAscii(": ") + fixLabel(dictKeyString);
710 				dictLabel = OUStringToCFString(dictLabelString);
711 				dictHeaders[i] = createHeaderForProperty(dictType, dictValues[i], dictLabel);
712 				if (!dictHeaders[i])
713 					dictHeaders[i] = new MacabHeader();
714 				length += dictHeaders[i]->getSize();
715 				CFRelease(dictLabel);
716 				CFRelease(localizedDictKey);
717 			}
718 
719 			/* Combine all of the macabfields in each MacabHeader into the
720 			 * headerNames array, which (at the end of this method) is used
721 			 * to create the MacabHeader that is returned.
722 			 */
723 			headerNames = new macabfield *[length];
724 			for(i = 0, j = 0, k = 0; i < length; i++,k++)
725 			{
726 				while(dictHeaders[j]->getSize() == k)
727 				{
728 					j++;
729 					k = 0;
730 				}
731 
732 				headerNames[i] = dictHeaders[j]->copy(k);
733 			}
734 
735 			for(i = 0; i < numRecords; i++)
736 				delete dictHeaders[i];
737 
738 			delete [] dictHeaders;
739 			free(dictKeys);
740 			free(dictValues);
741 			}
742 			break;
743 
744 		/* Array */
745 		case kABArrayProperty:
746 			/* For non-scalars, we can only get more information if the property
747 			 * actually exists.
748 			 */
749 			if(_propertyValue != NULL)
750 			{
751 				sal_Int32 arrLength = (sal_Int32) CFArrayGetCount( (CFArrayRef) _propertyValue);
752 				sal_Int32 i,j,k;
753 				CFTypeRef arrValue;
754 				ABPropertyType arrType;
755 				MacabHeader **arrHeaders = new MacabHeader *[arrLength];
756 				::rtl::OUString propertyNameString = CFStringToOUString(_propertyName);
757 				::rtl::OUString arrLabelString;
758 				CFStringRef arrLabel;
759 
760 				length = 0;
761 				/* Go through each element - since the elements here do not have
762 				 * unique keys like the ones in dictionaries, we create a unique
763 				 * key out of the id of the element in the array (the first
764 				 * element gets a 0 plopped onto the end of it, the second a 1...
765 				 * As with dictionaries, the elements could be anything, including
766 				 * another array, so we have to run this method recursively on
767 				 * each element, storing the resulting MacabHeader into an array,
768 				 * which we then combine into one MacabHeader that is returned.
769 				 */
770 				for(i = 0; i < arrLength; i++)
771 				{
772 					arrValue = (CFTypeRef) CFArrayGetValueAtIndex( (CFArrayRef) _propertyValue, i);
773 					arrType = (ABPropertyType) getABTypeFromCFType( CFGetTypeID(arrValue) );
774 					arrLabelString = propertyNameString + ::rtl::OUString::valueOf(i);
775 					arrLabel = OUStringToCFString(arrLabelString);
776 					arrHeaders[i] = createHeaderForProperty(arrType, arrValue, arrLabel);
777 					if (!arrHeaders[i])
778 						arrHeaders[i] = new MacabHeader();
779 					length += arrHeaders[i]->getSize();
780 					CFRelease(arrLabel);
781 				}
782 
783 				headerNames = new macabfield *[length];
784 				for(i = 0, j = 0, k = 0; i < length; i++,k++)
785 				{
786 					while(arrHeaders[j]->getSize() == k)
787 					{
788 						j++;
789 						k = 0;
790 					}
791 
792 					headerNames[i] = arrHeaders[j]->copy(k);
793 				}
794 				for(i = 0; i < arrLength; i++)
795 					delete arrHeaders[i];
796 
797 				delete [] arrHeaders;
798 			}
799 			break;
800 
801 			default:
802 				break;
803 
804 	}
805 
806 	/* If we succeeded at adding elements to the headerNames array, then
807 	 * length will no longer be 0. If it is, create a new MacabHeader
808 	 * out of the headerNames (after weeding out duplicate headers), and
809 	 * then return the result. If the length is still 0, return NULL: we
810 	 * failed to create a MacabHeader out of this property.
811 	 */
812 	if(length != 0)
813 	{
814 		manageDuplicateHeaders(headerNames, length);
815 		MacabHeader *headerResult = new MacabHeader(length, headerNames);
816 		delete [] headerNames;
817 		return headerResult;
818 	}
819 	else
820 		return NULL;
821 }
822 
823 // -------------------------------------------------------------------------
824 void MacabRecords::manageDuplicateHeaders(macabfield **_headerNames, const sal_Int32 _length) const
825 {
826 	/* If we have two cases of, say, phone: home, this makes it:
827 	 * phone: home (1)
828 	 * phone: home (2)
829 	 */
830 	sal_Int32 i, j;
831 	sal_Int32 count;
832 	for(i = _length-1; i >= 0; i--)
833 	{
834 		count = 1;
835 		for( j = i-1; j >= 0; j--)
836 		{
837 			if(CFEqual(_headerNames[i]->value, _headerNames[j]->value))
838 			{
839 				count++;
840 			}
841 		}
842 
843 		// duplicate!
844 		if(count != 1)
845 		{
846 			// There is probably a better way to do this...
847 			::rtl::OUString newName = CFStringToOUString((CFStringRef) _headerNames[i]->value);
848 			CFRelease(_headerNames[i]->value);
849 			newName += ::rtl::OUString::createFromAscii(" (") + ::rtl::OUString::valueOf(count) + ::rtl::OUString::createFromAscii(")");
850 			_headerNames[i]->value = OUStringToCFString(newName);
851 		}
852 	}
853 }
854 
855 // -------------------------------------------------------------------------
856 /* Create a MacabRecord out of an ABRecord, using a given MacabHeader and
857  * the record's type. We go through each property for this record type
858  * then process it much like we processed the header (above), with two
859  * exceptions: if we come upon something not in the header, we ignore it
860  * (it's something we don't want to add), and once we find a corresponding
861  * location in the header, we store the property and the property type in
862  * a macabfield. (For the header, we stored the property type and the name
863  * of the property as a CFString.)
864  */
865 MacabRecord *MacabRecords::createMacabRecord(const ABRecordRef _abrecord, const MacabHeader *_header, const CFStringRef _recordType) const
866 {
867 	/* The new record that we will create... */
868 	MacabRecord *macabRecord = new MacabRecord(_header->getSize());
869 
870 	CFArrayRef recordProperties = ABCopyArrayOfPropertiesForRecordType(addressBook, _recordType);
871 	sal_Int32 numProperties = (sal_Int32) CFArrayGetCount(recordProperties);
872 
873 	sal_Int32 i;
874 
875 	CFTypeRef propertyValue;
876 	ABPropertyType propertyType;
877 
878 	CFStringRef propertyName, localizedPropertyName;
879 	::rtl::OUString propertyNameString;
880 	for(i = 0; i < numProperties; i++)
881 	{
882 		propertyName = (CFStringRef) CFArrayGetValueAtIndex(recordProperties, i);
883 		localizedPropertyName = ABCopyLocalizedPropertyOrLabel(propertyName);
884 		propertyNameString = CFStringToOUString(localizedPropertyName);
885 		CFRelease(localizedPropertyName);
886 
887 		/* Get the property's value */
888 		propertyValue = ABRecordCopyValue(_abrecord,propertyName);
889 		if(propertyValue != NULL)
890 		{
891 			propertyType = ABTypeOfProperty(addressBook, _recordType, propertyName);
892 			if(propertyType != kABErrorInProperty)
893 				insertPropertyIntoMacabRecord(propertyType, macabRecord, _header, propertyNameString, propertyValue);
894 
895 			CFRelease(propertyValue);
896 		}
897 	}
898 	CFRelease(recordProperties);
899 	return macabRecord;
900 }
901 
902 // -------------------------------------------------------------------------
903 /* Inserts a given property into a MacabRecord. This method calls another
904  * method by the same name after getting the property type (it only
905  * receives the property value). It is called when we aren't given the
906  * property's type already.
907  */
908 void MacabRecords::insertPropertyIntoMacabRecord(MacabRecord *_abrecord, const MacabHeader *_header, const ::rtl::OUString _propertyName, const CFTypeRef _propertyValue) const
909 {
910 	CFTypeID cf_type = CFGetTypeID(_propertyValue);
911 	ABPropertyType ab_type = getABTypeFromCFType( cf_type );
912 
913 	if(ab_type != kABErrorInProperty)
914 		insertPropertyIntoMacabRecord(ab_type, _abrecord, _header, _propertyName, _propertyValue);
915 }
916 
917 // -------------------------------------------------------------------------
918 /* Inserts a given property into a MacabRecord. This method is recursive
919  * because properties can contain many sub-properties.
920  */
921 void MacabRecords::insertPropertyIntoMacabRecord(const ABPropertyType _propertyType, MacabRecord *_abrecord, const MacabHeader *_header, const ::rtl::OUString _propertyName, const CFTypeRef _propertyValue) const
922 {
923 	/* If there is no value, return */
924 	if(_propertyValue == NULL)
925 		return;
926 
927 	/* The main switch statement */
928 	switch(_propertyType)
929 	{
930 		/* Scalars */
931 		case kABStringProperty:
932 		case kABRealProperty:
933 		case kABIntegerProperty:
934 		case kABDateProperty:
935 		{
936 			/* Only scalars actually insert a property into the MacabRecord.
937 			 * In all other cases, this method is called recursively until a
938 			 * scalar type, an error, or an unknown type are found.
939 			 * Because of that, the following checks only occur for this type.
940 			 * We store whether we have successfully placed this property
941 			 * into the MacabRecord (or whether an unrecoverable error occured).
942 			 * Then, we try over and over again to place the property into the
943 			 * record. There are three possible results:
944 			 * 1) Success!
945 			 * 2) There is already a property stored at the column of this name,
946 			 * in which case we have a duplicate header (see the method
947 			 * manageDuplicateHeaders()). If that is the case, we add an ID
948 			 * to the end of the column name in the same format as we do in
949 			 * manageDuplicateHeaders() and try again.
950 			 * 3) No column of this name exists in the header. In this case,
951 			 * there is nothing we can do: we have failed to place this
952 			 * property into the record.
953 			 */
954 			sal_Bool bPlaced = sal_False;
955 			::rtl::OUString columnName = ::rtl::OUString(_propertyName);
956 			sal_Int32 i = 1;
957 
958 			// A big safeguard to prevent two fields from having the same name.
959 			while(bPlaced != sal_True)
960 			{
961 				sal_Int32 columnNumber = _header->getColumnNumber(columnName);
962 				bPlaced = sal_True;
963 				if(columnNumber != -1)
964 				{
965 					// collision! A property already exists here!
966 					if(_abrecord->get(columnNumber) != NULL)
967 					{
968 						bPlaced = sal_False;
969 						i++;
970 						columnName = ::rtl::OUString(_propertyName) + ::rtl::OUString::createFromAscii(" (") + ::rtl::OUString::valueOf(i) + ::rtl::OUString::createFromAscii(")");
971 					}
972 
973 					// success!
974 					else
975 					{
976 						_abrecord->insertAtColumn(_propertyValue, _propertyType, columnNumber);
977 					}
978 				}
979 			}
980 		}
981 		break;
982 
983 		/* Array */
984 		case kABArrayProperty:
985 			{
986 				/* An array is basically just a list of anything, so all we do
987 				 * is go through the array, and rerun this method recursively
988 				 * on each element.
989 				 */
990 				sal_Int32 arrLength = (sal_Int32) CFArrayGetCount( (CFArrayRef) _propertyValue);
991 				sal_Int32 i;
992 				const void *arrValue;
993 				::rtl::OUString newPropertyName;
994 
995 				/* Going through each element... */
996 				for(i = 0; i < arrLength; i++)
997 				{
998 					arrValue = CFArrayGetValueAtIndex( (CFArrayRef) _propertyValue, i);
999 					newPropertyName = _propertyName + ::rtl::OUString::valueOf(i);
1000 					insertPropertyIntoMacabRecord(_abrecord, _header, newPropertyName, arrValue);
1001 					CFRelease(arrValue);
1002 				}
1003 
1004 			}
1005 			break;
1006 
1007 		/* Dictionary */
1008 		case kABDictionaryProperty:
1009 			{
1010 				/* A dictionary is basically a hashmap. Technically, it can
1011 				 * hold any object as a key and any object as a value.
1012 				 * For our case, we assume that the key is a string (so that
1013 				 * we can use the key to get the column name and match it against
1014 				 * the header), but we don't assume anything about the value, so
1015 				 * we run this method recursively (or, rather, we run the version
1016 				 * of this method for when we don't know the object's type) until
1017 				 * we hit a scalar value.
1018 				 */
1019 
1020 				sal_Int32 numRecords = (sal_Int32) CFDictionaryGetCount((CFDictionaryRef) _propertyValue);
1021 				::rtl::OUString dictKeyString;
1022 				sal_Int32 i;
1023 				::rtl::OUString newPropertyName;
1024 
1025 				/* Unfortunately, the only way to get both keys and values out
1026 				 * of a dictionary in Carbon is to get them all at once, so we
1027 				 * do that.
1028 				 */
1029 				CFStringRef *dictKeys;
1030 				CFStringRef localizedDictKey;
1031 				CFTypeRef *dictValues;
1032 				dictKeys = (CFStringRef *) malloc(sizeof(CFStringRef)*numRecords);
1033 				dictValues = (CFTypeRef *) malloc(sizeof(CFTypeRef)*numRecords);
1034 				CFDictionaryGetKeysAndValues((CFDictionaryRef) _propertyValue, (const void **) dictKeys, (const void **) dictValues);
1035 
1036 				/* Going through each element... */
1037 				for(i = 0; i < numRecords; i++)
1038 				{
1039 					localizedDictKey = ABCopyLocalizedPropertyOrLabel(dictKeys[i]);
1040 					dictKeyString = CFStringToOUString(localizedDictKey);
1041 					CFRelease(localizedDictKey);
1042 					newPropertyName = _propertyName + ::rtl::OUString::createFromAscii(": ") + fixLabel(dictKeyString);
1043 					insertPropertyIntoMacabRecord(_abrecord, _header, newPropertyName, dictValues[i]);
1044 				}
1045 
1046 				free(dictKeys);
1047 				free(dictValues);
1048 			}
1049 			break;
1050 
1051 		/* Multivalue */
1052 		case kABMultiIntegerProperty:
1053 		case kABMultiDateProperty:
1054 		case kABMultiStringProperty:
1055 		case kABMultiRealProperty:
1056 		case kABMultiDataProperty:
1057 		case kABMultiDictionaryProperty:
1058 		case kABMultiArrayProperty:
1059 			{
1060 				/* All scalar multivalues are handled in the same way. Each element
1061 				 * is a label and a value. All labels are strings
1062 				 * (kABStringProperty), and all values have the same type
1063 				 * (which is the type of the multivalue minus 255, or as
1064 				 * Carbon's list of property types has it, minus 0x100.
1065 				 * We just get the correct type, then go through each element
1066 				 * and get the label and value and print them in a list.
1067 				 */
1068 
1069 				sal_Int32 i;
1070 				sal_Int32 multiLength = ABMultiValueCount((ABMutableMultiValueRef) _propertyValue);
1071 				CFStringRef multiLabel, localizedMultiLabel;
1072 				CFTypeRef multiValue;
1073 				::rtl::OUString multiLabelString, newPropertyName;
1074 				ABPropertyType multiType = (ABPropertyType) (ABMultiValuePropertyType((ABMutableMultiValueRef) _propertyValue) - 0x100);
1075 
1076 				/* Go through each element... */
1077 				for(i = 0; i < multiLength; i++)
1078 				{
1079 					/* Label and value */
1080 					multiLabel = ABMultiValueCopyLabelAtIndex((ABMutableMultiValueRef) _propertyValue, i);
1081 					multiValue = ABMultiValueCopyValueAtIndex((ABMutableMultiValueRef) _propertyValue, i);
1082 
1083 					localizedMultiLabel = ABCopyLocalizedPropertyOrLabel(multiLabel);
1084 					multiLabelString = CFStringToOUString(localizedMultiLabel);
1085 					newPropertyName = _propertyName + ::rtl::OUString::createFromAscii(": ") + fixLabel(multiLabelString);
1086 					insertPropertyIntoMacabRecord(multiType, _abrecord, _header, newPropertyName, multiValue);
1087 
1088 					/* free our variables */
1089 					CFRelease(multiLabel);
1090 					CFRelease(localizedMultiLabel);
1091 					CFRelease(multiValue);
1092 				}
1093 			}
1094 			break;
1095 
1096 		/* Unhandled types */
1097 		case kABErrorInProperty:
1098 		case kABDataProperty:
1099 		default:
1100 			/* An error, as far as I have seen, only shows up as a type
1101 			 * returned by a function for dictionaries when the dictionary
1102 			 * holds many types of values. Since we do not use that function,
1103 			 * it shouldn't come up. I have yet to see the kABDataProperty,
1104 			 * and I am not sure how to represent it as a string anyway,
1105 			 * since it appears to just be a bunch of bytes. Assumably, if
1106 			 * these bytes made up a string, the type would be
1107 			 * kABStringProperty. I think that this is used when we are not
1108 			 * sure what the type is (e.g., it could be a string or a number).
1109 			 * That being the case, I still don't know how to represent it.
1110 			 * And, default should never come up, since we've exhausted all
1111 			 * of the possible types for ABPropertyType, but... just in case.
1112 			 */
1113 			break;
1114 	}
1115 
1116 }
1117 
1118 // -------------------------------------------------------------------------
1119 ABPropertyType MacabRecords::getABTypeFromCFType(const CFTypeID cf_type ) const
1120 {
1121 	sal_Int32 i;
1122 	for(i = 0; i < lcl_CFTypesLength; i++)
1123 	{
1124 		/* A match! */
1125 		if(lcl_CFTypes[i].cf == (sal_Int32) cf_type)
1126 		{
1127 			return (ABPropertyType) lcl_CFTypes[i].ab;
1128 		}
1129 	}
1130 	return kABErrorInProperty;
1131 }
1132 
1133 // -------------------------------------------------------------------------
1134 sal_Int32 MacabRecords::size() const
1135 {
1136 	return currentRecord;
1137 }
1138 
1139 // -------------------------------------------------------------------------
1140 MacabRecords *MacabRecords::begin()
1141 {
1142 	return this;
1143 }
1144 
1145 // -------------------------------------------------------------------------
1146 MacabRecords::iterator::iterator ()
1147 {
1148 }
1149 
1150 // -------------------------------------------------------------------------
1151 MacabRecords::iterator::~iterator ()
1152 {
1153 }
1154 
1155 // -------------------------------------------------------------------------
1156 void MacabRecords::iterator::operator= (MacabRecords *_records)
1157 {
1158 	id = 0;
1159 	records = _records;
1160 }
1161 
1162 // -------------------------------------------------------------------------
1163 void MacabRecords::iterator::operator++ ()
1164 {
1165 	id++;
1166 }
1167 
1168 // -------------------------------------------------------------------------
1169 sal_Bool MacabRecords::iterator::operator!= (const sal_Int32 i) const
1170 {
1171 	return(id != i);
1172 }
1173 
1174 // -------------------------------------------------------------------------
1175 sal_Bool MacabRecords::iterator::operator== (const sal_Int32 i) const
1176 {
1177 	return(id == i);
1178 }
1179 
1180 // -------------------------------------------------------------------------
1181 MacabRecord *MacabRecords::iterator::operator* () const
1182 {
1183 	return records->getRecord(id);
1184 }
1185 
1186 // -------------------------------------------------------------------------
1187 sal_Int32 MacabRecords::end() const
1188 {
1189 	return currentRecord;
1190 }
1191 
1192 // -------------------------------------------------------------------------
1193 void MacabRecords::swap(const sal_Int32 _id1, const sal_Int32 _id2)
1194 {
1195 	MacabRecord *swapRecord = records[_id1];
1196 
1197 	records[_id1] = records[_id2];
1198 	records[_id2] = swapRecord;
1199 }
1200 
1201 // -------------------------------------------------------------------------
1202 void MacabRecords::setName(const ::rtl::OUString _sName)
1203 {
1204 	m_sName = _sName;
1205 }
1206 
1207 // -------------------------------------------------------------------------
1208 ::rtl::OUString MacabRecords::getName() const
1209 {
1210 	return m_sName;
1211 }
1212 
1213