HE:Telefonkonferenz

Aus Piratenwiki
Wechseln zu: Navigation, Suche

Hinweise zu Telefonkonferenzen des LV Hessen

Einleitung

Der Landesverband Hessen betreibt einen eigenen Server mit der Software Asterisk für Telefonkonferenzen. Diese WIKI-Seite soll Hinweise zur Bedienung und Einblick in die Konfiguration geben

Verhalten im Telefonkonferenzraum

Es ist üblich und erwünscht, dass man sich nach betreten des Telefonkonferenzraumes mit der Tastenkombination *1 stumm-schaltet. Wenn ihr stumm-geschaltet seid, kann euch niemand der Telnehmer hören. Das wird deshalb gemacht, damit die anderen Teilnehmer nicht durch Stör- oder Hintergrundgeräusche genervt werden. Ihr könnt euch jederzeit, wenn ihr einen Redebeitrag bringen wollt, mit der Tastenkombination *1 wieder laut schalten und etwas sagen.

Wenn ihr euch mit Mumble einwählt entfällt das. In dem Fall wird aber gebeten, dass ihr die Push-to-Talk-Funktion benutzt - also einstellt, dass ihr nur zu hören seit, wenn ihr eine bestimmte Taste drückt.

Zu Beginn wird ein Moderator ernannt. Generell hat erstmal nur der Moderator rederecht während der Telefonkonferenz. Alle anderen schalten sich bitte standardmäßig mit *1 stumm! Wenn ihr etwas sagen wollt, tut ihr das irgendwie in dem Pad-Chat kund; am besten indem ihr "WM" (= Wortmeldung) schreibt. Der Moderator erteilt euch dann das wort, ihr schaltet euch mit *1 wieder laut, macht euren Redebeitrag und schaltet euch dannach wieder mit *1 stumm.

Auf diese Weise hat man einen geordneten Ablauf, weiß immer, wer gerade redet und kann ggf. parallel im Pad arbeiten.

Einwahl

Die Telefonkonferenzen sind über eine Festnetznummer und mit einem SIP-Client direkt über eine SIP-URL erreichbar:

... mit einem Telefon

  • Festnetz Deutschland: +49 (0) 69 175 36 743 (Sipgate.de)
  • Festnetz Schweiz: +41 (0) 31 5110514 (PhoneStar*)
  • Festnetz Österreich: +43 (0) 720 512348 (Sipcall) oder +43 (0) 720 985395 (Sipgate.at)
  • Festnetz Luxemburg: +352 203 330 004 638 (MIXvoip)
  • Festnetz USA: +1 253-753-1915 (IPKall) Muss aber regelmässig genutzt werden, sonst wird der Account gelöscht

... mit einem SIP-Client

Achtung: Wer einen SIP-Client hinter einem Router mit NAT einsetzt muß vermutlich auch einen STUN-Server mit angeben. Ein öffentlich erreichbarer STUN-Server ist z.B. stun.sipgate.net:1000

Nach der Ansage muß man die Raumnummer gefolgt von der "#" eingeben. Administratoren können auch die Raumnummer gefolgt von der Administrator-PIN und dann der "#" verwenden. Damit können diese den Konferenzraum schließen und wieder öffnen.

Zur Kontrolle wird dann die eingegebene Raumnummer nochmals angesagt und im Erfolgsfall die Anzahl bisheriger Teilnehmer angegeben. So lange nur ein Teilnehmer in der Konferenz ist wird Musik von David Rovics gespielt: http://www.davidrovics.com Die Musik steht unter der Lizenz CC-BY-NC-SA http://creativecommons.org/licenses/by-nc-sa/3.0/

Innerhalb der Konferenz kann man mit der *-Taste ein Menü abrufen. Die Menübefehle sind im Einzelnen:

  • *1 schaltet das eigenen Mikrofon stumm oder wieder aktiv
  • *4444448 stellt den eigenen Lautsprecher leiser
  • *6666668 stellt den eigenen Lautsprecher lauter
  • *7777778 dämpft das eigene Mikrofon
  • *9999998 verstärkt das eigene Mikrofon

Wenn man aktuell nicht sprechen möchte sollte man Rücksicht auf andere Konferenzteilnehmer nehmen und sich mit * 1 stumm schalten (insbesondere wenn man viele Nebengeräusche hat). Wenn man dann sprechen möchte kann man sich mit einem erneuten * 1 wieder freischalten.

Administratoren haben zusätzlich folgende Optionen:

  • *2 schliesst den Konferenzraum oder öffnet ihn wieder
  • *3 wirft den zuletzt eingewählen Teilnehmer aus der Konferenz

Über das Webinterface kann der Administrator einen Livestream aktivieren. Dieser ist dann abrufbar unter http://sip.piratenpartei-hessen.de:8000/raum####.ogg (#### muss durch die Raumnummer ersetzt werden)

Howto für OSX

  1. X-Lite runterladen von: http://www.counterpath.com/x-lite-5-for-mac-download.html
  2. Starten und nerviges Werbevideo überleben
  3. Preferences öffnen
  4. Accounts öffnen
  5. Name: Piratenpartei (oder was immer du passend findest)
  6. Domain: sip.piratenpartei-hessen.de
  7. Display Name: <dein Name oder Nick>
  8. "Register with domain and receive calls" ausschalten
  9. Nach "Topology" wechseln
  10. auto-detect auswählen
  11. server: stun.sipgate.net
  12. Rest so lassen
  13. Preferences schließen
  14. ggf. nag-Window wegklicken
  15. oben das Lautsprechersymbol (5. Symbol von rechts) aktivieren
  16. 500 wählen
  17. <Raumnummer> + # eintippen (nicht wählen, einfach tippen ohne vorher irgendwo hinzuklicken nach dem wählen)
  18. win!


