Passed
Pull Request — master (#20)
by Nikolay
04:51
created

SIPConf::generateConfigProtected()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 25
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 19
c 0
b 0
f 0
dl 0
loc 25
rs 9.6333
cc 3
nc 3
nop 0
1
<?php
2
/*
3
 * Copyright © MIKO LLC - All Rights Reserved
4
 * Unauthorized copying of this file, via any medium is strictly prohibited
5
 * Proprietary and confidential
6
 * Written by Alexey Portnov, 10 2020
7
 */
8
9
namespace MikoPBX\Core\Asterisk\Configs;
10
11
use MikoPBX\Common\Models\{Codecs,
12
    ExtensionForwardingRights,
13
    Extensions as ExtensionsModel,
14
    NetworkFilters,
15
    OutgoingRoutingTable,
16
    PbxSettings,
17
    Sip,
18
    Users};
19
use MikoPBX\Core\Asterisk\AstDB;
20
use MikoPBX\Modules\Config\ConfigClass;
21
use MikoPBX\Core\System\{MikoPBXConfig, Network, Util};
22
use MikoPBX\Core\Utilities\SubnetCalculator;
23
use Phalcon\Di;
24
25
class SIPConf extends ConfigClass
26
{
27
    public const TYPE_PJSIP = 'PJSIP';
28
29
    protected $data_peers;
30
    protected $data_providers;
31
    protected $data_rout;
32
    protected string $technology;
33
    protected array  $contexts_data;
34
35
    protected string $description = 'pjsip.conf';
36
37
    /**
38
     *
39
     * @return array
40
     */
41
    public function dependenceModels(): array
42
    {
43
        return [Sip::class, Users::class];
44
    }
45
46
    /**
47
     * Генератор sip.conf
48
     *
49
     * @return bool|void
50
     */
51
    protected function generateConfigProtected(): void
52
    {
53
        $conf = '';
54
        $conf .= $this->generateGeneralPj();
55
        $conf .= $this->generateProvidersPj();
56
        $conf .= $this->generatePeersPj();
57
58
        Util::fileWriteContent($this->config->path('asterisk.astetcdir') . '/pjsip.conf', $conf);
59
        $pjConf = '[log_mappings]'."\n".
60
            'type=log_mappings'."\n".
61
            'asterisk_error = 0'."\n".
62
            'asterisk_warning = 2'."\n".
63
            'asterisk_debug = 1,3,4,5,6'."\n\n";
64
65
        file_put_contents($this->config->path('asterisk.astetcdir') . '/pjproject.conf', $pjConf);
66
        file_put_contents($this->config->path('asterisk.astetcdir') . '/sorcery.conf', '');
67
68
        $db = new AstDB();
69
        foreach ($this->data_peers as $peer) {
70
            // Помещаем в AstDB сведения по маршуртизации.
71
            $ringlength = ($peer['ringlength'] == 0) ? '' : trim($peer['ringlength']);
72
            $db->databasePut('FW_TIME', "{$peer['extension']}", $ringlength);
73
            $db->databasePut('FW', "{$peer['extension']}", trim($peer['forwarding']));
74
            $db->databasePut('FW_BUSY', "{$peer['extension']}", trim($peer['forwardingonbusy']));
75
            $db->databasePut('FW_UNAV', "{$peer['extension']}", trim($peer['forwardingonunavailable']));
76
        }
77
    }
78
79
    /**
80
     * Генератора секции general pjsip.conf
81
     *
82
     *
83
     * @return string
84
     */
85
    private function generateGeneralPj(): string
86
    {
87
        $lang    = $this->generalSettings['PBXLanguage'];
88
        [$topology, $extipaddr, $exthostname, $subnets] = $this->getTopologyData();
89
90
        $codecs = $this->getCodecs();
91
        $codecConf = '';
92
        foreach ($codecs as $codec){
93
            $codecConf.= "allow = {$codec}\n";
94
        }
95
96
        $pbxVersion = PbxSettings::getValueByKey('PBXVersion');
97
        $natConf = '';
98
        if ($topology === 'private') {
99
            foreach ($subnets as $net) {
100
                $natConf .= "local_net={$net}\n";
101
            }
102
            if ( ! empty($exthostname)) {
103
                $parts = explode(':', $exthostname);
104
                $natConf  .= 'external_media_address=' . $parts[0] . "\n";
105
                $natConf  .= 'external_signaling_address=' . $parts[0] . "\n";
106
                $natConf  .= 'external_signaling_port=' . ($parts[1] ?? '5060');
107
            } elseif ( ! empty($extipaddr)) {
108
                $parts = explode(':', $extipaddr);
109
                $natConf  .= 'external_media_address=' . $parts[0] . "\n";
110
                $natConf  .= 'external_signaling_address=' . $parts[0] . "\n";
111
                $natConf  .= 'external_signaling_port=' . ($parts[1] ?? '5060');
112
            }
113
        }
114
115
        $conf = "[general] \n" .
116
            "disable_multi_domain=on\n" .
117
            "transport = udp \n\n" .
118
119
            "[global] \n" .
120
            "type = global\n" .
121
            "endpoint_identifier_order=username,ip,anonymous\n" .
122
            "user_agent = mikopbx-{$pbxVersion}\n\n" .
123
124
            "[anonymous]\n" .
125
            "type = endpoint\n" .
126
            $codecConf.
127
            "language={$lang}\n".
128
            "timers = no\n" .
129
            "context = public-direct-dial\n\n".
130
131
            "[transport-udp]\n" .
132
            "type = transport\n" .
133
            "protocol = udp\n" .
134
            "bind=0.0.0.0:{$this->generalSettings['SIPPort']}\n".
135
            "{$natConf}\n\n".
136
137
            "[transport-tcp]\n" .
138
            "type = transport\n" .
139
            "protocol = tcp\n" .
140
            "bind=0.0.0.0:{$this->generalSettings['SIPPort']}\n".
141
            "{$natConf}\n\n".
142
            '';
143
144
        $varEtcDir = $this->config->path('core.varEtcDir');
145
        file_put_contents($varEtcDir . '/topology_hash', md5($topology . $exthostname . $extipaddr. $this->generalSettings['SIPPort']));
146
        $conf .= "\n";
147
148
        return $conf;
149
    }
150
151
    /**
152
     * Проверка ключевых параметров.
153
     * Если параметры изменены, то необходим рестарт Asterisk процесса.
154
     * @return bool
155
     */
156
    public function needAsteriskRestart():bool{
157
        $di     = Di::getDefault();
158
        if ($di === null) {
159
            return false;
160
        }
161
        $mikoPBXConfig  = new MikoPBXConfig();
162
        [$topology, $extipaddr, $exthostname] = $this->getTopologyData();
163
164
        $generalSettings = $mikoPBXConfig->getGeneralSettings();
165
        $now_hadh = md5($topology . $exthostname . $extipaddr. $generalSettings['SIPPort']);
166
        $old_hash   = '';
167
        $varEtcDir = $di->getShared('config')->path('core.varEtcDir');
168
        if (file_exists($varEtcDir . '/topology_hash')) {
169
            $old_hash = file_get_contents($varEtcDir . '/topology_hash');
170
        }
171
172
        return $old_hash !== $now_hadh;
173
    }
174
175
    /**
176
     * @return array
177
     */
178
    private function getTopologyData():array{
179
        $network = new Network();
180
181
        $topology    = 'public';
182
        $extipaddr   = '';
183
        $exthostname = '';
184
        $networks    = $network->getEnabledLanInterfaces();
185
        $subnets     = [];
186
        foreach ($networks as $if_data) {
187
            $lan_config = $network->getInterface($if_data['interface']);
188
            if (empty($lan_config['ipaddr']) || empty($lan_config['subnet'])) {
189
                continue;
190
            }
191
            $sub = new SubnetCalculator($lan_config['ipaddr'], $lan_config['subnet']);
192
            $net = $sub->getNetworkPortion() . '/' . $lan_config['subnet'];
193
            if ($if_data['topology'] === 'private' && in_array($net, $subnets, true) === false) {
194
                $subnets[] = $net;
195
            }
196
            if (trim($if_data['internet']) === '1') {
197
                $topology    = trim($if_data['topology']);
198
                $extipaddr   = trim($if_data['extipaddr']);
199
                $exthostname = trim($if_data['exthostname']);
200
            }
201
        }
202
203
        $networks = NetworkFilters::find('local_network=1');
204
        foreach ($networks as $net) {
205
            if (in_array($net->permit, $subnets, true) === false) {
206
                $subnets[] = $net->permit;
207
            }
208
        }
209
210
        return array(
211
            $topology,
212
            $extipaddr,
213
            $exthostname,
214
            $subnets,
215
        );
216
217
    }
218
219
    /**
220
     * Генератор секции провайдеров в sip.conf
221
     *
222
     *
223
     * @return string
224
     */
225
    private function generateProvidersPj(): string
226
    {
227
        $conf        = '';
228
        $reg_strings = '';
229
        $prov_config = '';
230
        if ($this->data_providers===null){
231
            $this->getSettings();
232
        }
233
        foreach ($this->data_providers as $provider) {
234
            $manual_attributes = Util::parseIniSettings(base64_decode($provider['manualattributes'] ?? ''));
235
            $port              = (trim($provider['port']) === '') ? '5060' : $provider['port'];
236
237
            $need_register = $provider['noregister'] !== '1';
238
            if ($need_register) {
239
                $options     = [
240
                    'type'     => 'auth',
241
                    'username' => $provider['username'],
242
                    'password' => $provider['secret'],
243
                ];
244
                $reg_strings .= "[REG-AUTH-{$provider['uniqid']}]\n";
245
                $reg_strings .= Util::overrideConfigurationArray($options, $manual_attributes, 'registration-auth');
246
247
                $options     = [
248
                    'type'                        => 'registration',
249
                    // 'transport'                   => 'transport-udp',
250
                    'outbound_auth'               => "REG-AUTH-{$provider['uniqid']}",
251
                    'contact_user'                => $provider['username'],
252
                    'retry_interval'              => '30',
253
                    'max_retries'                 => '100',
254
                    'forbidden_retry_interval'    => '300',
255
                    'fatal_retry_interval'        => '300',
256
                    'expiration'                  => $this->generalSettings['SIPDefaultExpiry'],
257
                    'server_uri'                  => "sip:{$provider['host']}:{$port}",
258
                    'client_uri'                  => "sip:{$provider['username']}@{$provider['host']}:{$port}",
259
                ];
260
                $reg_strings .= "[REG-{$provider['uniqid']}] \n";
261
                $reg_strings .= Util::overrideConfigurationArray($options, $manual_attributes, 'registration');
262
            }
263
264
            if ('1' !== $provider['receive_calls_without_auth']) {
265
                $options     = [
266
                    'type'     => 'auth',
267
                    'username' => $provider['username'],
268
                    'password' => $provider['secret'],
269
                ];
270
                $prov_config .= "[{$provider['uniqid']}-OUT]\n";
271
                $prov_config .= Util::overrideConfigurationArray($options, $manual_attributes, 'endpoint-auth');
272
            }
273
274
            $defaultuser = (trim($provider['defaultuser']) === '') ? $provider['username'] : $provider['defaultuser'];
275
            if ( ! empty($defaultuser) && '1' !== $provider['receive_calls_without_auth']) {
276
                $contact = "sip:$defaultuser@{$provider['host']}:{$port}";
277
            } else {
278
                $contact = "sip:{$provider['host']}:{$port}";
279
            }
280
281
            $options     = [
282
                'type'               => 'aor',
283
                'max_contacts'       => '1',
284
                'contact'            => $contact,
285
                'maximum_expiration' => $this->generalSettings['SIPMaxExpiry'],
286
                'minimum_expiration' => $this->generalSettings['SIPMinExpiry'],
287
                'default_expiration' => $this->generalSettings['SIPDefaultExpiry'],
288
            ];
289
            if($provider['qualify'] === '1'){
290
                $options['qualify_frequency'] = $provider['qualifyfreq'];
291
                $options['qualify_timeout']   = '3.0';
292
            }
293
294
            $prov_config .= "[{$provider['uniqid']}]\n";
295
            $prov_config .= Util::overrideConfigurationArray($options, $manual_attributes, 'aor');
296
297
            $options     = [
298
                'type'     => 'identify',
299
                'endpoint' => $provider['uniqid'],
300
                'match'    => $provider['host'],
301
            ];
302
            $prov_config .= "[{$provider['uniqid']}]\n";
303
            $prov_config .= Util::overrideConfigurationArray($options, $manual_attributes, 'identify');
304
305
            $fromdomain = (trim($provider['fromdomain']) === '') ? $provider['host'] : $provider['fromdomain'];
306
            $from       = (trim(
307
                    $provider['fromuser']
308
                ) === '') ? "{$provider['username']}; username" : "{$provider['fromuser']}; fromuser";
309
            $from_user  = ($provider['disablefromuser'] === '1') ? null : $from;
310
            $lang       = $this->generalSettings['PBXLanguage'];
311
312
            if (count($this->contexts_data[$provider['context_id']]) === 1) {
313
                $context_id = $provider['uniqid'];
314
            } else {
315
                $context_id = $provider['context_id'];
316
            }
317
            $dtmfmode = ($provider['dtmfmode'] === 'rfc2833') ? 'rfc4733' : $provider['dtmfmode'];
318
            $options  = [
319
                'type'            => 'endpoint',
320
                '100rel'          => "no",
321
                'context'         => "{$context_id}-incoming",
322
                'dtmf_mode'       => $dtmfmode,
323
                'disallow'        => 'all',
324
                'allow'           => $provider['codecs'],
325
                'rtp_symmetric'   => 'yes',
326
                'force_rport'     => 'yes',
327
                'rewrite_contact' => 'yes',
328
                'ice_support'     => 'no',
329
                'direct_media'    => 'no',
330
                'from_user'       => $from_user,
331
                'from_domain'     => $fromdomain,
332
                'sdp_session'     => 'mikopbx',
333
                'language'        => $lang,
334
                'aors'            => $provider['uniqid'],
335
                'timers'          => ' no',
336
            ];
337
            if ('1' !== $provider['receive_calls_without_auth']) {
338
                $options['outbound_auth'] = "{$provider['uniqid']}-OUT";
339
            }
340
            $prov_config .= "[{$provider['uniqid']}]\n";
341
            $prov_config .= Util::overrideConfigurationArray($options, $manual_attributes, 'endpoint');
342
        }
343
344
        $conf .= $reg_strings;
345
        $conf .= $prov_config;
346
347
        return $conf;
348
    }
349
350
    /**
351
     * Генератор сеции пиров для sip.conf
352
     *
353
     *
354
     * @return string
355
     */
356
    public function generatePeersPj(): string
357
    {
358
        if ($this->data_peers===null){
359
            $this->getSettings();
360
        }
361
        $lang              = $this->generalSettings['PBXLanguage'];
362
        $additionalModules = $this->di->getShared('pbxConfModules');
363
        $conf              = '';
364
365
        foreach ($this->data_peers as $peer) {
366
            $manual_attributes = Util::parseIniSettings($peer['manualattributes'] ?? '');
367
368
            $language = str_replace('_', '-', strtolower($lang));
369
            $language = (trim($language) === '') ? 'en-en' : $language;
370
371
            $calleridname = (trim($peer['calleridname']) === '') ? $peer['extension'] : $peer['calleridname'];
372
            $busylevel    = (trim($peer['busylevel']) === '') ? '1' : '' . $peer['busylevel'];
373
374
            $options = [
375
                'type'     => 'auth',
376
                'username' => $peer['extension'],
377
                'password' => $peer['secret'],
378
            ];
379
            $conf    .= "[{$peer['extension']}] \n";
380
            $conf    .= Util::overrideConfigurationArray($options, $manual_attributes, 'auth');
381
382
            $options = [
383
                'type'              => 'aor',
384
                'qualify_frequency' => '60',
385
                'qualify_timeout'   => '5',
386
                'max_contacts'      => '5',
387
            ];
388
            $conf    .= "[{$peer['extension']}] \n";
389
            $conf    .= Util::overrideConfigurationArray($options, $manual_attributes, 'aor');
390
391
            $dtmfmode = ($peer['dtmfmode'] === 'rfc2833') ? 'rfc4733' : $peer['dtmfmode'];
392
            $options  = [
393
                'type'                 => 'endpoint',
394
                // 'transport'            => 'transport-udp',
395
                'context'              => 'all_peers',
396
                'dtmf_mode'            => $dtmfmode,
397
                'disallow'             => 'all',
398
                'allow'                => $peer['codecs'],
399
                'rtp_symmetric'        => 'yes',
400
                'force_rport'          => 'yes',
401
                'rewrite_contact'      => 'yes',
402
                'ice_support'          => 'no',
403
                'direct_media'         => 'no',
404
                'callerid'             => "{$calleridname} <{$peer['extension']}>",
405
                // 'webrtc'   => 'yes',
406
                'send_pai'             => 'yes',
407
                'call_group'           => '1',
408
                'pickup_group'         => '1',
409
                'sdp_session'          => 'mikopbx',
410
                'language'             => $language,
411
                'mailboxes'            => 'admin@voicemailcontext',
412
                'device_state_busy_at' => $busylevel,
413
                'aors'                 => $peer['extension'],
414
                'auth'                 => $peer['extension'],
415
                'outbound_auth'        => $peer['extension'],
416
                'acl'                  => "acl_{$peer['extension']}",
417
                'timers'               => ' no',
418
            ];
419
            // ---------------- //
420
            $conf .= "[{$peer['extension']}] \n";
421
            $conf .= Util::overrideConfigurationArray($options, $manual_attributes, 'endpoint');
422
423
            foreach ($additionalModules as $Object) {
424
                $conf .= $Object->generatePeerPjAdditionalOptions($peer);
425
            }
426
        }
427
428
        foreach ($additionalModules as $Object) {
429
            // Prevent cycling, skip current class
430
            if (is_a($Object, __CLASS__)) {
431
                continue;
432
            }
433
            $conf .= $Object->generatePeersPj();
434
        }
435
436
        return $conf;
437
    }
438
439
    /**
440
     * Получение настроек.
441
     */
442
    public function getSettings(): void
443
    {
444
        $this->contexts_data  = [];
445
        // Настройки для текущего класса.
446
        $this->data_peers     = $this->getPeers();
447
        $this->data_providers = $this->getProviders();
448
        $this->data_rout      = $this->getOutRoutes();
449
        $this->technology     = self::getTechnology();
450
    }
451
452
    /**
453
     * Получение данных по SIP пирам.
454
     *
455
     * @return array
456
     */
457
    private function getPeers(): array
458
    {
459
        /** @var \MikoPBX\Common\Models\NetworkFilters $network_filter */
460
        /** @var \MikoPBX\Common\Models\Sip $sip_peer */
461
        /** @var \MikoPBX\Common\Models\Extensions $extension */
462
        /** @var \MikoPBX\Common\Models\Users $user */
463
        /** @var \MikoPBX\Common\Models\ExtensionForwardingRights $extensionForwarding */
464
465
        $data    = [];
466
        $db_data = Sip::find("type = 'peer' AND ( disabled <> '1')");
467
        foreach ($db_data as $sip_peer) {
468
            $arr_data       = $sip_peer->toArray();
469
            $network_filter = null;
470
            if (null != $sip_peer->networkfilterid) {
471
                $network_filter = NetworkFilters::findFirst($sip_peer->networkfilterid);
472
            }
473
            $arr_data['permit'] = ($network_filter === null) ? '' : $network_filter->permit;
474
            $arr_data['deny']   = ($network_filter === null) ? '' : $network_filter->deny;
475
476
            // Получим используемые кодеки.
477
            $arr_data['codecs'] = $this->getCodecs();
478
479
            // Имя сотрудника.
480
            $extension = ExtensionsModel::findFirst("number = '{$sip_peer->extension}'");
481
            if (null === $extension) {
482
                $arr_data['publicaccess'] = false;
483
                $arr_data['language']     = '';
484
                $arr_data['calleridname'] = $sip_peer->extension;
485
            } else {
486
                $arr_data['publicaccess'] = $extension->public_access;
487
                $arr_data['calleridname'] = $extension->callerid;
488
                $user                     = Users::findFirst($extension->userid);
489
                if (null !== $user) {
490
                    $arr_data['language'] = $user->language;
491
                    $arr_data['user_id']  = $user->id;
492
                }
493
            }
494
            $extensionForwarding = ExtensionForwardingRights::findFirst("extension = '{$sip_peer->extension}'");
495
            if (null === $extensionForwarding) {
496
                $arr_data['ringlength']              = '';
497
                $arr_data['forwarding']              = '';
498
                $arr_data['forwardingonbusy']        = '';
499
                $arr_data['forwardingonunavailable'] = '';
500
            } else {
501
                $arr_data['ringlength']              = $extensionForwarding->ringlength;
502
                $arr_data['forwarding']              = $extensionForwarding->forwarding;
503
                $arr_data['forwardingonbusy']        = $extensionForwarding->forwardingonbusy;
504
                $arr_data['forwardingonunavailable'] = $extensionForwarding->forwardingonunavailable;
505
            }
506
            $data[] = $arr_data;
507
        }
508
509
        return $data;
510
    }
511
512
    /**
513
     * Возвращает доступные пиру кодеки.
514
     *
515
     * @return array
516
     */
517
    private function getCodecs(): array
518
    {
519
        $arr_codecs = [];
520
        $filter     = [
521
            'conditions'=>'disabled="0"',
522
            'order' => 'type, priority',
523
        ];
524
        $codecs     = Codecs::find($filter);
525
        foreach ($codecs as $codec_data) {
526
            $arr_codecs[] = $codec_data->name;
527
        }
528
529
        return $arr_codecs;
530
    }
531
532
    /**
533
     * Получение данных по SIP провайдерам.
534
     *
535
     * @return array
536
     */
537
    private function getProviders(): array
538
    {
539
        /** @var \MikoPBX\Common\Models\Sip $sip_peer */
540
        /** @var \MikoPBX\Common\Models\NetworkFilters $network_filter */
541
        // Получим настройки всех аккаунтов.
542
        $data    = [];
543
        $db_data = Sip::find("type = 'friend' AND ( disabled <> '1')");
544
        foreach ($db_data as $sip_peer) {
545
            $arr_data                               = $sip_peer->toArray();
546
            $arr_data['receive_calls_without_auth'] = $sip_peer->receive_calls_without_auth;
547
            $network_filter                         = NetworkFilters::findFirst($sip_peer->networkfilterid);
548
            $arr_data['permit']                     = ($network_filter === null) ? '' : $network_filter->permit;
549
            $arr_data['deny']                       = ($network_filter === null) ? '' : $network_filter->deny;
550
551
            // Получим используемые кодеки.
552
            $arr_data['codecs'] = $this->getCodecs();
553
554
            $context_id = preg_replace("/[^a-z\d]/iu", '', $sip_peer->host . $sip_peer->port);
555
            if ( ! isset($this->contexts_data[$context_id])) {
556
                $this->contexts_data[$context_id] = [];
557
            }
558
            $this->contexts_data[$context_id][$sip_peer->uniqid] = $sip_peer->username;
559
560
            $arr_data['context_id'] = $context_id;
561
            $data[]                 = $arr_data;
562
        }
563
564
        return $data;
565
    }
566
567
    /**
568
     * Генератор исходящих контекстов для пиров.
569
     *
570
     * @return array
571
     */
572
    private function getOutRoutes(): array
573
    {
574
        if ($this->data_peers===null){
575
            $this->getSettings();
576
        }
577
        /** @var \MikoPBX\Common\Models\OutgoingRoutingTable $rout */
578
        /** @var \MikoPBX\Common\Models\OutgoingRoutingTable $routs */
579
        /** @var \MikoPBX\Common\Models\Sip $db_data */
580
        /** @var \MikoPBX\Common\Models\Sip $sip_peer */
581
582
        $data    = [];
583
        $routs   = OutgoingRoutingTable::find(['order' => 'priority']);
584
        $db_data = Sip::find("type = 'friend' AND ( disabled <> '1')");
585
        foreach ($routs as $rout) {
586
            foreach ($db_data as $sip_peer) {
587
                if ($sip_peer->uniqid !== $rout->providerid) {
588
                    continue;
589
                }
590
                $arr_data                = $rout->toArray();
591
                $arr_data['description'] = $sip_peer->description;
592
                $arr_data['uniqid']      = $sip_peer->uniqid;
593
                $data[]                  = $arr_data;
594
            }
595
        }
596
597
        return $data;
598
    }
599
600
601
602
    /**
603
     * Генератор extension для контекста peers.
604
     *
605
     * @return string
606
     */
607
    public function extensionGenContexts(): string
608
    {
609
        if ($this->data_peers===null){
610
            $this->getSettings();
611
        }
612
        // Генерация внутреннего номерного плана.
613
        $conf = '';
614
615
        foreach ($this->data_peers as $peer) {
616
            $conf .= "[peer_{$peer['extension']}] \n";
617
            $conf .= "include => internal \n";
618
            $conf .= "include => outgoing \n";
619
        }
620
621
        $contexts = [];
622
        // Входящие контексты.
623
        foreach ($this->data_providers as $provider) {
624
            $contexts_data = $this->contexts_data[$provider['context_id']];
625
            if (count($contexts_data) === 1) {
626
                $conf .= ExtensionsConf::generateIncomingContextPeers($provider['uniqid'], $provider['username'], '');
627
            } elseif ( ! in_array($provider['context_id'], $contexts, true)) {
628
                $conf       .= ExtensionsConf::generateIncomingContextPeers(
629
                    $contexts_data,
630
                    null,
631
                    $provider['context_id']
632
                );
633
                $contexts[] = $provider['context_id'];
634
            }
635
        }
636
637
        return $conf;
638
    }
639
640
    /**
641
     * Генерация хинтов.
642
     *
643
     * @return string
644
     */
645
    public function extensionGenHints(): string
646
    {
647
        if ($this->data_peers===null){
648
            $this->getSettings();
649
        }
650
        $conf = '';
651
        foreach ($this->data_peers as $peer) {
652
            $conf .= "exten => {$peer['extension']},hint,{$this->technology}/{$peer['extension']} \n";
653
        }
654
655
        return $conf;
656
    }
657
658
    public function extensionGenInternal(): string
659
    {
660
        if ($this->data_peers===null){
661
            $this->getSettings();
662
        }
663
        // Генерация внутреннего номерного плана.
664
        $conf = '';
665
        foreach ($this->data_peers as $peer) {
666
            $conf .= "exten => {$peer['extension']},1,Goto(internal-users,{$peer['extension']},1) \n";
667
        }
668
        $conf .= "\n";
669
670
        return $conf;
671
    }
672
673
    public function extensionGenInternalTransfer(): string
674
    {
675
        if ($this->data_peers===null){
676
            $this->getSettings();
677
        }
678
        // Генерация внутреннего номерного плана.
679
        $conf = '';
680
        foreach ($this->data_peers as $peer) {
681
            $conf .= "exten => {$peer['extension']},1,Set(__ISTRANSFER=transfer_) \n";
682
            $conf .= "	same => n,Goto(internal-users,{$peer['extension']},1) \n";
683
        }
684
        $conf .= "\n";
685
686
        return $conf;
687
    }
688
689
    /**
690
     * Returns PJSIP ot SIP uses at PBX
691
     *
692
     * @return string
693
     */
694
    public static function getTechnology(): string
695
    {
696
        return self::TYPE_PJSIP;
697
    }
698
}