Initial checkin of upstream version 4.09.
Signed-off-by: Thomas Hochstein <thh@inter.net>
This commit is contained in:
commit
ac7e2c541a
484
CHANGES
Normal file
484
CHANGES
Normal file
|
@ -0,0 +1,484 @@
|
||||||
|
UseVoteGer Versionshistorie (aktuelle Version: 4.09, released 07.10.2007)
|
||||||
|
=========================================================================
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
- aussortieren von Bounces aus Stimmenliste
|
||||||
|
- Unterstuetzung von Maildir
|
||||||
|
- [Zugschlus] ich fänd es klasse, wenn man eine Kopie des Wahlscheines ins
|
||||||
|
Abstimmungsverzeichnis legt und Usevote einem dann auf Abruf ein diff
|
||||||
|
oder wdiff zwischen Sollwahlschein und wirklich eingreichtem
|
||||||
|
Wahlschein macht. Auf diese Weise erwischt man auch kleine Änderungen
|
||||||
|
am Datenschutzhinweis (da bin ich eben in eine Falle von th-h getappt).
|
||||||
|
|
||||||
|
|
||||||
|
Version 4.09 (14.09.2007):
|
||||||
|
- "votefile"-Option in usevote.cfg an passendere Stelle verschoben und
|
||||||
|
den Kommentar korrigiert (natuerlich gilt pop3=0 als Bedingung, nicht
|
||||||
|
etwa wie vorher angegeben smtp=0)
|
||||||
|
- Fehler in Template für Ergebnisausgabe korrigiert (fehlendes Newline
|
||||||
|
nach umgebrochenen Abstimmungspunkten)
|
||||||
|
- Fehler in Doku der Kommandozeilenoptionen von uvcount.pl behoben
|
||||||
|
(--voters statt --votes)
|
||||||
|
- Date-Header in Englisch erzeugen (statt in eingestellter locale)
|
||||||
|
(verwendet nun Modul Email::Date)
|
||||||
|
- Message-ID-Header selbst erzeugen
|
||||||
|
|
||||||
|
Version 4.08 (06.10.2005):
|
||||||
|
- beim Ignorieren von Regelverletzungen (im Menue mit "Stimmen OK" bestaetigt)
|
||||||
|
wird jetzt keine (dann ja unangebrachte) Fehlermail mehr verschickt.
|
||||||
|
- neuer Buchstabe I bzw. i in usevote.rul, der auf NEIN und ENTHALTUNG matcht.
|
||||||
|
Damit lässt sich eine Stichwahl realisieren, bei der nur für eine von
|
||||||
|
zwei Möglichkeiten mit JA gestimmt werden darf und im anderen Feld entweder
|
||||||
|
NEIN oder ENTHALTUNG (bzw. garnichts, was Enthaltung enspricht)
|
||||||
|
eingetragen werden muss.
|
||||||
|
- analog neuer Buchstabe H bzw. h für JA/ENTHALTUNG, der Vollstaendigkeit halber
|
||||||
|
- uvvote.pl sortiert die Liste der Ergebnisdateien jetzt vorm Zusammenfuegen
|
||||||
|
zur neuen ergebnis.alle, so dass die Reihenfolge auf jeden Fall stimmt,
|
||||||
|
auch wenn das System die Dateien unsortiert liefert
|
||||||
|
- wenn uvcount.pl in der ergebnis.alle auf eine falsche Anzahl von Abstimmungspunkten
|
||||||
|
bei einer Stimme trifft (z.B. versehentlich Leerzeichen oder Buchstabe
|
||||||
|
am Ende einer Zeile zuviel, wenn manuell editiert wurde), bricht es ab und
|
||||||
|
weist auf die fehlerhafte Stimme hin. Vorher wurde das als weiterer
|
||||||
|
Abstimmungspunkt gezählt.
|
||||||
|
- Doku ergänzt: "envelopefrom" bezieht sich nur auf SMTP, ansonsten muss
|
||||||
|
das in "mailcmd" konfiguriert werden
|
||||||
|
- Bug bei Eingruppenmodus behoben: Es wurde immer das selbe ausgegeben,
|
||||||
|
unabhaengig vom Ergebnis (keine 60 Stimmen, keine 2/3 Mehrheit)
|
||||||
|
|
||||||
|
Version 4.07 (26.09.2004):
|
||||||
|
- wenn "nodup=1" gesetzt war, wurden auch keine Annullierungen aussortiert.
|
||||||
|
Ausserdem wurde ansonsten der Wahlleiter unnoetig gefragt, welche
|
||||||
|
Stimme aussortiert werden soll, auch wenn letztlich beide annulliert
|
||||||
|
waren (die Annullierung aber erst spaeter eingegangen war).
|
||||||
|
Um diese Fehler zu beheben, wurde ein zusaetzlicher Verarbeitungsschritt
|
||||||
|
in uvcount.pl eingefuehrt, der sich nur um Annullierungen kuemmert und
|
||||||
|
die gleich am Anfang verarbeitet.
|
||||||
|
- es ist jetzt auch moeglich, nach einer Annullierung mit derselben
|
||||||
|
Mailadresse nochmal abzustimmen. Vorher wurde so eine Stimmabgabe
|
||||||
|
durch die vorher erfolgte Annullierung mit erfasst
|
||||||
|
- Template result-proportional korrigiert. Es kam zu Darstellungsfehlern
|
||||||
|
bei umgebrochenen Gruppennamen/Wahlgegenstaenden (falsche Einrueckung,
|
||||||
|
falscher Umbruch)
|
||||||
|
- Formatfunktion 'generate-date-header' fuer Templates eingefuehrt
|
||||||
|
- Template 'mailheader' um Date-Header ergaenzt
|
||||||
|
- chomp auf Message-ID nur noch machen, wenn eine Message-ID vorhanden ist
|
||||||
|
(gibt sonst Warnung wegen undef)
|
||||||
|
- wenn die Option "mailcc" gesetzt ist, wurden die Hochkommata in der
|
||||||
|
domail-Datei (siehe Changelog von Version 4.06) um beide Adressen gesetzt.
|
||||||
|
Jetzt wird in einer Schleife jede Adresse einzeln gequotet.
|
||||||
|
- RegEx fuer Realnamenserkennung um den Bindestrich erweitert, damit
|
||||||
|
Doppelnamen anerkannt werden
|
||||||
|
|
||||||
|
Version 4.06 (18.06.2004):
|
||||||
|
- Es werden nun "In-Reply-To:" und "References:" Header in den
|
||||||
|
generierten Mails erzeugt
|
||||||
|
- beim Schreiben des domail-Scripts (Verschicken von Mails ohne SMTP)
|
||||||
|
wurde ein fehlerhafter Zeilenumbruch eingefuegt
|
||||||
|
- Leerzeichen am Zeilenende in der usevote.cfg hatten dazu geführt,
|
||||||
|
dass Einstellungen nicht korrekt eingelesen wurden. Jetzt werden
|
||||||
|
beim Einlesen der Konfiguration solche Leerzeichen gelöscht (außer
|
||||||
|
wenn der Teil rechts vom Gleichzeichen durch Anführungsstriche umschlossen
|
||||||
|
ist)
|
||||||
|
- Mailadresse und Waehlername werden jetzt korrekt zurueckgesetzt, so
|
||||||
|
dass bei fehlendem From-Header nicht noch die Daten der vorherigen Mail
|
||||||
|
in den Variablen stehen
|
||||||
|
- Mailadresse wird nun in Hochkommata eingeschlossen, wenn sie in die
|
||||||
|
"domail"-Datei geschrieben wird (bei smtp=0 in usevote.cfg), damit
|
||||||
|
Shell-Metazeichen nicht beim Ausfuehren des MTA interpretiert und damit
|
||||||
|
die Mailadresse veraendert bzw. potentiell schaedlicher Code ausgefuehrt
|
||||||
|
wird
|
||||||
|
- Es ist jetzt moeglich, bei der Warnung "Es wurden nicht alle Fehler behoben,
|
||||||
|
der Waehler wird eine Fehlermail erhalten" zurueck ins Menue zu gehen
|
||||||
|
und die Fehler doch noch zu beheben
|
||||||
|
- in uvcfv.pl (Verschicken von personalisierten Wahlscheinen) einige
|
||||||
|
Bugs behoben [warum hatte das ueberhaupt so funktioniert? Schroedinger
|
||||||
|
laesst gruessen.] und den Hinweistext "Wahlschein wurde bereits einmal
|
||||||
|
zugeschickt" aus dem Perlcode in das Template ballot-personal verlagert
|
||||||
|
- mittels "uvcfv.pl -t" laesst sich jetzt ein personalisierter
|
||||||
|
Dummy-Wahlschein ausgeben (wenn "personal=1" in usevote.cfg), um ihn
|
||||||
|
vorab der dana-Moderation zur Pruefung zukommen lassen zu koennen
|
||||||
|
|
||||||
|
Version 4.05 (27.12.2003):
|
||||||
|
- Aendern von Mailadressen oder Namen im Menue fuehrte zu "keine Scheinkennung"
|
||||||
|
Fehlern, auch wenn die personalisierten Wahlscheine nicht aktiviert waren
|
||||||
|
(personal=0 in usevote.cfg).
|
||||||
|
- Fehler beim Verarbeiten von Mailbox-Files behoben. In den letzten
|
||||||
|
Versionen funktionierte nur POP3.
|
||||||
|
- In Wahlschein-Templates "kann fuer ungueltig erklaert werden" in
|
||||||
|
"wird fuer ungueltig erklaert werden" geaendert (bei falschem Realname)
|
||||||
|
- kosmetische Aenderungen in Templates (Anpassung an neue Rechtschreibung,
|
||||||
|
Entfernung von Umlauten fuer einheitliches Schriftbild)
|
||||||
|
|
||||||
|
Version 4.04 (22.11.2003):
|
||||||
|
- uvcount.pl: Fehler beim Aussortieren von Duplikaten behoben, was
|
||||||
|
i.d.R. nur bei doppelten Mailadressen, nicht aber bei doppelten Namen
|
||||||
|
funktionierte (falsche Regular Expression und Probleme bei
|
||||||
|
unterschiedlicher Gross-/Kleinschreibung der Namen)
|
||||||
|
|
||||||
|
Version 4.03 (19.10.2003):
|
||||||
|
- UVsendmail.pm: Vernuenftige Fehlerbehandlung bei SMTP implementiert:
|
||||||
|
Bei fehlgeschlagenen Zustellversuchen wird jetzt die Datei ack.control
|
||||||
|
passend neu geschrieben, so dass mit "uvvote.pl clean" ein neuer
|
||||||
|
Versuch unternommen werden kann. Vorher wurde zwar eine Fehlermeldung
|
||||||
|
angezeigt, die Mail aber einfach geloescht...
|
||||||
|
- es wird kein Fehler mehr angezeigt, wenn ack.control bereits existiert,
|
||||||
|
da der Code durchaus damit umgehen kann (es wird einfach an die
|
||||||
|
Datei angehaengt). Entsprechende Fehlermeldung aus messages.txt
|
||||||
|
entfernt
|
||||||
|
- Schreibfehler in messages.cfg behoben (ggf. statt ggfls.)
|
||||||
|
- me@privacy.net in mailpatterns.cfg aufgenommen
|
||||||
|
- UIDLs werden jetzt in der Reihenfolge gespeichert, in der die
|
||||||
|
Mails auf dem POP3-Server lagen. Dadurch ist bei einem Abbruch
|
||||||
|
waehrend der Auswertung leichter kontrollierbar, welche Mails noch
|
||||||
|
einmal abgerufen werden sollen (einfach die letzten X UIDLs aus
|
||||||
|
der Datei uidlcache loeschen)
|
||||||
|
- uvcfv.pl, uvbounce.pl und uvvote.pl besitzen jetzt einen Locking-
|
||||||
|
Mechanismus, der ein gleichzeitiges bzw. mehrfaches Starten dieser
|
||||||
|
Programme unterbindet. Andernfalls koennte es zu Inkonsistenzen
|
||||||
|
im Datenbestand kommen (gleichzeitiger Abruf derselben Mailbox,
|
||||||
|
Auswertung noch nicht fertig geschriebener Ergebnisdateien)
|
||||||
|
- es koennen jetzt zusaetzliche Konfigurationsdateien in usevote.cfg
|
||||||
|
eingebunden werden, um z.B. die immer gleichen Einstellungen nur
|
||||||
|
einmal zentral abzulegen. Hierzu einfach eine Zeile
|
||||||
|
include dateiname
|
||||||
|
einfuegen. Die Position ist wichtig: Bei mehrfacher Definition
|
||||||
|
der selben Option gilt die letzte. Daher sollte eine globale
|
||||||
|
Konfigurationsdatei am Anfang eingebunden werden, um die
|
||||||
|
Einstellungen bei Bedarf mit wahlspezifischen ueberschreiben zu
|
||||||
|
koennen
|
||||||
|
|
||||||
|
Version 4.02 (31.05.2003):
|
||||||
|
- UVpath.pm wieder entfernt, da mittlerweile eine bessere Loesung
|
||||||
|
gefunden: Das Modul FindBin wird eingesetzt, um den Pfad der
|
||||||
|
ausgefuehrten .pl Datei zu ermitteln. Wenn die .pm Dateien im selben
|
||||||
|
Verzeichnis liegen, werden sie dort gefunden. Ausserdem wurde der
|
||||||
|
Hinweis auf die Umgebungsvariable PERL5LIB in die README Datei
|
||||||
|
aufgenommen, die ansonsten auch auf den Pfad zu den Usevote-Perlmodulen
|
||||||
|
gesetzt werden kann.
|
||||||
|
|
||||||
|
Version 4.01 (29.05.2003):
|
||||||
|
- Wahlschein-, Result- und Bestaetigungsmail-Templates angepasst, so dass
|
||||||
|
bei langem "votename" ein Umbruch im Wahlschein erfolgt und auch bei einer
|
||||||
|
zweistelligen Anzahl von Wahlgegenstaenden eine buendige Ausgabe erfolgt
|
||||||
|
- uvballot.pl und Template "result-multi" angepasst, so dass bei
|
||||||
|
Mehrgruppenabstimmungen die Anzahl der Enthaltungen nicht ausgegeben
|
||||||
|
wird (laesst sich nicht als Gesamtzahl ermitteln, koennte man hoechstens
|
||||||
|
fuer jede Gruppe einzeln angeben)
|
||||||
|
- Es brauchen jetzt nur noch die Konfigurationsdateien sowie die
|
||||||
|
UVpath.pm in einem Abstimmungsverzeichnis zu liegen, die .pl und .pm
|
||||||
|
Dateien koennen zentral fuer mehrere Abstimmungen abgelegt werden.
|
||||||
|
- Formatierungsfunktion "replace" in UVformats.pm implementiert, mit
|
||||||
|
deren Hilfe die Ersetzung von Zeichen oder Zeichenketten in Templates
|
||||||
|
moeglich ist. Praktische Anwendung ist z.B. die Verfremdung von
|
||||||
|
Mailadressen im Result als trivialer Spamschutz. Wie die Templates
|
||||||
|
dafuer geaendert werden muss, ist in der README Datei im Abschnitt 10
|
||||||
|
beschrieben
|
||||||
|
- Bei den Standard-Funktionen append und justify (inkl. justify-before
|
||||||
|
und justify-behind) wird der uebergebene Key jetzt rekursiv ueber die
|
||||||
|
Formatdefinitionen im Template aufgeloest. Das ermoeglicht die
|
||||||
|
Vorbehandlung eines Wertes, z.B.:
|
||||||
|
mail := value mail | replace '@' '-at-'
|
||||||
|
line := value name | justify-before mail 70
|
||||||
|
Hier wurde vorher die unveraenderte Mailadresse benutzt, jetzt wird
|
||||||
|
die obere Definition beachtet und zunaechst die Ersetzung durchgefuehrt.
|
||||||
|
- Formatierungsfunktion "sprintf" in UVformats.pm implementiert, um
|
||||||
|
z.B. Verhaeltnisse in Results formatiert ausgeben zu koennen
|
||||||
|
- Auswertung nach Verhaeltnis Ja- zu Nein-Stimmen implementiert
|
||||||
|
(in usevote.cfg proportional=1 setzen und prop_formula passend waehlen).
|
||||||
|
Damit ist z.B. fuer jeden Abstimmungsgegenstand das Verhaeltnis oder
|
||||||
|
auch die Differenz zwischen Ja- und Nein-Stimmen ermittelbar. Letzteres
|
||||||
|
wird fuer Moderationsnachwahlen benoetigt. Kombiniert werden kann dies
|
||||||
|
mit einer weiteren Bedingung, z.B. mindestens soviele Ja- wie Nein-Stimmen.
|
||||||
|
|
||||||
|
Version 4.0 (22.03.2003):
|
||||||
|
- UVformats.pm dokumentiert
|
||||||
|
- Defaultwert fuer "formats" korrigiert (UVconfig.pm)
|
||||||
|
- Defaultwert fuer "bdsgfile" fehlte (UVconfig.pm)
|
||||||
|
- kosmetische Aenderung (fehlende Leerzeichen) an Template result-multi
|
||||||
|
- Windows-Pager-Empfehlung in README und usevote.cfg geaendert (vorher
|
||||||
|
wurde "more" empfohlen, da mitgeliefert, aber more ist so buggy, dass
|
||||||
|
jetzt die Installation von "less" nahegelegt wird
|
||||||
|
- Fehler in UVsendmail.pm behoben: Wenn beim "uvvote.pl clean" Aufruf keine
|
||||||
|
Mails zu verschicken waren, wurde das Programm in UVsendmail::send()
|
||||||
|
einfach mit "exit 0" beendet (korrigiert in "return 0"). Ausserdem
|
||||||
|
wurde die Fehlermeldung wegen eines Schreibfehlers im Konstantennamen
|
||||||
|
nicht angezeigt.
|
||||||
|
|
||||||
|
Version 4.0beta15:
|
||||||
|
- Fehlermeldung bei nicht vorhandener messages.cfg korrigiert
|
||||||
|
(Dateiname wurde wegen falschen Configschluessels nicht angezeigt)
|
||||||
|
- Bei manuell eingegebener Scheinkennung wurde irrtuemlicherweise eine
|
||||||
|
Fehlermeldung angezeigt, auch wenn die Kennung zur Mailadresse passte
|
||||||
|
- Bei neu eingegebener Mailadresse wurde die Zugehoerigkeit der
|
||||||
|
Scheinkennung nicht neu geprueft
|
||||||
|
- bei nicht erkannten Abstimmungspunkten im Wahlschein wurde eine
|
||||||
|
Warnmeldung angezeigt, die auf Nicht-Wertung hinwies. In Wirklichkeit
|
||||||
|
wurde die Stimme aber normal bestaetigt und lediglich alle nicht erkannten
|
||||||
|
Punkte als "Enthaltung" gewertet. Die Warnmeldung erscheint jetzt nicht
|
||||||
|
mehr, um keine Verwirrung zu stiften.
|
||||||
|
- Fehler in UVmessage.pm behoben: Der Wert 0 wurde durch den leeren String
|
||||||
|
ersetzt. Jetzt wird defined() eingesetzt statt auf true/false zu pruefen.
|
||||||
|
- Fehler in UVsendmail.pm behoben: Wenn kein SMTP aktiviert war, wurde
|
||||||
|
die "domail" Datei mit den MTA-Aufrufen zwar geschrieben, aber nicht
|
||||||
|
ausgefuehrt. Dadurch schlug auch das Loeschen der Temp-Dateien fehl,
|
||||||
|
was beim naechsten Aufruf Fehlermeldungen verursachte.
|
||||||
|
- Templates eingebaut
|
||||||
|
- acktext.txt durch Templates ersetzt. BDSG-Text ist jetzt in der
|
||||||
|
Datei bdsgtext.cfg
|
||||||
|
- "cfvfile" Option entfernt (nicht mehr noetig, durch Templates abgeloest)
|
||||||
|
- Bedingungen fuer Wahlerfolg ueber usevote.cfg konfigurierbar gemacht.
|
||||||
|
Standardwerte:
|
||||||
|
condition1 = $yes>=2*$no
|
||||||
|
condition2 = $yes>=60
|
||||||
|
- usevote.cfg bzgl. der Ueberschriften "jedes Mal anpassen" / "nur einmal
|
||||||
|
anpassen" ein wenig umsortiert
|
||||||
|
- wenn kein "smtphelo" definiert wurde, wird jetzt der eigene
|
||||||
|
Hostname genommen
|
||||||
|
- README an aktuelle Aenderungen angepasst (Dateilisten, Beschreibungen
|
||||||
|
der Menues) und vervollstaendigt
|
||||||
|
|
||||||
|
Version 4.0beta14:
|
||||||
|
- Fehler in UVmenu.pm behoben, der beim Auswaehlen von
|
||||||
|
"Stimmen vom Waehler annulliert" im Menue auftrat
|
||||||
|
- Erkennung von doppelten, sich widersprechenden Stimmabgaben in einer
|
||||||
|
Mail funktioniert jetzt
|
||||||
|
- beim Verschicken per SMTP gibt es die neue Option envelopefrom, die
|
||||||
|
die Absenderadresse im Envelope (Return-Path) enthaelt, an die auch
|
||||||
|
Bounces zurueckgehen
|
||||||
|
- Neu: Erkennung von fehlenden Abstimmungspunkten im Wahlschein, Behandlung
|
||||||
|
wie bei unleserlichen Stimmabgaben mit entsprechendem Hinweis im Menue
|
||||||
|
- Fehler in uvvote.pl behoben, der bei unleserlichen Stimmabgaben auftrat
|
||||||
|
- statt encode_mimewords wird jetzt encode_mimeword verwendet und das
|
||||||
|
"Drumherum" komplett selbst gemacht. Man schaue in den Code von
|
||||||
|
MIME::Words::encode_mimewords(), dann weiss man, warum ;-)
|
||||||
|
- Weitere Texte in messages.txt ausgelagert (uvvote.pl, uvcount.pl)
|
||||||
|
- config test (-t Option) gibt jetzt auch Auskunft ueber die Konfiguration
|
||||||
|
(falls Option nicht in usevote.cfg gesetzt, wird der Standardwert
|
||||||
|
ausgegeben)
|
||||||
|
|
||||||
|
Version 4.0beta13:
|
||||||
|
- Fehlerbehandlung bei SMTP eingefuehrt, so dass keine Mails verloren gehen
|
||||||
|
- es laesst sich jetzt ein anderer Port fuer SMTP/POP3 angeben
|
||||||
|
- uvbounce.pl benutzt jetzt auch POP3, falls dieses in usevote.cfg aktiviert
|
||||||
|
wurde. Mit der Option -f ist aber unabhaengig davon das Einlesen der
|
||||||
|
Bounces aus einer Datei in jedem Fall moeglich
|
||||||
|
- auftretende Fehler beim Ausfuehren von uvvote.pl werden jetzt in eine
|
||||||
|
Datei geschrieben und beim Verlassen wird darauf hingewiesen
|
||||||
|
- Wenn das interaktive Menue ausgeblendet und dazu der Bildschirm geloescht
|
||||||
|
wird, informiert jetzt eine Meldung darueber, dass Mails verarbeitet werden
|
||||||
|
- Menues so umgestellt, dass [a] immer fuer "alles OK" steht, egal ob
|
||||||
|
Mailadresse, Name, Stimmen oder die BDSG-Klausel strittig sind
|
||||||
|
- Ausgaben/Texte von UVreadmail.pm und UVsendmail.pm nach messages.txt
|
||||||
|
ausgelagert
|
||||||
|
- Verzeichnisnamen "fertig" und "tmp" jetzt konfigurierbar
|
||||||
|
- Zeilen "Waehleradresse: " und "Wahlscheinkennung: " im Wahlschein
|
||||||
|
konfigurierbar gemacht
|
||||||
|
- Pager konfigurierbar gemacht (vorher immer "more") und standardmaessig
|
||||||
|
auf "less" gesetzt, weil "more" mit der Umleitung von STDERR Probleme hat
|
||||||
|
- kleinere Bugs behoben
|
||||||
|
|
||||||
|
Version 4.0beta12:
|
||||||
|
- Fehler in Menue behoben
|
||||||
|
- im Menue kann man jetzt explizit Stimmen ungueltig werten, indem man
|
||||||
|
den Namen, die Adresse oder die Stimmen ungueltig macht. Es wird eine
|
||||||
|
passende Fehlermail generiert.
|
||||||
|
- genauso kann man jetzt explizit annullieren (sinnvoll, falls der Waehler
|
||||||
|
z.B. "annullierung" falsch buchstabiert hat *g*), wobei automatisch
|
||||||
|
diverse andere Probleme als irrelevant erkannt werden (z.B. braucht man
|
||||||
|
in dem Fall keinen Datenschutzhinweis zu akzeptieren und nicht unbedingt
|
||||||
|
einen Namen anzugeben, falls die Adresse stimmt)
|
||||||
|
- MIME-Kodierung fuer Subject- und From-Header in UVsendmail.pm eingefuehrt
|
||||||
|
- In Bestaetigungsmails gibt es jetzt kein gesondertes Feld mehr zum
|
||||||
|
Korrigieren des Namens, sondern es kann einfach die ohnehin vorhandene
|
||||||
|
Zeile "Wahlername: Vorname Nachname" editiert werden.
|
||||||
|
- "nametext2" in usevote.cfg ist jetzt "Waehlername:" und wird auch
|
||||||
|
statt des fest kodierten Strings an den entsprechenden Codestellen
|
||||||
|
verwendet
|
||||||
|
- uvcount.pl: Bugs bei Annullierungen und fehlendem Namen behoben
|
||||||
|
- uvbounce an geaendertes UVreadmail.pm angepasst (funktioniert bei
|
||||||
|
Aktivierung des POP3-Zugriffs nicht mehr)
|
||||||
|
- saemtliche Ausgaben/Texte in UVmenu.pm nach messages.txt ausgelagert
|
||||||
|
|
||||||
|
Version 4.0beta11:
|
||||||
|
- kompletter Rewrite der Ueberpruefungsfunktionen in uvvote.pl und UVmenu.pl.
|
||||||
|
Es werden jetzt alle Fehler an ein Array angehaengt und in einem Rutsch
|
||||||
|
von der Menue-Funktion verarbeitet. Fuer Darstellung der Votemail wird
|
||||||
|
"more" benutzt.
|
||||||
|
|
||||||
|
Version 4.0beta10:
|
||||||
|
- Zeilenumbrueche richten sich jetzt nach der "rightmargin"-Einstellung
|
||||||
|
aus usevote.cfg (vorher waren die Zeilenlaengen teilweise noch hartkodiert)
|
||||||
|
- Fehler beim Erstellen des domail-Scripts behoben
|
||||||
|
- kosmetische Code-Aenderungen
|
||||||
|
|
||||||
|
Version 4.0beta9:
|
||||||
|
- Auch bei zurueckgeschickten (korrigierten) Wahlbestaetigungen wird
|
||||||
|
jetzt der Name automatisch im Body erkannt (Zeile "Waehlername:").
|
||||||
|
- Regular Expressions zur Stimmerkennung geaendert: Manche komische
|
||||||
|
Mailprogramme benutzen zum Kodieren von Leerzeichen =A0, was aber
|
||||||
|
nach der Dekodierung nicht als \s erkannt wird. \W ist nicht optimal,
|
||||||
|
aber funktioniert.
|
||||||
|
- uvbounce.pl: Bounces von Antworten auf Wahlscheinanforderungen werden
|
||||||
|
jetzt erkannt und mit einem gesonderten Hinweis gekennzeichnet
|
||||||
|
("Wahlschein nicht zustellbar")
|
||||||
|
- in den Config Files koennen die Kommentarzeichen escaped werden: \#
|
||||||
|
|
||||||
|
Version 4.0beta8:
|
||||||
|
- beim Einlesen aus usevote.cfg wird ein eventuelles \r geloescht
|
||||||
|
- es werden nicht mehr jedes Mal saemtliche Mails abgerufen (bei POP3),
|
||||||
|
sondern es wird mit dem UIDL Kommando geprueft, ob schon ein vorheriger
|
||||||
|
Abruf stattfand. Ausserdem ist es jetzt moeglich, die Mails vom Server
|
||||||
|
zu loeschen.
|
||||||
|
- uvcfv.pl kann jetzt auch richtig mit POP3 umgehen
|
||||||
|
- Platzhalter im Wahlschein bei personalisierten Wahlscheinen geaendert
|
||||||
|
- Aktuelle Werte werden teilweise jetzt im Menue angezeigt (wenn man
|
||||||
|
Stimmen, Name oder Mailadresse neu gesetzt hat)
|
||||||
|
- Dokumentation verbessert
|
||||||
|
|
||||||
|
Version 4.0beta7:
|
||||||
|
- kosmetische Code-Aenderungen (Vereinfachungen, Verschoenerungen, ...)
|
||||||
|
- Inhalt der Datei bdsgtext.txt als Abschnitt [BDSG Hinweis] in
|
||||||
|
acktext.txt uebernommen (es gibt keinen Grund dafuer, dass dieser
|
||||||
|
Text eine eigene Datei bekommen sollte...)
|
||||||
|
- Testweise einige Programm-Meldungen in externe Datei (meldungen.cfg)
|
||||||
|
ausgelagert, um eine leichtere Anpassung zu ermoeglichen (z.B.
|
||||||
|
Uebersetzung in andere Sprachen). Nach und nach werden saemtliche
|
||||||
|
Meldungen in diese Konfigurationsdatei wandern.
|
||||||
|
- acktext.txt in acktext.cfg umbenannt: Alle Konfigurationsdateien
|
||||||
|
haben damit die Endung .cfg
|
||||||
|
- POP3-Abruf und Verschicken per SMTP eingebaut
|
||||||
|
- Shellbefehl-Aufrufe (chmod- und mkdir) durch Perl-Pendants ersetzt,
|
||||||
|
um Plattformunabhaengigkeit zu bieten
|
||||||
|
- In uvcfv.pl Doppelung im Mailsubject geloescht
|
||||||
|
- In uvcount.pl stimmte die Zuordnung von Abstimmungsgegenstand zur
|
||||||
|
einzelnen Stimmabgabe nicht (umgekehrte Reihenfolge)
|
||||||
|
- in UVmenu.pm entstand bei Mehrgruppenabstimmungen der Kommentar
|
||||||
|
"Wahlleiter setzte Stimmen, Stimmen, Stimmen" (jetzt nur noch
|
||||||
|
einmal gesetzt statt fuer jede Gruppe)
|
||||||
|
- Falls keine Scheinkennung und keine BDSG-Zustimmung: Bislang wurden
|
||||||
|
dann zwei Mails generiert (keine Abfrage auf bereits aufgetretenen
|
||||||
|
Fehler), nun behoben
|
||||||
|
|
||||||
|
Version 4.0beta6:
|
||||||
|
- RegExp fuer Namensangabe im Body verbessert (wenn kein Name angegeben
|
||||||
|
wurde und auch im Header keiner zu finden war, wurde der nachfolgende
|
||||||
|
Hinweissatz "Wenn Du keinen Namen angibst..." als Realname erkannt
|
||||||
|
- RegExp fuer Namenserkennung konfigurierbar gemacht (usevote.cfg)
|
||||||
|
und um Accents erweitert
|
||||||
|
- RegExp fuer Erkennung verdaechtiger Adressen trifft jetzt nur noch
|
||||||
|
zu, wenn der String direkt am Anfang der Adresse steht. Gegenteiliges
|
||||||
|
Verhalten kann durch Wildcards herbeigefuehrt werden
|
||||||
|
- Statt manuellen Trennens von Header und Body wird in UVreadmail.pm
|
||||||
|
jetzt das Modul MIME::Parser eingesetzt
|
||||||
|
- kleinere Bugs behoben (z.B. einfache vs. doppelte Anfuehrungsstriche)
|
||||||
|
- Fehler bei UVmenu::menu-Aufruf im Falle von "keine Stimmen" behoben
|
||||||
|
(eine Variable fehlte in der Uebergabeliste)
|
||||||
|
- uvcount.pl um Eingruppen-Format ergaenzt
|
||||||
|
- uvballot.pl um Option -t ergaenzt, um eine Vorlage fuer cfv.txt bei
|
||||||
|
Verwendung von personalisierten Wahlscheinen zu erzeugen
|
||||||
|
- uvbounce.pl zur Generierung von ungueltigen Adressen aus einer
|
||||||
|
Mailbox mit Bounces implementiert
|
||||||
|
- Bei Annullierungen wird jetzt nicht mehr die BDSG-Klausel geprueft
|
||||||
|
(es erfolgt ja ohnehin eine Loeschung der Stimmabgabe)
|
||||||
|
- Statt Mail::Field wird nun eine eigene RegExp verwendet (Danke an
|
||||||
|
Marc Brockschmidt fuer die Idee), Mail::Field hat einige unschoene Bugs.
|
||||||
|
- Bei nicht erkannten Stimmabgaben bei Abstimmungen mit nur einem
|
||||||
|
Abstimmungsgegenstand wird nun auch die Ungueltigwertung angeboten
|
||||||
|
(als Alternative zu "Enthaltung").
|
||||||
|
|
||||||
|
Version 4.0beta5:
|
||||||
|
- die Mailboxdatei wird nun vor der Verarbeitung verschoben, so dass waehrend
|
||||||
|
des uvvote-Laufs keine neuen Mails angehaengt werden koennen
|
||||||
|
- es wird jetzt fuer jeden Durchlauf eine gesonderte Ergebnisdatei angelegt
|
||||||
|
- neu eingefuehrter Parameter "clean", der Bestaetigungen verschickt,
|
||||||
|
Ergebnisdatei und die Mailbox in das Verzeichnis fertig/ verschiebt,
|
||||||
|
temporaere Dateien loescht und aus allen Einzelergebnissen eine neue
|
||||||
|
Gesamtergebnisdatei (normalerweise "ergebnis.alle") erstellt
|
||||||
|
- dadurch sind jetzt zwei Durchgaenge erforderlich: Erster Aufruf ohne
|
||||||
|
die Option "clean" (Erzeugt die Ergebnisse und Mailvorlagen), dann kann
|
||||||
|
eine Kontrolle erfolgen, anschliessend ein weiterer Aufruf mit der Option
|
||||||
|
"clean" zum Aufraeumen und Verschicken der Bestaetigungen
|
||||||
|
- neues Modul UVsendmail.pm, in das die Funktion zum Erstellen von
|
||||||
|
Mails ausgelagert wurde
|
||||||
|
- neues Modul UVmenu.pm mit der Menuefunktionalitaet zum interaktiven
|
||||||
|
Eingriff in die Stimmwertung
|
||||||
|
- Bugs bei Stimmaufzeichnung behoben: Fehlerhafte Stimmen wurden teilweise
|
||||||
|
nicht in der Ergebnisdatei vermerkt. Ausserdem wurde nicht konsequent
|
||||||
|
auf die Option "voteack" geprueft
|
||||||
|
- Reply-To kann jetzt beachtet werden (muss in usevote.cfg eingeschaltet
|
||||||
|
werden) und ueberschreibt das From. Mit Vorsicht zu geniessen, da so
|
||||||
|
jeder Waehler fuer andere Stimmen abgeben und die Bestaetigungen zu
|
||||||
|
sich umlenken kann!
|
||||||
|
- Umgang mit personalisierten Wahlscheinen (Abschnitt 6a der Wahlregeln
|
||||||
|
fuer de.*), Generierung und Pruefung von Scheinkennungen. Siehe Optionen
|
||||||
|
"personal" und "idfile" in usevote.cfg sowie das Programm uvcfv.pl zum
|
||||||
|
Verschicken der persoenlichen Wahlscheine
|
||||||
|
- Das Flag beim Aufruf der Menuefunktion ist jetzt ein Hash, in dem
|
||||||
|
diverse Werte ueber- und zurueckgegeben werden. Dadurch auch feine
|
||||||
|
Steuerung der aktiven Menuepunkte moeglich
|
||||||
|
- Ausgabe der Fehlermeldung in UVmenu.pm verlagert (wird in besagtem
|
||||||
|
Hash uebergeben)
|
||||||
|
- Kommentarfeld fuer Ergebisdatei ("Wahlleiter setzte xyz") wird erst
|
||||||
|
zum Schluss erzeugt, vorher werden nur die vom Wahlleiter manuell
|
||||||
|
veraenderten Felder in einem Array mitgefuehrt
|
||||||
|
- uvcfv.pl zum Generieren der persoenlichen Wahlscheine und Verschicken
|
||||||
|
des CfVs implementiert
|
||||||
|
- Bisherige Funktionalitaet von uvack, uvcount, uvdup in uvcount.pl
|
||||||
|
implementiert
|
||||||
|
- uvballot.pl zum Erstellen eines Musterwahlscheins
|
||||||
|
- uvcfv.pl: Es wird nun auch die Vollstaendigkeit von $config{bdsgtext}
|
||||||
|
im Wahlschein geprueft und bei Auswahl von "Ende+Speichern" wird
|
||||||
|
noch einmal zur Sicherheit gefragt, ob die Stimme wirklich
|
||||||
|
gespeichert und verarbeitet werden soll
|
||||||
|
- Kompatibilitaetsprobleme mit Perl 5.6.1 bei Variablenzuweisungen behoben
|
||||||
|
|
||||||
|
Version 4.0beta4:
|
||||||
|
- bei Regelverletzung wird jetzt ein interaktives Menue aufgerufen,
|
||||||
|
so dass der Wahlleiter entscheiden kann, was er machen will
|
||||||
|
- Stimmerkennung legt unbekannte Vote-Strings (nicht Ja, Nein,
|
||||||
|
Enthaltung oder Annullierung) jetzt dem Wahlleiter vor und
|
||||||
|
laesst ihn entscheiden (Default ist Enthaltung). Fehlermail ist
|
||||||
|
in so einem Fall bislang nicht vorgesehen, laesst sich aber noch
|
||||||
|
einbauen, falls erforderlich. Wenn der Waehler die Bestaetigung
|
||||||
|
ueberprueft, reicht es auch, wenn dort "Enthaltung" auftaucht...
|
||||||
|
- Pruefung auf vollstaendige Bestaetigung der Datenschutz-Klausel
|
||||||
|
ist implementiert und ueber usevote.cfg und bdsgtext.txt konfigurierbar
|
||||||
|
- Regelpruefung kompakter und dreimal schneller gemacht (Idee von
|
||||||
|
Cornell Binder), dafuer Code schlechter lesbar... aber dokumentiert ;-)
|
||||||
|
- Alle Regel-Subs in UVrules.pm ausgelagert
|
||||||
|
|
||||||
|
Version 4.0beta3:
|
||||||
|
- Einlesen und Testen der Konfiguration sowie Ausgabe der Regeln
|
||||||
|
im Klartext sind jetzt im externen Modul UsevoteConfig.pm untergebracht
|
||||||
|
- Das Einlesen der Mail und MIME-Bearbeitung erfolgt wurde in das
|
||||||
|
Modul UsevoteReadmail.pm ausgelagert
|
||||||
|
- verdaechtige Mailadressen werden nun in einer gesonderten Datei
|
||||||
|
konfiguriert (Default: mailpatterns.cfg)
|
||||||
|
- Fehler bei Parsing von %body% und %headbody% in acktext.txt behoben
|
||||||
|
|
||||||
|
Version 4.0beta2:
|
||||||
|
- Auslagerung des Abschnittes [Realname Info] nach acktext.txt
|
||||||
|
(vorher hardcoded)
|
||||||
|
- Einfuehrung des Platzhalters %version% fuer acktext.txt
|
||||||
|
- Einfuehrung der Option voteack (Einzelbestaetigung kann deaktiviert werden)
|
||||||
|
- saemtliche Konfigurationsoptionen sind nun mit Defaultwerten belegt,
|
||||||
|
aber wahlspezifische Optionen (Gruppennamen etc.) muessen natuerlich
|
||||||
|
auf jeden Fall gesetzt werden
|
||||||
|
- Aenderung der Stimmerkennungsmethode. Um problemlos mit eigenwilligen
|
||||||
|
Zeilenumbruechen diverser schrottiger Software umgehen zu koennen,
|
||||||
|
wird ein Identifier an den Zeilenanfang gesetzt und direkt dahinter
|
||||||
|
die Stimme. Der Gruppenname kann dann ruhig umgebrochen sein.
|
||||||
|
|
||||||
|
Version 4.0beta1:
|
||||||
|
- kompletter Rewrite in Perl. Noch ziemlich unvollstaendig (nur uvvote.pl)
|
||||||
|
|
||||||
|
bis Version 3.1beta7 (Wolfgang Behrens):
|
||||||
|
- Funktionialitaet fuer persoenliche Wahlschein eingebaut
|
||||||
|
- Reply-To Auswertung u.a. auf GVV-Beduerfnisse angepasst
|
||||||
|
|
||||||
|
Version Usevote 3.0a
|
||||||
|
- Uebersetzung ins Deutsche und Anpassung an Wahlregeln in de.*
|
||||||
|
(Frederik Ramm)
|
||||||
|
|
||||||
|
Version Usevote 3.0
|
||||||
|
- Urversion von Ron Dippold (Englisch), nicht an hiesige Wahlregeln angepasst
|
339
COPYING
Normal file
339
COPYING
Normal file
|
@ -0,0 +1,339 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
675 Mass Ave, Cambridge, MA 02139, USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) 19yy <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Library General
|
||||||
|
Public License instead of this License.
|
329
UVconfig.pm
Normal file
329
UVconfig.pm
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
# UVconfig: Reads config files and tests configuration
|
||||||
|
# Used by all components
|
||||||
|
|
||||||
|
package UVconfig;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Net::Domain qw(hostname hostfqdn hostdomain);
|
||||||
|
use UVmessage;
|
||||||
|
use vars qw(@ISA @EXPORT $VERSION $usevote_version %config %messages
|
||||||
|
@rules @groups $bdsg_regexp $bdsg2_regexp %ids %functions);
|
||||||
|
|
||||||
|
require Exporter;
|
||||||
|
@ISA = qw(Exporter);
|
||||||
|
@EXPORT = qw($usevote_version %config %messages @rules @groups
|
||||||
|
$bdsg_regexp $bdsg2_regexp %ids %functions);
|
||||||
|
|
||||||
|
# Module version
|
||||||
|
$VERSION = "0.18";
|
||||||
|
|
||||||
|
# Usevote version
|
||||||
|
$usevote_version = "UseVoteGer 4.09";
|
||||||
|
|
||||||
|
sub read_config {
|
||||||
|
|
||||||
|
my ($cfgfile, $redir_errors) = @_;
|
||||||
|
|
||||||
|
# Default configuration options (overwritten in usevote.cfg)
|
||||||
|
%config = (votefile => "votes",
|
||||||
|
votename => "unkonfiguriertes Usevote",
|
||||||
|
resultfile => "ergebnis.alle",
|
||||||
|
rulefile => "usevote.rul",
|
||||||
|
badaddrfile => "mailpatterns.cfg",
|
||||||
|
messagefile => "messages.cfg",
|
||||||
|
idfile => "scheinkennungen",
|
||||||
|
requestfile => "anforderung",
|
||||||
|
errorfile => "errors.log",
|
||||||
|
lockfile => "usevote.lock",
|
||||||
|
replyto => 0,
|
||||||
|
personal => 0,
|
||||||
|
proportional => 0,
|
||||||
|
bdsg => 0,
|
||||||
|
onestep => 0,
|
||||||
|
multigroup => 0,
|
||||||
|
voteack => 1,
|
||||||
|
voteaccount => "<> (unkonfiguriertes Usevote)",
|
||||||
|
mailfrom => "<> (unkonfiguriertes Usevote)",
|
||||||
|
envelopefrom => "<>",
|
||||||
|
mailstart => "^From ",
|
||||||
|
archivedir => "fertig",
|
||||||
|
tmpdir => "tmp",
|
||||||
|
templatedir => "templates",
|
||||||
|
formats => "UVformats.pm",
|
||||||
|
domailfile => "tmp/domail",
|
||||||
|
controlfile => "tmp/ack.control",
|
||||||
|
mailcmd => "sendmail -oi -oem",
|
||||||
|
mailcc => "",
|
||||||
|
sleepcmd => "sleep 1",
|
||||||
|
clearcmd => "clear",
|
||||||
|
pager => "less",
|
||||||
|
pop3 => 0,
|
||||||
|
pop3server => "localhost",
|
||||||
|
pop3port => 110,
|
||||||
|
pop3user => "default",
|
||||||
|
pop3pass => "default",
|
||||||
|
pop3delete => 0,
|
||||||
|
pop3uidlcache => "uidlcache",
|
||||||
|
pop3server_req => "localhost",
|
||||||
|
pop3port_req => 110,
|
||||||
|
pop3user_req => "default",
|
||||||
|
pop3pass_req => "default",
|
||||||
|
pop3delete_req => 0,
|
||||||
|
pop3uidlcache_req => "uidlcache_req",
|
||||||
|
pop3server_bounce => "localhost",
|
||||||
|
pop3port_bounce => 110,
|
||||||
|
pop3user_bounce => "default",
|
||||||
|
pop3pass_bounce => "default",
|
||||||
|
pop3delete_bounce => 0,
|
||||||
|
pop3uidlcache_bounce => 'uidlcache_bounce',
|
||||||
|
smtp => 0,
|
||||||
|
smtpserver => 'localhost',
|
||||||
|
smtpport => 25,
|
||||||
|
smtphelo => hostfqdn(),
|
||||||
|
fqdn => hostfqdn(),
|
||||||
|
smtpauth => 0,
|
||||||
|
smtpuser => '',
|
||||||
|
smtppass => '',
|
||||||
|
name_re => '[a-zA-ZäöüÄÖÜß-]{2,} +.*[a-zA-ZäöüÄÖÜß]{2,}',
|
||||||
|
ja_stimme => '(J\s*A|J|(D\s*A\s*)?F\s*U\s*E\s*R)',
|
||||||
|
nein_stimme => '(N\s*E\s*I\s*N|N|(D\s*A\s*)?G\s*E\s*G\s*E\s*N)',
|
||||||
|
enth_stimme => '(E|E\s*N\s*T\s*H\s*A\s*L\s*T\s*U\s*N\s*G)',
|
||||||
|
ann_stimme => 'A\s*N\s*N\s*U\s*L\s*L\s*I\s*E\s*R\s*U\s*N\s*G',
|
||||||
|
condition1 => '$yes>=2*$no', # twice as many yes as no
|
||||||
|
condition2 => '$yes>=60', # min 60 yes votes
|
||||||
|
prop_formula => '$yes/$no',
|
||||||
|
tpl_ack_mail => 'ack-mail',
|
||||||
|
tpl_bouncelist => 'bouncelist',
|
||||||
|
tpl_mailheader => 'mailheader',
|
||||||
|
tpl_result_multi => 'result-multi',
|
||||||
|
tpl_result_single => 'result-single',
|
||||||
|
tpl_result_prop => 'result-proportional',
|
||||||
|
tpl_votes_multi => 'votes-multi',
|
||||||
|
tpl_votes_single => 'votes-single',
|
||||||
|
tpl_voterlist => 'voterlist',
|
||||||
|
tpl_ballot => 'ballot',
|
||||||
|
tpl_ballot_request => 'ballot-request',
|
||||||
|
tpl_ballot_personal => 'ballot-personal',
|
||||||
|
tpl_addr_reg => 'address-not-registered',
|
||||||
|
tpl_no_ballotid => 'no-ballotid',
|
||||||
|
tpl_wrong_ballotid => 'wrong-ballotid',
|
||||||
|
tpl_bdsg_error => 'bdsg-error',
|
||||||
|
tpl_cancelled => 'cancelled',
|
||||||
|
tpl_invalid_account => 'invalid-account',
|
||||||
|
tpl_invalid_name => 'invalid-name',
|
||||||
|
tpl_multiple_votes => 'multiple-votes',
|
||||||
|
tpl_no_ballot => 'no-ballot',
|
||||||
|
tpl_no_votes => 'no-votes',
|
||||||
|
tpl_rule_violated => 'rule-violated',
|
||||||
|
begin_divider => 'Alles vor dieser Zeile bitte loeschen',
|
||||||
|
end_divider => 'Alles nach dieser Zeile bitte loeschen',
|
||||||
|
nametext => 'Dein Realname, falls nicht im FROM-Header:',
|
||||||
|
nametext2 => 'Waehlername:',
|
||||||
|
addresstext => 'Waehleradresse:',
|
||||||
|
ballotidtext => 'Wahlscheinkennung:',
|
||||||
|
bdsgtext => 'Datenschutzklausel - Zustimmung',
|
||||||
|
bdsgfile => 'bdsgtext.cfg',
|
||||||
|
rightmargin => 72,
|
||||||
|
usevote_version => $usevote_version); # needed for use in templates
|
||||||
|
|
||||||
|
# read config
|
||||||
|
read_file($cfgfile);
|
||||||
|
|
||||||
|
# read message file
|
||||||
|
open (RES, "<$config{messagefile}")
|
||||||
|
or die "Could not read message file $config{messagefile}!\n\n";
|
||||||
|
my @lines = <RES>;
|
||||||
|
close(RES);
|
||||||
|
|
||||||
|
foreach my $line (@lines) {
|
||||||
|
chomp($line);
|
||||||
|
$line =~ s/^#.*//; # Delete comments
|
||||||
|
if ($line =~ m/^\s*([A-Za-z0-9_-]+)\s*=\s*(.+)\s*$/){
|
||||||
|
$messages{$1} = $2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# missing "groupX =" lines in config file?
|
||||||
|
die UVmessage::get("CONF_NOGROUPS", CONFIGFILE=>$cfgfile) . "\n\n" unless (@groups);
|
||||||
|
|
||||||
|
# redirect errors to a file if desired by calling script
|
||||||
|
open (STDERR, ">$config{errorfile}") if ($redir_errors);
|
||||||
|
|
||||||
|
# check for data protection law? read text for ballot
|
||||||
|
parse_bdsgtext() if ($config{bdsg});
|
||||||
|
|
||||||
|
# personalized ballots? read ballot IDs
|
||||||
|
read_ballot_ids() if ($config{personal});
|
||||||
|
|
||||||
|
load_formats() if ($config{formats});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# read config file #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub read_file {
|
||||||
|
|
||||||
|
my $cfgfile = shift;
|
||||||
|
my $CONFIG;
|
||||||
|
open ($CONFIG, "<$cfgfile") or die "Could not find config file $cfgfile!\n\n";
|
||||||
|
|
||||||
|
while (<$CONFIG>) {
|
||||||
|
next if (/^#/); # line is a comment
|
||||||
|
chomp; # delete \n
|
||||||
|
s/\r//; # delete \r if present
|
||||||
|
s/([^\\])#.*$/$1/; # Remove comments not starting at beginning of line.
|
||||||
|
# (ignore escaped comment sign \#)
|
||||||
|
|
||||||
|
|
||||||
|
if (/^include (\S+)$/) {
|
||||||
|
# include other config file
|
||||||
|
read_file($1);
|
||||||
|
|
||||||
|
} elsif (my($key, $value) = split (/\s*=\s*/, $_, 2)) {
|
||||||
|
# delete trailing spaces
|
||||||
|
$value =~ s/\s*$//;
|
||||||
|
|
||||||
|
# evaluate quotation marks
|
||||||
|
$value =~ s/^\"([^\"]+[^\\\"])\".*$/$1/;
|
||||||
|
$value =~ s/\\"/"/g;
|
||||||
|
|
||||||
|
if ($key =~ /^group(\d+)$/) {
|
||||||
|
my $num = $1;
|
||||||
|
$groups[$num-1] = $value; # internal index starts at 0
|
||||||
|
} else {
|
||||||
|
$config{$key} = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close ($CONFIG);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# parse data protection law texts #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub parse_bdsgtext {
|
||||||
|
|
||||||
|
open (BDSG, "<$config{bdsgfile}") or die UVmessage::get("CONF_NOBDSGFILE",
|
||||||
|
('BDSGFILE' => "$config{bdsgfile}")) . "\n\n";
|
||||||
|
my @bdsg = <BDSG>;
|
||||||
|
close BDSG;
|
||||||
|
|
||||||
|
$config{bdsginfo} = '';
|
||||||
|
|
||||||
|
foreach my $line (@bdsg) {
|
||||||
|
$config{bdsginfo} .= $line unless ($line =~ /^\s*#/);
|
||||||
|
}
|
||||||
|
|
||||||
|
my $bdsgtmp = $config{bdsginfo};
|
||||||
|
$bdsgtmp =~ s/\"/\\\"/g;
|
||||||
|
$bdsgtmp =~ s/\'/\\\'/g;
|
||||||
|
$bdsgtmp =~ s/\(/\\\(/g;
|
||||||
|
$bdsgtmp =~ s/\)/\\\)/g;
|
||||||
|
$bdsgtmp =~ s/\[/\\\[/g;
|
||||||
|
$bdsgtmp =~ s/\]/\\\]/g;
|
||||||
|
$bdsgtmp =~ s/\./\\\./g;
|
||||||
|
$bdsgtmp =~ s/\!/\\\!/g;
|
||||||
|
my @bdsgtext = split(' ', $bdsgtmp);
|
||||||
|
|
||||||
|
# Build Regular Expression from single words.
|
||||||
|
# There has to be at least a space between two words, additional characters
|
||||||
|
# are allowed, e.g. quotation marks (but no letters)
|
||||||
|
$bdsg_regexp = join('\s\W*?', @bdsgtext);
|
||||||
|
|
||||||
|
# Build Regular Expression from $config{bdsgtext}
|
||||||
|
$bdsg2_regexp = join('\s\W*?', split(' ', $config{bdsgtext}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Read suspicious mail addresses (normally mailpatterns.cfg) #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub read_badaddr {
|
||||||
|
|
||||||
|
my @bad_addr = ();
|
||||||
|
|
||||||
|
open (BADADDR, "<$config{badaddrfile}") or die
|
||||||
|
UVmessage::get("CONF_NOBADADDR",(BADADDRFILE => $config{badaddrfile})) . "\n\n";
|
||||||
|
|
||||||
|
while (<BADADDR>) {
|
||||||
|
chomp;
|
||||||
|
# Comment line? Not only whitespaces?
|
||||||
|
if (/^[^#]/ && /[^\s]/) {
|
||||||
|
push(@bad_addr, $_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close (BADADDR);
|
||||||
|
return @bad_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Read ballot IDs #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub read_ballot_ids {
|
||||||
|
# open file with ballot ids
|
||||||
|
open(FILE, "<$config{idfile}") or return 1;
|
||||||
|
while (<FILE>) {
|
||||||
|
chomp;
|
||||||
|
# Format: mailaddress (whitespace) ballot ID
|
||||||
|
if (/^(.+@.+)\s+([a-z0-9]+)/) {
|
||||||
|
# $1=mailadresse, $2=ballot ID
|
||||||
|
$ids{$1} = $2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(FILE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Funktionen für Templates laden #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub load_formats {
|
||||||
|
my $modules = $config{formats};
|
||||||
|
|
||||||
|
my @modules = split(/\s*,\s*/, $modules);
|
||||||
|
|
||||||
|
foreach my $module (@modules){
|
||||||
|
if (-r $module){
|
||||||
|
require $module;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# config test #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub test_config {
|
||||||
|
print UVmessage::get("CONF_CONFIG"), "\n\n";
|
||||||
|
foreach my $option (keys %config) {
|
||||||
|
print "$option = $config{$option}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
print "\n", UVmessage::get("CONF_TEST_RULES");
|
||||||
|
if (@rules) {
|
||||||
|
print "\n\n";
|
||||||
|
for (my $n=0; $n<@rules; $n++) {
|
||||||
|
my $text = UVrules::rule_print($n);
|
||||||
|
print $text;
|
||||||
|
}
|
||||||
|
print "\n";
|
||||||
|
} else {
|
||||||
|
print UVmessage::get("CONF_NO_RULES"), "\n\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
566
UVformats.pm
Normal file
566
UVformats.pm
Normal file
|
@ -0,0 +1,566 @@
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
package UVformats;
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
UVformats - Methoden zur Stringformatierung
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
value <name-of-key>
|
||||||
|
append <name-of-key>
|
||||||
|
|
||||||
|
fill-left <width> <character>
|
||||||
|
fill-right <width> <character>
|
||||||
|
fill-center <width> <character>
|
||||||
|
|
||||||
|
justify <name-of-key> <width>
|
||||||
|
justify-before <name-of-key> <width>
|
||||||
|
justify-behind <name-of-key> <width>
|
||||||
|
|
||||||
|
first-words <width>
|
||||||
|
drop-words <width>
|
||||||
|
create-lines <width>
|
||||||
|
|
||||||
|
multi-graph <width> <position> <count>
|
||||||
|
multi-line <width> <count>
|
||||||
|
|
||||||
|
quote <string>
|
||||||
|
replace <original-string> <replacement-string>
|
||||||
|
sprintf <format-string>
|
||||||
|
|
||||||
|
generate_date_header
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Dieses Modul stellt verschiedenste Methoden bereit, um die Strings in
|
||||||
|
den Templates auf die unterschiedlichste Art zu formatieren.
|
||||||
|
|
||||||
|
Dieses Modul beschraenkt sich auf die Beschreibung der Funktionen. Ihre
|
||||||
|
Einbindung wird in UVtemplates beschrieben.
|
||||||
|
|
||||||
|
=head1 FUNCTIONS
|
||||||
|
|
||||||
|
=over 3
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use vars qw(@ISA @EXPORT $VERSION $functions);
|
||||||
|
|
||||||
|
use Exporter;
|
||||||
|
$VERSION = 0.01;
|
||||||
|
|
||||||
|
@ISA = qw(Exporter);
|
||||||
|
@EXPORT = qw( getFunctions );
|
||||||
|
|
||||||
|
use Text::Wrap;
|
||||||
|
#use POSIX qw(strftime);
|
||||||
|
use Email::Date;
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
sub getFunctions{
|
||||||
|
return $functions;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
=item value
|
||||||
|
|
||||||
|
Gibt den Wert eines Schluessel zurueck.
|
||||||
|
|
||||||
|
new-key := value 'old-key' | <other-functions> ...
|
||||||
|
|
||||||
|
Diese Funktion sollte dann eingesetzt werden, wenn man einen virtuellen
|
||||||
|
Schluessel erzeugen will. D.h. der Bezeichner nicht im Template als
|
||||||
|
Schluessel vorhanden ist. Durch den Einsatz von value wird der Wert eines
|
||||||
|
anderen Schluessel kopiert und kann dann weiter formatiert werden.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub value{
|
||||||
|
my ($data, $value, $key) = @_;
|
||||||
|
return $data->getKey($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=item append
|
||||||
|
|
||||||
|
Den Wert eines anderen Schluessels an den bisherigen String anhaengen.
|
||||||
|
|
||||||
|
... | append 'other-key' | ...
|
||||||
|
|
||||||
|
Per default wird als Trenner der beiden String ein Leerzeichen verwendet.
|
||||||
|
Soll dieses entfallen oder ein anderes Zeichen benutzt werden, so kann
|
||||||
|
ein dementsprechender drittere Parameter angegeben werden.
|
||||||
|
|
||||||
|
... | append 'other-key' '' | ...
|
||||||
|
... | append 'other-key' '_' | ...
|
||||||
|
|
||||||
|
Im ersten Beispiel wird der Wert von C<other-key> nahtlos hinzugefuegt.
|
||||||
|
Im zweiten statt des Leerzeichens '_' benutzt.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub append{
|
||||||
|
my ($data, $value, $key, $sep) = @_;
|
||||||
|
|
||||||
|
$sep = ' ' unless defined($sep);
|
||||||
|
|
||||||
|
return $value. $sep. $data->getConvKey($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=item fill-left, fill-right, fill-center
|
||||||
|
|
||||||
|
Fuellt den String entsprechend mit Zeichen auf bis die gewuenschte
|
||||||
|
Laenge erreicht ist. Bei C<fill-left> werden die Zeichen vorranggestellt,
|
||||||
|
bei C<fill-right> angehaengt. C<fill-center> verteilt die Zeichen
|
||||||
|
gleichmaessig vor und nach dem String.
|
||||||
|
|
||||||
|
... | fill-left 72 '.' | ...
|
||||||
|
|
||||||
|
Wird kein zweiter Parameter angegeben, wird automatisch das Leerzeichen
|
||||||
|
benutzt.
|
||||||
|
|
||||||
|
... | fill-right 60 | ...
|
||||||
|
|
||||||
|
Ist der String bereits laenger als gewuenscht, wird er nicht weiter
|
||||||
|
veraendert und auch nicht verkuerzt.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub fill_left{
|
||||||
|
my ($data, $value, $width, $char) = @_;
|
||||||
|
|
||||||
|
$width ||= 72;
|
||||||
|
$char = ' ' unless (defined($char) && length($char) == 1);
|
||||||
|
|
||||||
|
my $fill = $width - length($value);
|
||||||
|
|
||||||
|
$value = $char x $fill . $value if ($fill > 0);
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub fill_right{
|
||||||
|
my ($data, $value, $width, $char) = @_;
|
||||||
|
|
||||||
|
$width ||= 72;
|
||||||
|
$char ||= ' ';
|
||||||
|
|
||||||
|
my $fill = $width - length($value);
|
||||||
|
|
||||||
|
$value .= $char x $fill if ($fill > 0);
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub fill_both{
|
||||||
|
my ($data, $value, $width, $char) = @_;
|
||||||
|
|
||||||
|
$width ||= 72;
|
||||||
|
$char ||= ' ';
|
||||||
|
|
||||||
|
my $fill = $width - length($value);
|
||||||
|
|
||||||
|
if ($fill > 0){
|
||||||
|
my $left = int($fill / 2);
|
||||||
|
my $right = $fill - $left;
|
||||||
|
|
||||||
|
$value = $char x $left . $value . $char x $right;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=item justify, justify-before, justify-behind
|
||||||
|
|
||||||
|
Fuegt zwischen den existierenden String und dem Wert des angegebenen
|
||||||
|
Schluessel genau so viele Leerzeichen ein, damit die gewuenschte
|
||||||
|
Stringlaenge erreicht wird.
|
||||||
|
|
||||||
|
... | justify-behind 'key' 72 | ...
|
||||||
|
|
||||||
|
C<justify-behind> haengt den Wert des Schluessel an das Ende des Strings,
|
||||||
|
C<justify-before> stellt es davor.
|
||||||
|
|
||||||
|
justify-behind: existing-string.........value-of-key
|
||||||
|
justify-before: value-of-key.........existing-string
|
||||||
|
|
||||||
|
C<justify> ist lediglich ein Alias auf C<justify-behind>.
|
||||||
|
|
||||||
|
Sind die beiden Strings zusammen länger als die gewuenschte
|
||||||
|
Zeilenlaenge, wird automatisch einen Zeilenbruch eingefuegt
|
||||||
|
und beide Zeilen entsprechend mit Leerzeichen gefuellt.
|
||||||
|
|
||||||
|
very-very-very-long-existing-string.........\n
|
||||||
|
...................and-a-too-long-new-string
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub justify_behind{
|
||||||
|
my ($data, $value, $key, $width) = @_;
|
||||||
|
return _justify( $value, $data->getConvKey($key), $width);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub justify_before{
|
||||||
|
my ($data, $value, $key, $width) = @_;
|
||||||
|
return _justify( $data->getConvKey($key), $value, $width);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _justify{
|
||||||
|
my ($lval, $rval, $width) = @_;
|
||||||
|
|
||||||
|
my $sep = ' ';
|
||||||
|
|
||||||
|
if (length($lval.$rval) >= $width ){
|
||||||
|
# wir basteln zwei zeilen
|
||||||
|
$lval .= $sep x ($width - length($lval));
|
||||||
|
$rval = $sep x ($width - length($rval)) . $rval;
|
||||||
|
|
||||||
|
return $lval."\n".$rval;
|
||||||
|
|
||||||
|
}else{
|
||||||
|
my $fill = $width - length($lval) - length($rval);
|
||||||
|
return $lval . $sep x $fill . $rval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=item first-words
|
||||||
|
|
||||||
|
Gibt nur die ersten Worte eines Strings zurueck, die vollstaendig
|
||||||
|
innerhalb der angegebenen Laenge liegen.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub first_words{
|
||||||
|
my ($data, $value, $width) = @_;
|
||||||
|
|
||||||
|
my @words = split('\s+', $value);
|
||||||
|
my $string;
|
||||||
|
|
||||||
|
$string .= shift(@words);
|
||||||
|
|
||||||
|
while(@words && (length($string) + length($words[0]) + 1) < $width){
|
||||||
|
$string .= ' ' . shift(@words);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
=item drop-words
|
||||||
|
|
||||||
|
Alle Woerter am Anfang des Strings entfernen, die komplett innerhalb
|
||||||
|
der angegebenen Laenge liegen.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub drop_words{
|
||||||
|
my ($data, $value, $width) = @_;
|
||||||
|
|
||||||
|
my @words = split('\s+', $value);
|
||||||
|
|
||||||
|
# das erste "Wort" immer verwerfen, egal wie lang es ist
|
||||||
|
my $first = shift(@words);
|
||||||
|
my $length = length($first);
|
||||||
|
|
||||||
|
while (@words && ( $length + length($words[0]) + 1 ) < $width ){
|
||||||
|
$length += length($words[0]) + 1;
|
||||||
|
shift(@words);
|
||||||
|
}
|
||||||
|
|
||||||
|
return join(' ', @words);
|
||||||
|
}
|
||||||
|
|
||||||
|
=item create-lines
|
||||||
|
|
||||||
|
Zerlegt einen String in einen Array, in dem die einzelnen Zeilen nicht
|
||||||
|
laenger als die gewuenschte Anzahl Zeichen sind.
|
||||||
|
|
||||||
|
absatz := value 'key' | create-lines 72
|
||||||
|
|
||||||
|
Mit Hilfe dieser Funktion ist es moeglich, ueberlange Zeilen zu Absatzen
|
||||||
|
umzuformatieren.
|
||||||
|
|
||||||
|
Die Funktion erzeugt intern eine Liste, die jeweils den Schluessel C<line>
|
||||||
|
mit dem entsprechenden String als Wert enthaelt.
|
||||||
|
|
||||||
|
Im Template wird der so Absatz dann mit Hilfe des Schleifen-Syntax
|
||||||
|
eingebunden:
|
||||||
|
|
||||||
|
[@absatz|[line]\n]
|
||||||
|
|
||||||
|
Achtung! Da die Funktion keinen String zurueckgibt, sollte sie am Ende
|
||||||
|
der Kette stehen, da die normalen Formatierungsfunktionen einen String
|
||||||
|
als Input erwartern!
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub create_lines{
|
||||||
|
my ($data, $value, $width) = @_;
|
||||||
|
|
||||||
|
my @words = split('\s+', $value);
|
||||||
|
|
||||||
|
my @lines;
|
||||||
|
|
||||||
|
while (@words){
|
||||||
|
my $string .= shift(@words);
|
||||||
|
|
||||||
|
while(@words && (length($string) + length($words[0]) + 1) < $width){
|
||||||
|
$string .= ' ' . shift(@words);
|
||||||
|
}
|
||||||
|
|
||||||
|
my $new = $data->new( line => $string );
|
||||||
|
push(@lines, $new);
|
||||||
|
}
|
||||||
|
|
||||||
|
return \@lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=item multi-graph, multi-line
|
||||||
|
|
||||||
|
Spezielle Funktionen, um eine bestimmte graphische Ausgabe fuer
|
||||||
|
Votings mit mehreren Abstimmungspunkten zu erzeugen:
|
||||||
|
|
||||||
|
Punkt 1 --------------------------+
|
||||||
|
Punkt 2a ------------------------+|
|
||||||
|
Punkt 2b -----------------------+||
|
||||||
|
Punkt 3 -----------------------+|||
|
||||||
|
||||
|
||||||
|
Name of Voter 1 jjnn
|
||||||
|
Name of Voter 2 nnjj
|
||||||
|
|
||||||
|
C<multi-graph> ist hierbei für die Formatierung der einzelnen Abstimmungspunkte
|
||||||
|
zustaendig.
|
||||||
|
|
||||||
|
multi-graph 'key' 'width' 'pos-key' 'max-key'
|
||||||
|
|
||||||
|
Der erste Parameter gibt den Schluessel an, dessen Wert als Abstimmungspunkt
|
||||||
|
ausgegeben werden soll. C<width> die Laenge des zu erzeugenden Strings.
|
||||||
|
C<pos-key> und C<max-key> sind die Namen der Schluessel, in denen stehen
|
||||||
|
muss, um den wievielten Abstimmungspunkt es sich handelt (per default 'pos')
|
||||||
|
und wieviele Abstimmungspunkte es insgesamt gibt ('anzpunkte').
|
||||||
|
|
||||||
|
C<multi-line> erzeugt einfach nur einen String in der gewuenschten
|
||||||
|
Laenge, der entsprechend der Anzahl der Abstimmungspunkte mit '|'
|
||||||
|
abschliesst.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub mgraph{
|
||||||
|
my ($data, $value, $width, $pkey, $okey) = @_;
|
||||||
|
return unless $data;
|
||||||
|
|
||||||
|
my $pos = $data->getKey($pkey || 'pos');
|
||||||
|
my $of = $data->getKey($okey || 'anzpunkte');
|
||||||
|
|
||||||
|
my $gfx = '';
|
||||||
|
|
||||||
|
$gfx = ' ---'.'-' x ($of-$pos) .'+'. '|' x ($pos - 1) if ($pos && $of);
|
||||||
|
|
||||||
|
if (length($value.$gfx) < $width){
|
||||||
|
$value = ' ' x ($width - length($value.$gfx)) . $value . $gfx;
|
||||||
|
|
||||||
|
}elsif (length($value.$gfx) > $width){
|
||||||
|
my @lines = _wrap($value, $width - length($gfx));
|
||||||
|
|
||||||
|
$value = shift(@lines) . $gfx;
|
||||||
|
$value = ' ' x ($width - length($value)) . $value;
|
||||||
|
|
||||||
|
# Hilfzeile erzeugen
|
||||||
|
$gfx = ' '.' ' x ($of-$pos) . '|' x ($pos) if ($pos && $of);
|
||||||
|
|
||||||
|
foreach my $line (@lines){
|
||||||
|
$value .= "\n".' ' x ($width - length($line.$gfx)) . $line . $gfx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub mgline{
|
||||||
|
my ($data, undef, $width, $okey) = @_;
|
||||||
|
return unless $data;
|
||||||
|
|
||||||
|
my $of = $data->getKey($okey || 'anzpunkte') || 0;
|
||||||
|
|
||||||
|
return ' ' x ($width - $of) . '|' x $of;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub _wrap{
|
||||||
|
my ($string, $width) = @_;
|
||||||
|
|
||||||
|
my @words = split('\s+', $string);
|
||||||
|
|
||||||
|
my @lines;
|
||||||
|
|
||||||
|
while (@words){
|
||||||
|
my $line .= shift(@words);
|
||||||
|
|
||||||
|
while(@words && (length($line) + length($words[0]) + 1) < $width){
|
||||||
|
$line .= ' ' . shift(@words);
|
||||||
|
}
|
||||||
|
|
||||||
|
push(@lines, $line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return @lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=item quote
|
||||||
|
|
||||||
|
Stellt in einem (mehrzeiligem) String jeder Zeile den gewuenschten
|
||||||
|
Quotestring voran.
|
||||||
|
|
||||||
|
body := value 'body' | quote '> '
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub quote{
|
||||||
|
my ($data, $value, $quotechar) = @_;
|
||||||
|
|
||||||
|
$quotechar = '> ' unless defined($quotechar);
|
||||||
|
|
||||||
|
$value =~ s/^/$quotechar/mg;
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=item replace
|
||||||
|
|
||||||
|
Ersetzt in einem String ein oder mehrere Zeichen durch eine beliebige
|
||||||
|
Anzahl anderer Zeichen. Diese Funktion kann z.B. genutzt werden, um
|
||||||
|
beim Result die Mailadressen zu verfremden (Schutz vor Adress-Spidern).
|
||||||
|
|
||||||
|
mail := value 'mail' | replace '@' '-at-'
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub replace{
|
||||||
|
my ($data, $value, $original, $replacement) = @_;
|
||||||
|
|
||||||
|
$original = ' ' unless defined($original);
|
||||||
|
$replacement = ' ' unless defined($replacement);
|
||||||
|
|
||||||
|
$value =~ s/\Q$original\E/$replacement/g;
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=item sprintf
|
||||||
|
|
||||||
|
Gibt Text oder Zahlen mittels der Funktion sprintf formatiert aus
|
||||||
|
(siehe "man 3 sprintf" oder "perldoc -f sprintf").
|
||||||
|
|
||||||
|
proportion := value 'proportion' | sprintf '%6.3f'
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub sprintf{
|
||||||
|
my ($data, $value, $format) = @_;
|
||||||
|
|
||||||
|
$format = '%s' unless defined($format);
|
||||||
|
|
||||||
|
return sprintf($format, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=item generate_date_header
|
||||||
|
|
||||||
|
Gibt ein Datum im RFC822-Format zur Verwendung im Date:-Header einer
|
||||||
|
Mail aus.
|
||||||
|
|
||||||
|
date := generate_date_header
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub generate_date_header{
|
||||||
|
my ($data, $value, $format) = @_;
|
||||||
|
#return strftime('%a, %d %b %Y %H:%M:%S %z', localtime);
|
||||||
|
return format_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=item generate_msgid
|
||||||
|
|
||||||
|
Gibt eine Message-ID im RFC822-Format zur Verwendung im Message-ID:-Header
|
||||||
|
einer Mail aus.
|
||||||
|
|
||||||
|
msgid := generate_msgid
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub generate_msgid{
|
||||||
|
return ("<".$$.time().rand(999)."\@".$UVconfig::config{fqdn}.">");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
BEGIN{
|
||||||
|
%UVconfig::functions = ( %UVconfig::functions,
|
||||||
|
value => \&value,
|
||||||
|
append => \&append,
|
||||||
|
|
||||||
|
'fill-left' => \&fill_left,
|
||||||
|
'fill-right' => \&fill_right,
|
||||||
|
'fill-both' => \&fill_both,
|
||||||
|
|
||||||
|
justify => \&justify_behind,
|
||||||
|
'justify-behind' => \&justify_behind,
|
||||||
|
'justify-before' => \&justify_before,
|
||||||
|
|
||||||
|
'first-words' => \&first_words,
|
||||||
|
'drop-words' => \&drop_words,
|
||||||
|
|
||||||
|
'create-lines' => \&create_lines,
|
||||||
|
|
||||||
|
'multi-graph' => \&mgraph,
|
||||||
|
'multi-line' => \&mgline,
|
||||||
|
|
||||||
|
'quote' => \"e,
|
||||||
|
'replace' => \&replace,
|
||||||
|
'sprintf' => \&sprintf,
|
||||||
|
|
||||||
|
'generate-date-header' => \&generate_date_header,
|
||||||
|
'generate-msgid' => \&generate_msgid
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
L<UVtemplate>
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Cornell Binder <cobi@dex.de>
|
||||||
|
Marc Langer <usevote@marclanger.de>
|
380
UVmenu.pm
Normal file
380
UVmenu.pm
Normal file
|
@ -0,0 +1,380 @@
|
||||||
|
# UVmenu: menu for interaction with the votetaker
|
||||||
|
# Used by uvvote.pl, uvcfv.pl, uvcount.pl
|
||||||
|
|
||||||
|
package UVmenu;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use UVconfig;
|
||||||
|
use UVmessage;
|
||||||
|
use UVrules;
|
||||||
|
use vars qw($VERSION);
|
||||||
|
|
||||||
|
use Text::Wrap qw(wrap $columns);
|
||||||
|
|
||||||
|
# Module version
|
||||||
|
$VERSION = "0.4";
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Menu for interaction with the votetaker #
|
||||||
|
# Parameters: votes list and header (references to arrays) #
|
||||||
|
# Body, Mailadress, Name, Ballot ID (references to strings) #
|
||||||
|
# List of newly set fields (reference to array) #
|
||||||
|
# List of errors to correct (Array-Ref) #
|
||||||
|
# Return Values: 'w': proceed #
|
||||||
|
# 'i': ignore (don't save vote) #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub menu {
|
||||||
|
my ($votes, $header, $body, $addr, $name, $ballot_id, $set, $errors) = @_;
|
||||||
|
my $input = "";
|
||||||
|
my $voter_addr = $$addr || '';
|
||||||
|
my $voter_name = $$name || '';
|
||||||
|
my @newvotes = @$votes;
|
||||||
|
my $mailonly = 0;
|
||||||
|
my %errors;
|
||||||
|
$$ballot_id ||= '';
|
||||||
|
|
||||||
|
foreach my $error (@$errors) {
|
||||||
|
|
||||||
|
# unrecognized vote: extract group number und display warning
|
||||||
|
if ($error =~ /^UnrecognizedVote #(\d+)#(.+)$/) {
|
||||||
|
$errors{UnrecognizedVote} ||= UVmessage::get("MENU_UNRECOGNIZEDVOTE");
|
||||||
|
$errors{UnrecognizedVote} .= "\n " . UVmessage::get("MENU_UNRECOGNIZED_LIST")
|
||||||
|
. " #$1: $2";
|
||||||
|
|
||||||
|
# violated rule: extract rule number and display warning
|
||||||
|
} elsif ($error =~ /^ViolatedRule #(\d+)$/) {
|
||||||
|
$errors{ViolatedRule} ||= UVmessage::get("MENU_VIOLATEDRULE", (RULE => "#$1"));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
# special handling if called from uvballot.pl
|
||||||
|
$mailonly = 1 if ($error =~ s/Ballot$//);
|
||||||
|
|
||||||
|
# get error message for this error from messages.cfg
|
||||||
|
$errors{$error} = UVmessage::get("MENU_" . uc($error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# This loop is only left by 'return'
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
system($config{clearcmd});
|
||||||
|
print UVmessage::get("MENU_PROBLEMS") . "\n";
|
||||||
|
|
||||||
|
foreach my $error (keys %errors) {
|
||||||
|
print "* $errors{$error}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
my $menucaption = UVmessage::get("MENU_CAPTION");
|
||||||
|
print "\n\n$menucaption\n";
|
||||||
|
print "=" x length($menucaption), "\n\n";
|
||||||
|
print "(1) ", UVmessage::get("MENU_SHOW_MAIL"), "\n\n",
|
||||||
|
UVmessage::get("MENU_CHANGE_PROPERTIES"), "\n",
|
||||||
|
"(2) ", UVmessage::get("MENU_ADDRESS"), " [$voter_addr]\n";
|
||||||
|
|
||||||
|
# don't print these options if called from uvcfv.pl
|
||||||
|
unless ($mailonly) {
|
||||||
|
print "(3) ", UVmessage::get("MENU_NAME"), " [$voter_name]\n";
|
||||||
|
print "(4) ", UVmessage::get("MENU_VOTES"), " [", @$votes, "]\n";
|
||||||
|
print "(5) ", UVmessage::get("MENU_BALLOT_ID"), " [$$ballot_id]\n"
|
||||||
|
if ($config{personal});
|
||||||
|
print "(6) ", UVmessage::get("MENU_BDSG"), "\n" if ($config{bdsg});
|
||||||
|
}
|
||||||
|
|
||||||
|
print "\n",
|
||||||
|
"(i) ", UVmessage::get("MENU_IGNORE"), "\n",
|
||||||
|
"(w) ", UVmessage::get("MENU_PROCEED"), "\n\n",
|
||||||
|
UVmessage::get("MENU_PROMPT");
|
||||||
|
|
||||||
|
do { $input = <STDIN>; } until ($input);
|
||||||
|
chomp $input;
|
||||||
|
print "\n";
|
||||||
|
|
||||||
|
# only accept 1, 2, i and w if called from uvcfv.pl
|
||||||
|
next if ($mailonly && $input !~ /^[12iw]$/i);
|
||||||
|
|
||||||
|
if ($input eq '1') {
|
||||||
|
system($config{clearcmd});
|
||||||
|
# ignore SIGPIPE (Bug in more and less)
|
||||||
|
$SIG{PIPE} = 'IGNORE';
|
||||||
|
open (MORE, "|$config{pager}");
|
||||||
|
print MORE join("\n", @$header), "\n\n", $$body, "\n";
|
||||||
|
close (MORE);
|
||||||
|
|
||||||
|
print "\n", UVmessage::get("MENU_GETKEY");
|
||||||
|
$input = <STDIN>;
|
||||||
|
|
||||||
|
} elsif ($input eq '2') {
|
||||||
|
my $sel;
|
||||||
|
do {
|
||||||
|
print "[a] ", UVmessage::get("MENU_ADDRESS_OK"), "\n",
|
||||||
|
"[b] ", UVmessage::get("MENU_ADDRESS_CHANGE"), "\n",
|
||||||
|
"[c] ", UVmessage::get("MENU_ADDRESS_INVALID"), "\n\n",
|
||||||
|
UVmessage::get("MENU_PROMPT");
|
||||||
|
$sel = <STDIN>;
|
||||||
|
} until ($sel =~ /^[abc]$/i);
|
||||||
|
if ($sel =~ /^a$/i) {
|
||||||
|
delete $errors{SuspiciousAccount};
|
||||||
|
delete $errors{InvalidAddress};
|
||||||
|
next;
|
||||||
|
} elsif ($sel =~ /^c$/i) {
|
||||||
|
delete $errors{SuspiciousAccount};
|
||||||
|
$errors{InvalidAddress} = UVmessage::get("MENU_INVALIDADDRESS") . " " .
|
||||||
|
UVmessage::get("MENU_INVALIDADDRESS2");
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
print "\n", UVmessage::get("MENU_ADDRESS_PROMPT"), " ";
|
||||||
|
$voter_addr = <STDIN>;
|
||||||
|
chomp ($voter_addr);
|
||||||
|
} until ($voter_addr);
|
||||||
|
$$addr = $voter_addr;
|
||||||
|
push (@$set, 'Adresse');
|
||||||
|
delete $errors{SuspiciousAccount};
|
||||||
|
delete $errors{InvalidAddress};
|
||||||
|
check_ballotid(\%errors, \$voter_addr, $ballot_id, \%ids);
|
||||||
|
|
||||||
|
} elsif ($input eq '3') {
|
||||||
|
my $sel;
|
||||||
|
do {
|
||||||
|
print "[a] ", UVmessage::get("MENU_NAME_OK"), "\n",
|
||||||
|
"[b] ", UVmessage::get("MENU_NAME_CHANGE"), "\n",
|
||||||
|
"[c] ", UVmessage::get("MENU_NAME_INVALID"), "\n\n",
|
||||||
|
UVmessage::get("MENU_PROMPT");
|
||||||
|
$sel = <STDIN>;
|
||||||
|
} until ($sel =~ /^[abc]$/i);
|
||||||
|
if ($sel =~ /^a$/i) {
|
||||||
|
delete $errors{InvalidName};
|
||||||
|
next;
|
||||||
|
} elsif ($sel =~ /^c$/i) {
|
||||||
|
$errors{InvalidName} = UVmessage::get("MENU_INVALIDNAME");
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
print UVmessage::get("MENU_NAME"), ": ";
|
||||||
|
$voter_name = <STDIN>;
|
||||||
|
chomp ($voter_name);
|
||||||
|
$$name = $voter_name;
|
||||||
|
push (@$set, 'Name');
|
||||||
|
delete $errors{NoName};
|
||||||
|
delete $errors{InvalidName};
|
||||||
|
|
||||||
|
$errors{InvalidName} = UVmessage::get("MENU_INVALIDNAME")
|
||||||
|
unless ($voter_name =~ /$config{name_re}/);
|
||||||
|
|
||||||
|
} elsif ($input eq '4') {
|
||||||
|
# set votes
|
||||||
|
|
||||||
|
my $sel;
|
||||||
|
do {
|
||||||
|
print "[a] ", UVmessage::get("MENU_VOTES_OK"), "\n",
|
||||||
|
"[b] ", UVmessage::get("MENU_VOTES_RESET"), "\n",
|
||||||
|
"[c] ", UVmessage::get("MENU_VOTES_INVALID"), "\n",
|
||||||
|
"[d] ", UVmessage::get("MENU_VOTES_CANCELLED"), "\n\n",
|
||||||
|
UVmessage::get("MENU_PROMPT");
|
||||||
|
$sel = <STDIN>;
|
||||||
|
} until ($sel =~ /^[abcd]$/i);
|
||||||
|
if ($sel =~ /^[ad]$/i) {
|
||||||
|
delete $errors{NoVote};
|
||||||
|
delete $errors{UnrecognizedVote};
|
||||||
|
delete $errors{ViolatedRule};
|
||||||
|
delete $errors{DuplicateVote};
|
||||||
|
if ($sel =~ /^d$/i) {
|
||||||
|
# cancelled vote: replace all votes with an A
|
||||||
|
@$votes = split(//, 'A' x scalar @groups);
|
||||||
|
push @$set, 'Stimmen';
|
||||||
|
# some errors are irrelevant when cancelling a vote:
|
||||||
|
delete $errors{InvalidName};
|
||||||
|
delete $errors{NoName};
|
||||||
|
delete $errors{InvalidBDSG};
|
||||||
|
delete $errors{InvalidAddress};
|
||||||
|
delete $errors{SuspiciousAccount};
|
||||||
|
}
|
||||||
|
next;
|
||||||
|
} elsif ($sel =~ /^c$/i) {
|
||||||
|
$errors{NoVote} = UVmessage::get("MENU_INVALIDVOTE");
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set columns for Text::Wrap
|
||||||
|
$columns = $config{rightmargin};
|
||||||
|
print "\n", wrap('', '', UVmessage::get("MENU_VOTES_REENTER_ASK")), "\n\n";
|
||||||
|
print UVmessage::get("MENU_VOTES_REENTER_LEGEND"), "\n";
|
||||||
|
|
||||||
|
for (my $n=0; $n<@groups; $n++) {
|
||||||
|
my $voteinput = "";
|
||||||
|
$votes->[$n] ||= 'E';
|
||||||
|
|
||||||
|
# repeat while invalid character entered
|
||||||
|
while (!($voteinput =~ /^[JNE]$/)) {
|
||||||
|
my $invalid = $#groups ? 0 : 1;
|
||||||
|
print UVmessage::get("MENU_VOTES_REENTER", (GROUP => $groups[$n]));
|
||||||
|
$voteinput = <STDIN>;
|
||||||
|
chomp $voteinput;
|
||||||
|
$voteinput ||= $votes->[$n];
|
||||||
|
$voteinput =~ tr/jne/JNE/;
|
||||||
|
}
|
||||||
|
|
||||||
|
# valid input, save new votes
|
||||||
|
$newvotes[$n] = $voteinput;
|
||||||
|
}
|
||||||
|
|
||||||
|
print "\n\n";
|
||||||
|
my $oldvotes = UVmessage::get("MENU_VOTES_REENTER_OLD");
|
||||||
|
my $newvotes = UVmessage::get("MENU_VOTES_REENTER_NEW");
|
||||||
|
my $oldlen = length($oldvotes);
|
||||||
|
my $newlen = length($newvotes);
|
||||||
|
my $maxlen = 1 + (($newlen>$oldlen) ? $newlen : $oldlen);
|
||||||
|
print $oldvotes, ' ' x ($maxlen - length($oldvotes)), @$votes, "\n",
|
||||||
|
$newvotes, ' ' x ($maxlen - length($newvotes)), @newvotes, "\n\n";
|
||||||
|
|
||||||
|
do {
|
||||||
|
print "[a] ", UVmessage::get("MENU_VOTES_REENTER_ACK"), " ",
|
||||||
|
"[b] ", UVmessage::get("MENU_VOTES_REENTER_NACK"), "\n\n",
|
||||||
|
UVmessage::get("MENU_PROMPT");
|
||||||
|
$sel = <STDIN>;
|
||||||
|
} until ($sel =~ /^[ab]$/i);
|
||||||
|
|
||||||
|
next if ($sel =~ /^b$/i);
|
||||||
|
@$votes = @newvotes;
|
||||||
|
push @$set, 'Stimmen';
|
||||||
|
delete $errors{UnrecognizedVote};
|
||||||
|
delete $errors{DuplicateVote};
|
||||||
|
delete $errors{NoVote};
|
||||||
|
delete $errors{ViolatedRule};
|
||||||
|
|
||||||
|
if (my $rule = UVrules::rule_check($votes)) {
|
||||||
|
$errors{ViolatedRule} = UVmessage::get("MENU_VIOLATEDRULE", (RULE => "#$rule"));
|
||||||
|
}
|
||||||
|
|
||||||
|
} elsif ($input eq '5' && $config{personal}) {
|
||||||
|
print "\n", UVmessage::get("MENU_BALLOT_ID"), ": ";
|
||||||
|
$$ballot_id = <STDIN>;
|
||||||
|
chomp ($$ballot_id);
|
||||||
|
push (@$set, 'Kennung');
|
||||||
|
check_ballotid(\%errors, \$voter_addr, $ballot_id, \%ids);
|
||||||
|
|
||||||
|
} elsif ($input eq '6' && $config{bdsg}) {
|
||||||
|
my $sel;
|
||||||
|
do {
|
||||||
|
print "[a] ", UVmessage::get("MENU_BDSG_ACCEPTED"), "\n",
|
||||||
|
"[b] ", UVmessage::get("MENU_BDSG_DECLINED"), "\n\n",
|
||||||
|
UVmessage::get("MENU_PROMPT");
|
||||||
|
$sel = <STDIN>;
|
||||||
|
} until ($sel =~ /^[ab]$/i);
|
||||||
|
|
||||||
|
if ($sel =~ /^a$/i) {
|
||||||
|
delete $errors{InvalidBDSG};
|
||||||
|
} else {
|
||||||
|
$errors{InvalidBDSG} = UVmessage::get("MENU_INVALIDBDSG");
|
||||||
|
}
|
||||||
|
|
||||||
|
} elsif ($input =~ /^i$/i) {
|
||||||
|
my $ignore = UVmessage::get("MENU_IGNORE_STRING");
|
||||||
|
# Set columns for Text::Wrap
|
||||||
|
$columns = $config{rightmargin};
|
||||||
|
print wrap('', '', UVmessage::get("MENU_IGNORE_WARNING",
|
||||||
|
(MENU_IGNORE_STRING => $ignore)
|
||||||
|
));
|
||||||
|
if (<STDIN> eq "$ignore\n") {
|
||||||
|
print "\n";
|
||||||
|
return "i";
|
||||||
|
}
|
||||||
|
|
||||||
|
} elsif ($input =~ /^w$/i) {
|
||||||
|
|
||||||
|
if (keys %errors) {
|
||||||
|
if ((keys %errors)==1 && $errors{UnrecognizedVote}) {
|
||||||
|
# unrecognized vote lines aren't errors if votetaker
|
||||||
|
# did not change them
|
||||||
|
@$errors = ();
|
||||||
|
} else {
|
||||||
|
# Set columns for Text::Wrap
|
||||||
|
$columns = $config{rightmargin};
|
||||||
|
@$errors = keys %errors;
|
||||||
|
my $warning = ' ' . UVmessage::get("MENU_ERROR_WARNING") . ' ';
|
||||||
|
my $length = length($warning);
|
||||||
|
print "\n", '*' x (($config{rightmargin}-$length)/2), $warning,
|
||||||
|
'*' x (($config{rightmargin}-$length)/2), "\n\n",
|
||||||
|
wrap('', '', UVmessage::get("MENU_ERROR_TEXT")), "\n\n",
|
||||||
|
'*' x $config{rightmargin}, "\n\n",
|
||||||
|
UVmessage::get("MENU_ERROR_GETKEY");
|
||||||
|
my $input = <STDIN>;
|
||||||
|
next if ($input !~ /^y$/i);
|
||||||
|
print "\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
@$errors = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
system($config{clearcmd});
|
||||||
|
print "\n", UVmessage::get("MENU_PROCESSING"), "\n";
|
||||||
|
return "w";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub check_ballotid {
|
||||||
|
my ($errors, $voter_addr, $ballot_id, $ids) = @_;
|
||||||
|
|
||||||
|
return 0 unless ($config{personal});
|
||||||
|
|
||||||
|
delete $errors->{NoBallotID};
|
||||||
|
delete $errors->{WrongBallotID};
|
||||||
|
delete $errors->{AddressNotRegistered};
|
||||||
|
|
||||||
|
if ($$ballot_id) {
|
||||||
|
if ($ids->{$$voter_addr}) {
|
||||||
|
if ($ids->{$$voter_addr} ne $$ballot_id) {
|
||||||
|
# ballot id incorrect
|
||||||
|
$errors->{WrongBallotID} = UVmessage::get("MENU_WRONGBALLOTID");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$errors->{AddressNotRegistered} = UVmessage::get("MENU_ADDRESSNOTREGISTERED");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$errors->{NoBallotID} = UVmessage::get("MENU_NOBALLOTID");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Menu for sorting out duplicate votings manually #
|
||||||
|
# Parameters: References to hashes with the paragraphs from the result file #
|
||||||
|
# and the default value #
|
||||||
|
# Return value: selected menu item (1, 2 or 0) #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub dup_choice {
|
||||||
|
my ($vote1, $vote2, $default) = @_;
|
||||||
|
|
||||||
|
print STDERR "\n", UVmessage::get("MENU_DUP_VOTE"), "\n\n";
|
||||||
|
print STDERR UVmessage::get("MENU_DUP_FIRST"), "\n";
|
||||||
|
print STDERR "A: $vote1->{A}\n";
|
||||||
|
print STDERR "N: $vote1->{N}\n";
|
||||||
|
print STDERR "D: $vote1->{D}\n";
|
||||||
|
print STDERR "K: $vote1->{K}\n";
|
||||||
|
print STDERR "S: $vote1->{S}\n\n";
|
||||||
|
print STDERR UVmessage::get("MENU_DUP_SECOND"), "\n";
|
||||||
|
print STDERR "A: $vote2->{A}\n";
|
||||||
|
print STDERR "N: $vote2->{N}\n";
|
||||||
|
print STDERR "D: $vote2->{D}\n";
|
||||||
|
print STDERR "K: $vote2->{K}\n";
|
||||||
|
print STDERR "S: $vote2->{S}\n\n";
|
||||||
|
print STDERR "1: ", UVmessage::get("MENU_DUP_DELFIRST"), "\n",
|
||||||
|
"2: ", UVmessage::get("MENU_DUP_DELSECOND"), "\n",
|
||||||
|
"0: ", UVmessage::get("MENU_DUP_DELNONE"), "\n\n";
|
||||||
|
|
||||||
|
my $input;
|
||||||
|
|
||||||
|
do {
|
||||||
|
print STDERR UVmessage::get("MENU_PROMPT"), "[$default] ";
|
||||||
|
$input = <STDIN>;
|
||||||
|
chomp $input;
|
||||||
|
} until ($input eq '' || ($input >= 0 && $input<3));
|
||||||
|
|
||||||
|
return $input || $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
32
UVmessage.pm
Normal file
32
UVmessage.pm
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# UVmessages: parses resource strings and substitutes variables
|
||||||
|
# Used by all components
|
||||||
|
|
||||||
|
package UVmessage;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use vars qw(@ISA @EXPORT_OK $VERSION);
|
||||||
|
|
||||||
|
require Exporter;
|
||||||
|
@ISA = qw(Exporter);
|
||||||
|
@EXPORT_OK = qw(get);
|
||||||
|
|
||||||
|
# Module version
|
||||||
|
$VERSION = "0.1";
|
||||||
|
|
||||||
|
sub get {
|
||||||
|
my ($key, %param) = @_;
|
||||||
|
|
||||||
|
my $string = $UVconfig::messages{$key} || return '';
|
||||||
|
|
||||||
|
while ($string =~ m/\$\{([A-Za-z0-9_-]+)\}/) {
|
||||||
|
my $skey = $1;
|
||||||
|
my $sval = $param{$skey};
|
||||||
|
$sval = '' unless defined($sval);
|
||||||
|
|
||||||
|
$string =~ s/\$\{$skey\}/$sval/g;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
225
UVreadmail.pm
Normal file
225
UVreadmail.pm
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
# UVreadmail: functions for reading and processing mailfiles
|
||||||
|
# Used by uvvote.pl, uvcfv.pl, uvbounce.pl
|
||||||
|
|
||||||
|
package UVreadmail;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use UVconfig;
|
||||||
|
use UVmessage;
|
||||||
|
use MIME::QuotedPrint;
|
||||||
|
use MIME::Base64;
|
||||||
|
use MIME::Parser;
|
||||||
|
use POSIX qw(strftime);
|
||||||
|
|
||||||
|
use vars qw($VERSION);
|
||||||
|
|
||||||
|
# Module version
|
||||||
|
$VERSION = "0.11";
|
||||||
|
|
||||||
|
sub process {
|
||||||
|
|
||||||
|
# $filename: file containing bounces or (if POP3 is enabled) where
|
||||||
|
# mails should be saved
|
||||||
|
# $callsub: reference to a sub which should be called for each mail
|
||||||
|
# $caller: 0 = uvvote.pl, 1 = uvcfv.pl, 2 = uvbounce.pl
|
||||||
|
# 3 = uvbounce.pl but POP3 disabled (overrides $config{pop3}
|
||||||
|
#
|
||||||
|
|
||||||
|
my ($filename, $callsub, $caller) = @_;
|
||||||
|
my ($voter_addr, $voter_name, $body);
|
||||||
|
my $count = 0;
|
||||||
|
my ($pop3server, $pop3user, $pop3pass, $pop3delete, $pop3uidlcache);
|
||||||
|
my @mails = ();
|
||||||
|
$caller ||= 0;
|
||||||
|
|
||||||
|
if ($config{pop3} && $caller<3) {
|
||||||
|
|
||||||
|
if ($caller == 1) {
|
||||||
|
# Ballot request (personal = 1 set in usevote.cfg) from uvcfv.pl
|
||||||
|
$pop3server = $config{pop3server_req} . ':' . $config{pop3port_req};
|
||||||
|
$pop3user = $config{pop3user_req};
|
||||||
|
$pop3pass = $config{pop3pass_req};
|
||||||
|
$pop3delete = $config{pop3delete_req};
|
||||||
|
$pop3uidlcache = $config{pop3uidlcache_req};
|
||||||
|
} elsif ($caller == 2) {
|
||||||
|
# called from uvbounce.pl
|
||||||
|
$pop3server = $config{pop3server_bounce} . ':' . $config{pop3port_bounce};
|
||||||
|
$pop3user = $config{pop3user_bounce};
|
||||||
|
$pop3pass = $config{pop3pass_bounce};
|
||||||
|
$pop3delete = $config{pop3delete_bounce};
|
||||||
|
$pop3uidlcache = $config{pop3uidlcache_bounce};
|
||||||
|
} else {
|
||||||
|
$pop3server = $config{pop3server} . ':' . $config{pop3port};
|
||||||
|
$pop3user = $config{pop3user};
|
||||||
|
$pop3pass = $config{pop3pass};
|
||||||
|
$pop3delete = $config{pop3delete};
|
||||||
|
$pop3uidlcache = $config{pop3uidlcache};
|
||||||
|
}
|
||||||
|
|
||||||
|
# read list of seen mails (UIDLs)
|
||||||
|
my %uidls = (); # hash for quick searching
|
||||||
|
my @uidls = (); # array to preserve order
|
||||||
|
my $cacheexist = 1;
|
||||||
|
open (UIDLCACHE, "<$pop3uidlcache") or $cacheexist = 0;
|
||||||
|
if ($cacheexist) {
|
||||||
|
while (my $uidl = <UIDLCACHE>) {
|
||||||
|
chomp ($uidl);
|
||||||
|
$uidls{$uidl} = 1;
|
||||||
|
push (@uidls, $uidl);
|
||||||
|
}
|
||||||
|
close (UIDLCACHE);
|
||||||
|
}
|
||||||
|
|
||||||
|
print UVmessage::get("READMAIL_STATUS"), "\n" unless ($caller == 2);
|
||||||
|
|
||||||
|
# open POP3 connection and get new mails
|
||||||
|
use Net::POP3;
|
||||||
|
my $pop = Net::POP3->new($pop3server)
|
||||||
|
or die UVmessage::get("READMAIL_NOCONNECTION") . "\n\n";
|
||||||
|
|
||||||
|
my $mailcount = $pop->login($pop3user, $pop3pass);
|
||||||
|
|
||||||
|
die UVmessage::get("READMAIL_NOLOGIN") . "\n\n" unless ($mailcount);
|
||||||
|
|
||||||
|
for (my $n=1; $n<=$mailcount; $n++) {
|
||||||
|
my $uidl = $pop->uidl($n);
|
||||||
|
if ($uidl) {
|
||||||
|
next if ($uidls{$uidl});
|
||||||
|
$uidls{$uidl} = 1;
|
||||||
|
push (@uidls, $uidl);
|
||||||
|
}
|
||||||
|
my $mailref = $pop->get($n)
|
||||||
|
or print STDERR UVmessage::get("READMAIL_GET_PROBLEM", (NR => $n)) . "\n";
|
||||||
|
my $mail = join ('', @$mailref);
|
||||||
|
my $fromline = 'From ';
|
||||||
|
if ($mail =~ /From: .*?<(.+?)>/) {
|
||||||
|
$fromline .= $1;
|
||||||
|
} elsif ($mail =~ /From:\s+?(\S+?\@\S+?)\s/) {
|
||||||
|
$fromline .= $1;
|
||||||
|
} else {
|
||||||
|
$fromline .= 'foo@bar.invalid';
|
||||||
|
}
|
||||||
|
$fromline .= ' ' . strftime ('%a %b %d %H:%M:%S %Y', localtime) . "\n";
|
||||||
|
push (@mails, $fromline . $mail);
|
||||||
|
if ($pop3delete) {
|
||||||
|
$pop->delete($n)
|
||||||
|
or print STDERR UVmessage::get("READMAIL_DEL_PROBLEM", (NR => $n)) . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# save UIDLs
|
||||||
|
my $uidlerr = 0;
|
||||||
|
open (UIDLCACHE, ">$pop3uidlcache") or $uidlerr = 1;
|
||||||
|
if ($uidlerr) {
|
||||||
|
print STDERR UVmessage::get("READMAIL_UIDL_PROBLEM") . "\n";
|
||||||
|
print STDERR UVmessage::get("READMAIL_UIDL_PROBLEM2") . "\n";
|
||||||
|
} else {
|
||||||
|
print UIDLCACHE join("\n", @uidls);
|
||||||
|
close (UIDLCACHE) or print STDERR UVmessage::get("READMAIL_UIDL_CLOSE") . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# make archive of all mails
|
||||||
|
my $fileproblem = 0;
|
||||||
|
open (VOTES, ">$filename") or $fileproblem = 1;
|
||||||
|
if ($fileproblem) {
|
||||||
|
print STDERR UVmessage::get("READMAIL_ARCHIVE_PROBLEM",
|
||||||
|
(FILE => $filename)) . "\n";
|
||||||
|
} else {
|
||||||
|
print VOTES join ("\n", @mails);
|
||||||
|
close (VOTES)
|
||||||
|
or print STDERR UVmessage::get("READMAIL_ARCHIVE_CLOSE",
|
||||||
|
(FILE => $filename)) . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$pop->quit();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
# open mail file
|
||||||
|
open(VOTES, "<$filename")
|
||||||
|
or die UVmessage::get("READMAIL_NOMAILFILE", (FILE => $filename)) . "\n\n";
|
||||||
|
|
||||||
|
# read all mails
|
||||||
|
my $i = 0;
|
||||||
|
while (<VOTES>) {
|
||||||
|
if (/$config{mailstart}/) {
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
$mails[$i] = ($mails[$i] || "") . $_;
|
||||||
|
}
|
||||||
|
|
||||||
|
# close mail file
|
||||||
|
close(VOTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $mail (@mails) {
|
||||||
|
next unless $mail;
|
||||||
|
|
||||||
|
# split mail into array and remove first line (from line)
|
||||||
|
my @mail = split(/\n/, $mail);
|
||||||
|
shift (@mail) if ($mail[0] =~ /^From /);
|
||||||
|
|
||||||
|
# generate MIME-Parser object for the mail
|
||||||
|
my $parser = new MIME::Parser;
|
||||||
|
# headers are to be decoded
|
||||||
|
$parser->decode_headers(1);
|
||||||
|
# don't write into file
|
||||||
|
$parser->output_to_core(1);
|
||||||
|
|
||||||
|
# read mail
|
||||||
|
my $entity = $parser->parse_data(join("\n", @mail));
|
||||||
|
my $head = $entity->head;
|
||||||
|
|
||||||
|
# extract address and name
|
||||||
|
my $from = $head->get('From') || '';
|
||||||
|
|
||||||
|
if ($from =~ /\s*([^<]\S+\@\S+[^>]) \((.+)\)/) {
|
||||||
|
($voter_addr, $voter_name) = ($1, $2);
|
||||||
|
} elsif ($from =~ /\s*\"?([^\"]+)\"?\s*<(\S+\@\S+)>/) {
|
||||||
|
($voter_name, $voter_addr) = ($1, $2);
|
||||||
|
$voter_name =~ s/\s+$//; # kill spaces at the end
|
||||||
|
} elsif ($from =~ /\s*<?(\S+\@[^\s>]+)>?[^\(\)]*/) {
|
||||||
|
($voter_addr, $voter_name) = ($1, '');
|
||||||
|
} else {
|
||||||
|
# initialize with empty value
|
||||||
|
$voter_addr = '';
|
||||||
|
$voter_name = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
# look at reply-to?
|
||||||
|
if ($config{replyto}) {
|
||||||
|
|
||||||
|
my $replyto = Mail::Field->new('Reply-To', $head->get('Reply-To'));
|
||||||
|
|
||||||
|
# Address in Reply-To?
|
||||||
|
($voter_addr) = $replyto->addresses() if ($replyto->addresses());
|
||||||
|
|
||||||
|
# Name in reply-to?
|
||||||
|
if ($replyto->names()) {
|
||||||
|
my ($nametmp) = $replyto->names();
|
||||||
|
$voter_name = $nametmp unless ($nametmp =~ /^\s*$/);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# decode body
|
||||||
|
my $encoding = $head->get('Content-Transfer-Encoding') || '';
|
||||||
|
if ($encoding =~ /quoted-printable/i) {
|
||||||
|
$body = decode_qp($entity->stringify_body);
|
||||||
|
} elsif ($encoding =~ /base64/i) {
|
||||||
|
$body = decode_base64($entity->stringify_body);
|
||||||
|
} else {
|
||||||
|
$body = $entity->stringify_body;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $h_date = $head->get('Date') || '';
|
||||||
|
chomp $h_date;
|
||||||
|
|
||||||
|
# call referred sub and increase counter
|
||||||
|
&$callsub($voter_addr, $voter_name, $h_date, $entity, \$body);
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
409
UVrules.pm
Normal file
409
UVrules.pm
Normal file
|
@ -0,0 +1,409 @@
|
||||||
|
# UVrules: Module with rule functions for usevote
|
||||||
|
# Used by uvvote.pl, UVconfig.pm
|
||||||
|
|
||||||
|
package UVrules;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use vars qw (@ISA @EXPORT $VERSION @rules);
|
||||||
|
use UVconfig;
|
||||||
|
use UVmessage;
|
||||||
|
|
||||||
|
require Exporter;
|
||||||
|
@ISA = qw(Exporter);
|
||||||
|
@EXPORT = qw(@rules);
|
||||||
|
|
||||||
|
# Module version
|
||||||
|
$VERSION = "0.3";
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Erlaeuterung zur Regelpruefung (to be translated)
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Um Stimmen mit multiplen Abstimmungspunkten auf ihre Sinnfaelligkeit
|
||||||
|
# pruefen zu koennen, koennen in Usevote verschiedenste Regeln
|
||||||
|
# fuer solche Pruefungen definiert werden.
|
||||||
|
#
|
||||||
|
# Die Regeln bestehen aus zwei Teilen. Einer IF-Klausel und einer THEN-
|
||||||
|
# Klausel. Die IF-Klausel bestimmt, ob die Stimme mit der THEN-Klausel
|
||||||
|
# verglichen werden soll. Passt sie auf diese, ist die Stimme in Ordnung,
|
||||||
|
# wenn nicht liegt ein Fehler vor.
|
||||||
|
#
|
||||||
|
# Ein kleines Beispiel: "IF S.. THEN .SS"
|
||||||
|
# Wenn beim ersten Punkt mit Ja oder Nein gestimmt wurde, dann muss
|
||||||
|
# bei den anderen beiden Punkten auch ein Ja oder Nein vorliegen.
|
||||||
|
#
|
||||||
|
# Die Stimmabgabe JNE wuerde also gegen die obige Regel verstossen,
|
||||||
|
# JJN nicht. EEJ wuerde ebenfalls gueltig sein, da die Regel nicht unter
|
||||||
|
# die IF-Klausel faellt und somit keine Ueberpruefung der THEN-Klausel
|
||||||
|
# erfolgt.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Implementierung
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Um eine moeglichst einfache Ueberpruefung der Stimmen vorzunehmen,
|
||||||
|
# bietet es sich an, aus den beiden Klauseln regulaere Ausdruecke zu
|
||||||
|
# generieren. Diese wuerden dann auf die Stimme angewandt werden.
|
||||||
|
#
|
||||||
|
# Bei der Umwandlung in regulaere Audruecke kommt uns die Notation
|
||||||
|
# der Regeln bereits entgegen. So kann der Punkt als beliebige Stimme
|
||||||
|
# beibehalten werden. Die grossen Buchstaben bleiben ebenfalls bis
|
||||||
|
# auf S erhalten, da die zu pruefenden Stimmen aus den Buchstaben
|
||||||
|
# 'JNE' bestehen.
|
||||||
|
#
|
||||||
|
# So muessen wir zur Ueberpruefung von direkten Stimmen nur 'S' in
|
||||||
|
# eine Klasse mit [JN] und I in eine Klasse mit [EN] umwandeln.
|
||||||
|
#
|
||||||
|
# 'J..' => 'J..', 'NNE' => 'NNE', 'S..' => '[JN]..'
|
||||||
|
#
|
||||||
|
# Bei den indirekten Stimmabgaben wird es schon schwieriger. Hier
|
||||||
|
# muessten alle Moeglichkeiten eines Strings gebaut werden, um zu
|
||||||
|
# testen ob mindestens eine Version matcht.
|
||||||
|
#
|
||||||
|
# '.jjj' => '.(j..|.j.|..j)
|
||||||
|
#
|
||||||
|
# Je komplexer die Regeln, um so mehr Moeglichkeiten muessten
|
||||||
|
# konstruiert werden, um einen geschlossenen regulaeren Ausdruck
|
||||||
|
# zu erhalten.
|
||||||
|
#
|
||||||
|
# Wir koennen den Regex aber auch einfach aufbauen, in dem wir
|
||||||
|
# nicht alle Faelle betrachten die moeglich sind, sondern nur die
|
||||||
|
# Faelle die nicht erlaubt sind.
|
||||||
|
#
|
||||||
|
# D.h. soll an einer Stelle ein Ja stehen, erlauben wir dort
|
||||||
|
# nur Nein und Enthaltungen. Passt eine Stimme auf diesen Regex,
|
||||||
|
# kann sie unmoeglich die Vorgabe enthalten.
|
||||||
|
#
|
||||||
|
# 'nnnn' => '[JE][JE][JE][JE]'
|
||||||
|
#
|
||||||
|
# Besteht eine Stimme also nur aus Ja und Enthaltung, wissen wir
|
||||||
|
# das kein einziges Nein enthalten seien kann. Die Stimme passt
|
||||||
|
# also nicht auf unser Muster.
|
||||||
|
#
|
||||||
|
# Tritt hingegen nur ein einziges J auf, passt der regulaere Ausdruck
|
||||||
|
# nicht mehr, und wir wissen, dass die Stimme die Regel erfuellt.
|
||||||
|
#
|
||||||
|
# Wie wir sehen koennen, ist der negative Ausdruck leichter zu
|
||||||
|
# bilden als der positive.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Da eine Stimme nun sowohl aus direkten, als auch indirekten
|
||||||
|
# Stimmen bestehen kann (z.B. 'Jnnn..') muessen wir die Stimme
|
||||||
|
# zerlegen. Wir bilden einen positiven Regex fuer die Grossbuch-
|
||||||
|
# staben und einen negativen Regex fuer die kleinen.
|
||||||
|
#
|
||||||
|
# Passt eine Stimme dann auf den positiven Regex und nicht auf
|
||||||
|
# den negativen Regex, so entspricht sie der urspruenglichen
|
||||||
|
# Regel.
|
||||||
|
#
|
||||||
|
# Ein Beispiel: 'Sss..' (Der erste Punkt und der zweite oder dritte
|
||||||
|
# Punkt muessen ein Ja oder Nein sein.)
|
||||||
|
#
|
||||||
|
# positiver Regex: '[JN]...' muss erfuellt werden
|
||||||
|
# negativer Regex: '.EE.' darf nicht erfuellt werden
|
||||||
|
#
|
||||||
|
# JJNN => positiv matcht => negativ matcht nicht => Regel erfuellt
|
||||||
|
# ENJE => positiv matcht nicht => Regel nicht erfuellt
|
||||||
|
# NEEJ => positiv matcht => negativ matcht => Regel nicht erfuellt
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Mit Hilfe dieser Technik, lassen sich einfach Regex bilden, die
|
||||||
|
# ebenso einfach ueberprueft werden koennen.
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Read usevote.rul and check rules for correct syntax #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub read_rulefile {
|
||||||
|
@rules = ();
|
||||||
|
|
||||||
|
open (RULES, "<$config{rulefile}")
|
||||||
|
or die UVmessage::get("RULES_ERROPENFILE", (FILE => $config{rulefile})) . "\n\n";
|
||||||
|
|
||||||
|
while (<RULES>) {
|
||||||
|
chomp;
|
||||||
|
s/#.*$//; # delete comments
|
||||||
|
|
||||||
|
# does line match correct if-then syntax?
|
||||||
|
if (/^\s*if\s+(\S+)\s+then\s+(\S+)\s*$/) {
|
||||||
|
my $if = $1;
|
||||||
|
my $then = $2;
|
||||||
|
|
||||||
|
# $num contains the rule's array index
|
||||||
|
my $num = @rules;
|
||||||
|
|
||||||
|
# check for correct length of condition
|
||||||
|
my $errortext;
|
||||||
|
if (length($if) < @groups) {
|
||||||
|
$errortext = UVmessage::get("RULES_TOOSHORT", (NUM=>$num+1, TYPE=>"if"));
|
||||||
|
|
||||||
|
} elsif (length($if) > @groups) {
|
||||||
|
$errortext = UVmessage::get("RULES_TOOLONG", (NUM=>$num+1, TYPE=>"if"));
|
||||||
|
|
||||||
|
} elsif (length($then) < @groups) {
|
||||||
|
$errortext = UVmessage::get("RULES_TOOSHORT", (NUM=>$num+1, TYPE=>"then"));
|
||||||
|
|
||||||
|
} elsif (length($then) > @groups) {
|
||||||
|
$errortext = UVmessage::get("RULES_TOOLONG", (NUM=>$num+1, TYPE=>"then"));
|
||||||
|
}
|
||||||
|
die $errortext . ": $_\n\n" if ($errortext);
|
||||||
|
|
||||||
|
# check for correct characters in conditions
|
||||||
|
if ($if !~ /^[JjNnEeSsHhIi\.]+$/) {
|
||||||
|
die UVmessage::get ("RULES_INVCHARS", (NUM=>$num+1, TYPE=>"if")) . ": $if\n\n";
|
||||||
|
|
||||||
|
} elsif ($then !~ /^[JjNnEeSsHhIi\.]+$/) {
|
||||||
|
die UVmessage::get ("RULES_INVCHARS",
|
||||||
|
(NUM=>$num+1, TYPE=>"if")) . ": $then\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Zur Speicherung der Regeln (to be translated):
|
||||||
|
# - if_compl und then_compl sind die kompletten Bedingungen als Strings,
|
||||||
|
# werden fuer die Sprachausgabe der Regeln benoetigt
|
||||||
|
# - zusaetzlich werden der if- und then-Teil fuer die einfachere
|
||||||
|
# Verarbeitung in zwei Teile gesplittet: Eine Positiv-Regex, die auf
|
||||||
|
# die Grossbuchstaben (explizite Forderungen, UND-Verknuepfungen)
|
||||||
|
# matched, und eine Negativ-Regex, die bei den Kleinbuchstaben
|
||||||
|
# (optionale Felder, ODER-Verknuepfungen) verwendet wird.
|
||||||
|
|
||||||
|
my %rule = ( if_compl => $if,
|
||||||
|
if_pos => make_regex_pos($if),
|
||||||
|
if_neg => make_regex_neg($if),
|
||||||
|
then_compl => $then,
|
||||||
|
then_pos => make_regex_pos($then),
|
||||||
|
then_neg => make_regex_neg($then) );
|
||||||
|
|
||||||
|
push (@rules, \%rule);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Generates a RegEx for positive matching of the rules #
|
||||||
|
# #
|
||||||
|
# All lower case characters are replaced with dots, as they are to be #
|
||||||
|
# matched by the negativ RegEx. Furthermore the symbol S is replaced by [JN] #
|
||||||
|
# and I is replaced by [EN] (for use in combined votings when only one #
|
||||||
|
# option may be accepted and the others must be rejected or abstained. #
|
||||||
|
# As a result we have a regular expression that can be matched against the #
|
||||||
|
# received votes. #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub make_regex_pos {
|
||||||
|
my $pat = $_[0];
|
||||||
|
|
||||||
|
$pat =~ s/[hijens]/./g;
|
||||||
|
$pat =~ s/S/[JN]/g;
|
||||||
|
$pat =~ s/H/[EJ]/g;
|
||||||
|
$pat =~ s/I/[EN]/g;
|
||||||
|
|
||||||
|
return $pat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Generates a RegEx for negative matching of the rules #
|
||||||
|
# #
|
||||||
|
# All upper case characters are replaced with dots, as they are to be #
|
||||||
|
# matched by the positiv RegEx. If lower case characters are found the #
|
||||||
|
# condition is reversed, so that we are able to match votes *not* #
|
||||||
|
# corresponding to this rule #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub make_regex_neg {
|
||||||
|
my $pat = $_[0];
|
||||||
|
|
||||||
|
# upper case characters are replaced with dots
|
||||||
|
# (are covered by make_regex_pos)
|
||||||
|
$pat =~ s/[HIJENS]/./g;
|
||||||
|
|
||||||
|
# reverse lower case characters
|
||||||
|
$pat =~ s/j/[NE]/g;
|
||||||
|
$pat =~ s/n/[JE]/g;
|
||||||
|
$pat =~ s/e/[JN]/g;
|
||||||
|
$pat =~ s/s/E/g;
|
||||||
|
$pat =~ s/h/N/g;
|
||||||
|
$pat =~ s/i/J/g;
|
||||||
|
|
||||||
|
# If the string contained only upper case characters they are now all
|
||||||
|
# replaced with dots and the RegEx would match everything, i.e. declare
|
||||||
|
# every vote as invalid. In this case an empty pattern is returned.
|
||||||
|
$pat =~ s/^\.+$//;
|
||||||
|
|
||||||
|
return $pat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Check a voting for rule compliance #
|
||||||
|
# Parameters: Votes (Reference to Array) #
|
||||||
|
# Return value: Number of violated rule or 0 (everything OK) #
|
||||||
|
# (Internally rules are saved with indexes starting at 0) #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub rule_check {
|
||||||
|
my ($voteref) = @_;
|
||||||
|
|
||||||
|
# Turn array reference into a string
|
||||||
|
my $vote = join ('', @$voteref);
|
||||||
|
|
||||||
|
# For compliance with the rules every rule has to be matched against the
|
||||||
|
# the vote. If the IF clause matches but not the THEN clause the vote is
|
||||||
|
# invalid and the rule number is returned.
|
||||||
|
|
||||||
|
for (my $n = 0; $n < @rules; $n++) {
|
||||||
|
return $n+1 if ($vote =~ m/^$rules[$n]->{if_pos}$/ &&
|
||||||
|
$vote !~ m/^$rules[$n]->{if_neg}$/ &&
|
||||||
|
not($vote =~ m/^$rules[$n]->{then_pos}$/ &&
|
||||||
|
$vote !~ m/^$rules[$n]->{then_neg}$/ ));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Print rules in human readable format #
|
||||||
|
# Parameter: rule number #
|
||||||
|
# Return value: rule text #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub rule_print {
|
||||||
|
my ($n) = @_;
|
||||||
|
|
||||||
|
my $and = UVmessage::get ("RULES_AND");
|
||||||
|
my $or = UVmessage::get ("RULES_OR");
|
||||||
|
my $yes = UVmessage::get ("RULES_YES");
|
||||||
|
my $no = UVmessage::get ("RULES_NO");
|
||||||
|
my $abst = UVmessage::get ("RULES_ABSTAIN");
|
||||||
|
|
||||||
|
$n++;
|
||||||
|
my $text = UVmessage::get ("RULES_RULE") . " #$n:\n";
|
||||||
|
$text .= " " . UVmessage::get ("RULES_IF") . "\n";
|
||||||
|
|
||||||
|
my @rule = split (//, $rules[$n-1]->{if_compl});
|
||||||
|
my $firstrun = 1;
|
||||||
|
my $fill = "";
|
||||||
|
|
||||||
|
for (my $i=0; $i<@rule; $i++) {
|
||||||
|
my $text1 = "";
|
||||||
|
|
||||||
|
if ($rule[$i] eq 'J') {
|
||||||
|
$fill = " $and ";
|
||||||
|
$text1 = UVmessage::get ("RULES_IFCLAUSE", (VOTE=>$yes, GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'N') {
|
||||||
|
$fill = " $and ";
|
||||||
|
$text1 = UVmessage::get ("RULES_IFCLAUSE", (VOTE=>$no, GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'E') {
|
||||||
|
$fill = " $and ";
|
||||||
|
$text1 = UVmessage::get ("RULES_IFCLAUSE", (VOTE=>$abst, GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'S') {
|
||||||
|
$fill = " $and ";
|
||||||
|
$text1 = UVmessage::get ("RULES_IFCLAUSE",
|
||||||
|
(VOTE=>"$yes $or $no", GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'H') {
|
||||||
|
$fill = " $and ";
|
||||||
|
$text1 = UVmessage::get ("RULES_IFCLAUSE",
|
||||||
|
(VOTE=>"$abst $or $yes", GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'I') {
|
||||||
|
$fill = " $and ";
|
||||||
|
$text1 = UVmessage::get ("RULES_IFCLAUSE",
|
||||||
|
(VOTE=>"$abst $or $no", GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'j') {
|
||||||
|
$fill = " $or ";
|
||||||
|
$text1 = UVmessage::get ("RULES_IFCLAUSE", (VOTE=>$yes, GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'n') {
|
||||||
|
$fill = " $or ";
|
||||||
|
$text1 = UVmessage::get ("RULES_IFCLAUSE", (VOTE=>$no, GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'e') {
|
||||||
|
$fill = " $or ";
|
||||||
|
$text1 = UVmessage::get ("RULES_IFCLAUSE", (VOTE=>$abst, GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 's') {
|
||||||
|
$fill = " $or ";
|
||||||
|
$text1 = UVmessage::get ("RULES_IFCLAUSE",
|
||||||
|
(VOTE=>"$yes $or $no", GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'h') {
|
||||||
|
$fill = " $or ";
|
||||||
|
$text1 = UVmessage::get ("RULES_IFCLAUSE",
|
||||||
|
(VOTE=>"$abst $or $yes", GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'i') {
|
||||||
|
$fill = " $or ";
|
||||||
|
$text1 = UVmessage::get ("RULES_IFCLAUSE",
|
||||||
|
(VOTE=>"$abst $or $no", GROUP=>$groups[$i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($text1) {
|
||||||
|
if ($firstrun) {
|
||||||
|
$text .= " " . $text1 . "\n";
|
||||||
|
$firstrun = 0;
|
||||||
|
} else {
|
||||||
|
$text .= $fill . $text1 . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@rule = split (//, $rules[$n-1]->{then_compl});
|
||||||
|
$text .= " ..." . UVmessage::get ("RULES_THEN") . "\n";
|
||||||
|
$firstrun = 1;
|
||||||
|
|
||||||
|
for (my $i=0; $i<@rule; $i++) {
|
||||||
|
my $text1 = "";
|
||||||
|
if ($rule[$i] eq 'J') {
|
||||||
|
$fill = " $and ";
|
||||||
|
$text1 = UVmessage::get ("RULES_THENCLAUSE", (VOTE=>$yes, GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'N') {
|
||||||
|
$fill = " $and ";
|
||||||
|
$text1 = UVmessage::get ("RULES_THENCLAUSE", (VOTE=>$no, GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'E') {
|
||||||
|
$fill = " $and ";
|
||||||
|
$text1 = UVmessage::get ("RULES_THENCLAUSE", (VOTE=>$abst, GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'S') {
|
||||||
|
$fill = " $and ";
|
||||||
|
$text1 = UVmessage::get ("RULES_THENCLAUSE",
|
||||||
|
(VOTE=>"$yes $or $no", GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'H') {
|
||||||
|
$fill = " $and ";
|
||||||
|
$text1 = UVmessage::get ("RULES_THENCLAUSE",
|
||||||
|
(VOTE=>"$abst $or $yes", GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'I') {
|
||||||
|
$fill = " $and ";
|
||||||
|
$text1 = UVmessage::get ("RULES_THENCLAUSE",
|
||||||
|
(VOTE=>"$abst $or $no", GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'j') {
|
||||||
|
$fill = " $or ";
|
||||||
|
$text1 = UVmessage::get ("RULES_THENCLAUSE", (VOTE=>$yes, GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'n') {
|
||||||
|
$fill = " $or ";
|
||||||
|
$text1 = UVmessage::get ("RULES_THENCLAUSE", (VOTE=>$no, GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'e') {
|
||||||
|
$fill = " $or ";
|
||||||
|
$text1 = UVmessage::get ("RULES_THENCLAUSE", (VOTE=>$abst, GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 's') {
|
||||||
|
$fill = " $or ";
|
||||||
|
$text1 = UVmessage::get ("RULES_THENCLAUSE",
|
||||||
|
(VOTE=>"$yes $or $no", GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'h') {
|
||||||
|
$fill = " $or ";
|
||||||
|
$text1 = UVmessage::get ("RULES_THENCLAUSE",
|
||||||
|
(VOTE=>"$abst $or $yes", GROUP=>$groups[$i]));
|
||||||
|
} elsif ($rule[$i] eq 'i') {
|
||||||
|
$fill = " $or ";
|
||||||
|
$text1 = UVmessage::get ("RULES_THENCLAUSE",
|
||||||
|
(VOTE=>"$abst $or $no", GROUP=>$groups[$i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($text1) {
|
||||||
|
if ($firstrun) {
|
||||||
|
$text .= " " . $text1 . "\n";
|
||||||
|
$firstrun = 0;
|
||||||
|
} else {
|
||||||
|
$text .= $fill . $text1 . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $text . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
336
UVsendmail.pm
Normal file
336
UVsendmail.pm
Normal file
|
@ -0,0 +1,336 @@
|
||||||
|
# UVsendmail: functions for sending mails
|
||||||
|
# Used by uvvote.pl, uvcfv.pl
|
||||||
|
|
||||||
|
package UVsendmail;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use UVconfig;
|
||||||
|
use UVtemplate;
|
||||||
|
use MIME::Words;
|
||||||
|
use Text::Wrap qw(wrap $columns);
|
||||||
|
|
||||||
|
# Set columns for Text::Wrap
|
||||||
|
$columns = $config{rightmargin};
|
||||||
|
|
||||||
|
use vars qw($VERSION);
|
||||||
|
|
||||||
|
# Module version
|
||||||
|
$VERSION = "0.9";
|
||||||
|
|
||||||
|
my $num = 0;
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# generation of acknowledge and error mails (don't sends them out yet) #
|
||||||
|
# each mail is saved in a different file and a control file containing #
|
||||||
|
# filename and envelope-to address is generated. #
|
||||||
|
# Parameters: mail address, fixed part of subject and body of mail (strings) #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub mail {
|
||||||
|
my ($addr, $subject, $text, $reference, $replyto) = @_;
|
||||||
|
|
||||||
|
# address set?
|
||||||
|
if ($addr) {
|
||||||
|
# generate mail to sender
|
||||||
|
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
$template->setKey('from' => mimeencode($config{mailfrom}));
|
||||||
|
$template->setKey('subject' => mimeencode("$config{votename} - $subject"));
|
||||||
|
$template->setKey('address' => $addr);
|
||||||
|
$template->setKey('reference' => $reference) if ($reference);
|
||||||
|
$template->setKey('reply-to' => $replyto) if ($replyto);
|
||||||
|
$template->setKey('usevote-version' => $usevote_version);
|
||||||
|
|
||||||
|
my $message = $template->processTemplate($config{'tpl_mailheader'});
|
||||||
|
$message .= "\n" . $text;
|
||||||
|
|
||||||
|
# get envelope-to addresses
|
||||||
|
my $envaddr = $addr;
|
||||||
|
$envaddr .= " $config{mailcc}" if ($config{mailcc});
|
||||||
|
|
||||||
|
my $mailfile = '';
|
||||||
|
|
||||||
|
# search for file names
|
||||||
|
do {
|
||||||
|
$num++;
|
||||||
|
$mailfile = "$config{tmpdir}/ack.$num";
|
||||||
|
} while (-e $mailfile);
|
||||||
|
|
||||||
|
# write mail in a file and append a line at the control file
|
||||||
|
|
||||||
|
open (CONTROL, ">>$config{controlfile}") or print STDERR "\n\n",
|
||||||
|
UVmessage::get("SENDMAIL_ERROPENCONTROL", (FILE => $config{controlfile})), "\n";
|
||||||
|
print CONTROL "$mailfile\t$envaddr\n";
|
||||||
|
close (CONTROL) or print STDERR "\n\n",
|
||||||
|
UVmessage::get("SENDMAIL_ERRCLOSECONTROL", (FILE => $config{controlfile})), "\n";
|
||||||
|
|
||||||
|
open (MAIL, ">$mailfile") or print STDERR "\n\n",
|
||||||
|
UVmessage::get("SENDMAIL_ERROPENMAIL", (FILE => $config{controlfile})), "\n";
|
||||||
|
print MAIL $message;
|
||||||
|
close (MAIL) or print STDERR "\n\n",
|
||||||
|
UVmessage::get("SENDMAIL_ERRCLOSEMAIL", (FILE => $config{controlfile})), "\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Send previously generated acknowledge or error mails. #
|
||||||
|
# Depending on configuration mails are piped to your MTA or send via SMTP. #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub send {
|
||||||
|
unless (-e $config{controlfile}) {
|
||||||
|
print "\n", UVmessage::get("SENDMAIL_NOMAILS", (FILE => $config{controlfile})),
|
||||||
|
"\n\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
open (CONTROL, "<$config{controlfile}") or die "\n\n",
|
||||||
|
UVmessage::get("SENDMAIL_ERROPENCONTROL", (FILE => $config{controlfile})), "\n";
|
||||||
|
my @mailinfo = <CONTROL>;
|
||||||
|
close (CONTROL);
|
||||||
|
|
||||||
|
print UVmessage::get("SENDMAIL_SENDING"), "\n";
|
||||||
|
|
||||||
|
if ($config{smtp}) {
|
||||||
|
# send mails via SMTP
|
||||||
|
use Net::SMTP;
|
||||||
|
my $smtp = Net::SMTP->new("$config{smtpserver}:$config{smtpport}",
|
||||||
|
Hello => $config{smtphelo});
|
||||||
|
die UVmessage::get("SENDMAIL_SMTP_CONNREFUSED") . "\n\n" unless ($smtp);
|
||||||
|
if ($config{smtpauth}) {
|
||||||
|
$smtp->auth($config{smtpuser}, $config{smtppass})
|
||||||
|
or die UVmessage::get("SENDMAIL_SMTP_CONNREFUSED") . "\n" .
|
||||||
|
$smtp->code() . ' ' . $smtp->message() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
my $errors = 0;
|
||||||
|
my $missingfiles = 0;
|
||||||
|
|
||||||
|
open (CONTROL, ">$config{controlfile}") or die "\n\n",
|
||||||
|
UVmessage::get("SENDMAIL_ERROPENCONTROL", (FILE => $config{controlfile})), "\n";
|
||||||
|
|
||||||
|
foreach my $mail (@mailinfo) {
|
||||||
|
|
||||||
|
chomp ($mail);
|
||||||
|
next unless $mail;
|
||||||
|
|
||||||
|
my ($file, $envelope) = split(/\t/, $mail);
|
||||||
|
my $notfound = 0;
|
||||||
|
open (MAIL, "<$file") or $notfound = 1;
|
||||||
|
if ($notfound) {
|
||||||
|
print STDERR UVmessage::get("SENDMAIL_ERRNOTFOUND") . "\n";
|
||||||
|
$missingfiles++;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
my $message = join('', <MAIL>);
|
||||||
|
close (MAIL);
|
||||||
|
|
||||||
|
next unless $message;
|
||||||
|
|
||||||
|
$smtp->reset();
|
||||||
|
$smtp->mail($config{envelopefrom});
|
||||||
|
unless ($smtp->ok()) {
|
||||||
|
print STDERR UVmessage::get("SENDMAIL_SMTP_INVRCPT", (RCPT => $envelope)),
|
||||||
|
"\n", $smtp->code(), ' ', $smtp->message(), "\n";
|
||||||
|
$errors++;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $onesent = 0;
|
||||||
|
my $onefail = 0;
|
||||||
|
foreach my $addr (split(/ +/, $envelope)) {
|
||||||
|
$smtp->to($addr);
|
||||||
|
if ($smtp->ok()) {
|
||||||
|
$onesent = 1;
|
||||||
|
} else {
|
||||||
|
print CONTROL ($onefail ? " " : "$file\t");
|
||||||
|
print CONTROL $addr;
|
||||||
|
print STDERR UVmessage::get("SENDMAIL_SMTP_INVRCPT", (RCPT => $envelope)),
|
||||||
|
"\n", $smtp->code(), ' ', $smtp->message(), "\n";
|
||||||
|
$errors++;
|
||||||
|
$onefail = 1;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print CONTROL "\n" if ($onefail);
|
||||||
|
next unless $onesent;
|
||||||
|
|
||||||
|
$smtp->data();
|
||||||
|
if ($smtp->ok()) {
|
||||||
|
$smtp->datasend($message);
|
||||||
|
$smtp->dataend();
|
||||||
|
}
|
||||||
|
unless ($smtp->ok()) {
|
||||||
|
print STDERR UVmessage::get("SENDMAIL_SMTP_INVRCPT", (RCPT => $envelope)),
|
||||||
|
"\n", $smtp->code(), ' ', $smtp->message(), "\n";
|
||||||
|
$errors++;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
unlink ($file) unless ($onefail);
|
||||||
|
}
|
||||||
|
|
||||||
|
$smtp->quit();
|
||||||
|
close (CONTROL) or die "\n\n",
|
||||||
|
UVmessage::get("SENDMAIL_ERRCLOSECONTROL", (FILE => $config{controlfile})), "\n";
|
||||||
|
|
||||||
|
if ($errors) {
|
||||||
|
print STDERR "\n".wrap('', '', "$errors ".UVmessage::get("SENDMAIL_ERROCCURED"))."\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($missingfiles) {
|
||||||
|
print STDERR wrap('', '', "$missingfiles " .
|
||||||
|
UVmessage::get("SENDMAIL_MISSINGFILES")), "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
foreach my $mail (@mailinfo) {
|
||||||
|
next unless $mail;
|
||||||
|
chomp($mail);
|
||||||
|
my ($file, @rcpt) = split(/\s+/, $mail);
|
||||||
|
open (DOMAIL, ">>$config{domailfile}");
|
||||||
|
print DOMAIL "$config{mailcmd} ";
|
||||||
|
foreach my $rcpt (@rcpt) {
|
||||||
|
print DOMAIL "'$rcpt' ";
|
||||||
|
}
|
||||||
|
print DOMAIL "<$file && rm $file ; $config{sleepcmd}\n";
|
||||||
|
close (DOMAIL)
|
||||||
|
or print STDERR "\n\n", UVmessage::get("SENDMAIL_ERRCLOSEDOMAIL"), "\n";
|
||||||
|
}
|
||||||
|
chmod(0700, $config{domailfile});
|
||||||
|
system($config{domailfile});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
opendir (DIR, $config{tmpdir});
|
||||||
|
my @files = grep (/^ack\.\d+/, readdir (DIR));
|
||||||
|
closedir (DIR);
|
||||||
|
return 0 if (@files);
|
||||||
|
|
||||||
|
unlink $config{controlfile} or print STDERR "\n\n",
|
||||||
|
UVmessage::get("SENDMAIL_ERRDELCONTROL", (FILE => $config{controlfile})), "\n";
|
||||||
|
|
||||||
|
unless ($config{smtp}) {
|
||||||
|
unlink $config{domailfile} or print STDERR "\n\n",
|
||||||
|
UVmessage::get("SENDMAIL_ERRDELCONTROL", (FILE => $config{domailfile})), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Encodes a string for use in mail headers #
|
||||||
|
# #
|
||||||
|
# Parameters: $text = string to encode. #
|
||||||
|
# Returns: $newtext = encoded string. #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub mimeencode {
|
||||||
|
my ($text) = @_;
|
||||||
|
my @words = split(/ /, $text);
|
||||||
|
my $line = '';
|
||||||
|
my @lines;
|
||||||
|
|
||||||
|
foreach my $word (@words) {
|
||||||
|
my $sameword = 0;
|
||||||
|
$word =~ s/\n//g;
|
||||||
|
my $encword;
|
||||||
|
if ($word =~ /[\x7F-\xFF]/) {
|
||||||
|
$encword = MIME::Words::encode_mimeword($word, 'Q', 'ISO-8859-1');
|
||||||
|
} elsif (length($word) > 75) {
|
||||||
|
$encword = MIME::Words::encode_mimeword($word, 'Q', 'us-ascii');
|
||||||
|
} else {
|
||||||
|
$encword = $word;
|
||||||
|
}
|
||||||
|
|
||||||
|
# no more than 75 chars per line allowed
|
||||||
|
if (length($encword) > 75) {
|
||||||
|
while ($encword) {
|
||||||
|
if ($encword =~ /(^=\?[-\w]+\?\w\?)(.{55}.*?)((=.{2}|[^=]{3}).*\?=)$/) {
|
||||||
|
addword($1 . $2 . '?=', \$line, \@lines, $sameword);
|
||||||
|
$encword = $1 . $3;
|
||||||
|
} else {
|
||||||
|
addword($encword, \$line, \@lines, $sameword);
|
||||||
|
$encword = '';
|
||||||
|
}
|
||||||
|
$sameword = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addword($encword, \$line, \@lines, $sameword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my $delim = (@lines) ? ' ' : '';
|
||||||
|
push(@lines, $delim . $line) if ($line);
|
||||||
|
return join('', @lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Adds a word to a MIME encoded string, inserts linefeed if necessary #
|
||||||
|
# #
|
||||||
|
# Parameters: #
|
||||||
|
# $word = word to add #
|
||||||
|
# $line = current line #
|
||||||
|
# $lines = complete text (without current line) #
|
||||||
|
# $sameword = boolean switch, indicates that this is another part of #
|
||||||
|
# the last word (for encoded words > 75 chars) #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub addword {
|
||||||
|
my ($word, $line, $lines, $sameword) = @_;
|
||||||
|
|
||||||
|
# If the passed fragment is a new word (and not another part of the
|
||||||
|
# previous): Check if it is MIME encoded
|
||||||
|
if (!$sameword && $word =~ /^(=\?[^\?]+?\?[QqBb]\?)(.+\?=[^\?]*)$/) {
|
||||||
|
|
||||||
|
# Word is encoded, save without the MIME header
|
||||||
|
# (e.g. "t=E4st?=" instead of "?iso-8859-1?q?t=E4st?=")
|
||||||
|
my $charset = $1;
|
||||||
|
my $newword = $2;
|
||||||
|
|
||||||
|
if ($$line =~ /^(=\?[^\?]+\?[QqBb]\?)(.+)\?=$/) {
|
||||||
|
# Previous word was encoded, too:
|
||||||
|
# Delete the trailing "?=" and insert an underline character (=space)
|
||||||
|
# (space between to encoded words is ignored)
|
||||||
|
if ($1 eq $charset) {
|
||||||
|
if (length($1.$2)+length($newword)>75) {
|
||||||
|
my $delim = (@$lines) ? ' ' : '';
|
||||||
|
push(@$lines, "$delim$1$2_?=\n");
|
||||||
|
$$line = $word;
|
||||||
|
} else {
|
||||||
|
$$line = $1 . $2 . '_' . $newword;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (length("$$line $word")>75) {
|
||||||
|
my $delim = (@$lines) ? ' ' : '';
|
||||||
|
push(@$lines, "$delim$1$2_?=\n");
|
||||||
|
$$line = $word;
|
||||||
|
} else {
|
||||||
|
$$line = "$1$2_?= $word";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# New word is not encoded: simply append it, but check for line length
|
||||||
|
# and add a newline if necessary
|
||||||
|
if (length($$line) > 0) {
|
||||||
|
if (length($$line) + length($word) >= 75) {
|
||||||
|
my $delim = (@$lines) ? ' ' : '';
|
||||||
|
push(@$lines, "$delim$$line\n");
|
||||||
|
$$line = $word;
|
||||||
|
} else {
|
||||||
|
$$line .= " $word";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# line is empty
|
||||||
|
$$line = $word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
810
UVtemplate.pm
Normal file
810
UVtemplate.pm
Normal file
|
@ -0,0 +1,810 @@
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
package UVtemplate;
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
UVtemplate - Templateverarbeitung und String-Formatierungen
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
use UVtemplate;
|
||||||
|
|
||||||
|
$plate = UVtemplate->new([%keys]);
|
||||||
|
|
||||||
|
$plate->setKey(%keys);
|
||||||
|
$item = $plate->addListItem($name, %keys);
|
||||||
|
|
||||||
|
$string = $plate->processTemplate($file);
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Mit Hilfe von UVtemplate, wird die komplette Aufbereitung und
|
||||||
|
Formatierung der Programmausgaben nicht nur ausgelagert sondern
|
||||||
|
auch so flexibiliert, dass sie jederzeit angepasst werden kann,
|
||||||
|
ohne das im eigentlichen Programmcode veraendert werden muss.
|
||||||
|
|
||||||
|
Auf Programmseite wird eine Datenstruktur mit Schluessel-Wert
|
||||||
|
Paaren erzeugt. In den Template-Dateien werden dann spaeter die
|
||||||
|
jeweiligen Schluessel, durch ihre im Programm festgelegten
|
||||||
|
Werte ersetzt. Zusaetzlich ist es moeglich Schluessel zu Listen
|
||||||
|
zusammenzufassen.
|
||||||
|
|
||||||
|
Da es sich bei den Templates um Ascii-Texte handelt, gibt es
|
||||||
|
zusaetzlich die Moeglichkeit die Werte der Schluessel zuformatieren
|
||||||
|
um eine einheitliche Ausgabe zu ermoeglichen. D.h. es kann z.B. durch
|
||||||
|
das Anhaengen von Leerzeichen dafuer gesorgt werden, das ein Schluessel
|
||||||
|
einer Liste immer 60 Zeichen lang ist um ansehnliche Tabellen auszugeben.
|
||||||
|
|
||||||
|
=head1 FUNCTIONS
|
||||||
|
|
||||||
|
=over 3
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use vars qw( $VERSION $functions @dirs);
|
||||||
|
use UVconfig;
|
||||||
|
|
||||||
|
$VERSION = 0.1;
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=item new
|
||||||
|
|
||||||
|
Eine neues Objekt vom Typ UVtemplate anlegen.
|
||||||
|
|
||||||
|
my $plate = UVtemplate->new();
|
||||||
|
|
||||||
|
Als Parameter koennen gleich beliebig viele Schluessel-Wert-Paare
|
||||||
|
uebergeben werden.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub new{
|
||||||
|
my $class = shift;
|
||||||
|
my $self = {};
|
||||||
|
|
||||||
|
if (ref($class)){
|
||||||
|
$self->{FATHER} = $class;
|
||||||
|
bless($self, ref($class));
|
||||||
|
|
||||||
|
}else{
|
||||||
|
bless($self, $class);
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->setKey(@_);
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
=item setKey
|
||||||
|
|
||||||
|
Schluessel und zugehoerige Werte im Objekt speichern.
|
||||||
|
|
||||||
|
$plate->setKey( vote-addr => 'to-vote@dom.ain' );
|
||||||
|
$plate->setKey( datenschutz => 1);
|
||||||
|
|
||||||
|
Ist der zu speichernde Schluessel bereits vorhanden, wird er
|
||||||
|
durch den neuen Wert ueberschrieben.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub setKey{
|
||||||
|
my $self = shift;
|
||||||
|
my %param = @_;
|
||||||
|
|
||||||
|
foreach my $key (keys(%param)){
|
||||||
|
$self->{KEYS}->{$key} = $param{$key};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
=item addListItem
|
||||||
|
|
||||||
|
Erzeugt ein neues Objekt vom Typ UVtemplate und fuegt es der
|
||||||
|
angebenen Liste hinzu.
|
||||||
|
|
||||||
|
$plate->addListItem(name => 'Musterman', email => 'em@il');
|
||||||
|
|
||||||
|
Da sich Listen wie normale Schluessel-Wert Paare verhalten,
|
||||||
|
wird die Liste als Array ueber UVtemplate-Objekte unter dem
|
||||||
|
definiertem Schluessel abgelegt. Ist dieser Schluessel bereits
|
||||||
|
gesetzt und enthaehlt keinen Array, so bricht die Funktion ab.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub addListItem{
|
||||||
|
my $self = shift;
|
||||||
|
my $list = shift;
|
||||||
|
|
||||||
|
# pruefen ob key angegeben ist und falls key vorhanden
|
||||||
|
# eine liste vorliegt
|
||||||
|
return unless ($list && (not($self->{KEYS}->{$list}) ||
|
||||||
|
UNIVERSAL::isa($self->{KEYS}->{$list}, 'ARRAY')));
|
||||||
|
|
||||||
|
# neues Element erzeugen
|
||||||
|
my $new = $self->new( @_ );
|
||||||
|
|
||||||
|
# an listen anhaengen
|
||||||
|
push(@{$self->{KEYS}->{$list}}, $new);
|
||||||
|
|
||||||
|
# referenz zurueckgeben
|
||||||
|
return $new;
|
||||||
|
}
|
||||||
|
|
||||||
|
=item getKey($key)
|
||||||
|
|
||||||
|
Den Wert eines Schluessel ermitteln.
|
||||||
|
|
||||||
|
my $value = $plate->getKey('email');
|
||||||
|
|
||||||
|
Ist der Wert im Objekt nicht gesetzt, wird - falls es sich um ein
|
||||||
|
Element einer Liste handelt - rekursiv beim Vater weiter gesucht.
|
||||||
|
|
||||||
|
So stehen allen Kindern auch die Schluessel-Wert Paare ihrer Eltern
|
||||||
|
zur Verfuegung.
|
||||||
|
|
||||||
|
Zum Schluss wird noch geprueft, ob der Schluessel in usevote.cfg
|
||||||
|
gesetzt wurde. Dadurch sind alle Konfigurationsoptionen direkt
|
||||||
|
in Templates nutzbar.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub getKey{
|
||||||
|
my $self = shift;
|
||||||
|
my $key = $_[0];
|
||||||
|
|
||||||
|
my $value;
|
||||||
|
|
||||||
|
do{
|
||||||
|
$value = $self->{KEYS}->{$key};
|
||||||
|
$self = $self->{FATHER};
|
||||||
|
|
||||||
|
}while(!defined($value) && $self);
|
||||||
|
|
||||||
|
if (!defined($value) && defined($config{$key})) {
|
||||||
|
$value = $config{$key};
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
sub getRules{
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
do{
|
||||||
|
return $self->{RULES} if ($self->{RULES});
|
||||||
|
$self = $self->{FATHER};
|
||||||
|
}while($self);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
=item getConvKey{
|
||||||
|
|
||||||
|
Einen Format ermitteln.
|
||||||
|
|
||||||
|
my $value = $plate->getConvKey('email-adresse');
|
||||||
|
|
||||||
|
Diese Funktion ueberprueft ob eine Formatierung mit den entsprechenden
|
||||||
|
Schluessel definiert ist und ruft dementsprechend die dort definierten
|
||||||
|
Funktionen ueber der Datenstruktur auf.
|
||||||
|
|
||||||
|
Ist kein solches Format definiert, wird der Wert des Schluessel mit
|
||||||
|
einem solchen Namen zurueckgegeben. (Es wird intern getKey aufgerufen).
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub getConvKey{
|
||||||
|
my $self = shift;
|
||||||
|
my $key = $_[0] || return;
|
||||||
|
|
||||||
|
my $rules = $self->getRules();
|
||||||
|
my $value = $self->getKey($key);
|
||||||
|
|
||||||
|
$value = '' unless (defined($value));
|
||||||
|
|
||||||
|
if ($rules && ($rules->{$key})){
|
||||||
|
my @funcs = @{$rules->{$key}};
|
||||||
|
|
||||||
|
foreach my $func (@funcs){
|
||||||
|
my ($name, @params) = @$func;
|
||||||
|
|
||||||
|
if ($functions->{$name}){
|
||||||
|
$value = $functions->{$name}->($self, $value, @params);
|
||||||
|
|
||||||
|
}else{
|
||||||
|
print STDERR "format function '$name' not found!\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
=item processTemplate
|
||||||
|
|
||||||
|
Daten des Objekts in ein Template einfuegen.
|
||||||
|
|
||||||
|
my $string = $plate->processTemplate('template/info.txt');
|
||||||
|
|
||||||
|
Die angebene Datei wird eingelesen, zerlegt und danach
|
||||||
|
die enstprechenden Platzhalter durch die (formatierten)
|
||||||
|
Werte aus der Datenstruktur ersetzt.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub processTemplate{
|
||||||
|
my $self = shift;
|
||||||
|
my $file = $_[0] || return;
|
||||||
|
|
||||||
|
my ($rules, $body) = _split_file($file);
|
||||||
|
|
||||||
|
# konvertierungsregeln parsen
|
||||||
|
$self->{RULES} = _parse_rules($rules);
|
||||||
|
|
||||||
|
# template zerlegen (zuerst fuehrende leerzeilen entfernen!)
|
||||||
|
$body =~ s/^\n+//s;
|
||||||
|
my $token = UVtemplate::scan->new(string => $body);
|
||||||
|
|
||||||
|
# daten einsetzen
|
||||||
|
return $token->processData($self);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _split_file{
|
||||||
|
my $file = $_[0] || return;
|
||||||
|
|
||||||
|
my $fname = _complete_filename($file);
|
||||||
|
|
||||||
|
unless ($fname){
|
||||||
|
print STDERR "couldnt find '$file'\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
my (@rules, @body);
|
||||||
|
|
||||||
|
open(PLATE, $fname);
|
||||||
|
my @lines = <PLATE>;
|
||||||
|
close(PLATE);
|
||||||
|
|
||||||
|
my $body = 0;
|
||||||
|
|
||||||
|
foreach my $line (@lines){
|
||||||
|
if ($line =~ m/^== TEMPLATE/){
|
||||||
|
$body = 1;
|
||||||
|
|
||||||
|
}else{
|
||||||
|
if ($body){
|
||||||
|
push(@body, $line);
|
||||||
|
|
||||||
|
}else{
|
||||||
|
push(@rules, $line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# falls kein Separator definiert war, wird der komplette Text
|
||||||
|
# als Body interpretiert. Es gibt keine Regeln!
|
||||||
|
|
||||||
|
unless ($body){
|
||||||
|
@body = @rules;
|
||||||
|
@rules = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
# und nun wieder zu Strings zusammenpappen
|
||||||
|
return (join('', @rules), join('', @body));
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _complete_filename{
|
||||||
|
my $file = $_[0] || return;
|
||||||
|
|
||||||
|
my $dirs = $UVconfig::config{templatedir};
|
||||||
|
@dirs = split(/\s*,\s*/, $dirs) if $dirs;
|
||||||
|
|
||||||
|
my $fname;
|
||||||
|
|
||||||
|
foreach my $dir (@dirs, '.'){
|
||||||
|
$fname = "$dir/$file";
|
||||||
|
return $fname if (-r $fname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
# Konvertierungs-Regeln
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
sub _parse_rules{
|
||||||
|
my $string = $_[0] || return;
|
||||||
|
|
||||||
|
my @stack;
|
||||||
|
my $rules = {};
|
||||||
|
|
||||||
|
my $this = [];
|
||||||
|
|
||||||
|
while (length($string) > 0){
|
||||||
|
_strip_chars(\$string);
|
||||||
|
|
||||||
|
my $token = _parse_token(\$string);
|
||||||
|
|
||||||
|
if ($token){
|
||||||
|
push(@stack, $token);
|
||||||
|
|
||||||
|
_strip_chars(\$string);
|
||||||
|
|
||||||
|
if ($string =~ s/^:=//){
|
||||||
|
# neuen Schluessel vom Stack holen
|
||||||
|
my $key = pop(@stack);
|
||||||
|
|
||||||
|
# restlichen Stack auf alten Schluessel packen
|
||||||
|
push(@$this, [ @stack ]);
|
||||||
|
@stack = ();
|
||||||
|
|
||||||
|
# neuen Schluessel anlegen
|
||||||
|
$rules->{$key} = $this = [];
|
||||||
|
|
||||||
|
}elsif($string =~ s/^\|//){
|
||||||
|
# stack auf schluessel packen
|
||||||
|
push(@$this, [ @stack ]);
|
||||||
|
@stack = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
}else{
|
||||||
|
# fehlermeldung ausgeben (nacharbeiten!)
|
||||||
|
print STDERR "Syntaxerror in Definition\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# den Rest vom Stack abarbeiten
|
||||||
|
push(@$this, [ @stack ]) if @stack;
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _strip_chars{
|
||||||
|
my $line = $_[0] || return;
|
||||||
|
|
||||||
|
# führenden whitespace entfernen
|
||||||
|
$$line =~ s/^\s+//;
|
||||||
|
|
||||||
|
# kommentare bis zum nächsten Zeilenumbruch entfernen
|
||||||
|
$$line =~ s/^#.*$//m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub _parse_token{
|
||||||
|
my $string = shift;
|
||||||
|
|
||||||
|
if ($$string =~ s/^(["'])//){
|
||||||
|
return _parse_string($string, $1);
|
||||||
|
|
||||||
|
}else{
|
||||||
|
return _parse_ident($string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub _parse_string{
|
||||||
|
my ($string, $limit) = @_;
|
||||||
|
|
||||||
|
my $value;
|
||||||
|
|
||||||
|
while ($$string){
|
||||||
|
if ($$string =~ s/^$limit//){
|
||||||
|
$$string =~ s/^\s*//;
|
||||||
|
return $value;
|
||||||
|
|
||||||
|
}elsif($$string =~ s/^\\(.)//){
|
||||||
|
$value .= $1;
|
||||||
|
|
||||||
|
}else{
|
||||||
|
$$string =~ s/^[^$limit\\]*//;
|
||||||
|
$value .= $&;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# end of line
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub _parse_ident{
|
||||||
|
my $string = shift;
|
||||||
|
|
||||||
|
if ($$string =~ s/^([A-Za-z0-9-]+)\s*//){
|
||||||
|
return $1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
BEGIN{
|
||||||
|
$functions = \%UVconfig::functions;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
package UVtemplate::scan;
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
sub new{
|
||||||
|
my $class = shift;
|
||||||
|
my %param = @_;
|
||||||
|
|
||||||
|
my $self = {};
|
||||||
|
bless($self, $class);
|
||||||
|
|
||||||
|
$self->parseFile($param{file}) if defined($param{file});
|
||||||
|
$self->parseString($param{string}) if defined($param{string});
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
sub processData{
|
||||||
|
my $self = shift;
|
||||||
|
my $data = $_[0];
|
||||||
|
|
||||||
|
return _process_data($self->{toks}, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _process_data{
|
||||||
|
my ($toref, $data) = @_;
|
||||||
|
|
||||||
|
my $string = '';
|
||||||
|
my $length = 0;
|
||||||
|
my $empty = 0;
|
||||||
|
|
||||||
|
foreach my $token (@$toref){
|
||||||
|
if (ref($token)){
|
||||||
|
my $before = length($string);
|
||||||
|
$empty = 0;
|
||||||
|
|
||||||
|
if ($token->[0] eq 'VAR'){
|
||||||
|
my $value = $data->getConvKey(_process_data($token->[1], $data));
|
||||||
|
|
||||||
|
if (defined($value) && length($value)){
|
||||||
|
$string .= $value;
|
||||||
|
|
||||||
|
}else{
|
||||||
|
$string .= _process_data($token->[2], $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}elsif($token->[0] eq 'IF'){
|
||||||
|
if ($data->getConvKey(_process_data($token->[1], $data))){
|
||||||
|
$string .= _process_data($token->[2], $data);
|
||||||
|
|
||||||
|
}else{
|
||||||
|
$string .= _process_data($token->[3], $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}elsif($token->[0] eq 'LOOP'){
|
||||||
|
my $nodes = $data->getConvKey(_process_data($token->[1], $data));
|
||||||
|
my @block;
|
||||||
|
|
||||||
|
if ($nodes && (UNIVERSAL::isa($nodes, 'ARRAY'))){
|
||||||
|
foreach my $node (@$nodes){
|
||||||
|
push(@block, _process_data($token->[2], $node));
|
||||||
|
}
|
||||||
|
|
||||||
|
$string .= join(_process_data($token->[3], $data), @block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$length = length($string);
|
||||||
|
$empty = 1 if ($before == $length);
|
||||||
|
|
||||||
|
}else{
|
||||||
|
if ($empty && ($string =~ m/(\n|^)$/s)){
|
||||||
|
$empty = 0; # Falls die letzte Zeile nur aus einem Token
|
||||||
|
$token =~ s/^\n//s; # ohne Inhalt bestand, wird die Zeile entfernt
|
||||||
|
}
|
||||||
|
|
||||||
|
$string .= $token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
# Den String in einen Syntaxbaum abbilden
|
||||||
|
|
||||||
|
sub _parse_token_string{
|
||||||
|
my $self = shift;
|
||||||
|
my ($string, $intern) = @_;
|
||||||
|
|
||||||
|
my (@token, $toref);
|
||||||
|
my $data = '';
|
||||||
|
|
||||||
|
while ($string){
|
||||||
|
if ($intern && $string =~ m/^(\]|\|)/){
|
||||||
|
last;
|
||||||
|
|
||||||
|
}elsif ($string =~ s/^\[//){
|
||||||
|
my $orig = $string;
|
||||||
|
|
||||||
|
($toref, $string) = $self->_parse_token($string);
|
||||||
|
|
||||||
|
if (@$toref){
|
||||||
|
push (@token, $data) if $data;
|
||||||
|
$data = '';
|
||||||
|
|
||||||
|
push(@token, $toref)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($string !~ s/^\]//){
|
||||||
|
my $pos = $self->{lines} - _count_lines($orig) + 1;
|
||||||
|
|
||||||
|
print STDERR "Scanner: [$pos] missing right bracket\n";
|
||||||
|
return (\@token, $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
}elsif($string =~ s/^\\n//s){
|
||||||
|
$data .= "\n";
|
||||||
|
|
||||||
|
}elsif($string =~ s/^\\(.)//s){
|
||||||
|
$data .= $1;
|
||||||
|
|
||||||
|
}elsif($intern){
|
||||||
|
$string =~ s/^([^\]\[\|\\]+)//s;
|
||||||
|
$data .= $1;
|
||||||
|
|
||||||
|
}else{
|
||||||
|
$string =~ s/^([^\[\\]+)//s;
|
||||||
|
$data .= $1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
push (@token, $data) if length($data);
|
||||||
|
return (\@token, $string)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub _parse_token{
|
||||||
|
my $self = shift;
|
||||||
|
my $string = $_[0];
|
||||||
|
|
||||||
|
my @token = ();
|
||||||
|
|
||||||
|
if ($string =~ s/^\$//s){
|
||||||
|
# Variablen - Syntax: [$key[|<else>]]
|
||||||
|
push (@token, 'VAR');
|
||||||
|
|
||||||
|
}elsif ($string =~ s/^\?//s){
|
||||||
|
# Bedingung - Syntax: [?if|<then>[|<else>]]
|
||||||
|
push (@token, 'IF');
|
||||||
|
|
||||||
|
}elsif ($string =~ s/^\@//s){
|
||||||
|
# Schleifen - Syntax: [@key|<block>[|<sep>]]
|
||||||
|
push (@token, 'LOOP');
|
||||||
|
|
||||||
|
}elsif ($string =~ s/^#//s){
|
||||||
|
# Kommentare - Syntax: [# ... ]
|
||||||
|
$string = _parse_comment($string);
|
||||||
|
|
||||||
|
return (\@token, $string);
|
||||||
|
|
||||||
|
}else{
|
||||||
|
print STDERR "unknown token in template\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
my $toref;
|
||||||
|
|
||||||
|
($toref, $string) = $self->_parse_token_string($string, 1);
|
||||||
|
push(@token, $toref);
|
||||||
|
|
||||||
|
while ($string =~ s/^\|//){
|
||||||
|
($toref, $string) = $self->_parse_token_string($string, 1);
|
||||||
|
push(@token, $toref);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (\@token, $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub _parse_comment{
|
||||||
|
my $string = $_[0];
|
||||||
|
my $count = 1;
|
||||||
|
|
||||||
|
while($string && $count) {
|
||||||
|
$string =~ s/^[^\[\]\\]+//s; # alles außer Klammern und Backslash wegwerfen
|
||||||
|
$string =~ s/^\\.//; # alles gesperrte löschen
|
||||||
|
|
||||||
|
$count++ if $string =~ s/^\[//;
|
||||||
|
$count-- if $string =~ s/^\]//;
|
||||||
|
}
|
||||||
|
|
||||||
|
$string = ']'.$string if !$count;
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
sub parseString{
|
||||||
|
my $self = shift;
|
||||||
|
my $text = $_[0];
|
||||||
|
|
||||||
|
$self->{lines} = _count_lines($text);
|
||||||
|
my ($toref, $rest) = $self->_parse_token_string($text);
|
||||||
|
|
||||||
|
$self->{toks} = $toref;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub _count_lines{
|
||||||
|
return 0 unless defined($_[0]);
|
||||||
|
|
||||||
|
my ($string, $count) = ($_[0], 1);
|
||||||
|
$count++ while($string =~ m/\n/sg);
|
||||||
|
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 SYNTAX
|
||||||
|
|
||||||
|
Eine Templatedatei besteht aus zwei Teilen. Am Anfang werden die
|
||||||
|
Formatierungen bestimmter Schluessel definiert und nach einem
|
||||||
|
Trenner folgt der eigentlich Template-Koerper, der dann von Programm
|
||||||
|
bearbeitet und ausgegeben wird.
|
||||||
|
|
||||||
|
format-key := function1 param | function2 param
|
||||||
|
|
||||||
|
== TEMPLATE ====================================
|
||||||
|
|
||||||
|
Ich bin nun das eigentliche Template:
|
||||||
|
|
||||||
|
format-key: [$format-key]
|
||||||
|
|
||||||
|
Der Trenner beginnt mit den Zeichen '== TEMPLATE' danach koennen
|
||||||
|
beliebige Zeichen folgen um die beiden Sektionen optisch voneinander
|
||||||
|
abzugrenzen.
|
||||||
|
|
||||||
|
Wenn es keine Formatierungsanweisungen gibt, kann der Trenner auch
|
||||||
|
weggelassen werden. D.h. wenn kein Trenner gefunden wird, wird der
|
||||||
|
komplette Text als Template-Koerper betrachtet.
|
||||||
|
|
||||||
|
=head2 Template-Koerper
|
||||||
|
|
||||||
|
Im Template-Koerper werden die zu ersetzenden Token durch eckige
|
||||||
|
Klammern abgegrenzt. Sollen eckige Klammern im Text ausgegeben werden
|
||||||
|
muessen diese durch einen Backslash freigestellt werden.
|
||||||
|
|
||||||
|
[$termersetzung] [@schleife] nur eine \[ Klammer
|
||||||
|
|
||||||
|
=over 3
|
||||||
|
|
||||||
|
=item $ - Termersetzung
|
||||||
|
|
||||||
|
Ersetzt den Token durch den Wert des angegeben Schluessels.
|
||||||
|
|
||||||
|
[$formatierung] [$schluessel]
|
||||||
|
|
||||||
|
Es wird zuerst nach einer Formatierung mit den entsprechenden
|
||||||
|
Bezeichner gesucht. Ist dies der Fall werden die entsprechenden
|
||||||
|
Funktionen ausgefuehrt.
|
||||||
|
|
||||||
|
Kann kein Format gefunden, wird direkt in der Datenstruktur
|
||||||
|
nach einem Schhluessel mit dem angegeben Bezeichner gesucht
|
||||||
|
und sein Wert eingesetzt.
|
||||||
|
|
||||||
|
Schlussendlich ist es noch moeglich einen default-Wert zu
|
||||||
|
definieren, der eingesetzt wird, wenn keiner der obigen Wege
|
||||||
|
erfolgreich war.
|
||||||
|
|
||||||
|
Hallo [$name|Unbekannter]!
|
||||||
|
|
||||||
|
=item ? - bedingte Verzeigung
|
||||||
|
|
||||||
|
Ueberprueft ob der Wert des angegebenen Formats/Schluessel
|
||||||
|
boolsch WAHR ist. Dementsprechend wird der then oder else
|
||||||
|
Block eingefuegt.
|
||||||
|
|
||||||
|
[?if|then|else] oder auch nur [?if|then]
|
||||||
|
|
||||||
|
Die then/else Bloecke werden natuerlich auch auf Tokens
|
||||||
|
geparst und diese dementsprechend ersetzt.
|
||||||
|
|
||||||
|
=item @ - Schleifen/Listen
|
||||||
|
|
||||||
|
Der nachfolgende Textblock wird fuer alle Elemente des durch
|
||||||
|
den Schluessel bezeichneten Arrays ausgefuehrt und eingefuegt.
|
||||||
|
|
||||||
|
[@schluessel|block] oder [@schluessel|block|sep]
|
||||||
|
|
||||||
|
Als zweiter Parameter kann ein Separtor definiert werden, mit
|
||||||
|
dem sich z.B. kommaseparierte Listen erzeugen lassen, da der
|
||||||
|
Separator eben nur zwischen den Element eingefuegt wird.
|
||||||
|
|
||||||
|
Auch fuer Schleifen koennen Formatierungen genutzt werden.
|
||||||
|
Allerdings darf kein String zurueckgegeben werden, sondern
|
||||||
|
ein Array mit einer Menge von UVtemplate-Objekten.
|
||||||
|
|
||||||
|
=item # - Kommentare
|
||||||
|
|
||||||
|
Token die nach der Bearbeitungen entfernt werden.
|
||||||
|
|
||||||
|
[# mich sieht man nicht]
|
||||||
|
|
||||||
|
=item Sonstiges
|
||||||
|
|
||||||
|
Um in Listen einen Zeilenumbruch zu erzwingen, muss
|
||||||
|
lediglich ein '\n' eingefuegt werden, falls eine kompakte
|
||||||
|
Definition der Liste erfolgen soll.
|
||||||
|
|
||||||
|
[@names|[name] [email]\n]
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head2 Formatierungen
|
||||||
|
|
||||||
|
Eine Formatierung besteht eigentlich nur aus dem entsprechenden
|
||||||
|
Namen und einer beliebigen Anzahl von Funktionsaufrufen:
|
||||||
|
|
||||||
|
format := funktion param1 "param 2" | funktion param
|
||||||
|
|
||||||
|
Aehnlich der Unix-Shell-Funktionalitaet, wird dabei die Ausgabe
|
||||||
|
einer Funktion an die folgende weitergeleitet. So ist es moeglich
|
||||||
|
verschiedenste simple Formatierungen zu kombinieren um nicht fuer
|
||||||
|
jeden Spezialfall eine neue Funktion schreiben zu muessen.
|
||||||
|
|
||||||
|
Die jeweilige Formatierungsfunktion erhaelt als Input die Datenstruktur,
|
||||||
|
den Output der vorherigen Funktion und die definierten Parameter in der
|
||||||
|
entsprechenden Reihenfolge.
|
||||||
|
|
||||||
|
Zahlen und einfache Bezeichner koennen direkt definiert werden. Sollen
|
||||||
|
Sonderzeichen oder Leerzeichen uebergeben werden muessen diese gequotet
|
||||||
|
werden. Dazu kann ' also auch " verwendet werden.
|
||||||
|
|
||||||
|
Die Funktionen geben im Allgemeinen einen String zurueck. Im Rahmen
|
||||||
|
von Listen können auch Arrays uebergeben werden.
|
||||||
|
|
||||||
|
Die erste Funktion duerfte ueblicherweise 'value' sein. Sie gibt den
|
||||||
|
des angegeben Schluessel zurueck, der dann von den folgenden Funktionen
|
||||||
|
definiert wird.
|
||||||
|
|
||||||
|
name-60 := value name | fill-right 60
|
||||||
|
|
||||||
|
Das Format "name-60" definiert also den Wert des Schluessel "name" der
|
||||||
|
um Leerzeichen aufgefuellt wird, bis eine Laenge von 60 Zeichen
|
||||||
|
erreicht wird.
|
||||||
|
|
||||||
|
name-email := value name | justify-behind mail 72
|
||||||
|
|
||||||
|
"name-email" resultiert in einem String, der zwischen den Werten
|
||||||
|
von "name" und "email" genau so viele Leerzeichen enthaelt, damit
|
||||||
|
der gesamte String 72 Zeichen lang ist.
|
||||||
|
|
||||||
|
Wird dieses Format in einer Liste angewandt, erhaelt man eine Tabelle
|
||||||
|
in der die linke Spalte linksbuendig und die rechte Spalte entsprechend
|
||||||
|
rechtsbuendig ist.
|
||||||
|
|
||||||
|
Soweit ein kleiner Ueberblick ueber die Formatierungen.
|
||||||
|
Ausfuehrliche Funktionsbeschreibungen und weitere Beispiele finden
|
||||||
|
sich in der Dokumentation des Moduls UVformat.
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
L<UVformats>
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Cornell Binder <cobi@dex.de>
|
13
bdsgtext.cfg
Normal file
13
bdsgtext.cfg
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Diese Datei enthaelt den Hinweistext auf die Datenschutzklausel,
|
||||||
|
# der im Wahlschein erscheint und auch bei eingegangenen Wahlscheinen
|
||||||
|
# wieder abgeprueft wird. Alle Zeilen, die mit dem Kommentarzeichen #
|
||||||
|
# anfangen, werden ignoriert.
|
||||||
|
#
|
||||||
|
Zur Verarbeitung des Wahlscheines und inbesondere der Veroeffentlichung
|
||||||
|
des Ergebnisses ist deine Zustimmung zur Speicherung, Auswertung und
|
||||||
|
Veroeffentlichung deiner Stimmdaten (Name und E-Mail-Adresse in
|
||||||
|
Verbindung mit dem Stimmverhalten) im Rahmen dieses Verfahrens
|
||||||
|
erforderlich. Wenn du im Feld unterhalb dieses Absatzes "JA"
|
||||||
|
eintraegst, erklaerst du dich damit einverstanden. In allen anderen
|
||||||
|
Faellen wird der Wahlschein mit Ruecksicht auf das deutsche
|
||||||
|
Bundesdatenschutzgesetz verworfen und nicht gewertet.
|
42
mailpatterns.cfg
Normal file
42
mailpatterns.cfg
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
# Mailadressen, die auf diese Kriterien zutreffen, werden als verdaechtig
|
||||||
|
# angesehen und zurueckgewiesen. Im interaktiven Modus kann der Wahlleiter
|
||||||
|
# im Einzelfall entscheiden.
|
||||||
|
#
|
||||||
|
# Bitte ein Pattern (Regular Expression) pro Zeile eingeben.
|
||||||
|
# Achtung, es wird so benutzt, wie es hier steht, also auf fuehrende oder
|
||||||
|
# abschliessende Leerzeichen aufpassen!
|
||||||
|
#
|
||||||
|
# Alle Zeilen, die mit dem Kommentarzeichen # anfangen, werden ignoriert.
|
||||||
|
|
||||||
|
@anon\.penet\.fi
|
||||||
|
@anon\.sub\.net
|
||||||
|
anonymous@mixmaster\.nullify\.org
|
||||||
|
me@privacy.net
|
||||||
|
admin@
|
||||||
|
daemon@
|
||||||
|
anon@
|
||||||
|
audit@
|
||||||
|
bin@
|
||||||
|
decnet@
|
||||||
|
default@
|
||||||
|
field@
|
||||||
|
guest@
|
||||||
|
hostmaster@
|
||||||
|
install@
|
||||||
|
mailer.*@
|
||||||
|
maint.*@
|
||||||
|
news@
|
||||||
|
newsmaster@
|
||||||
|
nobody@
|
||||||
|
operator@
|
||||||
|
postmaster@
|
||||||
|
root@
|
||||||
|
shutdown@
|
||||||
|
sync@
|
||||||
|
sys@
|
||||||
|
sysop@
|
||||||
|
system@
|
||||||
|
test@
|
||||||
|
tutor@
|
||||||
|
usenet@
|
||||||
|
uucp@
|
194
messages.cfg
Normal file
194
messages.cfg
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
# Messages used in Usevote. Variables are enclosed in ${... }.
|
||||||
|
# Mostly these is interactive output for the votetaker, but texts from
|
||||||
|
# uvbounce.pl and uvrules.pl are also partly mailed back to the voters.
|
||||||
|
#
|
||||||
|
# Comments are allowed, but the # sign must be at the beginning of the line
|
||||||
|
# (no leading spaces or others characters allowed).
|
||||||
|
#
|
||||||
|
# General format:
|
||||||
|
# Identifier = message
|
||||||
|
# (Identifier has to start at the beginning of the line, without leading space)
|
||||||
|
#
|
||||||
|
###################################################################################
|
||||||
|
#
|
||||||
|
# UVconfig.pm
|
||||||
|
#
|
||||||
|
CONF_NOGROUPS = Kein Abstimmungsgegenstand definiert (siehe ${CONFIGFILE})!
|
||||||
|
CONF_NOBDSGFILE = Datei mit Datenschutzhinweis ("${BDSGFILE}") nicht lesbar!
|
||||||
|
CONF_NOSIG = Abschnitt [Signatur] nicht in Datei ${FILE} gefunden!
|
||||||
|
CONF_NOBADADDR = Datei mit verdaechtigen Adressen "${BADADDRFILE}" nicht lesbar!
|
||||||
|
CONF_TEST_RULES = Regeln aus usevote.rul:
|
||||||
|
CONF_NO_RULES = (keine Regeln definiert)
|
||||||
|
CONF_CONFIG = Konfiguration:
|
||||||
|
#
|
||||||
|
# UVmenu.pm
|
||||||
|
#
|
||||||
|
MENU_INVALIDNAME = Ungueltiger Name.
|
||||||
|
MENU_NONAME = Kein Name angegeben.
|
||||||
|
MENU_INVALIDBDSG = Datenschutzhinweis fehlerhaft oder nicht bestaetigt.
|
||||||
|
MENU_DUPLICATEVOTE = Doppelte Stimmabgabe gefunden.
|
||||||
|
MENU_NOVOTE = Keine Stimmabgabe gefunden.
|
||||||
|
MENU_INVALIDVOTE = Ungueltige Stimmabgabe.
|
||||||
|
MENU_NOBALLOTID = Keine Scheinkennung gefunden.
|
||||||
|
MENU_WRONGBALLOTID = Scheinkennung falsch.
|
||||||
|
MENU_ADDRESSNOTREGISTERED = Adresse nicht registriert.
|
||||||
|
MENU_INVALIDADDRESS = Ungueltige Mail-Adresse.
|
||||||
|
MENU_INVALIDADDRESS2 = Es wird keine Mail verschickt!
|
||||||
|
MENU_SUSPICIOUSACCOUNT = Verdaechtige Adresse gefunden.
|
||||||
|
MENU_UNRECOGNIZEDVOTE = Stimmen nicht vollstaendig erkannt. Im Zweifelsfall "Enthaltung" angenommen.
|
||||||
|
MENU_UNRECOGNIZED_LIST = Stimme
|
||||||
|
MENU_VIOLATEDRULE = Regel ${RULE} verletzt.
|
||||||
|
MENU_PROBLEMS = Die folgenden Probleme muessen beseitigt werden:
|
||||||
|
MENU_CAPTION = Auswahlmenue:
|
||||||
|
MENU_SHOW_MAIL = Anzeigen der Wahlmail
|
||||||
|
MENU_CHANGE_PROPERTIES = Bestaetigen oder Aendern von Wahlschein-Eigenschaften:
|
||||||
|
MENU_ADDRESS = Mailadresse
|
||||||
|
MENU_ADDRESS_CHANGE = Adresse aendern
|
||||||
|
MENU_ADDRESS_OK = Adresse OK
|
||||||
|
MENU_ADDRESS_INVALID = Adresse ungueltig
|
||||||
|
MENU_ADDRESS_PROMPT = Waehleradresse:
|
||||||
|
MENU_NAME = Waehlername
|
||||||
|
MENU_NAME_CHANGE = Namen aendern
|
||||||
|
MENU_NAME_OK = Name OK
|
||||||
|
MENU_NAME_INVALID = Name ungueltig
|
||||||
|
MENU_VOTES = Stimmen
|
||||||
|
MENU_VOTES_RESET = Stimmen neu setzen
|
||||||
|
MENU_VOTES_OK = Stimmen OK
|
||||||
|
MENU_VOTES_INVALID = Stimmen ungueltig
|
||||||
|
MENU_VOTES_CANCELLED = Stimmen vom Waehler annulliert
|
||||||
|
MENU_VOTES_REENTER = Stimme fuer ${GROUP} (J, N oder E):
|
||||||
|
MENU_VOTES_REENTER_ASK = Bitte die Stimmen neu eingeben. Die aus dem Wahlschein erkannten Stimmen sind jeweils der Standardwert und werden in [ ] aufgefuehrt.
|
||||||
|
MENU_VOTES_REENTER_LEGEND = J: Ja | N: Nein | E: Enthaltung
|
||||||
|
MENU_VOTES_REENTER_OLD = Bisherige Stimmen:
|
||||||
|
MENU_VOTES_REENTER_NEW = Neue Stimmen:
|
||||||
|
MENU_VOTES_REENTER_ACK = Stimmen uebernehmen
|
||||||
|
MENU_VOTES_REENTER_NACK = bisherige Stimmen belassen
|
||||||
|
MENU_BALLOT_ID = Scheinkennung
|
||||||
|
MENU_BDSG = Datenschutzklausel
|
||||||
|
MENU_BDSG_ACCEPTED = Datenschutzklausel wurde akzeptiert
|
||||||
|
MENU_BDSG_DECLINED = Datenschutzklausel nicht akzeptiert bzw. Text veraendert
|
||||||
|
MENU_IGNORE = Diese Stimme ignorieren (ohne Benachrichtigung verwerfen)
|
||||||
|
MENU_IGNORE_WARNING = Die Stimme wird nicht aufgezeichnet, und es wird keine Bestaetigung verschickt. ${MENU_IGNORE_STRING} eingeben, wenn Du sicher bist:
|
||||||
|
MENU_IGNORE_STRING = JA
|
||||||
|
MENU_PROCEED = Weiter
|
||||||
|
MENU_PROMPT = Eingabe:
|
||||||
|
MENU_GETKEY = *** Return druecken, um fortzufahren ***
|
||||||
|
MENU_PROCESSING = Verarbeite Mails...
|
||||||
|
MENU_ERROR_WARNING = WARNUNG
|
||||||
|
MENU_ERROR_TEXT = Es wurden nicht alle Fehler behoben. Der Waehler wird eine Fehlermail erhalten und die Stimme wird ungueltig gewertet.
|
||||||
|
MENU_ERROR_GETKEY = Bitte mit 'y' bestätigen oder mit jeder anderen Eingabe zurück:
|
||||||
|
MENU_DUP_VOTE = Moeglicherweise doppelte Stimmabgabe!
|
||||||
|
MENU_DUP_FIRST = Erste Stimme:
|
||||||
|
MENU_DUP_SECOND = Zweite Stimme:
|
||||||
|
MENU_DUP_DELFIRST = Erste loeschen
|
||||||
|
MENU_DUP_DELSECOND = Zweite loeschen
|
||||||
|
MENU_DUP_DELNONE = Keine loeschen
|
||||||
|
#
|
||||||
|
# UVreadmail.pm
|
||||||
|
#
|
||||||
|
READMAIL_STATUS = Abruf neuer Mails vom POP3-Server...
|
||||||
|
READMAIL_NOCONNECTION = Verbindung zum POP3-Server fehlgeschlagen!
|
||||||
|
READMAIL_NOLOGIN = Anmeldung am POP3-Server nicht moeglich!
|
||||||
|
READMAIL_NOMAILFILE = Maildatei ${FILE} nicht lesbar!
|
||||||
|
READMAIL_GET_PROBLEM = Warnung! Konnte Mail Nr. ${NR} nicht abrufen.
|
||||||
|
READMAIL_DEL_PROBLEM = Warnung! Konnte Mail Nr. ${NR} nicht loeschen.
|
||||||
|
READMAIL_UIDL_PROBLEM = Warnung! Konnte Liste mit UIDLs nicht speichern.
|
||||||
|
READMAIL_UIDL_PROBLEM2 = Beim naechsten Lauf keine Erkennung bereits abgerufener Mails moeglich!
|
||||||
|
READMAIL_UIDL_CLOSE = Warnung! Konnte UIDL-Cachedatei nicht ordnungsgemaess schliessen.
|
||||||
|
READMAIL_ARCHIVE_PROBLEM = Warnung! Wahlmails konnten nicht in Datei ${FILE} gesichert werden.
|
||||||
|
READMAIL_ARCHIVE_CLOSE = Warnung! Konnte Wahlmail-Archivdatei ${FILE} nicht schliessen.
|
||||||
|
#
|
||||||
|
# UVrules.pm
|
||||||
|
#
|
||||||
|
RULES_ERROPENFILE = Kann Regeldatei ${FILE} nicht oeffnen
|
||||||
|
RULES_TOOSHORT = Regel ${NUM}: '${TYPE}'-Bedingung zu kurz
|
||||||
|
RULES_TOOLONG = Regel ${NUM}: '${TYPE}'-Bedingung zu lang
|
||||||
|
RULES_INVCHARS = Regel ${NUM}: '${TYPE}'-Bedingung enthaelt nicht erlaubte Zeichen
|
||||||
|
RULES_RULE = Wahlregel
|
||||||
|
RULES_IF = Wenn Du
|
||||||
|
RULES_THEN = musst Du
|
||||||
|
RULES_AND = und
|
||||||
|
RULES_OR = oder
|
||||||
|
RULES_YES = JA
|
||||||
|
RULES_NO = NEIN
|
||||||
|
RULES_ABSTAIN = ENTHALTUNG
|
||||||
|
RULES_IFCLAUSE = ${VOTE} stimmst fuer ${GROUP}
|
||||||
|
RULES_THENCLAUSE = ${VOTE} stimmen fuer ${GROUP}
|
||||||
|
#
|
||||||
|
# UVsendmail.pm
|
||||||
|
#
|
||||||
|
SENDMAIL_ERROPENCONTROL = FEHLER! Steuerungsdatei ${FILE} konnte nicht geoeffnet werden.
|
||||||
|
SENDMAIL_ERRCLOSECONTROL = FEHLER! Steuerungsdatei ${FILE} konnte nicht geschlossen werden.
|
||||||
|
SENDMAIL_ERRDELCONTROL = FEHLER! Steuerungsdatei ${FILE} konnte nicht geloescht werden.
|
||||||
|
SENDMAIL_ERROPENMAIL = FEHLER! Mail-Datei ${FILE} konnte nicht geoeffnet werden.
|
||||||
|
SENDMAIL_ERRCLOSEMAIL = FEHLER! Mail-Datei ${FILE} konnte nicht geschlossen werden.
|
||||||
|
SENDMAIL_NOMAILS = Keine Mails zu verschicken (Datei ${FILE} nicht gefunden).
|
||||||
|
SENDMAIL_SMTP_CONNREFUSED = Keine Verbindung zum SMTP-Server moeglich!
|
||||||
|
SENDMAIL_SMTP_AUTHERR = Anmeldung am SMTP-Server fehlgeschlagen!
|
||||||
|
SENDMAIL_ERRNOTFOUND = Datei ${FILE} nicht gefunden.
|
||||||
|
SENDMAIL_SMTP_INVRCPT = Mail an ${RCPT} konnte nicht verschickt werden:
|
||||||
|
SENDMAIL_SENDING = Mails werden verschickt...
|
||||||
|
SENDMAIL_ERROCCURED = Fehler aufgetreten. Bitte kontrollieren und "uvvote.pl clean" ggf. noch einmal starten!
|
||||||
|
SENDMAIL_MISSINGFILES = Dateien konnten nicht gefunden werden. Dieser Fehler kann auftreten, falls bei einem vorherigen Lauf nur einzelne Mails verschickt werden konnten (diese Dateien wurden dann bereits geloescht).
|
||||||
|
SENDMAIL_ERRCLOSEDOMAIL = FEHLER! domail-Datei konnte nicht geschlossen werden.
|
||||||
|
SENDMAIL_ACKTXT_MISSING = KONFIGURATIONSFEHLER: Abschnitt [${SECTION}] in ${FILE} existiert nicht! Mails an die Waehler sind moeglicherweise unvollstaendig.
|
||||||
|
#
|
||||||
|
# uvballot.pl
|
||||||
|
#
|
||||||
|
BALLOT_NO_PERSONAL = Die Option -t kann nur in Zusammenhang mit persoenlichen Wahlscheinen verwendet werden (Option "personal" in ${CFGFILE}).
|
||||||
|
#
|
||||||
|
# uvbounce.pl
|
||||||
|
#
|
||||||
|
BOUNCE_BALLOT = ! Wahlschein nicht zustellbar (Adresse ungueltig)
|
||||||
|
BOUNCE_ACKMAIL = ! Bestaetigung nicht zustellbar (Adresse ungueltig)
|
||||||
|
#
|
||||||
|
# uvcfv.pl
|
||||||
|
#
|
||||||
|
CFV_NUMBER = Es werden ${COUNT} CfVs verschickt.
|
||||||
|
CFV_ERRWRITE = Kann nicht in Scheinkennungsdatei ${FILE} schreiben!
|
||||||
|
CFV_ERRCLOSE = Kann Scheinkennungsdatei nicht schliessen!
|
||||||
|
CFV_ERROPENCFV = Kann CfV-Datei ${FILE} nicht lesen!
|
||||||
|
CFV_SUBJECT = Wahlschein
|
||||||
|
#
|
||||||
|
# uvcount.pl
|
||||||
|
#
|
||||||
|
COUNT_ERR_OPEN = Kann Ergebnisdatei ${FILE} nicht oeffnen!
|
||||||
|
COUNT_ERR_RESULT = Fehler in ${FILE} Zeile ${LINE}
|
||||||
|
COUNT_ERR_GROUPCOUNT = Bei Stimme von <${ADDR}>: ${NUM1} statt ${NUM2} Stimmen gefunden (${RESULTFILE} kontrollieren!)
|
||||||
|
COUNT_DELETED = ${NUM} Stimme(n) geloescht.
|
||||||
|
#
|
||||||
|
# uvvote.pl
|
||||||
|
#
|
||||||
|
VOTE_RENAMING_MAILBOX = Benenne Stimmdatei um...
|
||||||
|
VOTE_WRITE_RESULTS = Ergebnisdatei ${FILE} nicht schreibbar!
|
||||||
|
VOTE_CLOSE_RESULTS = Ergebnisdatei ${FILE} konnte nicht erfolgreich geschlossen werden!
|
||||||
|
VOTE_NO_VOTES = Keine Stimmen zu verarbeiten.
|
||||||
|
VOTE_NUM_VOTES = ${COUNT} Stimmen bearbeitet.
|
||||||
|
VOTE_NOT_SAVED = ${COUNT} Stimmen bearbeitet, aber nicht gespeichert.
|
||||||
|
VOTE_FIRSTRUN = 'uvvote clean' aufrufen, um Ergebnisse zu speichern und Bestaetigungen zu verschicken.
|
||||||
|
VOTE_ERRORS = Folgende Fehler sind aufgetreten (siehe auch ${FILE}):
|
||||||
|
VOTE_INVALID_BALLOTID = Scheinkennung ungueltig
|
||||||
|
VOTE_MISSING_BALLOTID = Scheinkennung fehlt
|
||||||
|
VOTE_UNREGISTERED_ADDRESS = Adresse nicht registriert
|
||||||
|
VOTE_INVALID_VOTE = Ungueltige Stimmabgabe
|
||||||
|
VOTE_VIOLATED_RULE = Regel ${RULE} verletzt
|
||||||
|
VOTE_NO_VOTES = Keine Stimmen abgegeben
|
||||||
|
VOTE_INVALID_ACCOUNT = Ungueltiger Account
|
||||||
|
VOTE_INVALID_ADDRESS = Ungueltige Adresse
|
||||||
|
VOTE_INVALID_REALNAME = Ungueltiger Realname
|
||||||
|
VOTE_MISSING_NAME = Kein Name angegeben
|
||||||
|
VOTE_DUPLICATES = Verschiedene Stimmen fuer gleichen Abstimmungspunkt
|
||||||
|
VOTE_FILE_COMMENT = Wahlleiter setzte ${FIELDS}
|
||||||
|
VOTE_NO_NEW_RESULTS = Keine noch nicht verarbeiteten Ergebnisdateien gefunden! Bitte uvvote.pl zunaechst ohne die 'clean'-Option starten.
|
||||||
|
VOTE_MOVE_RESULTFILE = Fehler! Konnte Ergebnisdatei ${FILE} nicht verschieben:
|
||||||
|
VOTE_MOVE_VOTEFILE = Fehler! Konnte Stimmdatei ${FILE} nicht verschieben:
|
||||||
|
VOTE_CREATING_RESULTS = Erstelle neue Gesamtergebnisdatei ${FILENAME}...
|
||||||
|
#
|
||||||
|
# Allgemeine Meldungen
|
||||||
|
#
|
||||||
|
ERR_MKDIR = Kann Verzeichnis '${DIR}' nicht anlegen:
|
||||||
|
ERR_NOTPERSONAL = Usevote ist nicht fuer die Verwendung personalisierter Wahlscheine konfiguriert (Option "personal" in ${CFGFILE})
|
||||||
|
ERR_FILE_CREATION = Fataler Fehler: Konnte keine Datei anlegen.
|
||||||
|
ERR_RENAME_MAILFILE = Konnte Maildatei nicht umbenennen:
|
||||||
|
ERR_LOCK = Lockfile ${FILE} bereits vorhanden! Wurde UseVoteGer mehrfach gestartet?
|
||||||
|
INFO_TIDY_UP = Aufraeumen...
|
46
templates/ack-mail
Normal file
46
templates/ack-mail
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
ballotid-line := value ballotidtext | fill-right 20 | append ballotid
|
||||||
|
address-line := value addresstext | fill-right 20 | append address
|
||||||
|
name-line := value nametext2 | fill-right 20 | append name
|
||||||
|
pos := value pos | fill-right 2
|
||||||
|
group-first := value group | first-words 50
|
||||||
|
group-more := value group | drop-words 50 | create-lines 50
|
||||||
|
vote := value vote | fill-both 10
|
||||||
|
votetaker := value mailfrom | fill-left 65
|
||||||
|
|
||||||
|
== TEMPLATE =================================================================
|
||||||
|
Diese automatische Nachricht wurde dir nach Zaehlung deiner Stimme
|
||||||
|
zugesandt. Wenn alles stimmt, gibt es keinen Anlass fuer eine Reaktion.
|
||||||
|
Wenn deine Stimme falsch registriert wurde, stimme bitte erneut ab,
|
||||||
|
indem du diese Mail komplett zitierst und die falschen Wertungen
|
||||||
|
korrigierst (zwischen die eckigen Klammern schreiben). Dabei darf
|
||||||
|
keinesfalls die laufende Nummer am Zeilenanfang entfernt werden.
|
||||||
|
|
||||||
|
Diese Wahl ist oeffentlich, und die Adressen aller Waehlerinnen und
|
||||||
|
Waehler werden am Ende bekanntgegeben. Wenn du deine Adresse & Stimme
|
||||||
|
loeschen willst, kannst du erneut abstimmen und dabei 'ANNULLIERUNG'
|
||||||
|
anstelle von 'JA' oder 'NEIN' angeben. \[Doppel-N, Doppel-L :-)\]
|
||||||
|
|
||||||
|
[?personal|Da diese Abstimmung mit personalisierten Wahlscheinen durchgefuehrt
|
||||||
|
wird, sind auch saemtliche Aenderungen nur mit Angabe der folgenden
|
||||||
|
Wahlscheinkennung gueltig!
|
||||||
|
|
||||||
|
[$ballotid-line]]
|
||||||
|
[$address-line]
|
||||||
|
[$name-line]
|
||||||
|
(Real-Namen sind fuer diese Abstimmung vorgeschrieben. Wenn hier
|
||||||
|
nicht Dein wirklicher Name steht, dann korrigiere die Zeile
|
||||||
|
bitte und sende die Nachricht zurueck; sonst kann die Stimme
|
||||||
|
spaeter als ungueltig gewertet werden.)
|
||||||
|
|
||||||
|
|
||||||
|
Deine Stimmabgabe wurde wie folgt erkannt:
|
||||||
|
|
||||||
|
[@groups|#[$pos] \[[$vote]\] fuer [$group-first]
|
||||||
|
[@group-more| [$line]\n]|\n]
|
||||||
|
|
||||||
|
|
||||||
|
Danke fuer deine Stimmabgabe. Eine Kopie des CfV kannst du von mir er-
|
||||||
|
halten (bitte Namen der Abstimmung angeben, falls mehrere laufen).
|
||||||
|
|
||||||
|
[$votetaker]
|
||||||
|
\[mit [$usevote_version]\]
|
25
templates/address-not-registered
Normal file
25
templates/address-not-registered
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
votetaker := value mailfrom | fill-left 65
|
||||||
|
head := value head | quote "> "
|
||||||
|
body := value body | quote "> "
|
||||||
|
|
||||||
|
== TEMPLATE =================================================================
|
||||||
|
Deine Adresse ist beim Wahlleiter bisher nicht mit einer Wahlschein-
|
||||||
|
kennung registriert, mit einer EMail an die im CfV genannten Adresse
|
||||||
|
kannst du dir eine Kennung zuteilen lassen.
|
||||||
|
|
||||||
|
Solltest du bereits eine Kennung erhalten haben, so achte bitte darauf,
|
||||||
|
diese nur mit genau der Mailadresse zu verwenden, fuer die sie
|
||||||
|
registriert ist.
|
||||||
|
|
||||||
|
Achtung, die Mailadresse wird unter Beachtung von Gross- und Klein-
|
||||||
|
schreibung ausgewertet, Meier und meier sind daher _nicht_ identisch!
|
||||||
|
|
||||||
|
Hier die Mail, die ich erhalten habe:
|
||||||
|
|
||||||
|
[$head]
|
||||||
|
>
|
||||||
|
[$body]
|
||||||
|
|
||||||
|
|
||||||
|
[$votetaker]
|
||||||
|
\[mit [$usevote_version]\]
|
34
templates/ballot
Normal file
34
templates/ballot
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
votename-first := value votename | first-words 55
|
||||||
|
votename-more := value votename | drop-words 55 | create-lines 55
|
||||||
|
|
||||||
|
pos := value pos | fill-right 2
|
||||||
|
|
||||||
|
group-first := value group | first-words 50
|
||||||
|
group-more := value group | drop-words 50 | create-lines 50
|
||||||
|
|
||||||
|
bdsginfo := value bdsginfo | create-lines 72
|
||||||
|
bdsgtext-first := value bdsgtext | first-words 50
|
||||||
|
bdsgtext-more := value bdsgtext | drop-words 50 | create-lines 50
|
||||||
|
|
||||||
|
== TEMPLATE =================================================================
|
||||||
|
|
||||||
|
=-=-=-=-=-=-=-=- Alles vor dieser Zeile bitte loeschen =-=-=-=-=-=-=-=-
|
||||||
|
|
||||||
|
WAHLSCHEIN fuer [$votename-first]
|
||||||
|
[@votename-more| [$line]\n]
|
||||||
|
|
||||||
|
|
||||||
|
[$nametext]
|
||||||
|
|
||||||
|
Wenn du keinen Real-Namen angibst, wird deine Stimme fuer
|
||||||
|
ungueltig erklaert werden.
|
||||||
|
|
||||||
|
|
||||||
|
Nr \[Deine Stimme\] Gruppe/Abstimmungsgegenstand
|
||||||
|
========================================================================
|
||||||
|
[@groups|#[$pos] \[ \] [$group-first]
|
||||||
|
[@group-more| [$line]\n]|\n]
|
||||||
|
[?bdsg|[@bdsginfo|[$line]|\n]\n\n#a \[ \] [$bdsgtext-first]
|
||||||
|
[@bdsgtext-more| [$line]|\n]]
|
||||||
|
|
||||||
|
=-=-=-=-=-=-=-=- Alles nach dieser Zeile bitte loeschen =-=-=-=-=-=-=-=-
|
63
templates/ballot-personal
Normal file
63
templates/ballot-personal
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
votename-first := value votename | first-words 55
|
||||||
|
votename-more := value votename | drop-words 55 | create-lines 55
|
||||||
|
|
||||||
|
pos := value pos | fill-right 2
|
||||||
|
|
||||||
|
group-first := value group | first-words 50
|
||||||
|
group-more := value group | drop-words 50 | create-lines 50
|
||||||
|
|
||||||
|
bdsginfo := value bdsginfo | create-lines 72
|
||||||
|
bdsgtext-first := value bdsgtext | first-words 50
|
||||||
|
bdsgtext-more := value bdsgtext | drop-words 50 | create-lines 50
|
||||||
|
|
||||||
|
votetaker := value mailfrom | fill-left 65
|
||||||
|
|
||||||
|
== TEMPLATE =================================================================
|
||||||
|
|
||||||
|
[?alreadysent|
|
||||||
|
!! Dieser CfV wurde dir bereits einmal zugeschickt, sollte der erste
|
||||||
|
!! Wahlschein nicht angekommen oder die Anforderung nicht auf deinen
|
||||||
|
!! Wunsch geschehen sein, so wende dich bitte an den Wahlleiter.
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
************************************
|
||||||
|
*** hier den CfV-Text einfuegen! ***
|
||||||
|
************************************
|
||||||
|
|
||||||
|
|
||||||
|
=-=-=-=-=-=-=-=- Alles vor dieser Zeile bitte loeschen =-=-=-=-=-=-=-=-
|
||||||
|
|
||||||
|
WAHLSCHEIN fuer [$votename-first]
|
||||||
|
[@votename-more| [$line]\n]
|
||||||
|
|
||||||
|
|
||||||
|
[$ballotidtext] [$ballotid]
|
||||||
|
[$addresstext] [$address]
|
||||||
|
|
||||||
|
Dies ist deine persoenliche und _geheime_ Wahlschein-Kennung!
|
||||||
|
Halte deine Wahlscheinkennung zwecks Missbrauchs- und Manipulations-
|
||||||
|
vermeidung bitte moeglichst geheim, da jeder, der sie kennt, in
|
||||||
|
deinem Namen abstimmen kann!
|
||||||
|
|
||||||
|
[$nametext]
|
||||||
|
|
||||||
|
Wenn du keinen Real-Namen angibst, wird deine Stimme fuer
|
||||||
|
ungueltig erklaert werden.
|
||||||
|
|
||||||
|
|
||||||
|
Nr \[Deine Stimme\] Gruppe/Abstimmungsgegenstand
|
||||||
|
========================================================================
|
||||||
|
[@groups|#[$pos] \[ \] [$group-first]
|
||||||
|
[@group-more| [$line]\n]|\n]
|
||||||
|
[?bdsg|[@bdsginfo|[$line]|\n]\n\n#a \[ \] [$bdsgtext-first]
|
||||||
|
[@bdsgtext-more| [$line]|\n]]
|
||||||
|
|
||||||
|
=-=-=-=-=-=-=-=- Alles nach dieser Zeile bitte loeschen =-=-=-=-=-=-=-=-
|
||||||
|
|
||||||
|
|
||||||
|
Danke fuer Deine Stimmabgabe.
|
||||||
|
|
||||||
|
[$votetaker]
|
||||||
|
\[mit [$usevote_version]\]
|
10
templates/ballot-request
Normal file
10
templates/ballot-request
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
=-=-=-=-=-=-=-=- Alles vor dieser Zeile bitte loeschen =-=-=-=-=-=-=-=-
|
||||||
|
|
||||||
|
Zur Wahlscheinanforderung einfach formlos *per Mail* auf dieses
|
||||||
|
Posting antworten. Falls nach einigen Tagen noch kein Wahlschein
|
||||||
|
eingetroffen ist, kannst du unter folgender Adresse mit dem
|
||||||
|
Wahlleiter Kontakt aufnehmen:
|
||||||
|
|
||||||
|
[$mailaddress]
|
||||||
|
|
||||||
|
=-=-=-=-=-=-=-=- Alles nach dieser Zeile bitte loeschen =-=-=-=-=-=-=-=-
|
29
templates/bdsg-error
Normal file
29
templates/bdsg-error
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
votetaker := value mailfrom | fill-left 65
|
||||||
|
|
||||||
|
== TEMPLATE =================================================================
|
||||||
|
Zur Wertung deiner Stimme ist die Zustimmung zur Speicherung,
|
||||||
|
Verarbeitung und Veroeffentlichung der Stimmabgabe erforderlich.
|
||||||
|
Diese Zustimmung konnte nicht automatisch erkannt werden.
|
||||||
|
deine Stimme wurde daher geloescht und wird nicht gewertet.
|
||||||
|
|
||||||
|
Dieses kann folgende Gruende haben:
|
||||||
|
|
||||||
|
* In deinem Wahlschein fehlt der Abschnitt, der ueber die Art
|
||||||
|
der Verarbeitung deiner Stimmdaten informiert, oder er wurde
|
||||||
|
als nicht vollstaendig erkannt. Um bezueglich des deutschen
|
||||||
|
Bundesdatenschutzgesetzes keine Risiken einzugehen, muss ich
|
||||||
|
darauf bestehen, dass dieser Absatz unveraendert mitgeschickt
|
||||||
|
und akzeptiert wird.
|
||||||
|
|
||||||
|
* Du hast nicht der Speicherung/Verarbeitung/Veroeffentlichung
|
||||||
|
zugestimmt. Im dazugehoerigen Feld muss "JA" eingetragen
|
||||||
|
werden.
|
||||||
|
|
||||||
|
Bitte stimme erneut ab, lasse dabei den Hinweistext im
|
||||||
|
Wahlschein intakt und akzeptiere die Klausel, indem du im
|
||||||
|
vorgesehen Feld "JA" eintraegst. Sollte das Problem aufgrund eines
|
||||||
|
Uebermittlungsfehlers bestehen bleiben, melde Dich bitte unter
|
||||||
|
der unten angegebenen Adresse bei mir.
|
||||||
|
|
||||||
|
[$votetaker]
|
||||||
|
\[mit [$usevote_version]\]
|
10
templates/bouncelist
Normal file
10
templates/bouncelist
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
multi-line := value name | justify-before mail 72
|
||||||
|
bouncetext := value bouncetext | create-lines 72
|
||||||
|
|
||||||
|
== TEMPLATE =================================================================
|
||||||
|
|
||||||
|
Als ungueltig erkannte Stimmen:
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
[@bounces|[$multi-line]
|
||||||
|
[@bouncetext|[$line]]|\n]
|
||||||
|
|
12
templates/cancelled
Normal file
12
templates/cancelled
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
votetaker := value mailfrom | fill-left 65
|
||||||
|
|
||||||
|
== TEMPLATE =================================================================
|
||||||
|
Diese automatische Nachricht wurde dir nach Erhalt Deiner ANNULLIERUNG
|
||||||
|
zugesandt. Jede vorherige Stimmabgabe in dieser Abstimmung ist dadurch
|
||||||
|
annulliert und wird weder gezaehlt noch veroeffentlicht.
|
||||||
|
|
||||||
|
Wenn dies ein Fehler war und du doch waehlen moechtest, musst du erneut
|
||||||
|
abstimmen.
|
||||||
|
|
||||||
|
[$votetaker]
|
||||||
|
\[mit [$usevote_version]\]
|
27
templates/invalid-account
Normal file
27
templates/invalid-account
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
votetaker := value mailfrom | fill-left 65
|
||||||
|
head := value head | quote "> "
|
||||||
|
body := value body | quote "> "
|
||||||
|
|
||||||
|
== TEMPLATE =================================================================
|
||||||
|
Deine Stimme kann nicht akzeptiert werden, da du eine kritische
|
||||||
|
Absenderadresse verwendest. Nichtpersoenliche Accounts wie root@,
|
||||||
|
operator@, postmaster@, guest@ usw. sind im Allgemeinen nicht zu
|
||||||
|
Abstimmungen zugelassen, insbesondere, wenn kein Realname angegeben
|
||||||
|
wird. Stimmen von Anon-Servern werden ebenfalls nicht akzeptiert.
|
||||||
|
Bitte stimme erneut von einem persoenlichen Account aus ab.
|
||||||
|
|
||||||
|
Wenn das ein Fehler ist und dein wahrer Name/Account faelschlicherweise
|
||||||
|
fuer einen dieser unpersoenlichen oder Anon-Accounts gehalten wurde, so
|
||||||
|
schicke bitte eine eMail an meine persoenliche Adresse. Sorry fuer das
|
||||||
|
umstaendliche Verfahren, aber nur so ist die zuverlaessige automatische
|
||||||
|
Stimmenzaehlung moeglich.
|
||||||
|
|
||||||
|
Hier die Mail, die ich erhielt:
|
||||||
|
|
||||||
|
[$head]
|
||||||
|
>
|
||||||
|
[$body]
|
||||||
|
|
||||||
|
|
||||||
|
[$votetaker]
|
||||||
|
\[mit [$usevote_version]\]
|
19
templates/invalid-name
Normal file
19
templates/invalid-name
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
votetaker := value mailfrom | fill-left 65
|
||||||
|
head := value head | quote "> "
|
||||||
|
body := value body | quote "> "
|
||||||
|
|
||||||
|
== TEMPLATE =================================================================
|
||||||
|
Dieser Call for Votes (CfV) erfordert die Angabe eines Real-Namens ent-
|
||||||
|
weder im "From:"-Feld des Headers oder im dafuer vorgesehehen Feld des
|
||||||
|
Wahlscheins. Bitte wiederhole Deine Stimmabgabe mit Angabe Deines wirk-
|
||||||
|
lichen Namens.
|
||||||
|
|
||||||
|
Hier die Mail, die ich erhalten habe:
|
||||||
|
|
||||||
|
[$head]
|
||||||
|
>
|
||||||
|
[$body]
|
||||||
|
|
||||||
|
|
||||||
|
[$votetaker]
|
||||||
|
\[mit [$usevote_version]\]
|
16
templates/mailheader
Normal file
16
templates/mailheader
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
date := generate-date-header
|
||||||
|
msgid := generate-msgid
|
||||||
|
|
||||||
|
== TEMPLATE =================================================================
|
||||||
|
From: [$from]
|
||||||
|
Subject: [$subject]
|
||||||
|
To: [$address]
|
||||||
|
[?reply-to|Reply-To: [$reply-to]]
|
||||||
|
[?reference|In-Reply-To: [$reference]]
|
||||||
|
[?reference|References: [$reference]]
|
||||||
|
Message-ID: [$msgid]
|
||||||
|
Date: [$date]
|
||||||
|
X-Automated-Message: generated by [$usevote-version]
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset\=iso-8859-1
|
||||||
|
Content-Transfer-Encoding: 8bit
|
19
templates/multiple-votes
Normal file
19
templates/multiple-votes
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
votetaker := value mailfrom | fill-left 65
|
||||||
|
body := value body | quote "> "
|
||||||
|
|
||||||
|
== TEMPLATE =================================================================
|
||||||
|
Dein Wahlschein enthielt widerspruechliche Stimmen (z.B. sowohl JA- als
|
||||||
|
auch NEIN-Stimme fuer dieselbe Gruppe).
|
||||||
|
|
||||||
|
Das passiert meistens, wenn du mehrere Zeilen schickst, die als Stimme
|
||||||
|
interpretiert werden, z. B. wenn du vergisst, eine Beispielzeile im CfV
|
||||||
|
zu loeschen. Bitte lies den CfV noch einmal und wiederhole deine Stimm-
|
||||||
|
abgabe.
|
||||||
|
|
||||||
|
Hier die Mail, die ich erhalten habe:
|
||||||
|
|
||||||
|
[$body]
|
||||||
|
|
||||||
|
|
||||||
|
[$votetaker]
|
||||||
|
\[mit [$usevote_version]\]
|
16
templates/no-ballot
Normal file
16
templates/no-ballot
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
votetaker := value mailfrom | fill-left 65
|
||||||
|
body := value body | quote "> "
|
||||||
|
|
||||||
|
== TEMPLATE =================================================================
|
||||||
|
In deiner Mail wurde kein gueltiger Wahlschein gefunden. Bitte lies die
|
||||||
|
Hinweise im Call for Votes (CfV) und stimme nochmal ab.
|
||||||
|
Dieser Fehler tritt meistens dann auf, wenn du Zeilen loeschst, die du
|
||||||
|
laut CfV nicht haettest loeschen sollen.
|
||||||
|
|
||||||
|
Hier die Mail, die ich erhalten habe:
|
||||||
|
|
||||||
|
[$body]
|
||||||
|
|
||||||
|
|
||||||
|
[$votetaker]
|
||||||
|
\[mit [$usevote_version]\]
|
19
templates/no-ballotid
Normal file
19
templates/no-ballotid
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
votetaker := value mailfrom | fill-left 65
|
||||||
|
head := value head | quote "> "
|
||||||
|
body := value body | quote "> "
|
||||||
|
|
||||||
|
== TEMPLATE =================================================================
|
||||||
|
In deinem Wahlschein konnte keine Wahlscheinkennung gefunden werden,
|
||||||
|
diese wurde dir zusammen mit dem Wahlschein zugeschickt. Solltest
|
||||||
|
du noch keine eigenen Wahlscheinkennung haben, so kannst du mit
|
||||||
|
einer Mail an die im CfV genannte Adresse eine anfordern.
|
||||||
|
|
||||||
|
Hier die Mail, die ich erhalten habe:
|
||||||
|
|
||||||
|
[$head]
|
||||||
|
>
|
||||||
|
[$body]
|
||||||
|
|
||||||
|
|
||||||
|
[$votetaker]
|
||||||
|
\[mit [$usevote_version]\]
|
20
templates/no-votes
Normal file
20
templates/no-votes
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
votetaker := value mailfrom | fill-left 65
|
||||||
|
body := value body | quote "> "
|
||||||
|
|
||||||
|
== TEMPLATE =================================================================
|
||||||
|
Offenbar hast du keinerlei Stimmen abgegeben. Wenn das ein Irrtum war,
|
||||||
|
lies bitte nochmal die Hinweise im CfV und wiederhole Deine Stimmabgabe.
|
||||||
|
|
||||||
|
Dieser Fehler tritt oft auf, wenn du dich vertippst oder dich nicht an
|
||||||
|
das im Wahlschein vorgegebene Format haeltst.
|
||||||
|
|
||||||
|
Wenn du dich enthalten willst, dann setze bitte ENTHALTUNG an die
|
||||||
|
Stelle von JA oder NEIN.
|
||||||
|
|
||||||
|
Hier die Mail, die ich erhalten habe:
|
||||||
|
|
||||||
|
[$body]
|
||||||
|
|
||||||
|
|
||||||
|
[$votetaker]
|
||||||
|
\[mit [$usevote_version]\]
|
31
templates/result-multi
Normal file
31
templates/result-multi
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
votename-first := value votename | first-words 60
|
||||||
|
votename-more := value votename | drop-words 60 | create-lines 60
|
||||||
|
numinvalid := value numinvalid | fill-left 4
|
||||||
|
numabstain-formatted := value numabstain | fill-left 4
|
||||||
|
yes := value yes | fill-left 4
|
||||||
|
no := value no | fill-left 4
|
||||||
|
group-first := value group | first-words 40
|
||||||
|
group-more := value group | drop-words 40 | create-lines 40
|
||||||
|
|
||||||
|
== TEMPLATE ============================================================
|
||||||
|
|
||||||
|
Ergebnisse [$votename-first]
|
||||||
|
[@votename-more| [$line]\n]
|
||||||
|
([$numvalid] gueltige Stimmen)
|
||||||
|
|
||||||
|
Ja Nein : 2/3? >=60? : ang.? : Gruppe
|
||||||
|
---- ---- : ---- ----- : ----- : ---------------------------------------
|
||||||
|
[@count|[$yes] [$no] : [?cond1| Ja |Nein] [?cond2| Ja |Nein] : [?result| Ja |Nein] : [$group-first]
|
||||||
|
[@group-more| : : : [$line]\n]\n]
|
||||||
|
[?numabstain|[$numabstain-formatted] Enthaltungen]
|
||||||
|
[?numinvalid|[$numinvalid] ungueltige Stimme(n)]
|
||||||
|
|
||||||
|
Gegen dieses Ergebnis kann innerhalb einer Woche nach seiner
|
||||||
|
Veroeffentlichung Einspruch erhoben werden. Der Einspruch ist per
|
||||||
|
E-Mail bei der Moderation von de.admin.news.announce (Adressen
|
||||||
|
siehe Signatur) einzulegen.
|
||||||
|
Wenn es keine ernsthaften Einsprueche gibt oder diese abgelehnt
|
||||||
|
werden, wird die Moderation von de.admin.news.announce das
|
||||||
|
Ergebnis danach umsetzen.
|
||||||
|
|
||||||
|
|
31
templates/result-proportional
Normal file
31
templates/result-proportional
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
votename-first := value votename | first-words 60
|
||||||
|
votename-more := value votename | drop-words 60 | create-lines 60
|
||||||
|
proportion := value proportion | sprintf '%6.3f'
|
||||||
|
numinvalid := value numinvalid | fill-left 4
|
||||||
|
numabstain-formatted := value numabstain | fill-left 4
|
||||||
|
yes := value yes | fill-left 4
|
||||||
|
no := value no | fill-left 4
|
||||||
|
group-first := value group | first-words 40
|
||||||
|
group-more := value group | drop-words 40 | create-lines 40
|
||||||
|
|
||||||
|
== TEMPLATE ============================================================
|
||||||
|
|
||||||
|
Ergebnisse [$votename-first]
|
||||||
|
[@votename-more| [$line]\n]
|
||||||
|
([$numvalid] gueltige Stimmen)
|
||||||
|
|
||||||
|
Ja Nein : J>=N? Ja/Nein : ang.? : Gruppe
|
||||||
|
---- ---- : ----- ------- : ----- : ---------------------------------------
|
||||||
|
[@count|[$yes] [$no] : [?cond1| Ja |Nein] [$proportion] : : [$group-first]
|
||||||
|
[@group-more| : : : [$line]\n]\n]
|
||||||
|
[?numinvalid|[$numinvalid] ungueltige Stimme(n)]
|
||||||
|
|
||||||
|
Gegen dieses Ergebnis kann innerhalb einer Woche nach seiner
|
||||||
|
Veroeffentlichung Einspruch erhoben werden. Der Einspruch ist per
|
||||||
|
E-Mail bei der Moderation von de.admin.news.announce (Adressen
|
||||||
|
siehe Signatur) einzulegen.
|
||||||
|
Wenn es keine ernsthaften Einsprueche gibt oder diese abgelehnt
|
||||||
|
werden, wird die Moderation von de.admin.news.announce das
|
||||||
|
Ergebnis danach umsetzen.
|
||||||
|
|
||||||
|
|
28
templates/result-single
Normal file
28
templates/result-single
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
votename-first := value votename | first-words 60
|
||||||
|
votename-more := value votename | drop-words 60 | create-lines 60
|
||||||
|
|
||||||
|
votename-text-first := value votename | first-words 30
|
||||||
|
votename-text-more := value votename | drop-words 30 | create-lines 72
|
||||||
|
|
||||||
|
== TEMPLATE ============================================================
|
||||||
|
|
||||||
|
Ergebnisse [$votename-first]
|
||||||
|
[@votename-more| [$line]\n]
|
||||||
|
([$numvalid] gueltige Stimmen)
|
||||||
|
|
||||||
|
Es gab [$yes] Ja-Stimmen und [$no] Nein-Stimmen[?numabstain| bei [$numabstain] Enthaltungen].
|
||||||
|
[?numinvalid|[$numinvalid] Stimme(n) wurden als ungueltig gewertet.]
|
||||||
|
|
||||||
|
Es wurde [?cond1|die|keine] 2/3-Mehrheit erreicht und es gingen [?cond2|mehr|weniger] als
|
||||||
|
60 Ja-Stimmen ein. Damit ist die [$votename-text-first]
|
||||||
|
[@votename-text-more|[$line] |\n][?cond1|[?cond2|angenommen|abgelehnt]|abgelehnt].
|
||||||
|
|
||||||
|
Gegen dieses Ergebnis kann innerhalb einer Woche nach seiner
|
||||||
|
Veroeffentlichung Einspruch erhoben werden. Der Einspruch ist per
|
||||||
|
E-Mail bei der Moderation von de.admin.news.announce (Adressen
|
||||||
|
siehe Signatur) einzulegen.
|
||||||
|
Wenn es keine ernsthaften Einsprueche gibt oder diese abgelehnt
|
||||||
|
werden, wird die Moderation von de.admin.news.announce das
|
||||||
|
Ergebnis danach umsetzen.
|
||||||
|
|
||||||
|
|
20
templates/rule-violated
Normal file
20
templates/rule-violated
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
votetaker := value mailfrom | fill-left 65
|
||||||
|
body := value body | quote "> "
|
||||||
|
|
||||||
|
== TEMPLATE =================================================================
|
||||||
|
Diese Abstimmung unterliegt bestimmten Bedingungen, fuer welche Gruppen
|
||||||
|
wie abgestimmt werden kann. Diese Bedingungen wurden im Call for Votes
|
||||||
|
erklaert. Deine Stimme verletzt eine oder mehrere der Regeln. Bitte lies
|
||||||
|
den CfV noch einmal durch und wiederhole Deine Stimmabgabe.
|
||||||
|
|
||||||
|
Die folgenden Regeln wurden nicht eingehalten:
|
||||||
|
|
||||||
|
[$rules]
|
||||||
|
|
||||||
|
Hier die Mail, die ich erhalten habe:
|
||||||
|
|
||||||
|
[$body]
|
||||||
|
|
||||||
|
|
||||||
|
[$votetaker]
|
||||||
|
\[mit [$usevote_version]\]
|
12
templates/voterlist
Normal file
12
templates/voterlist
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
multi-line := value name | justify-before mail 72
|
||||||
|
|
||||||
|
== TEMPLATE ============================================================
|
||||||
|
|
||||||
|
Folgende Personen haben sich bislang an der Abstimmung beteiligt:
|
||||||
|
========================================================================
|
||||||
|
[@multi|[$multi-line]|\n]
|
||||||
|
|
||||||
|
|
||||||
|
Als ungueltig erkannte Stimmen:
|
||||||
|
========================================================================
|
||||||
|
[@invalid|[$multi-line]\n[$reason]|\n]
|
36
templates/votes-multi
Normal file
36
templates/votes-multi
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
grafix := value group | multi-graph 72 pos groupcount
|
||||||
|
grafix-line := multi-line 72 groupcount
|
||||||
|
multi-line := value name | append vote | justify-before mail 72
|
||||||
|
invalid-line := value name | justify-before mail 72
|
||||||
|
numinvalid := value numinvalid | fill-left 4
|
||||||
|
yes := value yes | fill-left 4
|
||||||
|
no := value no | fill-left 4
|
||||||
|
condition1 := value cond1 | fill-both 4
|
||||||
|
condition2 := value cond2 | fill-both 5
|
||||||
|
result := value result | fill-both 5
|
||||||
|
|
||||||
|
== TEMPLATE ============================================================
|
||||||
|
|
||||||
|
========================================================================
|
||||||
|
|
||||||
|
Wichtiger Hinweis:
|
||||||
|
|
||||||
|
Die unten aufgefuehrten Personen haben der Speicherung, Verarbeitung
|
||||||
|
und Veroeffentlichung ihrer Adressen und Stimmdaten nur im Rahmen dieses
|
||||||
|
Verfahrens zugestimmt. Eine Verwendung darueber hinaus wurde nicht
|
||||||
|
erlaubt. Damit ist insbesondere die Nutzung oder Uebermittlung der Daten
|
||||||
|
fuer Werbezwecke oder fuer die Markt- oder Meinungsforschung verboten.
|
||||||
|
|
||||||
|
========================================================================
|
||||||
|
|
||||||
|
|
||||||
|
Liste der gezaehlten Stimmen:
|
||||||
|
|
||||||
|
[@groups|[$grafix]|\n]
|
||||||
|
[$grafix-line]
|
||||||
|
[@multi|[$multi-line]|\n]
|
||||||
|
|
||||||
|
|
||||||
|
Ungueltige Stimmen:
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
[@invalid|[$invalid-line]\n[$reason]|\n]
|
33
templates/votes-single
Normal file
33
templates/votes-single
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
mail-name := value mail | justify name 72
|
||||||
|
invalid-line := value name | justify-before mail 72
|
||||||
|
|
||||||
|
== TEMPLATE ============================================================
|
||||||
|
|
||||||
|
========================================================================
|
||||||
|
|
||||||
|
Wichtiger Hinweis:
|
||||||
|
|
||||||
|
Die unten aufgefuehrten Personen haben der Speicherung, Verarbeitung
|
||||||
|
und Veroeffentlichung ihrer Adressen und Stimmdaten nur im Rahmen dieses
|
||||||
|
Verfahrens zugestimmt. Eine Verwendung darueber hinaus wurde nicht
|
||||||
|
erlaubt. Damit ist insbesondere die Nutzung oder Uebermittlung der Daten
|
||||||
|
fuer Werbezwecke oder fuer die Markt- oder Meinungsforschung verboten.
|
||||||
|
|
||||||
|
========================================================================
|
||||||
|
|
||||||
|
|
||||||
|
Ja gestimmt:
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
[@yes|[$mail-name]\n]
|
||||||
|
|
||||||
|
Nein gestimmt:
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
[@no|[$mail-name]\n]
|
||||||
|
|
||||||
|
[?abstain|Enthaltung:
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
[@abstain|[$mail-name]\n]]
|
||||||
|
|
||||||
|
Ungueltige Stimmen:
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
[@invalid|[$invalid-line]\n[$reason]|\n]
|
23
templates/wrong-ballotid
Normal file
23
templates/wrong-ballotid
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
votetaker := value mailfrom | fill-left 65
|
||||||
|
head := value head | quote "> "
|
||||||
|
body := value body | quote "> "
|
||||||
|
|
||||||
|
== TEMPLATE =================================================================
|
||||||
|
Die Wahlscheinkennung, die du in deinem Wahlschein benutzt hast,
|
||||||
|
entspricht nicht der Kennung, die beim Wahlleiter fuer deine EMail-
|
||||||
|
Adresse registriert ist, bitte benutzte die Wahlscheinkennung
|
||||||
|
aus deinem persoenlichen Wahlschein.
|
||||||
|
|
||||||
|
Solltest du wirklich eine andere Wahlscheinkennung zugeschickt
|
||||||
|
bekommen haben (oder du hast gar keinen Wahlschein angefordert),
|
||||||
|
so setzte dich bitte mit mir in Verbindung.
|
||||||
|
|
||||||
|
Hier die Mail, die ich erhalten habe:
|
||||||
|
|
||||||
|
[$head]
|
||||||
|
>
|
||||||
|
[$body]
|
||||||
|
|
||||||
|
|
||||||
|
[$votetaker]
|
||||||
|
\[mit [$usevote_version]\]
|
0
tmp/ergebnis-1191790177
Normal file
0
tmp/ergebnis-1191790177
Normal file
0
tmp/stimmen-1191790177
Normal file
0
tmp/stimmen-1191790177
Normal file
293
usevote.cfg
Normal file
293
usevote.cfg
Normal file
|
@ -0,0 +1,293 @@
|
||||||
|
########################################################################
|
||||||
|
# Diese Einstellungen muessen fuer jede Abstimmung angepasst werden
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
# Name der Abstimmung
|
||||||
|
votename = Einrichtung von xyz
|
||||||
|
|
||||||
|
# Abstimmungsgegenstaende (beliebig viele groupX moeglich,
|
||||||
|
# von 1 an durchzunummerieren)
|
||||||
|
group1 = Einrichtung von abc
|
||||||
|
|
||||||
|
# Bei den folgenden Fragen bedeutet jeweils:
|
||||||
|
# 0: nein
|
||||||
|
# 1: ja
|
||||||
|
|
||||||
|
# Persoenliche Wahlscheine generieren und Scheinkennung erzwingen?
|
||||||
|
personal = 0
|
||||||
|
|
||||||
|
# Verhaeltniswahl durchfuehren? (z.B. fuer Moderationsnachwahlen)
|
||||||
|
proportional = 0
|
||||||
|
|
||||||
|
# Formel fuer die Berechnung des Verhaeltnisses. Kann z.B.
|
||||||
|
# $yes/$no oder $yes-$no sein, letzteres wird bei Moderationsnachwahlen
|
||||||
|
# verwendet. Als Variablen sind $yes und $no zulaessig, es kann
|
||||||
|
# beliebiger Perlcode angegeben werden, dessen Rueckgabewert im
|
||||||
|
# Result erscheinen soll. Ausserdem wird bei der Auswertung die
|
||||||
|
# Bedingung aus "condition1" weiter unten in dieser Datei ausgewertet.
|
||||||
|
prop_formula = $yes/$no
|
||||||
|
|
||||||
|
# Vote-Account (diese Adresse muss unbedingt korrekt sein, wird
|
||||||
|
# in das Reply-To uebernommen)
|
||||||
|
voteaccount = vote-xyz@foo.bar
|
||||||
|
|
||||||
|
# Absender fuer den From-Header der Bestaetigungsmails
|
||||||
|
mailfrom = Vorname Nachname <gvv@foo.bar>
|
||||||
|
|
||||||
|
# Absender fuer den Envelope (Return-Path) der Bestaetigungsmails
|
||||||
|
# bei Verwendung von SMTP (bitte einfach nur die Adresse eintragen,
|
||||||
|
# ohne Klammern und Zusaetze). Bei smtp=0 muss das in "mailcmd"
|
||||||
|
# eingestellt werden, z.B. "-fadresse" für Sendmail
|
||||||
|
envelopefrom = gvv@foo.bar
|
||||||
|
|
||||||
|
# Nur bei persoenlichen Wahlscheinen: Datei mit Anforderungsmails
|
||||||
|
requestfile = anforderung
|
||||||
|
|
||||||
|
# Datenschutzklausel generieren und auf deren Existenz pruefen?
|
||||||
|
# Konfiguration siehe unten (bdsgtext)
|
||||||
|
bdsg = 1
|
||||||
|
|
||||||
|
# Reply-To beachten?
|
||||||
|
# Nicht empfohlen, da jemand fuer andere Personen abstimmen und
|
||||||
|
# die Bestaetigungen zu sich umlenken koennte.
|
||||||
|
replyto = 0
|
||||||
|
|
||||||
|
# Stimmen einzeln bestaetigen? Empfohlen!
|
||||||
|
voteack = 1
|
||||||
|
|
||||||
|
# Bcc-Adresse fuer alle Mails (Backup fuer alle Faelle)
|
||||||
|
#
|
||||||
|
#mailcc =
|
||||||
|
|
||||||
|
# Alles in einem Schritt durchfuehren (gesonderter Aufruf von
|
||||||
|
# "uvvote.pl clean" entfaellt)? Fuehrt zu geringeren
|
||||||
|
# Eingreifmoeglichkeiten! (Mails werden automatisch verschickt)
|
||||||
|
onestep = 0
|
||||||
|
|
||||||
|
# Fuer das Ergebnis (xx Ja-Stimmen, xx Nein-Stimmen, xx Enthaltungen)
|
||||||
|
# auch bei Eingruppenabstimmung des Mehrgruppenformat waehlen?
|
||||||
|
multigroup = 1
|
||||||
|
|
||||||
|
# Bedingungen fuer einen Erfolg der Abstimmung (genau zwei erforderlich).
|
||||||
|
# Es muss sich jeweils um gueltigen Perl-Code handeln, Rueckgabewert
|
||||||
|
# wird boolesch ausgewertet (true/false). Als Variablen sind $yes
|
||||||
|
# und $no zugelassen. Falls oben "proportional = 1" gesetzt wurde,
|
||||||
|
# wird nur Bedingung 1 ausgewertet und kann z.B. auf "$yes>$no" gesetzt
|
||||||
|
# werden.
|
||||||
|
condition1 = $yes>=2*$no
|
||||||
|
condition2 = $yes>=60
|
||||||
|
|
||||||
|
# Ergebnisdatei, in der alle Einzelergebniss zusammengeschrieben werden
|
||||||
|
# (wird bei jedem Programmlauf neu erstellt!)
|
||||||
|
resultfile = ergebnis.alle
|
||||||
|
|
||||||
|
# Datei fuer Scheinkennungen
|
||||||
|
idfile = scheinkennungen
|
||||||
|
|
||||||
|
# POP3 benutzen? (falls nicht, wird eine lokale Mailbox eingelesen)
|
||||||
|
pop3 = 1
|
||||||
|
|
||||||
|
# Mailbox, in der die zu verarbeitenden Mails liegen (falls pop3=0)
|
||||||
|
votefile = votes
|
||||||
|
|
||||||
|
# POP3-Einstellungen fuer Abruf der eingehenden Wahlscheine:
|
||||||
|
# Server, Port, Benutzername, Passwort
|
||||||
|
pop3server = 127.0.0.1
|
||||||
|
pop3port = 110
|
||||||
|
pop3user = test
|
||||||
|
pop3pass = test
|
||||||
|
# Mail nach dem Abrufen vom Server loeschen?
|
||||||
|
pop3delete = 0
|
||||||
|
# Dateiname zum Speichern der bereits abgerufenen Mail-IDs (UIDL)
|
||||||
|
pop3uidlcache = uidlcache
|
||||||
|
|
||||||
|
# POP3-Einstellungen fuer Abruf von Wahlschein-Anforderungen bei Abstimmungen
|
||||||
|
# mit personalisierten Wahlscheinen (Punkt 6a der Wahlregeln in de.*)
|
||||||
|
# Diese zweite Mailbox ist notwendig, um Wahlschein-Anforderungen und die
|
||||||
|
# eigentliche Abstimmung voneinander zu trennen (nicht noetig, wenn
|
||||||
|
# personal = 0 gesetzt ist)
|
||||||
|
pop3server_req = 127.0.0.1
|
||||||
|
pop3port_req = 110
|
||||||
|
pop3user_req = test
|
||||||
|
pop3pass_req = test
|
||||||
|
# Mail nach dem Abrufen vom Server loeschen?
|
||||||
|
pop3delete_req = 0
|
||||||
|
# Dateiname zum Speichern der bereits abgerufenen Mail-IDs (UIDL)
|
||||||
|
pop3uidlcache_req = uidlcache_req
|
||||||
|
|
||||||
|
# POP3-Einstellungen fuer uvbounce.pl (Verarbeitung von Bounces
|
||||||
|
# und Generierung einer Liste mit ungueltigen Stimmen). Alle
|
||||||
|
# zurueckgekommenen Mails an Waehler sollten in dieser Mailbox landen
|
||||||
|
pop3server_bounce = 127.0.0.1
|
||||||
|
pop3port_bounce = 110
|
||||||
|
pop3user_bounce = test2
|
||||||
|
pop3pass_bounce = test2
|
||||||
|
# Mail nach dem Abrufen vom Server loeschen?
|
||||||
|
pop3delete_bounce = 0
|
||||||
|
# Dateiname zum Speichern der bereits abgerufenen Mail-IDs (UIDL)
|
||||||
|
pop3uidlcache_bounce = uidlcache_bounce
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Alles ab hier braucht i.d.R. nur einmal festgelegt werden.
|
||||||
|
# Es ist moeglich, diese Einstellungen in eine globale Konfigurations-
|
||||||
|
# datei auszulagern. Das Einbinden erfolgt mit der Zeile
|
||||||
|
#
|
||||||
|
# include /pfad/zur/globalen_datei
|
||||||
|
#
|
||||||
|
# Falls Einstellungen aus der globalen Konfigurationsdatei hier
|
||||||
|
# fuer einzelne Abstimmungen ueberschrieben werden sollen, muessen
|
||||||
|
# diese *hinter* dem Include-Befehl stehen!
|
||||||
|
# (der letzte Wert ueberschreibt vorhergehende Definitionen)
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
# SMTP benutzen? (falls nicht, wird der weiter unten einstellbare
|
||||||
|
# MTA direkt aufgerufen; unter Windows kann nur SMTP benutzt werden!)
|
||||||
|
smtp = 1
|
||||||
|
|
||||||
|
# SMTP-Server (falls smtp = 1)
|
||||||
|
smtpserver = localhost
|
||||||
|
smtpport = 25
|
||||||
|
|
||||||
|
# SMTP-Authentifizierung benutzen? (RFC 2554)
|
||||||
|
# Das entsprechende Perlmodul (Net::SMTP) kann derzeit nur AUTH PLAIN,
|
||||||
|
# funktioniert also moeglicherweise nicht mit jedem Server
|
||||||
|
#smtpauth = 0
|
||||||
|
#smtpuser =
|
||||||
|
#smtppass =
|
||||||
|
|
||||||
|
# Falls als HELO etwas anderes als der Hostname verwendet werden soll:
|
||||||
|
#smtphelo =
|
||||||
|
|
||||||
|
# Falls ein anderer Fully Qualified Domain Name als der Hostname fuer
|
||||||
|
# die Message-ID verwendet werden soll:
|
||||||
|
#fqdn =
|
||||||
|
|
||||||
|
# Verzeichnis fuer fertig verarbeitete Mails und Ergebnisse
|
||||||
|
archivedir = fertig
|
||||||
|
|
||||||
|
# Temporaeres Verzeichnis
|
||||||
|
tmpdir = tmp
|
||||||
|
|
||||||
|
# Pfad zu den Templates (kommaseparierte Liste mit Verzeichnissen)
|
||||||
|
templatedir = templates
|
||||||
|
|
||||||
|
# Konvertierungsfunktionen für die Templates
|
||||||
|
# (kommaseparierte Liste mit Funktions-Modulen)
|
||||||
|
formats = UVformats.pm
|
||||||
|
|
||||||
|
# Dateiname der Steuerungsdatei fuer den Mailversandt
|
||||||
|
controlfile = tmp/ack.control
|
||||||
|
|
||||||
|
# Dateiname des Shellscripts zum Versenden der Bestaetigungsmails (falls smtp=0)
|
||||||
|
domailfile = tmp/domail
|
||||||
|
|
||||||
|
# MTA-Aufruf zum Verschicken der Bestaetigungsmails
|
||||||
|
# nuetzlich ist die Sendmail-Option -f zum Setzen des Absenders
|
||||||
|
#mailcmd = sendmail -oi -oem -femail@adresse
|
||||||
|
|
||||||
|
# Weiteres Kommando, welches nach jeder Mail aufgerufen werden soll (falls smtp=0).
|
||||||
|
# Sinnvoll ist ein "sleep x", wobei x bei langsamen Systemen hoeher
|
||||||
|
# gewaehlt werden sollte, um die Belastung gering zu halten.
|
||||||
|
sleepcmd = sleep 1
|
||||||
|
|
||||||
|
# Shellbefehl zum Loeschen des Bildschirms
|
||||||
|
# Unix: i.d.R. "clear"
|
||||||
|
# Windows: "cls"
|
||||||
|
# Falls das Betriebssystem bzw. die Shell keinen solchen Befehl zur Verfuegung
|
||||||
|
# stellt, sollte ein Kommando verwendet werden, welches eine Trennlinie
|
||||||
|
# oder aehnliches auf dem Bildschirm ausgibt, z.B. mit "echo"
|
||||||
|
clearcmd = clear
|
||||||
|
|
||||||
|
# Shellbefehl zum seitenweisen Darstellen von Mails auf dem Bildschirm
|
||||||
|
# Empfohlene Einstellung: "less", da more Probleme mit der Umleitung von
|
||||||
|
# STDERR in eine Datei Probleme hat. Unter Windows ist "less" nicht
|
||||||
|
# vorinstallirt, kann man sich aber herunterladen und einfach in das
|
||||||
|
# Windows-Verzeichnis kopieren (URL siehe README-Datei)
|
||||||
|
pager = less
|
||||||
|
|
||||||
|
# Datei mit diversen Meldungen und Textfragmenten (Resourcendatei)
|
||||||
|
messagefile = messages.cfg
|
||||||
|
|
||||||
|
# Datei mit Wahlregeln
|
||||||
|
rulefile = usevote.rul
|
||||||
|
|
||||||
|
# Datei mit verdaechtigen Mailadressen
|
||||||
|
badaddrfile = mailpatterns.cfg
|
||||||
|
|
||||||
|
# Datei fuer Fehlermeldungen beim Programmlauf
|
||||||
|
errorfile = errors.log
|
||||||
|
|
||||||
|
# Lockdatei (Verhinderung von mehrfachen Programmstarts)
|
||||||
|
lockfile = usevote.lock
|
||||||
|
|
||||||
|
# Einleitungszeile fuer naechste Mail (RegExp)
|
||||||
|
mailstart = "^From "
|
||||||
|
|
||||||
|
# Trennlinien vor und nach dem Wahlschein
|
||||||
|
begin_divider = Alles vor dieser Zeile bitte loeschen
|
||||||
|
end_divider = Alles nach dieser Zeile bitte loeschen
|
||||||
|
|
||||||
|
# Text fuer die Namens-Angabe im Wahlschein. Achtung, muss im
|
||||||
|
# Wahlschein genauso stehen!
|
||||||
|
nametext = Dein Realname, falls nicht im FROM-Header:
|
||||||
|
|
||||||
|
# Text fuer Namens-Angabe in Bestaetigungsmails
|
||||||
|
nametext2 = Waehlername:
|
||||||
|
|
||||||
|
# Text fuer die Adress-Angabe im Wahlschein
|
||||||
|
addresstext = Waehleradresse:
|
||||||
|
|
||||||
|
# Text für die Angabe der Wahlscheinkennung (siehe Option "personal")
|
||||||
|
ballotidtext = Wahlscheinkennung:
|
||||||
|
|
||||||
|
# Text fuer Datenschutzklausel (siehe Option "bdsg"), erscheint als Abstimmungspunkt
|
||||||
|
bdsgtext = Datenschutzklausel - Zustimmung: Ich bin mit der Verarbeitung meiner Daten wie oben beschrieben einverstanden
|
||||||
|
|
||||||
|
# Datei mit Erklaerungstext fuer BDSG-Klausel
|
||||||
|
bdsgfile = bdsgtext.cfg
|
||||||
|
|
||||||
|
# Rechter Rand fuer einige Bildschirmausgaben (Terminalbreite)
|
||||||
|
rightmargin = 72
|
||||||
|
|
||||||
|
# Regular Expression fuer Erkennung eines gueltigen Realnamens
|
||||||
|
name_re = [-a-zA-ZäöüáàâéèêíìîóòôúùûÄÖÜÁÁÂÉÈÊÍÌÎÓÒÔÚÙÛß]{2,} +.*[a-zA-ZäöüáàâéèêíìîóòôúùûÄÖÜÁÁÂÉÈÊÍÌÎÓÒÔÚÙÛß]{2,}
|
||||||
|
|
||||||
|
# RegExp fuer JA-Stimmen (case-insensitive)
|
||||||
|
# Standardmaessig wird J, JA, FUER und DAFUER erkannt
|
||||||
|
ja_stimme = (J\s*A|J|(D\s*A\s*)?F\s*U\s*E\s*R)
|
||||||
|
|
||||||
|
# RegExp fuer NEIN-Stimmen (case-insensitive)
|
||||||
|
# Standardmaessig wird N, NEIN, GEGEN und DAGEGEN erkannt
|
||||||
|
nein_stimme = (N\s*E\s*I\s*N|N|(D\s*A\s*)?G\s*E\s*G\s*E\s*N)
|
||||||
|
|
||||||
|
# RegExp fuer ENTHALTUNG (case-insensitive)
|
||||||
|
enth_stimme = (E|E\s*N\s*T\s*H\s*A\s*L\s*T\s*U\s*N\s*G)
|
||||||
|
|
||||||
|
# RegExp fuer ANNULLIERUNG (case-insensitive)
|
||||||
|
# Achtung, sollte auch in den Templates im Bestaetigungstext angepasst werden
|
||||||
|
ann_stimme = A\s*N\s*N\s*U\s*L\s*L\s*I\s*E\s*R\s*U\s*N\s*G
|
||||||
|
|
||||||
|
# Template files (these files are in the template directory defined above)
|
||||||
|
tpl_mailheader = "mailheader" # generally used mail header
|
||||||
|
tpl_bouncelist = "bouncelist" # used by uvbounce.pl
|
||||||
|
tpl_result_multi = "result-multi" # used by uvcount.pl -r -m
|
||||||
|
tpl_result_single = "result-single" # used by uvcount.pl -r -o
|
||||||
|
tpl_result_prop = "result-proportional" # used by uvcount.pl -r (proportional = 1)
|
||||||
|
tpl_votes_multi = "votes-multi" # used by uvcount.pl -v (multiple groups)
|
||||||
|
tpl_votes_single = "votes-single" # used by uvcount.pl -v (single group only)
|
||||||
|
tpl_voterlist = "voterlist" # used by uvcount.pl -l (2nd CfV)
|
||||||
|
tpl_ballot = "ballot" # used by uvballot.pl (personal = 0)
|
||||||
|
tpl_ballot_request = "ballot-request" # used by uvballot.pl (personal = 1)
|
||||||
|
tpl_ballot_personal = "ballot-personal" # used by uvcfv.pl (personal = 1)
|
||||||
|
tpl_addr_reg = "address-not-registered" # used by uvvote.pl (personal = 1)
|
||||||
|
tpl_no_ballotid = "no-ballotid" # used by uvvote.pl (personal = 1)
|
||||||
|
tpl_wrong_ballotid = "wrong-ballotid" # used by uvvote.pl (personal = 1)
|
||||||
|
tpl_bdsg_error = "bdsg-error" # used by uvvote.pl (bdsg = 1)
|
||||||
|
tpl_ack_mail = "ack-mail" # used by uvvote.pl (voteack = 1)
|
||||||
|
tpl_cancelled = "cancelled" # used by uvvote.pl
|
||||||
|
tpl_invalid_account = "invalid-account" # used by uvvote.pl
|
||||||
|
tpl_invalid_name = "invalid-name" # used by uvvote.pl
|
||||||
|
tpl_multiple_votes = "multiple-votes" # used by uvvote.pl
|
||||||
|
tpl_no_ballot = "no-ballot" # used by uvvote.pl
|
||||||
|
tpl_no_votes = "no-votes" # used by uvvote.pl
|
||||||
|
tpl_rule_violated = "rule-violated" # used by uvvote.pl (c.f. usevote.rul)
|
68
usevote.rul
Normal file
68
usevote.rul
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
# UseVote (c) 1993,94 Ron Dippold, alle Rechte vorbehalten
|
||||||
|
# uebersetzt von Frederik Ramm
|
||||||
|
#
|
||||||
|
# Mit dieser Datei koennen spezielle Regeln fuer eine gueltige Stimmabgabe
|
||||||
|
# bei Mehrgruppenabstimmungen erstellt werden.
|
||||||
|
# Beispiel: Eine Gruppe soll aufgeteilt werden, und Du willst erzwingen,
|
||||||
|
# dass jemand, der fuer eine der neuen Untergruppen stimmt, auch fuer
|
||||||
|
# die .misc-Gruppe stimmen muss. Man kann eine Menge komplexe Sachen hier-
|
||||||
|
# mit machen, wenn man Programmierer ist :-)
|
||||||
|
#
|
||||||
|
# Das allgemeine Format sieht so aus:
|
||||||
|
# (a) alles, was mit # anfaengt, ist ein Kommentar.
|
||||||
|
# (b) "echte" Regeln sehen etwa so aus (natuerlich ohne #):
|
||||||
|
# if .jjjjj then J.....
|
||||||
|
#
|
||||||
|
# Eine Regel beginnt immer mit "if", und danach folgen eine Anzahl Symbole;
|
||||||
|
# diese Anzahl muss gleich der Anzahl der Gruppen sein, ueber die abgestimmt
|
||||||
|
# wird.
|
||||||
|
# Oben geht es also um eine Abstimmung ueber sechs Gruppen.
|
||||||
|
# Die Symbole zwischen 'if' und 'then' geben an, welche Bedingungen erfuellt
|
||||||
|
# sein muessen, damit das System auch die Bedingungen hinter then prueft.
|
||||||
|
#
|
||||||
|
# Nach 'then' folgen nochmal so viele Symbole, die angeben, welche Bedin-
|
||||||
|
# gungen erfuellt sein muessen, falls die Bedingungen zwischen 'if' und
|
||||||
|
# 'then' erfuellt waren. Jeder Wahlschein, auf den das nicht zutrifft, ist
|
||||||
|
# ungueltig.
|
||||||
|
#
|
||||||
|
# Folgende Symbole sind erlaubt:
|
||||||
|
# J eine JA-Stimme
|
||||||
|
# N eine NEIN-Stimme
|
||||||
|
# E eine Enthaltung
|
||||||
|
# S eine JA- oder NEIN-Stimme
|
||||||
|
# H eine Enthaltung oder JA-Stimme
|
||||||
|
# I eine Enthaltung oder NEIN-Stimme
|
||||||
|
# . egal (Ja, nein oder Enthaltung)
|
||||||
|
# j eine oder mehrere der markierten Gruppen hat JA-Stimme
|
||||||
|
# n "" "" "" "" "" "" "" NEIN-Stimme
|
||||||
|
# e "" "" "" "" "" "" "" Enthaltung
|
||||||
|
# s "" "" "" "" "" "" "" Ja- oder Nein-Stimme
|
||||||
|
# h "" "" "" "" "" "" "" Enthaltung oder Ja-Stimme
|
||||||
|
# i "" "" "" "" "" "" "" Enthaltung oder Nein-Stimme
|
||||||
|
#
|
||||||
|
# Alles klar? Jede Stimme wird mit den Symbolen verglichen, und wenn alle
|
||||||
|
# Kriterien passen, ist der Ausdruck wahr. Wenn der erste Ausdruck (if x)
|
||||||
|
# wahr ist, muss auch der zeite (then y) wahr sein, sonst ist der Wahlschein
|
||||||
|
# ungueltig. Ein Beispiel:
|
||||||
|
# if .jjjjj then J.....
|
||||||
|
# Das heisst: Wenn der Waehler fuer *irgendeine* ausser der ersten Gruppe mit
|
||||||
|
# JA stimmt, dann *muss* er JA fuer die erste Gruppe stimmen, oder das ganze
|
||||||
|
# ist ungueltig.
|
||||||
|
# Das koennte z.B. eine Gruppenaufteilung sein, wo fuer die erste (die .misc)-
|
||||||
|
# Gruppe gestimmt werden *muss*, wenn fuer eine der anderen gestimmt wird.
|
||||||
|
#
|
||||||
|
# Hier noch ein Beispiel:
|
||||||
|
# if S... then .ss.
|
||||||
|
# if .S.. then ..E.
|
||||||
|
# if ..S. then .E..
|
||||||
|
# Diese Regeln sagen: Wer fuer die erste Gruppe abstimmt, der muss auch fuer
|
||||||
|
# die zweite und dritte Gruppe abstimmen - egal wie. Ausserdem muss er (Re-
|
||||||
|
# geln 2 und 3) sich bei 3 enthalten, wenn er bei 2 eine Stimme abgibt und
|
||||||
|
# umgekehrt. Die vierte Gruppe wird hier gar nicht betroffen.
|
||||||
|
#
|
||||||
|
# Also: es gibt einfache Regeln, aber es sind auch sehr komplizierte Kom-
|
||||||
|
# binationen denkar. Das Programm macht alles mit... die Frage ist, ob
|
||||||
|
# es die Waehler tun :-)
|
||||||
|
#
|
||||||
|
# Fuege Deine Regeln hier an. Mit "uvvote.pl -t" kannst Du sie testen.
|
||||||
|
|
116
uvballot.pl
Normal file
116
uvballot.pl
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# UseVoteGer 4.09 Wahlscheingenerierung
|
||||||
|
# (c) 2001-2005 Marc Langer <uv@marclanger.de>
|
||||||
|
#
|
||||||
|
# This script package is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Public License as published by the
|
||||||
|
# Free Software Foundation.
|
||||||
|
#
|
||||||
|
# Use this script to create the ballot which can be inserted into the CfV.
|
||||||
|
# Not for personal ballots (personal=1 in usevote.cfg), use uvcfv.pl instead.
|
||||||
|
#
|
||||||
|
# Many thanks to:
|
||||||
|
# - Ron Dippold (Usevote 3.0, 1993/94)
|
||||||
|
# - Frederik Ramm (German translation, 1994)
|
||||||
|
# - Wolfgang Behrens (UseVoteGer 3.1, based on Frederik's translation, 1998/99)
|
||||||
|
# - Cornell Binder for some good advice and code fragments
|
||||||
|
#
|
||||||
|
# This is a complete rewrite of UseVoteGer 3.1 in Perl (former versions were
|
||||||
|
# written in C). Not all functions of Usevote/UseVoteGer 3.x are implemented!
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Getopt::Long;
|
||||||
|
use Text::Wrap qw(wrap $columns);
|
||||||
|
use FindBin qw($Bin);
|
||||||
|
use lib $Bin;
|
||||||
|
use UVconfig;
|
||||||
|
use UVtemplate;
|
||||||
|
|
||||||
|
my %opt_ctl = ();
|
||||||
|
|
||||||
|
print STDERR "\n$usevote_version Wahlscheingenerierung - (c) 2001-2005 Marc Langer\n\n";
|
||||||
|
|
||||||
|
# unknown parameters remain in @ARGV (for "help")
|
||||||
|
Getopt::Long::Configure(qw(pass_through bundling));
|
||||||
|
|
||||||
|
# Put known parameters in %opt_ctl
|
||||||
|
GetOptions(\%opt_ctl, qw(t|template c|config-file=s));
|
||||||
|
|
||||||
|
# Additional parameters or invalid options? Show help and exit.
|
||||||
|
help() if (@ARGV);
|
||||||
|
|
||||||
|
# Get name auf config file (default: usevote.cfg) and read it
|
||||||
|
my $cfgfile = $opt_ctl{c} || "usevote.cfg";
|
||||||
|
UVconfig::read_config($cfgfile);
|
||||||
|
|
||||||
|
# Set columns for Text::Wrap
|
||||||
|
$columns = $config{rightmargin};
|
||||||
|
|
||||||
|
if ($config{personal}) {
|
||||||
|
print_ballot_personal();
|
||||||
|
} else {
|
||||||
|
print_ballot();
|
||||||
|
}
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Print out a proper ballot #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub print_ballot {
|
||||||
|
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
|
||||||
|
$template->setKey('votename' => $config{votename});
|
||||||
|
$template->setKey('nametext' => $config{nametext});
|
||||||
|
$template->setKey('bdsg' => $config{bdsg});
|
||||||
|
$template->setKey('bdsgtext' => $config{bdsgtext});
|
||||||
|
$template->setKey('bdsginfo' => $config{bdsginfo});
|
||||||
|
|
||||||
|
for (my $n=0; $n<@groups; $n++) {
|
||||||
|
$template->addListItem('groups', pos=>$n+1, group=>$groups[$n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
print $template->processTemplate($config{'tpl_ballot'});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Generate a ballot request (if personalized ballots are activated) #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub print_ballot_personal {
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
$template->setKey('mailaddress' => $config{mailfrom});
|
||||||
|
print $template->processTemplate($config{'tpl_ballot_request'});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Print help text (options and syntax) on -h or --help #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub help {
|
||||||
|
print STDERR <<EOF;
|
||||||
|
Usage: uvballot.pl [-c config_file]
|
||||||
|
uvballot.pl -h
|
||||||
|
|
||||||
|
Generiert den Wahlschein fuer den CfV. Bei personalisierten Wahlscheinen
|
||||||
|
(personal = 1 in usevote.cfg) wird nur ein Dummy-Abschnitt mit Hinweisen
|
||||||
|
zur Wahlscheinanforderung ausgegeben.
|
||||||
|
|
||||||
|
-c config_file liest die Konfiguration aus config_file
|
||||||
|
(usevote.cfg falls nicht angegeben)
|
||||||
|
|
||||||
|
-h, --help zeigt diesen Hilfetext an
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
}
|
194
uvbounce.pl
Normal file
194
uvbounce.pl
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# UseVoteGer 4.09 Bounce-Verarbeitung
|
||||||
|
# (c) 2001-2005 Marc Langer <uv@marclanger.de>
|
||||||
|
#
|
||||||
|
# This script package is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Public License as published by the
|
||||||
|
# Free Software Foundation.
|
||||||
|
#
|
||||||
|
# Use this script to process bounce messages and generate a list of
|
||||||
|
# undeliverable voter adresses.
|
||||||
|
#
|
||||||
|
# Many thanks to:
|
||||||
|
# - Ron Dippold (Usevote 3.0, 1993/94)
|
||||||
|
# - Frederik Ramm (German translation, 1994)
|
||||||
|
# - Wolfgang Behrens (UseVoteGer 3.1, based on Frederik's translation, 1998/99)
|
||||||
|
# - Cornell Binder for some good advice and code fragments
|
||||||
|
#
|
||||||
|
# This is a complete rewrite of UseVoteGer 3.1 in Perl (former versions were
|
||||||
|
# written in C). Not all functions of Usevote/UseVoteGer 3.x are implemented!
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Getopt::Long;
|
||||||
|
use FindBin qw($Bin);
|
||||||
|
use lib $Bin;
|
||||||
|
use UVconfig;
|
||||||
|
use UVreadmail;
|
||||||
|
use UVtemplate;
|
||||||
|
|
||||||
|
my %opt_ctl = ();
|
||||||
|
my %bounces = ();
|
||||||
|
my $pop3 = 0;
|
||||||
|
|
||||||
|
print STDERR "\n$usevote_version Bounce-Verarbeitung - (c) 2001-2005 Marc Langer\n\n";
|
||||||
|
|
||||||
|
# unknown parameters remain in @ARGV (for "help")
|
||||||
|
Getopt::Long::Configure(qw(pass_through bundling));
|
||||||
|
|
||||||
|
# Put known parameters in %opt_ctl
|
||||||
|
GetOptions(\%opt_ctl, qw(h|help f|file config-file=s c=s));
|
||||||
|
|
||||||
|
# Get name auf config file (default: usevote.cfg) and read it
|
||||||
|
my $cfgfile = $opt_ctl{'config-file'} || $opt_ctl{c} || "usevote.cfg";
|
||||||
|
UVconfig::read_config($cfgfile);
|
||||||
|
|
||||||
|
# check POP3 settings in usevote.cfg and combination with -f parameter
|
||||||
|
$pop3 = 1 if ($config{pop3} && !$opt_ctl{f});
|
||||||
|
|
||||||
|
# Additional parameters or invalid options? Show help and exit.
|
||||||
|
help() if ($opt_ctl{h} || !(@ARGV || $pop3));
|
||||||
|
|
||||||
|
# check for lock file
|
||||||
|
if (-e $config{lockfile}) {
|
||||||
|
my $lockfile = $config{lockfile};
|
||||||
|
|
||||||
|
# don't delete lockfile in END block ;-)
|
||||||
|
$config{lockfile} = '';
|
||||||
|
|
||||||
|
# exit
|
||||||
|
die UVmessage::get("ERR_LOCK", (FILE=>$lockfile)) . "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# safe exit (delete lockfile)
|
||||||
|
$SIG{QUIT} = 'sighandler';
|
||||||
|
$SIG{INT} = 'sighandler';
|
||||||
|
$SIG{KILL} = 'sighandler';
|
||||||
|
$SIG{TERM} = 'sighandler';
|
||||||
|
$SIG{HUP} = 'sighandler';
|
||||||
|
|
||||||
|
# create lock file
|
||||||
|
open (LOCKFILE, ">$config{lockfile}");
|
||||||
|
close (LOCKFILE);
|
||||||
|
|
||||||
|
# read and process mails
|
||||||
|
# for each mail pass a reference to the sub to be called
|
||||||
|
|
||||||
|
if ($pop3) {
|
||||||
|
unless (-d $config{archivedir}) {
|
||||||
|
mkdir ($config{archivedir}, 0700)
|
||||||
|
or die UVmessage::get("ERR_MKDIR", (DIR => $config{archivedir})) . "$!\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# mails are saved in file
|
||||||
|
# normally unixtime is sufficient for a unique file name, else append PID
|
||||||
|
my $ext = time;
|
||||||
|
|
||||||
|
opendir (ARCHIVE, $config{archivedir});
|
||||||
|
my @fertigfiles = readdir (ARCHIVE);
|
||||||
|
closedir (ARCHIVE);
|
||||||
|
|
||||||
|
# append PID if file name already exists
|
||||||
|
$ext .= "-$$" if (grep (/$ext/, @fertigfiles));
|
||||||
|
|
||||||
|
my $file = "$config{archivedir}/bounces-" . $ext;
|
||||||
|
UVreadmail::process($file, \&process_bounce, 2); # 2 = POP3
|
||||||
|
|
||||||
|
} else {
|
||||||
|
foreach my $file (@ARGV) {
|
||||||
|
UVreadmail::process($file, \&process_bounce, 3); # 3 = existing file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
|
||||||
|
foreach my $address (sort keys %bounces) {
|
||||||
|
my $name = $bounces{$address};
|
||||||
|
my $request = 0;
|
||||||
|
my $text;
|
||||||
|
if ($name eq '***request***') {
|
||||||
|
$name = '';
|
||||||
|
$text = UVmessage::get ("BOUNCE_BALLOT") . "\n";
|
||||||
|
} else {
|
||||||
|
$text = UVmessage::get ("BOUNCE_ACKMAIL") . "\n";
|
||||||
|
}
|
||||||
|
$name = ' ' unless($name);
|
||||||
|
$template->addListItem('bounces', name=>$name, mail=>$address, bouncetext=>$text);
|
||||||
|
}
|
||||||
|
|
||||||
|
print $template->processTemplate($config{'tpl_bouncelist'});
|
||||||
|
exit 0;
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Evaluate a bounce #
|
||||||
|
# This sub is called from UVreadmail::process() for every mail #
|
||||||
|
# Parameters: voter address and name, date header (strings) #
|
||||||
|
# complete header and body (references to strings) #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub process_bounce {
|
||||||
|
# last element of @_ is the body, other stuff not needed here
|
||||||
|
my $body = pop;
|
||||||
|
my ($address, $name);
|
||||||
|
|
||||||
|
# search body for voter name and address
|
||||||
|
if ($$body =~ /$config{addresstext}\s+(\S+@\S+)/) {
|
||||||
|
$address = $1;
|
||||||
|
if ($$body =~ /$config{nametext2}\s+(.*)$/m) {
|
||||||
|
$name = $1;
|
||||||
|
$bounces{$address} = $name;
|
||||||
|
} elsif ($$body =~ /$config{nametext}/) {
|
||||||
|
# Text from this config option does only appear in ballots,
|
||||||
|
# not in acknowledge mails. So this has to be a bounced ballot request
|
||||||
|
$bounces{$address} = '***request***';
|
||||||
|
} else {
|
||||||
|
$bounces{$address} = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
END {
|
||||||
|
# delete lockfile
|
||||||
|
unlink $config{lockfile} if ($config{lockfile});
|
||||||
|
}
|
||||||
|
|
||||||
|
sub sighandler {
|
||||||
|
my ($sig) = @_;
|
||||||
|
die "\n\nSIG$sig: deleting lockfile and exiting\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Print help text (options and syntax) on -h or --help #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub help {
|
||||||
|
print <<EOF;
|
||||||
|
Usage: uvbounce.pl [-c config_file] [-f] DATEI1 [DATEI2 [...]]
|
||||||
|
uvbounce.pl -h
|
||||||
|
|
||||||
|
Liest Bounces aus den uebergebenen Dateien oder aus einer POP3-Mailbox ein
|
||||||
|
(Verhalten haengt von usevote.cfg ab) und generiert eine Liste von
|
||||||
|
unzustellbaren Adressen, die an den 2. CfV oder das Result angehaengt
|
||||||
|
werden kann. Falls POP3 in usevote.cfg eingeschaltet und die Option -f
|
||||||
|
(siehe unten) nicht benutzt wurde, werden die uebergebenen Dateinamen
|
||||||
|
ignoriert.
|
||||||
|
|
||||||
|
-c config_file liest die Konfiguration aus config_file
|
||||||
|
(usevote.cfg falls nicht angegeben)
|
||||||
|
|
||||||
|
-f, --file liest die Bounces aus den uebergebenen Dateien, auch
|
||||||
|
wenn in der Konfigurationsdatei POP3 eingeschaltet ist.
|
||||||
|
Diese Option wird benoetigt, falls zwar die Stimmzettel
|
||||||
|
per POP3 eingelesen werden sollen, nicht aber die Bounces.
|
||||||
|
|
||||||
|
-h, --help zeigt diesen Hilfetext an
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
}
|
282
uvcfv.pl
Normal file
282
uvcfv.pl
Normal file
|
@ -0,0 +1,282 @@
|
||||||
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# UseVoteGer 4.09 Personalisierte Wahlscheine
|
||||||
|
# (c) 2001-2005 Marc Langer <uv@marclanger.de>
|
||||||
|
#
|
||||||
|
# This script package is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Public License as published by the
|
||||||
|
# Free Software Foundation.
|
||||||
|
#
|
||||||
|
# Use this script to read mails and send back a CfV with unique ballot id
|
||||||
|
#
|
||||||
|
# Many thanks to:
|
||||||
|
# - Ron Dippold (Usevote 3.0, 1993/94)
|
||||||
|
# - Frederik Ramm (German translation, 1994)
|
||||||
|
# - Wolfgang Behrens (UseVoteGer 3.1, based on Frederik's translation, 1998/99)
|
||||||
|
# - Cornell Binder for some good advice and code fragments
|
||||||
|
#
|
||||||
|
# This is a complete rewrite of UseVoteGer 3.1 in Perl (former versions were
|
||||||
|
# written in C). Not all functions of Usevote/UseVoteGer 3.x are implemented!
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Getopt::Long;
|
||||||
|
use Digest::MD5 qw(md5_hex);
|
||||||
|
use Text::Wrap qw(wrap $columns);
|
||||||
|
use FindBin qw($Bin);
|
||||||
|
use lib $Bin;
|
||||||
|
use UVconfig;
|
||||||
|
use UVmenu;
|
||||||
|
use UVmessage;
|
||||||
|
use UVreadmail;
|
||||||
|
use UVsendmail;
|
||||||
|
use UVtemplate;
|
||||||
|
|
||||||
|
my %opt_ctl = ();
|
||||||
|
|
||||||
|
print "\n$usevote_version Personalisierte Wahlscheine - (c) 2001-2005 Marc Langer\n\n";
|
||||||
|
|
||||||
|
# unknown parameters remain in @ARGV (for "help")
|
||||||
|
Getopt::Long::Configure(qw(pass_through bundling));
|
||||||
|
|
||||||
|
# Put known parameters in %opt_ctl
|
||||||
|
GetOptions(\%opt_ctl, qw(test t config-file=s c=s));
|
||||||
|
|
||||||
|
# test mode? (default: no)
|
||||||
|
my $test_only = $opt_ctl{test} || $opt_ctl{t} || 0;
|
||||||
|
|
||||||
|
# # Additional parameters or invalid options? Show help and exit.
|
||||||
|
help() if (@ARGV);
|
||||||
|
|
||||||
|
# Get name auf config file (default: usevote.cfg) and read it
|
||||||
|
my $cfgfile = $opt_ctl{'config-file'} || $opt_ctl{c} || "usevote.cfg";
|
||||||
|
UVconfig::read_config($cfgfile);
|
||||||
|
|
||||||
|
# Set columns for Text::Wrap
|
||||||
|
$columns = $config{rightmargin};
|
||||||
|
|
||||||
|
# read list of suspicious mail addresses from file
|
||||||
|
my @bad_addr = UVconfig::read_badaddr();
|
||||||
|
|
||||||
|
# exit if option "personal=1" in config file not set
|
||||||
|
unless ($config{personal}) {
|
||||||
|
die wrap ('', '', UVmessage::get("ERR_NOTPERSONAL", (CFGFILE => $cfgfile))) . "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# option -t used?
|
||||||
|
if ($test_only) {
|
||||||
|
print_ballot();
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# check for lock file
|
||||||
|
if (-e $config{lockfile}) {
|
||||||
|
my $lockfile = $config{lockfile};
|
||||||
|
|
||||||
|
# don't delete lockfile in END block ;-)
|
||||||
|
$config{lockfile} = '';
|
||||||
|
|
||||||
|
# exit
|
||||||
|
die UVmessage::get("ERR_LOCK", (FILE=>$lockfile)) . "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# safe exit (delete lockfile)
|
||||||
|
$SIG{QUIT} = 'sighandler';
|
||||||
|
$SIG{INT} = 'sighandler';
|
||||||
|
$SIG{KILL} = 'sighandler';
|
||||||
|
$SIG{TERM} = 'sighandler';
|
||||||
|
$SIG{HUP} = 'sighandler';
|
||||||
|
|
||||||
|
# create lock file
|
||||||
|
open (LOCKFILE, ">$config{lockfile}");
|
||||||
|
close (LOCKFILE);
|
||||||
|
|
||||||
|
# check for tmp directory and domail file
|
||||||
|
unless (-d $config{tmpdir}) {
|
||||||
|
mkdir ($config{tmpdir}, 0700)
|
||||||
|
or die UVmessage::get("ERR_MKDIR", (DIR => $config{tmpdir})) . "\n$!\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate filename for mail archive
|
||||||
|
# normally unixtime is sufficient, if it is not unique append a number
|
||||||
|
my $file = my $base = "anforderung-" . time();
|
||||||
|
my $count = 0;
|
||||||
|
while ($count<1000 && (-e "$config{archivedir}/$file" || -e "$config{tmpdir}/$file")) {
|
||||||
|
$file = "$base-" . ++$count;
|
||||||
|
}
|
||||||
|
die UVmessage::get("ERR_FILE_CREATION") . "\n\n" if ($count == 1000);
|
||||||
|
|
||||||
|
unless ($config{pop3}) {
|
||||||
|
rename ($config{requestfile}, "$config{tmpdir}/$file")
|
||||||
|
or die UVmessage::get("ERR_RENAME_MAILFILE") . "$!\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# wait, so that current mail deliveries can finalize
|
||||||
|
sleep 2;
|
||||||
|
|
||||||
|
# initiliaze random number generator
|
||||||
|
srand;
|
||||||
|
|
||||||
|
# read votes and process them
|
||||||
|
# for each mail pass a reference to the sub to be called
|
||||||
|
# The third parameter "1" shows that it is called from uvcfv.pl
|
||||||
|
$count = UVreadmail::process("$config{tmpdir}/$file", \&process_request, 1);
|
||||||
|
print "\n", UVmessage::get("CFV_NUMBER", (COUNT => $count)), "\n\n";
|
||||||
|
UVsendmail::send();
|
||||||
|
|
||||||
|
print UVmessage::get("INFO_TIDY_UP") . "\n\n";
|
||||||
|
rename("$config{tmpdir}/$file", "$config{archivedir}/$file");
|
||||||
|
chmod (0400, "$config{archivedir}/$file");
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Evaluate a ballot request #
|
||||||
|
# Called from UVreadmail::process() for every mail #
|
||||||
|
# Parameters: Voter address and name, date header of vote mail (strings), #
|
||||||
|
# complete header and body (references to Strings) #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub process_request {
|
||||||
|
my ($voter_addr, $voter_name, $h_date, $entity, $body) = @_;
|
||||||
|
|
||||||
|
my @header = split(/\n/, $entity->stringify_header);
|
||||||
|
my $head = $entity->head;
|
||||||
|
my $msgid = $head->get('Message-ID');
|
||||||
|
chomp($msgid) if ($msgid);
|
||||||
|
|
||||||
|
# found address?
|
||||||
|
if ($voter_addr) {
|
||||||
|
# check for suspicious addresses
|
||||||
|
foreach my $element (@bad_addr) {
|
||||||
|
if ($voter_addr =~ /^$element/) {
|
||||||
|
my (@votes, @set, $ballot_id); # irrelevant, but necessary for UVmenu::menu()
|
||||||
|
my @errors = ('SuspiciousAccountBallot');
|
||||||
|
my $res = UVmenu::menu(\@votes, \@header, $body, \$voter_addr, \$voter_name, \$ballot_id, \@set, \@errors);
|
||||||
|
|
||||||
|
# "Ignore": don't deliver a ballot
|
||||||
|
return 0 if ($res eq 'i');
|
||||||
|
if (@errors) {
|
||||||
|
# send error mail if address hasn't been accepted
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
$template->setKey('head' => $entity->stringify_header);
|
||||||
|
$template->setKey('body' => $$body);
|
||||||
|
my $msg = $template->processTemplate($config{tpl_invalid_account});
|
||||||
|
UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
# no address found in mail (non-RFC compliant?)
|
||||||
|
my (@votes, @set, $ballot_id); # irrelevant, but necessary for UVmenu::menu()
|
||||||
|
my @errors = ('InvalidAddressBallot');
|
||||||
|
my $res = UVmenu::menu(\@votes, \@header, $body, \$voter_addr, \$voter_name, \$ballot_id, \@set, \@errors);
|
||||||
|
|
||||||
|
# "ignore" or address not ok: no ballot can be sent
|
||||||
|
return 0 if (@errors || $res eq 'i');
|
||||||
|
}
|
||||||
|
|
||||||
|
my $subject = UVmessage::get("CFV_SUBJECT");
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
my $ballot_id = "";
|
||||||
|
|
||||||
|
#if ($ballot_id ne $ids{$voter_addr}) {
|
||||||
|
if ($ids{$voter_addr}) {
|
||||||
|
$ballot_id = $ids{$voter_addr};
|
||||||
|
$template->setKey('alreadysent' => 1) if ($ballot_id = $ids{$voter_addr});
|
||||||
|
} else {
|
||||||
|
# generate new ballot id from the MD5 sum of header, body and a random value
|
||||||
|
$ballot_id = md5_hex($entity->stringify_header . $body . rand 65535);
|
||||||
|
$ids{$voter_addr} = $ballot_id;
|
||||||
|
|
||||||
|
# write ballot id to file
|
||||||
|
open(IDFILE, ">>$config{idfile}")
|
||||||
|
or die UVmessage::get("CFV_ERRWRITE", (FILE => $config{idfile})) . "\n\n";
|
||||||
|
print IDFILE "$voter_addr $ballot_id\n";
|
||||||
|
close(IDFILE) or die UVmessage::get("CFV_ERRCLOSE") . "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$template->setKey('ballotid' => $ballot_id);
|
||||||
|
$template->setKey('address' => $voter_addr);
|
||||||
|
$template->setKey('bdsginfo' => $config{bdsginfo});
|
||||||
|
|
||||||
|
for (my $n=0; $n<@groups; $n++) {
|
||||||
|
$template->addListItem('groups', pos=>$n+1, group=>$groups[$n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
my $msg = $template->processTemplate($config{'tpl_ballot_personal'});
|
||||||
|
|
||||||
|
# $config{voteaccount} is the Reply-To address:
|
||||||
|
UVsendmail::mail($voter_addr, $subject, $msg, $msgid, $config{voteaccount});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Print dummy personalized ballot in STDOUT for checking purposes #
|
||||||
|
# Called if command line argument -t is present #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub print_ballot {
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
|
||||||
|
# generate new ballot id
|
||||||
|
my $ballot_id = md5_hex(rand 65535);
|
||||||
|
|
||||||
|
$template->setKey('ballotid' => $ballot_id);
|
||||||
|
$template->setKey('address' => 'dummy@foo.invalid');
|
||||||
|
$template->setKey('bdsginfo' => $config{bdsginfo});
|
||||||
|
|
||||||
|
for (my $n=0; $n<@groups; $n++) {
|
||||||
|
$template->addListItem('groups', pos=>$n+1, group=>$groups[$n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
my $msg = $template->processTemplate($config{'tpl_ballot_personal'});
|
||||||
|
|
||||||
|
print $msg, "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Handle Signals and delete lock files when exiting #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
END {
|
||||||
|
# delete lockfile
|
||||||
|
unlink $config{lockfile} if ($config{lockfile});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub sighandler {
|
||||||
|
my ($sig) = @_;
|
||||||
|
die "\n\nSIG$sig: deleting lockfile and exiting\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Print help text (options and syntax) on -h or --help #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub help {
|
||||||
|
print <<EOF;
|
||||||
|
Usage: uvcfv.pl [-c config_file] [-t]
|
||||||
|
uvcfv.pl -h
|
||||||
|
|
||||||
|
Liest Mailboxen ein und beantwortet alle Mails mit personalisierten CfVs.
|
||||||
|
|
||||||
|
-c config_file liest die Konfiguration aus config_file
|
||||||
|
(usevote.cfg falls nicht angegeben)
|
||||||
|
|
||||||
|
-t, --test gibt einen Dummy-Wahlschein fuer Pruefzwecke aus
|
||||||
|
|
||||||
|
-h, --help zeigt diesen Hilfetext an
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
}
|
475
uvcount.pl
Normal file
475
uvcount.pl
Normal file
|
@ -0,0 +1,475 @@
|
||||||
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# UseVoteGer 4.09 Stimmauswertung
|
||||||
|
# (c) 2001-2005 Marc Langer <uv@marclanger.de>
|
||||||
|
#
|
||||||
|
# This script package is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Public License as published by the
|
||||||
|
# Free Software Foundation.
|
||||||
|
#
|
||||||
|
# Use this script to create voter lists and results.
|
||||||
|
#
|
||||||
|
# Many thanks to:
|
||||||
|
# - Ron Dippold (Usevote 3.0, 1993/94)
|
||||||
|
# - Frederik Ramm (German translation, 1994)
|
||||||
|
# - Wolfgang Behrens (UseVoteGer 3.1, based on Frederik's translation, 1998/99)
|
||||||
|
# - Cornell Binder for some good advice and code fragments
|
||||||
|
#
|
||||||
|
# This is a complete rewrite of UseVoteGer 3.1 in Perl (former versions were
|
||||||
|
# written in C). Not all functions of Usevote/UseVoteGer 3.x are implemented!
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Getopt::Long;
|
||||||
|
use Digest::MD5 qw(md5_hex);
|
||||||
|
use Date::Parse;
|
||||||
|
use FindBin qw($Bin);
|
||||||
|
use lib $Bin;
|
||||||
|
use UVconfig;
|
||||||
|
use UVmenu;
|
||||||
|
use UVmessage;
|
||||||
|
use UVtemplate;
|
||||||
|
|
||||||
|
my %opt_ctl = ();
|
||||||
|
|
||||||
|
print STDERR "\n$usevote_version Stimmauswertung - (c) 2001-2005 Marc Langer\n\n";
|
||||||
|
|
||||||
|
# unrecognized parameters remain in @ARGV (for "help")
|
||||||
|
Getopt::Long::Configure(qw(pass_through bundling));
|
||||||
|
|
||||||
|
# recognized parameters are written into %opt_ctl
|
||||||
|
GetOptions(\%opt_ctl, qw(l|list v|voters r|result n|nodup m|multigroup o|onegroup c|config-file=s f|result-file=s));
|
||||||
|
|
||||||
|
if (!$opt_ctl{r} && ($opt_ctl{m} || $opt_ctl{o})) {
|
||||||
|
print STDERR "Die Optionen -m bzw. -o koennen nur in Verbindung mit -r verwendet werden!\n\n";
|
||||||
|
help(); # show help and exit
|
||||||
|
} elsif (@ARGV || !($opt_ctl{l} || $opt_ctl{v} || $opt_ctl{r})) {
|
||||||
|
# additional parameters passed
|
||||||
|
help(); # show help and exit
|
||||||
|
} elsif ($opt_ctl{l} && $opt_ctl{v}) {
|
||||||
|
print STDERR "Die Optionen -l und -v duerfen nicht zusammen verwendet werden!\n\n";
|
||||||
|
help(); # show help and exit
|
||||||
|
} elsif ($opt_ctl{m} && $opt_ctl{o}) {
|
||||||
|
print STDERR "Die Optionen -m und -o duerfen nicht zusammen verwendet werden!\n\n";
|
||||||
|
help(); # show help and exit
|
||||||
|
}
|
||||||
|
|
||||||
|
# get config file name (default: usevote.cfg) and read it
|
||||||
|
my $cfgfile = $opt_ctl{c} || "usevote.cfg";
|
||||||
|
UVconfig::read_config($cfgfile);
|
||||||
|
|
||||||
|
# Overwrite result file if started with option -f
|
||||||
|
$config{resultfile} = $opt_ctl{f} if ($opt_ctl{f});
|
||||||
|
|
||||||
|
read_resultfile($opt_ctl{n});
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Read result file and (optionally) sort out duplicate votes #
|
||||||
|
# Parameters: 1 if no duplicates should be deleted, else 0 #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub read_resultfile {
|
||||||
|
my ($nodup) = @_;
|
||||||
|
my $num = 0;
|
||||||
|
my $invalid = '';
|
||||||
|
my $inv_count = 0;
|
||||||
|
my $validcount = 0;
|
||||||
|
my $vote = {};
|
||||||
|
my @votes = ();
|
||||||
|
my @deleted = ();
|
||||||
|
my @votecount = ();
|
||||||
|
my %vnames = ();
|
||||||
|
my %vaddr = ();
|
||||||
|
my %lists = (J => '', N => '', E => ''); # for one-group format
|
||||||
|
my $list = ''; # for multiple-group format
|
||||||
|
my %varname = (J => 'yes', N => 'no', E => 'abstain');
|
||||||
|
|
||||||
|
# Initialization of the sum array
|
||||||
|
for (my $group=0; $group<@groups; $group++) {
|
||||||
|
$votecount[$group]->{J} = 0;
|
||||||
|
$votecount[$group]->{N} = 0;
|
||||||
|
$votecount[$group]->{E} = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
open(FILE, "<$config{resultfile}")
|
||||||
|
or die UVmessage::get("COUNT_ERR_OPEN", (FILE=>$config{resultfile})) . "\n\n";
|
||||||
|
|
||||||
|
# Read file
|
||||||
|
while(<FILE>) {
|
||||||
|
chomp;
|
||||||
|
$num++;
|
||||||
|
|
||||||
|
unless (/^(\w): (.*)$/) {
|
||||||
|
print STDERR UVmessage::get("COUNT_ERR_RESULT",
|
||||||
|
(FILE=>$config{resultfile}, LINE=>$num)) . "\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $field = $1;
|
||||||
|
my $content = $2;
|
||||||
|
$vote->{$field} = $content;
|
||||||
|
|
||||||
|
# End of a paragraph reached?
|
||||||
|
if ($field eq 'S') {
|
||||||
|
|
||||||
|
# The array @votes countains references to the hashes
|
||||||
|
push (@votes, $vote);
|
||||||
|
|
||||||
|
# For sorting and duplicate detection indexes are build from address and name.
|
||||||
|
# These are hashes containing references to an array of index numbers of
|
||||||
|
# the @votes array.
|
||||||
|
#
|
||||||
|
# Example: $vnames{'marc langer'}->[0] = 2
|
||||||
|
# $vnames{'marc langer'}->[1] = 10
|
||||||
|
# Meaning: $votes[2] und $votes[10] contain votes of Marc Langer
|
||||||
|
|
||||||
|
push (@{$vnames{lc($vote->{N})}}, $#votes);
|
||||||
|
|
||||||
|
# Conversion in lower case, so that words with an upper case first
|
||||||
|
# letter are not at the top after sorting
|
||||||
|
push (@{$vaddr{lc($vote->{A})}}, $#votes);
|
||||||
|
|
||||||
|
# reset $vote, begin a new vote
|
||||||
|
$vote = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(FILE);
|
||||||
|
|
||||||
|
# delete cancelled votes
|
||||||
|
foreach my $addr (keys %vaddr) {
|
||||||
|
# Run through all votes belonging to a mail address and search for cancellation
|
||||||
|
for (my $n=0; $n<=$#{$vaddr{$addr}}; $n++) {
|
||||||
|
if ($votes[$vaddr{$addr}->[$n]]->{S} =~ /^\*/) {
|
||||||
|
# delete from array
|
||||||
|
push(@deleted, splice(@{$vaddr{$addr}}, 0, $n+1));
|
||||||
|
$n=-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# sort out duplicates?
|
||||||
|
unless ($nodup) {
|
||||||
|
|
||||||
|
# search for duplicate addresses
|
||||||
|
foreach my $addr (keys %vaddr) {
|
||||||
|
|
||||||
|
# Run through all votes belonging to a mail address.
|
||||||
|
# If one vote is deleted it has also to be deleted from the array
|
||||||
|
# so that the following addresses move up. In the other case the
|
||||||
|
# counter is incremented as long as further votes are to be compared.
|
||||||
|
|
||||||
|
my $n=0;
|
||||||
|
while ($n<$#{$vaddr{$addr}}) {
|
||||||
|
|
||||||
|
my $ask = 0;
|
||||||
|
|
||||||
|
if ($votes[$vaddr{$addr}->[$n]]->{S} =~ /!/ ||
|
||||||
|
$votes[$vaddr{$addr}->[$n+1]]->{S} =~ /!/) {
|
||||||
|
|
||||||
|
# One of the votes is invalid: Ask votetaker
|
||||||
|
$ask = 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
# Convert date into unixtime (str2time is located in Date::Parse)
|
||||||
|
my $date1 = str2time($votes[$vaddr{$addr}->[$n]]->{D});
|
||||||
|
my $date2 = str2time($votes[$vaddr{$addr}->[$n+1]]->{D});
|
||||||
|
|
||||||
|
# compare dates
|
||||||
|
my $order = $date1 <=> $date2;
|
||||||
|
|
||||||
|
# first date is earlier
|
||||||
|
if ($order == -1) {
|
||||||
|
push(@deleted, $vaddr{$addr}->[$n]);
|
||||||
|
# delete first element from the array
|
||||||
|
splice(@{$vaddr{$addr}}, $n, 1);
|
||||||
|
|
||||||
|
# second date is earlier
|
||||||
|
} elsif ($order == 1) {
|
||||||
|
push(@deleted, $vaddr{$addr}->[$n+1]);
|
||||||
|
# delete second element from the array
|
||||||
|
splice(@{$vaddr{$addr}}, $n+1, 1);
|
||||||
|
|
||||||
|
# both are equal (ask votetaker)
|
||||||
|
} else {
|
||||||
|
$ask = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# Has votetaker to be asked?
|
||||||
|
if ($ask) {
|
||||||
|
my $default = 0;
|
||||||
|
my $res = UVmenu::dup_choice($votes[$vaddr{$addr}->[0]],
|
||||||
|
$votes[$vaddr{$addr}->[1]],
|
||||||
|
$default);
|
||||||
|
|
||||||
|
if ($res == 1) {
|
||||||
|
push(@deleted, $vaddr{$addr}->[0]);
|
||||||
|
# delete first element from the array
|
||||||
|
splice(@{$vaddr{$addr}}, $n, 1);
|
||||||
|
|
||||||
|
} elsif ($res == 2) {
|
||||||
|
push(@deleted, $vaddr{$addr}->[1]);
|
||||||
|
# delete second element from the array
|
||||||
|
splice(@{$vaddr{$addr}}, $n+1, 1);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
# don't delete anything: increment counter
|
||||||
|
$n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# the same for equal names:
|
||||||
|
foreach my $name (keys %vnames) {
|
||||||
|
my $n = 0;
|
||||||
|
while ($n<$#{$vnames{$name}}) {
|
||||||
|
|
||||||
|
# check if vote was already deleted by prior address sorting
|
||||||
|
if (grep(/^$vnames{$name}->[$n]$/, @deleted)) {
|
||||||
|
# delete first element from the array
|
||||||
|
splice(@{$vnames{$name}}, $n, 1);
|
||||||
|
next;
|
||||||
|
|
||||||
|
} elsif (grep(/^$vnames{$name}->[$n+1]$/, @deleted)) {
|
||||||
|
# delete second element from the array
|
||||||
|
splice(@{$vnames{$name}}, $n+1, 1);
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convert date into unixtime (str2time is located in Date::Parse)
|
||||||
|
my $date1 = str2time($votes[$vnames{$name}->[$n]]->{D});
|
||||||
|
my $date2 = str2time($votes[$vnames{$name}->[$n+1]]->{D});
|
||||||
|
|
||||||
|
# Set default for menu choice to the earlier vote
|
||||||
|
my $default = ($date2 < $date1) ? 2 : 0;
|
||||||
|
|
||||||
|
my $res = UVmenu::dup_choice($votes[$vnames{$name}->[$n]],
|
||||||
|
$votes[$vnames{$name}->[$n+1]],
|
||||||
|
$default);
|
||||||
|
|
||||||
|
# delete first
|
||||||
|
if ($res == 1) {
|
||||||
|
push(@deleted, $vnames{$name}->[$n]);
|
||||||
|
splice(@{$vnames{$name}}, $n, 1);
|
||||||
|
|
||||||
|
# delete second
|
||||||
|
} elsif ($res == 2) {
|
||||||
|
push(@deleted, $vnames{$name}->[$n+1]);
|
||||||
|
# delete second element from the array
|
||||||
|
splice(@{$vnames{$name}}, $n+1, 1);
|
||||||
|
|
||||||
|
# don't delete anything: increment counter
|
||||||
|
} else {
|
||||||
|
$n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print STDERR UVmessage::get("COUNT_DELETED", (NUM=>scalar @deleted)), "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Count votes and generate voter list
|
||||||
|
|
||||||
|
my $list_tpl = UVtemplate->new();
|
||||||
|
$list_tpl->setKey('groupcount' => scalar @groups);
|
||||||
|
|
||||||
|
# reversed order as caption string for last column comes first
|
||||||
|
for (my $n=$#groups; $n>=0; $n--) {
|
||||||
|
$list_tpl->addListItem('groups', pos=>@groups-$n, group=>$groups[$n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
# loop through all addresses
|
||||||
|
foreach my $addr (sort keys %vaddr) {
|
||||||
|
|
||||||
|
# loop through all votes for every address
|
||||||
|
for (my $n=0; $n<@{$vaddr{$addr}}; $n++) {
|
||||||
|
|
||||||
|
# Ignore vote if already deleted.
|
||||||
|
# If $nodup is not set one single vote should remain
|
||||||
|
unless (grep(/^$vaddr{$addr}->[$n]$/, @deleted)) {
|
||||||
|
|
||||||
|
# extract $vote for simplier code
|
||||||
|
my $vote = $votes[$vaddr{$addr}->[$n]];
|
||||||
|
|
||||||
|
# vote is invalid if there is an exclamation mark
|
||||||
|
if ($vote->{S} =~ /!/) {
|
||||||
|
$inv_count++;
|
||||||
|
} else {
|
||||||
|
# split vote string into single votes and count
|
||||||
|
my @splitvote = split(//, $vote->{S});
|
||||||
|
if (@groups != @splitvote) {
|
||||||
|
die UVmessage::get("COUNT_ERR_GROUPCOUNT", (ADDR=>$addr, NUM1=>scalar @splitvote,
|
||||||
|
NUM2=>scalar @groups), RESULTFILE=>$config{resultfile}), "\n\n";
|
||||||
|
}
|
||||||
|
for (my $group=0; $group<@splitvote; $group++) {
|
||||||
|
$votecount[$group]->{$splitvote[$group]}++;
|
||||||
|
}
|
||||||
|
$validcount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($opt_ctl{l} || $opt_ctl{v}) {
|
||||||
|
|
||||||
|
# vote is invalid if there is an exclamation mark
|
||||||
|
if ($vote->{S} =~ /!/) {
|
||||||
|
$list_tpl->addListItem('invalid', (name=>$vote->{N}, mail=>$vote->{A}, reason=>$vote->{S}));
|
||||||
|
|
||||||
|
# in other cases the vote is valid: generate list of votes
|
||||||
|
} else {
|
||||||
|
|
||||||
|
# one-group or multiple-group format?
|
||||||
|
# must use multiple-group data structure for voter list (2. CfV)!
|
||||||
|
if ($#groups || $opt_ctl{l}) {
|
||||||
|
$list_tpl->addListItem('multi', (name=>$vote->{N}, mail=>$vote->{A}, vote=>$vote->{S}));
|
||||||
|
} else {
|
||||||
|
my ($votestring) = split(//, $vote->{S});
|
||||||
|
$list_tpl->addListItem($varname{$votestring}, (name=>$vote->{N}, mail=>$vote->{A}));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($opt_ctl{r}) {
|
||||||
|
|
||||||
|
my $tplname;
|
||||||
|
my $result_tpl = UVtemplate->new();
|
||||||
|
$result_tpl->setKey('votename' => $config{votename});
|
||||||
|
$result_tpl->setKey('numvalid' => $validcount);
|
||||||
|
$result_tpl->setKey ('numinvalid', $inv_count);
|
||||||
|
|
||||||
|
# proportional vote?
|
||||||
|
if ($config{proportional}) {
|
||||||
|
$tplname = $config{'tpl_result_prop'};
|
||||||
|
for (my $group=0; $group<@votecount; $group++) {
|
||||||
|
# calculate conditions
|
||||||
|
my $yes = $votecount[$group]->{J};
|
||||||
|
my $no = $votecount[$group]->{N};
|
||||||
|
my $cond1 = eval $config{condition1};
|
||||||
|
my $proportion = 0;
|
||||||
|
|
||||||
|
# don't evaluate if division by zero
|
||||||
|
unless ($config{prop_formula} =~ m#.+/(.+)# && eval($1)==0) {
|
||||||
|
$proportion = eval $config{prop_formula};
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate result line
|
||||||
|
$result_tpl->addListItem('count', (yes => $votecount[$group]->{J},
|
||||||
|
no => $votecount[$group]->{N},
|
||||||
|
cond1 => $cond1,
|
||||||
|
proportion => $proportion,
|
||||||
|
result => '', # must be set manually
|
||||||
|
group => $groups[$group]));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
# use one-group or multiple-group format?
|
||||||
|
if (@groups == 1 && (!($config{multigroup} || $opt_ctl{m}) || $opt_ctl{o})) {
|
||||||
|
$tplname = $config{'tpl_result_single'};
|
||||||
|
my $yes = $votecount[0]->{J};
|
||||||
|
my $no = $votecount[0]->{N};
|
||||||
|
my $acc1 = eval $config{condition1};
|
||||||
|
my $acc2 = eval $config{condition2};
|
||||||
|
$result_tpl->setKey('yes' => $votecount[0]->{J});
|
||||||
|
$result_tpl->setKey('no' => $votecount[0]->{N});
|
||||||
|
$result_tpl->setKey('numabstain' => $votecount[0]->{E});
|
||||||
|
$result_tpl->setKey('cond1' => $acc1);
|
||||||
|
$result_tpl->setKey('cond2' => $acc2);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$tplname = $config{'tpl_result_multi'};
|
||||||
|
$result_tpl->setKey('numabstain' => 0);
|
||||||
|
|
||||||
|
for (my $group=0; $group<@votecount; $group++) {
|
||||||
|
# calculate conditions
|
||||||
|
my $yes = $votecount[$group]->{J};
|
||||||
|
my $no = $votecount[$group]->{N};
|
||||||
|
my $cond1 = eval $config{condition1};
|
||||||
|
my $cond2 = eval $config{condition2};
|
||||||
|
|
||||||
|
# generate result line
|
||||||
|
$result_tpl->addListItem('count', (yes => $votecount[$group]->{J},
|
||||||
|
no => $votecount[$group]->{N},
|
||||||
|
cond1 => $cond1,
|
||||||
|
cond2 => $cond2,
|
||||||
|
result => ($cond1 && $cond2),
|
||||||
|
group => $groups[$group]));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result_tpl->setKey ('numabstain', $votecount[0]->{E}) if (@votecount == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
print $result_tpl->processTemplate($tplname);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($opt_ctl{v}) {
|
||||||
|
|
||||||
|
# one-group or multiple-group format?
|
||||||
|
if ($#groups) {
|
||||||
|
print $list_tpl->processTemplate($config{'tpl_votes_multi'});
|
||||||
|
} else {
|
||||||
|
print $list_tpl->processTemplate($config{'tpl_votes_single'});
|
||||||
|
}
|
||||||
|
|
||||||
|
} elsif ($opt_ctl{l}) {
|
||||||
|
print $list_tpl->processTemplate($config{'tpl_voterlist'});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Print help text (options and syntax) on -h or --help #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub help {
|
||||||
|
print STDERR <<EOF;
|
||||||
|
Usage: uvcount.pl [-c config_file] [-f result_file] [-l | -v] [-r [-m | -o]] [-n]
|
||||||
|
uvcount.pl -h
|
||||||
|
|
||||||
|
Zaehlt Stimmen und gibt Waehlerlisten aus.
|
||||||
|
|
||||||
|
-c config_file liest die Konfiguration aus config_file
|
||||||
|
(usevote.cfg falls nicht angegeben)
|
||||||
|
|
||||||
|
-f result_file liest die Stimmen aus result_file (ueberschreibt
|
||||||
|
die "resultfile"-Angabe aus der Konfigurationsdatei)
|
||||||
|
|
||||||
|
-l, --list Gibt eine Liste aller Waehler aus (ohne Stimmen).
|
||||||
|
|
||||||
|
-v, --voters Wie -l, aber mit Angabe der abgegebenen Stimmen.
|
||||||
|
|
||||||
|
-r, --result Ausgabe des Endergebnisses (kann mit -l oder -v
|
||||||
|
kombiniert werden).
|
||||||
|
|
||||||
|
-m, --multigroup Benutzt auch bei Eingruppenabstimmungen das
|
||||||
|
Mehrgruppenformat beim Endergebnis (ueberschreibt
|
||||||
|
die Einstellung aus usevote.cfg).
|
||||||
|
Nur in Kombination mit -r verwendbar, schliesst -o aus.
|
||||||
|
|
||||||
|
-o, --onegroup Benutzt bei Eingruppenabstimmungen immer das
|
||||||
|
Eingruppenformat beim Endergebnis (ueberschreibt
|
||||||
|
die Einstellung aus usevote.cfg).
|
||||||
|
Nur in Kombination mit -r verwendbar, schliesst -m aus.
|
||||||
|
|
||||||
|
-n, --nodup Verzichtet auf das Aussortieren von doppelten
|
||||||
|
Stimmabgaben. Nicht empfohlen!
|
||||||
|
|
||||||
|
-h, --help zeigt diesen Hilfetext an
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
}
|
595
uvvote.pl
Normal file
595
uvvote.pl
Normal file
|
@ -0,0 +1,595 @@
|
||||||
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# UseVoteGer 4.09 Wahldurchfuehrung
|
||||||
|
# (c) 2001-2005 Marc Langer <uv@marclanger.de>
|
||||||
|
#
|
||||||
|
# This script package is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Public License as published by the
|
||||||
|
# Free Software Foundation.
|
||||||
|
#
|
||||||
|
# The script reads usenet vote ballots from mailbox files. The format
|
||||||
|
# can be set by changing the option "mailstart".
|
||||||
|
#
|
||||||
|
# Many thanks to:
|
||||||
|
# - Ron Dippold (Usevote 3.0, 1993/94)
|
||||||
|
# - Frederik Ramm (German translation, 1994)
|
||||||
|
# - Wolfgang Behrens (UseVoteGer 3.1, based on Frederik's translation, 1998/99)
|
||||||
|
# - Cornell Binder for some good advice and code fragments
|
||||||
|
#
|
||||||
|
# This is a complete rewrite of UseVoteGer 3.1 in Perl (former versions were
|
||||||
|
# written in C). Not all functions of Usevote/UseVoteGer 3.x are implemented!
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Getopt::Long;
|
||||||
|
use Text::Wrap qw(wrap $columns);
|
||||||
|
use FindBin qw($Bin);
|
||||||
|
use lib $Bin;
|
||||||
|
use UVconfig;
|
||||||
|
use UVmenu;
|
||||||
|
use UVmessage;
|
||||||
|
use UVreadmail;
|
||||||
|
use UVsendmail;
|
||||||
|
use UVrules;
|
||||||
|
use UVtemplate;
|
||||||
|
|
||||||
|
my $clean = 0;
|
||||||
|
my %opt_ctl = ();
|
||||||
|
|
||||||
|
print "\n$usevote_version Wahldurchfuehrung - (c) 2001-2005 Marc Langer\n\n";
|
||||||
|
|
||||||
|
# unknown parameters remain in @ARGV (for "help")
|
||||||
|
Getopt::Long::Configure(qw(pass_through bundling));
|
||||||
|
|
||||||
|
# Put known parameters in %opt_ctl
|
||||||
|
GetOptions(\%opt_ctl, qw(test t config-file=s c=s));
|
||||||
|
|
||||||
|
# Get name auf config file (default: usevote.cfg) and read it
|
||||||
|
my $cfgfile = $opt_ctl{'config-file'} || $opt_ctl{c} || "usevote.cfg";
|
||||||
|
|
||||||
|
# test mode? (default: no)
|
||||||
|
my $test_only = $opt_ctl{test} || $opt_ctl{t} || 0;
|
||||||
|
|
||||||
|
if (@ARGV){
|
||||||
|
# additional parameters passed
|
||||||
|
|
||||||
|
if ($ARGV[0] eq "clean") {
|
||||||
|
$clean = 1;
|
||||||
|
} else {
|
||||||
|
# print help and exit program
|
||||||
|
help();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UVconfig::read_config($cfgfile, 1); # read config file, redirect errors to log
|
||||||
|
UVrules::read_rulefile(); # read rules from file
|
||||||
|
|
||||||
|
# read list of suspicious mail addresses from file
|
||||||
|
my @bad_addr = UVconfig::read_badaddr();
|
||||||
|
|
||||||
|
# option -t used?
|
||||||
|
if ($test_only) {
|
||||||
|
UVconfig::test_config();
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# check for lock file
|
||||||
|
if (-e $config{lockfile}) {
|
||||||
|
my $lockfile = $config{lockfile};
|
||||||
|
|
||||||
|
# don't delete lockfile in END block ;-)
|
||||||
|
$config{lockfile} = '';
|
||||||
|
|
||||||
|
# exit
|
||||||
|
die UVmessage::get("ERR_LOCK", (FILE=>$lockfile)) . "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# safe exit (delete lockfile)
|
||||||
|
$SIG{QUIT} = 'sighandler';
|
||||||
|
$SIG{INT} = 'sighandler';
|
||||||
|
$SIG{KILL} = 'sighandler';
|
||||||
|
$SIG{TERM} = 'sighandler';
|
||||||
|
$SIG{HUP} = 'sighandler';
|
||||||
|
|
||||||
|
# create lock file
|
||||||
|
open (LOCKFILE, ">$config{lockfile}");
|
||||||
|
close (LOCKFILE);
|
||||||
|
|
||||||
|
# Set columns for Text::Wrap
|
||||||
|
$columns = $config{rightmargin};
|
||||||
|
|
||||||
|
# check for tmp and archive directory
|
||||||
|
unless (-d $config{archivedir}) {
|
||||||
|
mkdir ($config{archivedir}, 0700)
|
||||||
|
or die UVmessage::get("ERR_MKDIR", (DIR=>$config{archivedir})) . "$!\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
unless (-d $config{tmpdir}) {
|
||||||
|
mkdir ($config{tmpdir}, 0700)
|
||||||
|
or die UVmessage::get("ERR_MKDIR", (DIR=>$config{tmpdir})) . "$!\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($clean) {
|
||||||
|
# Program has been startet with "clean" option:
|
||||||
|
# save votes and send out acknowledge mails
|
||||||
|
make_clean();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
# normal processing
|
||||||
|
|
||||||
|
# generate file names for result file
|
||||||
|
# normally unixtime is sufficient, if it is not unique append our PID
|
||||||
|
my $ext = time;
|
||||||
|
|
||||||
|
opendir (TMP, $config{tmpdir});
|
||||||
|
my @tmpfiles = readdir (DIR);
|
||||||
|
closedir (TMP);
|
||||||
|
opendir (FERTIG, $config{archivedir});
|
||||||
|
my @fertigfiles = readdir (FERTIG);
|
||||||
|
closedir (FERTIG);
|
||||||
|
|
||||||
|
# append PID if necessary
|
||||||
|
$ext .= "-$$" if (grep (/$ext/, @tmpfiles) || grep (/$ext/, @fertigfiles));
|
||||||
|
|
||||||
|
my $thisresult = "ergebnis-" . $ext;
|
||||||
|
my $thisvotes = "stimmen-" . $ext;
|
||||||
|
|
||||||
|
# POP3 not activated: rename votes file
|
||||||
|
unless ($config{pop3}) {
|
||||||
|
print UVmessage::get("VOTE_RENAMING_MAILBOX"), "\n";
|
||||||
|
rename ($config{votefile}, "$config{tmpdir}/$thisvotes")
|
||||||
|
or die UVmessage::get("ERR_RENAME_MAILFILE") . "$!\n\n";
|
||||||
|
|
||||||
|
# wait, so that current mail deliveries can finalize
|
||||||
|
sleep 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
# open results file
|
||||||
|
open (RESULT, ">>$config{tmpdir}/$thisresult")
|
||||||
|
or die UVmessage::get("VOTE_WRITE_RESULTS", (FILE=>$thisresult)) . "\n\n";
|
||||||
|
|
||||||
|
# read votes and process them
|
||||||
|
# for each mail pass a reference to the sub to be called
|
||||||
|
my $count = UVreadmail::process("$config{tmpdir}/$thisvotes", \&process_vote, 0);
|
||||||
|
|
||||||
|
close (RESULT)
|
||||||
|
or print STDERR UVmessage::get("VOTE_CLOSE_RESULTS", (FILE=>$thisresult)) . "\n";
|
||||||
|
|
||||||
|
# no mails: exit here
|
||||||
|
unless ($count) {
|
||||||
|
print UVmessage::get("VOTE_NO_VOTES") . "\n\n";
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($config{onestep}) {
|
||||||
|
# everything should be done in one step
|
||||||
|
print "\n" . UVmessage::get("VOTE_NUM_VOTES", (COUNT=>$count)) . "\n";
|
||||||
|
make_clean();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
print "\n", UVmessage::get("VOTE_NOT_SAVED", (COUNT=>$count)), "\n",
|
||||||
|
wrap('', '', UVmessage::get("VOTE_FIRSTRUN")), "\n\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
|
||||||
|
END {
|
||||||
|
close (STDERR);
|
||||||
|
|
||||||
|
# delete lockfile
|
||||||
|
unlink $config{lockfile} if ($config{lockfile});
|
||||||
|
|
||||||
|
if (-s $config{errorfile}) {
|
||||||
|
# errors ocurred
|
||||||
|
print '*' x $config{rightmargin}, "\n",
|
||||||
|
UVmessage::get("VOTE_ERRORS",(FILE => $config{errorfile})), "\n",
|
||||||
|
'*' x $config{rightmargin}, "\n\n";
|
||||||
|
open (ERRFILE, "<$config{errorfile}");
|
||||||
|
print <ERRFILE>;
|
||||||
|
close (ERRFILE);
|
||||||
|
print "\n";
|
||||||
|
} else {
|
||||||
|
unlink ($config{errorfile});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub sighandler {
|
||||||
|
my ($sig) = @_;
|
||||||
|
die "\n\nSIG$sig: deleting lockfile and exiting\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Evaluation of a vote mail #
|
||||||
|
# Called from UVreadmail::process() for each mail. #
|
||||||
|
# Parameters: voter address and name, date header of the vote mail (strings) #
|
||||||
|
# complete header (reference to array), body (ref. to strings) #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub process_vote {
|
||||||
|
my ($voter_addr, $voter_name, $h_date, $entity, $body) = @_;
|
||||||
|
|
||||||
|
my @header = split(/\n/, $entity->stringify_header);
|
||||||
|
my $head = $entity->head;
|
||||||
|
my $msgid = $head->get('Message-ID');
|
||||||
|
chomp($msgid) if ($msgid);
|
||||||
|
|
||||||
|
my @votes = (); # the votes
|
||||||
|
my @set; # interactively changed fields
|
||||||
|
my @errors = (); # recognized errors (show menu for manual action)
|
||||||
|
my $onevote = 0; # 0=no votes, 1=everything OK, 2=vote cancelled
|
||||||
|
my $voteerror = ""; # error message in case of invalid vote
|
||||||
|
my $ballot_id = ""; # ballot id (German: Wahlscheinkennung)
|
||||||
|
|
||||||
|
# found address?
|
||||||
|
if ($voter_addr) {
|
||||||
|
# search for suspicious addresses
|
||||||
|
foreach my $element (@bad_addr) {
|
||||||
|
if ($voter_addr =~ /^$element/) {
|
||||||
|
push (@errors, 'SuspiciousAccount');
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# found no address in mail (perhaps violates RFC?)
|
||||||
|
push (@errors, 'InvalidAddress');
|
||||||
|
}
|
||||||
|
|
||||||
|
# personalized ballots?
|
||||||
|
if ($config{personal}) {
|
||||||
|
if ($$body =~ /$config{ballotidtext}\s+([a-z0-9]+)/) {
|
||||||
|
$ballot_id = $1;
|
||||||
|
# Address registered? ($ids is set in UVconfig.pm)
|
||||||
|
if ($ids{$voter_addr}) {
|
||||||
|
push (@errors, 'WrongBallotID') if ($ids{$voter_addr} ne $ballot_id);
|
||||||
|
} else {
|
||||||
|
push (@errors, 'AddressNotRegistered');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
push (@errors, 'NoBallotID');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# evaluate vote strings
|
||||||
|
for (my $n=0; $n<@groups; $n++) {
|
||||||
|
|
||||||
|
# counter starts at 1 in ballot
|
||||||
|
my $votenum = $n+1;
|
||||||
|
my $vote = "";
|
||||||
|
|
||||||
|
# a line looks like this: #1 [ VOTE ] Group
|
||||||
|
# matching only on number and vote, because of line breaks likely
|
||||||
|
# inserted by mail programs
|
||||||
|
|
||||||
|
# duplicate vote?
|
||||||
|
if ($$body =~ /#$votenum\W*?\[\s*?(\w+)\s*?\].+?#$votenum\W*?\[\s*?(\w+)\s*?\]/s) {
|
||||||
|
push (@errors, "DuplicateVote") if ($1 ne $2);
|
||||||
|
}
|
||||||
|
|
||||||
|
# this matches on a single appearance:
|
||||||
|
if ($$body =~ /#$votenum\W*?\[(.+)\]/) {
|
||||||
|
# one or more vote strings were found
|
||||||
|
$onevote = 1;
|
||||||
|
my $votestring = $1;
|
||||||
|
if ($votestring =~ /^\W*$config{ja_stimme}\W*$/i) {
|
||||||
|
$vote = "J";
|
||||||
|
} elsif ($votestring =~ /^\W*$config{nein_stimme}\W*$/i) {
|
||||||
|
$vote = "N";
|
||||||
|
} elsif ($votestring =~ /^\W*$config{enth_stimme}\W*$/i) {
|
||||||
|
$vote = "E";
|
||||||
|
} elsif ($votestring =~ /^\s*$/) {
|
||||||
|
# nothing has been entered between the [ ]
|
||||||
|
$vote = "E";
|
||||||
|
} elsif ($votestring =~ /^\W*$config{ann_stimme}\W*$/i) {
|
||||||
|
$vote = "A";
|
||||||
|
$onevote = 2; # Cancelled vote: set $onevote to 2
|
||||||
|
} elsif (!$votes[$n]) {
|
||||||
|
# vote not recognized
|
||||||
|
$vote = "E";
|
||||||
|
push (@errors, 'UnrecognizedVote #' . $votenum . "#$votestring");
|
||||||
|
}
|
||||||
|
push (@votes, $vote);
|
||||||
|
} else {
|
||||||
|
# vote not found
|
||||||
|
push (@votes, 'E');
|
||||||
|
push (@errors, 'UnrecognizedVote #' . $votenum . '#(keine Stimmabgabe fuer "'
|
||||||
|
. $groups[$n] . '" gefunden)');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($onevote == 0) {
|
||||||
|
push (@errors, "NoVote") unless ($onevote);
|
||||||
|
} elsif ($onevote == 1) {
|
||||||
|
# check rules
|
||||||
|
my $rule = UVrules::rule_check(\@votes);
|
||||||
|
push (@errors, "ViolatedRule #$rule") if ($rule);
|
||||||
|
} else {
|
||||||
|
# cancelled vote: replace all votes with an A
|
||||||
|
@votes = split(//, 'A' x scalar @votes);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Evaluate Data Protection Law clause (not on cancelled votes)
|
||||||
|
if ($config{bdsg} && $onevote<2) {
|
||||||
|
|
||||||
|
# Text in ballot complete and clause accepted?
|
||||||
|
# Should read like this: #a [ STIMME ] Text
|
||||||
|
# (Text is configurable in usevote.cfg)
|
||||||
|
unless ($$body =~ /$bdsg_regexp/s &&
|
||||||
|
$$body =~ /#a\W*?\[\W*?$config{ja_stimme}\W*?\]\W*?$bdsg2_regexp/is) {
|
||||||
|
|
||||||
|
push (@errors, 'InvalidBDSG');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Name in body?
|
||||||
|
if ($$body =~ /($config{nametext}|$config{nametext2})( |\t)*(\S.+?)$/m) {
|
||||||
|
$voter_name = $3;
|
||||||
|
$voter_name =~ s/^\s+//; # strip leading spaces
|
||||||
|
$voter_name =~ s/\s+$//; # strip trailing spaces
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($voter_name) {
|
||||||
|
# Name invalid?
|
||||||
|
push (@errors, 'InvalidName') unless ($voter_name =~ /$config{name_re}/);
|
||||||
|
} else {
|
||||||
|
# no name found:
|
||||||
|
push (@errors, 'NoName') unless ($voter_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Errors encountered?
|
||||||
|
if (@errors) {
|
||||||
|
my $res = UVmenu::menu(\@votes, \@header, $body, \$voter_addr, \$voter_name,
|
||||||
|
\$ballot_id, \@set, \@errors);
|
||||||
|
return 0 if ($res eq 'i'); # "Ignore": Ignore vote, don't save
|
||||||
|
|
||||||
|
my $tpl;
|
||||||
|
|
||||||
|
# Check Ballot ID stuff
|
||||||
|
if ($config{personal}) {
|
||||||
|
if ($ballot_id) {
|
||||||
|
if ($ids{$voter_addr}) {
|
||||||
|
if ($ids{$voter_addr} ne $ballot_id) {
|
||||||
|
$voteerror = UVmessage::get("VOTE_INVALID_BALLOTID");
|
||||||
|
$tpl = $config{tpl_wrong_ballotid};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$voteerror = UVmessage::get("VOTE_UNREGISTERED_ADDRESS");
|
||||||
|
$tpl = $config{tpl_addr_reg};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$voteerror = UVmessage::get("VOTE_MISSING_BALLOTID");
|
||||||
|
$tpl = $config{tpl_no_ballotid};
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate error mail (if error occurred)
|
||||||
|
if ($tpl) {
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
$template->setKey('head' => $entity->stringify_header);
|
||||||
|
$template->setKey('body' => $$body);
|
||||||
|
my $msg = $template->processTemplate($tpl);
|
||||||
|
UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid) if ($config{voteack});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check rules and send error mail unless rule violation was ignored in the use menu
|
||||||
|
# or another error was detected
|
||||||
|
if (grep(/ViolatedRule/, @errors) && !$voteerror && (my $rule = UVrules::rule_check(\@votes))) {
|
||||||
|
$voteerror = UVmessage::get("VOTE_VIOLATED_RULE", (RULE=>$rule));
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
$template->setKey('body' => $$body);
|
||||||
|
$template->setKey('rules' => UVrules::rule_print($rule-1));
|
||||||
|
my $msg = $template->processTemplate($config{tpl_rule_violated});
|
||||||
|
UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid) if ($config{voteack});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$voteerror && @errors) {
|
||||||
|
|
||||||
|
# turn errors array into hash
|
||||||
|
|
||||||
|
my %error;
|
||||||
|
foreach my $error (@errors) {
|
||||||
|
$error{$error} = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check uncorrected errors
|
||||||
|
if ($error{InvalidBDSG}) {
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
my $msg = $template->processTemplate($config{tpl_bdsg_error});
|
||||||
|
UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid) if ($config{voteack});
|
||||||
|
return 0;
|
||||||
|
} elsif ($error{NoVote}) {
|
||||||
|
$voteerror = UVmessage::get("VOTE_NO_VOTES");
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
$template->setKey('body' => $$body);
|
||||||
|
my $msg = $template->processTemplate($config{tpl_no_votes});
|
||||||
|
UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid) if ($config{voteack});
|
||||||
|
} elsif ($error{SuspiciousAccount}) {
|
||||||
|
$voteerror = UVmessage::get("VOTE_INVALID_ACCOUNT");
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
$template->setKey('head' => $entity->stringify_header);
|
||||||
|
$template->setKey('body' => $$body);
|
||||||
|
my $msg = $template->processTemplate($config{tpl_invalid_account});
|
||||||
|
UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid) if ($config{voteack});
|
||||||
|
} elsif ($error{InvalidAddress}) {
|
||||||
|
$voteerror = UVmessage::get("VOTE_INVALID_ADDRESS");
|
||||||
|
} elsif ($error{InvalidName}) {
|
||||||
|
$voteerror = UVmessage::get("VOTE_INVALID_REALNAME");
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
$template->setKey('head' => $entity->stringify_header);
|
||||||
|
$template->setKey('body' => $$body);
|
||||||
|
my $msg = $template->processTemplate($config{tpl_invalid_name});
|
||||||
|
UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid) if ($config{voteack});
|
||||||
|
} elsif ($error{DuplicateVote}) {
|
||||||
|
$voteerror = UVmessage::get("VOTE_DUPLICATES");
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
$template->setKey('head' => $entity->stringify_header);
|
||||||
|
$template->setKey('body' => $$body);
|
||||||
|
my $msg = $template->processTemplate($config{tpl_multiple_votes});
|
||||||
|
UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid) if ($config{voteack});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# check voter name
|
||||||
|
unless ($voter_name || $voteerror) {
|
||||||
|
$voteerror = UVmessage::get("VOTE_MISSING_NAME");
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
$template->setKey('head' => $entity->stringify_header);
|
||||||
|
$template->setKey('body' => $$body);
|
||||||
|
my $msg = $template->processTemplate($config{tpl_invalid_name});
|
||||||
|
UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid) if ($config{voteack});
|
||||||
|
}
|
||||||
|
|
||||||
|
# set mark for cancelled vote
|
||||||
|
$onevote = 2 if ($votes[0] eq 'A');
|
||||||
|
|
||||||
|
# create comment line for result file
|
||||||
|
my $comment;
|
||||||
|
if ($config{personal}) {
|
||||||
|
# Personalized Ballots: insert ballot id
|
||||||
|
$comment = "($ballot_id)";
|
||||||
|
} else {
|
||||||
|
$comment = "()";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (@set) {
|
||||||
|
$comment .= ' '.UVmessage::get("VOTE_FILE_COMMENT", (FIELDS => join(', ', @set)));
|
||||||
|
}
|
||||||
|
|
||||||
|
# write result file
|
||||||
|
print RESULT "A: $voter_addr\n";
|
||||||
|
print RESULT "N: $voter_name\n";
|
||||||
|
print RESULT "D: $h_date\n";
|
||||||
|
print RESULT "K: $comment\n";
|
||||||
|
|
||||||
|
# invalid vote?
|
||||||
|
if ($voteerror) {
|
||||||
|
print RESULT "S: ! $voteerror\n";
|
||||||
|
|
||||||
|
# cancelled vote?
|
||||||
|
} elsif ($onevote == 2) {
|
||||||
|
print RESULT "S: * Annulliert\n";
|
||||||
|
|
||||||
|
if ($config{voteack}) {
|
||||||
|
# send cancellation acknowledge
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
my $msg = $template->processTemplate($config{tpl_cancelled});
|
||||||
|
UVsendmail::mail($voter_addr, "Bestaetigung", $msg, $msgid);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
print RESULT "S: ", join ("", @votes), "\n";
|
||||||
|
|
||||||
|
# send acknowledge mail?
|
||||||
|
if ($config{voteack}) {
|
||||||
|
|
||||||
|
my $template = UVtemplate->new();
|
||||||
|
$template->setKey(ballotid => $ballot_id);
|
||||||
|
$template->setKey(address => $voter_addr);
|
||||||
|
$template->setKey(name => $voter_name);
|
||||||
|
|
||||||
|
for (my $n=0; $n<@groups; $n++) {
|
||||||
|
my $vote = $votes[$n];
|
||||||
|
$vote =~ s/^J$/JA/;
|
||||||
|
$vote =~ s/^N$/NEIN/;
|
||||||
|
$vote =~ s/^E$/ENTHALTUNG/;
|
||||||
|
$template->addListItem('groups', pos=>$n+1, vote=>$vote, group=>$groups[$n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
my $msg = $template->processTemplate($config{'tpl_ack_mail'});
|
||||||
|
UVsendmail::mail($voter_addr, "Bestaetigung", $msg, $msgid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Send out acknowledge mails and tidy up (we're called as "uvvote.pl clean") #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub make_clean {
|
||||||
|
|
||||||
|
# send mails
|
||||||
|
UVsendmail::send();
|
||||||
|
|
||||||
|
print UVmessage::get("INFO_TIDY_UP"), "\n";
|
||||||
|
|
||||||
|
# search unprocessed files
|
||||||
|
opendir (DIR, $config{tmpdir});
|
||||||
|
my @files = readdir DIR;
|
||||||
|
closedir (DIR);
|
||||||
|
|
||||||
|
my @resultfiles = grep (/^ergebnis-/, @files);
|
||||||
|
my @votefiles = grep (/^stimmen-/, @files);
|
||||||
|
|
||||||
|
unless (@resultfiles) {
|
||||||
|
print wrap('', '', UVmessage::get("VOTE_NO_NEW_RESULTS")), "\n\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $thisresult (@resultfiles) {
|
||||||
|
chmod (0400, "$config{tmpdir}/$thisresult");
|
||||||
|
rename "$config{tmpdir}/$thisresult", "$config{archivedir}/$thisresult"
|
||||||
|
or die UVmessage::get("VOTE_MOVE_RESULTFILE", (FILE=>$thisresult)) . "$!\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $thisvotes (@votefiles) {
|
||||||
|
chmod (0400, "$config{tmpdir}/$thisvotes");
|
||||||
|
rename "$config{tmpdir}/$thisvotes", "$config{archivedir}/$thisvotes"
|
||||||
|
or die UVmessage::get("VOTE_MOVE_VOTEFILE", (FILE=>$thisvotes)) . "$!\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
print UVmessage::get("VOTE_CREATING_RESULTS", (FILENAME=>$config{resultfile})), "\n";
|
||||||
|
|
||||||
|
# search all result files
|
||||||
|
opendir (DIR, "$config{archivedir}/");
|
||||||
|
@files = grep (/^ergebnis-/, readdir (DIR));
|
||||||
|
closedir (DIR);
|
||||||
|
|
||||||
|
# Create complete result from all single result files.
|
||||||
|
# The resulting file (ergebnis.alle) is overwritten as there could have been
|
||||||
|
# made changes in the single result files
|
||||||
|
open(RESULT, ">$config{resultfile}");
|
||||||
|
foreach my $file (sort @files) {
|
||||||
|
open(THISRESULT, "<$config{archivedir}/$file");
|
||||||
|
print RESULT join('', <THISRESULT>);
|
||||||
|
close(THISRESULT);
|
||||||
|
}
|
||||||
|
close(RESULT);
|
||||||
|
|
||||||
|
print "\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Print help text (options and syntax) on -h or --help #
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
sub help {
|
||||||
|
print <<EOF;
|
||||||
|
Usage: uvvote.pl [-c config_file] [-t]
|
||||||
|
uvvote.pl [-c config_file] clean
|
||||||
|
uvvote.pl -h
|
||||||
|
|
||||||
|
Liest Mailboxen aus einer Datei oder per POP3 ein wertet die Mails
|
||||||
|
als Stimmzettel aus. Erst beim Aufruf mit der Option "clean" werden
|
||||||
|
die Ergebnisse endgueltig gespeichert und die Bestaetigungsmails
|
||||||
|
verschickt.
|
||||||
|
|
||||||
|
-c config_file liest die Konfiguration aus config_file
|
||||||
|
(usevote.cfg falls nicht angegeben)
|
||||||
|
|
||||||
|
-t, --test fuehrt einen Test der Konfiguration durch und
|
||||||
|
gibt das ermittelte Ergebnis aus.
|
||||||
|
|
||||||
|
-h, --help zeigt diesen Hilfetext an
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
}
|
Loading…
Reference in a new issue