Initial commit

This commit is contained in:
Pali 2019-10-01 19:01:56 +02:00
commit 4a0f2d370b
81 changed files with 2724 additions and 0 deletions

59
admin_scripts/auto_answer.pl Executable file
View file

@ -0,0 +1,59 @@
#!/usr/bin/perl
# (c) Pali 2019, Perl license
use strict;
use warnings;
use Net::Telnet;
use Time::HiRes qw(usleep);
die "Usage: $0 host pass line 0|1\n" unless @ARGV == 4;
my $host = $ARGV[0];
my $pass = $ARGV[1];
my $line = $ARGV[2];
my $enable = $ARGV[3];
die "Line $line is not valid line number [1-6]\n" unless $line =~ /^[1-6]$/;
my $t = Net::Telnet->new(Timeout => 3, Prompt => '/[^\n]*> $/');
$t->open($host);
$t->waitfor('/Password :$/');
$t->print($pass);
$t->waitfor($t->prompt);
my $failed;
my $skip;
my $auto_answer;
for (1..10) {
if ($_ == 10) {
$failed = 1;
last;
}
($auto_answer) = map { /^auto_answer : ([0-9]+)$/ ? $1 : () } $t->cmd('show config');
if ($enable and ($auto_answer & (1 << ($line - 1)))) {
do { print "auto_answer on $host is already enabled\n"; $skip = 1 } if $_ == 1;
last;
} elsif (not $enable and not ($auto_answer & (1 << ($line - 1)))) {
do { print "auto_answer on $host is already disabled\n"; $skip = 1 } if $_ == 1;
last;
}
foreach ('open', 'key dir', 'key set', 'key set', 'key soft4', 'key set', 'key 6', 'key 8', "key $line", 'key soft1', 'key soft2', 'key set', 'close') {
$t->cmd("test $_");
usleep 200_000;
}
}
$t->print("exit");
$t->close();
if ($failed) {
warn (($enable ? "enabling" : "disabling") . " auto_answer on $host failed\n");
exit 1;
} else {
print ("auto_answer on $host is now " . ($enable ? "enabled" : "disabled") . "\n") unless $skip;
exit 0;
}

25
admin_scripts/erase_config.pl Executable file
View file

@ -0,0 +1,25 @@
#!/usr/bin/perl
# (c) Pali 2019, Perl license
use strict;
use warnings;
use Net::Telnet;
die "Usage: $0 host pass\n" unless @ARGV == 2;
my $host = $ARGV[0];
my $pass = $ARGV[1];
my $t = Net::Telnet->new(Timeout => 3, Prompt => '/[^\n]*> $/');
$t->open($host);
$t->waitfor('/Password :$/');
$t->print($pass);
$t->waitfor($t->prompt);
$t->cmd('erase protflash');
# TODO: check if erase was allowed
$t->print('exit');
$t->close();

24
admin_scripts/force_reboot.pl Executable file
View file

@ -0,0 +1,24 @@
#!/usr/bin/perl
# (c) Pali 2019, Perl license
use strict;
use warnings;
use Net::Telnet;
die "Usage: $0 host pass\n" unless @ARGV == 2;
my $host = $ARGV[0];
my $pass = $ARGV[1];
my $t = Net::Telnet->new(Timeout => 3, Prompt => '/[^\n]*> $/');
$t->open($host);
$t->waitfor('/Password :$/');
$t->print($pass);
$t->waitfor($t->prompt);
$t->print('reset');
# TODO: check if reset was allowed
$t->close();

23
admin_scripts/list_errors.pl Executable file
View file

@ -0,0 +1,23 @@
#!/usr/bin/perl
# (c) Pali 2019, Perl license
use strict;
use warnings;
use Net::Telnet;
die "Usage: $0 host pass\n" unless @ARGV == 2;
my $host = $ARGV[0];
my $pass = $ARGV[1];
my $t = Net::Telnet->new(Timeout => 3, Prompt => '/[^\n]*> $/');
$t->open($host);
$t->waitfor('/Password :$/');
$t->print($pass);
$t->waitfor($t->prompt);
print "$_\n" foreach grep !/^(?:Current Phone Status|--------------------|I100 No errors|)$/, map { /^[\x00-\x31\s]*(.*?)\s*$/s; $1 } $t->cmd('show status');
$t->print("exit");
$t->close();

View file

@ -0,0 +1,29 @@
#!/usr/bin/perl
# (c) Pali 2019, Perl license
use strict;
use warnings;
use Net::Telnet;
use Time::HiRes qw(usleep);
die "Usage: $0 host pass volume\n" unless @ARGV == 3;
my $host = $ARGV[0];
my $pass = $ARGV[1];
my $vol = $ARGV[2];
my $t = Net::Telnet->new(Timeout => 3, Prompt => '/[^\n]*> $/');
$t->open($host);
$t->waitfor('/Password :$/');
$t->print($pass);
$t->waitfor($t->prompt);
foreach ('open', ('key voldn') x 16, ('key volup') x $vol, 'close') {
$t->cmd("test $_");
usleep 200_000;
}
$t->print("exit");
$t->close();

54
admin_scripts/send_reboot.pl Executable file
View file

@ -0,0 +1,54 @@
#!/usr/bin/perl
# (c) Pali 2019, Perl license
use strict;
use warnings;
use Net::SIP;
use Net::SIP::Util qw(laddr4dst INETSOCK ip_sockaddr2parts);
use Socket;
die "Usage: $0 host line\n" unless @ARGV == 2;
my $host = $ARGV[0];
my $line = $ARGV[1];
my $ip = inet_aton($host);
die "ERROR: Cannot resolve host\n" unless defined $ip;
my $addr = inet_ntoa($ip);
my $laddr = laddr4dst($addr);
die "ERROR: No route to host\n" unless $laddr;
my $sock = INETSOCK(Proto => 'udp', LocalAddr => $laddr, LocalPort => 0);
die "ERROR: Cannot create socket: $!\n" unless $sock;
my $lport = (ip_sockaddr2parts(getsockname($sock)))[1];
my $leg = Net::SIP::Leg->new(sock => $sock);
die "ERROR: Cannot create leg: $!\n" unless $leg;
my $ua = Net::SIP::Simple->new(from => "<sip:root\@$laddr:$lport>", leg => $leg);
die "ERROR: Cannot create SIP user agent: $!\n" unless $ua;
my ($stop, $code, $text);
$ua->{endpoint}->new_request(
'NOTIFY',
{ from => $ua->{from}, to => "<sip:$line\@$host>" },
sub {
(undef, undef, undef, $code, my $packet) = @_;
(undef, $text) = $packet ? $packet->as_parts : ();
$stop = 1;
},
'',
uri => "sip:$line\@$addr",
Event => 'check-sync',
Contact => $ua->{from},
);
$ua->loop(3, \$stop);
$ua->cleanup();
die "ERROR: Timeout\n" unless $stop;
die "ERROR: Invalid response\n" unless $code and $text;
die "ERROR: SIP response: $code $text\n" unless $code eq '200';

