Fonaria als zweite Anlage neben Starface

Die SyncEngine kennt jetzt nur noch IContactBackend. Was dahinter steckt,
entscheidet das Profil — der Ablauf mit getrennten Baselines, Wiederzuordnung
und Konfliktaufloesung bleibt unangetastet. In ihm steckt die Erfahrung, die
man nicht zweimal machen will.

FonariaApiClient spricht deren REST-API. Der Kern ist das Feld `verwaltet`,
das jeder Schreibvorgang mitschickt: Fonaria haelt den Kontakt als
vollstaendige vCard, dieses Sync-Modell bildet davon nur einen Ausschnitt ab.
Ohne diese Liste haette ein aus Outlook gespiegelter Kontakt nach dem ersten
Abgleich kein Bild, keine Kategorien und keinen Jahrestag mehr — nicht weil
jemand sie geloescht haette, sondern weil wir sie nicht kannten.

Zwei Verluste lagen darunter und sind gefunden worden, weil der Client gegen
eine echte Anlage lief:

- Die Abteilung steckt im zweiten Teil von ORG. Wer nur die Firma schickt,
  loescht sie mit.
- Neben der geschaeftlichen Anschrift kann eine private stehen. Das
  Sync-Modell traegt nur eine.

Beides wird jetzt aus dem gelesenen Stand unveraendert zurueckgeschrieben.