Einstellungen SIP-Client (jedes Betriebssystem)

  1. SIP-Client deiner Wahl herunterladen
  2. Es ist kein Account bei einem VoIP-Anbieter erforderlich
  3. In der Konfiguration bei Provider und bei Domain sip.piratenpartei-hessen.de eingeben
  4. kein Anmeldename und kein Passwort
  5. Anzeigename nach Wunsch
  6. stun-server: stun.sipgate.net
  7. 500 wählen
  8. <Raumnummer> + # eintippen
  9. getestet z.B. mit Phoner lite unter Windows 7

Raumnummern

Folgende Konferenzräume sind derzeit vorgesehen:

  • 1000# Vorstandssitzungen LV Hessen
  • 1001# AK Basisdemokratie
  • 1002# Brückenraum zum NRW Mumble
  • 1003# AG Web
  • 1004# Hessen AGs, PGs
  • 1005# Presse-AG
  • 1006# ? AK Soziales Hessen ?
  • 1010# Schiedsgericht LV Hessen (nur mit PIN zugänglich)
  • 1011# Schiedsgericht LV HE
  • 1012# unbelegt ??
  • 1020# Landesgeschäftsstelle
  • 1510# Kreisverband Frankfurt
  • 1511# ELF Piraten Fraktion Frankfurt
  • 1520# Kreisverband Kassel
  • 1530# Kreisverband Wetterau
  • 1540# Vorstandssitzungen KV Schwalm-Eder
  • 1550# KV Bergstrasse
  • 1551# ??
  • 1560# KV Offenbach-Land
  • 1570# KV Main-Kinzig
  • 1575# KV Main-Kinzig Kreistagspiraten
  • 1580# KV Wiesbaden (Basis)
  • 1581# KV Wiesbaden Fraktion
  • 1590# KV Marburg-Biedenkopf
  • 1600# KV Hochtaunus
  • 1610# KV Gießen
  • 1620# KV Groß-Gerau
  • 1630# KV Main-Taunus-Kreis
  • 1640# KV Odenwald
  • 1650# KV Darmstadt/Darmstadt-Dieburg
  • 2000# BW Vorstandskonferenz
  • 2101# LV RLP KV Rhein-Pfalz
  • 2200# LV Bayern Vorstandssitzungen
  • 2201# BzV Mittelfranken
  • 2202# BzV Oberbayern
  • 2203# BzV Schwaben
  • 2204# BzV Unterfranken
  • 2205# BzV Niederbayern
  • 2206# BzV Oberpfalz
  • 2207# BzV Oberfranken
  • 2210# AG Werbemittel Bayern
  • 2211# KV Erlangen
  • 2220# FG Bildung LV Bayern
  • 2221# FG Gesundheit LV Bayern
  • 2222# KV Ingolstadt
  • 2299# LV Bayern Landesvorstand
  • 2300# Nordpiraten
  • 2301# LaVo Niedersachsen
  • 2302# KV Osnabrück
  • 2303# Veranstaltungsbeauftragte / AG Event
  • 2304# Ratsfraktion Braunschweig
  • 2305# LSG Niedersachsen
  • 2306# RV Hannover
  • 2307# Presse LV Niedersachsen
  • 2308# KV Diepholz
  • 2309# SG Wahlen NDS
  • 2310# KV Celle
  • 2311# RV Ostfriesland
  • 2400# LV Sachsen Vorstandssitzung
  • 2410# KV Chemnitz
  • 2411# LSG Sachsen (nur mit PIN zugänglich)
  • 2500# LV RLP Vorstandssitzung
  • 2600# LV SH Vorstandssitzung
  • 2650# SH Fraktion
  • 2700# LV Brandenburg Vorstandssitzung
  • 2800# LV Thüringen
  • 3000# JuPis
  • 8000# PPI
       PPI Vorstand: Jeden Dienstag 21h
       Präsidium PPLU: Jeden zweiten Mittwoch beginnend 13.10.2010 um 20:00
  • 8001# Court of Arbitration (nur per PIN zugänglich)
  • 8002# Court of Arbitration
  • 8100# Piraten ohne Grenzen
  • 8200# ACTA
  • 8300# PP-LU
  • 8500# Piratenradio
  • 9001# BundesAGs
       AG Energiepolitik: Dienstags 19:00 - 24:00 Uhr
  • 9002# BundesIT (Admindaten bei der IT)
       Telko: Montags 21:00 - 24:00 

Datenschutzhinweise

Im Konfigurationsmenü zum Sipgate-Account sind die Anruferlisten deaktiviert. Bei Sipcall, MIXvoip und bei Phonestar lässt sich die Anrufprotokollierung leider nicht abschalten. Bei SIPBroker ist der Status derzeit nicht bekannt.

Durch Nutzung der SIP-URL umgeht man jegliche Speicherung des Anrufs bei Providern.

Der Server des Landesverbandes selbst erstellt keine Protokolldateien über die Anrufe. Im RAM werden von Asterisk jedoch folgende Daten vorgehalten und können während der Konferenz durch Administratoren abgerufen werden:

  • Rufnummer des Teilnehmers, sofern diese vom Anrufer übermittelt wird
  • Name des Anschlusses des Teilnehmers, sofern dieser vom Anrufer übermittelt wird (meistens ist dies gleich der Rufnummer, insbesondere bei Internettelefonie kann der Name aber ggf. abweichen)
  • IP-Adresse des SIP-Clients (bei Zugang über die Sipgate-Telefonnummer ist dies die Adresse von Sipgate, bei Zugang über die SIP-URL ist dies die IP-Adresse des Anrufers)
  • ob der Teilnehmer gerade spricht, ruhig ist oder stummgeschaltet ist
  • die Dauer, die der Teilnehmer aktuell in der Konferenz ist

