====== std.edi.partner ====== Handelspartner-Profile für AS2- und SFTP-Transportkanäle. Die Unit ist ein **Metadaten-Registry** — kein Netzwerktreiber. Sie definiert, wie Nachrichten an einen Partner übertragen werden (Protokoll, Host, Pfad, vereinbarte Nachrichtentypen, Sicherheitsoptionen). Das Wire-Format ist Pipe-delimitierter Text (eine Zeile pro Partner): protocol|partnerID|ourID|host|port|path|msgTypes|options AS2|ACME-GmbH|MINE-Corp|as2.acme.com|4080|/as2|ORDERS,INVOIC|0 SFTP|ACME-FTP|MINE-Corp|sftp.acme.com|22|/edi/in|REMADV,ORDERS|1 import std.edi.partner; import std.alloc; import std.string; fn Feld(p: int64, l: int64): pchar { var b: int64 := alloc(l + 1); var i: int64 := 0; while (i < l) { poke8(b + i, peek8(p + i)); i := i + 1; } poke8(b + l, 0); return b as pchar; } fn main(): int64 { var p: int64 := alloc(EDI_PART_SIZE); var i: int64 := 0; while (i < EDI_PART_SIZE) { poke8(p + i, 0); i := i + 1; } poke64(p + EDI_PART_PROTOCOL, EDI_PART_PROTO_AS2); poke64(p + EDI_PART_PARTNERID, "PARTNER-AS2-ID"c as int64); poke64(p + EDI_PART_PARTNERLEN, 14); poke64(p + EDI_PART_OURID, "MEINE-AS2-ID"c as int64); poke64(p + EDI_PART_OURIDLEN, 12); poke64(p + EDI_PART_HOST, "edi.partner.example"c as int64); poke64(p + EDI_PART_HOSTLEN, 19); poke64(p + EDI_PART_PORT, 443); poke64(p + EDI_PART_PATH, "/as2/inbound"c as int64); poke64(p + EDI_PART_PATHLEN, 12); poke64(p + EDI_PART_MSGTYPES, EDI_PART_MSG_ORDERS + EDI_PART_MSG_INVOIC + EDI_PART_MSG_DESADV); poke64(p + EDI_PART_OPTIONS, EDI_PART_OPT_SIGN + EDI_PART_OPT_ENCRYPT); PrintLn(StrConcat("gueltig: ", IntToStr(EdiPartnerValidate(p)))); var out: int64 := alloc(1024); var n: int64 := EdiPartnerWrite(p, out, 1024); Print(Feld(out, n)); // Zeile endet bereits mit \n // Zeile wieder einlesen var p2: int64 := alloc(EDI_PART_SIZE); if (EdiPartnerRead(out, n, p2) == 1) { PrintLn(StrConcat("Host: ", Feld(peek64(p2 + EDI_PART_HOST), peek64(p2 + EDI_PART_HOSTLEN)))); PrintLn(StrConcat("Port: ", IntToStr(peek64(p2 + EDI_PART_PORT)))); PrintLn(StrConcat("ORDERS erlaubt: ", IntToStr(EdiPartnerSupports(p2, EDI_PART_MSG_ORDERS)))); PrintLn(StrConcat("CUSTOMS erlaubt: ", IntToStr(EdiPartnerSupports(p2, EDI_PART_MSG_CUSTOMS)))); } // Registry: mehrere Zeilen, Suche nach Partner-ID var parts: int64 := alloc(4 * EDI_PART_SIZE); var cnt: int64 := EdiPartnerListRead(out, n, parts, 4); // EdiPartnerFind liefert einen ZEIGER auf den Datensatz, keinen Index - 0 = nicht gefunden var rec: int64 := EdiPartnerFind(parts, cnt, "PARTNER-AS2-ID"c, 14); if (rec != 0) { PrintLn(StrConcat("Registry-Eintraege: ", IntToStr(cnt))); PrintLn(StrConcat("Pfad des Treffers: ", Feld(peek64(rec + EDI_PART_PATH), peek64(rec + EDI_PART_PATHLEN)))); } else { PrintLn("Partner nicht gefunden"); } return 0; } gueltig: 1 AS2|PARTNER-AS2-ID|MEINE-AS2-ID|edi.partner.example|443|/as2/inbound|ORDERS,INVOIC,DESADV|3 Host: edi.partner.example Port: 443 ORDERS erlaubt: 1 CUSTOMS erlaubt: 0 Registry-Eintraege: 1 Pfad des Treffers: /as2/inbound Das Speicherformat ist eine **pipe-getrennte Zeile** je Partner: Protokoll, Partner-ID, eigene ID, Host, Port, Pfad, Nachrichtentypen (Klartext, kommagetrennt), Optionen als Zahl. Eine Registry ist damit eine gewöhnliche Textdatei, die sich von Hand pflegen lässt. import std.edi.partner; // Partner definieren var partner: int64 := alloc(EDI_PART_SIZE); poke64(partner + EDI_PART_PROTOCOL, EDI_PART_PROTO_AS2); poke64(partner + EDI_PART_PARTNERID, "ACME-GmbH" as int64); poke64(partner + EDI_PART_PARTNERLEN, 9); poke64(partner + EDI_PART_OURID, "MINE-Corp" as int64); poke64(partner + EDI_PART_OURIDLEN, 9); poke64(partner + EDI_PART_HOST, "as2.acme.com" as int64); poke64(partner + EDI_PART_HOSTLEN, 12); poke64(partner + EDI_PART_PORT, 4080); poke64(partner + EDI_PART_MSGTYPES, EDI_PART_MSG_ORDERS + EDI_PART_MSG_INVOIC); poke64(partner + EDI_PART_OPTIONS, EDI_PART_OPT_SIGN + EDI_PART_OPT_MDN_SYNC); // Prüfen ob Partner INVOIC unterstützt if (EdiPartnerSupports(partner, EDI_PART_MSG_INVOIC) == 1) { PrintLn("INVOIC wird unterstützt"); } free(partner, EDI_PART_SIZE); ---- ===== Imports ===== * ''std.alloc'' ---- ===== Konstanten ===== ==== Transport-Protokolle ==== ^ Konstante ^ Wert ^ Bedeutung ^ | ''EDI_PART_PROTO_AS2'' | 1 | AS2-Transport (HTTPS + MDN) | | ''EDI_PART_PROTO_SFTP'' | 2 | SFTP-Transport | ==== Nachrichtentypen (Bit-Maske) ==== ^ Konstante ^ Bit ^ Nachrichtentyp ^ | ''EDI_PART_MSG_ORDERS'' | 1 | Bestellungen (ORDERS/ORDRSP/ORDCHG) | | ''EDI_PART_MSG_INVOIC'' | 2 | Rechnungen (INVOIC) | | ''EDI_PART_MSG_DESADV'' | 4 | Lieferschein/Wareneingang (DESADV/RECADV) | | ''EDI_PART_MSG_REMADV'' | 8 | Zahlungsavis (REMADV) | | ''EDI_PART_MSG_ORDERS_RSP'' | 16 | Auftragsbestätigungen | | ''EDI_PART_MSG_TRANSPORT'' | 32 | Transportnachrichten (IFTMIN etc.) | | ''EDI_PART_MSG_CUSTOMS'' | 64 | Zollnachrichten (CUSCAR etc.) | | ''EDI_PART_MSG_SEAFREIGHT'' | 128 | Seefrachtdaten (BAPLIE etc.) | ==== AS2-Optionen (Bit-Maske) ==== ^ Konstante ^ Bit ^ Bedeutung ^ | ''EDI_PART_OPT_SIGN'' | 1 | Ausgehende Nachrichten signieren | | ''EDI_PART_OPT_ENCRYPT'' | 2 | Ausgehende Nachrichten verschlüsseln | | ''EDI_PART_OPT_MDN_SYNC'' | 4 | Synchrones MDN (Message Disposition Notification) anfordern | | ''EDI_PART_OPT_COMPRESS'' | 8 | Payload komprimieren | ---- ===== Struct ===== ==== EdiPartner (EDI_PART_SIZE = 96 Bytes) ==== ^ Offset-Konstante ^ Inhalt ^ | ''EDI_PART_PROTOCOL'' | Transportprotokoll (''EDI_PART_PROTO_*'') | | ''EDI_PART_PARTNERID / EDI_PART_PARTNERLEN'' | Partner-ID (AS2-ID oder SFTP-User) | | ''EDI_PART_OURID / EDI_PART_OURIDLEN'' | Eigene ID beim Partner | | ''EDI_PART_HOST / EDI_PART_HOSTLEN'' | Hostname | | ''EDI_PART_PORT'' | TCP-Port (AS2: typisch 4080, SFTP: 22) | | ''EDI_PART_PATH / EDI_PART_PATHLEN'' | URL-Pfad (AS2) oder SFTP-Verzeichnis | | ''EDI_PART_MSGTYPES'' | Bit-Maske der vereinbarten Nachrichtentypen | | ''EDI_PART_OPTIONS'' | Bit-Maske der AS2-Optionen | ---- ===== Funktionen ===== ^ Signatur ^ Beschreibung ^ | ''EdiPartnerValidate(partner: int64): int64'' | Prüft Pflichtfelder (Protokoll, Partner-ID, Host). Gibt 0=ok, 1=Fehler. | | ''EdiPartnerSupports(partner: int64, msgType: int64): int64'' | Prüft ob ein Nachrichtentyp-Bit gesetzt ist. Gibt 1=ja, 0=nein. | | ''EdiPartnerWrite(partner: int64, out: int64, outMax: int64): int64'' | Serialisiert einen Partner als Pipe-delimited-Zeile. Gibt geschriebene Bytes zurück. | | ''EdiPartnerRead(buf: int64, bufLen: int64, partner: int64): int64'' | Deserialisiert eine Partner-Zeile. Gibt 0=ok. | | ''EdiPartnerListWrite(partners: int64, count: int64, out: int64, outMax: int64): int64'' | Schreibt mehrere Partner-Profile (eine Zeile pro Partner). | | ''EdiPartnerListRead(buf: int64, bufLen: int64, partners: int64, maxCount: int64): int64'' | Liest mehrzeilige Partner-Datei; gibt Anzahl der gelesenen Profile. | | ''EdiPartnerFind(partners: int64, count: int64, partnerID: int64, idLen: int64): int64'' | Sucht Partner-ID im Array; gibt Zeiger auf gefundenen EdiPartner oder 0. | ---- ===== Hinweise ===== * **Netzwerk nicht enthalten**: ''std.edi.partner'' liefert nur die Profile. Der eigentliche AS2/SFTP-Transport muss vom Caller implementiert werden. * **Nachrichtentypen kombinieren**: Mehrere Typen werden mit ''+''-Operator kombiniert: ''EDI_PART_MSG_ORDERS + EDI_PART_MSG_INVOIC'' = 3 (Bits 0 und 1 gesetzt). * **ORDERS_RSP vs ORDERS**: Das Bit ''EDI_PART_MSG_ORDERS_RSP'' deckt Auftragsbestätigungen (ORDRSP) ab — separat von ORDERS (16 vs. 1). * **''EdiPartnerFind'' liefert einen Zeiger**, keinen Index: Rückgabe ist die Adresse des Datensatzes im übergebenen Array oder ''0'', wenn die Partner-ID nicht vorkommt. Der Treffer wird direkt mit ''%%peek64(rec + EDI_PART_…)%%'' gelesen. * **''EdiPartnerWrite'' hängt selbst einen Zeilenumbruch an** — für eine Registry-Datei einfach Zeile an Zeile schreiben, ''EdiPartnerListRead'' trennt wieder an ''\n''. * **''EdiPartnerSupports'' prüft ein einzelnes Bit** und liefert 1 oder 0; mehrere Typen werden mit ''+'' kombiniert. ---- ===== Quelldatei ===== ^ Unit ^ Datei ^ | ''std.edi.partner'' | ''std/edi/partner.lyx'' | Letzte Aktualisierung: 2026-08-13 — Beispiel lauffähig gemacht und ausgeführt (lyxc 1.0.17K), Zeilenformat der Registry dokumentiert, ''EdiPartnerFind'' als Zeiger-Rückgabe klargestellt Codebeispiele geprüft: gegen **lyxc 1.2.5C** übersetzt (Prüflauf 2026-09-08 über die gesamte Doku: 574 Vollprogramme, 0 echte Fehler; zusätzlich 5159 Aufrufe gegen die ''pub fn''-Signaturen in ''aurum/std'' gehalten, 0 Abweichungen).