Datoteka manager.conf

V preteklih dveh člankih smo predstavili Asterisk v vlogi zmogljive platforme za razvoj telekomunikacijskih storitev. Predstavljena je bila možnost namestitve na različna okolja (na primer kartični računalnik Raspberry Pi) in določeni pogoji ter zahteve, ki jih moramo upoštevati v primeru takšne namestitve. Do zdaj smo spoznali tudi Asteriskovo zasnovo in kako strežnik konfiguriramo s pomočjo konfiguracijskih datotek, ki jih najdemo v imeniku /etc/asterisk. A le do nekaterih (najpogosteje uporabljenih) lahko dostopamo tudi s pomočjo različnih grafičnih vmesnikov.

Besedilo iz pretekle številke smo sklenili s spoznavanjem vmesnika AMI (Asterisk Manager Interface). Napovedali smo, da bomo ta vmesnik podrobneje spoznali v tokratni številki. Ponovimo le najpomembnejše. Dostop prek vmesnika AMI omogočimo s pomočjo vnosa v datoteko etc/asterisk/manager.conf ([general],enabled = yes , port = 5038) ter kreiranjem uporabnika z ustreznimi pravicami [mojmikro] ,secret = mikado, deny=0.0.0.0/0.0.0.0, …). Vmesnik AMI bomo na začetku uporabili neposredno na našem strežniku z nameščenim Asteriskom. Na strežnik se bomo prijavili s pomočjo odjemalca SSH (v našem primeru Putty). Tokrat se ne bomo prijavili v Asteriskovo ukazno vrstico, ampak bomo namesto tega prek telneta izvedli prijavo na vrata 5038. To storimo z nizom telnet 127.0.0.1 5038, ki nam izpiše sporočilo, podobno temu:

Trying 127.0.0.1…
Connected to Elastix.mojmikro.box (127.0.0.1).
Escape character is '^]'.
Asterisk Call Manager/1.1

Nato vnesemo zaporedje ukazov v skladu s strukturo, ki jo zahteva vmesnik AMI. Najprej definiramo želeno akcijo, v našem primeru je to prijava na sistem (ukaz login), sledita mu potrebna parametra – uporabniško ime in geslo, ki smo ju definirali v datoteki /etc/manager.conf. Vnesemo torej vrstice, ki si sledijo druga za drugo:

Action: login
Username: mojmikro
Secret: mikado

Če nas zaradi časovne kontrole strežnik zavrne, pripravimo vse ukaze kot besedilo v urejevalniku in jih prekopiramo naenkrat. Ko so ukazni vneseni, vnos potrdimo z dvema pritiskoma na tipko Enter. Če je bila prijava uspešna, nam strežnik odgovori s sporočilom

Response: Success
Message: Authentication accepted

Event: FullyBooted
Privilege: system,all
Status: Fully Booted

Na podoben način lahko izvedemo tudi odjavo. Vnesemo ukaz Action: logoff in pritisnemo dvakrat na tipko Enter. Te možnosti ne bomo izvedli, saj bi morali, če bi želeli nadaljevati, ponovno izvesti celoten postopek prijave. Prek vmesnika AMI lahko pošljemo poljuben ukaz (odvisno od pravic, definiranih v datoteki manager.conf). To storimo s pomočjo ukaza Action:command in vrstice, ki bi jo vnesli v Asteriskovo ukazno vrstico. Ukaz sip show peers bi tako poslali z nizom, ki mu na koncu spet dodamo še 'običajna' pritiska na tipko Enter.

Action: command
Command: sip show peers

Ukaz nam izpiše enake informacije, kot bi jih dobili z vnosom istega ukaza v Asteriskovo ukazno vrstico. Na podoben način bi lahko dobili informacijo o morebitni čakalni vrsti na sistemu, ki jo želimo izpisati Action: command ter Command: queue show klicna_številka_definirane_skupine. Na podoben način lahko pokličemo telefonsko številko 123 na strežniku z IP-naslovom 192.168.200.100 (pod pogojem, da ta 'sprejema' klice z našega strežnika) in jo povežemo s številko 220 na našem strežniku.

Action: Originate
Channel: SIP/123@192.168.200.100
Exten: 220
Context: from-internal
Priority: 1

Ukazni niz lahko nekoliko preuredimo, tako da bomo izvedli klic na prej omenjeno številko 123 in jo povezali z aplikacijo Playback, ki bo predvajala testno sporočilo demo-congrats.