Bei Aufruf des Web-Administrationsinterfaces werden folgende Daten gespeichert:

  • Datum und Uhrzeit
  • aufgerufene Seite
  • Status und Größe der Seite
  • Referer (sofern vom Browser übermittelt)
  • Browser-Identifikation (sofern vom Browser übermittelt)

Die IP-Adresse wird explizit nicht gespeichert.

Konfigurationsdateien Asterisk

Die Informationen in diesem und folgenden Abschnitten sind nur von Interesse, falls Du einen eigenen Telefonkonferenzserver betreiben willst.

asterisk.conf

[directories]
astetcdir => /opt/asterisk/etc/asterisk
astmoddir => /opt/asterisk/lib/asterisk/modules
astvarlibdir => /opt/asterisk/var/lib/asterisk
astdbdir => /opt/asterisk/var/lib/asterisk
astkeydir => /opt/asterisk/var/lib/asterisk
astdatadir => /opt/asterisk/var/lib/asterisk
astagidir => /opt/asterisk/var/lib/asterisk/agi-bin
astspooldir => /opt/asterisk/var/spool/asterisk
astrundir => /opt/asterisk/var/run
astlogdir => /opt/asterisk/var/log/asterisk

[options]
internal_timing = yes

extensions.conf

[globals]
Ortsnetz=69
Landnetz=49

[meet]
exten => _X.,1,Answer()
exten => _X.,n,Wait(1)
exten => _X.,n(anfang),Read(CONFNO,conf-getconfno)
exten => _X.,n,SayNumber(${CONFNO:0:4})
exten => _X.,n,GotoIf($[${LEN(${CONFNO})} < 4]?invalid)
exten => _X.,n,GotoIf($[${LEN(${CONFNO})} > 4]?pin)
exten => _X.,n,MeetMe(${CONFNO},cTsM,0)
exten => _X.,n,Goto(ende)
exten => _X.,n(pin),MeetMe(${CONFNO:0:4},cTsM,${CONFNO:4})
exten => _X.,n(ende),Hangup()
exten => _X.,n(invalid),Playback(conf-invalid)
exten => _X.,n,Goto(anfang)

[default]
exten => _X.,1,Set(CHANNEL(language)=de)
exten => _X.,n,Goto(intern,${EXTEN},1)

[de-in]
exten => _X.,1,Set(CHANNEL(language)=de)
exten => _X.,n,Goto(meet,${EXTEN},1)

[en-in]
exten => _X.,1,Set(CHANNEL(language)=en)
exten => _X.,n,Goto(meet,${EXTEN},1)

[intern]
exten => 500,1,Set(CHANNEL(language)=de)
exten => 500,n,Goto(meet,${EXTEN},1)
exten => 501,1,Set(CHANNEL(language)=en)
exten => 501,n,Goto(meet,${EXTEN},1)
exten => 502,1,Set(CHANNEL(language)=fr)
exten => 502,n,Goto(meet,${EXTEN},1)
exten => 503,1,Set(CHANNEL(language)=es)
exten => 503,n,Goto(meet,${EXTEN},1)
exten => 504,1,Set(CHANNEL(language)=it)
exten => 504,n,Goto(meet,${EXTEN},1)
exten => 505,1,Set(CHANNEL(language)=se)
exten => 505,n,Goto(meet,${EXTEN},1)
exten => 506,1,Set(CHANNEL(language)=ru)
exten => 506,n,Goto(meet,${EXTEN},1)
exten => _81XXXX,1,Answer()
exten => _81XXXX,n,Wait(1)
exten => _81XXXX,n,MeetMe(${EXTEN:2:4},m,0)
exten => _81XXXX,n,HangUp()
exten => _82XXXX,1,Answer()
exten => _82XXXX,n,Wait(1)
exten => _82XXXX,n,MeetMe(${EXTEN:2:4},T,0)
exten => _82XXXX,n,HangUp()
exten => 998,1,Answer()
exten => 998,n,Wait(1)
exten => 998,n,SayUnixTime()
exten => 998,n,Hangup()
exten => 999,1,Answer()
exten => 999,n,Echo()
exten => 999,n,Hangup()

meetme.conf

Die Administrator-PINs sind unkenntlich gemacht

[rooms]
conf => 1000,0,*pin*
conf => 1001,0,*pin*
conf => 1002,0,*pin*
conf => 1003,0,*pin*
conf => 1004,0,*pin*
conf => 1005,0,*pin*
conf => 1010,*pin*,*pin*
conf => 1510,0,*pin*
conf => 1520,0,*pin*
conf => 1530,0,*pin*
conf => 1540,0,*pin*
conf => 1550,0,*pin*
conf => 1560,0,*pin*
conf => 1570,0,*pin*
conf => 2000,0,*pin*
conf => 2101,0,*pin*
conf => 2200,0,*pin*
conf => 2201,0,*pin*
conf => 2202,0,*pin*
conf => 2203,0,*pin*
conf => 2210,0,*pin*
conf => 2300,0,*pin*
conf => 2301,0,*pin*
conf => 2400,0,*pin*
conf => 2500,0,*pin*
conf => 2600,0,*pin*
conf => 3000,0,*pin*
conf => 8000,0,*pin*
conf => 8100,0,*pin*
conf => 8200,0,*pin*
conf => 8500,0,*pin*
conf => 9001,0,*pin*
conf => 9002,0,*pin*
conf => 9003,0,*pin*
conf => 9004,0,*pin*
conf => 9005,0,*pin*
conf => 9006,0,*pin*
conf => 9007,0,*pin*
conf => 9008,0,*pin*
conf => 9009,0,*pin*
conf => 9010,0,*pin*
conf => 9011,0,*pin*
conf => 9012,0,*pin*
conf => 9324,0,*pin*
conf => 9500,0,*pin*
conf => 9600,0,*pin*
conf => 9610,0,*pin*
conf => 9999,0,*pin*

