Aufbau der "Header.def"
=======================

-1. Vorwort
    ~~~~~~~
  
Die Beschreibung der Skriptsprache ist nicht nur fr Korrnews, sondern auch
fr CopyIf relevant, da beide dieselbe Engine verwenden, praktische Unter-
schiede im Sprachumfang existieren im Normalfall dann, wenn eine Funktion
nur in einem der Programme Sinn ergibt.

Die weitere Beschreibung ist dabei auf Korrnews zugeschnitten, spezielle
CopyIf-Befehle finden sich in der CopyIf.txt.
    

0. Aufbau
   ~~~~~~

1. Allgemeines
2. Die konkreten Mglichkeiten
2.1 Definition zustzlicher Header, Header ndern oder Header lschen
2.2 "Wildcards", Variablen, Stringfunktionen, Numerische Funktionen
2.3 Bodyheader nutzen / lschen
2.4 Introductions, Lines & Signaturen
2.5 Text-Body bearbeiten
2.6 Optionen umstellen
2.7 Bedingte Anweisungen (If, else, Bedingungen)
2.8 Ablaufsteuerung (Gosub, Goto, Schleifen, Quit, Do Include)
2.9 Interaktion mit dem Nutzer
2.10 Sonderbefehle 
2.11 Debugging
2.12 Multi-Part-Postings/Mails
3. Syntax

1. Allgemeines
   ~~~~~~~~~~~
  
Der exakte Name der Datei ist in den Optionen beliebig einstellbar, die 
Datei mu sich im "Workpath" befinden, was defaultmig das Korrnews-
Verzeichnis ist. Die Auswertung der Header.Def-Anweisungen findet vor 
der Eintragung der "Bodyheader" statt, also der Header, welche im Body 
mit "X-Sowieso=Wert" bzw. "@Sowieso=Wert" am Anfang des Textes definiert 
wurden. Kommentare  sind mglich, die entsprechenden Zeilen mssen mit 
";", "#" oder ":" anfangen. Zeilen, die zu lang werden, knnen mittels "_" am
Zeilenende ber mehrere Zeilen verteilt werden.

Als Begriffsklrung hier noch der Aufbau einer Mail bzw. eines Postings:

------------
I. Header
II. Body
 a) BodyHeader
 b) Introduction
 c) Text
 d) Lines
 e) -- 
 f) Sig
------------

Beispiel:

------------
I.   Message-ID: <3375981e.18152730@news.netway.at>
     Date: Sat, 10 May 1997 16:32:11 GMT
     Newsgroups: de.newusers.questions
     From: habol@netway.at (Hans Boldrino)
     ...
II.
  a) X-Homepage: http://home.knuut.de/tgl/
     X-Virus: Och n
  
  b) Hallo Leute!
  c) Werdegang eines Newbies
  
     Anfang Februar dieses Jahres hat mich (49) die neue Zeit eingeholt.
     Mit einem Internet-Anschlu. Aber der Reihe nach.......
     ... 

  d) Gru und Tschss!  
     Hans
  e) -- 
  f) de.*        Kurzform fr alle de-Hierarchien und -Gruppen
     de.all      Synonym fr de.*
     de.!alt     Kurzform fr de.* auer de.alt
------------

Auer "normalen" Postings gibt es auch noch Multipart-Postings, auf deren 
Behandlung noch mal gesondert in 2.12 eingegangen wird:

------------
I. Header
II. Multi-Part 1
 a) Mime-Header 
 b) BodyHeader
 c) Introduction
 d) Text
 e) Lines
 f) -- 
 g) Sig
III. Multi-Part 2
 a) Mime-Header 
 b) BodyHeader
 c) Introduction
 d) Text
 e) Lines
 f) -- 
 g) Sig
... 
------------

Der Sonderfall, da ein Multi-Part wiederum Multi-Parts enthalten kann, wird 
von Korrnews nicht beachtet, drfte aber eher selten sein.


2. Die konkreten Mglichkeiten
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
   
2.1 Definition zustzlicher Header, Header ndern oder Header lschen
    -----------------------------------------------------------------
   
Die Grundfunktion von Header.def besteht darin, dauerhafte Zusatzheader 
zu nutzen, dazu reicht es, die gewnschten Eintrge einfach in die 
Datei zu schreiben, alternativ ist auch die Anweisung "Set Header Be-
zeichnung = Wert" zulssig und um der Lesbarkeit willen auch 
empfohlen. Sollte der Header bereits existieren, wird der aktuelle
Inhalt durch die Zuweisung an der Originalposition ersetzt, die korrekte 
Kodierung von 8-Bit-Zeichen erledigt Korrnews brigens automatisch.

Per "Delete Header Bezeichnung" oder einer leeren Zuweisung knnen
berflssige Header gelscht werden.

Beispiel:

  Set Header X-Newsreader: Forte Agent 32Bit (mit Hamster und einigen Patches)
  Set Header X-Homepage = http://www.Ich.bin.toll.de
  Delete Header X-Mailreader
  
ersetzt bzw. setzt den Newsreader-Verweis, ergnzt den Header um einen 
Homepage-Verweis und lscht den Header "X-Mailreader", sofern existent.

Die alternative Kurz-Schreibweise sieht so aus:

  X-Newsreader: Forte Agent 32Bit (mit Hamster und einigen Patches)
  X-Homepage: www.Ich.bin.toll.de
  X-Mailreader:
  
