CopyIf
======
Autor: Thomas G. Liesner <tgl@gmx.de>
Stand: 04.12.2000, V1.1, allerdings durchaus Lcken in der Doku mglich...
Voraussetzung: Installierter Hamster
                       
Aufbau der "CopyIf.ini"
=======================

[Settings]

; Falls die Message-IDs bei umkopierten Nachrichten gendert werden sollen,
; hier eine entsprechende Ergnzung a la $$$$NotOriginal$$$$. definieren,
; untergrbt u.a. die Crosspost-Erkennung von Agent, sofern diese nach 
; Message-ID sucht, kann ansonsten leer bleiben. Ansonsten mu bei Antworten 
; auf diese vernderten Nachrichten Korrnews genutzt werden, um die References 
; wieder in Ordnung zu bringen
AddToMessageID=    

; Erlaubt das Testen der Funktionen ohne echte nderungen
; 1 = Testen, 0 = Ernstfall
TestOnly=1

; Einschrnkung, wieviele Postings getestet werden sollen, 0 fr alle:
; - bzgl. neuen Gruppen
NewGroups_TestMax=100
; - bzgl. schon mindestens einmal durchsuchten Gruppen
TestMaxPostings=0                                     

; Welche Gruppen nicht durchsucht werden sollen - bitte als RegExp-Ausdruck
; angeben, bei mehreren Ausschlssen durch Kommata trennen.
IgnoreGroups=^local\.,^internal\.

; Folgende Gruppen trotzdem testen:
DontIgnoreGroups=

; Meldung ber noch unabgeholte Mails integrieren
MailInfo=1                                       

; Nur Kopieren, wenn noch keine Instanz vorhanden ist - bedingt gesetztes
; AddToMessageID, ansonsten wird immer kopiert:
CopyIfExist=0                                  

; Crosspostings nur einmal testen, 0 testet jede Instanz
CheckXPostingsOnlyOnce=1

[Display]           
                                    
; Immer Enddialog anzeigen Ja/nein = 1/0
ShowResultAlways=0

; Enddialog anzeigen, wenn kopiert oder verndert wurde
ShowResultIfAction=1

; Enddialog anzeigen, wenn Counter > 0 existieren (gilt auch fr
; Mailbenachrichtigungen):
ShowResultIfCounter=1
                          
; Nur Counter > 0 im Enddialog anzeigen                          
ShowOnlyCounterGreaterThanNull=1

; Suchvorgang in Taskbar anzeigen
ShowTaskBarEntry=1               

; Bei Testdurchlauf passende Postings anzeigen:
ShowFoundedPostingsWhenSimulate=1

[Groups]                                       
; Wird automatisch gefllt...


Aufbau der "CopyIf.def"
=======================

0. Aufbau
   ~~~~~~

1. Allgemeines
2. Die konkreten Mglichkeiten
  2.1 Einfhrung in die Syntax
    2.1.1 "Wildcards"
    2.1.2 Variablen
    2.1.3 Stringfunktionen
    2.1.4 If-Bedingungen
    2.1.5 Ablaufsteuerung
    2.1.6 Optionen umstellen
  2.2 Text-Body bearbeiten
    2.2.1 Introductions 
    2.2.2 Texte suchen/ersetzen
    2.2.3 Quoted-Printable => 8-Bit
    2.2.4 OE-Begin-Bug umgehen
  2.3 Header bearbeiten
    2.3.1 Definition zustzlicher Header, Header ndern oder Header lschen
    2.3.2 ISO-Header => 8-Bit
  2.4 nderungen speichern
  2.5 Weiteres  
3. Syntax


1. Allgemeines
   ~~~~~~~~~~~
   
Die CopyIf.def mu sich im selben Verzeichnis wie CopyIf.exe selber befinden.
Sie wird fr jedes neue Posting einmalig durchlaufen. ber die CopyIf.ini
sind bestimmte Gruppen ausschliessbar, zudem werden Crosspostings auch nur
einmal durchlaufen. Ein einmal verndert gespeichertes Posting bekommt einen
speziellen Headereintrag, welcher ebenfalls einen Zweitdurchlauf 
ausschliesst.

Sofern in der CopyIf.def nicht ausdrcklich gespeichert wird, werden
die eventuell gemachten nderungen ohne Rckmeldung verworfen.

