private void BuildProperties_LABEL(
            vCardPropertyCollection properties,
            vCard card)
        {
            foreach (vCardDeliveryLabel label in card.DeliveryLabels)
            {
                if (label.Text.Length > 0)
                {
                    vCardProperty property = new vCardProperty("LABEL", label.Text);

                    if (label.IsDomestic)
                    {
                        property.Subproperties.Add("DOM");
                    }

                    if (label.IsInternational)
                    {
                        property.Subproperties.Add("INTL");
                    }

                    if (label.IsParcel)
                    {
                        property.Subproperties.Add("PARCEL");
                    }

                    if (label.IsPostal)
                    {
                        property.Subproperties.Add("POSTAL");
                    }

                    if (label.IsHome)
                    {
                        property.Subproperties.Add("HOME");
                    }

                    if (label.IsWork)
                    {
                        property.Subproperties.Add("WORK");
                    }

                    // Give a hint to use QUOTED-PRINTABLE.

                    property.Subproperties.Add("ENCODING", "QUOTED-PRINTABLE");
                    properties.Add(property);
                }
            }
        }
        /// <summary>
        ///     Builds the ORG property.
        /// </summary>
        private void BuildProperties_ORG(
            vCardPropertyCollection properties,
            vCard card)
        {
            // The ORG property specifies the name of the
            // person's company or organization. Example:
            //
            // ORG:FairMetric LLC

            if (!string.IsNullOrEmpty(card.Organization))
            {
                vCardProperty property =
                    new vCardProperty("ORG", card.Organization);

                properties.Add(property);
            }
        }
        /// <summary>
        ///     Builds KEY properties.
        /// </summary>
        private void BuildProperties_KEY(
            vCardPropertyCollection properties,
            vCard card)
        {
            // A KEY field contains an embedded security certificate.

            foreach (vCardCertificate certificate in card.Certificates)
            {
                vCardProperty property = new vCardProperty();

                property.Name  = "KEY";
                property.Value = certificate.Data;
                property.Subproperties.Add(certificate.KeyType);

                properties.Add(property);
            }
        }
        /// <summary>
        ///     Builds the GEO property.
        /// </summary>
        private void BuildProperties_GEO(
            vCardPropertyCollection properties,
            vCard card)
        {
            // The GEO properties contains the latitude and
            // longitude of the person or company of the vCard.

            if (card.Latitude.HasValue && card.Longitude.HasValue)
            {
                vCardProperty property = new vCardProperty();

                property.Name  = "GEO";
                property.Value =
                    card.Latitude.ToString() + ";" + card.Longitude.ToString();

                properties.Add(property);
            }
        }
        private void BuildProperties_TITLE(
            vCardPropertyCollection properties,
            vCard card)
        {
            // The TITLE property specifies the job title of
            // the person.  Example:
            //
            // TITLE:Systems Analyst
            // TITLE:President

            if (!string.IsNullOrEmpty(card.Title))
            {
                vCardProperty property =
                    new vCardProperty("TITLE", card.Title);

                properties.Add(property);
            }
        }
        /// <summary>
        ///     Builds SOURCE properties.
        /// </summary>
        private void BuildProperties_SOURCE(
            vCardPropertyCollection properties,
            vCard card)
        {
            foreach (vCardSource source in card.Sources)
            {
                vCardProperty property = new vCardProperty();

                property.Name  = "SOURCE";
                property.Value = source.Uri.ToString();

                if (!string.IsNullOrEmpty(source.Context))
                {
                    property.Subproperties.Add("CONTEXT", source.Context);
                }

                properties.Add(property);
            }
        }
        private void BuildProperties_URL(
            vCardPropertyCollection properties,
            vCard card)
        {
            foreach (vCardWebsite webSite in card.Websites)
            {
                if (!string.IsNullOrEmpty(webSite.Url))
                {
                    vCardProperty property =
                        new vCardProperty("URL", webSite.Url.ToString());

                    if (webSite.IsWorkSite)
                    {
                        property.Subproperties.Add("WORK");
                    }

                    properties.Add(property);
                }
            }
        }
        /// <summary>
        ///     Builds the NOTE property.
        /// </summary>
        private void BuildProperties_NOTE(
            vCardPropertyCollection properties,
            vCard card)
        {
            foreach (vCardNote note in card.Notes)
            {
                if (!string.IsNullOrEmpty(note.Text))
                {
                    vCardProperty property = new vCardProperty();

                    property.Name  = "NOTE";
                    property.Value = note.Text;

                    if (!string.IsNullOrEmpty(note.Language))
                    {
                        property.Subproperties.Add("language", note.Language);
                    }

                    property.Subproperties.Add("ENCODING", "QUOTED-PRINTABLE");
                    properties.Add(property);
                }
            }
        }
        /// <summary>
        ///     Builds TEL properties.
        /// </summary>
        private void BuildProperties_TEL(
            vCardPropertyCollection properties,
            vCard card)
        {
            // The TEL property indicates a telephone number of
            // the person (including non-voice numbers like fax
            // and BBS numbers).
            //
            // TEL;VOICE;WORK:1-800-929-5805

            foreach (vCardPhone phone in card.Phones)
            {
                // A telephone entry has the property name TEL and
                // can have zero or more subproperties like FAX
                // or HOME.  Examples:
                //
                //   TEL;HOME:+1-612-555-1212
                //   TEL;FAX;HOME:+1-612-555-1212

                vCardProperty property = new vCardProperty();

                property.Name = "TEL";

                if (phone.IsBBS)
                {
                    property.Subproperties.Add("BBS");
                }

                if (phone.IsCar)
                {
                    property.Subproperties.Add("CAR");
                }

                if (phone.IsCellular)
                {
                    property.Subproperties.Add("CELL");
                }

                if (phone.IsFax)
                {
                    property.Subproperties.Add("FAX");
                }

                if (phone.IsHome)
                {
                    property.Subproperties.Add("HOME");
                }

                if (phone.IsISDN)
                {
                    property.Subproperties.Add("ISDN");
                }

                if (phone.IsMessagingService)
                {
                    property.Subproperties.Add("MSG");
                }

                if (phone.IsModem)
                {
                    property.Subproperties.Add("MODEM");
                }

                if (phone.IsPager)
                {
                    property.Subproperties.Add("PAGER");
                }

                if (phone.IsPreferred)
                {
                    property.Subproperties.Add("PREF");
                }

                if (phone.IsVideo)
                {
                    property.Subproperties.Add("VIDEO");
                }

                if (phone.IsVoice)
                {
                    property.Subproperties.Add("VOICE");
                }

                if (phone.IsWork)
                {
                    property.Subproperties.Add("WORK");
                }

                property.Value = phone.FullNumber;
                properties.Add(property);
            }
        }
        private void BuildProperties_PHOTO(
            vCardPropertyCollection properties,
            vCard card)
        {
            foreach (vCardPhoto photo in card.Photos)
            {
                if (photo.Url == null)
                {
                    // This photo does not have a URL associated
                    // with it.  Therefore a property can be
                    // generated only if the image data is loaded.
                    // Otherwise there is not enough information.

                    if (photo.IsLoaded)
                    {
                        properties.Add(
                            new vCardProperty("PHOTO", photo.GetBytes()));
                    }
                }
                else
                {
                    // This photo has a URL associated with it.  The
                    // PHOTO property can either be linked as an image
                    // or embedded, if desired.

                    bool doEmbedded =
                        photo.Url.IsFile ? this.embedLocalImages : this.embedInternetImages;

                    if (doEmbedded)
                    {
                        // According to the settings of the card writer,
                        // this linked image should be embedded into the
                        // vCard data.  Attempt to fetch the data.

                        try
                        {
                            photo.Fetch();
                        }
                        catch
                        {
                            // An error was encountered.  The image can
                            // still be written as a link, however.

                            doEmbedded = false;
                        }
                    }

                    // At this point, doEmbedded is true only if (a) the
                    // writer was configured to embed the image, and (b)
                    // the image was successfully downloaded.

                    if (doEmbedded)
                    {
                        properties.Add(
                            new vCardProperty("PHOTO", photo.GetBytes()));
                    }
                    else
                    {
                        vCardProperty uriPhotoProperty =
                            new vCardProperty("PHOTO");

                        // Set the VALUE property to indicate that
                        // the data for the photo is a URI.

                        uriPhotoProperty.Subproperties.Add("VALUE", "URI");
                        uriPhotoProperty.Value = photo.Url.ToString();

                        properties.Add(uriPhotoProperty);
                    }
                }
            }
        }
        /// <summary>
        ///     Builds EMAIL properties.
        /// </summary>
        private void BuildProperties_EMAIL(
            vCardPropertyCollection properties,
            vCard card)
        {
            // The EMAIL property contains an electronic
            // mail address for the purpose.  A vCard may contain
            // as many email addresses as needed.  The format also
            // supports various vendors, such as CompuServe addresses
            // and Internet SMTP addresses.
            //
            // EMAIL;INTERNET:[email protected]

            foreach (vCardEmailAddress emailAddress in card.EmailAddresses)
            {
                vCardProperty property = new vCardProperty();
                property.Name  = "EMAIL";
                property.Value = emailAddress.Address;

                if (emailAddress.IsPreferred)
                {
                    property.Subproperties.Add("PREF");
                }

                switch (emailAddress.EmailType)
                {
                case vCardEmailAddressType.Internet:
                    property.Subproperties.Add("INTERNET");
                    break;

                case vCardEmailAddressType.AOL:
                    property.Subproperties.Add("AOL");
                    break;

                case vCardEmailAddressType.AppleLink:
                    property.Subproperties.Add("AppleLink");
                    break;

                case vCardEmailAddressType.AttMail:
                    property.Subproperties.Add("ATTMail");
                    break;

                case vCardEmailAddressType.CompuServe:
                    property.Subproperties.Add("CIS");
                    break;

                case vCardEmailAddressType.eWorld:
                    property.Subproperties.Add("eWorld");
                    break;

                case vCardEmailAddressType.IBMMail:
                    property.Subproperties.Add("IBMMail");
                    break;

                case vCardEmailAddressType.MCIMail:
                    property.Subproperties.Add("MCIMail");
                    break;

                case vCardEmailAddressType.PowerShare:
                    property.Subproperties.Add("POWERSHARE");
                    break;

                case vCardEmailAddressType.Prodigy:
                    property.Subproperties.Add("PRODIGY");
                    break;

                case vCardEmailAddressType.Telex:
                    property.Subproperties.Add("TLX");
                    break;

                case vCardEmailAddressType.X400:
                    property.Subproperties.Add("X400");
                    break;

                default:
                    property.Subproperties.Add("INTERNET");
                    break;
                }

                properties.Add(property);
            }
        }
        /// <summary>
        ///     Builds ADR properties.
        /// </summary>
        private void BuildProperties_ADR(
            vCardPropertyCollection properties,
            vCard card)
        {
            foreach (vCardDeliveryAddress address in card.DeliveryAddresses)
            {
                // Do not generate a postal address (ADR) property
                // if the entire address is blank.

                if (
                    (!string.IsNullOrEmpty(address.City)) ||
                    (!string.IsNullOrEmpty(address.Country)) ||
                    (!string.IsNullOrEmpty(address.PostalCode)) ||
                    (!string.IsNullOrEmpty(address.Region)) ||
                    (!string.IsNullOrEmpty(address.Street)))
                {
                    // The ADR property contains the following
                    // subvalues in order.  All are required:
                    //
                    //   - Post office box
                    //   - Extended address
                    //   - Street address
                    //   - Locality (e.g. city)
                    //   - Region (e.g. province or state)
                    //   - Postal code (e.g. ZIP code)
                    //   - Country name

                    vCardValueCollection values = new vCardValueCollection(';');

                    values.Add(string.Empty);
                    values.Add(string.Empty);
                    values.Add(address.Street);
                    values.Add(address.City);
                    values.Add(address.Region);
                    values.Add(address.PostalCode);
                    values.Add(address.Country);

                    vCardProperty property =
                        new vCardProperty("ADR", values);

                    if (address.IsDomestic)
                    {
                        property.Subproperties.Add("DOM");
                    }

                    if (address.IsInternational)
                    {
                        property.Subproperties.Add("INTL");
                    }

                    if (address.IsParcel)
                    {
                        property.Subproperties.Add("PARCEL");
                    }

                    if (address.IsPostal)
                    {
                        property.Subproperties.Add("POSTAL");
                    }

                    if (address.IsHome)
                    {
                        property.Subproperties.Add("HOME");
                    }

                    if (address.IsWork)
                    {
                        property.Subproperties.Add("WORK");
                    }

                    properties.Add(property);
                }
            }
        }
        /// <summary>
        ///     Returns property encoded into a standard vCard NAME:VALUE format.
        /// </summary>
        public string EncodeProperty(vCardProperty property)
        {
            if (property == null)
            {
                throw new ArgumentNullException("property");
            }

            if (string.IsNullOrEmpty(property.Name))
            {
                throw new ArgumentException();
            }

            StringBuilder builder = new StringBuilder();

            builder.Append(property.Name);

            foreach (vCardSubproperty subproperty in property.Subproperties)
            {
                builder.Append(';');
                builder.Append(subproperty.Name);

                if (!string.IsNullOrEmpty(subproperty.Value))
                {
                    builder.Append('=');
                    builder.Append(subproperty.Value);
                }
            }

            // The property name and all subproperties have been
            // written to the string builder (the colon separator
            // has not been written).  The next step is to write
            // the value.  Depending on the type of value and any
            // characters in the value, it may be necessary to
            // use an non-default encoding.  For example, byte arrays
            // are written encoded in BASE64.

            if (property.Value == null)
            {
                builder.Append(':');
            }
            else
            {
                Type valueType = property.Value.GetType();

                if (valueType == typeof(byte[]))
                {
                    // A byte array should be encoded in BASE64 format.

                    builder.Append(";ENCODING=BASE64:");
                    builder.Append(EncodeBase64((byte[])property.Value));
                }
                else if (valueType == typeof(vCardValueCollection))
                {
                    vCardValueCollection values = (vCardValueCollection)property.Value;

                    builder.Append(':');
                    for (int index = 0; index < values.Count; index++)
                    {
                        builder.Append(EncodeEscaped(values[index]));
                        if (index < values.Count - 1)
                        {
                            builder.Append(values.Separator);
                        }
                    }
                }
                else
                {
                    // The object will be converted to a string (if it is
                    // not a string already) and encoded if necessary.
                    // The first step is to get the string value.

                    string stringValue = null;

                    if (valueType == typeof(char[]))
                    {
                        stringValue = new string(((char[])property.Value));
                    }
                    else
                    {
                        stringValue = property.Value.ToString();
                    }

                    builder.Append(':');

                    switch (property.Subproperties.GetValue("ENCODING"))
                    {
                    case "QUOTED-PRINTABLE":
                        builder.Append(EncodeQuotedPrintable(stringValue));
                        break;

                    default:
                        builder.Append(EncodeEscaped(stringValue));
                        break;
                    }
                }
            }

            return(builder.ToString());
        }