33
admin_scripts/volume_up.pl Executable file
View file

@ -0,0 +1,33 @@
#!/usr/bin/perl
# (c) Pali 2019, Perl license
use strict;
use warnings;
use Net::Telnet;
use Time::HiRes qw(usleep);
die "Usage: $0 host pass ast_user\n" unless @ARGV == 3;
my $host = $ARGV[0];
my $pass = $ARGV[1];
my $user = $ARGV[2];
my $t = Net::Telnet->new(Timeout => 3, Prompt => '/[^\n]*> $/');
$t->open($host);
$t->waitfor('/Password :$/');
$t->print($pass);
$t->waitfor($t->prompt);
foreach ('open', ('key volup') x 16, 'close') {
if (system('sh', '-c', qq[asterisk -rx "core show channels" |grep -q "$user"]) != 0) {
print STDERR "Call ended, exiting";
last;
}
$t->cmd("test $_");
usleep 200_000;
}
$t->print("exit");
$t->close();

6
all_reboot.sh Executable file
View file

@ -0,0 +1,6 @@
#!/bin/sh
pass=`sed -n 's/telnet_pass=//p' config.txt`
ip=`sed -n 's/server_ip=//p' config.txt | sed 's/\.[0-9]*$//'`
for i in `cat phones.txt | grep -v \- | sed -n 's/^\([0-9][0-9]\).*/\1/p'`; do
{ admin_scripts/send_reboot.pl "$ip.$i" "$i" 2>&1 || admin_scripts/force_reboot.pl "$ip.$i" "$pass" 2>&1 ; } | sed "s/^/$i: /"
done

14
ann_end.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/bash
line="$1"
[[ -n "$line" ]] || { echo >&2 "usage: $0 <line>"; exit 1; }
echo "Action: login
username: admin
secret: admin
events: off
Action: hangup
Channel: /PJSIP/emerg$line-.*/
" | socat - TCP:localhost:5038

11
ann_end_all.sh Executable file
View file

@ -0,0 +1,11 @@
#!/bin/bash
cd "$(dirname "$0")"
echo "Action: login
username: admin
secret: admin
events: off
Action: hangup
Channel: /.*emerg.*/
" | socat - TCP:localhost:5038

21
ann_listen.sh Executable file
View file

@ -0,0 +1,21 @@
#!/bin/bash
cd "$(dirname "$0")"
line="$1"
. config.txt
./ann_end.sh "$line" # and any existing calls to prevent our call ending up in "call waiting" state (and thus not autoanswered)
sleep 0.5
./autoanswer_line.sh "$line" 1 || { echo >&2 "failed to enable autoanswer, exiting."; exit 1; }
fn=/var/spool/asterisk/tmp/ann_$line.call
echo "
Channel: PJSIP/emerg$line
Context: emerg_listen
Extension: 120
Priority: 1
" >$fn
mv "$fn" /var/spool/asterisk/outgoing/
./ann_volup.sh "$line" &

5
ann_listen_all.sh Executable file
View file

@ -0,0 +1,5 @@
#!/bin/bash
cd "$(dirname "$0")"
cat phones.txt | awk '{print $1}' | grep '^[3-5]' | xargs -n1 -P0 ./ann_listen.sh

30
ann_play.sh Executable file
View file

@ -0,0 +1,30 @@
#!/bin/bash
# By default, we operate in bracketed mode: initiate listening calls, play announcement and terminate them
# With -n, we do not do bracketing, you have to initiate and terminate listening calls yourself
# with ann_listen[_all].sh and ann_end[_all].sh. Useful if you want to combine playback and speech in
# one announcement (call 121 to speak without bracketing).
if [[ "$1" == -n ]]; then num=121; shift; else num=122; fi
playstring="silence/1"
i=0
for arg in "$@"; do
if [[ "$arg" =~ ^silence ]]; then
playitem="$arg"
else
ffmpeg -i "$arg" -ar 8000 -ac 1 -y /tmp/ann$i.wav
playitem=/tmp/ann$i
fi
playstring="$playstring&$playitem"
i=$((i+1))
done
fn=/var/spool/asterisk/tmp/ann_play.call
echo "
Channel: Local/$num@orgs
Application: Playback
Data: $playstring
" >$fn
mv $fn /var/spool/asterisk/outgoing/

36
ann_play_unicast.sh Executable file
View file

@ -0,0 +1,36 @@
#!/bin/bash
cd "$(dirname "$0")"
line="$1"
snd="$2"
. config.txt
./ann_end.sh "$line" # and any existing calls to prevent our call ending up in "call waiting" state (and thus not autoanswered)
sleep 0.5
./autoanswer_line.sh "$line" 1 || { echo >&2 "failed to enable autoanswer, exiting."; exit 1; }
playstring="silence/1"
i=0
for arg in "$@"; do
if [[ "$arg" =~ ^silence ]]; then
playitem="$arg"
else
ffmpeg -i "$arg" -ar 8000 -ac 1 -y /tmp/ann${line}_$i.wav
playitem=/tmp/ann${line}_$i
fi
playstring="$playstring&$playitem"
i=$((i+1))
done
fn=/var/spool/asterisk/tmp/ann_$line.call
echo "
Channel: PJSIP/emerg$line
Application: Playback
Data: $playstring
Priority: 1
" >$fn
mv "$fn" /var/spool/asterisk/outgoing/
./ann_volup.sh "$line" &

18
ann_stop.sh Executable file
View file