Zum ersten Testen sollte man alles bis auf eine Gruppe ausschliessen und 
den Testmodus aktivieren, bis das Skript den eigenen Wnschen entspricht.

Als Begriffsklrung hier noch der Aufbau eines Postings aus Sicht von CopyIf:

------------
I. Header
II. Body
 a) Introduction
 b) Text
------------

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) Achtung, Newbie-Gruppe!
     -----------------------------------------
  
  b) Hallo Leute!
     Werdegang eines Newbies
     ...
------------


2. Die konkreten Mglichkeiten
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.1 Einfhrung in die Syntax
    ------------------------
    
Die "Sprache" von CopyIf entspricht weitgehend der von Korrnews. Sie ist zeilen-
orientiert und auf die konkreten Anforderungen abgestimmt. 


2.1.1 "Wildcards"
      - - - - - -

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

Verwendung finden Wildcards bei
- der Zuweisung u.a. von Headern
- Blockanweisungen (Introductions)

In den meisten anderen Fllen werden "Stringausdrcke" verwendet, welche 
dieselben Mglichkeiten haben, aber etwas lesbarer sein drften.
Fr die Zuweisung von Headern und Introduction-Blcken ist die Wildcard-
Syntax aber immer noch ganz passend.
                                        
Weitere Details sind der Korrnews-Dokumentation entnehmbar.
      

2.1.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 zur Zeit ausschliesslich String-Variablen, um trotzdem
Zahlen zu verarbeiten, knnen diese per Str() jederzeit in einen String gewandelt
werden und mit Val() wieder zu einer Zahl gemacht werden.

Die Definition einer neuen Variablen sieht so aus:

  Set %Gruppe% = Header(Newsgroups)
  Set %Programmierer% = "Thomas G. Liesner"
  Set %SeinVorname% = "Das ist doch der " + Extract("^[^ ]+", %Programmierer%) + "!"
  Set %ZitierteZeilen% = Str(MatchedLines('^>'))
  
Die Nutzung in Wildcards sieht dann so aus:

   X-Der-Programmierer: heisst %Programmierer%!
   
   Set Introduction
      Hinweis: F'up2 %Header(FollowUp-To)%
   end
  
Richtig interessant werden diese Funktionen im Zusammenhang mit Bedingungen.


2.1.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, ...)
  Str(...,...,...) Wandelt den als ersten Parameter bergebenen numerischen
                   Ausdruck in einen String um. Der optionale zweite numerische
                   Parameter legt die Anzahl der Vorkomma-, der optionale dritte
                   die Anzahl der Nachkommastellen fest.
  EscRegExp(...)   Wenn man Header u.. als RexExp nutzt, kann man mittels dieser
                   Funktion versehentliche Seiteneffekte vermeiden, da alle
                   speziellen Zeichen ausmaskiert werden ("." => "\." etc) 	                	

  String "zerlegen":
  ------------------
  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"
  Adress(...)      bezieht sich - wie auch die folgenden beiden Funktionen -
                   auf Mailadressen i.S. des From- oder Reply-To-Headers.
                   Adress 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"
  MakeAdress(...,...) 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(...,...) Sucht 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"
  CutLeft(...,...) Entfernt die als zweiten Parameter angegebene Zahl von Zeichen
                   aus dem als ersten Parameter bergebenen String, 
                   CutLeft("Re: Ups", 3) ergibt somit "Ups".
  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:".

  Sonderfunktionen:
  -----------------
  Header(...)	   liefert den Wert des angegebenen Headers
  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
  
  Konstanten:
  -----------
  CR		   Entspricht einem Zeilenumbruch	
  
      
2.1.4 If-Bedingungen
      - - - - - - - 

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>

Die genaue Syntax ist unter 3. zu finden, hier einfach mal einige kon-
krete Beispiele:

      ; MixGroups ersetzen
      ; ==================
      Set %MixGroup% = ""
      If %NG% begins with "uunet.de." and %NG%<>"uunet.de.test" then Set %MixGroup% = "uunet.de.all"
      If %NG% begins with "hamster." then Set %MixGroup% =  "hamster.de.ALL"
      If %NG% begins with "muenster." 
         If %NG% begins with "muenster.markt."
            Set %MixGroup% = "muenster.markt.ALL"
         else               
            Set %MixGroup% = "muenster.ALL"
         endif
      endif              
      ...
      If %MixGroup% > "" then Do Copy To Group %MixGroup%
      