Action: Originate
Channel: SIP/123@192.168.200.100
Application: Playback
Data: demo-congrats

V primeru odhodnega klicnega centra je lahko koristna možnost vzpostavitve klica na želeno številko (na primer 5555) in usmerjanja tega na čakalno vrsto (na primer številko 111).

Action: Originate
Channel: SIP/5555@192.168.200.100
Exten: 111
Context: from-internal
Priority: 1

PREPROSTO AMI

Opisani primeri kažejo, da lahko prek vmesnika AMI v primeru dopuščanja uporabniških pravil izvedemo poljubno opravilo, kar lahko izkoristimo tudi za uporabo 'zunanje' aplikacije. Tako aplikacijo lahko uporabimo tako za 'krmiljenje Asteriska' kot tudi za spreminjanje nastavitev oziroma nadzor nad delovanjem strežnika. S spletne strani http://sourceforge.net/projects/astchannelslive/ si naložite program AstChannelslive.

AMI prijava prek telneta

Po namestitvi in zagonu vnesemo v okno za prijavo naše podatke – IP-naslov strežnika z nameščenim Asteriskom in podatke za dostop prek vmesnika AMI (v našem primeru mojmikro in mikado). Če se pojavijo težave pri prijavljanju (podatki v oknu), sta težavi običajno dve – prva možnost je aktivnost požarnega zidu na Asterisku, druga pa neustrezna definicija v vrstici manager.conf. Požarni zid lahko začasno dezaktiviramo prek grafičnega vmesnika. V primeru distribucije Elastix storimo to prek privzetega grafičnega vmesnika (meni Security – Deactivate Firewall). Nastavitve v datoteki manager.conf pa popravimo s pomočjo urejevalnika tako, da bo pri uporabniškem računu za AMI definiciji dodana še vrstica permit z IP-naslovom računalnika, na katerega namestimo AstChannelslive. Po spremembi datoteke manager prek Asteriskove ukazne vrstice izvedemo še osvežitev nastavitev z ukazom manager reload.