@ -0,0 +1,18 @@
#!/bin/bash
cd "$(dirname "$0")"
./ann_end_all.sh
echo "Action: login
username: admin
secret: admin
events: off
Action: hangup
Channel: /.*emerg.*/
Action: ConfbridgeKick
Conference: 120
Channel: all
" | socat - TCP:localhost:5038

18
ann_volup.sh Executable file
View file

@ -0,0 +1,18 @@
#!/bin/bash
cd "$(dirname "$0")"
line="$1"
[[ "$line" =~ ^[0-9]+$ ]] || { echo >&2 "usage: $0 <line>"; exit 1; }
. config.txt
ip_prefix=${server_ip%.*}
ip="$ip_prefix.$line"
for i in $(seq 1 10); do
if asterisk -rx "core show channels" |grep -q "emerg$line"; then
./admin_scripts/volume_up.pl "$ip" "$telnet_pass" "emerg$line"
break
else
sleep 1
fi
done

15
autoanswer_all.sh Executable file
View file

@ -0,0 +1,15 @@
#!/bin/bash
state="$1"
case $state in
1)
gr=enabled
;;
0)
gr=disabled
;;
esac
cd /opt/ksp
cat phones.txt | awk '{print $1}' | grep '^[3-5]' | xargs -i -n1 -P0 ./autoanswer_line.sh '{}' "$state" | grep $gr | cut -d. -f4| cut -d' ' -f1

12
autoanswer_line.sh Executable file
View file

@ -0,0 +1,12 @@
#!/bin/bash
cd "$(dirname "$0")"
line="$1"
state="$2"
{ [[ "$line" =~ ^[0-9]+$ ]] && [[ "$state" =~ ^[01]$ ]]; } || { echo >&2 "usage: $0 <line> <0|1>"; exit 1; }
. config.txt
ip_prefix=${server_ip%.*}
ip="$ip_prefix.$line"
./admin_scripts/auto_answer.pl "$ip" "$telnet_pass" 2 "$state"

24
cislovaci_plan Normal file
View file

@ -0,0 +1,24 @@
veřejné číslo pro volání zvenku: 910 128 976
0 - 9 - nič
20 - 29 - ORG cisco telefóny
30 - 59 - zvyšné cisco telefóny
60 - 99 - zvyšné ne-cisco telefóny (ak budeme zapájať iných SIP klientov)
78 - (mnemonic: "su") Volání org-only čísel z libovolného telefonu, případně zvenku
100 - 199 - čísla pre automaty, odkazové schránky a iné veci
- 11x... veřejné konference
- 12x announce mechanismus
- 120 announce listen
- 121 [org only] announce speak (jen umožňuje mluvit k posluchačům)
- 122 [org only] announce (připoj všechny účastníky do konference a pak mluv)
- 123xx [org only] unicast announce na telefon xx (funguje obousměrně; nezneužívat k odposlechu, ale můžete se bavit s účastníky)
- 130 - vytočí náhodnú non-ORG linku
- 131 - vyzvednutí hlasových zpráv
- 14xx - přímé zanechání hlasové zprávy pro linku xx
- 16x - IVR
- 161 - FBI
Podle samolepek na telefonu:
8888 - helpdesk -> FBI
4445 - HR -> přečtení pokynů

2
clean.sh Executable file
View file

@ -0,0 +1,2 @@
#!/bin/sh
rm -f etc_asterisk/pjsip_wizard_phones.conf etc_asterisk/voicemail_gen.conf tftp_reflash/SIP00*.cnf tftp_reflash/SIPDefault.cnf tftp/Phones/SIP00*.cnf tftp/RINGLIST.DAT etc_dnsmasq.d/phones.conf www/directory.txt etc_asterisk/voicemail_gen.conf

4
config.txt Normal file
View file

@ -0,0 +1,4 @@
server_ip=172.16.0.1
telnet_pass=FIXME
hmac_key=FIXME
fake_year=2114

8
conv_ring.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/sh -e
if test "$#" != "1"; then echo "Usage: $0 sound_file.ext"; exit 1; fi
file="${1%.*}.pcm"
ffmpeg -loglevel fatal -y -i "$1" -f u8 -c pcm_mulaw -ar 8000 -ac 1 "$file"
size=`du -b "$file" | cut -f1`
size=$(($size/240*240))
if test "$size" -gt "16080"; then size=16080; fi
truncate -s "$size" "$file"

View file

@ -0,0 +1,22 @@
[default_bridge]
type=bridge
video_mode=none
[ann_listen]
type=user
startmuted=yes
quiet=yes
announce_only_user=no
[ann_speak]
type=user
quiet=yes
announce_only_user=no
startmuted=no
[ann]
type=bridge
video_mode=none
[empty_menu]
type=menu

141
etc_asterisk/extensions.lua Normal file
View file