oder

      ; Ersatz fr CopyFups
      ; ===================
      Set %CopyFups% = "0"
      Set %CopyThreads% = "0"
      If Header(References) contains "@"+%FQDN%+">" 
         If Header(References) ends with "@"+%FQDN%+">" 
            Set %CopyFups% = "1"
            Do Inc Counter "* neue direkte Antworten", "* in " + %XNG%
      	    Set %Typ% = "Direkte Antwort, "
         else 
            Do Inc Counter "* Neuzugnge in eigenen Threads", "* in " + %XNG% 
            Set %Typ% = "Eigener Thread, "
         endif     
         Set %CopyThreads% = "1"
      endif           
      ...
      If %CopyFups% = "1" then Do Copy To Group "tgl.fups"
      If %CopyThreads% = "1" then Do Copy To Group "tgl.threads"

oder

      ; Hinweise auf spezielle Headereintrge
      ; =====================================
      If %NG% contains ","
         If %Typ% = "" then Append Intro X-Post ber %Str(Count(',', Header(Newsgroups)))% Gruppen (%NG%)
      endif
      Set %temp% = Lower(Header(FollowUp-To))
      If %temp% > "" and Not (%NG% begins with "ml." or %NG%="de.rec.film.kritiken" _
         or %NG% contains "digest") _
      then
         If %temp%='de.alt.flame' or %temp%='de.alt.0d' or %temp% contains 'kasper'
            Append Intro ***** WARNUNG! => F'Up2 *%Upper(%temp%)%* gesetzt *****     
            Set Header FollowUp-To: %Header(FollowUp-To)%,%Header(Newsgroups)%
         else
            Append Intro F'Up2 %temp% gesetzt
         endif
      endif
      If Header(Control)>"" 
         Append Intro Control: %Header(Control)%
      endif
      If Header(Supersedes)>"" 
         Append Intro Supersedes: %Header(Supersedes)%
      endif
      If ChangedIntro
         Append Intro 
            ----------------------------------------------------------------------------------------------------------------
      
         end
      endIf
      ...
      Do Save Changes
      
   
2.1.5 Ablaufsteuerung
      - - - - - - - -

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 Intro
    Do Include "intro.txt"
  end                    

Wobei fr den Fall genausogut die 'richtige' Funktion

  Set Intro from "intro.txt"

genommen werden kann.  
  
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 
 
Der Befehl "Quit" beendet das Skript und ist bei Verwendung von Subs ntig,
da ansonsten die Fehlermeldung "Unbekannter Befehl 'Sub ...'" kommen wrde.

Zum Springen gibt es dann noch

  Goto Label
  
welcher zum Sprungziel

  :Label
  
fhrt.    
   
2.1.6 Optionen umstellen
      - - - - - - - - - 

Mit dem Befehl 

  Set Option Bezeichnung = Wert
  
knnen jederzeit die INI-Optionen fr den aktuellen Postingdurchlauf 
gendert werden, dauerhafte nderungen sind damit allerdings nicht 
mglich. 

Dies kann man z.B. gezielt nutzen, indem man die Option CopyIfExist
je nach Bedarf aktiviert oder deaktiviert:

 Set CopyIfExist = "0"
 
Hinweis: Die Namen der Optionen knnen sich prinzipiell in neuen
Programmfassungen ndern, auch wenn ich dies weitgehend zu vermeiden
suche.


2.2 Text-Body bearbeiten
    --------------------

2.2.1 Introductions 
      - - - - - - -
      
Fr Hinweise auf Fup2-Fallen und hnliches eigenen sich die Introductions - 
dies sind zustzliche Zeilen, die zu Anfang des Postings eingefgt werden.

Bei Zuweisungen gibt es zwei grundstzliche Alternativen: Neusetzen oder 
Anhngen, die Anweisung heisset entsprechend "Set" bzw. "Append".

Zudem gibt es drei Mglichkeiten, den Inhalt zu bergeben:

Entweder in der CopyIf.def selber als Mehrzeiler:

  ( Set | Append ) [raw] Introduction
    Zeile #1
    Zeile #2
    Zeile #3
    ...
  end

Beispiel:

  If Header(Newsgroups) contains ","
    Set Intro 
       Hinweis: Crossposting!
       Gruppen: %Header(Newsgroups)%
    end     
  endif  
  

