using System; using System.Collections.Generic; using System.Runtime.InteropServices; using StarfaceOutlookSync.Models; using Outlook = Microsoft.Office.Interop.Outlook; namespace StarfaceOutlookSync.Services { public class OutlookContactsService : IDisposable { private Outlook.Application _outlookApp; private bool _weStartedOutlook; private Outlook.Application GetOutlookApp() { if (_outlookApp != null) return _outlookApp; try { // Versuche laufende Outlook-Instanz zu finden _outlookApp = (Outlook.Application)Marshal.GetActiveObject("Outlook.Application"); _weStartedOutlook = false; } catch { // Outlook starten falls nicht laufend _outlookApp = new Outlook.Application(); _weStartedOutlook = true; } return _outlookApp; } public List GetContactFolderPaths() { var folders = new List(); try { var app = GetOutlookApp(); var ns = app.GetNamespace("MAPI"); // Standard-Kontaktordner var defaultFolder = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts); folders.Add(defaultFolder.FolderPath); // Unterordner AddSubFolders(defaultFolder, folders); // Weitere Kontaktordner in anderen Stores foreach (Outlook.Store store in ns.Stores) { try { var rootFolder = store.GetRootFolder(); FindContactFolders(rootFolder, folders); } catch { } } Marshal.ReleaseComObject(ns); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Error getting folders: {ex.Message}"); } return folders; } private void AddSubFolders(Outlook.MAPIFolder folder, List paths) { foreach (Outlook.MAPIFolder sub in folder.Folders) { if (sub.DefaultItemType == Outlook.OlItemType.olContactItem) { if (!paths.Contains(sub.FolderPath)) paths.Add(sub.FolderPath); AddSubFolders(sub, paths); } } } private void FindContactFolders(Outlook.MAPIFolder folder, List paths) { if (folder.DefaultItemType == Outlook.OlItemType.olContactItem) { if (!paths.Contains(folder.FolderPath)) paths.Add(folder.FolderPath); } foreach (Outlook.MAPIFolder sub in folder.Folders) { FindContactFolders(sub, paths); } } private Outlook.MAPIFolder GetFolderByPath(string folderPath) { var app = GetOutlookApp(); var ns = app.GetNamespace("MAPI"); // Standard-Kontaktordner als Fallback if (string.IsNullOrEmpty(folderPath)) return ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts); try { // Pfad durchlaufen var parts = folderPath.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries); Outlook.MAPIFolder current = null; foreach (Outlook.Store store in ns.Stores) { if (store.GetRootFolder().Name == parts[0] || store.GetRootFolder().FolderPath.TrimStart('\\') == parts[0]) { current = store.GetRootFolder(); break; } } if (current == null) return ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts); for (int i = 1; i < parts.Length; i++) { bool found = false; foreach (Outlook.MAPIFolder sub in current.Folders) { if (sub.Name == parts[i]) { current = sub; found = true; break; } } if (!found) return ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts); } return current; } catch { return ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts); } } public List GetContacts(string folderPath) { var contacts = new List(); try { var folder = GetFolderByPath(folderPath); var items = folder.Items; foreach (var item in items) { if (item is Outlook.ContactItem ci) { contacts.Add(MapFromOutlook(ci)); Marshal.ReleaseComObject(ci); } } Marshal.ReleaseComObject(items); Marshal.ReleaseComObject(folder); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Error reading contacts: {ex.Message}"); } return contacts; } public UnifiedContact CreateContact(UnifiedContact contact, string folderPath) { try { var folder = GetFolderByPath(folderPath); var ci = (Outlook.ContactItem)folder.Items.Add(Outlook.OlItemType.olContactItem); MapToOutlook(contact, ci); ci.Save(); contact.OutlookEntryId = ci.EntryID; Marshal.ReleaseComObject(ci); Marshal.ReleaseComObject(folder); return contact; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Error creating contact: {ex.Message}"); return null; } } public bool UpdateContact(string entryId, UnifiedContact contact) { try { var app = GetOutlookApp(); var ns = app.GetNamespace("MAPI"); var ci = (Outlook.ContactItem)ns.GetItemFromID(entryId); MapToOutlook(contact, ci); ci.Save(); Marshal.ReleaseComObject(ci); Marshal.ReleaseComObject(ns); return true; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Error updating contact: {ex.Message}"); return false; } } public bool DeleteContact(string entryId) { try { var app = GetOutlookApp(); var ns = app.GetNamespace("MAPI"); var ci = (Outlook.ContactItem)ns.GetItemFromID(entryId); ci.Delete(); Marshal.ReleaseComObject(ci); Marshal.ReleaseComObject(ns); return true; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Error deleting contact: {ex.Message}"); return false; } } private UnifiedContact MapFromOutlook(Outlook.ContactItem ci) { return new UnifiedContact { OutlookEntryId = ci.EntryID ?? "", FirstName = ci.FirstName ?? "", LastName = ci.LastName ?? "", Company = ci.CompanyName ?? "", JobTitle = ci.JobTitle ?? "", Email = ci.Email1Address ?? "", EmailSecondary = ci.Email2Address ?? "", PhoneWork = ci.BusinessTelephoneNumber ?? "", PhoneMobile = ci.MobileTelephoneNumber ?? "", PhoneHome = ci.HomeTelephoneNumber ?? "", Fax = ci.BusinessFaxNumber ?? "", Street = ci.BusinessAddressStreet ?? "", City = ci.BusinessAddressCity ?? "", PostalCode = ci.BusinessAddressPostalCode ?? "", State = ci.BusinessAddressState ?? "", Country = ci.BusinessAddressCountry ?? "", Website = ci.WebPage ?? "", Notes = ci.Body ?? "", Salutation = ci.Title ?? "", Title = ci.Suffix ?? "", Birthday = ci.Birthday != DateTime.MinValue && ci.Birthday.Year > 1900 ? ci.Birthday.ToString("yyyy-MM-dd") : "" }; } private void MapToOutlook(UnifiedContact contact, Outlook.ContactItem ci) { ci.FirstName = contact.FirstName; ci.LastName = contact.LastName; ci.CompanyName = contact.Company; ci.JobTitle = contact.JobTitle; ci.Email1Address = contact.Email; if (!string.IsNullOrEmpty(contact.EmailSecondary)) ci.Email2Address = contact.EmailSecondary; ci.BusinessTelephoneNumber = contact.PhoneWork; ci.MobileTelephoneNumber = contact.PhoneMobile; ci.HomeTelephoneNumber = contact.PhoneHome; ci.BusinessFaxNumber = contact.Fax; ci.BusinessAddressStreet = contact.Street; ci.BusinessAddressCity = contact.City; ci.BusinessAddressPostalCode = contact.PostalCode; ci.BusinessAddressState = contact.State; ci.BusinessAddressCountry = contact.Country; ci.WebPage = contact.Website; ci.Body = contact.Notes; ci.Title = contact.Salutation; if (!string.IsNullOrEmpty(contact.Birthday) && DateTime.TryParse(contact.Birthday, out var bday) && bday.Year > 1900) { ci.Birthday = bday; } } public void Dispose() { if (_outlookApp != null) { if (_weStartedOutlook) { try { _outlookApp.Quit(); } catch { } } Marshal.ReleaseComObject(_outlookApp); _outlookApp = null; } } } }