modules.conf

[modules]
autoload = yes
preload = chan_sip

musiconhold.conf

[default]
mode=files
directory=/opt/asterisk/var/lib/asterisk/moh
random=yes

sip.conf

Username und Passwort bei Sipgate sind unkenntlich gemacht

[general]
context=default
srvlookup=yes
allowguest=yes
alwaysauthreject=no
tos_sip=cs3
tos_audio=ef
tos_video=af41
language=de
maxexpirey=240
defaultexpirey=240
rtptimeout=900
rtpholdtimeout=1800
useragent=Useragent
register => *username*:*passwort*@sipgate.de/*username*
register => *username*:*passwort*@ps1.voipgateway.org/*username*
register => *username*:*passwort*@free1.voipgateway.org/*username*
register => *username*:*passwort*@sipregister.mixvoip.com/00352203330004638

[sipgate]
type=friend
qualify=yes
host=sipgate.de
nat=no
insecure=invite,port
canreinvite=yes
username=*username*
fromuser=*username*
fromdomain=sipgate.de
secret=*passwort*
context=de-in

[voipgateway-at]
type=friend
qualify=yes
secret=*passwort*
username=*username*
host=free1.voipgateway.org
nat=no
insecure=invite,port
canreinvite=no
fromuser=*username*
fromdomain=free1.voipgateway.org
context=de-in

[voipgateway-ch]
type=friend
qualify=yes
secret=*passwort*
username=*username*
host=ps1.voipgateway.org
nat=no
insecure=very
canreinvite=no
fromuser=*username*
fromdomain=ps1.voipgateway.org
context=de-in

[mixvoip]
type=friend
qualify=yes
host=sipregister.mixvoip.com
nat=no
insecure=invite,port
canreinvite=yes
username=*username*
fromuser=00352203330004638
fromdomain=sipregister.mixvoip.com
secret=*passwort*
context=en-in

Administrationsinterface

Für die Administration einer Konferenz gibt es ein kleines Web-Formular, welches mittels eines Bash CGI-Scriptes und eines Wrapper-Programmes für das CLI von Asterisk zur Verfügung gestellt wird:

meetmeadmin.cgi

#! /bin/bash

# Dieses Shell-Script stellt ein Webformular zur Administration einer
# Telefonkonferenz in Asterisk zur Verfügung. Der Aufruf des CLI von
# Asterisk erfolgt über ein Wrapper-Programm meetmeadmin, welches mittels
# Set-UID- / Set-GID-Bit den Zugriff auf die Asterisk-Konfiguration
# und den Socket zur Steuerung erhalten muss
# Author: Lothar Krauß (mailto: pirat@lkrauss.de)
# Lizenz: CC-BY


ADMINBIN=/opt/asterisk/sbin/meetmeadmin

p_loginform()
{
  echo '<FORM Method="POST" Action="meetmeadmin.cgi">'
  echo 'Raumnummer: <INPUT Type="TEXT" Name="raum" size=4 Value="'$RAUM'">'
  echo 'PIN: <INPUT Type="PASSWORD" Name="pin" size=8 Value="'$PIN'">'
  echo '<INPUT Type="SUBMIT" Name="aktion" Value="Einloggen">'
  echo '</FORM>'
}

p_buttons()
{
  echo '<TR><TD>'
  echo '<INPUT Type="SUBMIT" Name="aktion" Value="Schliessen">'
  echo '<INPUT Type="SUBMIT" Name="aktion" Value="Öffnen">'
  echo '</TD><TD align="right">Teilnehmer:'
  echo '<INPUT Type="SUBMIT" Name="aktion" Value="Stumm">'
  echo '<INPUT Type="SUBMIT" Name="aktion" Value="Sprechen">'
  echo '<INPUT Type="SUBMIT" Name="aktion" Value="Ausschliessen">'
  echo '</TD></TR>'
}

p_endhtml()
{
  echo '</body>'
  echo '</html>'
}

DATEN=""
RAUM=""
PIN=""
AKTION=""
SAMMEL=""
CLOSE=""
STATUS=""
STREAM=""
RECORD=""

if [ "$REQUEST_METHOD" = "POST" ]
then
  DATEN=`/bin/cat | /bin/sed -e 's,[^0-9a-zA-Z&=],,g' -e 's,&, ,g'`
  for x in $DATEN
  do
    feld=${x%=*}
    wert=${x#*=}
    case $feld in
      raum)
        RAUM="$wert"
        ;;
      pin)
        PIN="$wert"
        ;;
      close)
        CLOSE="$wert"
        ;;
      aktion)
        AKTION="$wert"
        ;;
      mark)
        SAMMEL="$SAMMEL $wert"
        ;;
    esac
  done
fi

if [ "$AKTION" = "Download" -a -r /opt/asterisk/var/spool/asterisk/monitor/raum$RAUM.gsm ]
then
  $ADMINBIN test $RAUM $PIN
  if [ "$?" = "0" ]
  then
    echo "Content-type: application/octed-stream"
    echo "Content-disposition: filename=raum$RAUM.ogg"
    echo ""
    sox /opt/asterisk/var/spool/asterisk/monitor/raum$RAUM.gsm -t ogg -
    exit 0
  fi
fi

/bin/cat <<ende1
Content-type: text/html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
  <title>Piratenpartei Hessen - Administration Telefonkonferenz</title>
  <meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
</head>
<body>
ende1

if [ "$AKTION" = "Ausloggen" ]
then
  RAUM=""
  PIN=""
fi

if [ "$RAUM" = "" -o "$PIN" = "" ]
then
  p_loginform
  p_endhtml
  exit 0
fi

if [ "$AKTION" = "Einloggen" ]
then
  $ADMINBIN test $RAUM $PIN
  if [ "$?" != "0" ]
  then
    sleep 5
    p_loginform
    echo '<h3>Fehler beim Einloggen</h3>'
    p_endhtml
    exit 0
  fi
fi

if [ "$AKTION" = "D6ffnen" ]
then
  $ADMINBIN unlock $RAUM $PIN
  if [ "$?" != "0" ]
  then
    p_loginform
    echo '<h3>Fehler beim &OUml;effnen</h3>'
    p_endhtml
    exit 0
  fi
  CLOSE=0
elif [ "$AKTION" = "Schliessen" ]
then
  $ADMINBIN lock $RAUM $PIN
  if [ "$?" != "0" ]
  then
    p_loginform
    echo '<h3>Fehler beim Schiessen</h3>'
    p_endhtml
    exit 0
  fi
  CLOSE=1
elif [ "$AKTION" = "Stream" ]
then
  x=`ps -fu asterisk | grep /opt/asterisk/ices/raum$RAUM.xml`
  if [ "$x" != "" ]
  then
    STATUS="Stream läuft bereits"
  else
    $ADMINBIN stream $RAUM $PIN
    if [ "$?" != "0" ]
    then
      p_loginform
      echo '<h3>Fehler beim Stream Starten</h3>'
      p_endhtml
      exit 0
    fi
    sleep 3
  fi
elif [ "$AKTION" = "Record" ]
then
  x=`$ADMINBIN list $RAUM $PIN|grep '!0!Record!Local/81'`
  if [ "$x" != "" ]
  then
    STATUS="Aufzeichnung läuft bereits"
  else
    $ADMINBIN record $RAUM $PIN
    if [ "$?" != "0" ]
    then
      p_loginform
      echo '<h3>Fehler beim Aufzeichnung Starten</h3>'
      p_endhtml
      exit 0
    fi
    sleep 3
  fi
elif [ "$AKTION" = "Delete" ]
then
  $ADMINBIN delrecord $RAUM $PIN
  if [ "$?" != "0" ]
  then
      p_loginform
      echo '<h3>Fehler beim Löschen der Aufzeichnung</h3>'
      p_endhtml
      exit 0
  fi
elif [ "$AKTION" = "Stumm" ]
then
  if [ "$SAMMEL" = "" ]
  then
     STATUS="Bitte mindestens einen Teilnehmer markieren"
  else
     $ADMINBIN mute $RAUM $PIN $SAMMEL
     if [ "$?" != "0" ]
     then
       p_loginform
       echo '<h3>Fehler beim Stummschalten</h3>'
       p_endhtml
       exit 0
     fi
  fi
elif [ "$AKTION" = "Sprechen" ]
then
  if [ "$SAMMEL" = "" ]
  then
     STATUS="Bitte mindestens einen Teilnehmer markieren"
  else
     $ADMINBIN unmute $RAUM $PIN $SAMMEL
     if [ "$?" != "0" ]
     then
       p_loginform
       echo '<h3>Fehler beim Freischalten</h3>'
       p_endhtml
       exit 0
     fi
  fi
elif [ "$AKTION" = "Ausschliessen" ]
then
  if [ "$SAMMEL" = "" ]
  then
     STATUS="Bitte mindestens einen Teilnehmer markieren"
  else
     $ADMINBIN kick $RAUM $PIN $SAMMEL
     if [ "$?" != "0" ]
     then
       p_loginform
       echo '<h3>Fehler beim Ausschliessen</h3>'
       p_endhtml
       exit 0
     fi
     sleep 3
  fi
fi

if [ "$STATUS" = "" ]
then
  if [ "$CLOSE" = "0" ]
  then
     STATUS="Raum ist geöffnet"
  elif [ "$CLOSE" = "1" ]
  then
     STATUS="Raum ist geschlossen"
  else
     STATUS=" "
  fi
fi

echo '<FORM Method="POST" Action="meetmeadmin.cgi">'
echo '<INPUT Type="HIDDEN" Name="raum" Value='"$RAUM"'>'
echo '<INPUT Type="HIDDEN" Name="pin" Value='"$PIN"'>'
echo '<INPUT Type="HIDDEN" Name="close" Value='"$CLOSE"'>'
echo '<TABLE><TR>'
echo '<TD>Raumnummer: '$RAUM' &nbsp'
echo '<INPUT Type="SUBMIT" Name="aktion" Value="Ausloggen">'
echo '</TD><TD align="right">'
echo '<INPUT Type="SUBMIT" Name="aktion" Value="Aktualisieren">'
echo '</TD></TR>'

echo '<TR><TD colspan="2">'
echo '<hr><h3>'$STATUS'</h3><hr>'
echo '</TD></TR>'

x=`ps -fu asterisk | grep /opt/asterisk/ices/raum$RAUM.xml`
if [ "$x" = "" ]
then
  STREAM=0
else
  STREAM=1
fi
x=`$ADMINBIN list $RAUM $PIN|grep '!0!Record!Local/81'`
if [ "$x" = "" ]
then
  if [ -r /opt/asterisk/var/spool/asterisk/monitor/raum$RAUM.gsm ]
  then
    RECORD=9
  else
    RECORD=0
  fi
else
  RECORD=1
fi

echo '<TR><TD colspan="2">'
if [ "$STREAM" = "0" ]
then
  echo '<INPUT Type="SUBMIT" Name="aktion" Value="Stream">'
fi
if [ "$RECORD" = "0" ]
then
  echo '<INPUT Type="SUBMIT" Name="aktion" Value="Record">'
elif  [ "$RECORD" = "9" ]
then
  echo '<INPUT Type="SUBMIT" Name="aktion" Value="Download">'
  echo '<INPUT Type="SUBMIT" Name="aktion" Value="Delete">'
fi
echo '</TD></TR>'
p_buttons
echo '<TR><TD colspan="2">'

echo '<TABLE border="3" cellpadding="5">'
echo '<tr><th>Lfd.</th><th>Nummer</th><th>Name</th><th>Kanal</th>'
echo '<th>Dauer</th><th>Status</th>'
echo '<td><INPUT type="CHECKBOX" name="mark" Value="all"></td></tr>'
$ADMINBIN list $RAUM $PIN|/usr/bin/awk -F '!' '{
   if ($5 == "1")
   {
     printf("<tr bgcolor=\"#ff0000\">");
   }
   else
   {
     printf("<tr>");
   }
   printf("<td align=\"right\">%s</td>",$1);
   printf("<td>%s</td>",$2);
   printf("<td>%s</td>",$3);
   printf("<td>%s</td>",$4);
   printf("<td>%s</td>",$9);
   if      ($7 == "1")  { printf("<td>stumm</td>"); }
   else if ($8 == "1")  { printf("<td bgcolor=\"#ff0000\">spricht</td>"); }
   else if ($8 == "-1") { printf("<td>unbekannt</td>"); }
   else                 { printf("<td bgcolor=\"#00ff00\">bereit</td>"); }
   printf("<td><INPUT type=\"CHECKBOX\" name=\"mark\" Value=\"%s\"></td>",$1);

   printf("</tr>\n");
}'
echo '</TABLE>'

echo '</TD></TR>'
p_buttons

echo '</TABLE>'
echo '</FORM>'

p_endhtml
exit 0

meetmeadmin.c

Dieses Programm muss mittels SUID/SGID-Bit

  • Leserechte auf /opt/asterisk/etc/asterisk/meetme.conf
  • Schreibrechte auf /opt/asterisk/var/run/asterisk.ctl

erhalten

/* --- Dieses Programm dient dazu, das CLI von Asterisk nur für den       --- */
/* --- meete-Befehl auszuführen. Zur Authorisation wird die Admini-       --- */
/* --- strator-PIN des Konferenzraumes geprüft. Dem Programm muss mittels --- */
/* --- Set-UID- / Set-GID-Bit der Zugriff auf die Asterisk-Konfiguration  --- */
/* --- und den Socket zur Steuerung gewährt werden                        --- */
/* --- Author: Lothar Krauß (mailto: pirat@lkrauss.de)                    --- */
/* --- Lizenz: CC-BY                                                      --- */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