In seltenen Fllen sind auch mehrzeilige Header sinnvoll, beispiels-
weise fr "X-Face"-Header. Diese sind folgendermaen definierbar:

 Set raw Header
    X-Face: #0o.eQed-fmU0T,?>{H9_B<%gqE~/fGDJ@[X.]<6obVPh=~9!7-U2x~73]qltjG9F;&/<H|
     z,DF5[lJsBdz<BR*Z+{*7y8G0"wvhXBJ5v^tSB>m"-e^.S`B=3[HG$1tjJXq~XDVXVf!r5}EuobNU)
     MA\WC%"2U8qB3uaW1#U`w9U=`VN/WxZZG^RA+m3&~d"\Vo;dq?eV>WV;Z=6_Q=
 end
 
Die Einrckung ist mglich, da KorrNews die Tiefe der Einrckung der 
ersten Zeile berprft und bei allen weiteren Zeilen dann genau so 
viele Leerzeichen am Anfang krzt.
  
Grundstzlich sollten Header einmalig sein, daher gibt es auch keine Mglich-
keit, gezielt den vierten From-Header zu setzen. Eine Ausnahme davon sind zumindest
die Auslieferungsheader von Mails mit dem "!RCPT TO"-Header.

Um auch damit umgehen zu knnen, bercksichtigt Korrnews multiple Header in 
zwei Fllen:
- Ein "Delete Header abc" lscht im Gegensatz zu "abc:" nicht nur den ersten, 
  sondern alle Inkarnationen des abc-Headers
- Der Befehl "Append Header abc: blubb" lscht keinen bestehenden abc-Header, 
  sondern setzt einen weiteren Header dieses Namens ein. Falls noch kein 
  abc-Header existiert, entspricht es einem "Set Header abc: blubb"

Fr die systematische Abarbeitung stehen inzwischen noch folgender Befehl
zur Verfgung:

  Set [raw] HeaderContent <Zahl> = ...
  
untersttzt von der numerischen Funktion Headerlines und den Stringfunktionen
HeaderName(nr), HeaderContent(Nr) und RawHeaderContent(Nr).
    

2.2 "Wildcards", Variablen, Stringfunktionen
    ----------------------------------------

2.2.1 "Wildcards":

Wildcards sind jeweils in Prozent-Zeichen eingeschlossen und erlauben 
z.B. die Nutzung eines Headers bei der Zuweisung an einen anderen 
Header, eine Sig oder hnliches. Innerhalb von Wildcards kann man auch 
Stringfunktionen nutzen, die anschliessend noch erlutert werden.

Verwendung finden Wildcards bei
- der Zuweisung u.a. von Headern
- Blockanweisungen (Signaturen, Macros etc)

In den meisten anderen Fllen werden "Stringausdrcke" verwendet, welche 
zwar dieselben Mglichkeiten, aber eine IMHO sinnvollere Syntax haben, die 
eigentliche Wildcard-Syntax ist hauptschlich deshalb noch drin, um reine
Headerzuweisungen nicht zu komplizieren. 
                                        
Doch jetzt erst mal konkrete Beispiele...

Um z.B. den originalen X-Newsreader-Header einfach zu ergnzen, ist 
folgende Anweisung mglich:

   X-Newsreader: %Header(X-Newsreader)% (plus Hamster & Korrnews)
   
Oder um einen In-Reply-To-Header fr XNews zu setzen, geht folgendes:   

   X-In-Reply-To: %Last(Header(References))%
   
Die Einzelnen Anweisungen wie Last, Header etc werden weiter unten erlutert, 
die Anweisung "Header" sollte allerdings relativ selbsterklrend sein.

Um in einem Wildcard-Ausdruck trotzdem "echte" Prozentzeichen zu nutzen, 
kann man entweder "raw"-Elemente verwenden oder je Prozentzeichen einfach 
zwei hintereinander schreiben:

  Set Header X-Promille: 25%% je Liter mu sein!
  
Falls einem die Stringausdrcke lieber sind, reicht es, diese mit "%" zu 
umranden, statt

  Set Header X-Egal: Der Autor ist %Header(From)%, behauptet er!
  
kann man genauso gut folgendes schreiben:

  Set Header X-Egal: %"Der Autor ist " + Header(From) + ", behauptet er!"%  


2.2.2 Variablen
               
Variablen sind z.B. dazu nutzbar, 

- einen lngeren/komplizierteren und mehrfach gebrauchten Ausdruck mit weniger
  Tippaufwand nutzen zu knnen
- Zustnde zu merken, um sie spter noch mal in IF-Anweisungen verwenden zu knnen
- Strings stckchenweise zusammensetzen zu knnen, um sie dann komplett z.B. einem
  Header zuzuweisen.

Die Skriptsprache kennt folgende Variablentypen:
  
  String  : Zeichenketten, Lnge praktisch beliebig
  Integer : Ganzzahlen zwischen ca. -4 Milliarden und +4 Milliarden
  Float   : Fliesskommazahlen in doppelter Genauigkeit
  Boolean : Entweder true oder false

Aus Kompatibilittsgrnden knnen String-Variablen ohne spezielle Deklaration 
erzeugt werden, ein einfaches "Set", die bergabe als Parameter oder das Nutzen
in einer For-Schleife erzeugt sie automatisch.

Erzeugt werden Variablen ber den "Var"-Befehl, wobei ggf. auch ein Anfangswert
oder die Gltigkeit angegeben werden kann. Um eine Stringvariable %Subjekt% zu 
erzeugen und mit dem Headerinhalt von  "Subject" vorzufllen, wre folgendes 
einzutippen:

  Var %Subjekt%: String = Header("Subject")

Man kann auch mehrere Variablen und sogar mehrere Variablen verschiedener Typen
auf einmal erzeugen:

  Var %Anz%, %Tr%: Integer, %Summe%, %DS%: Float, %Flag%: Boolean = true

Werden Variablen innerhalb von Subs definiert, gelten diese nur fr die Ausfhrung
der Sub und werden danach automatisch wieder gelscht. Globale Variablen gleichen
Namens werden solange verdeckt, aber nicht gendert. Globale Variablen sind alle
auerhalb von Subs angelegten Variablen bzw. auch Variablen in Subs, wenn diese mit
dem Zusatz "global" angelegt werden:

  Sub Init
     Var global %Subjekt%: String = Header("Hallo") 
     Var global %Fup%: String = Header("FollowUp-To")
     Var global %AnzNGs%: Integer = Count(",", Header(Newsgroups)) + 1
  end sub

Zur Illustration:

  Var %Test%: String
  %Test% = "Hallo"
  Gosub Test
  Do Show Info %Test%
  
  Sub Test
     Var %Test%: Integer = 42
     Do Show Info Str(%Test%)
  end sub

gibt zuerst "42", dann "Hallo" aus.

Konvertierungen zwischen den verschiedenen Variablentypen sind mit entsprechenden
Funktionen (Val, Str, IStr, BoolToStr, ...) mglich, fr die Ausgabe von Zahlen
ist Str praktisch immer erforderlich.

Das normale Setzen oder ndern einer existierenden Variable sieht so aus:

  %Gruppe% = Header(Newsgroups)
  %Programmierer% = "Thomas G. Liesner"
  %SeinVorname% = "Das ist doch der " + Extract("^[^ ]+", %Programmierer%) + "!"
  %ZitierteZeilen% = MatchedLines('^>')
  
Aus Kompatibilittsgrnden kann ein "Set" davor gesetzt werden:  

  Set %ZitierteZeilen% = MatchedLines('^>')
  
Die Nutzung in Wildcards sieht dann so aus:

   X-Der-Programmierer: heisst %Programmierer%!
   
Diese "Wildcard"-Ausdrcke sind nur noch in Headerzuweisungen und Set/end-Blcken
verwendbar, ansonsten entspricht die Skriptsprache einer "normalen" Programmier-
sprache: Variablen knnen berall verwendet werden, wo sie vom Typ passen bzw.
durch Hilfsfunktionen wie Val oder Str passend gemacht werden.

Ein Sonderfall ist aus Kompatibilittsgrnden For, der sowohl String- als auch
numerische Variablen akzeptiert.
  
Richtig interessant werden diese Funktionen aber erst im Zusammenhang mit 
Bedingungen.


2.2.3 Stringfunktionen:

  Konvertierungen:                           
  ----------------
  Lower(...)       wandelt den String in Kleinschrift um
  Upper(...)       wandelt den String in Grossschrift um
  DecodeISO(...)   wandelt einen als ISO-8859-1/qp-kodierten Header in einen 
                   "normalen" String mit 8Bit-Zeichen um.
  8BitTo7Bit(...)  wandelt 8-Bit-Zeichen in Ersatzzeichen innerhalb des ASCII-
                   Codes um. ( => ae,  => ss, ...)
  DosToWin(...)    wandelt DOS-Umlaute (und andere Sonderzeichen) in passende
                   Zeichen im Windowszeichensatz.
  WinToDos(...)    wandelt Windows-Umlaute (und andere Sonderzeichen) in passende
                   Zeichen im DOS-Zeichensatz.
  Str(...,...,...) Wandelt den als ersten Parameter bergebenen numerischen
                   Ausdruck in einen String um. Der zweite optionale numerische
                   Parameter legt die Anzahl der Vorkomma-, der dritte optionale
                   die Anzahl der Nachkommastellen fest, bei Nichtangabe werden
                   zwei NK-Stellen angezeigt.        
  IStr(...)        wandelt den als ersten Parameter bergebenen numerischen
                   Ausdruck in einen String (ohne NK-Stellen) um.
  BoolToStr(Bed.)  Wandelt das Resultat der bergebenen Bedingung in einen String 
                   um und erlaubt somit die direkte Zuweisung einer Bedingung an
                   eine Variable.
  EscRegExp(...)   Wenn man Header u.. als RexExp nutzt, kann man mittels dieser
                   Funktion versehentliche Seiteneffekte vermeiden, da alle
                   speziellen Zeichen ausmaskiert werden ("." => "\." etc.)
  Chr(...)         Wandelt den als ersten Parameter bergebenen numerischen
                   Ausdruck in das zugehrige ASCII/ANSI-Zeichen um.
  FillChar (..., ...)
                   Kopiert den ersten Parameter so oft aneinander, wie als zweiter
                   numerischer Parameter angegeben worden ist, FillChar('+-', 3)
                   wrde somit "+-+-+-" zurckliefern.
  LTrim(...)       Krzt alle Leerzeichen oder Tabs von vorne bis zum ersten anderen
                   Zeichen.
  RTrim(...)       Krzt alle Leerzeichen oder Tabs von hinten bis zum ersten anderen
                   Zeichen.
  Trim(...)        Kombiniert LTrim und RTrim.
  
                   
  String "zerlegen"/"umbauen":
  ---------------------------
  First(...)       sucht das erste Element des Strings heraus. Bei 
                   einem String mit Kommata den Teil vor dem ersten 
                   Komma (z.B. Newsgroups-Header bei Crosspostings), 
                   falls der String mit "<" anfngt und mit ">" endet,
                   holt er das erste "<...>"-Paar heraus (z.B. 
                   References-Header).
  Last(...)        sucht das letzte Element des Strings heraus, qui-
                   valent zu "First"
  Address(...)     bezieht sich - wie auch die folgenden beiden Funktionen -
                   auf Mailadressen i.S. des From- oder Reply-To-Headers.
                   Address versucht, nur die eigentliche Adresse zu extrahieren,
                   aus "Hans Hirni <abc@def.gh>" wird also "abc@def.gh"
  Name(...)        Versucht, den Gesamtnamen zu extrahieren, aus
                   "Hans Hirni <abc@def.gh>" wird also "Hans Hirni"
  FirstName(...)   Versucht, nur den Vornamen zu extrahieren, aus
                   "Hans Hirni <abc@def.gh>" wird also "Hans"
  MakeAddress(...,...) kombiniert den bergebenen Namen und die bergebene Mail-
                   adresse zu einem From/Reply-To/To-kompatiblen Ausdruck iSv
                   "Name <Adresse>" incl. Bercksichtigung von Sonderfllen
                   im Namen (Punkte, Anfhrungsstriche) 
  Extract(...,...) Versucht, den als 1. Parameter angegebenen regulren Ausdruck
                   (entspricht den regulren Ausdrcken im Hamster) im zweiten
                   Parameter zu finden, bei Erfolg liefert er den entsprechenden
                   Teil zurck, sonst einen Leerstring. 
                   Aus Extract("a.*e", "Hallenbau") wrde also "alle"
  Left(..., ...)   Liefert vom ersten Parameter die ersten x Zeichen zurck, das 
                   x steht dabei fr den zweiten Parameter.
  Right(...,...)   Liefert vom ersten Parameter die letzten x Zeichen zurck, das 
                   x steht dabei fr den zweiten Parameter.
  Copy(...,...,...)Liefert vom ersten Parameter ab dem x. Zeichen y Zeichen zurck, 
                   das x steht dabei fr den zweiten und das y fr den dritten Parameter.
  CutLeft(...,...) Entfernt die als zweiten Parameter angegebene Zahl von Zeichen
                   links aus dem als ersten Parameter bergebenen String, 
                   CutLeft("BENGEL", 1) ergibt somit "ENGEL".
  CutRight(...,...)Entfernt die als zweiten Parameter angegebene Zahl von Zeichen
                   rechts aus dem als ersten Parameter bergebenen String, 
                   CutRight("Re: Ups", 4) ergibt somit "Re:".
  Line (...,...)   Der erste Parameter gibt die Zeilennumer an, der zweite enthlt
                   den Text. Als Ergebnis wird die gewnschte Zeile zurckgegeben,
                   bei einer nicht existenten Zeilennummer ein Leerstring. Die 
                   Zhlung beginnt mit 1 und endet mit CountLines(String).
  Replace (...,...,...)
                   Ersetzt im ersten Parameter alle Vorkommen des zweiten Parameters
                   (interpretiert als RexExp!) mit dem dritten Parameter.
  WordWrap (...,...,...)
                   Liefert den ggf. umgebrochenen ersten Parameter zurck, der 
                   zweite numerische Parameter gibt dabei die maximal erlaubte
                   Zeilenzahl zurck, der dritte Parameter gibt den ab der zweiten
                   Zeile zu verwendenden Einzug (als String) an.

  Posting-spezifisches:
  ---------------------
  Header(...)      liefert den Inhalt des ber seinen Namen angesprochenen Headers
  HeaderName(Nr)   liefert den Namen des ber seine Position angesprochenen Headers
  HeaderContent(Nr)liefert den Inhalt des ber seine Position angesprochenen Headers
  RawHeaderContent(Nr)
                   liefert den ggf. noch kodierten Inhalt des ber seine Position 
                   angesprochenen Headers
  BodyHeader(...)  liefert den Wert des angegebenen BodyHeaders, siehe 
                   nchsten Punkt.
  Full [raw] Header [without Headername1, ...]
                   Ohne Parameter und z.Z. nur in Bedingungen sinnvoll nutzbar,
                   liefert den gesamten Header als Zeichenkette zurck. Um bestimmte
                   Header auszuschliessen, kann der "without"-Zusatz genutzt werden.
  Full [raw] Body  Ohne Parameter und z.Z. nur in Bedingungen sinnvoll nutzbar,
                   liefert den gesamten Textbody abzgl. der Signatur zurck.
  Full [raw] Sig[nature] 
                   Ohne Parameter und z.Z. nur in Bedingungen sinnvoll nutzbar,
                   liefert die komplette Signatur als String zurck
  Full Article/Posting/Mail               
                   liefert den gesamten Text im "raw"-Format als String zurck
  Path             liefert den Pfad, in dem Korrnews nach Postings sucht                
  Filename         liefert den Dateinamen des aktuell bearbeiteten Postings
  Partfilename     liefert bei Multi-Part-Postings den Dateinamen fr das 
                   Attachment, sofern ein entsprechender MIME-Part aktiv ist.
  Bodyline(...)    liefert den Inhalt der x. Zeile des Textbodys, dabei mu als
                   Parameter eine Zahl bzw. ein numerischer Ausdruck angegeben
                   werden. Nicht vorhandene Zeilen liefern einen Leerstring zurck.
  
  Externe Daten:
  --------------       
  ReadIniStr( )    liest aus einer INI-Datei, als Parameter werden der Dateiname, 
                   der Abschnitt, der Key und ein Standardwert (der benutzt wird,
                   wenn der Key nicht existiert) bentigt.                                
  GetDateTime(...) erlaubt das Auslesen der aktuellen Zeit bzw. des aktuellen Datums. 
                   Folgende Platzhalter sind im Formatstring erlaubt: 
                   
                   c         Zeigt das Datum im Kurzformat der Windowseinstellungen
                             und die Zeit im Langformat der Windowseinstellungen an.
                   d         Zeigt den Tag als Zahl ohne fhrende Null an (1-31).
                   dd        Zeigt den Tag als Zahl mit fhrender Null an (1-31).
                   ddd       Zeigt den Tag als Abkrzung an und verwendet dabei fr 
                             die Wahl der Abkrzungen die Windowseinstellungen.
                   dddd      Zeigt den Tag als vollstndigen Namen an, auch hier werden
                             die aktuellen Windowseinstellungen genutzt.
                   ddddd     Zeigt das Datum im Kurzformat der Windowseinstellungen an.
                   dddddd    Zeigt das Datum im Langformat der Windowseinstellungen an.
                   m         Zeigt den Monat als Zahl ohne fhrende Null an (1-12). 
                             Folgt der Bezeichner m direkt nach der Angabe h oder hh, 
                             wird statt des Monats die Minute angezeigt.
                   mm        Zeigt den Monat als Zahl mit fhrender Null an (01-12). 
                             Folgt der Bezeichner mm direkt nach der Angabe h oder hh, 
                             wird statt des Monats die Minute angezeigt.
                   mmm       Zeigt den Monat als Abkrzung an und verwendet dabei die 
                             Windowseinstellungen fr den Bezeichner.
                   mmmm      Zeigt den Monat als vollstndigen Namen an und verwendet 
                             dabei die Windowseinstellungen fr den Bezeichner.
                   yy        Zeigt das Jahr als zweistellige Zahl an (00-99).
                   yyyy      Zeigt das Jahr als vierstellige Zahl an (0000-9999).
                   h         Zeigt die Stunde ohne fhrende Null an (0-23).
                   hh        Zeigt die Stunde mit fhrender Null an (00-23).
                   n         Zeigt die Minute ohne fhrende Null an (0-59).
                   nn        Zeigt die Minute mit fhrender Null an (00-59).
                   s         Zeigt die Sekunde ohne fhrende Null an (0-59).
                   ss        Zeigt die Sekunde mit fhrender Null an (00-59).
                   z         Zeigt die Millisekunde ohne fhrende Nullen an (0-999).
                   zzz       Zeigt die Millisekunde mit fhrenden Nullen an (000-999).
                   t         Zeigt die Zeit im Kurzformat der Windowseinstellungen an.
                   tt        Zeigt die Zeit im Langformat der Windowseinstellungen an.
                   am/pm     Verwendet das 12-Stunden-Format fr den fhrenden Bezeichner 
                             h oder hh und zeigt 'am' fr Zeitangaben vor 12 Uhr mittags 
                             oder 'pm' fr Zeitangaben nach 12 Uhr mittags an. Der Bezeich-
                             ner am/pm kann in Gro-, Klein- oder gemischter Schreibweise 
                             angegeben werden und wird dementsprechend angezeigt.
                   a/p       Verwendet das 12-Stunden-Format fr den fhrenden Bezeichner h
                             oder hh und zeigt 'a' fr Zeitangaben vor 12 Uhr mittags oder 
                             'p' fr Zeitangaben nach 12 Uhr mittags an. Der Bezeichner a/p 
                             kann in Gro-, Klein- oder gemischter Schreibweise angegeben 
                             werden und wird dementsprechend angezeigt.
                   ampm      Verwendet das 12-Stunden-Format fr den fhrenden Bezeichner h 
                             oder hh und zeigt statt am/pm die in den Windowseinstellungen
                             vorgesehenen Krzel.
                   /         Verwendet das in den Windowseinstellungen vorgesehene Datums-
                             trennzeichen.
                   :         Verwendet das in den Windowseinstellungen vorgeshene Zeittrenn-
                             zeichen.
                   'xx'/"xx" In halbe oder ganze Anfhrungszeichen eingeschlossene Zeichen 
                             wirken sich nicht auf die Formatierung aus und werden wie 
                             eingegeben angezeigt.
                   
                   Beispiel: GetDateTime("dd.mm.yyyy") am 1.4.2000 => "01.04.2000"
  
  Konstanten:
  -----------
  CRLF             Entspricht einem Zeilenumbruch
  TAB              Entspricht dem Tabulator-Zeichen
  SigDel           Entspricht dem Signaturabtrenner "-- "
  
  Benutzereingaben:
  -----------------
  Input (.,.,.)    erlaubt die Eingabe eines Strings per Input-Box. Als Parameter 
                   mu der Dialogtitel, eine Eingabeaufforderung und der Vorgabe-
                   wert bergeben werden.                      
  
  Weiteres:
  ---------
  Version          gibt die aktuelle Versionsnummer zurck, funktioniert aber erst ab 
                   V2.86 
  
2.2.4 Numerische Funktionen:

Bei verschiedenen Stringfunktionen oder auch bei im weiteren erluterten
Befehlen sind numerische Parameter erlaubt. Diese knnen durchaus komplexer
sein.

Zum einen sind natrlich reine Konstanten mglich: 

   Delete Bodylines from 10 to 20
   
Aber auch Berechnungen:

   If Bodylines > 0 then Do show Info 'Durchschnittliche Zeichen pro Zeile: ' + _
      Str( Len( Full Body ) / Bodylines , 5, 2 ) 

Und natrlich numerische Variablen:

   Var %SubjLen%: Integer = Len(header(Subject))
   If %SubjLen% > 100 then Do Show Info "A bisserl langer Betreff..."
      
Berechnungen knnen auf die Grundrechenarten, Klammerungen, die in der Syntax 
erwhnten normalen Rechenfunktionen, die Potenzfunktion (^) und folgende
Zusatzfunktionen zurckgreifen:

  Allgemeine Funktionen:
  ====================== 
  Count (String, String)   Gibt die Anzahl der Vorkommen vom ersten String im
                           zweiten String zurck, bei berlappungen wird jedes
                           Teilstck gezhlt, Beispiel: Count("elle", 
                           "ellellellellelle") ergibt 5 und nicht 3.
  Ord (String)             Gibt den ASCII-Wert des ersten Zeichens des Strings zurck, 
                           0 bei einem leeren String.
  Pos (String, String)     Gibt die Position des ersten im zweiten String an, 0, falls
                           der String nicht im anderen vorkommt.
  Len[gth] (String)        Gibt die Lnge eines Strings (=Zeichenzahl) zurck
  Val (String)             Wandelt einen Stringausdruck in eine Zahl, auch 
                           Formeln erlaubt.
  Trunc (Zahl)             Gibt die Zahl ohne Nachkommastellen zurck.
  Random (Zahl)            Gibt eine ganzzahlige Zufallszahl zwischen 0 und
                           Zahl-1 zurck.

  Mail/News-spezifische Funktionen:
  =================================
  PartCount                Gibt die Anzahl der MIME-Parts zurck, bei einem
                           normalen Posting ist der Rckwert 1.
  MatchedLines (RegExp)    Gibt die Anzahl der Zeilen zurck, die dem 
                           angegebenen RegExp entsprechen.
  Bodylines                Gibt die Anzahl der Zeilen im Textbody zurck
  Headerlines              Gibt die Anzahl der Zeilen im Header zurck
  Siglines                 Gibt die Anzahl der Zeilen in der Signatur zurck
  Introlines               Gibt die Anzahl der Zeilen im Intro zurck 
  CountLines (String)      Gibt die Anzahl der Zeilen im bergebenen String zurck
  NextMatchedLine (Zahl, RexExp)
                           Gibt die erste Zeilennummer zurck, in der die RegExp 
                           gefunden wird, gesucht wird ab der als ersten Parameter
                           bergebenen Zeilennummer.
                            
                           

2.3. Bodyheader nutzen / lschen
     ---------------------------
     
Bodyheader sind die im Posting selber definierten Pseudoheader, welche 
Korrnews nach dem Durchlauf der Header.def automatisch in den 
eigentlichen Header bernimmt und im Body lscht. Es gibt allerdings 
durchaus Verwendungsmglichkeiten innerhalb der Header.def.

Zum einen sind Zuweisungen mglich, innerhalb von Wildcards ist ein 
Bodyheader ber das Konstrukt

  %BodyHeader(Bezeichnung)% 
  
erreichbar und somit sowohl Variablen als auch "richtigen" Headern 
zuweisbar. Die Hauptmglichkeit drfte aber auch die Mglichkeit sein, 
die Header.def zu steuern. Ein kleiner Vorgriff auf den If-Befehl macht 
das hoffentlich deutlicher:

  Var %NG%: String = Header("Newsgroups")
  Var %B-Fup%: String = BodyHeader(Fup)
  If %B-Fup%>"" 
     If Not (%NG% contains %B-FUP%)
        Set Header Newsgroups = %NG%,%B-FUP%
        %NG%=Header(Newsgroups)
     endif
     Set Header FollowUp-To: %B-Fup%
     Delete BodyHeader Fup
  endif
  
Dieser Block reagiert auf einen gesetzten Bodyheader namens "Fup" und 
setzt entsprechend den Header "FollowUp-To" und ergnzt ggf. noch den 
"Newsgroups"-Header um die gesetzte Gruppe.

Um Bodyheader, die eigentlich nur temporre Funktion zu haben, nicht 
wirklich zu verschicken, dient die Anweisung

  Delete Bodyheader Bezeichnung
  
welche verhindert, da die sonst bliche bertragung in den eigent-
lichen Header erfolgt.


2.4 Introductions, Lines & Signaturen
    ---------------------------------

- Introductions sind zustzliche Zeilen, die zu Anfang des Postings 
  eingefgt werden,
- Lines sind zustzliche Zeilen, die zwischen Text und Signatur 
  eingefgt bzw. ans Textende angefgt werden
- und die Signatur wiederum ist ein Textblock am Ende, welcher mittels
  Trenner ("-- ") optisch vom Rest abgetrennt wird.

Die Syntax ist in allen Fllen gleich, die einzige Besonderheit weist die 
Signatur auf: Bei Zuweisungen berprft Korrnews automatisch, ob in dem
Abschnitt oder der Datei mehrere Signaturen enthalten sind (durch Test auf
SigTrenner incl. Sigtrenner ohne Leerzeichen) und whlt - sofern mehr
als eine zur Verfgung steht - zufllig eine aus.

Bei Zuweisungen gibt es zwei grundstzliche Alternativen: Neusetzen oder 
Anhngen, die Anweisungen heissen entsprechend "Set" und "Append".

Zudem gibt es drei Mglichkeiten, den Inhalt zu bergeben:

Entweder in der Header.def selber als Mehrzeiler:

  ( Set | Append ) [raw] ( Sig[nature] | Line[s] | Introduction )
    Zeile #1
    Zeile #2
    Zeile #3
    Zeile #4
  end

Beispiele:

  If Header(Newsgroups) contains "test"
    Set Intro 
       ignore - noreply - ignore
       
    end     
  endif  
  
  Set Sig
     Name: Unbekannt
     Alter: Habe ich
     Gru: Tschss
  end

oder in der Header.def als Einzeiler:

  Set Signature = "Meine Signatur ist kurz"
  Append Sig = "(Oder doch nicht?)"
  
oder in einer externen Datei, so da in der Header.def nur noch ein 
Verweis steht:

  Set Sig from "sigs.txt"
  Set Lines from "Gruss.txt"
  
Sofern die Sig-Datei oder der Sig-Block "--"-Zeilen enthlt, interpretiert
Korrnews dies so, da dort mehrere Sigs enthalten sind. Im Normalfall
sucht sich Korrnews dann per Zufall eine heraus, um gezielt eine Sig
zu verwenden, ist folgende Syntax vorgesehen:

  Set Sig #12 from "many_sigs.txt"           
  
bzw.
                         
  If BodyHeader(X-Sigfile) > ""
     Set Sig # Val("0"+BodyHeader(X-SigNr)) from Bodyheader(X-Sigfile)
  endif   
  
Im zweiten Fall wrde - sofern der Bodyheader X-Sigfile gesetzt wurde - 
ein mglicherweise gesetzter Bodyheader X-SigNr ausgewertet, eine Null 
davorgesetzt, damit auch ein fehlender Bodyheader keinen Fehler verursacht, 
und das Zusammengesetze in eine Zahl konvertiert.

Mit einem
                                                 
 X-Sigfile: jokes.txt                                                
 X-SigNr: 3
 
am Anfang eines Posting wrde man mit obiger Anweisung die dritte Signatur
aus der angegebenen "jokes.txt" durch Korrnews ans Posting angehngt.

Bitte beachten Sie bzgl. der einzelnen Signaturen das Netiquette-Limit 
von 4 Zeilen je max. 80 Zeichen!
           
Korrnews achtet brigens darauf, da Lines, Intros und Sigs nicht bei
mehreren Durchlufen mehrfach drangehngt werden, indem er die jeweiligen
Zeilen mit dem einzusetzenden Text vergleicht und bei Identitt keine
nderungen vornimmt.

Mit 

  Delete Sig
  Delete Intro
  Delete Lines
  
knnen Zuweisungen auch noch mal zurckgenommen werden. Fr Abfragen gibt
es "HasSig" und fr spezielle vergleiche gibt es noch ChangedSig, ChangedIntro, 
ChangedLines und  Siglines und Introlines, wenn man die Zeilenzahl der
Abschnitte wissen mchte.


2.5 Text-Body bearbeiten
    -------------------- 

Zur nderung des eigentlichen Textes dienen verschiedene Befehle:

   Do Replace ( first | last | all ) <regexp> with <Stringausdruck>
        [ in ( Header | Header2 | Intro | Body | Lines | Sig  | %Variable% ) ]
        [ from <Zeilennummer> ] [ to <Zeilennummer> ]
   
Hiermit kann gezielt im Text gendert werden, der Suchausdruck ist
dabei ein regulrer Ausdruck wie auch im Hamster oft zu finden.

Beispiel: Mit 

  Do Replace first "<news:<" "<news:"
  
lt sich eine Einleitung a la "Frank Mller schrieb in <news:<dslklkdslds@dlklksd>:"
nach "Frank Mller schrieb in <news:dslklkdslds@dlklksd>:" ndern.

Um den Bereich einzugrenzen, ist die Eingabe der ersten und/oder letzten untersuchten
Textzeile bestimmbar - wobei QP-kodierte Texte umgebrochene Teilzeilen nicht als eigene
Zeilen mitzhlen.                         

Falls nicht der Textbody durchsucht werden soll, kann die Suche auch alternativ ber 
Lines, Signatur oder den aktuell eingestellten Einleitungsblock gehen:

  Set Sig 
    #  Einrckung soll von Korrnews    
    #    nicht gendert
    #       werden
    #         !!
  end
  Do Replace all "^#" with "" in Sig
  
Ein Sonderfall ist noch "Do Replace ... in %Variable%": Mit dieser Variante sind
auch first/last-Ersetzungen in einer Variablen mglich, welche mit der Stringfunktion
Replace nicht machbar sind. Allerdings werden from/to-Angaben nicht beachtet.  
  
Eine hnliche Funktion ist dann noch der Befehl

  Set Macro <Stringausdruck>
    ...
  end
  
Falls man z.B. einen automatischen Gru haben mchte, kann man folgendes
verwenden:

  Set Macro "#gruss#"
    
    Tschsschen,
    Euer Paule!
  end

Wenn dann im Posting

  Das war's eigentlich schon.      
  #gruss#
  
vorkommt, wird daraus mit obigem Befehl:

  Das war's eigentlich schon.
  
  Tschsschen,
  Euer Paule! 
  
Ein anderes naheliegendes Macro wre auch #spoiler#, man sollte nur darauf 
achten, da nicht versehentlich ungewollte Ersetzungen passieren, weil der
gewhlte Macro-Name auch mal so einzeln in einer Zeile auftauchen knnte.
             
Fr besonders spezielle Flle gibt es dann noch:

  Set Bodyline(ZeilenNr) = ...

zum ndern von bestimmen Zeilen,

  Delete Bodylines xx to xx
 
bzw.

  Delete Bodyline xx 
  
zum Lschen bestimmter Zeilen und

  Insert Bodyline ZeilenNr = ...
  
zum Einschieben von einzelnen Zeilen.

  Delete between ( first | last ) <RegExp>, <RegExp>, <Bedingung> [, <Stringausdruck>]
  
lscht den ersten bzw. letzten Textblock, dessen Anfangszeile dem ersten und dessen 
Endzeile dem zweiten RegExp-Ausdruck entspricht. Falls der erste Suchausdruck leer 
ist und der erste passende Textblock gelscht werden soll, wird alles bis zur zweiten 
RegExp gelscht, ist der zweite Suchausdruck leer und soll der letzte passende Textblock
gelscht werden, wird alles ab dem ersten RegExp gelscht. Die Bedingung bestimmt, 
ob die Anfangs- und Endzeile des Blockes mitgelscht werden soll und der optionale letzte 
Stringausdruck wird an die Stelle des ersetzten Ausdrucks eingefgt.

Diese Funktion ist zum Beispiel dazu brauchbar, Mailinglisten von Werbeblcken
zu befreien.
  

2.6 Optionen umstellen
    ------------------
    
Mit dem Befehl 

  Set Option Bezeichnung = "Wert"
  
knnen jederzeit die INI-Optionen fr den aktuellen Korrnews-Lauf 
temporr (!) gendert werden, dauerhafte nderungen sind damit 
im Gegensatz zu "Do Write IniStr" nicht mglich. 

Wenn man z.B. normalerweise in den Optionen eine Signatur-Datei akti-
viert hat, diese aber in einer bestimmten Gruppe nicht nutzen will, 
reicht folgende Anweisung:

 Set Option SigFile = 
 
Die Namen der Option sind zum einen in der HTML-Hilfe hinterlegt, 
zum anderen auch aus der Korrnews.ini entnehmbar. 

Hinweis: Die Namen der Optionen knnen sich im Laufe der zuknftigen 
Korrnews-Versionen  durchaus ndern. Prinzipiell bin ich zwar fr 
Konstanz, aber Garantien kann es nicht geben.


2.7 Bedingte Anweisungen
    --------------------

2.7.1 If / else / elseif / endif

Um flexiblere Mglichkeiten zu bieten, gibt es die Mglichkeit, Zeilen 
von Bedingungen abhngig zu machen. Die Grundform lautet:

 If <Bedingung> [then]
  ...
 [else if <Bedingung>
  ...]
 [else
  ...]
 endif
 
Der ElseIf- und der Else-Zweig sind optional, fr die "..." lassen sich 
beliebige Anweisungen einsetzen, der bersichtlichkeit halber sind Ein-
rckungen empfehlenswert. If-Bedingungen lassen sich auch schachteln, 
bis zu 15 Ebenen sind erlaubt.

Falls man nur einen Befehl ausfhren mchte, geht auch die Kurzvariante:

 If <Bedingung> then <Befehl>

Zuerst einige konkrete Beispiele:

Beheben des Agent-Bugs bzgl Anfhrungsstriche um den Namen im From:

 If Header(From) equals 'Thomas G. Liesner <tgl@gmx.de>'
   From: "Thomas G. Liesner" <tgl@gmx.de>
 endif
 
 macht aus 
   From: Thomas G. Liesner <tgl@gmx.de>
 folgendes:  
   From: "Thomas G. Liesner" <tgl@gmx.de>
 

berflssiges Reply-To lschen:

 If Header(From) contains Header(Reply-To)
   Delete Header Reply-To
 endif
 
 
In Testgruppen ein spezielles Reply-To setzen:

 If Header "Newsgroups" contains "test"
   ; fr <FQDN> bitte einen eigenen FQDN eingeben.
   Reply-To=botanswer@<FQDN> 
 endif

nderungen nur, wenn bestimmter Body-Header nicht verwendet:

 If BodyHeader "HeaderOk" Is Empty
    ...
 else
    ; Spuren verwischen
    Delete BodyHeader HeaderOk
 endif
 
Gruppenabhngiges Reply-To setzen:

 ; Nur, wenn auch richtige Mailadresse:
 If Lower(Header(From)) contains Lower("TGL")
  If Not Header "Newsgroups" is empty
    ; fr <FQDN> bitte einen eigenen FQDN eingeben.
    Reply-To=Answer.from.%First(Header(Newsgroups))@<FQDN>
  else
    Reply-To=Mailanswer@<FQDN>
  endif
 endif
 
In bestimmten Gruppen die Speicherung in deja.com vermeiden:
         
 Var %NG%: String = Header(Newsgroups)        
 If ("liebesakt" IN %NG%) or (%NG% contains "sex") then X-No-Archive: Yes
 
In bestimmten Gruppen besonders sicherheitsbewusst wirken:

 If Header(Newsgroups) = "de.soc.zensur"
   X-No-Archive: Yes
   X-PGP: ...
 endif
 
dnq-Sig-Projekt untersttzen, in anderen Gruppen Zufallssprche:

 If Not HasSignature and Header(Newsgroups)="de.newusers.questions"
   Set Signature from "dnq-proj.txt"
 elseIf not HasSignature
   Set Signature from "my-sigs.txt"
 endif
 
Hinweis oberhalb der Sig, wenn man ein FollowUp-To gesetzt hat:

 If Header "FollowUp-To" > ""
   If Header "Newsgroups" contains ","
     Set Lines 
        X-Post ber %Str(Count(',', Header(Newsgroups))+1)% Gruppen, FollowUp-To %Header(FollowUp-To)%
     end
   else
     Set Lines 
        FollowUp-To %Header(FollowUp-To)%
     end
   endif
 endif


2.7.2 Boolesche Funktionen

Die komplette bersicht findet sich in der Syntaxbeschreibung am Ende, hier 
eine Liste der booleschen Sonderfunktionen:

  Konstanten
  ----------
  True                     Steht fr "Ja"/"Wahr"
  False                    Steht fr "Nein"/"Falsch"

  Postingeigenschaften
  --------------------
  HasSig[nature]           Liefert "True", wenn eine Signatur existiert bzw. 
                           inzwischen per Skript angehngt wurde
  Has8BitChars             Liefert "True", wenn im Posting Zeichen mit gesetztem
                           8. Bit vorkommen wie unkodierte Umlaute etc.
  PartTyp is <Typ>         Liefert "True", wenn der Typ des aktuellen MIME-Parts gleich 
                           dem <Typ> ist. Fr <Typ> sind folgende Bezeichner erlaubt: 
                           Unknown, Text, Plaintext, UnknownText, HTML, Binary, 
                           Application, Audio, Image, Video. 
  PartEncoding is <Typ>    Liefert "True", wenn das Encoding des aktuellen MIME-Parts 
                           gleich dem <Typ> ist. Fr <Typ> sind folgende Bezeichner 
                           erlaubt: quoted-printable, qp, 8bit, 8-bit, 8 bit, base64,
                           ascii, 7-bit, 7bit, 7 bit, unknown.  
  
  Statusabfragen
  --------------
  Changed                  Gibt "True" zurck, wenn die bisherigen Skriptanwei-
                           sungen nderungen am Posting bewirkt haben.
  ChangedLines             Gibt "True" zurck, wenn durch "Set/Append Lines" 
                           angehngte Zeilen definiert wurden.
  ChangedSig[nature]       Gibt "True" zurck, wenn Sig-Anweisungen ausgefhrt
                           worden sind.
  ChangedIntro[duction]    Gibt "True" zurck, wenn die Einleitung per Set/Append
                           Intro gesetzt wurde.
  VarExists(Variablenname) Gibt "True" zurck, wenn die Variable angelegt worden
                           ist.                           
  
  Benutzersteuerung
  -----------------
  Ask (..., ...)           Gibt "True" zurck, wenn der Benutzer den Ja-Button
                           der angezeigten Messagebox besttigt. Als Parameter mu
                           der Text angegeben werden, der Titel kann zustzlich
                           bestimmt werden.
  Abort                    Gibt "True" zurck, wenn der Benutzer den Abbruch-Button
                           der angezeigten Messagebox besttigt. Als Parameter mu
                           der Text angegeben werden, der Titel kann zustzlich
                           bestimmt werden.

  Sonstiges
  ---------
  FileExists (...)         Testet, ob der angegebene Dateiname existiert. Sofern kein
                           Pfad angegeben ist, testet KN im aktuellen Verzeichnis.
  
  Konvertierung
  -------------
  StrToBool                konvertiert einen String in einen boolschen Wert.
  
Das Ergebnis einer Bedingung kann bei Bedarf einer boolschen Variable zugewiesen
werden: 

  Var %LongHeader% : boolean = HeaderLines > 30


2.8 Ablaufsteuerung (Gosub, Goto, Quit, Do Include)
    -----------------------------------------------

Um Funktionsblcke o.. auslagern zu knnen, gibt es folgendes Statement:

  Do Include <Dateiname>

Diese Anweisungen werden beim Laden der Skriptdatei bereits ausgefhrt, daher
funktioniert auch die Anweisung:

  Set Sig
    Do Include "sigs.txt"
  end                    
  
Der Inhalt der Datei wird genauso behandelt wie die "originalen" Zeilen des 
Skripts.                   
Der Dateiname wird - sofern kein absoluter Pfad angegeben - relativ zum 
Arbeitsverzeichnis geladen.

Mit 

  Gosub <Sub-name>
  
ist ein Sprung in die gleichnamige "Sub" mglich. Beispiel:

  Gosub Teil1
  Gosub Teil2
  Quit
  
  Sub Teil1
   ...
  endsub
  
  Sub Teil2
   ...
  endsub 
   
Um Parameter nutzen zu knnen, kann folgende Syntax verwendet werden:
Nach

  Gosub Combine "Dies und", "das", %Ergebnis%
  Gosub Combine %Ergebnis%, "wnsche ich mir", %Ergebnis%
  
  Sub Combine (%eins%: String, %zwei%: String, Var %Zusammen%: String)
     %Zusammen% = %eins% + " " + %zwei%
  endsub                                   
  
wrde in der Variable %Ergebnis% der Wert "Dies und das wnsche ich mir" stehen. 
Das "Var" erlaubt das ndern der ursprnglichen Variable. Bei Nicht-Var-Parametern
sind sowohl Konstanten als auch Stringfunktionen oder Variablen erlaubt.

Als Parameter sind dabei alle Variablentypen zulssig, bei Nicht-Angabe des 
Types wird der Parameter als Stringparameter behandelt.

Um einen Befehl mehrfach auszufhren, gibt es diverse Schleifentypen:

Das For / Next-Statement in zwei Varianten:

   For %i% = 1 to 10
      ....
   Next
   
und

   For %i% = 1 to 10 do ...   

Anfangs- und Endwert knnen dabei auch berechnet werden und mit "Step" kann die 
Schrittweite beliebig gewhlt werden:

  Var %Countdown%: Integer
  For %Countdown% = 10 to 1 step -1
     ...
  Next
  
Die Variable mu vom Typ Integer, Float oder String sein, letzteres ist aus
Kompatibilittsgrnden drin. Sollte die Variable vorher nicht per "Var"
definiert worden sein, wird sie als Stringvariable erzeugt.

Das While/Wend-Statement, welches ggf. gar nicht durchlaufen wird, wenn die 
Bedingung von Anfang an nicht erfllt wird:

  While <Bedingungen>
     ...
  Wend
  
Das Repeat/Until-Statement, welches zumindest einen Durchlauf hat, da die Bedingung
erst am Ende getestet wird. Bei Erfllung der Bedingung bricht die Schleife ab:

  Repeat
     ...
  Until <Bedingung>
  
Und die Endlosschleife, welche nur im Zusammenhang mit einem Abbruchbefehl Sinn macht:

  Endless
     ...
     If <Bedingung> then <Abbruchbefehle>
     ...
  Loop
  
Als Abbruchbefehle stehen Goto - welches ggf. auch mehrere Schleifen auf einmal verlassen 
kann - , continue (welches bei dieser Schleife allerdings nicht sehr sinnvoll sein drfte) 
und break zur Verfgung:

   ; Aus "@" ein " at " machen
   Var %i%: Integer, %s%: String = "Hallo@Erde"
   Endless
      %i% = Pos("@", %s%)
      If %i% = 0 then break
      %s% = Left(%s%, %i%-1)+" at "+Copy(%s%, %i%+1, Len(%s%)-%i%)
   Loop
   Do Show Info %s%

   ; Nur eigenen Text berprfen...
   Var %i%: Integer
   For %i% = 1 to Bodylines
      If Bodyline(%i%) begins with ">" then Continue
      ...
   Next
 
   Repeat
     :Hauptschleife
     ...
     While ...
        ...
        For ...
           ...
           If ... then Goto Hauptschleife
           If ... then Goto NotAus
           ...
        Next
        ...
     Wend
     ...
   Until ...
   :NotAus

Goto kann auch auerhalb von Schleifen verwendet werden, um bestimmte Teile zu
berspringen, im Normalfall fhrt der Verzicht auf Goto aber zu lesbareren
Skripten. Die Sprungziele von Goto mssen mit einem Doppelpunkt eingeleitet
werden und sollten jeweils einmalig sein, da KN ansonsten immer auf den ersten
passenden Label springen wrde.

Schleifen knnen - wie im letzten Beispiel gezeigt - natrlich auch beliebig geschachtelt 
werden, allerdings ist die intensive Nutzung von Schleifen aus Performancegrnden 
heraus nicht empfehlenswert, da das Interpretieren der Skriptsprache lngst nicht 
so schnell ist wie eine echte Programmiersprache.

Der Befehl "Quit" beendet das Skript und ist bei Verwendung von Subs ntig,
da ansonsten die Fehlermeldung "Unbekannter Befehl 'Sub ...'" kommen wrde.


2.9 Interaktion mit dem Benutzer
    ----------------------------
    
Die Funktion 

  Do Show Info <Text> [, <berschrift>]
  
erlaubt die Ausgabe einer Message-Box, erst nach Besttigung wird das Skript
fortgesetzt. Mit

  Do Show Info "Ein bischen exzessiv gequoted, oder?", "Nur ein Hinweis..."
  
wird z.B. auf ein etwas bertriebenes Zitieren hingewiesen.

Akustische Hinweise sind mit

  Do Play Wave "Troete.wav"
  
mglich. Falls erst nach Abspielen des Wavs weitergemacht werden soll, mu
einfach "and wait" angehngt werden:

  Do Play Wave "Troete.wav" and wait

Um auf Benutzereingaben zu reagieren, ist zum einen folgendes nutzbar:

  If Ask (<Frage> [, <berschrift]) then ...
  
Beispiel:

  If Not HasSig
     If Ask ('Soll noch eine Zufallssig an "'+Header(Subject)+'" gehngt werden?', 'Sig-loses Posting!') 
        Set Sig from "ManySigs.txt"
     endif
  endif  
  
oder 

  If ....
     If Ask ("Das Posting sollte so nicht abgeschickt werden, Endung auf 'not' ndern?")
        Set Option DontChangeRenameToExtension = not
     endif
  endif  

oder auch die "dringendere" Variante mit umgekehrtem Vorzeichen:

  If Abort (<Frage> [, <berschrift]) then ...
  
Beispiel:

  If HasSig
     If Not Abort('Die bestehende Signatur wird jetzt berschrieben...')
        Set Sig from "ManySigs.txt"
     endif
  endif  
  
oder 

  If Abort('Skript fortfhren', 'Experimentelle Header') then Quit

Die Eingabe von Texten mittels "Input" wurde bereits unter String-Funktionen erwhnt,
eine Beispielanwendung wre:

  If Header(newsgroups) ends with ".0d" then
    Set Header Newsgroups: %Input(Header(Subject), 'Gruppe korrigieren?', Header(newsgroups))%
  endif
  
Hier hat der Benutzer noch die Mglichkeit, ein versehentlich in de.alt.0d gesendetes Posting
noch in eine sinnvollere Gruppe umzuleiten.

   
2.10 Sonderbefehle
     -------------

Folgende Befehle passen nicht in die bisherigen Menpunkte und sind somit
hier gesammlt aufgefhrt:

  Do ( Exec | Run ) [ and wait ] <Stringausdruck> [ , <Stringausdruck> ]

Hiermit knnen externe Programme synchron (das Skript pausiert bis zum 
Programmende) oder asynchron (das Skript luft parallel weiter) aufgerufen werden, 
wobei zustzlich noch Parameter bergeben werden drfen:

  Do Run "Notepad.exe", "header.def"
 
wrde z.B. die "header.def" in den Editor laden. Als dritter Parameter kann der
Windows-Aufrufmodus gendert werden, die mglichen Werte stehen in der Gesamt-
bersicht am Ende und entsprechen den internen Namen von Windows.

  Do ( Open | Print ) <Stringausdruck>
  
ist ein Spezialfall, der das angegebene Dokument asynchron mit der zugehrigen
Anwendung ffnet bzw. druckt, sofern entsprechende Verknpfungen in Windows
definiert sind.  
    
  Do Sort Header <Headername>, <Headername>, ...
 
erlaubt die Sortierung der Header nach dem eigenen Geschmack. 

  Do Sort Header Newsgroups, FollowUp-To, From, Reply-To
 
wrde dafr sorgen, da die genannten Header als erste kommen - wobei 
nicht existente Header schlicht ignoriert werden - und die restlichen Header 
darunter in ihrer Originalreihenfolge stehen bleiben.

  Do Repair OEQuoting
  
entspricht der Konfigurationsoption "Kammquoting reparieren", kann aber 
natrlich im Gegensatz zur Option auch bedingt genutzt werden:

  If Lower(Header(X-Newsreader)) contains "outlook" then Do Repair OEQuoting

ruft die Funktion nur dann auf, wenn der entsprechende Headereintrag auf OE 
hinweist.   
                                                          
  Do Write IniStr Datei, Abschnitt, Key, Wert
  
ist die Gegenfunktion zu ReadIniStr und erlaubt das Setzen von Werten in
einer INI-Datei. 

  Do Write Textfile Datei, String
  
schreibt den String (der im Falle einer Variable o.. durchaus mehrzeilig
sein kann) in die angegebene Textdatei, eine eventuell schon vorhandene 
Datei wird dabei berschrieben.

  Do Convert BoxQuotes Nummer
  
fhrt gezielt eine bestimmte BoxQuote-Definition aus.

  Delete empty Lines at end
  
lscht Leerzeilen am Postingende.

  Delete Blanks at end of lines
  
lscht Leerzeichen an Zeilenenden, sofern kein Sig-Trenner.
  
  Do Convert Header to 8Bit
  
dekodiert alle Header in 8-Bit, aber ist ausschliesslich fr empfangende Mails 
bzw. CopyIf und Reader ohne MIME-Support sinnvoll, ausgehende Postings und 
Mails drfen nicht mit 8-Bit-Headern rausgeschickt werden!

  Do Convert Encoding to [ qp | 8bit | base64 | 7bit ]
  
Konvertiert den aktuellen MIME-Part in die gewnschte Kodierung.
  
  Do Convert HTML to Text
  
konvertiert HTML in Text, eine doppelte Anwendung ist nicht empfehlenswert.  

  Do Convert OEBeginBug
  
verhindert ggf. die Erkennung von angeblichen Attachments bei OE.

  Do Optimize BodyCharset
  
sucht den kleinstmglichen Zeichensatz fr den aktuellen MIME-Part und setzt die
MIME-Header entsprechend.
  
  Do Optimize Bodycharsets

sucht fr allen MIME-Parts den kleinstmglichen Zeichensatz und setzt die
MIME-Header entsprechend.

  Do Optimize MIMEHeader
  
kodiert Header mit 8-Bit-Zeichen und optimiert ggf. MIME-Kodierungen, um die
Erkennung durch andere Reader zu optimieren.  
  
                                                            
2.11 Debugging
     ---------

Wenn Korrnews auf "Stop" stt, erscheint (fast) derselbe Dialog wie bei 
Fehlern, welcher es erlaubt, aktuelle Variablenwerte u.. einzusehen. Falls
Only_KN verwendet wird, ist die Stop-Anweisung unzulssig.


2.12 Multi-Part-Postings/Mails
     -------------------------
     
Fr die Verwaltung von MIME-Multi-Part-Postings sind nur wenige Befehle ntig,
da alle anderen Anweisungen automatisch mit dem gerade eingestellten MIME-Part
arbeiten.

   Do Select Part Nummer
   
aktiviert den entsprechenden MIME-Part, mittels der numerischen Funktion

  PartCount
  
lt sich die Anzahl der MIME-Parts feststellen, mit 

  Do Save Part <Dateiname>  [, <Pfad>  [, ( Rename | overwrite | Nothing ) ] ]
  
lt sich ein MIME-Part als externe Datei speichern, wobei das Original durch
einen Link zur erzeugten Datei ersetzt wird. Die letzten beiden Parameter
sind optional und werden bei Fehlen durch die Einstellungen der aktuellen 
Konfiguration bestimmt. Der letzte Parameter gibt die Reaktion darauf an, 
wenn bereits eine Datei mit dem angegebenen Namen existiert und der Name auch 
keinen Joker (*) enthlt:

  If PartType is video and Partfilename > ""
    Do Save Part Partfilename, "c:\Anhaenge\video\", Overwrite
  endif

speichert alle Attachments vom Typ video/irgenwas im passenden Pfad, wobei gleich-
namige Dateien sich automatisch berschreiben sollen.

Mit

  Delete part because <Text>
  
lt sich ein MIME-Part lschen, der Text erscheint dann als Ersatz fr den originalen
Inhalt und ist als Begrndung fr die Lschung gedacht.
  
Eine Beispielnutzung bzgl. Multi-Part-Postings/Mails she so aus:

 For %Part% = 1 to PartCount
   Do Select Part Val(%Part%)
   If Partencoding is qp then Do Convert Encoding to 8bit
   If Parttype is html then Do Convert HTML to Text
   If PartType is binary
      Do Save Part "c:\tmp\", PartFileName, false
   endif
   If PartType is plaintext 
      Gosub Standardbehandlung
   endif
 Next
 Quit
 
 Sub Standardbehandlung
   ...
 end sub   

Die berprfung des Parttype ist im Zusammenhang mit MIMEParts extrem empfehlens-
wert, da z.B. die Umkodierung von Base64 nach 8Bit im Zusammenhang mit Attachments
zum Verlust des Inhalts durch enthaltene Null-Bytes fhren kann.

     
3. Syntax
   ~~~~~~

Die Header.def ist zeilenweise organisiert, somit mu zwischen Block-
strukturen, die sich ber mehrere Zeilen erstrecken, und "normalen" 
Anweisungen unterschieden werden.

Es gibt folgende Blockstrukturen:

  Sub <SubName> [ "(" [ Var ] <Variablenname> [ : <Variablentyp ] [, ... ] ")" ]
    Var local ...
    <Anweisung> | <Blockstruktur>
    ...
  endsub
                             
  For <Variablenname> = <numerischer Ausdruck> to <numerischer Ausdruck> [ Step <numerischer Ausdruck> ]
    <Anweisung> | <Blockstruktur>
     ...
  Next

  If <Bedingung> [then]
     <Anweisung> | <Blockstruktur>
     ...
  else if <Bedingung>
     <Anweisung> | <Blockstruktur>
     ...
  else <Bedingung>
     <Anweisung> | <Blockstruktur>
     ...
  endif
  
  ( Set | Append ) ( Intro[duction] | Lines | Sig[nature] [ # <num. Ausdruck> ] )
    <Wildcard-String>
    ...
  end
            
  ( Set | Append ) raw ( Intro[duction] | Lines | Sig[nature] [ # <num. Ausdruck> ] )
    <rawString>
    ...
  end

  Set [raw] Macro <Stringausdruck>
    ...
  end

  Set [raw] Header
     Headername: ...
      ...
  end

  Set [raw] %Variablenname%
     ...
     ...
  end       
  
Folgende Sonderflle gibt es noch:

  Do Include <Stringausdruck>

Diese Anweisung wird ausserhalb des normalen Ablaufs ausgefhrt, somit 
fhren Zugriffe auf Variablen automatisch zu Fehlern.
  
  :Label

Labels drfen nicht innerhalb von If-Blcken/Anweisungen plaziert werden, da
im ersten Fall die Anzahl der Endifs nicht mehr stimmen drfte und im zweiten
Fall der Label nicht gefunden wird.


"Normale" Anweisungen knnen ggf. auch ber mehrere Zeilen gehen, wenn sie 
jeweils mit einem "_" abgeschlossen werden, was vor allem bei lngeren 
Bedingungen ganz gut nutzbar ist, intern werden sie zu einer groen Zeile
zusammengesetzt und wie eine normale Zeile behandelt.

Die einzelnen Elemente sind so definiert:

Anweisung := (  Do Select Part <num. Ausdruck>
              | Delete part because <Stringausdruck>
              | Do Save Part <Stringausdruck> [ , <Stringausdruck> [ , ( Nothing | Rename | Overwrite ) ] ]
              | [Set Header] <Headername> ( = | : ) ( <Wildcard-String> )
              | Set [raw] HeaderContent <num. Ausdruck> ( from <Stringausdruck> | = <Wildcard-String> )
              | Set Header <Headername> from <Dateiname>
              | Var ( local | global ) <Variablenname> (, <Variablenname>...) : <Variablentyp> [ = <Anfangswert> ] [, ... ]
              | Set <Variablenname> = <Stringausdruck>
              | Set <Variablenname> from <Dateiname>
              | ( Set | Append ) [raw] H[eader] <Headername> ( = | : ) <Wildcard-String> )
              | Delete Header <Headername>
              | Do Sort Header <Headername>, <Headername>, ...
              | Delete BodyHeader <Headername>
              | ( Set | Append ) [raw] ( Intro[duction] | Line[s] ) = <Wildcard-String>
              | ( Set | Append ) [raw] ( Intro[duction] | Line[s] ) from <Stringausdruck>
              | ( Set | Append ) [raw] Sig[nature] [ # <num. Ausdruck> ] = <Wildcard-String>
              | ( Set | Append ) [raw] Sig[nature] [ # <num. Ausdruck> ] from <Stringausdruck>
              | Delete ( Intro[duction] | Line[s] | Sig[nature] )
              | Set [raw] Macro ( from <Stringausdruck> | = <Wildcard-String> )
              | Do Convert Boxquotes <num. Ausdruck>
              | Do Replace ( first | all | last ) <RegExp> with <Stringausdruck> 
                  [ in ( Body | Sig | Lines | Intro | Header | Header2 | <Variablenname> ) ]
                  [ from <num. Ausdruck> ] [ to <num. Ausdruck> ]
              | Set Bodyline <num. Ausdruck> ( from <Stringausdruck> | = <Wildcard-String> )
              | Insert Bodyline <num. Ausdruck> = <Wildcard-String>
              | Delete Bodylines from <num. Ausdruck> to <num. Ausdruck>
              | Delete Bodyline <num. Ausdruck>
              | Delete between (first|last) <RegExp>, <RegExp>, <Bedingung> [, <Stringausdruck>]
              | Delete Empty Lines at end                         
              | Delete Blanks at end of lines
              | Do Convert Header to 8Bit
              | Do Convert Encoding to ( qp | 8bit | base64 | 7bit )
              | Do Convert HTML to Text
              | Do Convert OEBeginBug
              | Do Convert OEKillFalseReBug
              | Do Repair OEQuotings
              | Do Optimize MIMEHeader
              | Do Optimize BodyCharset
              | Do Optimize Bodycharsets
              | Set Opt[ion] <Optionsname> = <Stringausdruck>
              | Do ( Exec | Run ) [ and wait ] <Stringausdruck> [, <Stringausdruck> [, <Aufruftyp> ] ]
              | Do ( Open | Print ) <Stringausdruck>
              | Do Write IniStr <Stringausdruck>, <Stringausdruck>, <Stringausdruck>, <Stringausdruck>
              | Do Write Textfile <Stringausdruck>, <Stringausdruck>
              | Do Show Info <Stringausdruck> [, <Stringausdruck>]
              | Do Play Wave <Stringausdruck> [ and wait ]
              | Do Include <Raw String>
              | If <Bedingung> then <Anweisung>
              | For <Variablenname> = <num. Ausdruck> to <num. Ausdruck> [ Step <num. Ausdruck> ] do <Anweisung>
              | break
              | cont[inue]
              | Next
              | Gosub <SubName> [ ( <Stringausdruck> | <Variablenname> ) [, ...] ]
              | Return
              | Goto <Label>
              | ":"<Label>
              | Quit
              | Stop
              | Kommentar                      
             ) 
   

Stringausdruck := (  Stringfunktion
                   | <Variablenname>
                   | "<rawString>"
                   | '<rawString>' 
                   | Filename
                   | Path
                   | Partfilename
                   | CRLF
                   | TAB                           
                   | SigDel
                   | Version
                   | Full [raw] Header [ without Headername [ , Headername [ , ... ] ] ]
                   | Full [raw] Body
                   | Full [raw] Sig[nature]
                   | Full Article / Posting / Mail
                   | <Stringausdruck> "+" <Stringausdruck>
                  )
                   
Stringfunktion := (  Lower (<Stringausdruck>)
                   | Upper (<Stringausdruck>)
                   | First (<Stringausdruck>)
                   | Last (<Stringausdruck>)
                   | Address (<Stringausdruck>)
                   | Name (<Stringausdruck>)
                   | FirstName (<Stringausdruck>)
                   | MakeAddress (<Stringausdruck>, <Stringausdruck>)
                   | DecodeISO (<Stringausdruck>)
                   | 8BitTo7Bit (<Stringausdruck>)
                   | DosToWin (<Stringausdruck>)
                   | WinToDos (<Stringausdruck>)
                   | EscRegExp (<Stringausdruck>) 
                   | Extract (<RegExp>, <Stringausdruck>)
                   | Replace (<Stringausdruck>, <RegExp>, <Stringausdruck>)
                   | WordWrap ( <Stringausdruck>, <numerischer Ausdruck>, <Stringausdruck> )
                   | Line ( <numerischer Ausdruck>, <(mehrzeiliger) Stringausdruck> )
                   | Header (<Stringausdruck>)
                   | Headername (<numerischer Ausdruck>)
                   | HeaderContent (<numerischer Ausdruck>)
                   | RawHeaderContent (<numerischer Ausdruck>)
                   | BodyHeader (<Stringausdruck>) 
                   | Bodyline (<numerischer Ausdruck>)
                   | Chr ( <numerischer Ausdruck> )
                   | FillChar ( <Stringausdruck>, <numerischer Ausdruck> )
                   | Left ( <Stringausdruck>, <numerischer Ausdruck> )
                   | Right ( <Stringausdruck>, <numerischer Ausdruck> )
                   | Copy ( <Stringausdruck>, <numerischer Ausdruck>, <numerischer Ausdruck> )
                   | CutLeft (<Stringausdruck>, <numerischer Ausdruck>)
                   | CutRight(<Stringausdruck>, <numerischer Ausdruck>)
                   | LTrim ( <Stringausdruck> )
                   | RTrim ( <Stringausdruck> )
                   | Trim ( <Stringausdruck> )
                   | Input (<Stringausdruck>, <Stringausdruck>, <Stringausdruck>)
                   | ReadIniStr (<Stringausdruck>, <Stringausdruck>, <Stringausdruck>, <Stringausdruck>)
                   | Str (<numerischer Ausdruck> [, <numerischer Ausdruck> [, <numerischer Ausdruck> ] ] )
                   | IStr (<numerischer Ausdruck>)
                   | BoolToStr ( <Bedingung> )
                   | GetDateTime (<Stringausdruck>)
                  ) 


RegExp := <Stringausdruck>

rawString := Ein ganz normaler String eben...
 
Headername := Bestehend aus ASCII-Zeichen, keine Leerzeichen, ansonsten siehe RFCs

Optionsname := Ein in "Korrnews.Ini" bestehender Optionsname

Aufruftyp :=  ShowDefault | Show 
              | Shownormal | ShowMinimized |  ShowMaximized 
              | ShowNoActivate | ShowMinNoActive | ShowNA 
              | Hide | Normal | Minimize | Max | Restore

Variablenname := % [A-Z] [A-Z,0-9,_,-]... %

Variablentyp :=  ( String | Float | Integer | Boolean )

Wildcard-String := (  <rawString>
                    | ( <Wildcard-String> ) %<Stringfunktion>% ( <Wildcard-String> )
                    | ( <Wildcard-String> ) <Variablenname> ( <Wildcard-String> )
                    
Bedingung := ( ["("] ["Not"] <Bedingung>
                    [ ( "or" | "and" | "xor" ) ["Not"] <Bedingung> ] [")"]
               | <Einfache Bedingung> )

Einfache Bedingung := (  <Stringvergleich>
                       | <Numerischer Vergleich>
                       | <Boolsche Funktion>
                       | "true"
                       | "false"
                      )

Stringvergleich := (  <Stringausdruck> 
                        ( "equals" | "contains" | "="
                          | "<>" | ">" | ">=" | "<=" | "<"
                          | "in" | "begins with" | "ends with" ) 
                      <Stringausdruck>
                    | <Stringausdruck> "like" / "matches" <RegExp>                       
                    | <Stringausdruck> "is empty"
                    | <Stringausdruck> "between" <Stringausdruck> "and" <Stringausdruck>
                   )

Numerischer Vergleich := (   <Numerischer Ausdruck> ( "=", ">", "<", "<=", ">=" ) <Numerischer Ausdruck>
                           | <Numerischer Ausdruck>
                           | <Numerischer Ausdruck> "between" <Numerischer Ausdruck> "and" <Numerischer Ausdruck>
                         )

Boolsche Funktion := (   HasSig[nature]
                       | Has8BitChars
                       | PartType is ( Unknown | Text | Plaintext | UnknownText | HTML | Binary | 
                           Application | Audio | Image | Video )
                       | PartEncoding is ( quoted-printable | qp | 8bit | 8-bit | 8 bit | 
                           base64 | ascii | 7-bit | 7bit | 7 bit | unknown )  
                       | Changed
                       | ChangedLines
                       | ChangedSig[nature]
                       | ChangedIntro[duction]
                       | VarExists ( <Variablenname> )
                       | StrToBool ( <Stringausdruck> ) 
                       | FileExists ( <Stringausdruck> )
                       | Ask ( <Stringausdruck> [ , <Stringausdruck> ] )
                       | Abort ( <Stringausdruck> [ , <Stringausdruck> ] )
                      )
  

<Numerischer Ausdruck> := (   ["-"]Zahl
                       | <Numerischer Ausdruck> "+" <Numerischer Ausdruck>
                       | <Numerischer Ausdruck> "-" <Numerischer Ausdruck>
                       | <Numerischer Ausdruck> "*" <Numerischer Ausdruck>
                       | <Numerischer Ausdruck> "/" <Numerischer Ausdruck>
                       | <Numerischer Ausdruck> "^" <Numerischer Ausdruck>
                       | "(" <Numerischer Ausdruck> ")"
                       | ( Sgn | Abs | SQRT ) "(" <Numerischer Ausdruck> ")"
                       | ( Max | Min ) "(" <Numerischer Ausdruck> , ... ")"
                       | Count "(" <Stringausdruck> "," <Stringausdruck> ")"
                       | MatchedLines "(" <RegExp> ")"
                       | Len[gth] "(" <Stringausdruck> ")"
                       | Pos "(" <Stringausdruck>, <Stringausdruck> ")"
                       | Val "(" <Stringausdruck> ")"
                       | Trunc "(" <Numerischer Ausdruck> ")"
                       | Random "(" <Numerischer Ausdruck> ")"
                       | PartCount
                       | Bodylines
                       | Headerlines
                       | Siglines
                       | Introlines 
                       | CountLines "(" <(mehrzeiliger) Stringausdruck> ")"
                       | NextMatchedLine "(" <Numerischer Ausdruck>, <Stringausdruck> ")"
                      )
                               
Kommentar := ( "#" | ";" | ":" ) <rawString>

Sofern mich entsprechende Anfragen erreichen, ist eine Erweiterung der 
Syntax durchaus denkbar, fr meine eigenen Bedrfnisse langt es zur 
Zeit.

So long,
Thomas G. Liesner  

<korrnews@tgl.westfalen.de>
