Passed
Push — develop ( 8d717c...9d129a )
by Портнов
05:17 queued 10s
created

InternalContexts::generateInternalUsers()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 36
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 22
c 1
b 0
f 0
dl 0
loc 36
rs 9.568
cc 1
nc 1
nop 0
1
<?php
2
3
4
namespace MikoPBX\Core\Asterisk\Configs\Generators\Extensions;
5
6
7
use MikoPBX\Common\Providers\PBXConfModulesProvider;
8
use MikoPBX\Core\Asterisk\Configs\SIPConf;
9
use MikoPBX\Modules\Config\ConfigClass;
10
use Phalcon\Di;
11
12
class InternalContexts extends ConfigClass {
13
14
15
    private array  $additionalModules = [];
16
    private string $technology;
17
    private string $extensionPattern = 'X!';
18
19
    public function getSettings(): void
20
    {
21
        $di = Di::getDefault();
22
        if ($di !== null) {
23
            $this->additionalModules = $di->getShared(PBXConfModulesProvider::SERVICE_NAME);
24
        }
25
        $this->technology = SIPConf::getTechnology();
26
    }
27
28
    /**
29
     * Генератор входящих контекстов. Точка входа.
30
     * @return string
31
     */
32
    public static function generate(): string
33
    {
34
        $generator = new self();
35
        $generator->getSettings();
36
        return $generator->makeDialplan();
37
    }
38
39
    /**
40
     * Генерация dialplan.
41
     * @return string
42
     */
43
    public function makeDialplan():string
44
    {
45
        $conf  = $this->generateAdditionalModulesContext();
46
47
        $conf .= "[internal-num-undefined] \n";
48
        $conf .= 'exten => _' . $this->extensionPattern . ',1,ExecIf($["${ISTRANSFER}x" != "x"]?Gosub(${ISTRANSFER}dial_hangup,${EXTEN},1))' . "\n\t";
49
        $conf .= 'same => n,ExecIf($["${BLINDTRANSFER}x" != "x"]?AGI(check_redirect.php,${BLINDTRANSFER}))' . "\n\t";
50
        $conf .= "same => n,Playback(pbx-invalid,noanswer) \n\n";
51
52
        $conf .= $this->generateInternalFW();
53
        $conf .= $this->generateAllPeers();
54
55
        $conf .= "[voice_mail_peer] \n";
56
        $conf .= 'exten => voicemail,1,Answer()' . "\n\t";
57
        $conf .= 'same => n,VoiceMail(admin@voicemailcontext)' . "\n\t";
58
        $conf .= 'same => n,Hangup()' . "\n\n";
59
60
        $conf .= $this->generateInternal();
61
        $conf .= $this->generateInternalUsers();
62
63
        return $conf;
64
    }
65
66
    /**
67
     * Генератор [internal] dialplan.
68
     * @return string
69
     */
70
    private function generateInternal():string
71
    {
72
        // Контекст для внутренних вызовов.
73
        $conf = "[internal] \n";
74
        $conf .= $this->generateAdditionalModulesInternalContext();
75
76
        $conf .= 'exten => i,1,NoOp(-- INVALID NUMBER --)' . "\n\t";
77
        $conf .= 'same => n,Set(DIALSTATUS=INVALID_NUMBER)' . "\n\t";
78
        $conf .= 'same => n,Playback(privacy-incorrect,noanswer)' . "\n\t";
79
        $conf .= 'same => n,Hangup()' . "\n";
80
81
        $conf .= 'exten => h,1,ExecIf($["${ISTRANSFER}x" != "x"]?Gosub(${ISTRANSFER}dial_hangup,${EXTEN},1))' . "\n\n";
82
83
        $conf .= "[internal-incoming]\n";
84
        $conf .= 'exten => _.!,1,ExecIf($["${MASTER_CHANNEL(M_TIMEOUT)}x" != "x"]?Set(TIMEOUT(absolute)=${MASTER_CHANNEL(M_TIMEOUT)}))' . " \n\t";
85
        $conf .= 'same => n,Set(MASTER_CHANNEL(M_TIMEOUT_CHANNEL)=${CHANNEL})' . " \n\t";
86
        $conf .= 'same => n,Set(MASTER_CHANNEL(M_TIMEOUT)=${EMPTY_VAR})' . " \n\t";
87
        $conf .= 'same => n,Goto(internal,${EXTEN},1)' . " \n\n";
88
89
        return $conf;
90
    }
91
92
    /**
93
     * Генератор [internal-users] dialplan.
94
     * @return string
95
     */
96
    private function generateInternalUsers():string
97
    {
98
        $conf  = "[internal-users] \n";
99
        $conf .= 'exten => _' . $this->extensionPattern . ',1,Set(CHANNEL(hangup_handler_wipe)=hangup_handler,s,1)' . " \n\t";
100
        $conf .= 'same => n,ExecIf($["${ISTRANSFER}x" != "x"]?Set(SIPADDHEADER01=${EMPTY_VAR})' . " \n\t";
101
        $conf .= 'same => n,ExecIf($["${CHANNEL(channeltype)}" == "Local"]?Gosub(set_orign_chan,s,1))' . " \n\t";
102
103
        $conf .= 'same => n,Gosub(${ISTRANSFER}dial,${EXTEN},1)' . "\n\t";
104
        // Проверим, существует ли такой пир.
105
106
        $conf .= 'same => n,ExecIf($["${PJSIP_ENDPOINT(${EXTEN},auth)}x" == "x"]?Goto(internal-num-undefined,${EXTEN},1))' . " \n\t";
107
        $conf .= 'same => n,ExecIf($["${DEVICE_STATE(' . $this->technology . '/${EXTEN})}" == "BUSY"]?Set(DIALSTATUS=BUSY))' . " \n\t";
108
        $conf .= 'same => n,GotoIf($["${DEVICE_STATE(' . $this->technology . '/${EXTEN})}" == "BUSY"]?fw_start)' . " \n\t";
109
110
        // Как долго звонить пиру.
111
        $conf .= 'same => n,Set(ringlength=${DB(FW_TIME/${EXTEN})})' . " \n\t";
112
        $conf .= 'same => n,ExecIf($["${ringlength}x" == "x"]?Set(ringlength=600))' . " \n\t";
113
        $conf .= 'same => n,ExecIf($["${QUEUE_SRC_CHAN}x" != "x" && "${ISTRANSFER}x" == "x"]?Set(ringlength=600))' . " \n\t";
114
115
        $conf .= 'same => n,GosubIf($["${DIALPLAN_EXISTS(${CONTEXT}-custom,${EXTEN},1)}" == "1"]?${CONTEXT}-custom,${EXTEN},1) ' . " \n\t";
116
        // Совершаем вызов пира.
117
        $conf .= 'same => n,Set(DST_CONTACT=${PJSIP_DIAL_CONTACTS(${EXTEN})})' . " \n\t";
118
        $conf .= 'same => n,ExecIf($["${FIELDQTY(DST_CONTACT,&)}" != "1"]?Set(__PT1C_SIP_HEADER=${EMPTY_VAR}))' . " \n\t";
119
        $conf .= 'same => n,ExecIf($["${DST_CONTACT}x" != "x"]?Dial(${DST_CONTACT},${ringlength},TtekKHhU(${ISTRANSFER}dial_answer)b(dial_create_chan,s,1)):Set(DIALSTATUS=CHANUNAVAIL))' . " \n\t";
120
        $conf .= 'same => n(fw_start),NoOp(dial_hangup)' . " \n\t";
121
122
        // QUEUE_SRC_CHAN - установлена, если вызов сервершен агенту очереди.
123
        // Проверяем нужна ли переадресация
124
        $conf .= 'same => n,ExecIf($["${DIALSTATUS}" != "ANSWER" && "${ISTRANSFER}x" != "x"]?Goto(internal-fw,${EXTEN},1))' . " \n\t";
125
        $conf .= 'same => n,ExecIf($["${DIALSTATUS}" != "ANSWER" && "${QUEUE_SRC_CHAN}x" == "x"]?Goto(internal-fw,${EXTEN},1))' . " \n\t";
126
        $conf .= 'same => n,ExecIf($["${BLINDTRANSFER}x" != "x"]?AGI(check_redirect.php,${BLINDTRANSFER}))' . " \n\t";
127
        $conf .= 'same => n,Hangup()' . "\n\n";
128
129
        $conf .= 'exten => h,1,ExecIf($["${ISTRANSFER}x" != "x"]?Gosub(${ISTRANSFER}dial_hangup,${EXTEN},1))' . "\n\n";
130
131
        return $conf;
132
    }
133
134
    /**
135
     * Генератор [all_peers] dialplan.
136
     * @return string
137
     */
138
    private function generateAllPeers():string
139
    {
140
        $conf = "[all_peers]\n";
141
        $conf .= 'include => internal-hints' . "\n";
142
        $conf .= 'exten => failed,1,Hangup()' . "\n";
143
144
        $conf .= 'exten => _.!,1,ExecIf($[ "${EXTEN}" == "h" ]?Hangup())' . "\n\t";
145
        // Фильтр спецсимволов. Разершаем только цифры.
146
        $conf .= 'same => n,Set(cleanNumber=${FILTER(\*\#\+1234567890,${EXTEN})})' . "\n\t";
147
        $conf .= 'same => n,ExecIf($["${EXTEN}" != "${cleanNumber}"]?Goto(${CONTEXT},${cleanNumber},$[${PRIORITY} + 1]))' . "\n\t";
148
149
        $conf .= 'same => n,Set(__FROM_CHAN=${CHANNEL})' . "\n\t";
150
        $conf .= 'same => n,ExecIf($["${OLD_LINKEDID}x" == "x"]?Set(__OLD_LINKEDID=${CHANNEL(linkedid)}))' . "\n\t";
151
        $conf .= 'same => n,ExecIf($["${CHANNEL(channeltype)}" != "Local"]?Gosub(set_from_peer,s,1))' . "\n\t";
152
        $conf .= 'same => n,ExecIf($["${CHANNEL(channeltype)}" == "Local"]?Gosub(set_orign_chan,s,1))' . "\n\t";
153
154
        $conf .= 'same => n,ExecIf($["${CALLERID(num)}x" == "x"]?Set(CALLERID(num)=${FROM_PEER}))' . "\n\t";
155
        $conf .= 'same => n,ExecIf($["${CALLERID(num)}x" == "x"]?Set(CALLERID(name)=${FROM_PEER}))' . "\n\t";
156
157
        $conf .= 'same => n,ExecIf($["${CHANNEL(channeltype)}" == "Local" && "${FROM_PEER}x" == "x"]?Set(__FROM_PEER=${CALLERID(num)}))' . "\n\t";
158
        $conf .= 'same => n,Set(CHANNEL(hangup_handler_wipe)=hangup_handler,s,1)' . "\n\t";
159
        $conf .= 'same => n,Gosub(${ISTRANSFER}dial,${EXTEN},1)' . "\n\t";
160
161
        $conf .= 'same => n,GosubIf($["${DIALPLAN_EXISTS(${CONTEXT}-custom,${EXTEN},1)}" == "1"]?${CONTEXT}-custom,${EXTEN},1)' . "\n\t";
162
        $dialplanNames = ['applications', 'internal', 'outgoing'];
163
        foreach ($dialplanNames as $name){
164
            $conf .= 'same => n,GosubIf($["${DIALPLAN_EXISTS('.$name.',${EXTEN},1)}" == "1"]?'.$name.',${EXTEN},1)'." \n\t";
165
        }
166
        $conf .= 'same => n,Hangup()'." \n";
167
168
        $pickupExtension  = $this->generalSettings['PBXFeaturePickupExten'];
169
        $conf        .= 'exten => _' . $pickupExtension . $this->extensionPattern . ',1,Set(PICKUPEER=' . $this->technology . '/${FILTER(0-9,${EXTEN:2})})' . "\n\t";
170
        $conf        .= 'same => n,Set(pt1c_dnid=${EXTEN})' . "\n\t";
171
        $conf        .= 'same => n,PickupChan(${PICKUPEER})' . "\n\t";
172
        $conf        .= 'same => n,Hangup()' . "\n\n";
173
174
        $voicemailExtension  = $this->generalSettings['VoicemailExten'];
175
        $conf            .= 'exten => ' . $voicemailExtension . ',1,NoOp(NOTICE, Dialing out from ${CALLERID(all)} to VoiceMail)' . "\n\t";
176
        $conf            .= 'same => n,VoiceMailMain(admin@voicemailcontext,s)' . "\n\t";
177
        $conf            .= 'same => n,Hangup()' . "\n\n";
178
179
        return $conf;
180
    }
181
182
    /**
183
     * Генератор [internal-fw] dialplan.
184
     * @return string
185
     */
186
    private function generateInternalFW():string
187
    {
188
        $conf  = "[internal-fw]\n";
189
        $conf .= 'exten => _' . $this->extensionPattern . ',1,NoOp(DIALSTATUS - ${DIALSTATUS})' . "\n\t";
190
        // CANCEL - вызов был отменен, к примеру *0, не нужно дальше искать адресат.
191
        $conf .= 'same => n,ExecIf($["${DIALSTATUS}" == "CANCEL"]?Hangup())' . "\n\t";
192
        // BUSY - занято. К примру абонент завершил вызов или DND.
193
        $conf .= 'same => n,ExecIf($["${DIALSTATUS}" == "BUSY"]?Set(dstatus=FW_BUSY))' . "\n\t";
194
        // CHANUNAVAIL - канал не доступен. К примеру телефон не зарегистрирован или не отвечает.
195
        $conf .= 'same => n,ExecIf($["${DIALSTATUS}" == "CHANUNAVAIL"]?Set(dstatus=FW_UNAV))' . "\n\t";
196
        // NOANSWER - не ответили по таймауту.
197
        $conf .= 'same => n,ExecIf($["${dstatus}x" == "x"]?Set(dstatus=FW))' . "\n\t";
198
        $conf .= 'same => n,Set(fw=${DB(${dstatus}/${EXTEN})})' . "\n\t";
199
        $conf .= 'same => n,ExecIf($["${fw}x" != "x"]?Set(__pt1c_UNIQUEID=${UNDEFINED})' . "\n\t";
200
        $conf .= 'same => n,ExecIf($["${fw}x" != "x"]?Goto(internal,${fw},1))' . "\n\t";
201
        $conf .= 'same => n,ExecIf($["${BLINDTRANSFER}x" != "x"]?AGI(check_redirect.php,${BLINDTRANSFER}))' . "\n\t";
202
        $conf .= 'same => n,Hangup() ' . "\n\n";
203
        return $conf;
204
    }
205
206
    /**
207
     * Генератор dialplan дополнительных модулей.
208
     * @return string
209
     */
210
    private function generateAdditionalModulesContext():string
211
    {
212
        $conf = '';
213
        foreach ($this->additionalModules as $appClass) {
214
            $addition = $appClass->extensionGenContexts();
215
            if ( ! empty($addition)) {
216
                $conf .= $appClass->confBlockWithComments($addition);
217
            }
218
        }
219
        $conf .= "\n";
220
        return $conf;
221
    }
222
223
    /**
224
     * Переопределение dialplan [internal] из дополнительных модулей.
225
     * @return string
226
     */
227
    private function generateAdditionalModulesInternalContext():string
228
    {
229
        $conf = '';
230
        foreach ($this->additionalModules as $appClass) {
231
            $addition = $appClass->getIncludeInternal();
232
            if ( ! empty($addition)) {
233
                $conf .= $appClass->confBlockWithComments($addition);
234
            }
235
        }
236
237
        foreach ($this->additionalModules as $appClass) {
238
            $addition = $appClass->extensionGenInternal();
239
            if ( ! empty($addition)) {
240
                $conf .= $appClass->confBlockWithComments($addition);
241
            }
242
        }
243
        return $conf;
244
    }
245
246
}