/* --- Konstanten zum Auffinden der Asterisk-Dateien --- */
#define ASTBIN  "/opt/asterisk/sbin/asterisk"
#define ASTMEET "/opt/asterisk/etc/asterisk/meetme.conf"
#define ASTICE  "/opt/asterisk/ices"
#define ASTOUT  "/opt/asterisk/var/spool/asterisk/outgoing"
#define ASTMON  "/opt/asterisk/var/spool/asterisk/monitor"
#define ICEPWD  "*passwort*"

/* --- Ein Buffer zum Einlesen einer Zeile --- */
char wBuf[512];

/* --- Liest eine Zeile aus f in s (max size-1 Bytes + Null-Byte) --- */
/* --- und schneidet Leerzeichen und Tabs vorne und hinten ab     --- */
/* --- Ergebnis: NULL = Fehler/Dateiende, ansonsten s             --- */
char *readTrim(char *s, int size, FILE *f)
{
  int i1,i2,j;
  if (fgets(s,size,f)==NULL) return(NULL);
  for (i1=0; strchr(" \t\r\n",s[i1])!=NULL; i1++);
  for (i2=strlen(s); i2>=i1 && strchr(" \t\r\n",s[i2-1])!=NULL; i2--);
  if (i1==0)
     j=i2;
  else
     for (j=0; i1<i2; j++,i1++) s[j]=s[i1];
  s[j]=0;
  return(s);
}