Po uspešnem zagonu dobimo na zaslonu informacije o konfiguriranih čakalnih vrstah, uporabnikih (SIP, IAX) ter povezavah z drugimi sistemi (DAHDI oziroma VoIP). Delovanje programa spominja na delovanje Asteriskovega grafičnega vmesnika Flash Operator Panel. Bistvena razlika pa je v delovanju, saj AstChannelslive deluje kot samostojni odjemalec 'na poljubnem' računalniku, Operator Panel pa kot spletna aplikacija. Dostop prek vmesnika AMI uporablja tudi Activa TSP (http://activa.sourceforge.net/). Po namestitvi paketa se med modemskimi nastavitvami pojavi nov povezovalni element (Activa TPS), ki ga lahko povežemo z ustreznim programom, ki podpira uporabo različnih 'linij' (TAPI). Če aktiviramo povezavo in prek tega programa, ki sicer ne podpira možnosti povezovanja prek SIP-protokola (podpira pa ga odjemalec, ki ga ta kliče), lahko tako vzpostavimo klic prek našega Asterisk strežnika. Tako lahko izvedemo integracijo Asteriska iz poljubne aplikacije s podporo TAPI. Med kopico omenimo zato le Microsoftov Outlook ali Dialer.

AstChannesLive uporablja vmesnik AMI

Vmesnik AMI se izkaže kot zelo uporaben, saj lahko z oddaljenega odjemalca prevzamemo praktično v celoti nadzor tako nad delovanjem kot konfiguracijo strežnika. Zaradi vpisovanja uporabniških imen in gesel, ki nam omogočajo dostop prek vmesnika, moramo biti previdni, kakšne uporabniške pravice dodelimo tem uporabnikom (minimum, ki še zadošča) in s katerih IP-naslovov omogočamo dostop (datoteka manager.conf). Če bi recimo v odjemalca vpisali uporabniško ime »admin« in bi nekdo želel zlorabiti ta uporabniški račun, bi z istega računalnika le zagnal ukazno vrstico in se s pomočjo telnet odjemalca prijavil na strežnik prek vrat 5038. Ko bi se s temi podatki prijavil, bi lahko zagnal poljuben ukaz - recimo za izbris uporabnikov, ustavitev sistema ali celo spremembo načrta usmerjenja, ki bo omogočal medcelinske klice –, tega pa si verjetno ne želite.

Podoben učinek kot prek vmesnika AMI lahko dosežemo tudi prek SSH-povezave. Uporabimo derivat odjemalca Putty – Kitty (http://www.9bis.net/kitty/). Uporaba Kitty je praktično enaka kot pri Puttyju, ima pa nekaj uporabnih dodatkov. Za preizkus naredimo povezavo (z imenom Elastix) do našega strežnika z naslovom 192.168.178.10. V polje Host name vnesemo 192.168.178.10 in izberemo polje SSH, ki samodejno vpiše v polje Port vrednost 22. V oknu Category izberemo Connection in zavihek Data. V polje Auto-login username vpišemo uporabniško ime za prijavo (v našem primeru root), v polje Auto-login password pa pripadajoče geslo. Ukaz, ki ga želimo samodejno poslati ob zagonu, zapišemo v polje v obliki asterisk -rcvx »želeni_ukaz_ki_bi_ga_poslali_preko_v_Asteriskovo_konzolo«. V našem primeru želimo poslati ukaz sip show peers, zato vpišemo v polje Connection asterisk -rcvx »sip show peers«. Celotno opravilo lahko zapišemo še v paketno datoteko in skrijemo za klik na namizju:

@echo off
kitty.exe -load elastix

Seveda pa bi lahko tudi AMI tunelirali prek SSH-povezave.

ŠE ENKRAT KONFIGURACIJA

Pomen in moč konfiguracijskih datotek smo spoznali že v preteklih člankih. V naših primerih smo že uporabljali najpogostejše aplikacije in funkcije. Za osvežitev naredimo odzivnik z uro. Marsikdo se gotovo še spomni številke 95, ki jo bomo uporabili tudi v našem primeru. V datoteko /etc/asterisk/extensions_custom conf dodamo nov vnos:

ActivaTSP za Asterisk

exten => 95,1,Answer()
same => n,SayUnixTime(,CET,R)
same => n,Playback(beep)
same => n,Hangup()

Ko vnos shranimo, ne smemo pozabiti na osvežitev konfiguracije. Zdaj že vemo, da bo v primeru klica na številko naš strežnik vzpostavil povezavo, povedal trenutni čas, na koncu predvajal beep datoteko in prekinil povezavo. Seveda bi lahko v primeru drugačnih nastavitev in datotek v slovenskem jeziku našo uro tudi 'poslovenili'.

Omenili smo že, da ima Asterik tudi interno bazo, ki je zelo preprosta za uporabo. Zapise v njej lahko izpišemo iz Asteriskove ukazne vrstice s pomočjo ukaza database show. V primeru, ki sledi, bomo spreminjali vsebino spremenljivke v bazi in jo uporabili kot podatek pri klicu. V našo datoteko extensions_custom.conf dodamo vrstice:

exten => 678,1,Set(COUNT=${DB(test/count)})
same => n,Answer
same => n,GotoIf($[${ISNULL(${COUNT})}]?:continue)
same => n,Set(DB(test/count)=1)
same => n,Goto(1)
same => n(continue),NoOp()
same => n,SayNumber(${COUNT})
same => n,Set(COUNT=$[${COUNT} + 1]
same => n,Set(DB(test/count)=${COUNT})
same => n,Goto(1)
same => n,Hangup()

exten => 876,1,Set(COUNT=${DB(test/count)})
same => n,Answer
same => n,GotoIf($[${ISNULL(${COUNT})}]?:continue1)
same => n,Set(DB(test/count)=1)
same => n,Goto(1)
same => n(continue1),NoOp()
same => n,SayNumber(${COUNT})
same => n,Set(COUNT=$[${COUNT} - 1]
same => n,Set(DB(test/count)=${COUNT})
same => n,Goto(1)
same => n,Hangup()

V primeru klica na številko 678 se pri prvem klicu v Asteriskovi bazi ustvari 'družina' test s 'spremenljivko' count, ki se ji priredi vrednost '1' (vrstica Set(DB(test/count)=1)). Vrednost spremenljivke se v času, dokler je klic vzpostavljen, povečuje za 1 (vrstica Set(COUNT=$[${COUNT} + 1]), strežnik pa nam predvaja glasovno sporočilo (vrstica SayNumber(${COUNT})) – dejansko šteje navzgor. Kot se za inteligenten sistem spodobi, v primeru prekinitve klica in po ponovni vzpostavitvi strežnik nadaljuje s štetjem tam, kjer smo 'pogovor' prekinili. Skrivnost je v zapisovanju trenutne vrednosti v lokalno bazo. Trenutno vrednost lahko preverimo z ukazom database show test (v našem primeru je bil odgovor /test/count: 7). Vrednost lahko tudi ročno spremenimo s pomočjo ukaza database put test count 100 in priredimo naši spremenljivki novo vrednost 100. Če pokličemo na številko 876, bo sistem odšteval od 100 navzdol oziroma če bomo zvezo prekinili, od tam, kjer smo končali. V primeru izmeničnega klicanja na številki 678 in 876 bo strežnik izmenično štel navzgor oziroma navzdol.

Naredimo kompleksnejši zgled. Ob klicu na številko 888 bomo po vzpostavitvi povezave vnesli prek DTMF-tonov dve poljubni (trimestni) števili, strežnik pa nas bo s sporočili vodil, ponovil obe števili in na koncu izračunal vsoto.

exten => 888,1,Answer()
same => n,Background(beep)
same => n,Playback(please-enter-the&first&number)
same => n,Read(a,,,,,3)
;same => n,wait(3)
same => n,SayNumber(${a})
same => n,Playback(beep)
same => n,Playback(please-enter-the&second&number)
same => n,Read(b,,,,,3)
;same => n,Wait(3)
same => n,SayNumber(${b})
same => n,Playback(beep)
same => n,Wait(0.5)
same => n,Playback(beep)
same => n,Set(c=$[${a}+${b}]
same => n,SayNumber(${a})
same => n,Playback(plus)
same => n,SayNumber(${b}
same => n,Playback(is)
same => n,SayNumber(${c})
same => n,Hangup()

Vse ukaze in uporabljene gradnike smo že spoznali. Dodatno pojasnilo zasluži le uporabljeni Playback, v katerem smo tokrat s pomočjo '&' skupaj 'zlepili' različne datoteke (datoteko please-enter-the, datoteko first in datoteko number). Vse uporabljene zvočne datoteke so že pripravljene v imeniku /var/lib/asterisk/sounds/.

V primeru morebitnih težav moramo izvesti določene akcije. To storimo običajno s pomočjo različnih skript ali prek oddaljenega dostopa (na primer VPN-povezave, SSH …). Posamezna dejanja pa lahko preprosto aktiviramo tudi s pomočjo klica na določeno številko. V našem primeru bomo s pomočjo klica na številko 987 izvedli ponoven zagon našega strežnik. Kot varnostni mehanizem je uporabljena številka kličočega. Če bo klic prišel s številke 1234, se bo ukaz shutdown -r now aktiviral, v primeru klica z druge številke pa se bo zveza le prekinila. Na tak način smo preprečili morebitno 'zlorabo' oziroma nepotrebni ponovni zagon v primeru klica na 'napačne številke'.

exten => 987,1,Answer()
same => n,Verbose(3,stevilka ki jo ujamem je ${CALLERID(num)})
same => n,GotoIf($[${CALLERID(num)}=1234]?mojmikro:ostali)
same => n(mojmikro),Playback(beep)
same => n,SayNumber(3)
same => n,SayNumber(2)
same => n,SayNumber(1)
same => n,System(sudo shutdown -r now)
same => n,Hangup()
same => n(ostali),Hangup()

Elastix omogoča preprost način vzpostavitve konferenčnega strežnika prek grafičnega menija (PBX-Conferences). Tako definiran strežnik omogoča govorno zvezo več uporabnikov, ki so jim namenjene posamezne konferenčne sobe. Privzeti grafični vmesnik pa omogoča sorazmerno malo nastavitev, saj lahko za vse uporabnike ene konferenčne sobe določimo le eno uporabniško in eno administratorsko geslo. Pri resnejši uporabi se to lahko izkaže za težavo, saj moramo, če želimo le enemu uporabniku omejiti dostop, zamenjati geslo za vse uporabnike. Bistveno lažje je, če ima vsak uporabnik ločeno geslo, ki je lahko različno za vsako konferenčno sobo. Konferenčni strežnik v skladu z našo željo bomo vzpostavili s spodaj navedenim vpisom v datoteki extensions_custom.conf:

exten => 777,1,Answer()
same => n,Read(conf_num,enter-conf-call-number,4)
same => n,Verbose(3,${conf_num}${CALLERID(num)})
same => n,set(passpin=${DB(conf/${conf_num}${CALLERID(num)}})
same => n,System("mkdir /tmp/${CALLERID(num)}")
same => n,System("date >> /tmp/${CALLERID(num)}/dnevnik")
same => n,System("echo ${conf_num} >> /tmp/${CALLERID(num)}/dnevnik")
same => n,Authenticate(${passpin})
same => n,MeetMe(${conf_num},siMDc,${passpin})
same => n,Hangup()

V primeru klica na številko 777 bo vrstica Read pozvala uporabnika prek zvočnega sporočila, da naj vnese številko konferenčne sobe. Vrstica Verbose je namenjena nadzoru in v Asteriskovi ukazni vrstici izpiše zajeta parametra – številko konferenčne sobe, ki je vnesena s pomočjo DTMF-tona, ter interno številko, s katere oseba kliče. Vrstica, ki sledi, priredi spremenljivki passpin vrednost, ki se prebere iz lokalne Asteriskove baze (družina conf, spremenljivka oziroma vrednost, ki je sestavljena iz številke konferenčne sobe in številke kličočega). Vrstice System v imeniku /tmp ustvarijo imenik z imenom številke kličočega, v njej ustvarijo (če je še ni) datoteko dnevnik in vanjo zapišejo čas prijave uporabnika na konferenčni strežnik. Sledijo vrstice za overjanje in prijavo v izbrano konferenčno sobo, v skladu s parametri (s = dostop do menija ob pritisku na *, i = najava ob prijavi uporabnikov, M = glasba na čakanju, če je uporabnik sam v konferenčni sobi, D = možnost dinamičnega dodajanja konference, C = nadaljevanje po izhodu iz konference). Preden je strežnik uporaben, moramo v bazo dodati še vnose v obliki database put conf soba&klicna_številka geslo. V našem primeru smo vpisali:

Kitty omogoča pošiljanje ukazov prek SSH

database put conf 4321100 7357
database put conf 4321101 007
database put conf 1234100 001122
database put conf 1234101 123

Tako smo definirali, da je v primeru klica s številke 100 geslo za dostop do sobe 4321 7357, z iste številke pa je dostop do sobe 1234 mogoč z geslom 001122. V primeru klica s številke 101 je omogočen dostop do konferenčne sobe 4321 z geslom 007, do sobe 1234 pa z geslom 123. Posameznikom lahko omogočimo z istim geslom dostop do vseh sob ali pa jim omogočimo dostop do le nekaterih. Uporabniška gesla in dostope lahko hitro preverimo s pomočjo ukaza database show conf. Če naredite še uporabniku prijazen vmesnik (na primer prek spletnega brskalnika) za administriranje uporabniških računov na konferenčnem sistemu, že imate uporaben konferenčni strežnik, ki dostope do posameznih sob tudi beleži (/tmp/.../dnevnik).

Še lažje zagotovimo funkcionalnost obveščanja večjega števila uporabnikov. V datoteki extensions_custom.conf definiramo novo številko takole (vse skupaj je ena vrstica):

exten => 800,1,Page(Local/${DB(pagegroup/mem0)}@from-internal&Local/${DB(pagegroup/mem1)}@from-internal&Local/${DB(pagegroup/mem2)}@from-internal&Local/${DB(pagegroup/mem3)}@from-internal&Local/${DB(pagegroup/mem4)}@from-internal&Local/${DB(pagegroup/mem5)}@from-internal&Local/${DB(pagegroup/mem6)}@from-internal&Local/${DB(pagegroup/mem7)}@from-internal&Local/${DB(pagegroup/mem8)}@from-internal&Local/${DB(pagegroup/mem9)}@from-internal,d&A(obvestilo)).

S klicem na številko 800 aktiviramo proceduro, s katero strežnik hkrati pokliče številke, definirane v lokalni bazi, in jim po vzpostavitvi zveze predvajamo zvočno datoteko obvestila. Posameznega uporabnika vpišemo v obliki database put pagegroup mem_zaporedna_st. klicna_številka_uporabnika.

Na pozicijo 0 vpišimo številko 1234567 (database put pagegroup mem0 1234567), drugo številko 323123 pa vpišemo na pozicijo 5 (database put pagegroup mem5 323123). Ker sta definirani le dve številki, bo sistem ob klicu na številko 800 obvestil le dva uporabnika. Glede na do zdaj pridobljeno znanje verjetno ne bo težko pripraviti skripte, ki bo na želeno pozicijo vpisala številke uporabnikov, ki jih želimo obveščati in jim predvajati sporočilo, ki ga želimo. Seveda lahko brez težav definicijo prilagodimo tudi za več uporabnikov.

Namesto paralelnega poziva uporabnikov lahko definiramo tudi zaporedje pozivanja. Vrsto definiramo za številko 864:

exten => 864,1,Mixmonitor(odhodni.wav)
same => n,Dial(Local/123from-internal/n,10,A(beep)&g)
same => n,Dial(Local/45664@from-internal/n,10,A(beep)&g)
same => n,Dial(Local/78900@from-internal/n,10,A(beep)&g)
same => n,Hangup()

Samo zaporedje (ki bi delovalo ne glede na odgovor klicane številke) pa bi lahko definirali tudi s pomočjo Asteriskove funkcije Delay.

Oglejmo si še tokratni zadnji primer z uporabo Asteriskove baze. Definirajmo številko 853. Odziv je v primeru klica odvisen od vpisa v bazo, razlikoval pa se bo glede na številko kličočega:

exten => 853,1,Answer()
same => n,Verbose(3,********** Parameter, ki ga zapomnim, je ${CALLERID(num)} **********)
same => n,Set(INFO=${DB(INFO-i/${CALLERID(num)})})
same => n,Verbose(3, INFO= ${INFO})
same => n,SayPhonetic(${INFO})
same => n,Hangup()

V bazo pa dodamo vnose:

/INFO-i/100 : Test
/INFO-i/101 : 1357
/INFO-i/102 : 007
/INFO-i/103 : 2468
/INFO-i/104 : 97531
/INFO-i/105 : mojMikro

Če pokličemo na številko 853 s številke 100, bo odgovor test, s številke 101 1357, s številke 102 007 … Če bi definicijo nekoliko razširili, lahko dobimo preprosto storitev, ki nam sporoči želeno stanje (na primer stanje delovnih ur).

Na koncu si oglejmo še preprosto definicijo funkcije FollowMe. Morda boste razočarani, a definiranje je resnično trivialno. V datoteko extensions_custom.conf dodamo:

exten => 844,1,Answer()
same => n,Followme(${EXTEN},sandI)
same => n,Hangup()

zaporedje pa definiramo v datoteke /etc/asterisk/followme.conf (strežnik bo poskušal za 10 s vzpostaviti povezavo s številko 1322400, nato s številko 1323063 in na koncu še s številko 031135776):

[844]
context => from-internal
number => 1322400,10,1
number => 1323063,10,2
number => 031135776,10,3

ZA NAJZAHTEVNEJŠE

V prihodnjem, zadnjem članku si bomo med drugim ogledali možnosti povezovanja Asteriska z drugim strežnikom, spoznali možnosti razhroščevanja in nadzora parametrov, pomembnih za delovanje strežnika, ter pokukali v bazo, ki hrani kopico koristnih podatkov.

Se nadaljuje …


Zanimivosti

Konfiguracijske parametre in stanje strežnika Asterisk lahko spremljamo na različne načine. Privzeti grafični vmesniki ponujajo največkrat le najosnovnejše informacije o delovanju sistema. Naprednejši uporabniki pa potrebujejo običajno več informacij, ki jih lahko pridobijo na različne načine.

AMI lahko uporabljamo za različne namene. Glede na uporabniške pravice je mogoče prek tega vmesnika izvajati različne operacije, ki jih lahko uporabimo tudi za delovanje lastne aplikacije. Pri določanju uporabniških pravic za dostop pa moramo paziti, da ne pride do morebitne zlorabe sistema.

Asterisk lahko uporablja tudi lastno bazo. V to bazo zapisuje uporabniške nastavitve in beleži različna stanja. Baze ni treba posebej nameščati in je zelo preprosta za uporabo.

Šele razumevanje delovanja Asteriska omogoča razvoj želenih aplikacij. Na ravni aplikacij in funkcij je mogoče izvesti želeno funkcionalnost pogosto le v nekaj vrsticah.

Moj mikro, November December 2012 | Evan Ambrož