oder in der CopyIf.def als Einzeiler:

  If IntroLines > 0 then Append Intro: "=================================================================="
  
oder in einer externen Datei, so da in der CopyIf.def nur noch ein 
Verweis steht:

  Set Intro from "Postingkopf.txt"
  
Mit 

  Delete Intro
  
kann das Intro auch wieder gelscht werden, mit ChangedIntro sollten nderungen
abfragbar sein und IntroLines wurde ja bereits im Beispiel genutzt.
      

2.2.2 Texte suchen/ersetzen
      - - - - - - - - - - -
      
Zur individuellen nderung des eigentlichen Textes gibt es folgenden Befehl:

   Do Replace ( first | last | all ) <regexp> <Stringausdruck>
   
Hiermit kann gezielt im Text gendert werden, der Suchausdruck ist
dabei ein regulrer Ausdruck wie auch im Hamster oft zu finden.

Beispiel: 

  If (Header(References) > "") and (Not %FB% contains CR+">") then
    If %FB% contains CR+" >" 
       Append Intro ... AMK-Quoting-Stil korrigiert.
       Do Replace All "^ >" with ">"
       Set %Save% = "1"
    endif
  endif 

erlaubt auch Agent-Nutzern, AMKs Postings angenehm zu lesen.         
                         
Eine weitere Option ist z.B. ganz gut fr Werbeanhnge brauchbar:
                         
   Delete between last <RegExp>, <RegExp>, <Bedingung> [, <Stringausdruck>]
   
Der erste Parameter gibt den Suchausdruck fr die einleitende Zeile an, der 
zweite Parameter den Suchausdruck fr die schliessende Zeile, wenn dieser 
Suchausdruck leer ist, wird nur nach dem ersten Suchausdruck gesucht und alles 
darunter befindliche gelscht.

Der dritte Ausdruck bestimmt, ob die einleitende und schliessende Zeile auch 
gelscht werden sollen, der letzte Ausdruck erlaubt es, einen Ersatz fr den
gelschten Text einzubauen.

Der Werbeblock der Hamster-Mailingliste sieht z.B. so aus:

  [Normales Posting]
  ------------------------------------------------------------------------
  Explore the popular High-End Room -
  Go To Where The Smart People Shop-uBid.com
  http://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/
  ------------------------------------------------------------------------

Der passende Lschausdruck ist somit:

   Set %Werbezeile% = "^------------------------------------------------------------------------$"
   Delete between last %Werbezeile%, %Werbezeile%, false , "[        Nerv-Werbung gelscht      ]"

bzw.    

   Set %Werbezeile% = "^------------------------------------------------------------------------$"
   Delete between last %Werbezeile%, %Werbezeile%, true

Mit dem Befehl

   Delete Empty Lines at end   

lassen sich berzhlige Leerzeilen am Ende auch noch eleminieren.  

      
2.2.3 Quoted-Printable => 8-Bit
      - - - - - - - - - - - - -

Fr Free Agent, OE- und Gravity-Nutzer sollte folgende Funktion noch 
interessant sein:

  Do Convert QPBody

konvertiert QP-Postings nach 8-Bit incl. Headeranpassung. 

      
2.2.4 OE-Begin-Bug umgehen
      - - - - - - - - - -

Fr OE-Nutzer, welche den "begin  Dateiname"-Bug leid sind, steht die Funktion

  Do Convert OEBeginBug
  
zur Verfgung, welche die beiden Leerzeichen auf ein Leerzeichen zusammenkrzt.         


    
2.3 Header bearbeiten
    -----------------

2.3.1 Definition zustzlicher Header, Header ndern oder Header lschen
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Um einen Header zu ndern oder neu zu erzeugen, ist folgender Befehl
gedacht:

  Set Header Headername: Inhalt

Mit 

  Set X-Hallo: Hi

wird der Header X-Hallo eingefgt. Der Inhalt der Zuweisung darf Wildcards
enthalten:

  Set X-Crosspost: %Str(Count(',',Header(Newsgroups)))%    

Das Lschen von Headern erfolgt ber

  Delete Header X-MimeOLE

Die Sortierung ist auch variabel:

  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.

      
2.3.2 ISO-Header => 8-Bit                                              
      - - - - - - - - - -

Damit auch Gravity oder Free Agent-Nutzer Header gut lesen knnen, ist die 
Anweisung      

  Do Convert QPHeader