/* --- Testet, ob "pin" die korrekte Admin PIN von Raum "room" ist --- */
/* --- Ergebnis: 0 = Raum oder PIN falsch                          --- */
/* ---           1 = Raum und PIN passen zuammen                   --- */
int checkAdmin(int room, int pin)
{
  FILE *f;
  int  i1,i2,flag_found;
  int  room1,pin1;

  if ((f=fopen(ASTMEET,"r"))==NULL) return(0);

  /* --- Suche eine Zeile "[rooms]" --- */
  strcpy(wBuf,"");
  flag_found=0;
  for (flag_found=0; !flag_found && readTrim(wBuf,sizeof(wBuf),f)!=NULL; )
  {
    if (!strcmp(wBuf,"[rooms]")) flag_found=1;
  }
  if (!flag_found)
  {
    fclose(f);
    return(0);
  }

  /* --- Suche die Raumnummer, Ende spaetestens bei naechster Sektion --- */
  for (flag_found=0; !flag_found && readTrim(wBuf,sizeof(wBuf),f)!=NULL; )
  {
    /* --- Zeile lautet "conf => raum,pin1,pin2" --- */
    if (strncmp(wBuf,"conf",4)) continue;
    for (i1=4; wBuf[i1]==' ' || wBuf[i1]=='\t'; i1++);
    if (strncmp(wBuf+i1,"=>",2))  continue;
    for (i1+=2; wBuf[i1]==' '||wBuf[i1]=='\t'; i1++);

    /* --- Lese Raumnummer --- */
    for (room1=0; isdigit(wBuf[i1]); i1++) room1=10*room1+(int)(wBuf[i1]-'0');
    if (room1!=room) continue;

    /* --- Ueberspringe "," --- */
    for (; wBuf[i1]==' '||wBuf[i1]=='\t'; i1++);
    if (wBuf[i1]!=',') continue;
    for (i1++ ; wBuf[i1]==' '||wBuf[i1]=='\t'; i1++);

    /* --- Ueberspringe User-PIN --- */
    for (; isdigit(wBuf[i1]); i1++);

    /* --- Ueberspringe "," --- */
    for (; wBuf[i1]==' '||wBuf[i1]=='\t'; i1++);
    if (wBuf[i1]!=',') continue;
    for (i1++ ; wBuf[i1]==' '||wBuf[i1]=='\t'; i1++);

    /* --- Lese Admin-PIN --- */
    for (pin1=0; isdigit(wBuf[i1]); i1++) pin1=10*pin1+(int)(wBuf[i1]-'0');
    flag_found=1;
  }

  if (!flag_found)
  {
    fclose(f);
    return(0);
  }

  fclose(f);

  if (pin!=pin1) return(0);
  return(1);
}

