Passed
Push — develop ( aa0db1...06f5e3 )
by Портнов
11:38
created

ExtensionsConf::generateOtherExten()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 94
Code Lines 77

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 77
dl 0
loc 94
rs 8.5018
c 3
b 0
f 0
cc 1
nc 1
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * MikoPBX - free phone system for small business
4
 * Copyright (C) 2017-2020 Alexey Portnov and Nikolay Beketov
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with this program.
17
 * If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
namespace MikoPBX\Core\Asterisk\Configs;
21
22
use MikoPBX\Common\Models\IncomingRoutingTable;
23
use MikoPBX\Core\Asterisk\Configs\Generators\Extensions\{IncomingContexts, InternalContexts, OutgoingContext};
24
use MikoPBX\Core\System\{Storage, Util};
25
26
class ExtensionsConf extends CoreConfigClass
27
{
28
    public const ALL_NUMBER_EXTENSION = '_[0-9*#+a-zA-Z][0-9*#+a-zA-Z]!';
29
    public const DIGIT_NUMBER_EXTENSION = '_X!';
30
    protected string $description = 'extensions.conf';
31
32
    /**
33
     * Sorts array by priority field
34
     *
35
     * @param $a
36
     * @param $b
37
     *
38
     * @return int|null
39
     */
40
    public static function sortArrayByPriority(array $a, array $b): int
41
    {
42
        $aPriority = (int)($a['priority'] ?? 0);
43
        $bPriority = (int)($b['priority'] ?? 0);
44
        if ($aPriority === $bPriority) {
45
            return 0;
46
        }
47
48
        return ($aPriority < $bPriority) ? -1 : 1;
49
    }
50
51
    /**
52
     * Основной генератор extensions.conf
53
     */
54
    protected function generateConfigProtected(): void
55
    {
56
        /** @scrutinizer ignore-call */
57
        $conf              = "[globals] \n" .
58
            "TRANSFER_CONTEXT=internal-transfer; \n";
59
        if ($this->generalSettings['PBXRecordCalls'] === '1') {
60
            $conf .= "MONITOR_DIR=" . Storage::getMonitorDir() . " \n";
61
            $conf .= "MONITOR_STEREO=" . $this->generalSettings['PBXSplitAudioThread'] . " \n";
62
        }
63
        $conf .= "PBX_REC_ANNONCE_IN=" .ExtensionsAnnounceRecording::getPathAnnounceFile($this->generalSettings['PBXRecordAnnouncementIn'])."\n";
64
        $conf .= "PBX_REC_ANNONCE_OUT=".ExtensionsAnnounceRecording::getPathAnnounceFile($this->generalSettings['PBXRecordAnnouncementOut'])."\n";
65
        $conf .= $this->hookModulesMethod(CoreConfigClass::EXTENSION_GLOBALS);
66
        $conf .= "\n";
67
        $conf .= "\n";
68
        $conf .= "[general] \n";
69
70
        // Контекст для внутренних вызовов.
71
        $conf .= InternalContexts::generate();
72
        // Создаем диалплан внутренних учеток.
73
        $this->generateOtherExten($conf);
74
        // Контекст для внутренних переадресаций.
75
        $this->generateInternalTransfer($conf);
76
        // Создаем контекст хинтов.
77
        $this->generateSipHints($conf);
78
        // Создаем контекст (исходящие звонки).
79
        $conf .= OutgoingContext::generate();
80
81
        // Описываем контекст для публичных входящих.
82
        $conf .= $this->generatePublicContext();
83
84
        Util::fileWriteContent($this->config->path('asterisk.astetcdir') . '/extensions.conf', $conf);
85
        $confLua =  '-- extensions["test-default"] = {'.PHP_EOL.
86
                    '--    ["100"] = function(context, extension)'.PHP_EOL.
87
                    '--        app.playback("please-hold");'.PHP_EOL.
88
                    '--    end;'.PHP_EOL.
89
                    '-- -- Forbidden to describe contexts defined in extensions.conf. This will cause a crash asterisk.'.PHP_EOL.
90
                    '-- };';
91
        Util::fileWriteContent($this->config->path('asterisk.luaDialplanDir') . '/99-extensions-override.lua', $confLua);
92
    }
93
94
    /**
95
     * Генератор прочих контекстов.
96
     *
97
     * @param $conf
98
     */
99
    private function generateOtherExten(&$conf): void
100
    {
101
        // Контекст для AMI originate. Без него отображается не корректный CallerID.
102
        $conf .= '[sipregistrations]' . "\n\n";
103
        // messages
104
        // https://community.asterisk.org/t/messagesend-to-all-pjsip-contacts/75485/5
105
        $conf .= '[messages]' . PHP_EOL .
106
                 'exten => _X.,1,NoOp("Sending message, To ${MESSAGE(to)}, Hint ${ARG1}, From ${MESSAGE(from)}, CID ${CALLERID}, Body ${MESSAGE(body)}")' . PHP_EOL ."\t".
107
                 'same => n,Gosub(set-dial-contacts,${EXTEN},1)' . PHP_EOL ."\t".
108
                 'same => n,While($["${SET(contact=${SHIFT(DST_CONTACT,&):6})}" != ""])' . PHP_EOL ."\t".
109
                 'same => n,MessageSend(pjsip:${contact},${REPLACE(MESSAGE(from),-WS)})' . PHP_EOL ."\t".
110
                 'same => n,NoOp("Send status is ${MESSAGE_SEND_STATUS}")' . PHP_EOL ."\t".
111
                 'same => n,EndWhile' . PHP_EOL ."\t".
112
                 'same => n,HangUp()' . PHP_EOL .PHP_EOL;
113
114
        $conf .= '[internal-originate]' . PHP_EOL .
115
            'exten => _.!,1,Set(pt1c_cid=${FILTER(\*\#\+1234567890,${pt1c_cid})})' . PHP_EOL . "\t" .
116
            'same => n,Set(MASTER_CHANNEL(ORIGINATE_DST_EXTEN)=${pt1c_cid})' . PHP_EOL . "\t" .
117
            'same => n,Set(number=${FILTER(\*\#\+1234567890,${EXTEN})})' . PHP_EOL . "\t" .
118
            'same => n,ExecIf($["${EXTEN}" != "${number}"]?Goto(${CONTEXT},${number},$[${PRIORITY} + 1]))' . PHP_EOL . "\t" .
119
            'same => n,Set(__IS_ORGNT=${EMPTY})' . PHP_EOL . "\t" .
120
121
            'same => n,Gosub(interception_start,${EXTEN},1)' . PHP_EOL . "\t" .
122
            'same => n,ExecIf($["${pt1c_cid}x" != "x"]?Set(CALLERID(num)=${pt1c_cid}))' . PHP_EOL . "\t" .
123
            'same => n,ExecIf($["${origCidName}x" != "x"]?Set(CALLERID(name)=${origCidName}))' . PHP_EOL . "\t" .
124
            'same => n,ExecIf($["${SRC_QUEUE}x" != "x"]?Goto(internal-originate-queue,${EXTEN},1))' . PHP_EOL . "\t" .
125
            'same => n,ExecIf($["${CUT(CHANNEL,\;,2)}" == "2"]?Set(__PT1C_SIP_HEADER=${SIPADDHEADER})) ' . PHP_EOL . "\t" .
126
            'same => n,GosubIf($["${DIALPLAN_EXISTS(${CONTEXT}-custom,${EXTEN},1)}" == "1"]?${CONTEXT}-custom,${EXTEN},1)' . PHP_EOL . "\t" .
127
            'same => n,ExecIf($["${PJSIP_ENDPOINT(${EXTEN},auth)}x" == "x"]?Goto(internal-num-undefined,${EXTEN},1))' . PHP_EOL . "\t" .
128
            'same => n,Gosub(set-dial-contacts,${EXTEN},1)' . PHP_EOL . "\t" .
129
            'same => n,ExecIf($["${FIELDQTY(DST_CONTACT,&)}" != "1" && "${ALLOW_MULTY_ANSWER}" != "1"]?Set(__PT1C_SIP_HEADER=${EMPTY_VAR}))' . PHP_EOL . "\t" .
130
            'same => n,ExecIf($["${DST_CONTACT}x" != "x"]?Dial(${DST_CONTACT},${ringlength},TtekKHhb(originate-create-channel,${EXTEN},1)U(originate-answer-channel),s,1)))' . PHP_EOL.
131
            'exten => h,1,Gosub(interception_bridge_result,${EXTEN},1)' . "\n\n".
132
133
            '[internal-originate-queue]' . PHP_EOL .
134
            'exten => _X!,1,Set(_NOCDR=1)' . PHP_EOL . "\t" .
135
            'same => n,GosubIf($["${DIALPLAN_EXISTS(${CONTEXT}-custom,${EXTEN},1)}" == "1"]?${CONTEXT}-custom,${EXTEN},1)' . PHP_EOL . "\t" .
136
            'same => n,ExecIf($["${SRC_QUEUE}x" != "x"]?Queue(${SRC_QUEUE},kT,,,300,,,originate-answer-channel))' . PHP_EOL . PHP_EOL .
137
            'exten => h,1,Hangup' . "\n\n".
138
139
            '[originate-create-channel] ' . PHP_EOL .
140
            'exten => _.!,1,ExecIf($[ "${EXTEN}" == "h" ]?Hangup()'. PHP_EOL . "\t" .
141
            'same => n,ExecIf($["${PT1C_SIP_HEADER}x" != "x"]?Set(PJSIP_HEADER(add,${CUT(PT1C_SIP_HEADER,:,1)})=${CUT(PT1C_SIP_HEADER,:,2)})) ' . PHP_EOL . "\t" .
142
            'same => n,Set(__PT1C_SIP_HEADER=${UNDEFINED}) ' . PHP_EOL . "\t" .
143
            'same => n,return' . PHP_EOL . PHP_EOL .
144
145
            '[originate-answer-channel]' . PHP_EOL .
146
            'exten => s,1,Set(IS_ORGNT=${EMPTY})' . PHP_EOL . "\t" .
147
            'same => n,Set(orign_chan=${CHANNEL})' . PHP_EOL . "\t" .
148
            'same => n,ExecIf($[ "${CHANNEL:0:5}" == "Local" ]?Set(pl=${IF($["${CHANNEL:-1}" == "1"]?2:1)}))' . PHP_EOL . "\t" .
149
            'same => n,ExecIf($[ "${CHANNEL:0:5}" == "Local" ]?Set(orign_chan=${IMPORT(${CUT(CHANNEL,\;,1)}\;${pl},DIALEDPEERNAME)}))' . PHP_EOL . "\t" .
150
            'same => n,Set(MASTER_CHANNEL(ORIGINATE_SRC_CHANNEL)=${orign_chan})' . PHP_EOL . "\t" .
151
            'same => n,return' . PHP_EOL . PHP_EOL;
152
153
        $conf .= '[dial_create_chan]' . " \n";
154
        $conf .= 'exten => s,1,Gosub(lua_${ISTRANSFER}dial_create_chan,${EXTEN},1)' . "\n\t";
155
        $conf .= 'same => n,Set(pt1c_is_dst=1)' . " \n\t";
156
        $conf .= 'same => n,ExecIf($["${PT1C_SIP_HEADER}x" != "x"]?Set(PJSIP_HEADER(add,${CUT(PT1C_SIP_HEADER,:,1)})=${CUT(PT1C_SIP_HEADER,:,2)}))' . " \n\t";
157
        $conf .= 'same => n,Set(__PT1C_SIP_HEADER=${UNDEFINED})' . " \n\t";
158
        $conf .= 'same => n,Set(CHANNEL(hangup_handler_wipe)=hangup_handler,s,1)' . " \n\t";
159
        $conf .= 'same => n,return' . " \n\n";
160
161
        $conf .= '[hangup_handler]' . "\n";
162
        $conf .= 'exten => s,1,NoOp(--- hangup - ${CHANNEL} ---)' . "\n\t";
163
        $conf .= 'same => n,Gosub(hangup_chan,${EXTEN},1)' . "\n\t";
164
165
        $conf .= 'same => n,return' . "\n\n";
166
167
        $conf .= '[set_orign_chan]' . "\n";
168
        $conf .= 'exten => s,1,Wait(0.2)' . "\n\t";
169
        $conf .= 'same => n,Set(pl=${IF($["${CHANNEL:-1}" == "1"]?2:1)})' . "\n\t";
170
        $conf .= 'same => n,Set(orign_chan=${IMPORT(${CUT(CHANNEL,\;,1)}\;${pl},BRIDGEPEER)})' . "\n\t";
171
        $conf .= 'same => n,ExecIf($[ "${orign_chan}x" == "x" ]?Set(orign_chan=${IMPORT(${CUT(CHANNEL,\;,1)}\;${pl},TRANSFERERNAME)}))' . "\n\t";
172
        $conf .= 'same => n,ExecIf($[ "${orign_chan}x" == "x" ]?Set(orign_chan=${IMPORT(${CUT(CHANNEL,\;,1)}\;${pl},FROM_CHAN)}))' . "\n\t";
173
        $conf .= 'same => n,ExecIf($[ "${QUEUE_SRC_CHAN}x" != "x" ]?Set(__QUEUE_SRC_CHAN=${orign_chan}))' . "\n\t";
174
        $conf .= 'same => n,ExecIf($[ "${QUEUE_SRC_CHAN:0:5}" == "Local" ]?Set(__QUEUE_SRC_CHAN=${FROM_CHAN}))' . "\n\t";
175
        $conf .= 'same => n,ExecIf($[ "${FROM_CHAN}x" == "x" ]?Set(__FROM_CHAN=${IMPORT(${CUT(CHANNEL,\;,1)}\;${pl},BRIDGEPEER)}))' . "\n\t";
176
        $conf .= 'same => n,return' . "\n\n";
177
178
        $conf .= '[playback]' . "\n";
179
        $conf .= 'exten => s,1,Playback(hello_demo,noanswer)' . "\n\t";
180
        $conf .= 'same => n,ExecIf($["${SRC_BRIDGE_CHAN}x" == "x"]?Wait(30))' . "\n\t";
181
        $conf .= 'same => n,Wait(0.3)' . "\n\t";
182
        $conf .= 'same => n,Bridge(${SRC_BRIDGE_CHAN},kKTthH)' . "\n\n";
183
184
        $conf .= 'exten => h,1,ExecIf($["${ISTRANSFER}x" != "x"]?Goto(transfer_dial_hangup,${EXTEN},1))' . "\n\n";
185
186
        $conf .= '[add-trim-prefix-clid]' . "\n";
187
        $conf .= 'exten => ' . self::ALL_NUMBER_EXTENSION . ',1,NoOp(--- Incoming call from ${CALLERID(num)} ---)' . "\n\t";
188
        $conf .= 'same => n,GosubIf($["${DIALPLAN_EXISTS(${CONTEXT}-custom,${EXTEN},1)}" == "1"]?${CONTEXT}-custom,${EXTEN},1)' . "\n\t";
189
        $conf .= 'same => n,return' . "\n\n";
190
        $conf .= 'exten => ' . self::DIGIT_NUMBER_EXTENSION . ',1,NoOp(--- Incoming call from ${CALLERID(num)} ---)' . "\n\t";
191
        $conf .= 'same => n,GosubIf($["${DIALPLAN_EXISTS(${CONTEXT}-custom,${EXTEN},1)}" == "1"]?${CONTEXT}-custom,${EXTEN},1)' . "\n\t";
192
        $conf .= 'same => n,return' . "\n\n";
193
    }
194
195
    /**
196
     * Генератор контекста для переадресаций.
197
     *
198
     * @param $conf
199
     */
200
    private function generateInternalTransfer(&$conf): void
201
    {
202
        $conf              .= "[internal-transfer] \n";
203
        $conf .= $this->hookModulesMethod(CoreConfigClass::GET_INCLUDE_INTERNAL_TRANSFER);
204
        $conf .= $this->hookModulesMethod(CoreConfigClass::EXTENSION_GEN_INTERNAL_TRANSFER);
205
        $conf .= 'exten => h,1,Goto(transfer_dial_hangup,${EXTEN},1)' . "\n\n";
206
    }
207
208
    /**
209
     * Генератор хинтов SIP.
210
     *
211
     * @param $conf
212
     */
213
    private function generateSipHints(&$conf): void
214
    {
215
        $conf .= "[internal-hints] \n";
216
        $conf .= $this->hookModulesMethod(CoreConfigClass::EXTENSION_GEN_HINTS);
217
        $conf .= "\n\n";
218
    }
219
220
    /**
221
     * Контекст для входящих внешних звонков без авторизации.
222
     *
223
     */
224
    public function generatePublicContext(): string
225
    {
226
        $conf              = "\n";
227
        $conf              .= IncomingContexts::generate('none');
228
        $conf              .= "[public-direct-dial] \n";
229
        $conf .= $this->hookModulesMethod(CoreConfigClass::GENERATE_PUBLIC_CONTEXT);
230
        $filter = ["provider IS NULL AND priority<>9999"];
231
232
        /**
233
         * @var array
234
         */
235
        $m_data = IncomingRoutingTable::find($filter);
236
        if (count($m_data->toArray()) > 0) {
237
            $conf .= 'include => none-incoming';
238
        }
239
240
        return $conf;
241
    }
242
243
    public static function getExtenByDid($did):string
244
    {
245
        if(mb_strpos($did, '_') === 0){
246
            $ext_prefix = '';
247
        }elseif(preg_match_all('/^[.|!|N|X|Z|0-9|\[|\]|\-]+$/m', $did, $matches, PREG_SET_ORDER) === 1){
248
            // Это скорее всего шаблон EXTEN.
249
            $ext_prefix = '_';
250
        }else{
251
            $ext_prefix = '';
252
        }
253
        return $ext_prefix.$did;
254
    }
255
}