eingebaut - sie wandelt nur ISO-8859-1/qp-Kodiertes, dies ist aber schon die 
Mehrzahl der entsprechenden Eintrge.

Fr XNews-Anwender macht die Funktion ebenfalls Sinn, da XNews beim Dekodieren
eines mehrzeiligen Headers fehlerhafterweise ein Leerzeichen zuviel einbaut,
was speziell im Subject extrem unangenehm ist. Das Dekodieren mittels CopyIf
umgeht diese fehlerhafte Dekodierung...
      

2.3.3 OE-Bug umgehen, der beim Antworten diverse Subject-Anfnge lscht
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

OE hat die Angewohnheit, alles, was mglicherweise ein lokalisiertes "Re: "
sein knnte, beim Antworten rigoros zu lschen. Aus "V: Schne Spiele" wird
bei OE beim Antworten "Re: Schne Spiele" statt "Re: V: Schne Spiele".

Die Funktion

  Do Convert OEKillFalseReBug
  
vermeidet diesen Fehler, indem er gegen sich selber eingesetzt wird: Aus 
"V: Schne Spiele" macht CopyIf - sofern keine References-Header vorhanden 
sind - einfach "XX: V: Schne Spiele", was beim Antworten mittels OE wieder
zu "Re: V: Schne Spiele" mutieren drfte - und allen anderen einen heilen
Thread bringt.

Das "XX: " wird immer dann davor gesetzt, wenn das Posting keine Antwort ist
und ein bis drei Zeichen (A-Z) enthlt, denen ein Doppelpunkt folgt.

Bitte diese Funktion nicht bei funktionierenden Newsreadern einsetzen, diese
wrden das "XX: " beim Antworten im Normalfall beibehalten...

      
2.4 nderungen speichern 
    --------------------

Damit man noch was von den nderungen hat, mssen sie noch gespeichert werden.
Dazu dienen zur Zeit drei Befehle:
    
   Do Copy to Group <Stringausdruck>
   
erstellt eine Kopie in die genannte Gruppe, die natrlich existieren muss.

   Do Export as <Stringausdruck>
   
speichert das Posting in eine Textdatei, diese mu im Namen einen "*" haben, 
der dann beim Speichern durch die erste noch freie Nummer ersetzt wird.

   Do Save Changes            
   
ersetzt das bisherige Posting, indem er die alten Instanzen lscht und den 
Artikel re-importiert.

   Do Touch <regulrer Ausdruck>
                 
erlaubt es, da Gruppen, die man nicht direkt im Client liest, sondern ber 
CopyIf in einer Pseudogruppe zusammengefat hat, trotzdem nicht als "tote" 
Gruppen in der tglichen Statistik auftauchen. Beispiel:
  
  ; Sofern man eine entsprechende Funktion definiert hat...
  Gosub MixGroup "hamster.de.", "hamster.de.all"           
  ; Originalgruppenlesedatum aktualisieren:
  Do Touch "^hamster\.de\."                
  ; Alternativschreibweise: Do Touch "^"+EscRegExp("hamster.de.")
  

2.5 Weiteres            
    --------

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

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

Hiermit knnen externe Programme aufgerufen werden, wobei zustzlich noch
Parameter bergeben werden drfen:

  Do Run "Notepad.exe", "CopyIf.def"
 
wrde z.B. die "CopyIf.def" in den Editor laden.
    
Das Skript hlt dabei nicht an, sondern luft nach Absetzen des Aufrufs 
direkt weiter, eventuell wird dies in zuknftigen Versionen per Parameter
steuerbar sein.                                                

  Do Include <Stringausdruck>

erlaubt das Auslagern von Teilen der CopyIf.def in andere Dateien, was den
Einbau von Fremdskripten erleichten drfte.

  Do Include "Skripte\iHinweis.def"
  
wrde die Datei "Skripte\iHinweis.def" ausgehend vom Arbeitsverzeichnis suchen
und in die aktuelle "CopyIf.def" einbinden.                                    

Zum Debuggen sind ggf. noch zwei Funktionen nutzbar:

  Stop

Geht in den Fehlerdialog, um z.B. Variablen u.. einsehen zu knnen

  Do Show
  
zeigt das aktuelle Posting incl. der bisherigen nderungen an.
            
  Do Inc counter <Stringausdruck> [, <Stringausdruck> ]
  