void showHelp()
{
  printf("Aufruf: meetmeadmin Befehl Raumnr PIN [Usernr] [Usernr]...\n");
  printf("Befehl: list     Listet die Teilnehmer der Konferenz\n");
  printf("Befehl: lock     Schliesst die Konferenz\n");
  printf("Befehl: unlock   Oeffnet die Konferenz wieder\n");
  printf("Befehl: mute     Schaltet die angegebenen Teilnehmer stumm\n");
  printf("Befehl: unmute   Schaltet die angegebenen Teilnehmer wieder frei\n");
  printf("Befehl: kick     Wirft die angegebenen Teilnehmer aus der Konferenz\n");
  printf("Befehl: stream   Startet einen Icecast Stream\n");
  printf("Befehl: test     Keine Ausgabe, Testet nur Gueltigkeit von Raum und PIN\n");
  printf("Returncode: 0=Erfolg, 1=Fehler\n");
}

/* --- Fuehrt einen Befehl aus (User darf NULL sein) --- */
void Cmd(char *sCmd, char *sRoom, char *sUser)
{
  int i,s;

  /* --- Plausi-Checks --- */
  if (sCmd==NULL||sRoom==NULL) return;
  i=7+strlen(sCmd)+1+strlen(sRoom)+1;
  if (sUser!=NULL) i=i+1+strlen(sUser);
  if (i>sizeof(wBuf)) return;

  strcpy(wBuf,"meetme ");
  strcat(wBuf,sCmd);
  strcat(wBuf," ");
  strcat(wBuf,sRoom);
  if (sUser!=NULL) { strcat(wBuf," "); strcat(wBuf,sUser); }
  i=fork();
  if (i==-1) return;
  if (i>0)
  {
    execl(ASTBIN,ASTBIN,"-r","-x",wBuf,NULL);
    exit(0);
  }
  else
  {
    waitpid(i,&s,0);
  }
}

void Stream(int iRoom)
{
   FILE *f;

   /* --- ices2-Konfiguration aufbauen --- */
   sprintf(wBuf,"%s/raum%04i.xml",ASTICE,iRoom);
   if ((f=fopen(wBuf,"w"))==NULL) return;
   chmod(wBuf,S_IREAD|S_IWRITE);
   fprintf(f,"<?xml version=\"1.0\"?>\n");
   fprintf(f,"<ices>\n");
   fprintf(f,"  <background>0</background>\n");
   fprintf(f,"  <logpath>/opt/asterisk/var/log/asterisk</logpath>\n");
   fprintf(f,"  <logfile>ices.log</logfile>\n");
   fprintf(f,"  <loglevel>1</loglevel>\n");
   fprintf(f,"  <consolelog>0</consolelog>\n");
   fprintf(f,"  <stream>\n");
   fprintf(f,"    <metadata>\n");
   fprintf(f,"      <name>Raum %04i</name>\n",iRoom);
   fprintf(f,"      <genre>Telefonkonferenz</genre>\n");
   fprintf(f,"      <description>Telefonkonferenz Piratenpartei Hessen Raum %04i</description>\n",iRoom);
   fprintf(f,"      <url>http://www.piratenpartei-hessen.de</url>\n");
   fprintf(f,"    </metadata>\n");
   fprintf(f,"    <input>\n");
   fprintf(f,"      <module>stdinpcm</module>\n");
   fprintf(f,"      <param name=\"rate\">8000</param>\n");
   fprintf(f,"      <param name=\"channels\">1</param>\n");
   fprintf(f,"    </input>\n");
   fprintf(f,"    <instance>\n");
   fprintf(f,"      <hostname>localhost</hostname>\n");
   fprintf(f,"      <port>8000</port>\n");
   fprintf(f,"      <password>%s</password>\n",ICEPWD);
   fprintf(f,"      <mount>/raum%04i.ogg</mount>\n",iRoom);
   fprintf(f,"      <yp>0</yp>\n");
   fprintf(f,"      <encode>\n");
   fprintf(f,"        <quality>0</quality>\n");
   fprintf(f,"        <samplerate>8000</samplerate>\n");
   fprintf(f,"        <channels>1</channels>\n");
   fprintf(f,"      </encode>\n");
   fprintf(f,"      <downmix>0</downmix>\n");
   fprintf(f,"    </instance>\n");
   fprintf(f,"  </stream>\n");
   fprintf(f,"</ices>\n");
   fclose(f);

   /* --- Asterisk Call File aufbauen --- */
   sprintf(wBuf,"%s/raum%04i.call",ASTOUT,iRoom);
   if ((f=fopen(wBuf,"w"))==NULL) return;
   fprintf(f,"Channel: LOCAL/81%04i\n",iRoom);
   fprintf(f,"MaxRetries: 1\n");
   fprintf(f,"RetryTime: 15\n");
   fprintf(f,"WaitTime: 30\n");
   fprintf(f,"Application: Ices\n");
   fprintf(f,"Data: %s/raum%04i.xml\n",ASTICE,iRoom);
   fprintf(f,"Callerid: Stream <0>\n");
   fprintf(f,"AlwaysDelete: Yes\n");
   fclose(f);
}