@ -0,0 +1,141 @@
extensions = {}
extensions.participants = {}
extensions.orgs = {}
extensions.emerg = {}
extensions.emerg_listen = {}
extensions.ann_bracket = {}
extensions.odorik = {}
extensions.external = {}
function sip_exten(ch, ext)
app.dial("PJSIP/" .. ext, 40)
local status = channel.DIALSTATUS:get()
app.verbose("status: " .. status)
if status == "BUSY" then
flags="b"
else
flags="u"
end
app.voicemail(ext, flags)
end
function ann_unicast(ch, ext)
app.dial("PJSIP/emerg" .. string.sub(ext, 4))
end
function sip_nightmode(ch, ext)
local hour = tonumber(os.date("%H"))
local minute = tonumber(os.date("%M"))
if hour < 12 or (hour == 12 and minute < 10) or hour > 23 or (hour == 23 and minute > 20) then
app.playback("/opt/ksp/sounds/nocni_klid")
app.voicemail(ext)
else
sip_exten(ch, ext)
end
end
function voicemail_direct(ch, ext)
app.voicemail(string.sub(ext, 3))
end
function voicemail_listen(ch, ext)
local caller = channel.CALLERID("num"):get()
app.voicemailmain(caller, "s") -- no password prompt
end
function conf(ch, ext)
app.confbridge(ext)
end
function add(ctxs, ext, func)
for i = 1, #ctxs do
extensions[ctxs[i]][ext] = func
end
end
function ann_listen(ch, ext)
app.confbridge("120", "ann", "ann_listen", "empty_menu")
end
function ann_speak(ch, ext)
app.confbridge("120", "ann", "ann_speak")
end
function ann_bracket(ch, ext)
app.system("/opt/ksp/ann_listen_all.sh")
app.confbridge("120", "ann", "ann_speak")
end
function ann_bracket_hangup(ch, ext)
app.system("/opt/ksp/ann_end_all.sh")
end
function ann_bracket_goto(ch, ext)
app.goto("ann_bracket", "122", 1)
end
function fbi(ch, ext)
app.dial("PJSIP/910119352@odorik")
end
function odorik_incoming(ch, ext)
app.answer()
app.read("klapka", "/opt/ksp/sounds/klapka")
local klapka = channel.klapka:get()
app.goto("external", klapka, 1)
end
function su(ch, ext)
app.read("heslo", "/opt/ksp/sounds/heslo")
local heslo = channel.heslo:get()
if heslo == "2886287" then
app.read("klapka", "/opt/ksp/sounds/klapka")
local klapka = channel.klapka:get()
app.goto("orgs", klapka, 1)
else
app.playback("/opt/ksp/sounds/spatne_heslo")
app.hangup()
end
end
--http://lua-users.org/wiki/StringTrim
function trim1(s)
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
function call_rand(ch, ext)
local caller = channel.CALLERID("num"):get():gsub("'", "")
local handle = io.popen("/opt/ksp/rand_line.sh '" .. caller .. "'")
local line = trim1(handle:read("*all"))
handle:close()
app.verbose("RAND: " .. line)
app.dial("PJSIP/"..line)
end
function snd(name)
return function(ch, ext)
app.answer()
app.playback("/opt/ksp/sounds/" .. name)
app.hangup()
end
end
add({"orgs"}, "_2X", sip_exten) -- org phones
add({"orgs"}, "_[345]X", sip_exten) -- participant phones
-- night mode restriction applies only when calling from participant phones
add({"participants", "external"}, "_2X", sip_nightmode) -- org phones
add({"participants", "external"}, "_[345]X", sip_nightmode) -- participant phones
add({"orgs", "participants", "external"}, "_11.", conf)
add({"orgs", "participants", "emerg_listen", "external"}, "120", ann_listen)
add({"orgs"}, "121", ann_speak)
-- Because hangup actions are per-context and not per-extension, we need to jump to
-- a separate context to allow a hangup handler to terminate listeners after a call
-- to 122 is done.
add({"orgs"}, "122", ann_bracket_goto)
add({"ann_bracket"}, "122", ann_bracket)
add({"ann_bracket"}, "h", ann_bracket_hangup)
add({"orgs"}, "_123XX", ann_unicast)
add({"orgs", "participants"}, "131", voicemail_listen) -- does not work, done in extensions.conf!!
add({"orgs", "participants", "external"}, "_14XX", voicemail_direct)
add({"participants", "external"}, "78", su)
add({"odorik"}, "s", odorik_incoming)
add({"orgs", "participants", "external"}, "160", fbi)
add({"orgs", "participants", "external"}, "910119352", fbi)
-- Na některých telefonech je od původních majitelů nálepka "call helpdesk at 8888"
add({"orgs", "participants", "external"}, "8888", fbi)
add({"orgs", "participants", "external"}, "4445", snd("hr"))
add({"orgs", "participants", "external"}, "130", call_rand)
--add({"orgs", "participants"}, "_131", snd("sadtromb"))

3
etc_asterisk/logger.conf Normal file
View file

@ -0,0 +1,3 @@
[logfiles]
console => notice,warning,error,debug,verbose

11
etc_asterisk/manager.conf Normal file
View file

@ -0,0 +1,11 @@
[general]
enabled = yes
webenabled = no
port = 5038
bindaddr = 127.0.0.1
[admin]
secret = admin
read = all
write = all

73
etc_asterisk/modules.conf Normal file
View file

@ -0,0 +1,73 @@
;
; Asterisk configuration file
;
; Module Loader configuration file
;
[modules]
autoload=yes
;
; Any modules that need to be loaded before the Asterisk core has been
; initialized (just after the logger has been initialized) can be loaded
; using 'preload'. This will frequently be needed if you wish to map all
; module configuration files into Realtime storage, since the Realtime
; driver will need to be loaded before the modules using those configuration
; files are initialized.
;
; An example of loading ODBC support would be:
;preload => res_odbc.so
;preload => res_config_odbc.so
;
; If you want, load the GTK console right away.
; Don't load the KDE console since
; it's not as sophisticated right now.
;
noload => pbx_gtkconsole.so
;load => pbx_gtkconsole.so
noload => pbx_kdeconsole.so
;
; Intercom application is obsoleted by
; chan_oss. Don't load it.
;
noload => app_intercom.so
;
; The 'modem' channel driver and its subdrivers are
; obsolete, don't load them.
;
noload => chan_modem.so
noload => chan_modem_aopen.so
noload => chan_modem_bestdata.so
noload => chan_modem_i4l.so
;
; Comment this out (after installing CAPI middleware and hardware
; drivers) if you have CAPI-able hardware and wish to use it in
; Asterisk.
;
noload => chan_capi.so
;
load => res_musiconhold.so
;
; Do not load load local channel drivers (using the system speaker) by default,
; they are not used in most installations and might block the sound hardware
;
noload => chan_alsa.so
noload => chan_console.so
noload => chan_oss.so
;
; Disable CDR logging to SQLite by default since it writes unconditionally to
; cdr.db without a way to rotate it.
;
noload => cdr_sqlite.so
;
; These conflict with app_directory.so and each other.
noload => app_directory_odbc.so
;
; Enable these if you want to configure Asterisk in a database
;
noload => res_config_odbc.so
noload => res_config_pgsql.so
;
; Module names listed in "global" section will have symbols globally
; exported to modules loaded after them.
;
[global]

10
etc_asterisk/pjsip.conf Normal file
View file

@ -0,0 +1,10 @@
[system-udp]
type=transport
protocol=udp
bind=0.0.0.0
[system-tcp]
type=transport
protocol=tcp
bind=0.0.0.0

View file

