public Contact GetCanonicalContact(PIMPersonalInfo pim, PIMNumbers num, IList<PIMAddresses> adr)
		{
			if (pim == null)
				return null;

			Contact contact = new Contact();

			if (pim.FormalName != null)
			{
				string[] names = pim.FormalName.Split(new char[] { ' ' });

				if (pim.FirstName == null && pim.LastName == null && pim.MiddleName == null)
				{
					if (names.Length > 2)
						pim.FirstName = names[0];
					else if (names.Length == 2)
						pim.FirstName = names[1];
					else if (names.Length > 0)
						pim.FirstName = names[0];

					if (names.Length == 3)
						pim.MiddleName = names[1];
					else if (names.Length > 3)
						pim.MiddleName = names[names.Length - 2];

					if (names.Length >= 3)
						pim.LastName = names[2];
					else if (names.Length > 1)
						pim.LastName = names[0];
				}
			}

			Name name = new Name(
				pim.FormalName,
				pim.GivenNamePronunciation, 
				null,
				pim.Title,
				pim.FirstName,
				pim.MiddleName,
				pim.LastName,
				null,
				pim.Suffix,
				pim.Nick);

			name.FormattedName = pim.LastName;
			if (name.FormattedName != null &&
				name.FormattedName != "")
				name.FormattedName += " ";
			name.FormattedName += pim.FirstName;
			if (name.FormattedName != null &&
				name.FormattedName != "")
				name.FormattedName += " ";
			name.FormattedName += pim.MiddleName;
			name.FormattedName = name.FormattedName.Trim();

			contact.Names.Add(name);

			PhoneNumber phone = null;
			
			if (num.Mobile.Count > 0)
			{
				foreach (string ph in num.Mobile) {
					phone = new PhoneNumber(ph);
					contact.PhoneNumbers.Add(phone, PhoneLabels.Cellular);
				}
			}

			if (num.MobileHome.Count > 0)
			{
				foreach (string ph in num.MobileHome) {
					phone = new PhoneNumber(ph);
					contact.PhoneNumbers.Add(phone, PhoneLabels.Cellular, PropertyLabels.Personal);
				}
			}

			if (num.MobileWork.Count > 0)
			{
				foreach (string ph in num.MobileWork) {
					phone = new PhoneNumber(ph);
					contact.PhoneNumbers.Add(phone, PhoneLabels.Cellular, PropertyLabels.Business);
				}
			}

			if (num.Telephone.Count > 0)
			{
				foreach (string ph in num.Telephone)
				{
					phone = new PhoneNumber(ph);
					contact.PhoneNumbers.Add(phone, PhoneLabels.Voice);
				}
			}

			if (num.Home.Count > 0)
			{
				foreach (string ph in num.Home)
				{
					phone = new PhoneNumber(ph);
					contact.PhoneNumbers.Add(phone, PhoneLabels.Voice, PropertyLabels.Personal);
				}
			}

			if (num.Work.Count > 0)
			{
				foreach (string ph in num.Work)
				{
					phone = new PhoneNumber(ph);
					contact.PhoneNumbers.Add(phone, PhoneLabels.Voice, PropertyLabels.Business);
				}
			}

			if (num.Fax.Count > 0)
			{
				foreach (string ph in num.Fax)
				{
					phone = new PhoneNumber(ph);
					contact.PhoneNumbers.Add(phone, PhoneLabels.Fax);
				}
			}

			if (num.FaxHome.Count > 0)
			{
				foreach (string ph in num.FaxHome)
				{
					phone = new PhoneNumber(ph);
					contact.PhoneNumbers.Add(phone, PhoneLabels.Fax, PropertyLabels.Personal);
				}
			}

			if (num.FaxWork.Count > 0)
			{
				foreach (string ph in num.FaxWork)
				{
					phone = new PhoneNumber(ph);
					contact.PhoneNumbers.Add(phone, PhoneLabels.Fax, PropertyLabels.Business);
				}
			}

			if (num.Pager.Count > 0)
			{
				foreach (string ph in num.Pager)
				{
					phone = new PhoneNumber(ph);
					contact.PhoneNumbers.Add(phone, PhoneLabels.Pager);
				}
			}

			if (num.Video.Count > 0)
			{
				foreach (string ph in num.Video)
				{
					phone = new PhoneNumber(ph);
					contact.PhoneNumbers.Add(phone, PhoneLabels.Video);
				}
			}

			if (num.VideoHome.Count > 0)
			{
				foreach (string ph in num.VideoHome)
				{
					phone = new PhoneNumber(ph);
					contact.PhoneNumbers.Add(phone, PhoneLabels.Video, PropertyLabels.Personal);
				}
			}

			if (num.VideoWork.Count > 0)
			{
				foreach (string ph in num.VideoWork)
				{
					phone = new PhoneNumber(ph);
					contact.PhoneNumbers.Add(phone, PhoneLabels.Video, PropertyLabels.Business);
				}
			}

			foreach (PIMAddresses a in adr)
			{
				PhysicalAddress phys = new PhysicalAddress(
					a.POBox, a.Street, a.City, a.State, a.PostalCode, a.Country,
					null, null);

				if (a.Private != null)
				{
					contact.Addresses.Add(phys, PropertyLabels.Personal);
				}
				else if (a.Business != null)
				{
					contact.Addresses.Add(phys, PropertyLabels.Business);
				}
				else
				{
					contact.Addresses.Add(phys, PropertyLabels.Personal);
				}
			}

			Position pos = new Position(null, null, pim.Company, null, null, pim.JobTitle, null);
			contact.Positions.Add(pos, PropertyLabels.Business);

			DateTime lastChanged = DateTime.Now;
			contact.Dates.Add(lastChanged, new string[] { "LastModificationTime" });
			
			return contact;
		}
		public void FetchTask()
		{
			mans.Clear();
			contactsByFullName.Clear();

			//if (owner != null)
			//	Dispatcher.BeginInvoke(new VoidInt(owner.SetBarLimits),
			//		FetchCount);

			syncEngine.CurrentTotal += FetchCount;

			if (syncEngine.SyncCanceled)
			{
				this.FetchSem.Release();
				return;
			}

			int hOperHandle = 0;
			int iRet = DAContentAccess.CABeginOperation(m_hContacts, 0, ref hOperHandle);
			if (iRet != Synrc.PCCSErrors.CONA_OK)
			{
				PCCAPIUtils.ShowErrorMessage("CABeginOperation", iRet);
				this.FetchSem.Release();
				return;
			}
			
			for (int k = 0; k < caIDList.iUIDCount; k++)
			{
				//if (owner != null && !quiet)
				//	Dispatcher.BeginInvoke(new VoidString(owner.IncBarPosition), "Loading" /*+ " " + this.Name*/);

				if (owner != null)
				{
					Dispatcher.Invoke(new SyncProgressEventHandler(owner.Progress), this,
						"Loading " + "(" + syncEngine.CurrentItemNum + "/" + syncEngine.CurrentTotal + ")",
						syncEngine.CurrentItemNum, syncEngine.CurrentTotal);
					syncEngine.CurrentItemNum++;
				}

				DAContentAccessDefinitions.CA_ITEM_ID UID = GetUidFromBuffer(k, caIDList.pUIDs);
				CADataDefinitions.CA_DATA_CONTACT dataContact = new CADataDefinitions.CA_DATA_CONTACT();
				ReadContact(UID, ref dataContact);
				PIMPersonalInfo pimData = new PIMPersonalInfo();
				PIMNumbers numData = new PIMNumbers();
				IList<PIMAddresses> adrData = new List<PIMAddresses>();

				for (int i = 0; i < dataContact.bPICount; i++)
				{
					Int64 iPtr = dataContact.pPIFields.ToInt64() + i * Marshal.SizeOf(typeof(CADataDefinitions.CA_DATA_ITEM));
					IntPtr ptr = new IntPtr(iPtr);
					CADataDefinitions.CA_DATA_ITEM itemData;
					itemData = (CADataDefinitions.CA_DATA_ITEM)Marshal.PtrToStructure(ptr, typeof(CADataDefinitions.CA_DATA_ITEM));
					if (itemData.iFieldType == CADataDefinitions.CA_FIELD_TYPE_CONTACT_PI)
						ReadPersonalInfo(pimData, itemData);
				}

				for (int i = 0; i < dataContact.bNumberCount; i++)
                {
                    Int64 iPtr = dataContact.pNumberFields.ToInt64() + i * Marshal.SizeOf(typeof(CADataDefinitions.CA_DATA_ITEM));
                    IntPtr ptr = new IntPtr(iPtr);
                    CADataDefinitions.CA_DATA_ITEM itemData;
                    itemData = (CADataDefinitions.CA_DATA_ITEM)Marshal.PtrToStructure(ptr, typeof(CADataDefinitions.CA_DATA_ITEM));
					if (itemData.iFieldType == CADataDefinitions.CA_FIELD_TYPE_CONTACT_NUMBER)
						ReadNumbers(numData, itemData);
                }

				for (int i = 0; i < dataContact.bAddressCount; i++)
				{
					Int64 iPtr = dataContact.pAddressFields.ToInt64() + i * Marshal.SizeOf(typeof(CADataDefinitions.CA_DATA_ITEM));
					IntPtr ptr = new IntPtr(iPtr);
					CADataDefinitions.CA_DATA_ITEM itemData;
					itemData = (CADataDefinitions.CA_DATA_ITEM)Marshal.PtrToStructure(ptr, typeof(CADataDefinitions.CA_DATA_ITEM));
					if (itemData.iFieldType == CADataDefinitions.CA_FIELD_TYPE_CONTACT_ADDRESS)
					{
						PIMAddresses a = new PIMAddresses();
                        if (false)
                        {
                            ReadAddresses(a, itemData);
                            adrData.Add(a);
                        }
                        
					}

					if (itemData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_POSTAL |
						itemData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_POSTAL_BUSINESS |
						itemData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_POSTAL_PRIVATE)
					{
					}
				}

				Contact contact = GetCanonicalContact(pimData, numData, adrData);
				contactsByFullName[contact.FullName] = contact;
				mans.Add(new Man { FullName = contact.FullName, EMail = contact.EMail, Phone = contact.Phone });
				
			}
			iRet = DAContentAccess.CAEndOperation(hOperHandle);
			if (iRet != PCCSErrors.CONA_OK)
			{
				//PCCAPIUtils.ShowErrorMessage("CAEndOperation", iRet);
				//syncEngine.CancelSync(PCCAPIUtils.CONAError2String(iRet));

				Dispatcher.Invoke(new SyncCancelEventHandler(owner.CancelSync),
						this, PCCAPIUtils.CONAError2String(iRet), null);

				this.FetchSem.Release();
				return;
			}
			
			CloseContactsConnection();

			//iRet = DAContentAccess.CAFreeIdListStructure(buf);
			//if (iRet != PCCSErrors.CONA_OK)
			//{
			//    PCCAPIUtils.ShowErrorMessage("CAFreeIdListStructure", iRet);
			//}
			Marshal.FreeHGlobal(buf);

			this.FetchSem.Release();
		}
		public void ReadPersonalInfo(PIMPersonalInfo c, CADataDefinitions.CA_DATA_ITEM pimData)
		{
            if (pimData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_NAME)
            {
				c.Name = Marshal.PtrToStringUni(pimData.pCustomData);
            } 
			else if (pimData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_FN)
            {
				c.FirstName = Marshal.PtrToStringUni(pimData.pCustomData);
            }
            else if (pimData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_MN)
            {
				c.MiddleName = Marshal.PtrToStringUni(pimData.pCustomData);
            }
            else if (pimData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_LN)
            {
				c.LastName = Marshal.PtrToStringUni(pimData.pCustomData);
            }
            else if (pimData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_TITLE)
            {
				c.Title = Marshal.PtrToStringUni(pimData.pCustomData);
            }
            else if (pimData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_SUFFIX)
            {
				c.Suffix = Marshal.PtrToStringUni(pimData.pCustomData);
            }
            else if (pimData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_COMPANY)
            {
				c.Company = Marshal.PtrToStringUni(pimData.pCustomData);
            }
            else if (pimData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_JOB_TITLE)
            {
				c.JobTitle = Marshal.PtrToStringUni(pimData.pCustomData);
            }
            else if (pimData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_BIRTHDAY)
            {
            }
            else if (pimData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_PICTURE)
            {
            }
            else if (pimData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_NICKNAME)
            {
				c.Nick = Marshal.PtrToStringUni(pimData.pCustomData);
            }
            else if (pimData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_FORMAL_NAME)
            {
				c.FormalName = Marshal.PtrToStringUni(pimData.pCustomData);
            }
            else if (pimData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_GIVEN_NAME_PRONUNCIATION)
            {
				c.GivenNamePronunciation = Marshal.PtrToStringUni(pimData.pCustomData);
            }
            else if (pimData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_FAMILY_NAME_PRONUNCIATION)
            {
                c.FamilyNamePronunciation = Marshal.PtrToStringUni(pimData.pCustomData);
            }
            else if (pimData.iFieldSubType == CADataDefinitions.CA_FIELD_SUB_TYPE_COMPANY_NAME_PRONUNCIATION)
            {
                c.CompanyNamePronunciation = Marshal.PtrToStringUni(pimData.pCustomData);
            }
		}