Um freie Ausgaben zu erlauben, kann man mit 

  Do Inc Counter "Antwortpostings"

oder     

  Do Inc Counter "Antwortpostings", Header(Newsgroups)
  
Zeilen fr den Enddialog erzeugen, jede Do Inc-Aufruf zhlt dabei automatisch 
hoch, am Ende werden dann die Zeilen im linken Dialogteil ausgegeben. Bei 
Nutzung des zweiten Parameters kann man das Ganz noch nach einem Sub-Schlssel
aufteilen lassen.

  Do Define Counter <Stringausdruck>, <Stringausdruck>, ...

Falls einem die Ausgabereihenfolge zu chaotisch ist, kann man mit diesem Befehl
die Counter-Reihenfolge rechtzeitig festlegen, zwei Kommata nacheinander sorgen
dabei fr eine Leerzeile.  


3. Syntax
   ~~~~~~

Die CopyIf.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>
    <Anweisung> | <Blockstruktur>
    ...
  endsub
                             
  If <Bedingung> [then]
     <Anweisung> | <Blockstruktur>
     ...
  else if <Bedingung>
     <Anweisung> | <Blockstruktur>
     ...
  else <Bedingung>
     <Anweisung> | <Blockstruktur>
     ...
  endif
  
  ( Set | Append ) Intro[duction]
    <Wildcard-String>
    ...
  end
            
  ( Set | Append ) raw Intro[duction]
    <rawString>
    ...
  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 := (  [Set Header] <Headername> ( = | : ) ( <Wildcard-String> )
              | Set Header <Headername> from <Dateiname>
              | Set <Variablenname> = <Stringausdruck>
              | Set <Variablenname> from <Dateiname>
              | ( Set | Append ) [raw] H[eader] <Headername> ( = | : ) <Wildcard-String> )
              | Delete Header <Headername>
              | Do Sort Header <Headername>, <Headername>, ...
              | ( Set | Append ) [raw] Intro[duction] = <Wildcard-String>
              | ( Set | Append ) [raw] Intro[duction] from <Stringausdruck>
              | Delete Intro[duction]
              | Do Replace ( first | all | last ) <RegExp> with <Stringausdruck>
	      | Delete between ( first | last ) <RegExp>, <RegExp>, <Bedingung> [, <Stringausdruck>]
              | Delete Empty Lines at end   
              | Set Opt[ion] <Optionsname> = <rawString>
              | Do ( Exec | Run ) <Stringausdruck>, <Stringausdruck>
              | If <Bedingung> then <Anweisung>
              | Gosub <SubName>
              | Return
              | Goto <Label>
              | ":"<Label>
              | Quit
              | Stop
              | Kommentar               
              | <Sonderbefehl>
             ) 
             
Sonderbefehl := (  Do Save Changes
                 | Do Copy To Group <Stringausdruck>
                 | Do Touch <RegExp>
                ) 
   

Stringausdruck := (  Stringfunktion
                   | <Variablenname>
                   | "<rawString>"
                   | '<rawString>' 
                   | CR
                   | 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>)
                   | Adress (<Stringausdruck>)
                   | Name (<Stringausdruck>)
                   | FirstName (<Stringausdruck>)
                   | MakeAdress (<Stringausdruck>, <Stringausdruck>)
                   | DecodeISO (<Stringausdruck>)
                   | 8BitTo7Bit (<Stringausdruck>) 
                   | EscRegExp (<Stringausdruck>) 
                   | Extract (<RegExp>, <Stringausdruck>)
                   | Replace (<Stringausdruck>, <RegExp>, <Stringausdruck>)
                   | Header (<Stringausdruck>)
                   | CutLeft (<Stringausdruck>, <numerischer Ausdruck>)
                   | CutRight(<Stringausdruck>, <numerischer Ausdruck>)
                   | Str (<numerischer Ausdruck> [, <numerischer Ausdruck> [, <numerischer Ausdruck> ] ] )
                  ) 

RegExp := <Stringausdruck>

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

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

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

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"
                   )

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

Boolsche Funktion := (   "Changed"
                       | "ChangedIntro[duction]"
                      )

<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> ")"
                            | Val "(" <Stringausdruck> ")"
                            | Bodylines
                            | Headerlines
                            | Siglines
                            | Introlines )
                               
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  
<tgl@gmx.de>