@ -0,0 +1,36 @@
[base_phone](!)
type = wizard
transport = system-udp
accepts_registrations = yes
sends_registrations = no
accepts_auth = yes
sends_auth = no
aor/max_contacts = 1
aor/remove_existing = yes
endpoint/allow = !all,alaw
endpoint/direct_media = yes
[participant_phone](!,base_phone)
endpoint/context = participants
[participant_emerg](!,base_phone)
endpoint/context = emerg
[org_phone](!,base_phone)
endpoint/context = orgs
[odorik]
type = wizard
transport = system-udp
sends_auth = yes
sends_registrations = yes
remote_hosts = 81.31.45.51 ; sip.odorik.cz
; public number: 910 128 976
outbound_auth/username = 747515
#include odorik_pass.conf
endpoint/context = odorik
aor/qualify_frequency = 15
endpoint/allow = !all,alaw
#include pjsip_wizard_phones.conf

View file

@ -0,0 +1,6 @@
[general]
format=wav
[default]
#include voicemail_gen.conf

6
etc_dnsmasq.d/dhcp.conf Normal file
View file

@ -0,0 +1,6 @@
interface=eth0
bind-dynamic
dhcp-authoritative
listen-address=172.16.0.1
dhcp-range=172.16.0.100,172.16.0.200
dhcp-leasefile=/tmp/dhcp.leases

View file

@ -0,0 +1,4 @@
dhcp-vendorclass=set:CiscoIPPhone,"Cisco Systems, Inc. IP Phone"
dhcp-option=tag:CiscoIPPhone,150,0.0.0.0
enable-tftp
tftp-root=/opt/ksp/tftp

174
gen.pl Executable file
View file

