From f612fc4f3f710a24dada1742b4bcf514480d3efc Mon Sep 17 00:00:00 2001 From: Abdel Date: Sat, 12 Sep 2015 19:58:10 -0400 Subject: [PATCH] Initial Commit --- .gitignore | 217 ++ Local.testsettings | 10 + TraceAndTestImpact.testsettings | 21 + vCardEditor.sln | 20 + vCardEditor.vsmdi | 6 + vCardEditor/ContactRepository.cs | 143 ++ vCardEditor/IContactRepository.cs | 22 + vCardEditor/Model/Contact.cs | 51 + vCardEditor/Presenter/MainPresenter.cs | 73 + vCardEditor/Program.cs | 28 + vCardEditor/Properties/AssemblyInfo.cs | 36 + vCardEditor/Properties/Resources.Designer.cs | 71 + vCardEditor/Properties/Resources.resx | 117 + vCardEditor/Properties/Settings.Designer.cs | 30 + vCardEditor/Properties/Settings.settings | 7 + vCardEditor/Thought.vCards/History.txt | 216 ++ vCardEditor/Thought.vCards/KnownIssues.txt | 22 + vCardEditor/Thought.vCards/License.txt | 504 ++++ .../WarningMessages.Designer.cs | 90 + .../Thought.vCards/WarningMessages.resx | 129 + vCardEditor/Thought.vCards/vCard.cs | 768 ++++++ .../vCardAccessClassification.cs | 44 + .../Thought.vCards/vCardCertificate.cs | 125 + .../vCardCertificateCollection.cs | 21 + vCardEditor/Thought.vCards/vCardCollection.cs | 22 + .../Thought.vCards/vCardDeliveryAddress.cs | 286 +++ .../vCardDeliveryAddressCollection.cs | 22 + .../vCardDeliveryAddressTypes.cs | 56 + .../Thought.vCards/vCardDeliveryLabel.cs | 228 ++ .../vCardDeliveryLabelCollection.cs | 21 + .../Thought.vCards/vCardEmailAddress.cs | 131 + .../vCardEmailAddressCollection.cs | 70 + .../Thought.vCards/vCardEmailAddressType.cs | 97 + vCardEditor/Thought.vCards/vCardEncoding.cs | 41 + vCardEditor/Thought.vCards/vCardException.cs | 66 + vCardEditor/Thought.vCards/vCardFormat.cs | 43 + vCardEditor/Thought.vCards/vCardGender.cs | 47 + vCardEditor/Thought.vCards/vCardNote.cs | 82 + .../Thought.vCards/vCardNoteCollection.cs | 48 + vCardEditor/Thought.vCards/vCardPhone.cs | 411 ++++ .../Thought.vCards/vCardPhoneCollection.cs | 67 + vCardEditor/Thought.vCards/vCardPhoneTypes.cs | 113 + vCardEditor/Thought.vCards/vCardPhoto.cs | 279 +++ .../Thought.vCards/vCardPhotoCollection.cs | 31 + vCardEditor/Thought.vCards/vCardProperty.cs | 258 ++ .../Thought.vCards/vCardPropertyCollection.cs | 22 + vCardEditor/Thought.vCards/vCardReader.cs | 94 + vCardEditor/Thought.vCards/vCardSource.cs | 110 + .../Thought.vCards/vCardSourceCollection.cs | 31 + .../Thought.vCards/vCardStandardReader.cs | 2156 +++++++++++++++++ .../Thought.vCards/vCardStandardWriter.cs | 1610 ++++++++++++ .../vCardStandardWriterOptions.cs | 41 + .../Thought.vCards/vCardSubproperty.cs | 141 ++ .../vCardSubpropertyCollection.cs | 368 +++ .../Thought.vCards/vCardValueCollection.cs | 80 + vCardEditor/Thought.vCards/vCardWebsite.cs | 170 ++ .../Thought.vCards/vCardWebsiteCollection.cs | 61 + .../Thought.vCards/vCardWebsiteTypes.cs | 45 + vCardEditor/Thought.vCards/vCardWriter.cs | 81 + vCardEditor/View/AboutDialog.Designer.cs | 186 ++ vCardEditor/View/AboutDialog.cs | 104 + vCardEditor/View/AboutDialog.resx | 604 +++++ vCardEditor/View/EventArgs.cs | 34 + vCardEditor/View/IMainView.cs | 25 + vCardEditor/View/MainForm.Designer.cs | 359 +++ vCardEditor/View/MainForm.cs | 120 + vCardEditor/View/MainForm.resx | 208 ++ vCardEditor/vCardEditor.csproj | 144 ++ vCardEditor_Test/MainPresenterTest.cs | 31 + vCardEditor_Test/Properties/AssemblyInfo.cs | 35 + vCardEditor_Test/vCardEditor_Test.csproj | 57 + 71 files changed, 12107 insertions(+) create mode 100644 .gitignore create mode 100644 Local.testsettings create mode 100644 TraceAndTestImpact.testsettings create mode 100644 vCardEditor.sln create mode 100644 vCardEditor.vsmdi create mode 100644 vCardEditor/ContactRepository.cs create mode 100644 vCardEditor/IContactRepository.cs create mode 100644 vCardEditor/Model/Contact.cs create mode 100644 vCardEditor/Presenter/MainPresenter.cs create mode 100644 vCardEditor/Program.cs create mode 100644 vCardEditor/Properties/AssemblyInfo.cs create mode 100644 vCardEditor/Properties/Resources.Designer.cs create mode 100644 vCardEditor/Properties/Resources.resx create mode 100644 vCardEditor/Properties/Settings.Designer.cs create mode 100644 vCardEditor/Properties/Settings.settings create mode 100644 vCardEditor/Thought.vCards/History.txt create mode 100644 vCardEditor/Thought.vCards/KnownIssues.txt create mode 100644 vCardEditor/Thought.vCards/License.txt create mode 100644 vCardEditor/Thought.vCards/WarningMessages.Designer.cs create mode 100644 vCardEditor/Thought.vCards/WarningMessages.resx create mode 100644 vCardEditor/Thought.vCards/vCard.cs create mode 100644 vCardEditor/Thought.vCards/vCardAccessClassification.cs create mode 100644 vCardEditor/Thought.vCards/vCardCertificate.cs create mode 100644 vCardEditor/Thought.vCards/vCardCertificateCollection.cs create mode 100644 vCardEditor/Thought.vCards/vCardCollection.cs create mode 100644 vCardEditor/Thought.vCards/vCardDeliveryAddress.cs create mode 100644 vCardEditor/Thought.vCards/vCardDeliveryAddressCollection.cs create mode 100644 vCardEditor/Thought.vCards/vCardDeliveryAddressTypes.cs create mode 100644 vCardEditor/Thought.vCards/vCardDeliveryLabel.cs create mode 100644 vCardEditor/Thought.vCards/vCardDeliveryLabelCollection.cs create mode 100644 vCardEditor/Thought.vCards/vCardEmailAddress.cs create mode 100644 vCardEditor/Thought.vCards/vCardEmailAddressCollection.cs create mode 100644 vCardEditor/Thought.vCards/vCardEmailAddressType.cs create mode 100644 vCardEditor/Thought.vCards/vCardEncoding.cs create mode 100644 vCardEditor/Thought.vCards/vCardException.cs create mode 100644 vCardEditor/Thought.vCards/vCardFormat.cs create mode 100644 vCardEditor/Thought.vCards/vCardGender.cs create mode 100644 vCardEditor/Thought.vCards/vCardNote.cs create mode 100644 vCardEditor/Thought.vCards/vCardNoteCollection.cs create mode 100644 vCardEditor/Thought.vCards/vCardPhone.cs create mode 100644 vCardEditor/Thought.vCards/vCardPhoneCollection.cs create mode 100644 vCardEditor/Thought.vCards/vCardPhoneTypes.cs create mode 100644 vCardEditor/Thought.vCards/vCardPhoto.cs create mode 100644 vCardEditor/Thought.vCards/vCardPhotoCollection.cs create mode 100644 vCardEditor/Thought.vCards/vCardProperty.cs create mode 100644 vCardEditor/Thought.vCards/vCardPropertyCollection.cs create mode 100644 vCardEditor/Thought.vCards/vCardReader.cs create mode 100644 vCardEditor/Thought.vCards/vCardSource.cs create mode 100644 vCardEditor/Thought.vCards/vCardSourceCollection.cs create mode 100644 vCardEditor/Thought.vCards/vCardStandardReader.cs create mode 100644 vCardEditor/Thought.vCards/vCardStandardWriter.cs create mode 100644 vCardEditor/Thought.vCards/vCardStandardWriterOptions.cs create mode 100644 vCardEditor/Thought.vCards/vCardSubproperty.cs create mode 100644 vCardEditor/Thought.vCards/vCardSubpropertyCollection.cs create mode 100644 vCardEditor/Thought.vCards/vCardValueCollection.cs create mode 100644 vCardEditor/Thought.vCards/vCardWebsite.cs create mode 100644 vCardEditor/Thought.vCards/vCardWebsiteCollection.cs create mode 100644 vCardEditor/Thought.vCards/vCardWebsiteTypes.cs create mode 100644 vCardEditor/Thought.vCards/vCardWriter.cs create mode 100644 vCardEditor/View/AboutDialog.Designer.cs create mode 100644 vCardEditor/View/AboutDialog.cs create mode 100644 vCardEditor/View/AboutDialog.resx create mode 100644 vCardEditor/View/EventArgs.cs create mode 100644 vCardEditor/View/IMainView.cs create mode 100644 vCardEditor/View/MainForm.Designer.cs create mode 100644 vCardEditor/View/MainForm.cs create mode 100644 vCardEditor/View/MainForm.resx create mode 100644 vCardEditor/vCardEditor.csproj create mode 100644 vCardEditor_Test/MainPresenterTest.cs create mode 100644 vCardEditor_Test/Properties/AssemblyInfo.cs create mode 100644 vCardEditor_Test/vCardEditor_Test.csproj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..150691a --- /dev/null +++ b/.gitignore @@ -0,0 +1,217 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions diff --git a/Local.testsettings b/Local.testsettings new file mode 100644 index 0000000..f289054 --- /dev/null +++ b/Local.testsettings @@ -0,0 +1,10 @@ + + + Il s'agit des paramètres de test par défaut pour une série de tests locale. + + + + + + + \ No newline at end of file diff --git a/TraceAndTestImpact.testsettings b/TraceAndTestImpact.testsettings new file mode 100644 index 0000000..f7c6fcc --- /dev/null +++ b/TraceAndTestImpact.testsettings @@ -0,0 +1,21 @@ + + + Il s'agit des paramètres de test pour trace et impact de test. + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vCardEditor.sln b/vCardEditor.sln new file mode 100644 index 0000000..b0e3e9b --- /dev/null +++ b/vCardEditor.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "vCardEditor", "vCardEditor\vCardEditor.csproj", "{A0D2ACEB-1BCC-4E7F-9E7D-2BE25A7ABE22}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A0D2ACEB-1BCC-4E7F-9E7D-2BE25A7ABE22}.Debug|x86.ActiveCfg = Debug|x86 + {A0D2ACEB-1BCC-4E7F-9E7D-2BE25A7ABE22}.Debug|x86.Build.0 = Debug|x86 + {A0D2ACEB-1BCC-4E7F-9E7D-2BE25A7ABE22}.Release|x86.ActiveCfg = Release|x86 + {A0D2ACEB-1BCC-4E7F-9E7D-2BE25A7ABE22}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/vCardEditor.vsmdi b/vCardEditor.vsmdi new file mode 100644 index 0000000..f8fdd43 --- /dev/null +++ b/vCardEditor.vsmdi @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/vCardEditor/ContactRepository.cs b/vCardEditor/ContactRepository.cs new file mode 100644 index 0000000..f349edc --- /dev/null +++ b/vCardEditor/ContactRepository.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Thought.vCards; +using VCFEditor.Model; +using System.ComponentModel; + +namespace VCFEditor +{ + public class ContactRepository : IContactRepository + { + public string fileName { get; set; } + + private BindingList _contacts; + public BindingList Contacts + { + get + { + if (_contacts == null) + _contacts = new BindingList(); + return _contacts; + } + set + { + _contacts = value; + } + } + + + + /// + /// Formatted name. + /// + public const string KeyName = "FN"; + + /// + /// Load contacts. + /// 1- Parse the file + /// 2- + /// + /// + public BindingList LoadContacts(string fileName) + { + string[] lines = File.ReadAllLines(fileName); + string[] parts; + var contact = new Contact(); + + //Prevent from adding contacts to existings ones. + Contacts.Clear(); + + for (int i = 0; i < lines.Length; i++) + { + + contact.RawContent.AppendLine(lines[i]); + if (lines[i] == "END:VCARD") + { + Contacts.Add(contact); + contact = new Contact(); + } + else + { + parts = lines[i].Split(new char[] { ':' }); + + if (string.Compare(parts[0], KeyName) == 0) + contact.Name = parts[1]; + } + } + + return Contacts; + } + + /// + /// Save the contact to the file. + /// + /// Path to the new file, else if null, we overwrite the same file + public void SaveContacts(string fileName) + { + //overwrite the same file, else save as another file. + if (string.IsNullOrEmpty(fileName)) + fileName = this.fileName; + + + StringBuilder sb = new StringBuilder(); + foreach (var entry in Contacts) + sb.Append(entry.RawContent); + + File.WriteAllText(fileName, sb.ToString()); + } + + + /// + /// Delete contacted that are selected. + /// + public void DeleteContact() + { + if (_contacts != null && _contacts.Count > 0) + { + //loop from the back to prevent index mangling... + for (int i = _contacts.Count - 1; i > -1; i--) + { + if (_contacts[i].isSelected) + _contacts.RemoveAt(i); + } + } + + } + + public vCard ParseContactAt(int index) + { + vCard card = null; + Contact contact = _contacts[index]; + + using (MemoryStream s = GenerateStreamFromString(contact.RawContent.ToString())) + using (TextReader streamReader = new StreamReader(s, Encoding.Default)) + { + card = new vCard(streamReader); + } + + return card; + } + + /// + /// + /// + /// + /// + private MemoryStream GenerateStreamFromString(string s) + { + MemoryStream stream = new MemoryStream(); + StreamWriter writer = new StreamWriter(stream); + writer.Write(s); + writer.Flush(); + stream.Position = 0; + return stream; + } + + + + } +} diff --git a/vCardEditor/IContactRepository.cs b/vCardEditor/IContactRepository.cs new file mode 100644 index 0000000..e9f3939 --- /dev/null +++ b/vCardEditor/IContactRepository.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Thought.vCards; +using VCFEditor.Model; +using System.ComponentModel; + +namespace VCFEditor +{ + public interface IContactRepository + { + string fileName { get; set; } + BindingList Contacts { get; set; } + + BindingList LoadContacts(string fileName); + void SaveContacts(string fileName); + vCard ParseContactAt(int index); + void DeleteContact(); + } +} diff --git a/vCardEditor/Model/Contact.cs b/vCardEditor/Model/Contact.cs new file mode 100644 index 0000000..4d633d0 --- /dev/null +++ b/vCardEditor/Model/Contact.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace VCFEditor.Model +{ + /// + /// + /// + public class Contact : INotifyPropertyChanged + { + private string _name; + + [DisplayName(" ")] + public bool isSelected { get; set; } + + + [DisplayName("Name")] + public string Name + { + get { return _name; } + set + { + _name = value; + this.NotifyPropertyChanged("Name"); + } + } + + [Browsable(false)] + public StringBuilder RawContent { get; set; } + + + public Contact() + { + RawContent = new StringBuilder(); + isSelected = false; + } + + private void NotifyPropertyChanged(string name) + { + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs(name)); + } + + public event PropertyChangedEventHandler PropertyChanged; + + } +} diff --git a/vCardEditor/Presenter/MainPresenter.cs b/vCardEditor/Presenter/MainPresenter.cs new file mode 100644 index 0000000..9347641 --- /dev/null +++ b/vCardEditor/Presenter/MainPresenter.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Thought.vCards; +using VCFEditor.Model; +using VCFEditor.View; +using System.ComponentModel; + + +namespace VCFEditor.Presenter +{ + public class MainPresenter + { + private readonly IMainView _view; + private readonly IContactRepository _repository; + + public MainPresenter(IMainView view, IContactRepository repository) + { + _view = view; + _repository = repository; + + //hook event from the view to event handler present in this presenter. + _view.NewFileOpened += NewFileOpened; + _view.SaveContactsSelected += SaveContacts; + _view.ChangeContactsSelected += ChangeContactSelected; + _view.DeleteContact += DeleteContact; + + + } + + private void DeleteContact(object sender, EventArgs e) + { + _repository.DeleteContact(); + } + + private void SaveContacts(object sender, EventArgs e) + { + _repository.SaveContacts(_repository.fileName); + } + + public void NewFileOpened(object sender, EventArg e) + { + DisplayContacts(e.Data); + } + + public void ChangeContactSelected(object sender, EventArg e) + { + if (e.Data > -1) + { + int index = e.Data; + vCard card = _repository.ParseContactAt(index); + if (card != null) + { + _view.DisplayContactDetail(card); + } + } + + } + + public void DisplayContacts(string path) + { + if (!string.IsNullOrEmpty(path)) + { + _repository.LoadContacts(path); + _view.DisplayContacts(_repository.Contacts); + } + + } + + } +} diff --git a/vCardEditor/Program.cs b/vCardEditor/Program.cs new file mode 100644 index 0000000..23d384f --- /dev/null +++ b/vCardEditor/Program.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; +using vCardEditor.View; +using VCFEditor.Presenter; +using VCFEditor; + +namespace vCardEditor +{ + static class Program + { + /// + /// Point d'entrée principal de l'application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + var mainForm = new MainForm(); + var presenter = new MainPresenter(mainForm, new ContactRepository()); + + Application.Run(mainForm); + } + } +} diff --git a/vCardEditor/Properties/AssemblyInfo.cs b/vCardEditor/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c95f2a6 --- /dev/null +++ b/vCardEditor/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Les informations générales relatives à un assembly dépendent de +// l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations +// associées à un assembly. +[assembly: AssemblyTitle("vCardEditor")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("vCardEditor")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly +// aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de +// COM, affectez la valeur true à l'attribut ComVisible sur ce type. +[assembly: ComVisible(false)] + +// Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM +[assembly: Guid("22e4348d-1699-4db2-be45-7407352a41d2")] + +// Les informations de version pour un assembly se composent des quatre valeurs suivantes : +// +// Version principale +// Version secondaire +// Numéro de build +// Révision +// +// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut +// en utilisant '*', comme indiqué ci-dessous : +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/vCardEditor/Properties/Resources.Designer.cs b/vCardEditor/Properties/Resources.Designer.cs new file mode 100644 index 0000000..9ab3436 --- /dev/null +++ b/vCardEditor/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// Ce code a été généré par un outil. +// Version du runtime :4.0.30319.34209 +// +// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si +// le code est régénéré. +// +//------------------------------------------------------------------------------ + +namespace vCardEditor.Properties +{ + + + /// + /// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées. + /// + // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder + // à l'aide d'un outil, tel que ResGen ou Visual Studio. + // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen + // avec l'option /str ou régénérez votre projet VS. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Retourne l'instance ResourceManager mise en cache utilisée par cette classe. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("vCardEditor.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Remplace la propriété CurrentUICulture du thread actuel pour toutes + /// les recherches de ressources à l'aide de cette classe de ressource fortement typée. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/vCardEditor/Properties/Resources.resx b/vCardEditor/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/vCardEditor/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/vCardEditor/Properties/Settings.Designer.cs b/vCardEditor/Properties/Settings.Designer.cs new file mode 100644 index 0000000..ab79ecb --- /dev/null +++ b/vCardEditor/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34209 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace vCardEditor.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/vCardEditor/Properties/Settings.settings b/vCardEditor/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/vCardEditor/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/vCardEditor/Thought.vCards/History.txt b/vCardEditor/Thought.vCards/History.txt new file mode 100644 index 0000000..087d3f8 --- /dev/null +++ b/vCardEditor/Thought.vCards/History.txt @@ -0,0 +1,216 @@ + +vCard Class Library for .NET +Copyright (c) 2007-2009 David Pinch (davepinch@gmail.com). + + +Please refer to README.TXT in the distribution archive. If you do +not have a copy of the archive, you may download the latest version +of this library from http://www.thoughtproject.com/Libraries/vCard/ +This library is distributed under the terms of the Lesser General +Public License. Please refer to LICENSE.TXT for the exact terms. + + +History + + ------------------------------------------------------------------------ + 2009-10-08: Version 0.4 + ------------------------------------------------------------------------ + + 1. Unit tests have been upgraded to NUnit 2.5.2. + + 2. Per the Microsoft guidelines for class library development, all string + properties are expected to return String.Empty instead of null (in + cases where the property is blank). This is already the case in + this library but the implementation was problematic. Instead each + string getter now takes the following form: + + return this.property ?? string.Empty; + + Previously the code attempted to translate null to string.Empty whenever + the value was assigned -- in the constructor, in the setter, etc. This + is prone to error. The form shown above is used instead. + + 3. Renames. The following types were renamed to comply with standard + naming conventions. Any code will need to be fixed. Fixes should be + minor only. + + Per class library design guidelines, flag enumerations should be + named with a plural name. See FxCop rule FlagsEnumsShouldHavePluralNames. + These changes are simple to fix in code; simple add an "s" whereever you + reference the enumeration. + + - vCardDeliveryAddressType => vCardDeliveryAddressTypes + - vCardPhoneType => vCardPhoneTypes + - vCardWebSiteType => vCardWebSiteTypes + + Per class library design guidelines, the term "WebSite" is actually + a discrete term "website". Refer to rule CompoundWordsShouldBeCasedCorrectly + in FxCop. The following types have been renamed: + + - vCardWebSite => vCardWebsite + - vCardWebSiteCollection => vCardWebsiteCollection + - vCardWebSiteType => vCardWebsiteType + + 3. Non-Breaking Changes: + + The following changes are internal fixes that are not expected to + cause compilation issues. + + - Assembly marked as language neutral (set to U.S. English). + - vCardStandardWriter no longer unnecessarily initializes embedInternetImages + - vCardStandardWriterOptions is now a flags enumeration + - vCardSubpropertyCollection uses StringComparison.OrdinalIgnoreCase. + - vCardStandardReader recognizes the date format exported by Outlook 2007. + - Updated various XML comments. + + Some collections have overloads that return the index of a named + value, e.g. vCardSubpropertyCollection.IndexOf(name). Internally + these functions perform a comparison using StringComparison.OrdinalIgnoreCase. + This should have no impact unless you were using the library under + a very unique language/environment. + + + + + ------------------------------------------------------------------------ + 2007-08-xx: Version 0.3 + ------------------------------------------------------------------------ + + Thank you to many people who have written with kind comments and + suggestions for the library. The biggest change in this version + is a complete refactoring of the code for reading and writing + the file formats. The main vCard object model is now a generic + model. Format-specific code has been moved to separate classes + for easier maintenance and support for vCard-compatible formats. + + Some changes will probably break your code. For example, the + library now supports multiple notes (previously only one note + per vCard was supported). The majority of changes will be + easy to fix, usually just by using the Intellisense(tm) in your + Visual Studio IDE. Please refer to the Unit Testing solution + if you need examples of using the API in various ways. The + number of unit tests have been expanded substantially. + + - Added support for quoted-printable and standard MIME escape + encoding. The read/write process has been completely refactored + into a separate API to better support multiple vCard formats. + + - Added vCardReader and vCardWriter, both abstract classes. They + define the core interfaces for creating format-specific readers + and writers. + + - Added vCardStandardReader and vCardStandardWriter. These two + classes implement the vCard 2.1 and 3.0 text format specifications. + These classes are fairly complex due to the wide variety of + interpretations found in the wild! + + - Removed all format and encoding-specific code from the main + vCard object model. Anything format-specific is expected to + be implemented in a reader or writer class. Currently only + the 2.1 and 3.0 formats are implemented, although future + versions will support RFD, hCard and other variations. + Therefore it makes no sense to have anything format-specific + in the main object model. + + - Added support for multiple web sites. The vCard.Url property + was removed in favor of vCard.WebSites, a collection. See + new items: vCardWebSite, vCardWebSiteCollection, and + vCardWebSiteType. Import and export logic also updated. + + - Added support for multiple notes/comments. The vCard.Note + property was removed in favor of vCard.Notes, a collection. + + - Added support for delivery addresses and delivery labels. + The current level of support is sufficient for Microsoft Outlook + but needs some more work for total vCard compliance. + + - Added vCard.AccessClassification. This indicates the + intended access/permissions of the vCard, such as private, + public or confidential. It corresponds to the CLASS + property of the vCard specification. + + - Added vCard.Categories (a string collection). This contains + any user-defined categories or keywords. It corresponds + with the CATEGORIES property of the vCard specification. + + - Added vCard.DisplayName. This maps to the NAME property and + specifies the display name of the vCard. A vCard application + might show this name as a title or header. + + - Added vCard.Latitude and vCard.Longitude. These correspond with + the GEO property of the specification. Usage seems to be + very rare but is implemented here for completeness. + + - Added vCard.Photos, a collection of vCardPhoto objects. + A photo can be referenced as a URL or specified directly + with a bitmap or byte array. + + - Added vCard.RevisionDate (nullable date). This contains the + last revision date of the vCard. The library does not + update this value when you make changes; you need to set + the revision date yourself. This maps to the REV property + of the specification. + + - Renamed vCardPhone.Subtype to vCardPhone.PhoneType in order to + be consistent with the naming conventions used elsewhere in + the library. + + And much more. + + + ------------------------------------------------------------------------ + 2007-05-14: Version 0.2 + ------------------------------------------------------------------------ + + vCard Format/Specification Changes: + + - Added support for the KEY property, which is used to embed + a certificate in the vCard. Only the BASE64 encoding, used by + Microsoft Outlook and many PIMs, is supported. Thanks for + Martin Meraner + + - Added support for the MAILER property. This property identifies + the software that generated the vCard; it is described in + section 2.4.3 of the vCard 2.1 specification. + + - Added support for the SOURCE vCard property. This property + identifies the URI of a directory that provided information + for the vCard contents (e.g., an LDAP URL). + + - Added support for the UID property. This property is a string + that uniquely identifies the vCard in relation to other vCards. + There is no standard but typical ID strings might be URLs, + GUIDs, etc. + + - Added support for the X-WAB-GENDER extended property. This + property identifies the gender of the contact; it may not be + supported elsewhere and therefore should be used with care. + It is an extended property used by Microsoft Outlook. + + - Added support for the ROLE property. This property describes + the role of the person at his/her organization, e.g. Programmer + or Executive, etc. + + Class Library API Changes: + + - Added the standard .NET constructors to the vCardException class. + - Added a unit testing project (designed for NUnit). + - Added vCardCertificate + - Added vCardCertificateCollection + - Added vCardDeliveryLabel + - Added vCardDeliveryLabelType + - Added vCardGender + - Added vCardSource + - Added vCardSourceCollection + - Added vCardValueType + - Fixed and expanded inline and XML comments. + - Fixed typo of vCardPhone.IsCelluar to vCardPhone.IsCellular. + + + ------------------------------------------------------------------------ + 2007-03-07: Version 0.1 + ------------------------------------------------------------------------ + + Initial release on www.thoughtproject.com/Libraries/vCards/ + + \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/KnownIssues.txt b/vCardEditor/Thought.vCards/KnownIssues.txt new file mode 100644 index 0000000..121a76f --- /dev/null +++ b/vCardEditor/Thought.vCards/KnownIssues.txt @@ -0,0 +1,22 @@ + +vCard Properties +-------------------------------------------------------------------------- + +X-MS-OL-DEFAULT-POSTAL-ADDRESS + + This property is generated by Microsoft Outlook 2007. It appears + to define the default postal address (which is shown as a checkbox + in the Outlook 2007 interface) but specific technical details are + unknown. The property is ignored in the current version of the library. + + +X-MS-IMADDRESS + + Microsoft extension to hold an instant message address. + + +X-MS-OL-DESIGN + + Research needed. + + \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/License.txt b/vCardEditor/Thought.vCards/License.txt new file mode 100644 index 0000000..5ab7695 --- /dev/null +++ b/vCardEditor/Thought.vCards/License.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/vCardEditor/Thought.vCards/WarningMessages.Designer.cs b/vCardEditor/Thought.vCards/WarningMessages.Designer.cs new file mode 100644 index 0000000..077cdf7 --- /dev/null +++ b/vCardEditor/Thought.vCards/WarningMessages.Designer.cs @@ -0,0 +1,90 @@ +//------------------------------------------------------------------------------ +// +// Ce code a été généré par un outil. +// Version du runtime :4.0.30319.34209 +// +// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si +// le code est régénéré. +// +//------------------------------------------------------------------------------ + +namespace Thought.vCards { + using System; + + + /// + /// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées. + /// + // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder + // à l'aide d'un outil, tel que ResGen ou Visual Studio. + // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen + // avec l'option /str ou régénérez votre projet VS. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class WarningMessages { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal WarningMessages() { + } + + /// + /// Retourne l'instance ResourceManager mise en cache utilisée par cette classe. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Thought.vCards.WarningMessages", typeof(WarningMessages).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Remplace la propriété CurrentUICulture du thread actuel pour toutes + /// les recherches de ressources à l'aide de cette classe de ressource fortement typée. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Recherche une chaîne localisée semblable à Line {0} A blank line was encountered. This is not allowed in the vCard specification.. + /// + internal static string BlankLine { + get { + return ResourceManager.GetString("BlankLine", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à Line {0}: A colon (:) is missing. All properties must be in NAME:VALUE format.. + /// + internal static string ColonMissing { + get { + return ResourceManager.GetString("ColonMissing", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à Line {0}: The name section of the property is empty.. + /// + internal static string EmptyName { + get { + return ResourceManager.GetString("EmptyName", resourceCulture); + } + } + } +} diff --git a/vCardEditor/Thought.vCards/WarningMessages.resx b/vCardEditor/Thought.vCards/WarningMessages.resx new file mode 100644 index 0000000..5bdeebc --- /dev/null +++ b/vCardEditor/Thought.vCards/WarningMessages.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Line {0} A blank line was encountered. This is not allowed in the vCard specification. + + + Line {0}: A colon (:) is missing. All properties must be in NAME:VALUE format. + + + Line {0}: The name section of the property is empty. + + \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCard.cs b/vCardEditor/Thought.vCards/vCard.cs new file mode 100644 index 0000000..9529654 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCard.cs @@ -0,0 +1,768 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections.Specialized; +using System.IO; +using System.Text; + +namespace Thought.vCards +{ + + /// + /// A vCard object for exchanging personal contact information. + /// + /// + /// + /// A vCard contains personal information, such as postal + /// addresses, public security certificates, email addresses, and + /// web sites. The vCard specification makes it possible for + /// different computer programs to exchange personal contact + /// information; for example, a vCard can be attached to an email or + /// sent over a wireless connection. + /// + /// + /// The standard vCard format is a text file with properties in + /// name:value format. However, there are multiple versions of + /// this format as well as compatible alternatives in XML and + /// HTML formats. This class library aims to accomodate these + /// variations but be aware some some formats do not support + /// all possible properties. + /// + /// + [Serializable] + public class vCard + { + + private vCardAccessClassification accessClassification; + private string additionalNames; + private DateTime? birthDate; + private StringCollection categories; + private string department; + private string displayName; + private string familyName; + private string formattedName; + private vCardGender gender; + private string givenName; + private float? latitude; + private float? longitude; + private string mailer; + private string namePrefix; + private string nameSuffix; + private StringCollection nicknames; + private string office; + private string organization; + private string productId; + private DateTime? revisionDate; + private string role; + private string timeZone; + private string title; + private string uniqueId; + + private vCardCertificateCollection certificates; + private vCardDeliveryAddressCollection deliveryAddresses; + private vCardDeliveryLabelCollection deliveryLabels; + private vCardEmailAddressCollection emailAddresses; + private vCardNoteCollection notes; + private vCardPhoneCollection phones; + private vCardPhotoCollection photos; + private vCardSourceCollection sources; + private vCardWebsiteCollection websites; + + /// + /// Initializes a new instance of the class. + /// + public vCard() + { + + // Per Microsoft best practices, string properties should + // never return null. String properties should always + // return String.Empty. + + this.additionalNames = string.Empty; + this.department = string.Empty; + this.displayName = string.Empty; + this.familyName = string.Empty; + this.formattedName = string.Empty; + this.givenName = string.Empty; + this.mailer = string.Empty; + this.namePrefix = string.Empty; + this.nameSuffix = string.Empty; + this.office = string.Empty; + this.organization = string.Empty; + this.productId = string.Empty; + this.role = string.Empty; + this.timeZone = string.Empty; + this.title = string.Empty; + this.uniqueId = string.Empty; + + this.categories = new StringCollection(); + this.certificates = new vCardCertificateCollection(); + this.deliveryAddresses = new vCardDeliveryAddressCollection(); + this.deliveryLabels = new vCardDeliveryLabelCollection(); + this.emailAddresses = new vCardEmailAddressCollection(); + this.nicknames = new StringCollection(); + this.notes = new vCardNoteCollection(); + this.phones = new vCardPhoneCollection(); + this.photos = new vCardPhotoCollection(); + this.sources = new vCardSourceCollection(); + this.websites = new vCardWebsiteCollection(); + } + + + /// + /// Loads a new instance of the class + /// from a text reader. + /// + /// + /// An initialized text reader. + /// + public vCard(TextReader input) + : this() + { + + vCardReader reader = new vCardStandardReader(); + reader.ReadInto(this, input); + + } + + + /// + /// Loads a new instance of the class + /// from a text file. + /// + /// + /// The path to a text file containing vCard data in + /// any recognized vCard format. + /// + public vCard(string path) + : this() + { + using (StreamReader streamReader = new StreamReader(path)) + { + vCardReader reader = new vCardStandardReader(); + reader.ReadInto(this, streamReader); + } + + //String example = "BEGIN:VCARD\nVERSION:3.0\nN:;Saad;;;\nFN:Saad\nTEL;TYPE=CELL:418-271-3874\nTEL;TYPE=HOME:418-524-7721\nEND:VCARD"; + // using (MemoryStream s = GenerateStreamFromString(example)) + //{ + // vCardReader reader = new vCardStandardReader(); + // TextReader streamReader = new StreamReader(s, Encoding.Default); + // reader.ReadInto(this, streamReader); + //} + + } + + + /// + /// + /// + /// + /// + public MemoryStream GenerateStreamFromString(string s) + { + MemoryStream stream = new MemoryStream(); + StreamWriter writer = new StreamWriter(stream); + writer.Write(s); + writer.Flush(); + stream.Position = 0; + return stream; + } + + /// + /// The security access classification of the vCard owner (e.g. private). + /// + public vCardAccessClassification AccessClassification + { + get + { + return this.accessClassification; + } + set + { + this.accessClassification = value; + } + } + + + /// + /// Any additional (e.g. middle) names of the person. + /// + /// + /// + /// + /// + public string AdditionalNames + { + get + { + return this.additionalNames ?? string.Empty; + } + set + { + this.additionalNames = value; + } + } + + + /// + /// The birthdate of the person. + /// + public DateTime? BirthDate + { + get + { + return this.birthDate; + } + set + { + this.birthDate = value; + } + } + + + /// + /// Categories of the vCard. + /// + /// + /// This property is a collection of strings containing + /// keywords or category names. + /// + public StringCollection Categories + { + get + { + return this.categories; + } + } + + + /// + /// Public key certificates attached to the vCard. + /// + /// + public vCardCertificateCollection Certificates + { + get + { + return this.certificates; + } + } + + + /// + /// Delivery addresses associated with the person. + /// + public vCardDeliveryAddressCollection DeliveryAddresses + { + get + { + return this.deliveryAddresses; + } + } + + + /// + /// Formatted delivery labels. + /// + public vCardDeliveryLabelCollection DeliveryLabels + { + get + { + return this.deliveryLabels; + } + } + + + /// + /// The department of the person in the organization. + /// + /// + /// + public string Department + { + get + { + return this.department ?? string.Empty; + } + set + { + this.department = value; + } + } + + + /// + /// The display name of the vCard. + /// + /// + /// This property is used by vCard applications for titles, + /// headers, and other visual elements. + /// + public string DisplayName + { + get + { + return this.displayName ?? string.Empty; + } + set + { + this.displayName = value; + } + } + + + /// + /// A collection of objects for the person. + /// + /// + public vCardEmailAddressCollection EmailAddresses + { + get + { + return this.emailAddresses; + } + } + + + /// + /// The family (last) name of the person. + /// + /// + /// + /// + /// + public string FamilyName + { + get + { + return this.familyName ?? string.Empty; + } + set + { + this.familyName = value; + } + } + + + /// + /// The formatted name of the person. + /// + /// + /// This property allows the name of the person to be + /// written in a manner specific to his or her culture. + /// The formatted name is not required to strictly + /// correspond with the family name, given name, etc. + /// + /// + /// + /// + /// + public string FormattedName + { + get + { + return this.formattedName ?? string.Empty; + } + set + { + this.formattedName = value; + } + } + + + /// + /// The gender of the person. + /// + /// + /// The vCard specification does not define a property + /// to indicate the gender of the contact. Microsoft + /// Outlook implements it as a custom property named + /// X-WAB-GENDER. + /// + /// + public vCardGender Gender + { + get + { + return this.gender; + } + set + { + this.gender = value; + } + } + + + /// + /// The given (first) name of the person. + /// + /// + /// + /// + /// + public string GivenName + { + get + { + return this.givenName ?? string.Empty; + } + set + { + this.givenName = value; + } + } + + + /// + /// The latitude of the person in decimal degrees. + /// + /// + public float? Latitude + { + get + { + return this.latitude; + } + set + { + this.latitude = value; + } + } + + + /// + /// The longitude of the person in decimal degrees. + /// + /// + public float? Longitude + { + get + { + return this.longitude; + } + set + { + this.longitude = value; + } + } + + + /// + /// The mail software used by the person. + /// + public string Mailer + { + get + { + return this.mailer ?? string.Empty; + } + set + { + this.mailer = value; + } + } + + + /// + /// The prefix (e.g. "Mr.") of the person. + /// + /// + public string NamePrefix + { + get + { + return this.namePrefix ?? string.Empty; + } + set + { + this.namePrefix = value; + } + } + + + /// + /// The suffix (e.g. "Jr.") of the person. + /// + /// + public string NameSuffix + { + get + { + return this.nameSuffix ?? string.Empty; + } + set + { + this.nameSuffix = value; + } + } + + + /// + /// A collection of nicknames for the person. + /// + /// + /// + /// + /// + public StringCollection Nicknames + { + get + { + return this.nicknames; + } + } + + + /// + /// A collection of notes or comments. + /// + public vCardNoteCollection Notes + { + get + { + return this.notes; + } + } + + + /// + /// The office of the person at the organization. + /// + /// + /// + public string Office + { + get + { + return this.office ?? string.Empty; + } + set + { + this.office = value; + } + } + + + /// + /// The organization or company of the person. + /// + /// + /// + /// + public string Organization + { + get + { + return this.organization ?? string.Empty; + } + set + { + this.organization = value; + } + } + + + /// + /// A collection of telephone numbers. + /// + public vCardPhoneCollection Phones + { + get + { + return this.phones; + } + } + + + /// + /// A collection of photographic images embedded or + /// referenced by the vCard. + /// + public vCardPhotoCollection Photos + { + get + { + return this.photos; + } + } + + + /// + /// The name of the product that generated the vCard. + /// + public string ProductId + { + get + { + return this.productId ?? string.Empty; + } + set + { + this.productId = value; + } + } + + + /// + /// The revision date of the vCard. + /// + /// + /// The revision date is not automatically updated by the + /// vCard when modifying properties. It is up to the + /// developer to change the revision date as needed. + /// + public DateTime? RevisionDate + { + get + { + return this.revisionDate; + } + set + { + this.revisionDate = value; + } + } + + + /// + /// The role of the person (e.g. Executive). + /// + /// + /// The role is shown as "Profession" in Microsoft Outlook. + /// + /// + /// + /// + /// + public string Role + { + get + { + return this.role ?? string.Empty; + } + set + { + this.role = value; + } + } + + + /// + /// Directory sources for the vCard information. + /// + /// + /// A vCard may contain zero or more sources. A source + /// identifies a directory that contains (or provided) + /// information found in the vCard. A program can + /// hypothetically connect to the source in order to + /// obtain updated information. + /// + public vCardSourceCollection Sources + { + get + { + return this.sources; + } + } + + + /// + /// A string identifying the time zone of the entity + /// represented by the vCard. + /// + public string TimeZone + { + get + { + return this.timeZone ?? string.Empty; + } + set + { + this.timeZone = value; + } + } + + + /// + /// The job title of the person. + /// + /// + /// + public string Title + { + get + { + return this.title ?? string.Empty; + } + set + { + this.title = value; + } + } + + + /// + /// Builds a string that represents the vCard. + /// + /// + /// The formatted name of the contact person, if defined, + /// or the default object.ToString(). + /// + public override string ToString() + { + if (string.IsNullOrEmpty(this.formattedName)) + { + return base.ToString(); + } + else + { + return this.formattedName; + } + } + + + /// + /// A value that uniquely identifies the vCard. + /// + /// + /// This value is optional. The string must be any string + /// that can be used to uniquely identify the vCard. The + /// usage of the field is determined by the software. Typical + /// possibilities for a unique string include a URL, a GUID, + /// or an LDAP directory path. However, there is no particular + /// standard dictated by the vCard specification. + /// + public string UniqueId + { + get + { + return this.uniqueId ?? string.Empty; + } + set + { + this.uniqueId = value; + } + } + + + /// + /// Web sites associated with the person. + /// + /// + /// + public vCardWebsiteCollection Websites + { + get + { + return this.websites; + } + } + + } +} diff --git a/vCardEditor/Thought.vCards/vCardAccessClassification.cs b/vCardEditor/Thought.vCards/vCardAccessClassification.cs new file mode 100644 index 0000000..b93d9ca --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardAccessClassification.cs @@ -0,0 +1,44 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; + +namespace Thought.vCards +{ + + /// + /// The access classification of a vCard. + /// + /// + /// The access classification defines the intent of the vCard owner. + /// + public enum vCardAccessClassification + { + + /// + /// The vCard classification is unknown. + /// + Unknown = 0, + + /// + /// The vCard is classified as public. + /// + Public, + + /// + /// The vCard is classified as private. + /// + Private, + + /// + /// The vCard is classified as confidential. + /// + Confidential + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardCertificate.cs b/vCardEditor/Thought.vCards/vCardCertificate.cs new file mode 100644 index 0000000..83b34ab --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardCertificate.cs @@ -0,0 +1,125 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Security.Cryptography.X509Certificates; + +namespace Thought.vCards +{ + + /// + /// A certificate attached to a vCard. + /// + /// + /// + /// A vCard can be associated with a public key or + /// authentication certificate. This is typically + /// a public X509 certificate that allows people to + /// use the key for validating messages. + /// + /// + [Serializable] + public class vCardCertificate + { + + private string keyType; + private byte[] data; + + + /// + /// Creates a new instance of the class. + /// + public vCardCertificate() + { + this.keyType = string.Empty; + } + + + /// + /// Creates a new instance of the + /// class using the specified key type and raw certificate data. + /// + /// + /// A string that identifies the type of certificate, + /// such as X509. + /// + /// + /// The raw certificate data stored as a byte array. + /// + public vCardCertificate(string keyType, byte[] data) + { + if (string.IsNullOrEmpty(keyType)) + throw new ArgumentNullException("keyType"); + + if (data == null) + throw new ArgumentNullException("data"); + + this.keyType = keyType; + this.data = data; + } + + + /// + /// Creates a vCard certificate based on an X509 certificate. + /// + /// + /// An initialized X509 certificate. + /// + public vCardCertificate(X509Certificate2 x509) + { + if (x509 == null) + throw new ArgumentNullException("x509"); + + this.data = x509.RawData; + this.keyType = "X509"; + + } + + + /// + /// The raw data of the certificate as a byte array. + /// + /// + /// Most certificates consist of 8-bit binary data + /// that is encoded into a text format using BASE64 + /// or a similar system. This property provides + /// access to the computer-friendly, decoded data. + /// + public byte[] Data + { + get + { + return this.data; + } + set + { + this.data = value; + } + } + + + /// + /// A short string that identifies the type of certificate. + /// + /// + /// The most common type is X509. + /// + public string KeyType + { + get + { + return this.keyType ?? string.Empty; + } + set + { + this.keyType = value; + } + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardCertificateCollection.cs b/vCardEditor/Thought.vCards/vCardCertificateCollection.cs new file mode 100644 index 0000000..9fb12a5 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardCertificateCollection.cs @@ -0,0 +1,21 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections.ObjectModel; + +namespace Thought.vCards +{ + + /// + /// A collection of objects. + /// + public class vCardCertificateCollection : Collection + { + } + +} diff --git a/vCardEditor/Thought.vCards/vCardCollection.cs b/vCardEditor/Thought.vCards/vCardCollection.cs new file mode 100644 index 0000000..b27f51b --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardCollection.cs @@ -0,0 +1,22 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections.ObjectModel; + +namespace Thought.vCards +{ + + /// + /// A generic collection of objects. + /// + public class vCardCollection : Collection + { + } + +} + diff --git a/vCardEditor/Thought.vCards/vCardDeliveryAddress.cs b/vCardEditor/Thought.vCards/vCardDeliveryAddress.cs new file mode 100644 index 0000000..94a73ee --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardDeliveryAddress.cs @@ -0,0 +1,286 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; + +namespace Thought.vCards +{ + + /// + /// A postal address. + /// + /// + [Serializable] + public class vCardDeliveryAddress + { + + private vCardDeliveryAddressTypes addressType; + private string city; + private string country; + private string postalCode; + private string region; + private string street; + + + /// + /// Creates a new delivery address object. + /// + public vCardDeliveryAddress() + { + this.city = string.Empty; + this.country = string.Empty; + this.postalCode = string.Empty; + this.region = string.Empty; + this.street = string.Empty; + } + + + /// + /// The type of postal address. + /// + public vCardDeliveryAddressTypes AddressType + { + get + { + return this.addressType; + } + set + { + this.addressType = value; + } + } + + + /// + /// The city or locality of the address. + /// + public string City + { + get + { + return this.city ?? string.Empty; + } + set + { + this.city = value; + } + } + + + /// + /// The country name of the address. + /// + public string Country + { + get + { + return this.country ?? string.Empty; + } + set + { + this.country = value; + } + } + + + /// + /// Indicates a domestic delivery address. + /// + public bool IsDomestic + { + get + { + return (this.addressType & vCardDeliveryAddressTypes.Domestic) == + vCardDeliveryAddressTypes.Domestic; + } + set + { + + if (value) + { + this.addressType |= vCardDeliveryAddressTypes.Domestic; + } + else + { + this.addressType &= ~vCardDeliveryAddressTypes.Domestic; + } + + } + } + + + /// + /// Indicates a home address. + /// + public bool IsHome + { + get + { + return (this.addressType & vCardDeliveryAddressTypes.Home) == + vCardDeliveryAddressTypes.Home; + } + set + { + if (value) + { + this.addressType |= vCardDeliveryAddressTypes.Home; + } + else + { + this.addressType &= ~vCardDeliveryAddressTypes.Home; + } + + } + } + + + /// + /// Indicates an international address. + /// + public bool IsInternational + { + get + { + return (this.addressType & vCardDeliveryAddressTypes.International) == + vCardDeliveryAddressTypes.International; + } + set + { + if (value) + { + this.addressType |= vCardDeliveryAddressTypes.International; + } + else + { + this.addressType &= ~vCardDeliveryAddressTypes.International; + } + } + } + + + /// + /// Indicates a parcel delivery address. + /// + public bool IsParcel + { + get + { + return (this.addressType & vCardDeliveryAddressTypes.Parcel) == + vCardDeliveryAddressTypes.Parcel; + } + set + { + if (value) + { + this.addressType |= vCardDeliveryAddressTypes.Parcel; + } + else + { + this.addressType &= ~vCardDeliveryAddressTypes.Parcel; + } + } + } + + + /// + /// Indicates a postal address. + /// + public bool IsPostal + { + get + { + return (this.addressType & vCardDeliveryAddressTypes.Postal) == + vCardDeliveryAddressTypes.Postal; + } + set + { + if (value) + { + this.addressType |= vCardDeliveryAddressTypes.Postal; + } + else + { + this.addressType &= ~vCardDeliveryAddressTypes.Postal; + } + } + } + + + /// + /// Indicates a work address. + /// + public bool IsWork + { + get + { + return (this.addressType & vCardDeliveryAddressTypes.Work) == + vCardDeliveryAddressTypes.Work; + } + set + { + if (value) + { + this.addressType |= vCardDeliveryAddressTypes.Work; + } + else + { + this.addressType &= ~vCardDeliveryAddressTypes.Work; + } + } + } + + + /// + /// The postal code (e.g. ZIP code) of the address. + /// + public string PostalCode + { + get + { + return this.postalCode ?? string.Empty; + } + set + { + this.postalCode = value; + } + } + + + /// + /// The region (state or province) of the address. + /// + public string Region + { + get + { + return this.region ?? string.Empty; + } + set + { + this.region = value; + } + } + + + /// + /// The street of the delivery address. + /// + public string Street + { + get + { + return this.street ?? string.Empty; + } + set + { + this.street = value; + } + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardDeliveryAddressCollection.cs b/vCardEditor/Thought.vCards/vCardDeliveryAddressCollection.cs new file mode 100644 index 0000000..bfdb0c4 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardDeliveryAddressCollection.cs @@ -0,0 +1,22 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections.ObjectModel; + +namespace Thought.vCards +{ + + /// + /// A collection of objects. + /// + /// + public class vCardDeliveryAddressCollection : Collection + { + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardDeliveryAddressTypes.cs b/vCardEditor/Thought.vCards/vCardDeliveryAddressTypes.cs new file mode 100644 index 0000000..4f63d19 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardDeliveryAddressTypes.cs @@ -0,0 +1,56 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; + +namespace Thought.vCards +{ + + /// + /// The type of a delivery address. + /// + [Flags] + public enum vCardDeliveryAddressTypes + { + + /// + /// Default address settings. + /// + Default = 0, + + /// + /// A domestic delivery address. + /// + Domestic, + + /// + /// An international delivery address. + /// + International, + + /// + /// A postal delivery address. + /// + Postal, + + /// + /// A parcel delivery address. + /// + Parcel, + + /// + /// A home delivery address. + /// + Home, + + /// + /// A work delivery address. + /// + Work + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardDeliveryLabel.cs b/vCardEditor/Thought.vCards/vCardDeliveryLabel.cs new file mode 100644 index 0000000..f40dae6 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardDeliveryLabel.cs @@ -0,0 +1,228 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; + +namespace Thought.vCards +{ + + /// + /// A formatted delivery label. + /// + /// + /// + public class vCardDeliveryLabel + { + + private vCardDeliveryAddressTypes addressType; + private string text; + + + /// + /// Initializes a new . + /// + public vCardDeliveryLabel() + { + } + + + /// + /// Initializes a new to + /// the specified text. + /// + /// + /// The formatted text of a delivery label. The label + /// may contain carriage returns, line feeds, and other + /// control characters. + /// + public vCardDeliveryLabel(string text) + { + this.text = text == null ? string.Empty : text; + } + + + /// + /// The type of delivery address for the label. + /// + public vCardDeliveryAddressTypes AddressType + { + get + { + return this.addressType; + } + set + { + this.addressType = value; + } + } + + + /// + /// Indicates a domestic delivery address. + /// + public bool IsDomestic + { + get + { + return (this.addressType & vCardDeliveryAddressTypes.Domestic) == + vCardDeliveryAddressTypes.Domestic; + } + set + { + + if (value) + { + this.addressType |= vCardDeliveryAddressTypes.Domestic; + } + else + { + this.addressType &= ~vCardDeliveryAddressTypes.Domestic; + } + + } + } + + + /// + /// Indicates a home address. + /// + public bool IsHome + { + get + { + return (this.addressType & vCardDeliveryAddressTypes.Home) == + vCardDeliveryAddressTypes.Home; + } + set + { + if (value) + { + this.addressType |= vCardDeliveryAddressTypes.Home; + } + else + { + this.addressType &= ~vCardDeliveryAddressTypes.Home; + } + + } + } + + + /// + /// Indicates an international address. + /// + public bool IsInternational + { + get + { + return (this.addressType & vCardDeliveryAddressTypes.International) == + vCardDeliveryAddressTypes.International; + } + set + { + if (value) + { + this.addressType |= vCardDeliveryAddressTypes.International; + } + else + { + this.addressType &= ~vCardDeliveryAddressTypes.International; + } + } + } + + + /// + /// Indicates a parcel delivery address. + /// + public bool IsParcel + { + get + { + return (this.addressType & vCardDeliveryAddressTypes.Parcel) == + vCardDeliveryAddressTypes.Parcel; + } + set + { + if (value) + { + this.addressType |= vCardDeliveryAddressTypes.Parcel; + } + else + { + this.addressType &= ~vCardDeliveryAddressTypes.Parcel; + } + } + } + + + /// + /// Indicates a postal address. + /// + public bool IsPostal + { + get + { + return (this.addressType & vCardDeliveryAddressTypes.Postal) == + vCardDeliveryAddressTypes.Postal; + } + set + { + if (value) + { + this.addressType |= vCardDeliveryAddressTypes.Postal; + } + else + { + this.addressType &= ~vCardDeliveryAddressTypes.Postal; + } + } + } + + + /// + /// Indicates a work address. + /// + public bool IsWork + { + get + { + return (this.addressType & vCardDeliveryAddressTypes.Work) == + vCardDeliveryAddressTypes.Work; + } + set + { + if (value) + { + this.addressType |= vCardDeliveryAddressTypes.Work; + } + else + { + this.addressType &= ~vCardDeliveryAddressTypes.Work; + } + } + } + + + /// + /// The formatted delivery text. + /// + public string Text + { + get + { + return this.text ?? string.Empty; + } + set + { + this.text = value; + } + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardDeliveryLabelCollection.cs b/vCardEditor/Thought.vCards/vCardDeliveryLabelCollection.cs new file mode 100644 index 0000000..dd95ca4 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardDeliveryLabelCollection.cs @@ -0,0 +1,21 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections.ObjectModel; + +namespace Thought.vCards +{ + + /// + /// A collection of objects. + /// + public class vCardDeliveryLabelCollection : Collection + { + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardEmailAddress.cs b/vCardEditor/Thought.vCards/vCardEmailAddress.cs new file mode 100644 index 0000000..75ed8e7 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardEmailAddress.cs @@ -0,0 +1,131 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; + +namespace Thought.vCards +{ + + /// + /// An email address in a . + /// + /// + /// Most vCard email addresses are Internet email addresses. However, + /// the vCard specification allows other email address formats, + /// such as CompuServe and X400. Unless otherwise specified, an + /// address is assumed to be an Internet address. + /// + /// + /// + public class vCardEmailAddress + { + + private string address; + private vCardEmailAddressType emailType; + private bool isPreferred; + + + /// + /// Creates a new . + /// + public vCardEmailAddress() + { + this.address = string.Empty; + this.emailType = vCardEmailAddressType.Internet; + } + + + /// + /// Creates a new Internet . + /// + /// + /// The Internet email address. + /// + public vCardEmailAddress(string address) + { + this.address = address == null ? string.Empty : address; + this.emailType = vCardEmailAddressType.Internet; + } + + + /// + /// Creates a new of the specified type. + /// + /// + /// The email address. + /// + /// + /// The type of email address. + /// + public vCardEmailAddress(string address, vCardEmailAddressType emailType) + { + this.address = address; + this.emailType = emailType; + } + + + /// + /// The email address. + /// + /// + /// The format of the email address is not validated by the class. + /// + public string Address + { + get + { + return this.address ?? string.Empty; + } + set + { + this.address = value; + } + } + + + /// + /// The email address type. + /// + public vCardEmailAddressType EmailType + { + get + { + return this.emailType; + } + set + { + this.emailType = value; + } + } + + + /// + /// Indicates a preferred (top priority) email address. + /// + public bool IsPreferred + { + get + { + return this.isPreferred; + } + set + { + this.isPreferred = value; + } + } + + + /// + /// Builds a string that represents the email address. + /// + public override string ToString() + { + return this.address; + } + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardEmailAddressCollection.cs b/vCardEditor/Thought.vCards/vCardEmailAddressCollection.cs new file mode 100644 index 0000000..d11725f --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardEmailAddressCollection.cs @@ -0,0 +1,70 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections.ObjectModel; + +namespace Thought.vCards +{ + + /// + /// A collection of objects. + /// + /// + /// + public class vCardEmailAddressCollection : Collection + { + + /// + /// Initializes a new instance of the . + /// + public vCardEmailAddressCollection() + : base() + { + } + + /// + /// Locates the first email address of the specified type while + /// giving preference to email addresses marked as preferred. + /// + /// + /// The type of email address to locate. This can be any + /// combination of values from . + /// + /// + /// The function returns the first preferred email address that matches + /// the specified type. If the collection does not contain a preferred + /// email address, then it will return the first non-preferred matching + /// email address. The function returns null if no matches were found. + /// + public vCardEmailAddress GetFirstChoice(vCardEmailAddressType emailType) + { + + vCardEmailAddress firstNonPreferred = null; + + foreach (vCardEmailAddress email in this) + { + + if ((email.EmailType & emailType) == emailType) + { + + if (firstNonPreferred == null) + firstNonPreferred = email; + + if (email.IsPreferred) + return email; + } + + } + + return firstNonPreferred; + + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardEmailAddressType.cs b/vCardEditor/Thought.vCards/vCardEmailAddressType.cs new file mode 100644 index 0000000..e1bc34c --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardEmailAddressType.cs @@ -0,0 +1,97 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; + +namespace Thought.vCards +{ + + /// + /// Identifies the type of email address in a vCard. + /// + /// + public enum vCardEmailAddressType + { + + /// + /// An Internet (SMTP) mail (default) address. + /// + Internet = 0, + + + /// + /// An America On-Line email address. + /// + AOL, + + + /// + /// An AppleLink email address. + /// + AppleLink, + + + /// + /// An AT&T Mail email address + /// + AttMail, + + + /// + /// A CompuServe Information Service (CIS) email address. + /// + CompuServe, + + + /// + /// An eWorld email address. + /// + /// + /// eWorld was an online service by Apple Computer in the mid 1990s. + /// It was officially shut down on March 31, 1996. + /// + eWorld, + + + /// + /// An IBM Mail email address. + /// + IBMMail, + + + /// + /// An MCI Mail email address. + /// + MCIMail, + + + /// + /// A PowerShare email address. + /// + PowerShare, + + + /// + /// A Prodigy Information Service email address. + /// + Prodigy, + + + /// + /// A telex email address. + /// + Telex, + + + /// + /// An X.400 service email address. + /// + X400 + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardEncoding.cs b/vCardEditor/Thought.vCards/vCardEncoding.cs new file mode 100644 index 0000000..6db8b30 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardEncoding.cs @@ -0,0 +1,41 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; + +namespace Thought.vCards +{ + + /// + /// The encoding used to store a vCard property value in text format. + /// + public enum vCardEncoding + { + + /// + /// Unknown or no encoding. + /// + Unknown = 0, + + /// + /// Standard escaped text. + /// + Escaped, + + /// + /// Binary or BASE64 encoding. + /// + Base64, + + /// + /// Quoted-Printable encoding. + /// + QuotedPrintable + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardException.cs b/vCardEditor/Thought.vCards/vCardException.cs new file mode 100644 index 0000000..020df0d --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardException.cs @@ -0,0 +1,66 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; + +namespace Thought.vCards +{ + + /// + /// Base class for -specific exceptions. + /// + [Serializable] + public class vCardException : Exception + { + + + /// + /// Initializes a new instance of the vCardException class. + /// + public vCardException() + : base() + { + } + + + /// + /// Initializes a new instance of the vCardException + /// class with the specified error message. + /// + /// + /// The message that describes the error. + /// + public vCardException(string message) + : base(message) + { + } + + + /// + /// Initializes a new instance of the vCardException + /// class with a specified error message and a reference + /// to the inner exception that is the cause of the + /// exception. + /// + /// + /// The error message that explains the reason for the exception. + /// + /// + /// The exception that is the cause of the current exception, + /// or a null reference (Nothing in Visual Basic) if no + /// inner exception is specified. + /// + public vCardException(string message, Exception innerException) + : base(message, innerException) + { + } + + + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardFormat.cs b/vCardEditor/Thought.vCards/vCardFormat.cs new file mode 100644 index 0000000..3a4ed14 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardFormat.cs @@ -0,0 +1,43 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; + +namespace Thought.vCards +{ + + /// + /// Identifies different vCard formats. + /// + public enum vCardFormat + { + + /// + /// Standard text format. + /// + Text, + + /// + /// Jabber XML format (not implemented yet). + /// + JabberXml, + + + /// + /// RDF format (not implemented yet). + /// + Rdf, + + + /// + /// hCard microformat (not implemented yet). + /// + hCard + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardGender.cs b/vCardEditor/Thought.vCards/vCardGender.cs new file mode 100644 index 0000000..2b1b684 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardGender.cs @@ -0,0 +1,47 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; + +namespace Thought.vCards +{ + + /// + /// The gender (male or female) of the contact. + /// + /// + /// + /// Gender is not directly supported by the vCard specification. + /// It is recognized by Microsoft Outlook and the Windows Address + /// Book through an extended property called X-WAB-GENDER. This + /// property has a value of 1 for women and 2 for men. + /// + /// + /// + public enum vCardGender + { + + /// + /// Unknown gender. + /// + Unknown = 0, + + + /// + /// Female gender. + /// + Female = 1, + + + /// + /// Male gender. + /// + Male = 2 + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardNote.cs b/vCardEditor/Thought.vCards/vCardNote.cs new file mode 100644 index 0000000..dce8789 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardNote.cs @@ -0,0 +1,82 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +namespace Thought.vCards +{ + + /// + /// A note or comment in a vCard. + /// + public class vCardNote + { + + private string language; + private string text; + + + /// + /// Initializes a new vCard note. + /// + public vCardNote() + { + } + + + /// + /// Initializes a new vCard note with the specified text. + /// + /// + /// The text of the note or comment. + /// + public vCardNote(string text) + { + this.text = text; + } + + + /// + /// The language of the note. + /// + public string Language + { + get + { + return this.language ?? string.Empty; + } + set + { + this.language = value; + } + } + + /// + /// The text of the note. + /// + public string Text + { + get + { + return this.text ?? string.Empty; + } + set + { + this.text = value; + } + } + + + /// + /// Returns the text of the note. + /// + public override string ToString() + { + return this.text ?? string.Empty; + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardNoteCollection.cs b/vCardEditor/Thought.vCards/vCardNoteCollection.cs new file mode 100644 index 0000000..0b98e25 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardNoteCollection.cs @@ -0,0 +1,48 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections.ObjectModel; + +namespace Thought.vCards +{ + + /// + /// A collection of objects. + /// + public class vCardNoteCollection : Collection + { + + /// + /// Initializes a new instance of the . + /// + public vCardNoteCollection() + : base() + { + } + + /// + /// Adds a new note to the collection. + /// + /// + /// The text of the note. + /// + /// + /// The object representing the note. + /// + public vCardNote Add(string text) + { + + vCardNote note = new vCardNote(text); + Add(note); + return note; + + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardPhone.cs b/vCardEditor/Thought.vCards/vCardPhone.cs new file mode 100644 index 0000000..6a7c960 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardPhone.cs @@ -0,0 +1,411 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; + +namespace Thought.vCards +{ + + /// + /// Telephone information for a . + /// + /// + /// + [Serializable] + public class vCardPhone + { + + private string fullNumber; + private vCardPhoneTypes phoneType; + + + /// + /// Creates a new object. + /// + public vCardPhone() + { + } + + + /// + /// Creates a new object with the specified number. + /// + /// + /// The phone number. + /// + public vCardPhone(string fullNumber) + { + this.fullNumber = fullNumber; + } + + + /// + /// Creates a new with the specified number and subtype. + /// + /// The phone number. + /// The phone subtype. + public vCardPhone(string fullNumber, vCardPhoneTypes phoneType) + { + this.fullNumber = fullNumber; + this.phoneType = phoneType; + } + + + /// + /// The full telephone number. + /// + public string FullNumber + { + get + { + return this.fullNumber ?? string.Empty; + } + set + { + this.fullNumber = value; + } + } + + + /// + /// Indicates a BBS number. + /// + /// + /// + public bool IsBBS + { + get + { + return (this.phoneType & vCardPhoneTypes.BBS) == vCardPhoneTypes.BBS; + } + set + { + if (value) + { + this.phoneType = this.phoneType | vCardPhoneTypes.BBS; + } + else + { + this.phoneType = this.phoneType & ~vCardPhoneTypes.BBS; + } + } + } + + + /// + /// Indicates a car number. + /// + /// + public bool IsCar + { + get + { + return (this.phoneType & vCardPhoneTypes.Car) == vCardPhoneTypes.Car; + } + set + { + if (value) + { + this.phoneType = this.phoneType | vCardPhoneTypes.Car; + } + else + { + this.phoneType = this.phoneType & ~vCardPhoneTypes.Car; + } + } + } + + + /// + /// Indicates a cellular number. + /// + /// + public bool IsCellular + { + get + { + return (this.phoneType & vCardPhoneTypes.Cellular) == vCardPhoneTypes.Cellular; + } + set + { + if (value) + { + this.phoneType = this.phoneType | vCardPhoneTypes.Cellular; + } + else + { + this.phoneType = this.phoneType & ~vCardPhoneTypes.Cellular; + } + } + } + + + /// + /// Indicates a fax number. + /// + /// + public bool IsFax + { + get + { + return (this.phoneType & vCardPhoneTypes.Fax) == vCardPhoneTypes.Fax; + } + set + { + if (value) + { + this.phoneType = this.phoneType | vCardPhoneTypes.Fax; + } + else + { + this.phoneType = this.phoneType & ~vCardPhoneTypes.Fax; + } + } + } + + + /// + /// Indicates a home number. + /// + /// + /// + public bool IsHome + { + get + { + return (this.phoneType & vCardPhoneTypes.Home) == vCardPhoneTypes.Home; + } + set + { + if (value) + { + this.phoneType = this.phoneType | vCardPhoneTypes.Home; + } + else + { + this.phoneType = this.phoneType & ~vCardPhoneTypes.Home; + } + } + } + + + /// + /// Indicates an ISDN number. + /// + /// + public bool IsISDN + { + get + { + return (this.phoneType & vCardPhoneTypes.ISDN) == vCardPhoneTypes.ISDN; + } + set + { + if (value) + { + this.phoneType = this.phoneType | vCardPhoneTypes.ISDN; + } + else + { + this.phoneType = this.phoneType & ~vCardPhoneTypes.ISDN; + } + } + } + + + /// + /// Indicates a messaging service number. + /// + /// + public bool IsMessagingService + { + get + { + return (this.phoneType & vCardPhoneTypes.MessagingService) == + vCardPhoneTypes.MessagingService; + } + set + { + if (value) + { + this.phoneType = this.phoneType | vCardPhoneTypes.MessagingService; + } + else + { + this.phoneType = this.phoneType & ~vCardPhoneTypes.MessagingService; + } + } + } + + + /// + /// Indicates a modem number. + /// + /// + /// + public bool IsModem + { + get + { + return (this.phoneType & vCardPhoneTypes.Modem) == vCardPhoneTypes.Modem; + } + set + { + if (value) + { + this.phoneType = this.phoneType | vCardPhoneTypes.Modem; + } + else + { + this.phoneType = this.phoneType & ~vCardPhoneTypes.Modem; + } + } + } + + + /// + /// Indicates a pager number. + /// + /// + public bool IsPager + { + get + { + return (this.phoneType & vCardPhoneTypes.Pager) == vCardPhoneTypes.Pager; + } + set + { + if (value) + { + this.phoneType = this.phoneType | vCardPhoneTypes.Pager; + } + else + { + this.phoneType = this.phoneType & ~vCardPhoneTypes.Pager; + } + } + } + + + /// + /// Indicates a preferred number. + /// + /// + public bool IsPreferred + { + get + { + return (this.phoneType & vCardPhoneTypes.Preferred) == vCardPhoneTypes.Preferred; + } + set + { + if (value) + { + this.phoneType = this.phoneType | vCardPhoneTypes.Preferred; + } + else + { + this.phoneType = this.phoneType & ~vCardPhoneTypes.Preferred; + } + } + } + + + /// + /// Indicates a video number. + /// + /// + public bool IsVideo + { + get + { + return (this.phoneType & vCardPhoneTypes.Video) == vCardPhoneTypes.Video; + } + set + { + if (value) + { + this.phoneType = this.phoneType | vCardPhoneTypes.Video; + } + else + { + this.phoneType = this.phoneType & ~vCardPhoneTypes.Video; + } + } + } + + + /// + /// Indicates a voice number. + /// + /// + public bool IsVoice + { + get + { + return (this.phoneType & vCardPhoneTypes.Voice) == vCardPhoneTypes.Voice; + } + set + { + if (value) + { + this.phoneType = this.phoneType | vCardPhoneTypes.Voice; + } + else + { + this.phoneType = this.phoneType & ~vCardPhoneTypes.Voice; + } + } + } + + + /// + /// Indicates a work number. + /// + /// + /// + public bool IsWork + { + get + { + return (this.phoneType & vCardPhoneTypes.Work) == vCardPhoneTypes.Work; + } + set + { + if (value) + { + this.phoneType = this.phoneType | vCardPhoneTypes.Work; + } + else + { + this.phoneType = this.phoneType & ~vCardPhoneTypes.Work; + } + } + } + + + /// + /// The phone subtype. + /// + /// + /// + /// + public vCardPhoneTypes PhoneType + { + get + { + return this.phoneType; + } + set + { + this.phoneType = value; + } + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardPhoneCollection.cs b/vCardEditor/Thought.vCards/vCardPhoneCollection.cs new file mode 100644 index 0000000..f5681fb --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardPhoneCollection.cs @@ -0,0 +1,67 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections.ObjectModel; + +namespace Thought.vCards +{ + + /// + /// A generic collection objects. + /// + /// + /// + public class vCardPhoneCollection : Collection + { + + + /// + /// Looks for the first phone of the specified + /// type that is a preferred phone. + /// + /// + /// The type of phone to seek. + /// + /// + /// The first that matches + /// the specified type. A preferred number is returned + /// before a non-preferred number. + /// + public vCardPhone GetFirstChoice(vCardPhoneTypes phoneType) + { + + vCardPhone firstNonPreferred = null; + + foreach (vCardPhone phone in this) + { + + if ((phone.PhoneType & phoneType) == phoneType) + { + + // This phone has the same phone type as + // specified by the caller. Save a reference + // to the first such phone encountered. + + if (firstNonPreferred == null) + firstNonPreferred = phone; + + if (phone.IsPreferred) + return phone; + } + + } + + // No phone had the specified phone type and was marked + // as preferred. + + return firstNonPreferred; + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardPhoneTypes.cs b/vCardEditor/Thought.vCards/vCardPhoneTypes.cs new file mode 100644 index 0000000..c96f2b8 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardPhoneTypes.cs @@ -0,0 +1,113 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; + +namespace Thought.vCards +{ + + /// + /// Identifies different phone types (e.g. Fax, BBS, etc). + /// + /// + /// + [Flags] + public enum vCardPhoneTypes + { + + /// + /// Indicates default properties. + /// + Default = 0, + + /// + /// Indicates a bulletin board system. + /// + BBS = 1, + + /// + /// Indicates a car phone. + /// + Car = 2, + + /// + /// Indicates a cell phone. + /// + Cellular = 4, + + /// + /// Indicates a celluar voice number. + /// + CellularVoice = Cellular + Voice, + + /// + /// Indicates a facsimile number. + /// + Fax = 8, + + /// + /// Indicates a home number + /// + Home = 16, + + /// + /// Indicates a home and voice number. + /// + HomeVoice = Home + Voice, + + /// + /// Indicates an ISDN number. + /// + ISDN = 32, + + /// + /// Indicates a messaging service on the number. + /// + MessagingService = 64, + + /// + /// Indicates a MODEM number. + /// + Modem = 128, + + /// + /// Indicates a pager number. + /// + Pager = 256, + + /// + /// Indicates a preferred number. + /// + Preferred = 512, + + /// + /// Indicates a video number. + /// + Video = 1024, + + /// + /// Indicates a voice number. + /// + Voice = 2048, + + /// + /// Indicates a work number. + /// + Work = 4096, + + /// + /// Indicates a work fax number. + /// + WorkFax = Work + Fax, + + /// + /// Indicates a work and voice number. + /// + WorkVoice = Work + Voice + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardPhoto.cs b/vCardEditor/Thought.vCards/vCardPhoto.cs new file mode 100644 index 0000000..c5ef8f9 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardPhoto.cs @@ -0,0 +1,279 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Drawing; +using System.IO; +using System.Net; + +namespace Thought.vCards +{ + + /// + /// A photo embedded in a vCard. + /// + /// + /// + /// You must specify the photo using a path, a byte array, + /// or a System.Drawing.Bitmap instance. The class will + /// extract the underlying raw bytes for storage into the + /// vCard. You can call the function + /// to create a new Windows bitmap object (e.g. for display + /// on a form) or to extract the raw + /// bytes (e.g. for transmission from a web page). + /// + /// + [Serializable] + public class vCardPhoto + { + + /// + /// The raw bytes of the image data. + /// + /// + /// The raw bytes can be passed directly to the photo object + /// or fetched from a file or remote URL. A .NET bitmap object + /// can also be specified, in which case the constructor + /// will load the raw bytes from the bitmap. + /// + private byte[] data; + + + /// + /// The url of the image. + /// + private Uri url; + + + /// + /// Loads a photograph from an array of bytes. + /// + /// + /// An array of bytes containing the raw data from + /// any of the supported image formats. + /// + public vCardPhoto(byte[] buffer) + { + if (buffer == null) + throw new ArgumentNullException("buffer"); + + this.data = (byte[])buffer.Clone(); + } + + + /// + /// The URL of the image. + /// + /// + /// A URL pointing to an image. + /// + public vCardPhoto(Uri url) + { + + if (url == null) + throw new ArgumentNullException("url"); + + this.url = url; + } + + + /// + /// Creates a new vCard photo from an image file. + /// + /// + /// The path to an image of any supported format. + /// + public vCardPhoto(string path) + { + + if (string.IsNullOrEmpty(path)) + throw new ArgumentNullException("path"); + + this.url = new Uri(path); + + } + + + /// + /// Creates a new vCard photo from an existing Bitmap object. + /// + /// + /// A bitmap to be attached to the vCard as a photo. + /// + public vCardPhoto(Bitmap bitmap) + { + + if (bitmap == null) + throw new ArgumentNullException("bitmap"); + + // Extract the raw bytes of the bitmap + // to a stream. + + MemoryStream bytes = new MemoryStream(); + bitmap.Save(bytes, bitmap.RawFormat); + + // Extract the bytes of the stream to the array. + + bytes.Seek(0, SeekOrigin.Begin); + bytes.Read(data, 0, (int)bytes.Length); + + } + + + /// + /// Fetches a linked image asynchronously. + /// + /// + /// This is a simple utility method for accessing the image + /// referenced by the URL. For asynchronous or advanced + /// loading you will need to download the image yourself + /// and load the bytes directly into the class. + /// + /// + /// + public void Fetch() + { + + // An image can be fetched only if the URL + // of the image is known. Otherwise the + // fetch operation makes no sense. + + if (this.url == null) + throw new InvalidOperationException(); + + // Create a web request object that will handle the + // specifics of downloading a file from the specified + // URL. For example, the URL is a file-based URL, then + // the CreateDefault method will return a FileWebRequest + // class. + + WebRequest request = + WebRequest.CreateDefault(this.url); + + // Start the request. The request begins when + // the GetResponse method is invoked. This is a + // synchronous (blocking) call (i.e. it will not + // return until the file is downloaded or an + // exception is raised). + + WebResponse response = request.GetResponse(); + + using (Stream responseStream = response.GetResponseStream()) + { + + // Allocate space to hold the entire image. + + this.data = new byte[response.ContentLength]; + + // The following call will fail if the image + // size is larger than the capacity of an Int32. + // This may be treated as a minor issue given + // the fact that this is a vCard library and + // such images are expected by humans to be small. + // No reasonable person would embed a multi-gigabyte + // image into a vCard. + + responseStream.Read( + this.data, + 0, + (int)response.ContentLength); + + } + + } + + + /// + /// Creates a Bitmap object from the photo data. + /// + /// + /// An initialized Bitmap object. An exception is + /// raised if the .NET framework is unable to identify + /// the format of the image data, or if the format + /// is not supported. + /// + public Bitmap GetBitmap() + { + MemoryStream stream = new MemoryStream(this.data); + return new Bitmap(stream); + + } + + + /// + /// Returns a copy of the raw bytes of the image. + /// + /// + /// A byte array containing the raw bytes of the image. + /// + /// + /// A copy of the raw bytes are returned. Modifying the + /// array will not modify the photo. + /// + public byte[] GetBytes() + { + return (byte[])this.data.Clone(); + } + + + /// + /// Indicates the bytes of the raw image have + /// been loaded by the object. + /// + /// + public bool IsLoaded + { + get + { + return this.data != null; + } + } + + + /// + /// The URL of the image. + /// + /// + /// Changing the URL will automatically invalidate the internal + /// image data if previously fetched. + /// + /// + public Uri Url + { + get + { + + return this.url; + } + set + { + + // This class maintains a byte array containing the raw + // bytes of the image. The use can call the Fetch method + // to load the raw bytes from a remote link. If the + // URL is changed (e.g. via this property), then the local + // cache must be invalidated. + + if (value == null) + { + this.data = null; + this.url = null; + } + else + { + if (this.url != value) + { + this.data = null; + this.url = value; + } + } + } + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardPhotoCollection.cs b/vCardEditor/Thought.vCards/vCardPhotoCollection.cs new file mode 100644 index 0000000..9d82532 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardPhotoCollection.cs @@ -0,0 +1,31 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections.ObjectModel; + +namespace Thought.vCards +{ + + /// + /// A collection of objects. + /// + /// + public class vCardPhotoCollection : Collection + { + + /// + /// Initializes a new instance of the . + /// + public vCardPhotoCollection() + : base() + { + } + + } + +} diff --git a/vCardEditor/Thought.vCards/vCardProperty.cs b/vCardEditor/Thought.vCards/vCardProperty.cs new file mode 100644 index 0000000..41c310a --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardProperty.cs @@ -0,0 +1,258 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Text; + +namespace Thought.vCards +{ + + /// + /// A property of a . + /// + /// + /// + /// A vCard property specifies a single piece of information, + /// such as an email address or telephone number. A property + /// can also specify meta-data like a revision number. A full + /// vCards is basically a collection of properties structured + /// into a computer-friendly text format. + /// + /// + /// A property has a name, a value, and optionally one or + /// more subproperties. A subproperty provides additional + /// information about the property (such as the encoding + /// used to store the value). The format of a value + /// depends on the property and in some cases may be broken + /// into multiple values. + /// + /// + /// + public class vCardProperty + { + + private string group; + private string language; + private string name; + private vCardSubpropertyCollection subproperties; + private object value; + + + /// + /// Creates a blank object. + /// + public vCardProperty() + { + this.subproperties = new vCardSubpropertyCollection(); + } + + + /// + /// Creates a object + /// with the specified name and a null value. + /// + /// + /// The name of the property. + /// + public vCardProperty(string name) + { + this.name = name; + this.subproperties = new vCardSubpropertyCollection(); + } + + + /// + /// Creates a object with the + /// specified name and value. + /// + /// + /// The vCard specification supports multiple values in + /// certain fields, such as the N field. The value specified + /// in this constructor is loaded as the first value. + /// + public vCardProperty(string name, string value) + { + this.name = name; + this.subproperties = new vCardSubpropertyCollection(); + this.value = value; + } + + + /// + /// Initializes a vCardProperty with the specified + /// name, value and group. + /// + /// + /// The name of the vCard property. + /// + /// + /// The value of the vCard property. + /// + /// + /// The group name of the vCard property. + /// + public vCardProperty(string name, string value, string group) + { + this.group = group; + this.name = name; + this.subproperties = new vCardSubpropertyCollection(); + this.value = value; + } + + + /// + /// Creates a with the + /// specified name and a byte array as a value. + /// + /// The name of the property. + /// The value as a byte array. + public vCardProperty(string name, byte[] value) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + + this.name = name; + this.subproperties = new vCardSubpropertyCollection(); + this.value = value; + } + + + /// + /// Creates a with + /// the specified name and date/time as a value. + /// + /// The name of the property. + /// The date/time value. + public vCardProperty(string name, DateTime value) + { + + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + + this.name = name; + this.subproperties = new vCardSubpropertyCollection(); + this.value = value; + } + + + /// + /// Initializes the vCard property with the specified + /// name and values. + /// + public vCardProperty(string name, vCardValueCollection values) + : this() + { + + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + + if (values == null) + throw new ArgumentNullException("values"); + + this.subproperties = new vCardSubpropertyCollection(); + this.name = name; + this.value = values; + } + + + /// + /// The group name of the property. + /// + public string Group + { + get + { + return this.group ?? string.Empty; + } + set + { + this.group = value; + } + } + + + /// + /// The language code of the property. + /// + public string Language + { + get + { + return this.language ?? string.Empty; + } + set + { + this.language = value; + } + } + + + /// + /// The name of the property (e.g. TEL). + /// + public string Name + { + get + { + return this.name ?? string.Empty; + } + set + { + this.name = value; + } + } + + + /// + /// Subproperties of the vCard property, not including + /// the name, encoding, and character set. + /// + public vCardSubpropertyCollection Subproperties + { + get + { + return this.subproperties; + } + } + + + /// + /// Returns the value of the property as a string. + /// + public override string ToString() + { + if (value == null) + { + return string.Empty; + } + else + { + return value.ToString(); + } + + } + + + /// + /// The value of the property. + /// + public object Value + { + get + { + return this.value; + } + set + { + this.value = value; + } + } + + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardPropertyCollection.cs b/vCardEditor/Thought.vCards/vCardPropertyCollection.cs new file mode 100644 index 0000000..ed34f65 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardPropertyCollection.cs @@ -0,0 +1,22 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections.ObjectModel; + +namespace Thought.vCards +{ + + /// + /// A generic collection of objects. + /// + /// + public class vCardPropertyCollection : Collection + { + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardReader.cs b/vCardEditor/Thought.vCards/vCardReader.cs new file mode 100644 index 0000000..c33c09f --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardReader.cs @@ -0,0 +1,94 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections.Specialized; +using System.IO; + +namespace Thought.vCards +{ + + /// + /// An abstract reader for vCard and vCard-like file formats. + /// + /// + /// + /// The property is a string collection + /// containing a description of each warning encountered during + /// the read process. An implementor of a card reader should + /// populate this collection as the vCard data is being parsed. + /// + /// + public abstract class vCardReader + { + + /// + /// Stores the warnings issued by the implementor + /// of the vCard reader. Currently warnings are + /// simple string messages; a future version will + /// store line numbers, severity levels, etc. + /// + /// + private StringCollection warnings; + + + /// + /// Initializes the base reader. + /// + protected vCardReader() + { + this.warnings = new StringCollection(); + } + + + /// + /// Reads a vCard from the specified input stream. + /// + /// + /// A text reader that points to the beginning of + /// a vCard in the format expected by the implementor. + /// + /// + /// An initialized object. + /// + public vCard Read(TextReader reader) + { + vCard card = new vCard(); + ReadInto(card, reader); + return card; + } + + + /// + /// Reads vCard information from a text reader and + /// populates into an existing vCard object. + /// + /// + /// An initialized vCard object. + /// + /// + /// A text reader containing vCard data in the format + /// expected by the card reader class. + /// + public abstract void ReadInto(vCard card, TextReader reader); + + + /// + /// A collection of warning messages. + /// + /// Reseved for future use. + public StringCollection Warnings + { + get + { + return this.warnings; + } + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardSource.cs b/vCardEditor/Thought.vCards/vCardSource.cs new file mode 100644 index 0000000..eaa55e1 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardSource.cs @@ -0,0 +1,110 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; + +namespace Thought.vCards +{ + + /// + /// A source of directory information for a vCard. + /// + /// + /// + /// A source identifies a directory that contains or provided + /// information for the vCard. A source consists of a URI + /// and a context. The URI is generally a URL; the + /// context identifies the protocol and type of URI. For + /// example, a vCard associated with an LDAP directory entry + /// will have an ldap:// URL and a context of "LDAP". + /// + /// + /// + public class vCardSource + { + + private string context; + private Uri uri; + + + /// + /// Initializes a new instance of the vCardSource class. + /// + public vCardSource() + { + this.context = string.Empty; + } + + + /// + /// Initializes a new source with the specified URI. + /// + /// + /// The URI of the directory entry. + /// + public vCardSource(Uri uri) + { + this.uri = uri; + } + + + /// + /// Initializes a new source with the specified + /// context and URI. + /// + /// + /// The URI of the source of the vCard data. + /// + /// + /// The context of the source. + /// + public vCardSource(Uri uri, string context) + { + this.context = context; + this.uri = uri; + } + + + /// + /// The context of the source URI. + /// + /// + /// The context identifies how the URI should be + /// interpreted. Example is "LDAP", which indicates + /// the URI is an LDAP reference. + /// + public string Context + { + get + { + return this.context ?? string.Empty; + } + set + { + this.context = value; + } + } + + + /// + /// The URI of the source. + /// + public Uri Uri + { + get + { + return this.uri; + } + set + { + this.uri = value; + } + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardSourceCollection.cs b/vCardEditor/Thought.vCards/vCardSourceCollection.cs new file mode 100644 index 0000000..f48a0cc --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardSourceCollection.cs @@ -0,0 +1,31 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections.ObjectModel; + +namespace Thought.vCards +{ + + /// + /// A collection of objects. + /// + /// + public class vCardSourceCollection : Collection + { + + /// + /// Initializes a new instance of the . + /// + public vCardSourceCollection() + : base() + { + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardStandardReader.cs b/vCardEditor/Thought.vCards/vCardStandardReader.cs new file mode 100644 index 0000000..66b47c6 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardStandardReader.cs @@ -0,0 +1,2156 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Globalization; +using System.IO; +using System.Text; + +namespace Thought.vCards +{ + + /// + /// Reads a vCard written in the standard 2.0 or 3.0 text formats. + /// This is the primary (standard) vCard format used by most + /// applications. + /// + /// + public class vCardStandardReader : vCardReader + { + + /// + /// The DeliveryAddressTypeNames array contains the recognized + /// TYPE values for an ADR (delivery address). + /// + private readonly string[] DeliveryAddressTypeNames = new string[] { + "DOM", // Domestic address + "INTL", // International address + "POSTAL", // Postal address + "PARCEL", // Parcel delivery address + "HOME", // Home address + "WORK", // Work address + "PREF" }; // Preferred address + + + /// + /// The PhoneTypeNames constant defines the recognized + /// subproperty names that identify the category or + /// classification of a phone. The names are used with + /// the TEL property. + /// + private readonly string[] PhoneTypeNames = new string[] { + "BBS", + "CAR", + "CELL", + "FAX", + "HOME", + "ISDN", + "MODEM", + "MSG", + "PAGER", + "PREF", + "VIDEO", + "VOICE", + "WORK" }; + + /// + /// The state of the quoted-printable decoder (private). + /// + /// + /// The function + /// is a utility function that parses a string that + /// has been encoded with the QUOTED-PRINTABLE format. + /// The function is implemented as a state-pased parser + /// where the state is updated after examining each + /// character of the input string. This enumeration + /// defines the various states of the parser. + /// + private enum QuotedPrintableState + { + None, + ExpectingHexChar1, + ExpectingHexChar2, + ExpectingLineFeed + } + + /// + /// Initializes a new instance of the . + /// + public vCardStandardReader() : base() + { + } + + + #region [ DecodeBase64(string) ] + + /// + /// Decodes a string containing BASE64 characters. + /// + /// + /// A string containing data that has been encoded with + /// the BASE64 format. + /// + /// + /// The decoded data as a byte array. + /// + public static byte[] DecodeBase64(string value) + { + + // Currently the .NET implementation is acceptable. However, + // a different algorithm may be used in the future. For + // this reason callers should use this function + // instead of the FromBase64String function in .NET. + // Performance is not an issue because the runtime engine + // will inline the code or eliminate the extra call. + + return Convert.FromBase64String(value); + } + + #endregion + + #region [ DecodeBase64(char[]) ] + + /// + /// Converts BASE64 data that has been stored in a + /// character array. + /// + /// + /// A character array containing BASE64 data. + /// + /// + /// A byte array containing the decoded BASE64 data. + /// + public static byte[] DecodeBase64(char[] value) + { + if (value == null) + { + throw new ArgumentNullException("value"); + } + else + { + return Convert.FromBase64CharArray(value, 0, value.Length); + } + } + + #endregion + + #region [ DecodeEmailAddressType ] + + /// + /// Parses the name of an email address type. + /// + /// + /// The email address type keyword found in the vCard file (e.g. AOL or INTERNET). + /// + /// + /// Null or the decoded . + /// + /// + /// + public static vCardEmailAddressType? DecodeEmailAddressType(string keyword) + { + + if (string.IsNullOrEmpty(keyword)) + return null; + + switch (keyword.ToUpperInvariant()) + { + + case "INTERNET": + return vCardEmailAddressType.Internet; + + case "AOL": + return vCardEmailAddressType.AOL; + + case "APPLELINK": + return vCardEmailAddressType.AppleLink; + + case "ATTMAIL": + return vCardEmailAddressType.AttMail; + + case "CIS": + return vCardEmailAddressType.CompuServe; + + case "EWORLD": + return vCardEmailAddressType.eWorld; + + case "IBMMAIL": + return vCardEmailAddressType.IBMMail; + + case "MCIMAIL": + return vCardEmailAddressType.MCIMail; + + case "POWERSHARE": + return vCardEmailAddressType.PowerShare; + + case "PRODIGY": + return vCardEmailAddressType.Prodigy; + + case "TLX": + return vCardEmailAddressType.Telex; + + case "X400": + return vCardEmailAddressType.X400; + + default: + return null; + + } + + + } + + #endregion + + #region [ DecodeEscaped ] + + /// + /// Decodes a string that has been encoded with the standard + /// vCard escape codes. + /// + /// + /// A string encoded with vCard escape codes. + /// + /// + /// The decoded string. + /// + public static string DecodeEscaped(string value) + { + + if (string.IsNullOrEmpty(value)) + return value; + + StringBuilder builder = new StringBuilder(value.Length); + + int startIndex = 0; + + do + { + + // Get the index of the next backslash character. + // This marks the beginning of an escape sequence. + + int nextIndex = value.IndexOf('\\', startIndex); + + if ((nextIndex == -1) || (nextIndex == value.Length - 1)) + { + // There are no more escape codes, or the backslash + // is located at the very end of the string. The + // characters between the index and the end of the + // string need to be copied to the output buffer. + + builder.Append( + value, + startIndex, + value.Length - startIndex); + + break; + + } + else + { + + // A backslash was located somewhere in the string. + // The previous statement ensured the backslash is + // not the very last character, and therefore the + // following statement is safe. + + char code = value[nextIndex + 1]; + + // Any characters between the starting point and + // the index must be pushed into the buffer. + + builder.Append( + value, + startIndex, + nextIndex - startIndex); + + switch (code) + { + + case '\\': + case ',': + case ';': + + builder.Append(code); + nextIndex += 2; + break; + + case 'n': + case 'N': + builder.Append('\n'); + nextIndex += 2; + break; + + case 'r': + case 'R': + builder.Append('\r'); + nextIndex += 2; + break; + + default: + builder.Append('\\'); + builder.Append(code); + nextIndex += 2; + break; + + } + + + } + + startIndex = nextIndex; + + } while (startIndex < value.Length); + + return builder.ToString(); + + } + + #endregion + + #region [ DecodeHexadecimal ] + + /// + /// Converts a single hexadecimal character to + /// its integer value. + /// + /// + /// A Unicode character. + /// + public static int DecodeHexadecimal(char value) + { + + if (char.IsDigit(value)) + { + return Convert.ToInt32(char.GetNumericValue(value)); + } + + // A = ASCII 65 + // F = ASCII 70 + // a = ASCII 97 + // f = ASCII 102 + + else if ((value >= 'A') && (value <= 'F')) + { + + // The character is one of the characters + // between 'A' (value 65) and 'F' (value 70). + // The character "A" (hex) is "10" (decimal). + + return Convert.ToInt32(value) - 55; + } + + else if ((value >= 'a') && (value <= 'f')) + { + + // The character is one of the characters + // between 'a' (value 97) and 'f' (value 102). + // The character "A" or "a" (hex) is "10" (decimal). + + return Convert.ToInt32(value) - 87; + + } + else + + // The specified character cannot be interpreted + // as a written hexadecimal character. Raise an + // exception. + + throw new ArgumentOutOfRangeException("value"); + + } + + #endregion + + #region [ DecodeQuotedPrintable ] + + /// + /// Decodes a string that has been encoded in QUOTED-PRINTABLE format. + /// + /// + /// A string that has been encoded in QUOTED-PRINTABLE. + /// + /// + /// The decoded string. + /// + public static string DecodeQuotedPrintable(string value) + { + + if (string.IsNullOrEmpty(value)) + return value; + + StringBuilder builder = new StringBuilder(); + char firstHexChar = '\x0'; + QuotedPrintableState state = QuotedPrintableState.None; + + foreach (char c in value) + { + + switch (state) + { + + case QuotedPrintableState.None: + + // The parser is not expacting any particular + // type of character. If the character is an + // equal sign (=), then this point in the string + // is the start of a character encoded in hexadecimal + // format. There are two hexadecimal characters + // expected. + + if (c == '=') + { + state = QuotedPrintableState.ExpectingHexChar1; + } + else + { + builder.Append(c); + } + break; + + case QuotedPrintableState.ExpectingHexChar1: + + // The parser previously encountered an equal sign. + // This has two purposes: it marks the beginning of + // a hexadecimal escape sequence, or it marks a + // so-called software end-of-line. + + if (IsHexDigit(c)) + { + + // The next character is a hexadecimal character. + // Therefore the equal sign marks the beginning + // of an escape sequence. + + firstHexChar = c; + state = QuotedPrintableState.ExpectingHexChar2; + } + + else if (c == '\r') + { + + // The prior equal sign was located immediately + // before carriage-return. This indicates a soft + // line break that is ignored. The next character + // is expected to be a line feed. + + state = QuotedPrintableState.ExpectingLineFeed; + + } + + else if (c == '=') + { + + // Another equal sign was encountered. This is + // bad data. The parser will output this bad + // character and assume this equal sign marks + // the beginning of a sequence. + + builder.Append('='); + state = QuotedPrintableState.ExpectingHexChar1; + + } + + else + { + + // The character after the equal sign was + // not a hex digit, a carriage return, or an + // equal sign. It is bad data. + + builder.Append('='); + builder.Append(c); + state = QuotedPrintableState.None; + } + break; + + case QuotedPrintableState.ExpectingHexChar2: + + // The parser previously encountered an equal + // sign and the first of two hexadecimal + // characters. This character is expected to + // be the second (final) hexadecimal character. + + if (IsHexDigit(c)) + { + + // Each hexadecimal character represents + // four bits of the encoded ASCII value. + // The first character was the upper 4 bits. + + int charValue = + (DecodeHexadecimal(firstHexChar) << 4) + + DecodeHexadecimal(c); + + builder.Append((char)charValue); + state = QuotedPrintableState.None; + + } + else + { + + // The parser was expecting the second + // hexadecimal character after the equal sign. + // Since this is not a hexadecimal character, + // the partial sequence is dumped to the output + // and skipped. + + builder.Append('='); + builder.Append(firstHexChar); + builder.Append(c); + state = QuotedPrintableState.None; + + } + break; + + case QuotedPrintableState.ExpectingLineFeed: + + // Previously the parser encountered an equal sign + // followed by a carriage-return. This is an indicator + // to the decoder that the encoded value contains a + // soft line break. The line break is ignored. + // Per mime standards, the character following the + // carriage-return should be a line feed. + + if (c == '\n') + { + state = QuotedPrintableState.None; + } + else if (c == '=') + { + // A line feed was expected but another equal + // sign was encountered. Assume the encoder + // failed to write a line feed. + + state = QuotedPrintableState.ExpectingHexChar1; + } + else + { + builder.Append(c); + state = QuotedPrintableState.None; + } + + break; + } + } + + // The parser has examined each character in the input string. + // In theory (for a correct string), the parser state should be + // none -- that is, all codes were property terminated. If not, + // the partial codes should be flushed to the output. + + switch (state) + { + case QuotedPrintableState.ExpectingHexChar1: + builder.Append('='); + break; + + case QuotedPrintableState.ExpectingHexChar2: + builder.Append('='); + builder.Append(firstHexChar); + break; + + case QuotedPrintableState.ExpectingLineFeed: + builder.Append('='); + builder.Append('\r'); + break; + } + + return builder.ToString(); + + } + + #endregion + + #region [ IsHexDigit ] + + /// + /// Indicates whether the specified character is + /// a hexadecimal digit. + /// + /// + /// + /// A unicode character + /// + public static bool IsHexDigit(char value) + { + + // First, see if the character is + // a decimal digit. All decimal digits + // are also hexadecimal digits. + + if (char.IsDigit(value)) + + return true; + + return + ((value >= 'A') && (value <= 'F')) || + ((value >= 'a') && (value <= 'f')); + + } + + #endregion + + // The following functions (Parse*) are utility functions + // that convert string values into their corresponding + // enumeration values from the class library. Some misc. + // parser functions are also present. + + #region [ ParseDate ] + + /// + /// Parses a string containing a date/time value. + /// + /// + /// A string containing a date/time value. + /// + /// + /// The parsed date, or null if no date could be parsed. + /// + /// + /// Some revision dates, such as those generated by Outlook, + /// are not directly supported by the .NET DateTime parser. + /// This function attempts to accomodate the non-standard formats. + /// + public static DateTime? ParseDate(string value) + { + + DateTime parsed; + if (DateTime.TryParse(value, out parsed)) + return parsed; + + // Outlook generates a revision date like this: + // + // 20061130T234000Z + // | | | || | ++------- Seconds (2 digits) + // | | | || ++--------- Minutes (2 digits) + // | | | |++----------- Hour (2 digits) + // | | | +------------- T (literal) + // | | ++-------------- Day (2 digits) + // | ++---------------- Month (2 digits) + // +--+------------------ Year (4 digits) + // + // This format does not seem to be recognized by + // the standard DateTime parser. A custom string + // can be defined: + // + // yyyyMMdd\THHmmss\Z + + if (DateTime.TryParseExact( + value, + @"yyyyMMdd\THHmmss\Z", + null, + DateTimeStyles.AssumeUniversal, + out parsed)) + { + return parsed; + } + + return null; + + } + + #endregion + + #region [ ParseEncoding ] + + /// + /// Parses an encoding name (such as "BASE64") and returns + /// the corresponding value. + /// + /// + /// The name of an encoding from a standard vCard property. + /// + /// + /// The enumerated value of the encoding. + /// + public static vCardEncoding ParseEncoding(string name) + { + + // If not specified, the default encoding (escaped) used + // by the vCard file specification is assumed. + + if (string.IsNullOrEmpty(name)) + return vCardEncoding.Unknown; + + switch (name.ToUpperInvariant()) + { + case "B": + + // Some vCard specification documents list the + // encoding name "b" instead of "base64". + + return vCardEncoding.Base64; + + case "BASE64": + return vCardEncoding.Base64; + + case "QUOTED-PRINTABLE": + return vCardEncoding.QuotedPrintable; + + default: + return vCardEncoding.Unknown; + + } + + } + + #endregion + + #region [ ParsePhoneType(string) ] + + /// + /// Parses the name of a phone type and returns the + /// corresponding value. + /// + /// + /// The name of a phone type from a TEL vCard property. + /// + /// + /// The enumerated value of the phone type, or Default + /// if the phone type could not be determined. + /// + public static vCardPhoneTypes ParsePhoneType(string name) + { + + if (string.IsNullOrEmpty(name)) + return vCardPhoneTypes.Default; + + switch (name.Trim().ToUpperInvariant()) + { + + + case "BBS": + return vCardPhoneTypes.BBS; + + case "CAR": + return vCardPhoneTypes.Car; + + case "CELL": + return vCardPhoneTypes.Cellular; + + case "FAX": + return vCardPhoneTypes.Fax; + + case "HOME": + return vCardPhoneTypes.Home; + + case "ISDN": + return vCardPhoneTypes.ISDN; + + case "MODEM": + return vCardPhoneTypes.Modem; + + case "MSG": + return vCardPhoneTypes.MessagingService; + + case "PAGER": + return vCardPhoneTypes.Pager; + + case "PREF": + return vCardPhoneTypes.Preferred; + + case "VIDEO": + return vCardPhoneTypes.Video; + + case "VOICE": + return vCardPhoneTypes.Voice; + + case "WORK": + return vCardPhoneTypes.Work; + + default: + return vCardPhoneTypes.Default; + } + + } + + #endregion + + #region [ ParsePhoneType(string[]) ] + + /// + /// Decodes the bitmapped phone type given an array of + /// phone type names. + /// + /// + /// An array containing phone type names such as BBS or VOICE. + /// + /// + /// The phone type value that represents the combination + /// of all names defined in the array. Unknown names are + /// ignored. + /// + public static vCardPhoneTypes ParsePhoneType(string[] names) + { + + vCardPhoneTypes sum = vCardPhoneTypes.Default; + + foreach (string name in names) + { + sum |= ParsePhoneType(name); + } + + return sum; + + } + + #endregion + + #region [ ParseDeliveryAddressType(string) ] + + /// + /// Parses the type of postal address. + /// + /// + /// The single value of a TYPE subproperty for the ADR property. + /// + /// + /// The that corresponds + /// with the TYPE keyword, or vCardPostalAddressType.Default if + /// the type could not be identified. + /// + public static vCardDeliveryAddressTypes ParseDeliveryAddressType(string value) + { + + if (string.IsNullOrEmpty(value)) + return vCardDeliveryAddressTypes.Default; + + switch (value.ToUpperInvariant()) + { + case "DOM": + return vCardDeliveryAddressTypes.Domestic; + + case "HOME": + return vCardDeliveryAddressTypes.Home; + + case "INTL": + return vCardDeliveryAddressTypes.International; + + case "PARCEL": + return vCardDeliveryAddressTypes.Parcel; + + case "POSTAL": + return vCardDeliveryAddressTypes.Postal; + + case "WORK": + return vCardDeliveryAddressTypes.Work; + + default: + return vCardDeliveryAddressTypes.Default; + } + + } + + #endregion + + #region [ ParseDeliveryAddressType(string[]) ] + + /// + /// Parses a string array containing one or more + /// postal address types. + /// + /// + /// A string array containing zero or more keywords + /// used with the TYPE subproperty of the ADR property. + /// + /// + /// A flags enumeration + /// that corresponds with all known type names from the array. + /// + public static vCardDeliveryAddressTypes ParseDeliveryAddressType(string[] typeNames) + { + + vCardDeliveryAddressTypes allTypes = vCardDeliveryAddressTypes.Default; + + foreach (string typeName in typeNames) + { + allTypes |= ParseDeliveryAddressType(typeName); + } + + return allTypes; + + } + + #endregion + + + #region [ ReadInto(vCard, TextReader) ] + + /// + /// Reads a vCard (VCF) file from an input stream. + /// + /// + /// An initialized vCard. + /// + /// + /// A text reader pointing to the beginning of + /// a standard vCard file. + /// + /// + /// The vCard with values updated from the file. + /// + public override void ReadInto(vCard card, TextReader reader) + { + + vCardProperty property; + + do + { + property = ReadProperty(reader); + + if (property != null) + { + + if ( + (string.Compare("END", property.Name, StringComparison.OrdinalIgnoreCase) == 0) && + (string.Compare("VCARD", property.ToString(), StringComparison.OrdinalIgnoreCase) == 0)) + { + + // This is a special type of property that marks + // the last property of the vCard. + + break; + } + else + { + ReadInto(card, property); + } + } + + } while (property != null); + + } + + #endregion + + #region [ ReadInto(vCard, vCardProperty) ] + + /// + /// Updates a vCard object based on the contents of a vCardProperty. + /// + /// + /// An initialized vCard object. + /// + /// + /// An initialized vCardProperty object. + /// + /// + /// + /// This method examines the contents of a property + /// and attempts to update an existing vCard based on + /// the property name and value. This function must + /// be updated when new vCard properties are implemented. + /// + /// + public void ReadInto(vCard card, vCardProperty property) + { + + if (card == null) + throw new ArgumentNullException("card"); + + if (property == null) + throw new ArgumentNullException("property"); + + if (string.IsNullOrEmpty(property.Name)) + return; + + switch (property.Name.ToUpperInvariant()) + { + + case "ADR": + ReadInto_ADR(card, property); + break; + + case "BDAY": + ReadInto_BDAY(card, property); + break; + + case "CATEGORIES": + ReadInto_CATEGORIES(card, property); + break; + + case "CLASS": + ReadInto_CLASS(card, property); + break; + + case "EMAIL": + ReadInto_EMAIL(card, property); + break; + + case "FN": + ReadInto_FN(card, property); + break; + + case "GEO": + ReadInto_GEO(card, property); + break; + + case "KEY": + ReadInto_KEY(card, property); + break; + + case "LABEL": + ReadInto_LABEL(card, property); + break; + + case "MAILER": + ReadInto_MAILER(card, property); + break; + + case "N": + ReadInto_N(card, property); + break; + + case "NAME": + ReadInto_NAME(card, property); + break; + + case "NICKNAME": + ReadInto_NICKNAME(card, property); + break; + + case "NOTE": + ReadInto_NOTE(card, property); + break; + + case "ORG": + ReadInto_ORG(card, property); + break; + + case "PHOTO": + ReadInto_PHOTO(card, property); + break; + + case "PRODID": + ReadInto_PRODID(card, property); + break; + + case "REV": + ReadInto_REV(card, property); + break; + + case "ROLE": + ReadInto_ROLE(card, property); + break; + + case "SOURCE": + ReadInto_SOURCE(card, property); + break; + + case "TEL": + ReadInto_TEL(card, property); + break; + + case "TITLE": + ReadInto_TITLE(card, property); + break; + + case "TZ": + ReadInto_TZ(card, property); + break; + + case "UID": + ReadInto_UID(card, property); + break; + + case "URL": + ReadInto_URL(card, property); + break; + + case "X-WAB-GENDER": + ReadInto_X_WAB_GENDER(card, property); + break; + + default: + + // The property name is not recognized and + // will be ignored. + + break; + + } + + } + + #endregion + + // The following functions (ReadInfo_xxx) implement the logic + // for each recognized vCard property. A separate function + // for each property is implemented for easier organization. + // + // Each function is a private function. It is not necessary + // for a function to double-check the name of a property, or + // check for null parameters. + + #region [ ReadInto_ADR() ] + + /// + /// Reads an ADR property. + /// + private void ReadInto_ADR(vCard card, vCardProperty property) + { + + // The ADR property defines a delivery address, such + // as a home postal address. The property contains + // the following components separated by semicolons: + // + // 0. Post office box + // 1. Extended address + // 2. Street + // 3. Locality (e.g. city) + // 4. Region (e.g. state or province) + // 5. Postal code + // 6. Country name + // + // This version of the reader ignores any ADR properties + // with a lesser number of components. If more than 7 + // components exist, then the lower seven components are + // assumed to still match the specification (e.g. the + // additional components may be from a future specification). + + string[] addressParts = + property.Value.ToString().Split(new char[] { ';' }); + + vCardDeliveryAddress deliveryAddress = new vCardDeliveryAddress(); + + if (addressParts.Length >= 7) + deliveryAddress.Country = addressParts[6].Trim(); + + if (addressParts.Length >= 6) + deliveryAddress.PostalCode = addressParts[5].Trim(); + + if (addressParts.Length >= 5) + deliveryAddress.Region = addressParts[4].Trim(); + + if (addressParts.Length >= 4) + deliveryAddress.City = addressParts[3].Trim(); + + if (addressParts.Length >= 3) + deliveryAddress.Street = addressParts[2].Trim(); + + if ( + (string.IsNullOrEmpty(deliveryAddress.City)) && + (string.IsNullOrEmpty(deliveryAddress.Country)) && + (string.IsNullOrEmpty(deliveryAddress.PostalCode)) && + (string.IsNullOrEmpty(deliveryAddress.Region)) && + (string.IsNullOrEmpty(deliveryAddress.Street))) + { + + // No address appears to be defined. + // Ignore. + + return; + + } + + // Handle the old 2.1 format in which the ADR type names (e.g. + // DOM, HOME, etc) were written directly as subproperties. + // For example, "ADR;HOME;POSTAL:...". + + deliveryAddress.AddressType = + ParseDeliveryAddressType(property.Subproperties.GetNames(DeliveryAddressTypeNames)); + + // Handle the new 3.0 format in which the delivery address + // type is a comma-delimited list, e.g. "ADR;TYPE=HOME,POSTAL:". + // It is possible for the TYPE subproperty to be listed multiple + // times (this is allowed by the RFC, although irritating that + // the authors allowed it). + + foreach (vCardSubproperty sub in property.Subproperties) + { + + // If this subproperty is a TYPE subproperty and + // has a non-null value, then parse it. + + if ( + (!string.IsNullOrEmpty(sub.Value)) && + (string.Compare("TYPE", sub.Name, StringComparison.OrdinalIgnoreCase) == 0)) + { + + deliveryAddress.AddressType |= + ParseDeliveryAddressType(sub.Value.Split(new char[] { ',' })); + + } + + } + + card.DeliveryAddresses.Add(deliveryAddress); + + } + + #endregion + + #region [ ReadInto_BDAY ] + + /// + /// Reads the BDAY property. + /// + private void ReadInto_BDAY(vCard card, vCardProperty property) + { + + DateTime bday; + if (DateTime.TryParse(property.ToString(), out bday)) + { + card.BirthDate = bday; + } + else + { + + // Microsoft Outlook writes the birthdate in YYYYMMDD, e.g. 20091015 + // for October 15, 2009. + + if (DateTime.TryParseExact( + property.ToString(), + "yyyyMMdd", + CultureInfo.InvariantCulture, + DateTimeStyles.None, + out bday)) + { + card.BirthDate = bday; + } + else + { + card.BirthDate = null; + } + } + + } + + #endregion + + #region [ ReadInto_CATEGORIES ] + + /// + /// Reads the CATEGORIES property. + /// + private void ReadInto_CATEGORIES(vCard card, vCardProperty property) + { + + // The CATEGORIES value is expected to be a comma-delimited list. + + string[] cats = property.ToString().Split(new char[] { ',' }); + + // Add each non-blank line to the categories collection. + + foreach (string cat in cats) + { + if (cat.Length > 0) + card.Categories.Add(cat); + } + + } + + #endregion + + #region [ ReadInto_CLASS ] + + /// + /// Reads the CLASS property. + /// + private void ReadInto_CLASS(vCard card, vCardProperty property) + { + + if (property.Value == null) + return; + + switch (property.ToString().ToUpperInvariant()) + { + case "PUBLIC": + card.AccessClassification = vCardAccessClassification.Public; + break; + + case "PRIVATE": + card.AccessClassification = vCardAccessClassification.Private; + break; + + case "CONFIDENTIAL": + card.AccessClassification = vCardAccessClassification.Confidential; + break; + } + + } + + #endregion + + #region [ ReadInto_EMAIL ] + + /// + /// Reads an EMAIL property. + /// + private void ReadInto_EMAIL(vCard card, vCardProperty property) + { + + vCardEmailAddress email = new vCardEmailAddress(); + + // The email address is stored as the value of the property. + // The format of the address depends on the type of email + // address. The current version of the library does not + // perform any validation. + + email.Address = property.Value.ToString(); + + // Loop through each subproperty and look for flags + // that indicate the type of email address. + + foreach (vCardSubproperty subproperty in property.Subproperties) + { + + switch (subproperty.Name.ToUpperInvariant()) + { + + case "PREF": + + // The PREF subproperty indicates the email + // address is the preferred email address to + // use when contacting the person. + + email.IsPreferred = true; + break; + + case "TYPE": + + // The TYPE subproperty is new in vCard 3.0. + // It identifies the type and can also indicate + // the PREF attribute. + + string[] typeValues = + subproperty.Value.Split(new char[] { ',' }); + + foreach (string typeValue in typeValues) + { + if (string.Compare("PREF", typeValue, StringComparison.OrdinalIgnoreCase) == 0) + { + email.IsPreferred = true; + } + else + { + vCardEmailAddressType? typeType = + DecodeEmailAddressType(typeValue); + + if (typeType.HasValue) + email.EmailType = typeType.Value; + } + + } + break; + + default: + + // All other subproperties are probably vCard 2.1 + // subproperties. This was before the email type + // was supposed to be specified with TYPE=VALUE. + + vCardEmailAddressType? emailType = + DecodeEmailAddressType(subproperty.Name); + + if (emailType.HasValue) + email.EmailType = emailType.Value; + + break; + + } + + } + + card.EmailAddresses.Add(email); + + } + + #endregion + + #region [ ReadInto_FN ] + + /// + /// Reads the FN property. + /// + private void ReadInto_FN(vCard card, vCardProperty property) + { + + // The FN property defines the formatted display name + // of the person. This is used for presentation. + + card.FormattedName = property.Value.ToString(); + + } + + #endregion + + #region [ ReadInfo_GEO ] + + /// + /// Reads the GEO property. + /// + private void ReadInto_GEO(vCard card, vCardProperty property) + { + + // The GEO property specifies latitude and longitude + // of the entity associated with the vCard. + + string[] coordinates = + property.Value.ToString().Split(new char[] { ';' }); + + if (coordinates.Length == 2) + { + float geoLatitude; + float geoLongitude; + + if ( + float.TryParse(coordinates[0], out geoLatitude) && + float.TryParse(coordinates[1], out geoLongitude)) + { + card.Latitude = geoLatitude; + card.Longitude = geoLongitude; + } + + } + + } + + #endregion + + #region [ ReadInto_KEY ] + + /// + /// Reads the KEY property. + /// + private void ReadInto_KEY(vCard card, vCardProperty property) + { + + // The KEY property defines a security certificate + // that has been attached to the vCard. Key values + // are usually encoded in BASE64 because they + // often consist of binary data. + + vCardCertificate certificate = new vCardCertificate(); + certificate.Data = (byte[])property.Value; + + // TODO: Support other key types. + + if (property.Subproperties.Contains("X509")) + certificate.KeyType = "X509"; + + card.Certificates.Add(certificate); + + } + + #endregion + + #region [ ReadInto_LABEL ] + + /// + /// Reads the LABEL property. + /// + private void ReadInto_LABEL(vCard card, vCardProperty property) + { + + vCardDeliveryLabel label = new vCardDeliveryLabel(); + + label.Text = property.Value.ToString(); + + // Handle the old 2.1 format in which the ADR type names (e.g. + // DOM, HOME, etc) were written directly as subproperties. + // For example, "LABEL;HOME;POSTAL:...". + + label.AddressType = + ParseDeliveryAddressType(property.Subproperties.GetNames(DeliveryAddressTypeNames)); + + // Handle the new 3.0 format in which the delivery address + // type is a comma-delimited list, e.g. "ADR;TYPE=HOME,POSTAL:". + // It is possible for the TYPE subproperty to be listed multiple + // times (this is allowed by the RFC, although irritating that + // the authors allowed it). + + foreach (vCardSubproperty sub in property.Subproperties) + { + + // If this subproperty is a TYPE subproperty and + // has a non-null value, then parse it. + + if ( + (!string.IsNullOrEmpty(sub.Value)) && + (string.Compare("TYPE", sub.Name, StringComparison.OrdinalIgnoreCase) == 0)) + { + + label.AddressType |= + ParseDeliveryAddressType(sub.Value.Split(new char[] { ',' })); + + } + + } + + card.DeliveryLabels.Add(label); + + + } + + #endregion + + #region [ ReadInto_MAILER ] + + /// + /// Reads the MAILER property. + /// + private void ReadInto_MAILER(vCard card, vCardProperty property) + { + + // The MAILER property identifies the mail software + // used by the person. This can be examined by a + // program to detect software-specific conventions. + // See section 2.4.3 of the vCard 2.1 spec. This + // property is not common. + + card.Mailer = property.Value.ToString(); + + } + + #endregion + + #region [ ReadInto_N ] + + /// + /// Reads the N property. + /// + private void ReadInto_N(vCard card, vCardProperty property) + { + + // The N property defines the name of the person. The + // propery value has several components, such as the + // given name, family name, and suffix. This is a + // core field found in almost all vCards. + // + // Each component is supposed to be separated with + // a semicolon. However, some vCard writers do not + // write out training semicolons. For example, the + // last two components are the prefix (e.g. Mr.) + // and suffix (e.g. Jr) of the name. The semicolons + // will be missing in some vCards if these components + // are blank. + + string[] names = property.ToString().Split(';'); + + // The first value is the family (last) name. + card.FamilyName = names[0]; + if (names.Length == 1) + return; + + // The next value is the given (first) name. + card.GivenName = names[1]; + if (names.Length == 2) + return; + + // The next value contains the middle name. + card.AdditionalNames = names[2]; + if (names.Length == 3) + return; + + // The next value contains the prefix, e.g. Mr. + card.NamePrefix = names[3]; + if (names.Length == 4) + return; + + // The last value contains the suffix, e.g. Jr. + card.NameSuffix = names[4]; + + } + + #endregion + + #region [ ReadInto_NAME ] + + /// + /// Reads the NAME property. + /// + private void ReadInto_NAME(vCard card, vCardProperty property) + { + + // The NAME property is used to define the displayable + // name of the vCard. Because it is intended for display + // purposes, any whitespace at the beginning or end of + // the name is trimmed. + + card.DisplayName = property.ToString().Trim(); + } + + #endregion + + #region [ ReadInto_NICKNAME ] + + /// + /// Reads the NICKNAME property. + /// + private void ReadInto_NICKNAME(vCard card, vCardProperty property) + { + + if (property.Value == null) + return; + + // The nicknames are comma-separated values. + + string[] nicknames = + property.Value.ToString().Split(new char[] { ',' }); + + foreach (string nickname in nicknames) + { + + string trimmedNickname = nickname.Trim(); + if (trimmedNickname.Length > 0) + { + card.Nicknames.Add(trimmedNickname); + } + + } + + } + + #endregion + + #region [ ReadInto_NOTE ] + + /// + /// Reads the NOTE property. + /// + private void ReadInto_NOTE(vCard card, vCardProperty property) + { + + if (property.Value != null) + { + + vCardNote note = new vCardNote(); + + note.Language = property.Subproperties.GetValue("language"); + note.Text = property.Value.ToString(); + + if (!string.IsNullOrEmpty(note.Text)) + { + card.Notes.Add(note); + } + + } + + } + + #endregion + + #region [ ReadInto_ORG ] + + /// + /// Reads the ORG property. + /// + private void ReadInto_ORG(vCard card, vCardProperty property) + { + + // The ORG property contains the name of the company + // or organization of the person. + + card.Organization = property.Value.ToString(); + + } + + #endregion + + #region [ ReadInto_PHOTO ] + + /// + /// Reads the PHOTO property. + /// + private void ReadInto_PHOTO(vCard card, vCardProperty property) + { + + // The PHOTO property contains an embedded (encoded) image + // or a link to an image. A URL (linked) image is supposed + // to be indicated with the VALUE=URI subproperty. + + string valueType = property.Subproperties.GetValue("VALUE"); + + if (string.Compare(valueType, "URI", StringComparison.OrdinalIgnoreCase) == 0) + { + + // This image has been defined as a URI/URL link, + // rather than being encoded directly in the vCard. + + card.Photos.Add( + new vCardPhoto(new Uri(property.ToString()))); + + + } + else + { + card.Photos.Add(new vCardPhoto((byte[])property.Value)); + } + } + + #endregion + + #region [ ReadInto_PRODID ] + + /// + /// Reads the PRODID property. + /// + private void ReadInto_PRODID(vCard card, vCardProperty property) + { + + // The PRODID property contains the name of the + // software that generated the vCard. This is not + // a common property. Also note: this library + // does not automatically generate a PRODID when + // creating a vCard file. The developer can set + // the PRODID (via the ProductId parameter) to + // anything desired. + + card.ProductId = property.ToString(); + + } + + #endregion + + #region [ ReadInto_REV ] + + /// + /// Reads the REV property. + /// + private void ReadInto_REV(vCard card, vCardProperty property) + { + + // The REV property indicates the last revision date + // of the vCard. Note that Outlook and perhaps other + // clients generate the revision date in a format not + // recognized directly by the .NET DateTime parser. + // A custom format is used; see ParseDate for details. + + card.RevisionDate = ParseDate(property.Value.ToString()); + + } + + #endregion + + #region [ ReadInto_ROLE ] + + /// + /// Reads the ROLE property. + /// + private void ReadInto_ROLE(vCard card, vCardProperty property) + { + + // The ROLE property describes the role of the + // person at his/her organization (e.g. Programmer + // or Executive, etc). + + card.Role = property.Value.ToString(); + + } + + #endregion + + #region [ ReadInto_SOURCE ] + + /// + /// Reads the SOURCE property. + /// + private void ReadInto_SOURCE(vCard card, vCardProperty property) + { + + // The SOURCE property identifies the source of + // directory information (e.g. an LDAP server). This + // is not widely supported. See RFC 2425, sec. 6.1. + + vCardSource source = new vCardSource(); + source.Context = property.Subproperties.GetValue("CONTEXT"); + source.Uri = new Uri(property.Value.ToString()); + card.Sources.Add(source); + + } + + #endregion + + #region [ ReadInto_TEL ] + + /// + /// Reads the TEL property. + /// + private void ReadInto_TEL(vCard card, vCardProperty property) + { + + vCardPhone phone = new vCardPhone(); + + // The full telephone number is stored as the + // value of the property. Currently no formatted + // rules are applied since the vCard specification + // is somewhat confusing on this matter. + + phone.FullNumber = property.ToString(); + if (string.IsNullOrEmpty(phone.FullNumber)) + return; + + foreach (vCardSubproperty sub in property.Subproperties) + { + + // If this subproperty is a TYPE subproperty + // and it has a value, then it is expected + // to contain a comma-delimited list of phone types. + + if ( + (string.Compare(sub.Name, "TYPE", StringComparison.OrdinalIgnoreCase) == 0) && + (!string.IsNullOrEmpty(sub.Value))) + { + // This is a vCard 3.0 subproperty. It defines the + // the list of phone types in a comma-delimited list. + // Note that the vCard specification allows for + // multiple TYPE subproperties (why ?!). + + phone.PhoneType |= + ParsePhoneType(sub.Value.Split(new char[] { ',' })); + + } + else + { + + // The other subproperties in a TEL property + // define the phone type. The only exception + // are meta fields like ENCODING, CHARSET, etc, + // but these are probably rare with TEL. + + phone.PhoneType |= ParsePhoneType(sub.Name); + + } + + } + + card.Phones.Add(phone); + + } + + #endregion + + #region [ ReadInto_TITLE ] + + /// + /// Reads the TITLE property. + /// + private void ReadInto_TITLE(vCard card, vCardProperty property) + { + + // The TITLE property defines the job title of the + // person. This should not be confused by the name + // prefix (e.g. "Mr"), which is called "Title" in + // some vCard-compatible software like Outlook. + + card.Title = property.ToString(); + + } + + #endregion + + #region [ ReadInto_TZ ] + + /// + /// Reads a TZ property. + /// + private void ReadInto_TZ(vCard card, vCardProperty property) + { + card.TimeZone = property.ToString(); + } + + #endregion + + #region [ ReadInto_UID ] + + /// + /// Reads the UID property. + /// + private void ReadInto_UID(vCard card, vCardProperty property) + { + card.UniqueId = property.ToString(); + } + + #endregion + + #region [ ReadInto_URL ] + + /// + /// Reads the URL property. + /// + private void ReadInto_URL(vCard card, vCardProperty property) + { + + vCardWebsite webSite = new vCardWebsite(); + + webSite.Url = property.ToString(); + + if (property.Subproperties.Contains("HOME")) + webSite.IsPersonalSite = true; + + if (property.Subproperties.Contains("WORK")) + webSite.IsWorkSite = true; + + card.Websites.Add(webSite); + + } + + #endregion + + #region [ ReadInto_X_WAB_GENDER ] + + /// + /// Reads the X-WAB-GENDER property. + /// + private void ReadInto_X_WAB_GENDER(vCard card, vCardProperty property) + { + + // The X-WAB-GENDER property is a custom property generated by + // Microsoft Outlook 2003. It contains the value 1 for females + // or 2 for males. It is not known if other PIM clients + // recognize this value. + + int genderId; + + if (int.TryParse(property.ToString(), out genderId)) + { + switch (genderId) + { + case 1: + card.Gender = vCardGender.Female; + break; + + case 2: + card.Gender = vCardGender.Male; + break; + } + } + + } + + #endregion + + #region [ ReadProperty(string) ] + + /// + /// Reads a property from a string. + /// + public vCardProperty ReadProperty(string text) + { + + if (string.IsNullOrEmpty(text)) + throw new ArgumentNullException("text"); + + using (StringReader reader = new StringReader(text)) + { + return ReadProperty(reader); + } + + } + + #endregion + + #region [ ReadProperty(TextReader) ] + + /// + /// Reads a property from a text reader. + /// + public vCardProperty ReadProperty(TextReader reader) + { + + if (reader == null) + throw new ArgumentNullException("reader"); + + do + { + + // Read the first line of the next property + // from the input stream. If a null string + // is returned, then the end of the input + // stream has been reached. + + string firstLine = reader.ReadLine(); + if (firstLine == null) + return null; + + // See if this line is a blank line. It is + // blank if (a) it has no characters, or (b) + // it consists of whitespace characters only. + + firstLine = firstLine.Trim(); + if (firstLine.Length == 0) + { + Warnings.Add(Thought.vCards.WarningMessages.BlankLine); + continue; + } + + // Get the index of the colon (:) in this + // property line. All vCard properties are + // written in NAME:VALUE format. + + int colonIndex = firstLine.IndexOf(':'); + if (colonIndex == -1) + { + Warnings.Add(Thought.vCards.WarningMessages.ColonMissing); + continue; + } + + // Get the name portion of the property. This + // portion contains the property name as well + // as any subproperties. + + string namePart = firstLine.Substring(0, colonIndex).Trim(); + if (string.IsNullOrEmpty(namePart)) + { + Warnings.Add(Thought.vCards.WarningMessages.EmptyName); + continue; + } + + // Split apart the name portion of the property. + // A property can have subproperties, separated + // by semicolons. + + string[] nameParts = namePart.Split(';'); + for (int i = 0; i < nameParts.Length; i++) + nameParts[i] = nameParts[i].Trim(); + + // The name of the property is supposed to + // be first on the line. An empty name is not + // legal syntax. + + if (nameParts[0].Length == 0) + { + Warnings.Add(Thought.vCards.WarningMessages.EmptyName); + continue; + } + + // At this point there is sufficient text + // to define a vCard property. The only + // true minimum requirement is a name. + + vCardProperty property = new vCardProperty(); + property.Name = nameParts[0]; + + // Next, store any subproperties. Subproperties + // are defined like "NAME;SUBNAME=VALUE:VALUE". Note + // that subproperties do not necessarily have to have + // a subvalue. + + for (int index = 1; index < nameParts.Length; index++) + { + + // Split the subproperty into its name and + // value components. If multiple equal signs + // happen to exist, they are interpreted as + // part of the value. This may change in a + // future version of the parser. + + string[] subNameValue = + nameParts[index].Split(new char[] { '=' }, 2); + + if (subNameValue.Length == 1) + { + + // The Split function above returned a single + // array element. This means no equal (=) sign + // was present. The subproperty consists of + // a name only. + + property.Subproperties.Add( + nameParts[index].Trim()); + } + else + { + property.Subproperties.Add( + subNameValue[0].Trim(), + subNameValue[1].Trim()); + } + + } + + // The subproperties have been defined. The next + // step is to try to identify the encoding of the + // value. The encoding is supposed to be specified + // with a subproperty called ENCODING. However, older + // versions of the format just wrote the plain + // encoding value, e.g. "NAME;BASE64:VALUE" instead + // of the normalized "NAME;ENCODING=BASE64:VALUE" form. + + string encodingName = + property.Subproperties.GetValue("ENCODING", + new string[] { "B", "BASE64", "QUOTED-PRINTABLE" }); + + // Convert the encoding name into its corresponding + // vCardEncoding enumeration value. + + vCardEncoding encoding = + ParseEncoding(encodingName); + + // At this point, the first line of the property has been + // loaded and the suggested value encoding has been + // determined. Get the raw value as encoded in the file. + + string rawValue = firstLine.Substring(colonIndex + 1); + + // The vCard specification allows long values + // to be folded across multiple lines. An example + // is a security key encoded in MIME format. + // When folded, each subsequent line begins with + // a space or tab character instead of the next property. + // + // See: RFC 2425, Section 5.8.1 + + do + { + int peekChar = reader.Peek(); + + if ((peekChar == 32) || (peekChar == 9)) + { + string foldedLine = reader.ReadLine(); + rawValue += foldedLine.Substring(1); + } + else + { + break; + } + + } while (true); + + if (encoding == vCardEncoding.QuotedPrintable && rawValue.Length > 0) + { + while (rawValue[rawValue.Length - 1] == '=') + { + rawValue += "\r\n" + reader.ReadLine(); + } + } + + // The full value has finally been loaded from the + // input stream. The next step is to decode it. + + switch (encoding) + { + case vCardEncoding.Base64: + property.Value = DecodeBase64(rawValue); + break; + + case vCardEncoding.Escaped: + property.Value = DecodeEscaped(rawValue); + break; + + case vCardEncoding.QuotedPrintable: + property.Value = DecodeQuotedPrintable(rawValue); + break; + + default: + property.Value = DecodeEscaped(rawValue); + break; + } + + return property; + + } while (true); + + } + + #endregion + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardStandardWriter.cs b/vCardEditor/Thought.vCards/vCardStandardWriter.cs new file mode 100644 index 0000000..74402c6 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardStandardWriter.cs @@ -0,0 +1,1610 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.IO; +using System.Text; + +namespace Thought.vCards +{ + + /// + /// Implements the standard vCard 2.1 and 3.0 text formats. + /// + public class vCardStandardWriter : vCardWriter + { + + private bool embedInternetImages; + private bool embedLocalImages; + private vCardStandardWriterOptions options; + private string productId; + + + /// + /// The characters that are escaped per the original + /// vCard specification. + /// + private readonly char[] standardEscapedCharacters = + new char[] { ',', '\\', ';', '\r', '\n' }; + + + /// + /// The characters that are escaped by Microsoft Outlook. + /// + /// + /// Microsoft Outlook does not property decode escaped + /// commas in values. + /// + private readonly char[] outlookEscapedCharacters = + new char[] { '\\', ';', '\r', '\n' }; + + + /// + /// Creates a new instance of the standard writer. + /// + /// + /// The standard writer is configured to create vCard + /// files in the highest supported version. This is + /// currently version 3.0. + /// + public vCardStandardWriter() + { + this.embedLocalImages = true; + } + + + /// + /// Indicates whether images that reference Internet + /// URLs should be embedded in the output. If not, + /// then a URL is written instead. + /// + public bool EmbedInternetImages + { + get + { + return this.embedInternetImages; + } + set + { + this.embedInternetImages = value; + } + } + + + /// + /// Indicates whether or not references to local + /// images should be embedded in the vCard. If not, + /// then a local file reference is written instead. + /// + public bool EmbedLocalImages + { + get + { + return this.embedLocalImages; + } + set + { + this.embedLocalImages = value; + } + } + + + /// + /// Extended options for the vCard writer. + /// + public vCardStandardWriterOptions Options + { + get + { + return this.options; + } + set + { + this.options = value; + } + } + + + /// + /// The product ID to use when writing a vCard. + /// + public string ProductId + { + get + { + return this.productId; + } + set + { + this.productId = value; + } + } + + + // The next set of functions generate raw vCard properties + // from an object in the vCard object model. Every method + // has a collection (into which new properties should be + // placed) and a vCard object (from which the properties + // should be generated). + + #region [ BuildProperties ] + + /// + /// Builds a collection of standard properties based on + /// the specified vCard. + /// + /// + /// A that contains all + /// properties for the current vCard, including the header + /// and footer properties. + /// + /// + /// + private vCardPropertyCollection BuildProperties( + vCard card) + { + + vCardPropertyCollection properties = + new vCardPropertyCollection(); + + // The BEGIN:VCARD line marks the beginning of + // the vCard contents. Later it will end with END:VCARD. + // See section 2.1.1 of RFC 2426. + + properties.Add(new vCardProperty("BEGIN", "VCARD")); + + BuildProperties_NAME( + properties, + card); + + BuildProperties_SOURCE( + properties, + card); + + BuildProperties_N( + properties, + card); + + BuildProperties_FN( + properties, + card); + + BuildProperties_ADR( + properties, + card); + + BuildProperties_BDAY( + properties, + card); + + BuildProperties_CATEGORIES( + properties, + card); + + BuildProperties_CLASS( + properties, + card); + + BuildProperties_EMAIL( + properties, + card); + + BuildProperties_GEO( + properties, + card); + + BuildProperties_KEY( + properties, + card); + + BuildProperties_LABEL( + properties, + card); + + BuildProperties_MAILER( + properties, + card); + + BuildProperties_NICKNAME( + properties, + card); + + BuildProperties_NOTE( + properties, + card); + + BuildProperties_ORG( + properties, + card); + + BuildProperties_PHOTO( + properties, + card); + + BuildProperties_PRODID( + properties, + card); + + BuildProperties_REV( + properties, + card); + + BuildProperties_ROLE( + properties, + card); + + BuildProperties_TEL( + properties, + card); + + BuildProperties_TITLE( + properties, + card); + + BuildProperties_TZ( + properties, + card); + + BuildProperties_UID( + properties, + card); + + BuildProperties_URL( + properties, + card); + + BuildProperties_X_WAB_GENDER( + properties, + card); + + // The end of the vCard is marked with an END:VCARD. + + properties.Add(new vCardProperty("END", "VCARD")); + return properties; + + } + + #endregion + + #region [ BuildProperties_ADR ] + + /// + /// Builds ADR properties. + /// + 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); + + } + + } + + } + + #endregion + + #region [ BuildProperties_BDAY ] + + /// + /// Builds the BDAY property. + /// + private void BuildProperties_BDAY( + vCardPropertyCollection properties, + vCard card) + { + + // The BDAY property indicates the birthdate + // of the person. The output format here is based on + // Microsoft Outlook, which writes the date as YYYMMDD. + + if (card.BirthDate.HasValue) + { + + vCardProperty property = + new vCardProperty("BDAY", card.BirthDate.Value); + + properties.Add(property); + } + + } + + #endregion + + #region [ BuildProperties_CATEGORIES ] + + private void BuildProperties_CATEGORIES( + vCardPropertyCollection properties, + vCard card) + { + + if (card.Categories.Count > 0) + { + + vCardValueCollection values = new vCardValueCollection(','); + + foreach (string category in card.Categories) + { + + if (!string.IsNullOrEmpty(category)) + values.Add(category); + } + + properties.Add( + new vCardProperty("CATEGORIES", values)); + + } + + } + + #endregion + + #region [ BuildProperties_CLASS ] + + private void BuildProperties_CLASS( + vCardPropertyCollection properties, + vCard card) + { + + vCardProperty property = new vCardProperty("CLASS"); + + switch (card.AccessClassification) + { + + case vCardAccessClassification.Unknown: + // No value is written. + return; + + case vCardAccessClassification.Confidential: + property.Value = "CONFIDENTIAL"; + break; + + case vCardAccessClassification.Private: + property.Value = "PRIVATE"; + break; + + case vCardAccessClassification.Public: + property.Value = "PUBLIC"; + break; + + default: + throw new NotSupportedException(); + + } + + properties.Add(property); + + } + + #endregion + + #region [ BuildProperties_EMAIL ] + + /// + /// Builds EMAIL properties. + /// + 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:support@fairmetric.com + + 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); + + } + + } + + #endregion + + #region [ BuildProperties_FN ] + + private void BuildProperties_FN( + vCardPropertyCollection properties, + vCard card) + { + + // The FN property indicates the formatted + // name of the person. This can be something + // like "John Smith". + + if (!string.IsNullOrEmpty(card.FormattedName)) + { + + vCardProperty property = + new vCardProperty("FN", card.FormattedName); + + properties.Add(property); + + } + + } + + #endregion + + #region [ BuildProperties_GEO ] + + /// + /// Builds the GEO property. + /// + 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); + + } + + } + + #endregion + + #region [ BuildProperties_KEY ] + + /// + /// Builds KEY properties. + /// + 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); + + } + + } + + #endregion + + #region [ BuildProperties_LABEL ] + + 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); + + + } + + } + + } + + #endregion + + #region [ BuildProperties_MAILER ] + + /// + /// Builds the MAILER property. + /// + private void BuildProperties_MAILER( + vCardPropertyCollection properties, + vCard card) + { + + // The MAILER property indicates the software that + // generated the vCard. See section 2.4.3 of the + // vCard 2.1 specification. Support is not widespread. + + if (!string.IsNullOrEmpty(card.Mailer)) + { + + vCardProperty property = + new vCardProperty("MAILER", card.Mailer); + + properties.Add(property); + + } + + } + + #endregion + + #region [ BuildProperties_N ] + + private void BuildProperties_N( + vCardPropertyCollection properties, + vCard card) + { + + // The property has the following components: Family Name, + // Given Name, Additional Names, Name Prefix, and Name + // Suffix. Example: + // + // N:Pinch;David + // N:Pinch;David;John + // + // The N property is required (see section 3.1.2 of RFC 2426). + + vCardValueCollection values = new vCardValueCollection(';'); + values.Add(card.FamilyName); + values.Add(card.GivenName); + values.Add(card.AdditionalNames); + values.Add(card.NamePrefix); + values.Add(card.NameSuffix); + + vCardProperty property = new vCardProperty("N", values); + + properties.Add(property); + + } + + #endregion + + #region [ BuildProperties_NAME ] + + private void BuildProperties_NAME( + vCardPropertyCollection properties, + vCard card) + { + + if (!string.IsNullOrEmpty(card.DisplayName)) + { + + vCardProperty property = + new vCardProperty("NAME", card.DisplayName); + + properties.Add(property); + } + + } + + #endregion + + #region [ BuildProperties_NICKNAME ] + + /// + /// Builds the NICKNAME property. + /// + private void BuildProperties_NICKNAME( + vCardPropertyCollection properties, + vCard card) + { + + // The NICKNAME property specifies the familiar name + // of the person, such as Jim. This is defined in + // section 3.1.3 of RFC 2426. Multiple names can + // be listed, separated by commas. + + if (card.Nicknames.Count > 0) + { + + // A NICKNAME property is a comma-separated + // list of values. Create a value list and + // add the nicknames collection to it. + + vCardValueCollection values = new vCardValueCollection(','); + values.Add(card.Nicknames); + + // Create the new properties with each name separated + // by a comma. + + vCardProperty property = + new vCardProperty("NICKNAME", values); + + properties.Add(property); + + } + + } + + #endregion + + #region [ BuildProperties_NOTE ] + + /// + /// Builds the NOTE property. + /// + 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); + + } + + } + + } + + #endregion + + #region [ BuildProperties_ORG ] + + /// + /// Builds the ORG property. + /// + 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); + + } + + } + + #endregion + + #region [ BuildProperties_PHOTO ] + + 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); + } + + } + } + } + + #endregion + + #region [ BuildProperties_PRODID ] + + /// + /// Builds PRODID properties. + /// + private void BuildProperties_PRODID( + vCardPropertyCollection properties, + vCard card) + { + + if (!string.IsNullOrEmpty(card.ProductId)) + { + vCardProperty property = new vCardProperty(); + property.Name = "PRODID"; + property.Value = card.ProductId; + properties.Add(property); + } + + } + + #endregion + + #region [ BuildProperties_REV ] + + /// + /// Builds the REV property. + /// + private void BuildProperties_REV( + vCardPropertyCollection properties, + vCard card) + { + + if (card.RevisionDate.HasValue) + { + + vCardProperty property = + new vCardProperty("REV", card.RevisionDate.Value.ToString()); + + properties.Add(property); + + } + + } + + #endregion + + #region [ BuildProperties_ROLE ] + + /// + /// Builds the ROLE property. + /// + private void BuildProperties_ROLE( + vCardPropertyCollection properties, + vCard card) + { + + // The ROLE property identifies the role of + // the person at his/her organization. + + if (!string.IsNullOrEmpty(card.Role)) + { + + vCardProperty property = + new vCardProperty("ROLE", card.Role); + + properties.Add(property); + + } + + } + + #endregion + + #region [ BuildProperties_SOURCE ] + + /// + /// Builds SOURCE properties. + /// + 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); + + } + + } + + #endregion + + #region [ BuildProperties_TEL ] + + /// + /// Builds TEL properties. + /// + 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); + + } + + } + + #endregion + + #region [ BuildProperties_TITLE ] + + 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); + } + + } + + #endregion + + #region [ BuildProperties_TZ ] + + private void BuildProperties_TZ( + vCardPropertyCollection properties, + vCard card) + { + + if (!string.IsNullOrEmpty(card.TimeZone)) + { + properties.Add(new vCardProperty("TZ", card.TimeZone)); + } + + } + + #endregion + + #region [ BuildProperties_UID ] + + private void BuildProperties_UID( + vCardPropertyCollection properties, + vCard card) + { + + if (!string.IsNullOrEmpty(card.UniqueId)) + { + vCardProperty property = new vCardProperty(); + property.Name = "UID"; + property.Value = card.UniqueId; + properties.Add(property); + } + + } + + #endregion + + #region [ BuildProperties_URL ] + + 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); + } + + } + + } + + #endregion + + #region [ BuildProperties_X_WAB_GENDER ] + + private void BuildProperties_X_WAB_GENDER( + vCardPropertyCollection properties, + vCard card) + { + + // The X-WAB-GENDER property is an extended (custom) + // property supported by Microsoft Outlook. + + switch (card.Gender) + { + case vCardGender.Female: + properties.Add(new vCardProperty("X-WAB-GENDER", "1")); + break; + + case vCardGender.Male: + properties.Add(new vCardProperty("X-WAB-GENDER", "2")); + break; + + } + + } + + #endregion + + // The next set of functions translate raw values into + // various string encodings. A vCard file is a text file + // with a defined format; values that break the format (such + // as binary values or strings with ASCII control characters) + // must be encoded. + + #region [ EncodeBase64(byte) ] + + /// + /// Converts a byte to a BASE64 string. + /// + public static string EncodeBase64(byte value) + { + return Convert.ToBase64String(new byte[] { value }); + } + + #endregion + + #region [ EncodeBase64(byte[]) ] + + /// + /// Converts a byte array to a BASE64 string. + /// + public static string EncodeBase64(byte[] value) + { + return Convert.ToBase64String(value); + } + + #endregion + + #region [ EncodeBase64(int) ] + + /// + /// Converts an integer to a BASE64 string. + /// + public static string EncodeBase64(int value) + { + + byte[] buffer = new byte[4]; + + buffer[0] = (byte)(value); + buffer[1] = (byte)(value >> 8); + buffer[2] = (byte)(value >> 16); + buffer[3] = (byte)(value >> 24); + + return Convert.ToBase64String(buffer); + } + + #endregion + + #region [ EncodeEscaped(string) ] + + /// + /// Encodes a string using simple escape codes. + /// + public string EncodeEscaped(string value) + { + + if ( + (this.options & vCardStandardWriterOptions.IgnoreCommas) == + vCardStandardWriterOptions.IgnoreCommas) + { + return EncodeEscaped(value, outlookEscapedCharacters); + } + else + { + return EncodeEscaped(value, standardEscapedCharacters); + } + } + + #endregion + + #region [ EncodeEscaped(string, char[]) ] + + /// + /// Encodes a character array using simple escape sequences. + /// + public static string EncodeEscaped( + string value, + char[] escaped) + { + + if (escaped == null) + throw new ArgumentNullException("escaped"); + + if (string.IsNullOrEmpty(value)) + return value; + + StringBuilder buffer = new StringBuilder(); + + int startIndex = 0; + + do + { + + // Get the index of the next character + // to be escaped (e.g. the next semicolon). + + int nextIndex = value.IndexOfAny(escaped, startIndex); + + if (nextIndex == -1) + { + // No more characters need to be escaped. + // Any characters between the start index + // and the end of the string can be copied + // to the buffer. + + buffer.Append( + value, + startIndex, + value.Length - startIndex); + + break; + + } + else + { + + char replacement; + switch (value[nextIndex]) + { + case '\n': + replacement = 'n'; + break; + + case '\r': + replacement = 'r'; + break; + + default: + replacement = value[nextIndex]; + break; + + } + + buffer.Append( + value, + startIndex, + nextIndex - startIndex); + + buffer.Append('\\'); + buffer.Append(replacement); + + startIndex = nextIndex + 1; + + } + + } while (startIndex < value.Length); + + return buffer.ToString(); + + // The following must be encoded: + // + // Backslash (\\) + // Colon (\:) + // Semicolon (\;) + + } + + #endregion + + #region [ EncodeQuotedPrintable ] + + /// + /// Converts a string to quoted-printable format. + /// + /// + /// The value to encode in Quoted Printable format. + /// + /// + /// The value encoded in Quoted Printable format. + /// + public static string EncodeQuotedPrintable(string value) + { + + if (string.IsNullOrEmpty(value)) + return value; + + StringBuilder builder = new StringBuilder(); + + foreach (char c in value) + { + + int v = (int)c; + + // The following are not required to be encoded: + // + // - Tab (ASCII 9) + // - Space (ASCII 32) + // - Characters 33 to 126, except for the equal sign (61). + + if ( + (v == 9) || + ((v >= 32) && (v <= 60)) || + ((v >= 62) && (v <= 126))) + { + builder.Append(c); + } + else + { + builder.Append('='); + builder.Append(v.ToString("X2")); + } + + } + + char lastChar = builder[builder.Length - 1]; + if (char.IsWhiteSpace(lastChar)) + { + builder.Remove(builder.Length - 1, 1); + builder.Append('='); + builder.Append(((int)lastChar).ToString("X2")); + } + + return builder.ToString(); + + } + + #endregion + + /// + /// Returns property encoded into a standard vCard NAME:VALUE format. + /// + 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(); + + } + + + /// + /// Writes a vCard to an output text writer. + /// + public override void Write(vCard card, TextWriter output) + { + + if (card == null) + throw new ArgumentNullException("card"); + + if (output == null) + throw new ArgumentNullException("output"); + + // Get the properties of the vCard. + + vCardPropertyCollection properties = + BuildProperties(card); + + Write(properties, output); + + } + + /// + /// Writes a collection of vCard properties to an output text writer. + /// + public void Write(vCardPropertyCollection properties, TextWriter output) + { + + if (properties == null) + throw new ArgumentNullException("properties"); + + if (output == null) + throw new ArgumentNullException("output"); + + foreach (vCardProperty property in properties) + { + output.WriteLine(EncodeProperty(property)); + } + + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardStandardWriterOptions.cs b/vCardEditor/Thought.vCards/vCardStandardWriterOptions.cs new file mode 100644 index 0000000..672e2a1 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardStandardWriterOptions.cs @@ -0,0 +1,41 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Thought.vCards +{ + + /// + /// Extended options for the class. + /// + [Flags] + public enum vCardStandardWriterOptions + { + + /// + /// No options. + /// + None = 0, + + /// + /// Indicates whether or not commas should be escaped in values. + /// + /// + /// The vCard specification requires that commas be escaped + /// in values (e.g. a "," is translated to "\,"). However, Microsoft + /// Outlook(tm) does not properly decode these escaped commas. This + /// option instruct the writer to ignored (not translate) embedded + /// commas for better compatibility with Outlook. + /// + IgnoreCommas = 1 + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardSubproperty.cs b/vCardEditor/Thought.vCards/vCardSubproperty.cs new file mode 100644 index 0000000..3043a8d --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardSubproperty.cs @@ -0,0 +1,141 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; + +namespace Thought.vCards +{ + + /// + /// A subproperty of a vCard property. + /// + /// + /// + /// A vCard is fundamentally a set of properties in NAME:VALUE + /// format, where the name is a keyword like "EMAIL" and the + /// value is a string appropriate for the keyword (e.g. an email + /// address for the EMAIL property, or a BASE64 encoded image + /// for the PHOTO property). + /// + /// + /// All vCard properties support subproperties. These can + /// be global options like encoding or value type, or might be + /// options specific to the keyword. For example, all vCard + /// properties can have an encoding subproperty that identifies + /// the text encoding of the value. A phone property, however, + /// supports special properties that identify the type and purpose + /// of the phone. + /// + /// + /// A subproperty is not required to have a value. In such a case + /// the subproperty acts like a flag. For example, the TEL + /// property of the vCard specification is used to indicate a + /// telephone number associated with the person. This property + /// supports a subproperty called BBS, which indicates the telephone + /// number is for a dial-up bulletin board system. The BBS + /// subproperty does not need a value; the existance of the BBS + /// subproperty is sufficient to indicate the telephone number is + /// for a BBS system. + /// + /// + public class vCardSubproperty + { + + /// + /// Stores the name of the subproperty. + /// + private string name; + + + /// + /// Stores the value of the subproperty. This can be null. + /// + private string value; + + + /// + /// Creates a subproperty with the specified + /// name and no value. + /// + /// + /// The name of the subproperty. + /// + public vCardSubproperty(string name) + { + + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException("name"); + } + else + { + this.name = name; + } + + } + + + /// + /// Creates a subproperty with the specified + /// name and value. + /// + /// + /// The name of the subproperty. + /// + /// + /// The value of the subproperty. This can be null. + /// + public vCardSubproperty(string name, string value) + { + + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException("name"); + } + else + { + this.name = name; + } + + this.value = value; + } + + + /// + /// The name of the subproperty. + /// + public string Name + { + get + { + return this.name; + } + set + { + this.name = value; + } + } + + + /// + /// The optional value of the subproperty. + /// + public string Value + { + get + { + return this.value; + } + set + { + this.value = value; + } + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardSubpropertyCollection.cs b/vCardEditor/Thought.vCards/vCardSubpropertyCollection.cs new file mode 100644 index 0000000..ffcf438 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardSubpropertyCollection.cs @@ -0,0 +1,368 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections; +using System.Collections.ObjectModel; + +namespace Thought.vCards +{ + + /// + /// A collection of objects. + /// + /// + /// + /// This class is a general-purpose collection of + /// objects. + /// + /// + /// A property of a vCard contains a piece of + /// contact information, such as an email address + /// or web site. A subproperty indicates options + /// or attributes of the property, such as the + /// type of email address or character set. + /// + /// + /// + /// + public class vCardSubpropertyCollection : Collection + { + + /// + /// Adds a subproperty without a value. + /// + /// + /// The name of the subproperty. + /// + public void Add(string name) + { + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException("name"); + } + else + { + Add(new vCardSubproperty(name)); + } + } + + + /// + /// Adds a subproperty with the specified name and value. + /// + /// + /// The name of the new subproperty to add. + /// + /// + /// The value of the new subproperty to add. This can be null. + /// + public void Add(string name, string value) + { + Add(new vCardSubproperty(name, value)); + } + + + /// + /// Either adds or updates a subproperty with the specified name. + /// + /// + /// The name of the subproperty to add or update. + /// + /// + /// The value of the subproperty to add or update. + /// + public void AddOrUpdate(string name, string value) + { + + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + + int index = IndexOf(name); + + if (index == -1) + { + Add(name, value); + } + else + { + this[index].Value = value; + } + + } + + + /// + /// Determines if the collection contains a subproperty + /// with the specified name. + /// + /// + /// The name of the subproperty. + /// + /// + /// True if the collection contains a subproperty with the + /// specified name, or False otherwise. + /// + public bool Contains(string name) + { + + foreach (vCardSubproperty sub in this) + { + + if (string.Compare(name, sub.Name, StringComparison.OrdinalIgnoreCase) == 0) + return true; + } + + return false; + + } + + + /// + /// Builds a string array containing subproperty names. + /// + /// + /// A string array containing the unmodified name of + /// each subproperty in the collection. + /// + public string[] GetNames() + { + + ArrayList names = new ArrayList(this.Count); + + foreach (vCardSubproperty sub in this) + { + names.Add(sub.Name); + } + + return (string[])names.ToArray(typeof(string)); + + } + + + /// + /// Builds a string array containing all subproperty + /// names that match one of the names in an array. + /// + /// + /// A list of valid subproperty names. + /// + /// + /// A string array containing the names of all subproperties + /// that match an entry in the filterNames list. + /// + public string[] GetNames(string[] filteredNames) + { + + if (filteredNames == null) + throw new ArgumentNullException("filteredNames"); + + // The vCard specification is not case-sensitive. + // Therefore the subproperty names and the filter names + // list must be compared in a case-insensitive matter. + // Whitespace will also be ignored. For better- + // performing comparisons, a processed version of + // the filtered list will be constructed. + + string[] processedNames = + (string[])filteredNames.Clone(); + + for (int index = 0; index < processedNames.Length; index++) + { + if (!string.IsNullOrEmpty(processedNames[index])) + { + processedNames[index] = + processedNames[index].Trim().ToUpperInvariant(); + } + } + + // Matching names will be stored in an array list, + // and then converted to a string array for return. + + ArrayList matchingNames = new ArrayList(); + + foreach (vCardSubproperty sub in this) + { + + // Convert this subproperty name to upper case. + // The names in the processed array are already + // in upper case. + + string subName = + sub.Name == null ? null : sub.Name.ToUpperInvariant(); + + // See if the processed subproperty name has any + // matches in the processed array. + + int matchIndex = + Array.IndexOf(processedNames, subName); + + if (matchIndex != -1) + matchingNames.Add(processedNames[matchIndex]); + + } + + return (string[])matchingNames.ToArray(typeof(string)); + + } + + + /// + /// Get the value of the subproperty with + /// the specified name. + /// + /// + /// The name of the subproperty. + /// + /// + /// The value of the subproperty or null if no + /// such subproperty exists in the collection. + /// + public string GetValue(string name) + { + + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + + // Get the collection index of the subproperty + // object that has the specified name. + + int index = IndexOf(name); + if (index == -1) + { + return null; + } + else + { + return this[index].Value; + } + + } + + + /// + /// Gets the value of the first subproperty with the + /// specified name, or the first value specified in + /// a list. + /// + /// + /// The expected name of the subproperty. + /// + /// + /// A list of values that are sometimes listed as + /// subproperty names. The first matching value is + /// returned if the name parameter does not match. + /// + public string GetValue( + string name, + string[] namelessValues) + { + + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + + // See if the subproperty exists with the + // specified name. If so, return the value + // immediately. + + int index = IndexOf(name); + if (index != -1) + { + return this[index].Value; + } + + // A subproperty with the specified name does + // not exist. However, this does not mean that + // the subproperty does not exist. Some subproperty + // values can be written directly without a name. + // An example is the ENCODING property. Example: + // + // New Format: KEY;ENCODING=BASE64:.... + // Old Format: KEY;BASE64:... + + if ((namelessValues == null) || (namelessValues.Length == 0)) + return null; + + int nameIndex = IndexOfAny(namelessValues); + if (nameIndex == -1) + { + return null; + } + else + { + return this[nameIndex].Name; + } + + } + + + /// + /// Searches for a subproperty with the specified name. + /// + /// + /// The name of the subproperty. + /// + /// + /// The collection (zero-based) index of the first + /// subproperty that matches the specified name. The + /// function returns -1 if no match is found. + /// + public int IndexOf(string name) + { + + for (int index = 0; index < this.Count; index++) + { + if (string.Compare(name, this[index].Name, StringComparison.OrdinalIgnoreCase) == 0) + { + return index; + } + } + + return -1; + + } + + + /// + /// Finds the first subproperty that has any of the + /// specified names. + /// + /// + /// An array of names to search. + /// + /// + /// The collection index of the first subproperty with + /// the specified name, or -1 if no subproperty was found. + /// + public int IndexOfAny(string[] names) + { + + if (names == null) + throw new ArgumentNullException("names"); + + for (int index = 0; index < this.Count; index++) + { + + foreach (string name in names) + { + + if (string.Compare(this[index].Name, name, StringComparison.OrdinalIgnoreCase) == 0) + { + return index; + } + } + + } + + return -1; + + } + + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardValueCollection.cs b/vCardEditor/Thought.vCards/vCardValueCollection.cs new file mode 100644 index 0000000..fe0e3ef --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardValueCollection.cs @@ -0,0 +1,80 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections.Specialized; +using System.Text; + +namespace Thought.vCards +{ + + /// + /// A collection of string values. + /// + public class vCardValueCollection : StringCollection + { + + private char separator; + + /// + /// Initializes an empty . + /// + public vCardValueCollection() + : base() + { + this.separator = ','; + } + + + /// + /// Initializes the value collection with the specified separator. + /// + /// + /// The suggested character to use as a separator when + /// writing the collection as a string. + /// + public vCardValueCollection(char separator) + { + this.separator = separator; + } + + + /// + /// Adds the contents of a StringCollection to the collection. + /// + /// + /// An initialized StringCollection containing zero or more values. + /// + public void Add(StringCollection values) + { + if (values == null) + throw new ArgumentNullException("values"); + + foreach (string value in values) + Add(value); + + } + + + /// + /// The suggested separator when writing values to a string. + /// + public char Separator + { + get + { + return this.separator; + } + set + { + this.separator = value; + } + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardWebsite.cs b/vCardEditor/Thought.vCards/vCardWebsite.cs new file mode 100644 index 0000000..e5f0e7e --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardWebsite.cs @@ -0,0 +1,170 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; + +namespace Thought.vCards +{ + + /// + /// A web site defined in a vCard. + /// + /// + /// + public class vCardWebsite + { + + private string url; + private vCardWebsiteTypes websiteType; + + + /// + /// Creates a vCardWebSite object. + /// + public vCardWebsite() + { + this.url = string.Empty; + } + + + /// + /// Creates a new vCardWebSite object with the specified URL. + /// + /// + /// The URL of the web site. + /// + public vCardWebsite(string url) + { + this.url = url == null ? string.Empty : url; + } + + + /// + /// Creates a new vCardWebSite with the + /// specified URL and classification. + /// + /// + /// The URL of the web site. + /// + /// + /// The classification of the web site. + /// + public vCardWebsite(string url, vCardWebsiteTypes websiteType) + { + this.url = url == null ? string.Empty : url; + this.websiteType = websiteType; + } + + + /// + /// Indicates a personal home page. + /// + public bool IsPersonalSite + { + get + { + return (this.websiteType & vCardWebsiteTypes.Personal) == + vCardWebsiteTypes.Personal; + } + set + { + + if (value) + { + this.websiteType |= vCardWebsiteTypes.Personal; + } + else + { + this.websiteType &= ~vCardWebsiteTypes.Personal; + } + + } + } + + + /// + /// Indicates a work-related web site. + /// + public bool IsWorkSite + { + get + { + return (this.websiteType & vCardWebsiteTypes.Work) == + vCardWebsiteTypes.Work; + } + set + { + + if (value) + { + this.websiteType |= vCardWebsiteTypes.Work; + } + else + { + this.websiteType &= ~vCardWebsiteTypes.Work; + } + + } + + } + + + /// + /// The URL of the web site. + /// + /// + /// The format of the URL is not validated. + /// + public string Url + { + get + { + return this.url; + } + set + { + if (value == null) + { + this.url = string.Empty; + } + else + { + this.url = value; + } + } + } + + + /// + /// The type of web site (e.g. home page, work, etc). + /// + public vCardWebsiteTypes WebsiteType + { + get + { + return this.websiteType; + } + set + { + this.websiteType = value; + } + } + + + /// + /// Returns the string representation (URL) of the web site. + /// + /// + /// The URL of the web site. + /// + public override string ToString() + { + return this.url; + } + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardWebsiteCollection.cs b/vCardEditor/Thought.vCards/vCardWebsiteCollection.cs new file mode 100644 index 0000000..114b9f1 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardWebsiteCollection.cs @@ -0,0 +1,61 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections.ObjectModel; + +namespace Thought.vCards +{ + + /// + /// A collection of objects. + /// + /// + /// + public class vCardWebsiteCollection : Collection + { + + /// + /// Returns the first web site of the specified type. If + /// the collection does not contain a website of the specified + /// type, but does contain a default (uncategorized) website, + /// then that website will be returned. + /// + /// + /// + public vCardWebsite GetFirstChoice(vCardWebsiteTypes siteType) + { + + vCardWebsite alternate = null; + + foreach (vCardWebsite webSite in this) + { + + if ((webSite.WebsiteType & siteType) == siteType) + { + return webSite; + } + else + { + + if ( + (alternate == null) && + (webSite.WebsiteType == vCardWebsiteTypes.Default)) + { + alternate = webSite; + } + + } + } + + return alternate; + + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardWebsiteTypes.cs b/vCardEditor/Thought.vCards/vCardWebsiteTypes.cs new file mode 100644 index 0000000..596309f --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardWebsiteTypes.cs @@ -0,0 +1,45 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; + +namespace Thought.vCards +{ + + /// + /// The type or classification of a web site. + /// + /// + /// + /// The Microsoft Outlook contact editor has a field for + /// entering a web site. The default classification of + /// this web site is work-related. A personal web site + /// can be viewed or entered through the All Fields tab. + /// + /// + [Flags] + public enum vCardWebsiteTypes + { + + /// + /// No web site designation. + /// + Default = 0, + + /// + /// A personal home page. + /// + Personal = 1, + + /// + /// A work-related web site. + /// + Work = 2 + + } + +} \ No newline at end of file diff --git a/vCardEditor/Thought.vCards/vCardWriter.cs b/vCardEditor/Thought.vCards/vCardWriter.cs new file mode 100644 index 0000000..5715c51 --- /dev/null +++ b/vCardEditor/Thought.vCards/vCardWriter.cs @@ -0,0 +1,81 @@ + +/* ======================================================================= + * vCard Library for .NET + * Copyright (c) 2007-2009 David Pinch; http://wwww.thoughtproject.com + * See LICENSE.TXT for licensing information. + * ======================================================================= */ + +using System; +using System.Collections.Specialized; +using System.IO; +using System.Text; + +namespace Thought.vCards +{ + + /// + /// Base class for vCard generators. + /// + /// + /// + public abstract class vCardWriter + { + + + /// + /// Holds output warnings. + /// + private StringCollection warnings = new StringCollection(); + + + /// + /// A collection of warning messages that were generated + /// during the output of a vCard. + /// + public StringCollection Warnings + { + get + { + return this.warnings; + } + } + + + /// + /// Writes a vCard to an I/O stream using the format + /// implemented by the class. + /// + /// + /// The vCard to write the I/O string. + /// + /// + /// The text writer to use for output. + /// + /// + /// The implementor should not close or flush the stream. + /// The caller owns the stream and may not wish for the + /// stream to be closed (e.g. the caller may call the + /// function again with a different vCard). + /// + public abstract void Write(vCard card, TextWriter output); + + + /// + /// Writes the vCard to the specified filename. + /// + public virtual void Write(vCard card, string filename) + { + + if (card == null) + throw new ArgumentNullException("card"); + + using (StreamWriter output = new StreamWriter(filename)) + { + Write(card, output); + } + + } + + } + +} \ No newline at end of file diff --git a/vCardEditor/View/AboutDialog.Designer.cs b/vCardEditor/View/AboutDialog.Designer.cs new file mode 100644 index 0000000..37d9083 --- /dev/null +++ b/vCardEditor/View/AboutDialog.Designer.cs @@ -0,0 +1,186 @@ +namespace vCardEditor.View +{ + partial class AboutDialog + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur Windows Form + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AboutDialog)); + this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.logoPictureBox = new System.Windows.Forms.PictureBox(); + this.labelProductName = new System.Windows.Forms.Label(); + this.labelVersion = new System.Windows.Forms.Label(); + this.labelCopyright = new System.Windows.Forms.Label(); + this.labelCompanyName = new System.Windows.Forms.Label(); + this.textBoxDescription = new System.Windows.Forms.TextBox(); + this.okButton = new System.Windows.Forms.Button(); + this.tableLayoutPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).BeginInit(); + this.SuspendLayout(); + // + // tableLayoutPanel + // + this.tableLayoutPanel.ColumnCount = 2; + this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33F)); + this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 67F)); + this.tableLayoutPanel.Controls.Add(this.logoPictureBox, 0, 0); + this.tableLayoutPanel.Controls.Add(this.labelProductName, 1, 0); + this.tableLayoutPanel.Controls.Add(this.labelVersion, 1, 1); + this.tableLayoutPanel.Controls.Add(this.labelCopyright, 1, 2); + this.tableLayoutPanel.Controls.Add(this.labelCompanyName, 1, 3); + this.tableLayoutPanel.Controls.Add(this.textBoxDescription, 1, 4); + this.tableLayoutPanel.Controls.Add(this.okButton, 1, 5); + this.tableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel.Location = new System.Drawing.Point(9, 9); + this.tableLayoutPanel.Name = "tableLayoutPanel"; + this.tableLayoutPanel.RowCount = 6; + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F)); + this.tableLayoutPanel.Size = new System.Drawing.Size(417, 265); + this.tableLayoutPanel.TabIndex = 0; + // + // logoPictureBox + // + this.logoPictureBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.logoPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("logoPictureBox.Image"))); + this.logoPictureBox.Location = new System.Drawing.Point(3, 3); + this.logoPictureBox.Name = "logoPictureBox"; + this.tableLayoutPanel.SetRowSpan(this.logoPictureBox, 6); + this.logoPictureBox.Size = new System.Drawing.Size(131, 259); + this.logoPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.logoPictureBox.TabIndex = 12; + this.logoPictureBox.TabStop = false; + // + // labelProductName + // + this.labelProductName.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelProductName.Location = new System.Drawing.Point(143, 0); + this.labelProductName.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelProductName.MaximumSize = new System.Drawing.Size(0, 17); + this.labelProductName.Name = "labelProductName"; + this.labelProductName.Size = new System.Drawing.Size(271, 17); + this.labelProductName.TabIndex = 19; + this.labelProductName.Text = "Nom du produit"; + this.labelProductName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // labelVersion + // + this.labelVersion.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelVersion.Location = new System.Drawing.Point(143, 26); + this.labelVersion.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelVersion.MaximumSize = new System.Drawing.Size(0, 17); + this.labelVersion.Name = "labelVersion"; + this.labelVersion.Size = new System.Drawing.Size(271, 17); + this.labelVersion.TabIndex = 0; + this.labelVersion.Text = "Version"; + this.labelVersion.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // labelCopyright + // + this.labelCopyright.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCopyright.Location = new System.Drawing.Point(143, 52); + this.labelCopyright.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelCopyright.MaximumSize = new System.Drawing.Size(0, 17); + this.labelCopyright.Name = "labelCopyright"; + this.labelCopyright.Size = new System.Drawing.Size(271, 17); + this.labelCopyright.TabIndex = 21; + this.labelCopyright.Text = "Copyright"; + this.labelCopyright.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // labelCompanyName + // + this.labelCompanyName.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCompanyName.Location = new System.Drawing.Point(143, 78); + this.labelCompanyName.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelCompanyName.MaximumSize = new System.Drawing.Size(0, 17); + this.labelCompanyName.Name = "labelCompanyName"; + this.labelCompanyName.Size = new System.Drawing.Size(271, 17); + this.labelCompanyName.TabIndex = 22; + this.labelCompanyName.Text = "Nom de la société"; + this.labelCompanyName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // textBoxDescription + // + this.textBoxDescription.Dock = System.Windows.Forms.DockStyle.Fill; + this.textBoxDescription.Location = new System.Drawing.Point(143, 107); + this.textBoxDescription.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3); + this.textBoxDescription.Multiline = true; + this.textBoxDescription.Name = "textBoxDescription"; + this.textBoxDescription.ReadOnly = true; + this.textBoxDescription.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.textBoxDescription.Size = new System.Drawing.Size(271, 126); + this.textBoxDescription.TabIndex = 23; + this.textBoxDescription.TabStop = false; + this.textBoxDescription.Text = "Description"; + // + // okButton + // + this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.okButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.okButton.Location = new System.Drawing.Point(339, 239); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(75, 23); + this.okButton.TabIndex = 24; + this.okButton.Text = "&OK"; + // + // AboutDialog + // + this.AcceptButton = this.okButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(435, 283); + this.Controls.Add(this.tableLayoutPanel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "AboutDialog"; + this.Padding = new System.Windows.Forms.Padding(9); + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "AboutDialog"; + this.tableLayoutPanel.ResumeLayout(false); + this.tableLayoutPanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel; + private System.Windows.Forms.PictureBox logoPictureBox; + private System.Windows.Forms.Label labelProductName; + private System.Windows.Forms.Label labelVersion; + private System.Windows.Forms.Label labelCopyright; + private System.Windows.Forms.Label labelCompanyName; + private System.Windows.Forms.TextBox textBoxDescription; + private System.Windows.Forms.Button okButton; + } +} diff --git a/vCardEditor/View/AboutDialog.cs b/vCardEditor/View/AboutDialog.cs new file mode 100644 index 0000000..a0cd2d2 --- /dev/null +++ b/vCardEditor/View/AboutDialog.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Windows.Forms; + +namespace vCardEditor.View +{ + partial class AboutDialog : Form + { + public AboutDialog() + { + InitializeComponent(); + this.Text = String.Format("À propos de {0}", AssemblyTitle); + this.labelProductName.Text = AssemblyProduct; + this.labelVersion.Text = String.Format("Version {0}", AssemblyVersion); + this.labelCopyright.Text = AssemblyCopyright; + this.labelCompanyName.Text = AssemblyCompany; + this.textBoxDescription.Text = AssemblyDescription; + } + + #region Accesseurs d'attribut de l'assembly + + public string AssemblyTitle + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); + if (attributes.Length > 0) + { + AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0]; + if (titleAttribute.Title != "") + { + return titleAttribute.Title; + } + } + return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase); + } + } + + public string AssemblyVersion + { + get + { + return Assembly.GetExecutingAssembly().GetName().Version.ToString(); + } + } + + public string AssemblyDescription + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyDescriptionAttribute)attributes[0]).Description; + } + } + + public string AssemblyProduct + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyProductAttribute)attributes[0]).Product; + } + } + + public string AssemblyCopyright + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyCopyrightAttribute)attributes[0]).Copyright; + } + } + + public string AssemblyCompany + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyCompanyAttribute)attributes[0]).Company; + } + } + #endregion + } +} diff --git a/vCardEditor/View/AboutDialog.resx b/vCardEditor/View/AboutDialog.resx new file mode 100644 index 0000000..0d686c1 --- /dev/null +++ b/vCardEditor/View/AboutDialog.resx @@ -0,0 +1,604 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + AAAAAElFTkSuQmCC + + + \ No newline at end of file diff --git a/vCardEditor/View/EventArgs.cs b/vCardEditor/View/EventArgs.cs new file mode 100644 index 0000000..91375bd --- /dev/null +++ b/vCardEditor/View/EventArgs.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace VCFEditor.View +{ + + //public class ArgumentEventArgs : EventArgs + //{ + // public object argument { get; set; } + //} + + //http://stackoverflow.com/questions/3312134/does-net-have-a-built-in-eventargst + + public class EventArg : EventArgs + { + // Property variable + private readonly T p_EventData; + + // Constructor + public EventArg(T data) + { + p_EventData = data; + } + + // Property for EventArgs argument + public T Data + { + get { return p_EventData; } + } + } +} diff --git a/vCardEditor/View/IMainView.cs b/vCardEditor/View/IMainView.cs new file mode 100644 index 0000000..41059c8 --- /dev/null +++ b/vCardEditor/View/IMainView.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Thought.vCards; +using VCFEditor.Model; +using System.ComponentModel; + +namespace VCFEditor.View +{ + public interface IMainView + { + #region All events + event EventHandler DeleteContact; + event EventHandler SaveContactsSelected; + event EventHandler> NewFileOpened; + event EventHandler> ChangeContactsSelected; + #endregion + + int SelectedContactIndex { get; } + void DisplayContacts(BindingList contacts); + void DisplayContactDetail(vCard card); + } +} diff --git a/vCardEditor/View/MainForm.Designer.cs b/vCardEditor/View/MainForm.Designer.cs new file mode 100644 index 0000000..c1ce350 --- /dev/null +++ b/vCardEditor/View/MainForm.Designer.cs @@ -0,0 +1,359 @@ +namespace vCardEditor.View +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); + this.menuStrip1 = new System.Windows.Forms.MenuStrip(); + this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); + this.quitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); + this.toolStrip1 = new System.Windows.Forms.ToolStrip(); + this.tbsOpen = new System.Windows.Forms.ToolStripButton(); + this.tbsSave = new System.Windows.Forms.ToolStripButton(); + this.tbsDelete = new System.Windows.Forms.ToolStripButton(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.tbsAbout = new System.Windows.Forms.ToolStripButton(); + this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); + this.bsContacts = new System.Windows.Forms.BindingSource(this.components); + this.dgContacts = new System.Windows.Forms.DataGridView(); + this.Column1 = new System.Windows.Forms.DataGridViewCheckBoxColumn(); + this.Column2 = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.CellularPhoneValue = new System.Windows.Forms.TextBox(); + this.CellularPhoneLabel = new System.Windows.Forms.Label(); + this.HomePhoneValue = new System.Windows.Forms.TextBox(); + this.FormattedNameValue = new System.Windows.Forms.TextBox(); + this.HomePhoneLabel = new System.Windows.Forms.Label(); + this.FormattedNameLabel = new System.Windows.Forms.Label(); + this.menuStrip1.SuspendLayout(); + this.toolStrip1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.bsContacts)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.dgContacts)).BeginInit(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // menuStrip1 + // + this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.fileToolStripMenuItem, + this.helpToolStripMenuItem}); + this.menuStrip1.Location = new System.Drawing.Point(0, 0); + this.menuStrip1.Name = "menuStrip1"; + this.menuStrip1.Size = new System.Drawing.Size(676, 24); + this.menuStrip1.TabIndex = 0; + this.menuStrip1.Text = "menuStrip1"; + // + // fileToolStripMenuItem + // + this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.openToolStripMenuItem, + this.toolStripMenuItem1, + this.quitToolStripMenuItem}); + this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; + this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); + this.fileToolStripMenuItem.Text = "File"; + // + // openToolStripMenuItem + // + this.openToolStripMenuItem.Name = "openToolStripMenuItem"; + this.openToolStripMenuItem.Size = new System.Drawing.Size(103, 22); + this.openToolStripMenuItem.Text = "&Open"; + // + // toolStripMenuItem1 + // + this.toolStripMenuItem1.Name = "toolStripMenuItem1"; + this.toolStripMenuItem1.Size = new System.Drawing.Size(100, 6); + // + // quitToolStripMenuItem + // + this.quitToolStripMenuItem.Name = "quitToolStripMenuItem"; + this.quitToolStripMenuItem.Size = new System.Drawing.Size(103, 22); + this.quitToolStripMenuItem.Text = "&Quit"; + // + // helpToolStripMenuItem + // + this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.aboutToolStripMenuItem}); + this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; + this.helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20); + this.helpToolStripMenuItem.Text = "Help"; + // + // aboutToolStripMenuItem + // + this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; + this.aboutToolStripMenuItem.Size = new System.Drawing.Size(107, 22); + this.aboutToolStripMenuItem.Text = "&About"; + // + // statusStrip1 + // + this.statusStrip1.Location = new System.Drawing.Point(0, 431); + this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.Size = new System.Drawing.Size(676, 22); + this.statusStrip1.TabIndex = 1; + this.statusStrip1.Text = "statusStrip1"; + // + // toolStrip1 + // + this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.tbsOpen, + this.tbsSave, + this.tbsDelete, + this.toolStripSeparator1, + this.tbsAbout}); + this.toolStrip1.Location = new System.Drawing.Point(0, 24); + this.toolStrip1.Name = "toolStrip1"; + this.toolStrip1.Size = new System.Drawing.Size(676, 25); + this.toolStrip1.TabIndex = 2; + this.toolStrip1.Text = "toolStrip1"; + // + // tbsOpen + // + this.tbsOpen.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.tbsOpen.Image = ((System.Drawing.Image)(resources.GetObject("tbsOpen.Image"))); + this.tbsOpen.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tbsOpen.Name = "tbsOpen"; + this.tbsOpen.Size = new System.Drawing.Size(23, 22); + this.tbsOpen.Text = "&Open"; + this.tbsOpen.Click += new System.EventHandler(this.tbsOpen_Click); + // + // tbsSave + // + this.tbsSave.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.tbsSave.Image = ((System.Drawing.Image)(resources.GetObject("tbsSave.Image"))); + this.tbsSave.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tbsSave.Name = "tbsSave"; + this.tbsSave.Size = new System.Drawing.Size(23, 22); + this.tbsSave.Text = "&Save"; + this.tbsSave.Click += new System.EventHandler(this.tbsSave_Click); + // + // tbsDelete + // + this.tbsDelete.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.tbsDelete.Image = ((System.Drawing.Image)(resources.GetObject("tbsDelete.Image"))); + this.tbsDelete.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tbsDelete.Name = "tbsDelete"; + this.tbsDelete.Size = new System.Drawing.Size(23, 22); + this.tbsDelete.Text = "Delete"; + this.tbsDelete.Click += new System.EventHandler(this.tbsDelete_Click); + // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25); + // + // tbsAbout + // + this.tbsAbout.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.tbsAbout.Image = ((System.Drawing.Image)(resources.GetObject("tbsAbout.Image"))); + this.tbsAbout.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tbsAbout.Name = "tbsAbout"; + this.tbsAbout.Size = new System.Drawing.Size(23, 22); + this.tbsAbout.Text = "&?"; + this.tbsAbout.Click += new System.EventHandler(this.tbsAbout_Click); + // + // openFileDialog + // + this.openFileDialog.FileName = "openFileDialog1"; + // + // dgContacts + // + this.dgContacts.AllowUserToAddRows = false; + this.dgContacts.AllowUserToDeleteRows = false; + this.dgContacts.AllowUserToResizeRows = false; + dataGridViewCellStyle1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224))))); + this.dgContacts.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle1; + this.dgContacts.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.dgContacts.AutoGenerateColumns = false; + this.dgContacts.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.dgContacts.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.Raised; + this.dgContacts.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.dgContacts.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.Column1, + this.Column2}); + this.dgContacts.DataSource = this.bsContacts; + this.dgContacts.Location = new System.Drawing.Point(12, 52); + this.dgContacts.MultiSelect = false; + this.dgContacts.Name = "dgContacts"; + this.dgContacts.RowHeadersVisible = false; + this.dgContacts.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; + this.dgContacts.Size = new System.Drawing.Size(191, 376); + this.dgContacts.TabIndex = 3; + this.dgContacts.SelectionChanged += new System.EventHandler(this.dgContacts_SelectionChanged); + // + // Column1 + // + this.Column1.DataPropertyName = "isSelected"; + this.Column1.HeaderText = " "; + this.Column1.Name = "Column1"; + this.Column1.Width = 50; + // + // Column2 + // + this.Column2.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.Column2.DataPropertyName = "Name"; + this.Column2.HeaderText = "Name"; + this.Column2.Name = "Column2"; + this.Column2.ReadOnly = true; + // + // groupBox1 + // + this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox1.Controls.Add(this.CellularPhoneValue); + this.groupBox1.Controls.Add(this.CellularPhoneLabel); + this.groupBox1.Controls.Add(this.HomePhoneValue); + this.groupBox1.Controls.Add(this.FormattedNameValue); + this.groupBox1.Controls.Add(this.HomePhoneLabel); + this.groupBox1.Controls.Add(this.FormattedNameLabel); + this.groupBox1.Location = new System.Drawing.Point(209, 52); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(467, 376); + this.groupBox1.TabIndex = 4; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Contact Detail :"; + // + // CellularPhoneValue + // + this.CellularPhoneValue.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.CellularPhoneValue.Location = new System.Drawing.Point(105, 92); + this.CellularPhoneValue.Name = "CellularPhoneValue"; + this.CellularPhoneValue.Size = new System.Drawing.Size(321, 20); + this.CellularPhoneValue.TabIndex = 47; + // + // CellularPhoneLabel + // + this.CellularPhoneLabel.Location = new System.Drawing.Point(16, 92); + this.CellularPhoneLabel.Name = "CellularPhoneLabel"; + this.CellularPhoneLabel.Size = new System.Drawing.Size(83, 19); + this.CellularPhoneLabel.TabIndex = 46; + this.CellularPhoneLabel.Text = "Mobile:"; + this.CellularPhoneLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // HomePhoneValue + // + this.HomePhoneValue.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.HomePhoneValue.Location = new System.Drawing.Point(105, 65); + this.HomePhoneValue.Name = "HomePhoneValue"; + this.HomePhoneValue.Size = new System.Drawing.Size(321, 20); + this.HomePhoneValue.TabIndex = 45; + // + // FormattedNameValue + // + this.FormattedNameValue.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.FormattedNameValue.Location = new System.Drawing.Point(105, 38); + this.FormattedNameValue.Name = "FormattedNameValue"; + this.FormattedNameValue.Size = new System.Drawing.Size(321, 20); + this.FormattedNameValue.TabIndex = 44; + // + // HomePhoneLabel + // + this.HomePhoneLabel.Location = new System.Drawing.Point(16, 65); + this.HomePhoneLabel.Name = "HomePhoneLabel"; + this.HomePhoneLabel.Size = new System.Drawing.Size(83, 19); + this.HomePhoneLabel.TabIndex = 43; + this.HomePhoneLabel.Text = "Home Phone:"; + this.HomePhoneLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // FormattedNameLabel + // + this.FormattedNameLabel.Location = new System.Drawing.Point(16, 38); + this.FormattedNameLabel.Name = "FormattedNameLabel"; + this.FormattedNameLabel.Size = new System.Drawing.Size(83, 19); + this.FormattedNameLabel.TabIndex = 42; + this.FormattedNameLabel.Text = "Name:"; + this.FormattedNameLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(676, 453); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.dgContacts); + this.Controls.Add(this.toolStrip1); + this.Controls.Add(this.statusStrip1); + this.Controls.Add(this.menuStrip1); + this.MainMenuStrip = this.menuStrip1; + this.Name = "MainForm"; + this.Text = "MainForm"; + this.menuStrip1.ResumeLayout(false); + this.menuStrip1.PerformLayout(); + this.toolStrip1.ResumeLayout(false); + this.toolStrip1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.bsContacts)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.dgContacts)).EndInit(); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.MenuStrip menuStrip1; + private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem openToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem quitToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem aboutToolStripMenuItem; + private System.Windows.Forms.StatusStrip statusStrip1; + private System.Windows.Forms.ToolStrip toolStrip1; + private System.Windows.Forms.ToolStripButton tbsOpen; + private System.Windows.Forms.ToolStripButton tbsSave; + private System.Windows.Forms.ToolStripButton tbsDelete; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + private System.Windows.Forms.ToolStripButton tbsAbout; + private System.Windows.Forms.OpenFileDialog openFileDialog; + private System.Windows.Forms.BindingSource bsContacts; + private System.Windows.Forms.DataGridView dgContacts; + private System.Windows.Forms.GroupBox groupBox1; + internal System.Windows.Forms.TextBox CellularPhoneValue; + internal System.Windows.Forms.Label CellularPhoneLabel; + internal System.Windows.Forms.TextBox HomePhoneValue; + internal System.Windows.Forms.TextBox FormattedNameValue; + internal System.Windows.Forms.Label HomePhoneLabel; + internal System.Windows.Forms.Label FormattedNameLabel; + private System.Windows.Forms.DataGridViewCheckBoxColumn Column1; + private System.Windows.Forms.DataGridViewTextBoxColumn Column2; + } +} \ No newline at end of file diff --git a/vCardEditor/View/MainForm.cs b/vCardEditor/View/MainForm.cs new file mode 100644 index 0000000..0dde928 --- /dev/null +++ b/vCardEditor/View/MainForm.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using VCFEditor.View; +using VCFEditor.Model; +using Thought.vCards; + +namespace vCardEditor.View +{ + public partial class MainForm : Form, IMainView + { + public event EventHandler SaveContactsSelected; + public event EventHandler DeleteContact; + public event EventHandler> NewFileOpened; + public event EventHandler> ChangeContactsSelected; + + public int SelectedContactIndex + { + get + { + return dgContacts.CurrentCell.RowIndex; + } + + } + + public MainForm() + { + InitializeComponent(); + } + + private void tbsOpen_Click(object sender, EventArgs e) + { + DialogResult result = openFileDialog.ShowDialog(); + if (result == DialogResult.OK) + { + string file = openFileDialog.FileName; + if (NewFileOpened != null) + NewFileOpened(sender, new EventArg(file)); + } + + } + + public void DisplayContacts(BindingList contacts) + { + if (contacts != null) + this.bsContacts.DataSource = contacts; + + } + + private void tbsSave_Click(object sender, EventArgs e) + { + if (SaveContactsSelected != null) + SaveContactsSelected(sender, e); + + } + + private void dgContacts_SelectionChanged(object sender, EventArgs e) + { + if (ChangeContactsSelected != null) + { + int index = dgContacts.CurrentCell.RowIndex; + ChangeContactsSelected(sender, new EventArg(index)); + } + } + + public void DisplayContactDetail(vCard card) + { + if (card == null) + throw new ArgumentException("card"); + + //Formatted Name + SetSummaryValue(FormattedNameValue, card.FormattedName); + + //Home Phone + SetSummaryValue(HomePhoneValue, card.Phones.GetFirstChoice(vCardPhoneTypes.Home)); + + //Cellular Phone + SetSummaryValue(CellularPhoneValue, card.Phones.GetFirstChoice(vCardPhoneTypes.Cellular)); + + + } + private void SetSummaryValue(TextBox valueLabel, string value) + { + if (valueLabel == null) + throw new ArgumentNullException("valueLabel"); + + //Clear textbox if value is empty! + valueLabel.Text = value; + } + + private void SetSummaryValue(TextBox valueLabel, vCardPhone phone) + { + valueLabel.Text = string.Empty; + if (phone != null) + SetSummaryValue(valueLabel, phone.FullNumber); + + } + + private void tbsDelete_Click(object sender, EventArgs e) + { + if (DeleteContact != null) + { + //commit changes... + dgContacts.EndEdit(); + DeleteContact(sender, e); + } + } + + private void tbsAbout_Click(object sender, EventArgs e) + { + AboutDialog dialog = new AboutDialog(); + dialog.ShowDialog(); + } + } +} diff --git a/vCardEditor/View/MainForm.resx b/vCardEditor/View/MainForm.resx new file mode 100644 index 0000000..cfac18e --- /dev/null +++ b/vCardEditor/View/MainForm.resx @@ -0,0 +1,208 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 132, 17 + + + 248, 17 + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAJHSURBVDhPxZBdSNNhFMb/F110ZZEVhVBgeeHNICiiuggp + olAUyyxI0oSaH1QYC3N+tKnp5ubm1JUua5uuqdNKMwr7kApFItTUkWZqVhSVYmao5Nevvy7UoYR3HXh4 + 4XCe33nOKyy3lAY7l9RWMo0O/raWXxEyo5spVYTNvOGyfIRPfW+ptOkXqaPl6T83hcRmExSdgzAz3NVm + YWyoYla/B+1M9JtxWLPpaH22JORIjI6gKAMB0jyEimIdo4OlbuaprwVMOOMovammpDADc34qppwUrmnl + 5Kni3aFlFg2j3y1z5mnRTJccnNIltQhwq0jFry+mOXNtpWZWDx1Z1NhV3C3JwGFOw25SYjVe5oYhiUKd + HKMmwQUrMWUw/CF3NnZvvYKqUh1TvUroS3fXe7HXkwidMngTS2t5KLbregSzMY2f3Wr4qKW6LJvGR1rX + 0MLor8OhKYTJBn/GHvvxrliCTBrsOqXIoOBHh5K+hmSq7FqmexTQHuUytkaKxuNMNgYyVneA4Qd7GKjc + hjLaRzxH7gIU6JIZaEvgtk1D8wsxSWecCDgNzWFMvwxm/PkhRmr3Mli1nW9lvjRdWc0Jf+/5jzRmyWmv + S+GOLQu6U6BFjPvqKOP1AYw88WOoZif9DgmfLVtxaj1RSLdwNvrkPCA3M54KqxrnvRia9MKcGrUrqFOt + 5H7qKsqT1mGO9+Lqhc2ELdw+U/r0i+gVZ8hMiCDx3DHORwZyKnQ/hw/uYt9uCTskPvh6e7Fp41rWr/Fg + g6eHO+A/lyD8ARfG3mk9fv1YAAAAAElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIySURBVDhPrZLfS5NRGMfff6H7boIuuq2pMZyL1eAt11CW + DcOKsB9vpFmaLtNExco0av6CbIVLJ61Wk3BSkT/AFCkRZSpZmrmiJQ41xSaCwdfznL15XEUX0Reem5f3 + 8znnec4j/Zc8fxYGla91CS3eRTx0z6OpMYS7jmnU1X6B/VYA18snUVoyjsKCt8jLHcH5c36ouCQR2NUJ + 1Nas4G9ZXlmFKbULh1Kf8lJxSfI+WeCCyopv6q+/h+DQ/DJ2WV5Ao1FgPegRAveDOS4oLfmq/h6dn/DH + 4AJizD4UXJrCAUuzEDgbZrjgou2DiohshIcnQtgme5GTPYbkJKcQ1N8OckHW2REVi+RXuM8fxGaDG4oy + ALPZIQQ11Z+5QDk1oKJ/hjv7P2FTfCMOH3mFxMQ6IbhROYWOdrCnBI4dfwPr0V4+bRoY9UzXppMjcDdS + rC8hy3YhuFI2gTYf2A4Aza4f7N2/o/zaLB8qDYx6zszwr8P7k1thNFYIweXCMXgeAfedq2xxwjClZUeV + Jd2GtDNFETiJwfs8MBjKhMCWN8pgoLoqzE8miH1GjE7G4PsZjE7OQsm9ij2mFg7rdrug1xcJAa2l4w7W + r00Cgk/n38S7wBwC04u4UGxHrMHF4CbEJtyDLj5fCDIzhljfSxzeavRgyw4Zj9t64GvvQ0d3P3pfD2Kv + 2QqNvgFxDN6urYdWmyMElJMnevh60obRktA701PRtGlg1DOdSkXwzrisaMG/RZLWAE60OMW5fNhvAAAA + AElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAL3SURBVDhPjZFrSJNRHMbPLLe5zXdmKyrTXEqZJWFmlJ/y + fkkplCwRsrAL5EzytlSUZM7bTDRvdDG10pIKHaaWaZmZaYpWBpJ96fJFsogtd8kRT+/Z1sXwQw/8Oec8 + 5/k9Ly+HLKYJVeDu8dKgC+NFQe/Mw+6pZ70mzYT4XCdEfo0Qxmr90WhJwNHpBl/M9q7DZCof6rU2GDu+ + DNSjdy2EKLs3uGHiYDTYokIrZhEb8J++4ou5EQmmz9piJCwAmhsX0efthRfJQgzEOqPbXQpDWxMMzTXo + 27IRVtSi58WBlz7dleLHKzuMHrLFZGwUTM3V0NQUQe3EwW2REJoLZTDVqzBbmovbQsHCgrFi/w/6fkeY + hoWYaRFAvWI5TJfLYWqoxOuEOMyWKzBfrYSuvsIMVxGSYkUtMhf0SDD/iIG+h0Gn1xJ8TD4GY1EOvlcW + wqiQY65CiW5XF9QScp5FuBbSqqcF/o0zre6Yf8DA2OmAyTQBete7wpidCkNaEow5aXi23Zt+uYaN8y3U + X+o44xfxpm4HtB2rMH+PwWAoF2M7fWGQp0KXmAB9egqmQoNwhZAGNs6xUAvFa8r0UdKSoWgHPN68Cfrc + LHyLicbckQR82x8DA3se8t5Kn7DOyvwWJyRDEBmrdMQ5uQe6JBJ8jY+HNiQcmtTTeBkcBJ1MBm1wGLSh + EWi3E6CREDcrSzihmYI9idWrUPXED60KDww6OUO7Lwa6JBkeSKWo92Lw/nACjOUqvN27l/6GmnJmOFjG + kx4odkBJnyeuTm1DrVqCdpE9ZpNlGN21CzVhS1GRx+AWj4euNavNa95qm0SWtaEFNuFZgsyTDStRPeaJ + suE1KBhgUH6Eh1tcLkrjuMhvE0HBPq2ybSXKqlxwQiVBSLrgzK+CpRE5ot5TrWIo+l2R3SNG9n0x5J1i + ZF63R0YHgyz2TH265j90RfJNMShDWVpgG57L/yy744AU9T/TvojHDs1ShrLmgjC5sCQyi/8lKk+E/xma + pQwhxPYnT5K9Ev2GYxQAAAAASUVORK5CYII= + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIVSURBVDhPtVJNaxNRFM1PyE+Yn1AUXLjK0uWgDWQZwUUX + KsGFBEEcCkIwqBEpGiydsSo2kupsasdo7Yi2toh0sFZjG5JpiZo20/TpVOmH5njvm8BYahEXHji8+968 + c+55l4n8F0zM+rhVWkHmdg29A/PoK1Yw8uIjOp/3xpvqBgrjLeilZbjNLXxZ34bwt6jexMVCGRndQenl + 0p+NWHzPXoP3rQ3bAbQhQM0E5Np2BKprbZzrm8TIs8puE+68+r0NwwZiacCwALEBCVcAqet8JlAjk1PZ + JzsNJt6u4+FMS3ZmMV9mmFNAMhesbBZLC6oFdOsd8oVXocmdx018Ej9k1FgqiJ0zgS6qlR6BVI4iEFRN + IJlxMF/1cfTMcGiQvbskB6ZqgairJ6BCTJKYu9tlAUW1oSRsNDwfB+JXQ4PzN6s07W0ZPxDS5aSgJEFn + 06Y9CaOqSauJRvMr9qmXQ4P8/RoWvU16eyBUEq5kbigwiKoOMTBQ0zbKlTq6TxihwejkZ1iOJwfEwmiC + BQ49yaW50J7Fh0xJw3IxbM3hwo2x0ICRHZzFgveTunYERK5lgo5YMxx8WPFw5Li+U8wYm66jNz+Naov+ + Beqiao58N5NrPluoryJO0QeKU7sNGKPPazh9aRzGo/eYmVvEMk270fTlmzl2N3XW9xL/jv7iaxw7+wAH + E9ew//AVxE8OItv/9O/Cf0ck8gud2vKswuxNZgAAAABJRU5ErkJggg== + + + + 353, 17 + + + 486, 17 + + + True + + + True + + \ No newline at end of file diff --git a/vCardEditor/vCardEditor.csproj b/vCardEditor/vCardEditor.csproj new file mode 100644 index 0000000..54db8eb --- /dev/null +++ b/vCardEditor/vCardEditor.csproj @@ -0,0 +1,144 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {A0D2ACEB-1BCC-4E7F-9E7D-2BE25A7ABE22} + WinExe + Properties + vCardEditor + vCardEditor + v4.0 + Client + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Form + + + AboutDialog.cs + + + + + Form + + + MainForm.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + + AboutDialog.cs + + + MainForm.cs + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + \ No newline at end of file diff --git a/vCardEditor_Test/MainPresenterTest.cs b/vCardEditor_Test/MainPresenterTest.cs new file mode 100644 index 0000000..ca6cec9 --- /dev/null +++ b/vCardEditor_Test/MainPresenterTest.cs @@ -0,0 +1,31 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace vCardEditor_Test +{ + /// + /// + /// + [TestClass] + public class MainPresenterTest + { + public MainPresenterTest() + { + // + // TODO: + // + } + + + [TestMethod] + public void TestMethod1() + { + // + // TODO: + // + } + } +} diff --git a/vCardEditor_Test/Properties/AssemblyInfo.cs b/vCardEditor_Test/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f365e05 --- /dev/null +++ b/vCardEditor_Test/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Les informations générales relatives à un assembly dépendent de +// l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations +// associées à un assembly. +[assembly: AssemblyTitle("vCardEditor_Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("vCardEditor_Test")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly +// aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de +// COM, affectez la valeur true à l'attribut ComVisible sur ce type. +[assembly: ComVisible(false)] + +// Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM +[assembly: Guid("d36513f5-c8e3-47bb-a474-830447685b12")] + +// Les informations de version pour un assembly se composent des quatre valeurs suivantes : +// +// Version principale +// Version secondaire +// Numéro de build +// Révision +// +// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de révision et de build par défaut +// en utilisant '*', comme indiqué ci-dessous : +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/vCardEditor_Test/vCardEditor_Test.csproj b/vCardEditor_Test/vCardEditor_Test.csproj new file mode 100644 index 0000000..e689f87 --- /dev/null +++ b/vCardEditor_Test/vCardEditor_Test.csproj @@ -0,0 +1,57 @@ + + + + Debug + AnyCPU + + + 2.0 + {76D5F727-2E1A-46B5-BD35-F8F9B5881FEE} + Library + Properties + vCardEditor_Test + vCardEditor_Test + v4.0 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + 3.5 + + + + + False + + + + + + + + \ No newline at end of file