void DelRecord(int iRoom)
{
   sprintf(wBuf,"%s/raum%04i.gsm",ASTMON,iRoom);
   unlink(wBuf);
}

void Record(int iRoom)
{
   FILE *f;
   /* --- Asterisk Call File aufbauen --- */
   sprintf(wBuf,"%s/raum%04i.call",ASTOUT,iRoom);
   if ((f=fopen(wBuf,"w"))==NULL) return;
   fprintf(f,"Channel: LOCAL/81%04i\n",iRoom);
   fprintf(f,"MaxRetries: 1\n");
   fprintf(f,"RetryTime: 15\n");
   fprintf(f,"WaitTime: 30\n");
   fprintf(f,"Application: Record\n");
   fprintf(f,"Data: %s/raum%04i.gsm|0|18000|x\n",ASTMON,iRoom);
   fprintf(f,"Callerid: Record <0>\n");
   fprintf(f,"AlwaysDelete: Yes\n");
   fclose(f);
}

int main(int argc, char **argv)
{
  char *sCmd,*sRoom,*sPin,*sUser;
  int iRoom,iPin;
  int i,j;

  if (argc<4) { showHelp(); exit(1); }

  sCmd=argv[1];

  sRoom=argv[2];
  for (i=0; isdigit(sRoom[i]); i++);
  if (i<1 || i>4 || sRoom[i]!=0) { exit(1); }
  iRoom=atoi(sRoom);

  sPin =argv[3];
  for (i=0; isdigit(sPin[i]); i++);
  if (i<1 || i>10 || sPin[i]!=0) { exit(1); }
  iPin =atoi(sPin);

  if (iRoom<1000||iRoom>9999||iPin<1) { exit(1); }

  if (!checkAdmin(iRoom,iPin))
  {
    exit(1);
  }

  if (!strcmp(sCmd,"test")) exit(0);

  if (!strcmp(sCmd,"lock")  ||
      !strcmp(sCmd,"unlock")  )
  {
    Cmd(sCmd,sRoom,NULL);
    exit(0);
  }

  if (!strcmp(sCmd,"list"))
  {
    Cmd(sCmd,sRoom,"concise");
    exit(0);
  }

  if (!strcmp(sCmd,"mute")   ||
      !strcmp(sCmd,"unmute") ||
      !strcmp(sCmd,"kick")     )
  {
    for (j=4; j<argc; j++)
    {
      sUser=argv[j];
      if (strcmp(sUser,"all"))
      {
        for (i=0; isdigit(sUser[i]); i++);
        if (i<1 || i>4 || sUser[i]!=0) { exit(1); }
      }
      Cmd(sCmd,sRoom,sUser);
    }
    return(0);
  }

  if (!strcmp(sCmd,"stream"))
  {
    Stream(iRoom);
    exit(0);
  }

  if (!strcmp(sCmd,"record"))
  {
    Record(iRoom);
    exit(0);
  }
  if (!strcmp(sCmd,"delrecord"))
  {
    DelRecord(iRoom);
    exit(0);
  }

  showHelp();
  exit(1);
}

Installation Asterisk

Da die Konferenzfunktion "meetme" in Asterisk nur aktiviert wird, wenn beim Compilieren das Kernelmodul "DAHDI" und die dazugehörigen Tools installiert sind, wird das Asterisk-Paket aus der Source erstellt:

Vorbedingungen: Folgendes muß installiert sein:

  • Kernel-Source
  • wget
  • gcc
  • make
  • ncurses-dev
  • libssl-dev
  • doxygen

DAHDI-Kernelmodul:
Quelle: http://downloads.asterisk.org/pub/telephony/dahdi-tools/dahdi-tools-current.tar.gz

make
sodu make install

DAHDI-Tools:
Quelle: http://downloads.asterisk.org/pub/telephony/dahdi-tools/dahdi-tools-current.tar.gz

./configure --prefix=/opt/dahdi
make
sodu make install

Asterisk:
Quelle: http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-1.4-current.tar.gz
Erstellen:

./configure --prefix=/opt/asterisk --localstatedir=/opt/asterisk/var --sysconfdir=/opt/asterisk/etc --with-dahdi=/opt/dahdi
make
sodu make install
sodu make progdocs

Deutsche Sprachprompts:
Quelle: http://www.greenable.de/downloads/core-prompts-DE-greenable.tar.gz
Der Inhalt muß auf die folgende Untererzeichnisse von /opt/asterisk/var/lib/asterisk/sound/ verteilt werden:

  • de
  • de/dictate
  • de/digits
  • de/followme
  • de/letters
  • de/phonetic

Weitere Sprachprompts:
Italienisch: http://www.voip.ammdomus.it/pub/asterisk-core-sounds-it-gsm-1.4.15-mm20090405.tar.gz
Schwedisch: http://www.danielnylander.se/asterisk/asterisk-prompt-se_1.045-orig.tar.gz
Russisch: http://ivrvoice.ru/downloader/download/file/7

Anschliessend sollte noch eine Group "phone" und ein User "asterisk" angelegt werden und die Rechte auf /opt/asterisk/... so angepasst werden, dass asterisk alles lesen und auf Unterverzeichnissen von /opt/asterisk/var (ausser lib) schreiben darf. Andere User sollten zumindestens auf /opt/asterisk/etc keine Leserechte haben, da dort Zugangsdaten hinterlegt sind.

Startscripte für verschiedene Systeme sind auf dem Asterisk Source-Verzeichnis unter contrib/init.d vorhanden. Es müssen darin dann noch Anpassungen vorgenommen werden um den Prozess als User:Group asterisk:phone und auf dem Verzeichnis /opt/asterisk gestartet wird.

Abschliessend sollten noch je nach persönlicher Preferenz auf /opt/asterisk/var/lib/asterisk/moh Musikdateien im WAV-Format hinterlegt werden.