@ -0,0 +1,174 @@
#!/usr/bin/perl
use strict;
use warnings;
use Digest::SHA qw(hmac_sha1_hex);
use Encode;
use Text::Unidecode;
mkdir "tftp/Phones";
my $fh;
my %config;
open $fh, '<', 'config.txt' or die "Cannot read file config: $!\n";
while (<$fh>) {
chomp;
my ($key, $value) = split /=/, $_, 2;
$config{$key} = $value;
}
close $fh;
my $server_ip = $config{server_ip};
my $ip_template = $server_ip;
$ip_template =~ s/\.[^.]*$//;
my $fake_second_half = $config{fake_year};
my $sipdefault_reflash = <<"EOD";
image_version: P0S3-8-12-00
phone_password: $config{telnet_pass}
encrypt_key: 00000000000000000000000000000000
telnet_level: 2
tftp_cfg_dir: ""
EOD
chomp $sipdefault_reflash;
open my $phones_fh, '<', 'phones.txt' or die "Cannot read file phones.txt: $!\n";
open my $ast_fh, '>', 'etc_asterisk/pjsip_wizard_phones.conf' or die "Cannot create file etc_asterisk/pjsip_wizard_phones.conf: $!\n";
open my $dnsmasq_fh, '>', 'etc_dnsmasq.d/phones.conf' or die "Cannot create file etc_dnsmasq.d/phones.conf: $!\n";
open my $directory_fh, '>', 'www/directory.txt' or die "Cannot create file www/directory.txt: $!\n";
open my $voicemail_fh, '>', 'etc_asterisk/voicemail_gen.conf' or die "Cannot create file etc_asterisk/voicemail_gen.conf: $!\n";
print $ast_fh "; This is autogenerated file, do not edit it!\n";
print $dnsmasq_fh "# This is autogenerated file, do not edit it!\n";
print $directory_fh "# This is autogenerated file, do not edit it!\n";
print $voicemail_fh "; This is autogenerated file, do not edit it!\n";
while (<$phones_fh>) {
chomp $_;
next if $_ =~ /^(?:#|$)/;
$_ =~ s/#.*//;
$_ =~ s/\s*$//;
my ($line, $mac, $alias, $name) = split /\s+/, $_, 4;
die "Invalid line $.: $_\n" unless defined $name;
$mac = uc $mac;
my $name_latin1 = $name;
Encode::from_to($name_latin1, 'UTF-8', 'ISO-8859-1', sub { unidecode(chr($_[0])) });
$line =~ /^[2-9][0-9]$/ or die "Invalid LINE $line on line $.: $_\n";
$alias =~ /^[A-Za-z0-9_]{1,20}$/ or die "Invalid ALIAS $alias on line $.: $_\n";
length $name_latin1 <= 30 or die "Too long NAME $name on line $.: $_\n";
my $parent = ($line =~ /^2[0-9]$/) ? 'org_phone' : 'participant_phone';
my $pass = substr(hmac_sha1_hex($line, $config{hmac_key}), 0, 12);
my $cisco_fh;
my $ciscofile;
if ($mac ne '-') {
$mac =~ /^(?:[0-9A-F]{2}:){5}[0-9A-F]{2}$/ or die "Invalid MAC $mac on line $.: $_\n";
$ciscofile = $mac;
$ciscofile =~ s/://g;
open $cisco_fh, '>', "tftp/Phones/SIP$ciscofile.cnf" or die "Cannot create file tftp/Phones/SIP$ciscofile.cnf: $!\n";
print $cisco_fh <<"EOD";
# This is autogenerated file, do not edit it!
phone_label: "$fake_second_half Klapka $line "
phone_prompt: "Telnet phone $line"
proxy_register: 1
proxy1_address: $server_ip
proxy1_port: 5060
line1_name: $line
line1_authname: $line
line1_password: $pass
line1_displayname: "$alias"
line1_shortname: "$name_latin1"
sntp_server: $server_ip
sntp_mode: unicast
services_url: http://$server_ip/services.xml
directory_url: http://$server_ip/directory.xml
logo_url: http://$server_ip/logo.bmp
messages_uri: 131
telnet_level: 2
EOD
close $fh;
}
print $ast_fh <<"EOD";
[$line]($parent)
inbound_auth/username = $line
inbound_auth/password = $pass
endpoint/mailboxes = $line
EOD
if ($parent eq 'participant_phone') {
print $ast_fh <<"EOD";
[emerg$line](participant_emerg)
inbound_auth/username = emerg$line
inbound_auth/password = $pass
EOD
if ($mac ne '-') {
print $cisco_fh <<"EOD"
proxy2_address: $server_ip
proxy2_port: 5060
line2_name: emerg$line
line2_authname: emerg$line
line2_password: $pass
line2_displayname: "Emergency $line"
line2_shortname: " "
EOD
}
} else {
if ($mac ne '-') {
print $cisco_fh <<"EOD"
dnd_control: 0
EOD
}
}
if ($mac ne '-') {
close $cisco_fh;
open $fh, '>', "tftp_reflash/SIP$ciscofile.cnf" or die "Cannot create file tftp_reflash/SIP$ciscofile.cnf: $!\n";
print $fh <<"EOD";
# This is autogenerated file, do not edit it!
$sipdefault_reflash
proxy_register: 0
line1_name: $line
EOD
}
if ($mac ne '-') {
print $dnsmasq_fh <<"EOD";
dhcp-host=$mac,$ip_template.$line,$alias
EOD
}
print $directory_fh <<"EOD";
$name=$line
EOD
print $voicemail_fh <<"EOD"
$line => 0000,$name
EOD
}
close $phones_fh;
close $ast_fh;
close $dnsmasq_fh;
close $directory_fh;
close $voicemail_fh;
open $fh, '>', 'tftp_reflash/SIPDefault.cnf' or die "Cannot create file tftp_reflash/SIPDefault.cnf: $!\n";
print $fh <<"EOD";
# This is autogenerated file, do not edit it!
$sipdefault_reflash;
EOD
close $fh;
open $fh, '>', 'tftp/RINGLIST.DAT' or die "Cannot create file tftp/RINGLIST.DAT: $!\n";
foreach (<tftp/RingTones/*.pcm>) {
$_ =~ m{^tftp/(RingTones/(.*)\.pcm)$};
my ($file, $name) = ($1, $2);
$name =~ s/_/ /g;
print $fh "$name\t$file\n";
}
close $fh;

11
gen_hr.sh Executable file
View file

@ -0,0 +1,11 @@
#!/bin/bash
i=0
grep . hr.txt | while read line; do
i=$((i+1))
echo ">> [$i] $line"
fn=hr/$(printf %03d $i).wav
if [[ -e "$fn" ]]; then continue; fi
./tts.sh "$line" "$fn"
sleep 10
done

16
gen_sounds.sh Executable file
View file

@ -0,0 +1,16 @@
#!/bin/bash
gen_sound() {
fn="sounds/$1.wav"
[[ -e "$fn" ]] || ./tts.sh "$2" "$fn"
}
gen_sound nocni_klid "Z důvodu nočního klidu budete přesměrováni do hlasové schránky. Pokud chcete telefonovat v reálném čase, můžete oba zavolat do společné konference."
gen_sound heslo "Zadejte heslo"
gen_sound spatne_heslo "Špatné heslo"
gen_sound klapka "Zadejte číslo klapky"
gen_sound wc_thanks "Děkujeme za použití toalety. Nezapomeňte si umýt ruce."
gen_sound wc_thanks_m "Děkujeme, že jste použil naše toalety. Nezapomeňte si umýt ruce."
gen_sound wc_thanks_f "Děkujeme, že jste použila naše toalety. Nezapomeňte si umýt ruce."
gen_sound tp_prizemi "V kontaminační komoře na nulté palubě došel toaletní papír. Prosíme cestující, aby se solidárně podělili o své noviny."
gen_sound tp_prvni "V kontaminační komoře na první palubě došel toaletní papír. Prosíme cestující, aby se solidárně podělili o své noviny."
gen_sound tp_druhe "V kontaminační komoře na druhé palubě došel toaletní papír. Prosíme cestující, aby se solidárně podělili o své noviny."

12
hangup_all.sh Executable file
View file

@ -0,0 +1,12 @@
#!/bin/bash
echo "Action: login
username: admin
secret: admin
events: off
Action: hangup
Channel: /.*/
" | socat - TCP:localhost:5038

179
hr.txt Normal file
View file

@ -0,0 +1,179 @@
VŠEOBECNÉ SMĚRNICE PROVOZU LODI
Pokud je vaše pracovní uniforma kontaminována dihydrogen monoxidem, použijte vysokokapacitní savou substanci pro odstranění kontaminace.
Loď je vybavena telekomunikačním systémem, jehož terminály jsou rozmístěny ve většině obytných i jiných prostor.
Tyto terminály smíte využívat pro vzájemnou komunikaci s posádkou i s vedením lodi.
Váš hovor může být monitorován pro zlepšení služeb, které jsou k dispozici vedení lodi.
Zároveň budou terminály využívány pro svolávání posádky či vyvolání poplachu.
Tyto terminály je ZAKÁZÁNO ničit, vypojovat, poškozovat či jinak s nimi nemístně manipulovat.
V případě katastrofálního nedostatku toaletního papíru, který je detekován až po zahájení využívání toalety, použijte pro přivolání asistence přiloženého telekomunikačního zařízení.
Strava na lodi je vydávána nejméně třikrát denně (snídaně, oběd, večeře).
Pro blaho posádky je povinnná účast na snídani.
Snídani předchází dobrovolná tělesná rozcvička a preventivní test psychoakustické zdatnosti.
Podmínkou účasti na snídani je účast na rozcvičce.
Vzdělávání posádky je vedením podporováno.
Z tohoto důvodu se ve společenských prostorách budou každý den pořádat přibližně tři bloky odborného trénování a lekcí z teorie civilizace a vesmírné kolonizace.
Na těchto lekcích je přísně zakázáno rušit či spát.
Spící osoby budou kosmeticky či geneticky modifikovány.
Při rekreační rotační pohybové hře kruhozávodu po směru hodinových ručiček budou libovolné vzpoury tvrdě potlačeny.
Viníci budou vyhozeni přetlakovou komorou do mezihvězdného prostoru, následně budou opět zachyceni a zpracováni na karbonovou pastu.
Vedení by chtělo důrazně varovat posádku lodi o faktu, že kdo umře v Polsku, umře i ve skutečnosti.
Je zakázáno chovat na lodi domácí mazlíčky či jinou zvěř mimo prostor skladiště biologického materiálu.
Vyjímku tvoří lišky, hroši, prasata a medvědi.
Každý lodní den bude vyhrazeno nejméně třicet tři procent dne na spánek či odpočinek.
Definice lodního dne, spánku, odpočinku a procent bude upřesněna.
Při zjištění incidentu zcizení vlastního předmětu jiným členem posádky je nutno zajistit znalost jména všech zúčastněných osob.
V případě závady na skafandru je možno vyžádat si od vedení lodi náhradní.
Mějte ovšem na paměti, že nadbytečných skafandrů je omezené množství.
K respirátorům jsou k dispozici speciální kyslíkové náplně s vůní mrkve.
Je přísně zakázáno krmit zvěř ve skladišti biologického materiálu.
Po večerce se uložte ke spánku v gravitačních kójích.
Pro kvalitní spánek je nutné nejdříve ke svému jazyku připojit kabely s koncovkou typu krokodýl, která stimuluje sny, detekuje náměsíčnost a slouží jako efektivní budíček.
Budíček smí využívat pouze bezpečných úrovní napětí.
Pokud nastane katastrofální selhání štěpného reaktoru, použijte k pacifikaci zběhlých neutronů vystužených kontrolních tyčí z boronu.
Vedení lodi by chtělo zvlášť poděkovat umělci Markovi "Maark" Černému za design lodního exteriéru.
Pro zlepšenou orientaci posádky je interiér lodi vybaven orietačními symboly a směrovkami.
Mějte na paměti, že směrovky jsou orientované! Navíc je zaručeno, že graf směrovek je 2-souvislý.
Je přísně zakázáno kontaminovat mezihvězdný prostor odpadky, jako jsou například konzervy.
Veškerá rekreační zařízení jsou testována na dětech.
Do stázové komory je vstup povolen pouze v pyžamu splňujícím normu 3GPP-4923587-3B.
Nedodržení může vyústit ve smrt stářím.
Berte na vědomí, že červená reflexní etiketa značí extrémně pálivé pokrmy.
Politické mapy nově kolonizovaných území musí splňovat, že sousední území nejsou obarvena shodně a jsou použity nejvýše čtyři barvy.
Pro případ politické diskuze jsou nouzové plamenomety uloženy na třetí palubě.
Nekrmte lodní kočku bez jejího svolení.
Veškerá data o posádce (včetně záznamů pohybu, biotelemetrie, vyhledávaných frází a publikovaných příspěvků na lodní sociální síti)
budou využita pro algoritmické vylepšení a personalizaci lodních předpisů.
Každý člen posádky musí znát nejméně 50 souhvězdí.
POKYNY PŘI EVAKUACI
Veškerá posádka lodi je povinna řídit se evakuačními pokyny.
Pokud dojde k evakuaci z důvodu úniku radioaktivního materiálu ze štěpného reaktoru,
z důvodu vniku radioaktivního materiálu do fůzního reaktoru,
kvůli selhání vzduchotechniky, softwarové vyjímky, kolize s cizím objektem,
kolize se spřízněným objektem, nebo z důvodu napadení cizí formou života,
ignorujte v tomto případě všeobecné nařízení §451-3.
Pokud dojde k evakuaci z důvodu ztráty elektrické energie,
z důvodu vniku radioaktivního materiálu do fůzního reaktoru,
kvůli prudkému poklesu tlaku, kontaminaci melounovou Kofolou či katastrofálnímu nadbytku čočky,
ignorujte lemma 6.66.
Pokyny:
Každý člen posádky je především povinen řídit se pokyny z lodní telefonní sítě.
S telefony je přísně zakázáno neoprávněně manipulovat či narušovat jejich činnost.
Každý člen posádky je povinen řídit se pokyny velících důstojníků, a to i mimo své domovské oddělení.
Evakuace je zahájena všeobecným poplachem.
Po zahájení evakuace se urychleně připravte opustit loď.
Očekávaná doba na přípravu je PĚT AŽ SEDM MINUT.
Pomalejší členové posádky budou zanecháni na lodi!
S sebou si vemte:
nezbytnou osobní výbavu na 2 až 5 hodin v mezihvězdném prostoru,
vhodný exosuit do slunečního větru, meteorického deště a zimy blízké absolutní nule,
osobní jetpack,
otvírák na konzervy a lžičku,
diplomatickou příručku,
šifrovací pomůcky
kyanidovou tabletku.
Po shromáždění osobní výbavy se urychleně přesuňte k přetlakové komoře.
Zde vám bude vydán skafandr, který si nasaďte před opuštěním lodi.
Po opuštění lodi se přesuňte k nástupnímu prostoru únikového modulu a urychleně do něj nastupte.
Únikový modul má kapacitu DESET osob.
Do únikového modulu vkročte PRAVOU nohou.
Unikový modul odlétá do PATNÁCTI minut od zahájení evakuace a v zájmu záchrany co největší části posádky na nikoho nečeká.
Jakmile budete v bezpečí, řiďte se pokyny pro zjistění stavu lodi a příčiny evakuace.
POKYNY V PŘÍPADĚ KONTAKTU S CIZÍ FORMOU ŽIVOTA
Při komunikaci ujistěte cizí formu života, že sdělené názory jsou vaše vlastní a nereprezentují oficiální stanovisko Hegemonie člověka.
V případě nenalezení společného jazyka využijte Braillovo písmo.
Při konfliktu s formou života na bázi stroje pamatujte, že před kyBorkem neutečete.
POKYNY PRO POUŽÍVÁNÍ TELEKOMUNIKAČNÍCH ZAŘÍZENÍ
Je přísně zakázáno libovolné telekomunikační zařízení vypínat, odpojovat z rozvodné sítě či jinak narušovat jeho činnost!
Dále je zakázáno měnit nastavení libovolného terminálu.
Při problémech se obraťte na vedení posádky či lodního síťaře.
Nenechávejte vyvěšené sluchátko!
V případě vypojení libovolného kabelu z terminálu DBEJTE ZVÝŠENÉ OPATRNOSTI! Terminály jsou netradičně napájeny z datových kabelů napětím 48V.
Je zakázáno olizovat libovolné dráty.
Některé jsou pod napětím.
Navíc jsou ostré.
Terminál může být použit k účelům všeobecné distribuce informace.
POKYNY V PŘÍPADĚ NÁVŠTĚVY EXOPLANETY
Tyto pokyny se vztahují pouze pro návštěvy exoplanet s prokazatelnou přítomností vyšších organismů.
Na exoplanetách s pouze bakteriálním životem či zcela bez biosféry se řiďte předpisy pro návštěvu asteroidů vyjma sekce 3 pokynů pro chování v mikrogravitaci.
Při pohybu na exoplanetách dbejte zvýšené opatrnosti.
Všichni členové posádky jsou povinni pohybovat se ve skupinách nejméně dvou osob.
V případě výskytu inteligentního domorodého života omezte kontakt na minimum, není-li vedením lodi specifikováno jinak.
Je doporučeno zahrnout do výbavy expedice šifrovací pomůcky.
Každá skupina je povinna mít s sebou nejméně jeden měřič ionizujícího záření.

5
hr_join.sh Executable file
View file

@ -0,0 +1,5 @@
#!/bin/bash
printf "file '%s'\n" hr/*.wav > hr_concat.txt
ffmpeg -f concat -safe 0 -i hr_concat.txt -c copy sounds/hr.wav

6
list_errors.sh Executable file
View file

@ -0,0 +1,6 @@
#!/bin/sh
pass=`sed -n 's/telnet_pass=//p' config.txt`
ip=`sed -n 's/server_ip=//p' config.txt | sed 's/\.[0-9]*$//'`
for i in `cat phones.txt | grep -v backup | grep -v \- | sed -n 's/^\([0-9][0-9]\).*/\1/p'`; do
admin_scripts/list_errors.pl "$ip.$i" "$pass" 2>&1 | sed '/^$/d' | sed "s/^/$i: /"
done

1
list_errors_crontab Normal file
View file

@ -0,0 +1 @@
*/10 * * * * cd /opt/ksp; ./list_errors.sh | sed -E 's/172\.16\.0\.//;s/,? ?port 23//;s/ ?at .* line [0-9]*//' > /tmp/error.log.new; mv /tmp/error.log.new /tmp/error.log

54
logo/anytoppm.sh Executable file
View file

@ -0,0 +1,54 @@
#!/bin/bash -eu
usage() {
echo >&2 "usage: $0 <input> <output>"
exit 1
}
[[ $# == 2 ]] || usage
FW_INFILE="$1"
FW_OUTFILE="$2"
MIME=`file -b --mime-type "$FW_INFILE"`
case $MIME in
image/gif)
giftopnm "$FW_INFILE" > "$FW_OUTFILE" 2>/dev/null
;;
image/jpeg |\
image/jpg)
jpegtopnm "$FW_INFILE" > "$FW_OUTFILE" 2>/dev/null
;;
image/png)
pngtopnm "$FW_INFILE" > "$FW_OUTFILE" 2>/dev/null
;;
image/x-ms-bmp |\
image/bmp |\
image/x-bmp |\
image/x-bitmap |\
image/x-xbitmap |\
image/x-win-bitmap |\
image/x-windows-bmp |\
image/ms-bmp)
bmptoppm "$FW_INFILE" > "$FW_OUTFILE" 2>/dev/null
;;
*)
echo "Unknown file contents. [$MIME]" >&2
exit 1
;;
esac
MIME2=`file -b --mime-type "$FW_OUTFILE"`
case $MIME2 in
image/x-portable-pixmap |\
image/x-portable-bitmap |\
image/x-portable-greymap)
#temporary file created
;;
*)
echo "Failed to convert file. [$MIME => $MIME2]" >&2
exit 1
;;
esac
exit 0