Umbenannt: StarfaceConnection -> SystemConnection, StarfaceAddressBook ->
RemoteAddressBook. Die JSON-Namen bleiben ueber JsonProperty erhalten, sonst
verloeren bestehende Profile ihre Verbindungsdaten. SyncMapping.StarfaceId
behaelt seinen Namen aus demselben Grund.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-11 22:10:43 +02:00
co-authored by Claude Opus 5
parent 88635c04f8
commit 6ecd5d7fa3
9 changed files with 655 additions and 54 deletions
+1 -1
View File
@@ -241,7 +241,7 @@ namespace StarfaceOutlookSync.UI
var item = new ListViewItem(new[]
{
p.Name,
$"{p.StarfaceConnection.Host} / {p.StarfaceAddressBook.Name}",
$"{p.Connection.Host} / {p.AddressBook.Name}",
p.OutlookFolderName,
dirText,
lastSync
+69 -26
View File
@@ -24,10 +24,30 @@ namespace StarfaceOutlookSync.UI
private Label _lblTestResult;
private Label _lblDirectionHint;
private List<StarfaceAddressBook> _addressBooks = new List<StarfaceAddressBook>();
private List<RemoteAddressBook> _addressBooks = new List<RemoteAddressBook>();
private List<string> _outlookFolderPaths = new List<string>();
private string _selectedOutlookPath = "";
private string _selectedOutlookName = "";
private ComboBox _cmbSystem;
private Label _lblAnlage;
private Label _lblLoginId;
private Label _lblAddressBook;
private string AnlagenName => GewaehlteAnlage == PhoneSystem.Fonaria ? "Fonaria" : "Starface";
private PhoneSystem GewaehlteAnlage =>
_cmbSystem != null && _cmbSystem.SelectedIndex == 1 ? PhoneSystem.Fonaria : PhoneSystem.Starface;
/// <summary>Beschriftungen, die je nach Anlage anders heissen.</summary>
private void UpdateSystemLabels()
{
var fonaria = GewaehlteAnlage == PhoneSystem.Fonaria;
if (_lblLoginId != null)
_lblLoginId.Text = fonaria ? "Benutzername:" : "Login-ID:";
if (_lblAddressBook != null)
_lblAddressBook.Text = fonaria ? "Fonaria-Adressbuch:" : "Starface-Adressbuch:";
UpdateDirectionHint();
}
public ProfileEditorForm(SyncProfile profile)
{
@@ -54,8 +74,26 @@ namespace StarfaceOutlookSync.UI
panel.Controls.Add(MakeLabel("Profilname:", 12, y)); y += 22;
_txtName = new TextBox { Left = 12, Top = y, Width = 420 }; panel.Controls.Add(_txtName); y += 32;
// === Starface ===
panel.Controls.Add(MakeSectionLabel("Starface-Verbindung", 12, y)); y += 26;
// === Anlage ===
_lblAnlage = MakeSectionLabel("Verbindung zur Telefonanlage", 12, y); y += 26;
panel.Controls.Add(_lblAnlage);
panel.Controls.Add(MakeLabel("Anlage:", 12, y)); y += 22;
_cmbSystem = new ComboBox { Left = 12, Top = y, Width = 200, DropDownStyle = ComboBoxStyle.DropDownList };
_cmbSystem.Items.AddRange(new object[] { "Starface", "Fonaria" });
_cmbSystem.SelectedIndex = 0;
// Beide sprechen ihre eigene Schnittstelle; der Vorgabeport ist
// derselbe, aber die Adressbuecher heissen anders. Beim Wechsel
// muss die Auswahl darum neu geladen werden.
_cmbSystem.SelectedIndexChanged += (s, e) =>
{
_addressBooks.Clear();
_cmbAddressBook.Items.Clear();
_lblTestResult.Text = "Anlage gewechselt - bitte Adressbuecher neu laden.";
_lblTestResult.ForeColor = Color.FromArgb(150, 80, 0);
UpdateSystemLabels();
};
panel.Controls.Add(_cmbSystem); y += 32;
panel.Controls.Add(MakeLabel("Host / IP-Adresse:", 12, y)); y += 22;
_txtHost = new TextBox { Left = 12, Top = y, Width = 320 };
@@ -67,7 +105,8 @@ namespace StarfaceOutlookSync.UI
_chkSsl = new CheckBox { Text = "HTTPS verwenden", Left = 12, Top = y, Checked = true, AutoSize = true };
panel.Controls.Add(_chkSsl); y += 28;
panel.Controls.Add(MakeLabel("Login-ID:", 12, y)); y += 22;
_lblLoginId = MakeLabel("Login-ID:", 12, y);
panel.Controls.Add(_lblLoginId); y += 22;
_txtLoginId = new TextBox { Left = 12, Top = y, Width = 200 }; panel.Controls.Add(_txtLoginId); y += 32;
panel.Controls.Add(MakeLabel("Kennwort:", 12, y)); y += 22;
@@ -84,7 +123,8 @@ namespace StarfaceOutlookSync.UI
_lblTestResult = new Label { Left = 12, Top = y, Width = 420, Height = 20, ForeColor = Color.Gray };
panel.Controls.Add(_lblTestResult); y += 26;
panel.Controls.Add(MakeLabel("Starface-Adressbuch:", 12, y)); y += 22;
_lblAddressBook = MakeLabel("Adressbuch der Anlage:", 12, y);
panel.Controls.Add(_lblAddressBook); y += 22;
_cmbAddressBook = new ComboBox { Left = 12, Top = y, Width = 420, DropDownStyle = ComboBoxStyle.DropDownList };
panel.Controls.Add(_cmbAddressBook); y += 32;
@@ -100,7 +140,7 @@ namespace StarfaceOutlookSync.UI
panel.Controls.Add(MakeLabel("Sync-Richtung:", 12, y)); y += 22;
_cmbDirection = new ComboBox { Left = 12, Top = y, Width = 250, DropDownStyle = ComboBoxStyle.DropDownList };
_cmbDirection.Items.AddRange(new object[] { "Bidirektional", "Outlook -> Starface", "Starface -> Outlook" });
_cmbDirection.Items.AddRange(new object[] { "Bidirektional", "Outlook -> Anlage", "Anlage -> Outlook" });
_cmbDirection.SelectedIndex = 0;
panel.Controls.Add(_cmbDirection); y += 28;
@@ -138,11 +178,11 @@ namespace StarfaceOutlookSync.UI
{
switch (_cmbDirection.SelectedIndex)
{
case 1: // Outlook -> Starface
_lblDirectionHint.Text = "Achtung: Das Starface-Adressbuch wird zur exakten Kopie von Outlook.\nKontakte, die nur in Starface existieren, werden geloescht.";
case 1: // Outlook -> Anlage
_lblDirectionHint.Text = $"Achtung: Das Adressbuch der {AnlagenName} wird zur exakten Kopie von Outlook.\nKontakte, die nur dort existieren, werden geloescht.";
break;
case 2: // Starface -> Outlook
_lblDirectionHint.Text = "Achtung: Der Outlook-Ordner wird zur exakten Kopie von Starface.\nKontakte, die nur in Outlook existieren, werden geloescht.";
case 2: // Anlage -> Outlook
_lblDirectionHint.Text = $"Achtung: Der Outlook-Ordner wird zur exakten Kopie der {AnlagenName}.\nKontakte, die nur in Outlook existieren, werden geloescht.";
break;
default: // Bidirektional
_lblDirectionHint.Text = "Aenderungen werden in beide Richtungen abgeglichen.";
@@ -182,15 +222,17 @@ namespace StarfaceOutlookSync.UI
if (_existingProfile != null)
{
_txtName.Text = _existingProfile.Name;
_txtHost.Text = _existingProfile.StarfaceConnection.Host;
_txtPort.Text = _existingProfile.StarfaceConnection.Port.ToString();
_chkSsl.Checked = _existingProfile.StarfaceConnection.UseSsl;
_txtLoginId.Text = _existingProfile.StarfaceConnection.LoginId;
_txtPassword.Text = _existingProfile.StarfaceConnection.Password;
_cmbSystem.SelectedIndex = _existingProfile.Connection.System == PhoneSystem.Fonaria ? 1 : 0;
_txtHost.Text = _existingProfile.Connection.Host;
_txtPort.Text = _existingProfile.Connection.Port.ToString();
_chkSsl.Checked = _existingProfile.Connection.UseSsl;
_txtLoginId.Text = _existingProfile.Connection.LoginId;
_txtPassword.Text = _existingProfile.Connection.Password;
_chkEnabled.Checked = _existingProfile.Enabled;
_numAutoSync.Value = _existingProfile.AutoSyncIntervalMinutes;
_cmbDirection.SelectedIndex = (int)_existingProfile.SyncDirection;
UpdateSystemLabels();
// Outlook-Ordner
_selectedOutlookPath = _existingProfile.OutlookFolderPath;
@@ -198,10 +240,10 @@ namespace StarfaceOutlookSync.UI
_txtOutlookFolder.Text = _selectedOutlookPath;
// Adressbuch
if (_existingProfile.StarfaceAddressBook != null)
if (_existingProfile.AddressBook != null)
{
_addressBooks.Add(_existingProfile.StarfaceAddressBook);
_cmbAddressBook.Items.Add(_existingProfile.StarfaceAddressBook.Name);
_addressBooks.Add(_existingProfile.AddressBook);
_cmbAddressBook.Items.Add(_existingProfile.AddressBook.Name);
_cmbAddressBook.SelectedIndex = 0;
}
}
@@ -227,10 +269,11 @@ namespace StarfaceOutlookSync.UI
}
}
private StarfaceConnection GetConnection()
private SystemConnection GetConnection()
{
return new StarfaceConnection
return new SystemConnection
{
System = GewaehlteAnlage,
Host = _txtHost.Text.Trim(),
Port = int.TryParse(_txtPort.Text, out var p) ? p : 443,
UseSsl = _chkSsl.Checked,
@@ -247,7 +290,7 @@ namespace StarfaceOutlookSync.UI
try
{
using (var client = new StarfaceApiClient(GetConnection()))
using (var client = ContactBackendFactory.Create(GetConnection()))
{
var ok = await client.LoginAsync();
if (ok)
@@ -280,7 +323,7 @@ namespace StarfaceOutlookSync.UI
try
{
using (var client = new StarfaceApiClient(GetConnection()))
using (var client = ContactBackendFactory.Create(GetConnection()))
{
var ok = await client.LoginAsync();
if (!ok)
@@ -350,8 +393,8 @@ namespace StarfaceOutlookSync.UI
{
Id = _existingProfile?.Id ?? _pm.GenerateId(),
Name = _txtName.Text.Trim(),
StarfaceConnection = GetConnection(),
StarfaceAddressBook = _addressBooks[_cmbAddressBook.SelectedIndex],
Connection = GetConnection(),
AddressBook = _addressBooks[_cmbAddressBook.SelectedIndex],
OutlookFolderPath = _selectedOutlookPath,
OutlookFolderName = _selectedOutlookName,
SyncDirection = (SyncDirection)_cmbDirection.SelectedIndex,
@@ -367,8 +410,8 @@ namespace StarfaceOutlookSync.UI
else
{
// Wenn Adressbuch gewechselt wurde, Mappings zuruecksetzen
if (_existingProfile.StarfaceAddressBook?.TagId != profile.StarfaceAddressBook?.TagId
|| _existingProfile.StarfaceAddressBook?.Type != profile.StarfaceAddressBook?.Type)
if (_existingProfile.AddressBook?.TagId != profile.AddressBook?.TagId
|| _existingProfile.AddressBook?.Type != profile.AddressBook?.Type)
{
_pm.SaveMappings(profile.Id, new List<SyncMapping>());
profile.LastSync = "";
@@ -35,7 +35,7 @@ namespace StarfaceOutlookSync.UI
var infoLabel = new Label
{
Text = $"{_profile.StarfaceConnection.Host} ({_profile.StarfaceAddressBook.Name}) <-> {_profile.OutlookFolderName}",
Text = $"{_profile.Connection.Host} ({_profile.AddressBook.Name}) <-> {_profile.OutlookFolderName}",
Left = 12, Top = 12, Width = 460, AutoSize = false, Height = 20
};