Compare commits

...

7 Commits

Author SHA1 Message Date
duffyduck f57518a1d5 Release v0.0.0.11 2026-04-03 12:51:14 +02:00
duffyduck 1be0a94b51 Fetch full contact details from Starface instead of summary
The contacts list endpoint only returns summaryValues/phoneNumbers.
Now fetch each contact individually via GET /contacts/{id} to get
all fields (blocks/attributes). Also log the detail JSON structure
so we can verify the field mapping is correct.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 12:50:16 +02:00
duffyduck 3c38a1a6cc Release v0.0.0.10 2026-04-03 12:17:30 +02:00
duffyduck ba0b79de64 Release v0.0.0.9 2026-04-03 12:14:42 +02:00
duffyduck 60bd3163a9 Add debug logging for raw Starface API contact data
Logs the first contact from Starface API response into the sync
log so we can see the actual JSON structure and fix field mapping.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 12:13:43 +02:00
duffyduck a3a3ac1dcc Release v0.0.0.8 2026-04-03 12:10:35 +02:00
duffyduck 9d58a1a113 Fix Starface JSON parsing and Outlook folder/contact reading
Starface API:
- Handle both array and object responses from /contacts endpoint
- Try common wrapper fields (items, contacts, data, results)

Outlook contacts:
- Add FindFolderByPath that matches exact FolderPath property
- Fallback to Namespace.Folders navigation if store lookup fails
- Fallback: try reading contact fields even if Class != 40
- Add debug logging for folder path and item count

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 12:08:50 +02:00
6 changed files with 175 additions and 43 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
; Erfordert Inno Setup 6.x (https://jrsoftware.org/isinfo.php) ; Erfordert Inno Setup 6.x (https://jrsoftware.org/isinfo.php)
#define MyAppName "Starface Outlook Sync" #define MyAppName "Starface Outlook Sync"
#define MyAppVersion "0.0.0.7" #define MyAppVersion "0.0.0.11"
#define MyAppPublisher "HackerSoft - Hacker-Net Telekommunikation" #define MyAppPublisher "HackerSoft - Hacker-Net Telekommunikation"
#define MyAppURL "https://www.hacker-net.de" #define MyAppURL "https://www.hacker-net.de"
#define MyAppExeName "StarfaceOutlookSync.exe" #define MyAppExeName "StarfaceOutlookSync.exe"
@@ -153,6 +153,32 @@ namespace StarfaceOutlookSync.Services
} }
} }
private dynamic FindFolderByPath(dynamic folder, string targetPath)
{
try
{
string currentPath = folder.FolderPath;
if (currentPath == targetPath)
return folder;
var subs = folder.Folders;
for (int i = 1; i <= (int)subs.Count; i++)
{
try
{
var sub = subs[i];
var match = FindFolderByPath(sub, targetPath);
if (match != null) return match;
Marshal.ReleaseComObject(sub);
}
catch { }
}
Marshal.ReleaseComObject(subs);
}
catch { }
return null;
}
private dynamic GetFolderByPath(string folderPath) private dynamic GetFolderByPath(string folderPath)
{ {
var app = GetOutlookApp(); var app = GetOutlookApp();
@@ -163,37 +189,46 @@ namespace StarfaceOutlookSync.Services
try try
{ {
var parts = folderPath.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries); // Versuch 1: Alle Kontaktordner durchsuchen und per FolderPath matchen
dynamic current = null;
var stores = ns.Stores; var stores = ns.Stores;
for (int i = 1; i <= (int)stores.Count; i++) for (int i = 1; i <= (int)stores.Count; i++)
{
try
{ {
var store = stores[i]; var store = stores[i];
var root = store.GetRootFolder(); var root = store.GetRootFolder();
string rootName = root.Name; var match = FindFolderByPath(root, folderPath);
if (match != null)
if (rootName == parts[0])
{ {
current = root; Marshal.ReleaseComObject(stores);
break; return match;
} }
Marshal.ReleaseComObject(root); Marshal.ReleaseComObject(root);
Marshal.ReleaseComObject(store); Marshal.ReleaseComObject(store);
} }
catch { }
}
Marshal.ReleaseComObject(stores); Marshal.ReleaseComObject(stores);
if (current == null) // Versuch 2: Namespace.Folders direkt navigieren
return ns.GetDefaultFolder(OlFolderContacts); var parts = folderPath.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length >= 1)
for (int i = 1; i < parts.Length; i++) {
var topFolders = ns.Folders;
for (int i = 1; i <= (int)topFolders.Count; i++)
{
var topFolder = topFolders[i];
if ((string)topFolder.Name == parts[0])
{
dynamic current = topFolder;
for (int p = 1; p < parts.Length; p++)
{ {
bool found = false; bool found = false;
var subFolders = current.Folders; var subs = current.Folders;
for (int j = 1; j <= (int)subFolders.Count; j++) for (int j = 1; j <= (int)subs.Count; j++)
{ {
var sub = subFolders[j]; var sub = subs[j];
if ((string)sub.Name == parts[i]) if ((string)sub.Name == parts[p])
{ {
current = sub; current = sub;
found = true; found = true;
@@ -201,13 +236,22 @@ namespace StarfaceOutlookSync.Services
} }
Marshal.ReleaseComObject(sub); Marshal.ReleaseComObject(sub);
} }
Marshal.ReleaseComObject(subFolders); Marshal.ReleaseComObject(subs);
if (!found) { current = null; break; }
if (!found) }
return ns.GetDefaultFolder(OlFolderContacts); if (current != null)
{
Marshal.ReleaseComObject(topFolders);
return current;
}
}
Marshal.ReleaseComObject(topFolder);
}
Marshal.ReleaseComObject(topFolders);
} }
return current; System.Diagnostics.Debug.WriteLine($"Folder not found by path: {folderPath}, using default");
return ns.GetDefaultFolder(OlFolderContacts);
} }
catch catch
{ {
@@ -221,24 +265,51 @@ namespace StarfaceOutlookSync.Services
try try
{ {
var folder = GetFolderByPath(folderPath); var folder = GetFolderByPath(folderPath);
var items = folder.Items; System.Diagnostics.Debug.WriteLine($"Reading contacts from: {(string)folder.FolderPath}");
for (int i = 1; i <= (int)items.Count; i++) var items = folder.Items;
int count = (int)items.Count;
System.Diagnostics.Debug.WriteLine($"Items count: {count}");
for (int i = 1; i <= count; i++)
{ {
dynamic item = null; dynamic item = null;
try try
{ {
item = items[i]; item = items[i];
// Nur ContactItems verarbeiten (Class = 40 = olContact) int itemClass = -1;
if ((int)item.Class == 40) try { itemClass = (int)item.Class; } catch { }
// olContact = 40, aber manche Kontakte melden Class anders
// Versuch einfach die Kontakt-Felder zu lesen
if (itemClass == 40)
{ {
contacts.Add(MapFromOutlook(item)); contacts.Add(MapFromOutlook(item));
} }
else
{
// Fallback: Pruefen ob es trotzdem ein Kontakt ist
try
{
string eid = item.EntryID;
string fn = item.FirstName;
string ln = item.LastName;
// Hat Kontakt-Felder -> ist ein Kontakt
contacts.Add(MapFromOutlook(item));
}
catch
{
// Kein Kontakt, ueberspringen
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Error reading item {i}: {ex.Message}");
} }
catch { }
finally finally
{ {
if (item != null) Marshal.ReleaseComObject(item); if (item != null) try { Marshal.ReleaseComObject(item); } catch { }
} }
} }
@@ -155,11 +155,14 @@ namespace StarfaceOutlookSync.Services
return books; return books;
} }
public event Action<string> OnDebug;
public async Task<List<UnifiedContact>> GetContactsAsync(StarfaceAddressBook book) public async Task<List<UnifiedContact>> GetContactsAsync(StarfaceAddressBook book)
{ {
var contacts = new List<UnifiedContact>(); var contacts = new List<UnifiedContact>();
int page = 0; int page = 0;
const int pageSize = 200; const int pageSize = 200;
bool firstPage = true;
while (true) while (true)
{ {
@@ -172,11 +175,68 @@ namespace StarfaceOutlookSync.Services
var resp = await _http.GetAsync($"{_baseUrl}/contacts?{query}"); var resp = await _http.GetAsync($"{_baseUrl}/contacts?{query}");
if (!resp.IsSuccessStatusCode) break; if (!resp.IsSuccessStatusCode) break;
var array = JArray.Parse(await resp.Content.ReadAsStringAsync()); var body = await resp.Content.ReadAsStringAsync();
JArray array;
// Die API gibt je nach Version ein Array oder ein Objekt mit "items" zurueck
var token = JToken.Parse(body);
if (token is JArray directArray)
{
array = directArray;
}
else if (token is JObject obj)
{
// Versuche gaengige Felder: items, contacts, data, results
array = (obj["items"] ?? obj["contacts"] ?? obj["data"] ?? obj["results"]) as JArray;
if (array == null)
{
// Einzelnes Kontakt-Objekt? Dann in Array wrappen
if (obj["id"] != null && obj["blocks"] != null)
{
array = new JArray { obj };
}
else
{
System.Diagnostics.Debug.WriteLine($"Unerwartete Starface-Antwort: {body.Substring(0, Math.Min(200, body.Length))}");
break;
}
}
}
else
{
break;
}
if (array.Count == 0) break; if (array.Count == 0) break;
OnDebug?.Invoke($"Seite {page}: {array.Count} Kontakte in Liste");
// Die Listen-API gibt nur Summary zurueck.
// Jeden Kontakt einzeln abrufen fuer alle Felder.
foreach (var item in array) foreach (var item in array)
contacts.Add(MapFromStarface(item)); {
var id = item["id"]?.ToString();
if (string.IsNullOrEmpty(id)) continue;
try
{
var detailResp = await _http.GetAsync($"{_baseUrl}/contacts/{id}");
if (detailResp.IsSuccessStatusCode)
{
var detailBody = await detailResp.Content.ReadAsStringAsync();
var detailObj = JObject.Parse(detailBody);
if (firstPage)
{
OnDebug?.Invoke($"Starface Kontakt-Detail (1. Kontakt):\n{detailObj.ToString(Formatting.Indented)}");
firstPage = false;
}
contacts.Add(MapFromStarface(detailObj));
}
}
catch { }
}
if (array.Count < pageSize) break; if (array.Count < pageSize) break;
page++; page++;
@@ -53,6 +53,7 @@ namespace StarfaceOutlookSync.Services
Log("Verbinde mit Starface..."); Log("Verbinde mit Starface...");
using (var starface = new StarfaceApiClient(profile.StarfaceConnection)) using (var starface = new StarfaceApiClient(profile.StarfaceConnection))
{ {
starface.OnDebug += (msg) => Log(msg);
var loginOk = await starface.LoginAsync(); var loginOk = await starface.LoginAsync();
if (!loginOk) if (!loginOk)
{ {
@@ -7,9 +7,9 @@
<AssemblyTitle>Starface Outlook Sync</AssemblyTitle> <AssemblyTitle>Starface Outlook Sync</AssemblyTitle>
<Company>HackerSoft - Hacker-Net Telekommunikation</Company> <Company>HackerSoft - Hacker-Net Telekommunikation</Company>
<Product>Starface Outlook Sync</Product> <Product>Starface Outlook Sync</Product>
<Version>0.0.0.7</Version> <Version>0.0.0.11</Version>
<AssemblyVersion>0.0.0.7</AssemblyVersion> <AssemblyVersion>0.0.0.11</AssemblyVersion>
<FileVersion>0.0.0.7</FileVersion> <FileVersion>0.0.0.11</FileVersion>
<Description>Synchronisiert Outlook-Kontakte mit Starface Telefonanlage</Description> <Description>Synchronisiert Outlook-Kontakte mit Starface Telefonanlage</Description>
<Copyright>Stefan Hacker - HackerSoft</Copyright> <Copyright>Stefan Hacker - HackerSoft</Copyright>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
+1 -1
View File
@@ -27,7 +27,7 @@ namespace StarfaceOutlookSync.UI
var lblVersion = new Label var lblVersion = new Label
{ {
Text = "Version 0.0.0.7", Text = "Version 0.0.0.11",
Left = 0, Top = 56, Width = 340, Height = 20, Left = 0, Top = 56, Width = 340, Height = 20,
TextAlign = ContentAlignment.MiddleCenter, TextAlign = ContentAlignment.MiddleCenter,
ForeColor = Color.Gray ForeColor = Color.Gray