BIN
logo/hipporion.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
logo/hipporion.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 797 B

BIN
logo/hipporion2.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
logo/hipporion2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 777 B

BIN
logo/ksp.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
logo/logo Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

55
logo/logo.sh Executable file
View file

@ -0,0 +1,55 @@
#!/bin/bash
set -eu
CONVERTED_FILE=processed.pnm
FW_INFILE="$1"
TARGET="$2"
./anytoppm.sh "$FW_INFILE" $CONVERTED_FILE || exit 1
#generate logo for the phone
PREVIEW=_preview.png
FW_IDENT=logo_sip
case $FW_IDENT in
logo_sip)
# BMP 90x56 (8-bit), phone can display 4 colors
{ cat $CONVERTED_FILE | pnmscale -width 90 -height 56 | ppmquant 4 | ./ppmfix.sh | ppmtobmp -bpp=8 > $TARGET; } 2>/dev/null
#generate logo preview for Operator's Administration
{ cat $TARGET | bmptopnm | ./ppmfix.sh | pnmtopng > $PREVIEW; } 2>/dev/null
;;
logo_sep_bw)
# PNG 320x196 (8-bit), phone can display a 4 color PNG file
{ cat $CONVERTED_FILE | pnmscale -width 320 -height 196 | ppmquant 4 | ./ppmfix.sh | pnmtopng > $TARGET; } 2>/dev/null
# BMP 80x49 (8-bit), phone can display a 4 color PNG file
{ cat $CONVERTED_FILE | pnmscale -width 80 -height 49 | ppmquant 4 | ./ppmfix.sh | pnmtopng > $TARGET_TN; } 2>/dev/null
#generate logo preview for Operator's Administration
cp $TARGET $PREVIEW
;;
logo_sep_color)
# PNG 320x212 (12-bit)
{ cat $CONVERTED_FILE | pnmscale -width 320 -height 212 | ppmquant 4096 | ./ppmfix.sh | pnmtopng > $TARGET; } 2>/dev/null
# PNG 80x53 (12-bit)
{ cat $CONVERTED_FILE | pnmscale -width 80 -height 53 | ppmquant 4096 | ./ppmfix.sh | pnmtopng > $TARGET_TN; } 2>/dev/null
#generate logo preview for Operator's Administration
cp $TARGET $PREVIEW
;;
logo_sep_color_16)
# PNG 320x212 (16-bit)
{ cat $CONVERTED_FILE | pnmscale -width 320 -height 212 | ppmquant 65536 | ./ppmfix.sh | pnmtopng > $TARGET; } 2>/dev/null
# PNG 80x53 (16-bit)
{ cat $CONVERTED_FILE | pnmscale -width 80 -height 53 | ppmquant 65536 | ./ppmfix.sh | pnmtopng > $TARGET_TN; } 2>/dev/null
#generate logo preview for Operator's Administration
cp $TARGET $PREVIEW
;;
*)
echo "Unknown logo ident. [$FW_IDENT]" >&2
exit 1
;;
esac

21
logo/ppmfix.sh Executable file
View file

@ -0,0 +1,21 @@
#!/usr/bin/gawk -f
BEGIN {
fix = 0
}
NR == 3 && /^0$/ {
fix = 1
print "1"
next
}
fix == 0 {
print
next
}
fix == 1 {
gsub(/\x00/, "\x01", $0)
print $0
}