Passed
Push — develop ( 69733b...ba4915 )
by Портнов
05:14
created

SIPConf::dependenceModels()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
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,
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
            $language   = $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'        => $language,
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
341
            self::getToneZone($options, $language);
342
343
            $prov_config .= "[{$provider['uniqid']}]\n";
344
            $prov_config .= Util::overrideConfigurationArray($options, $manual_attributes, 'endpoint');
345
        }
346
347
        $conf .= $reg_strings;
348
        $conf .= $prov_config;
349
350
        return $conf;
351
    }
352
353
    public static function getToneZone(array &$options, string $lang):void {
354
        $settings = [
355
            'ru-ru' => 'ru',
356
            'en-gb' => 'uk',
357
            'de-de' => 'de',
358
            'da-dk' => 'dk',
359
            'es-es' => 'es',
360
            'fr-ca' => 'fr',
361
            'it-it' => 'it',
362
            'ja-jp' => 'jp',
363
            'nl-nl' => 'nl',
364
            'pl-pl' => 'pl',
365
            'pt-br' => 'pt',
366
        ];
367
        $toneZone = $settings[$lang]??'';
368
        if(!empty($toneZone)){
369
            $options['inband_progress'] = 'yes';
370
            $options['tone_zone'] = $toneZone;
371
        }
372
    }
373
374
    /**
375
     * Генератор сеции пиров для sip.conf
376
     *
377
     *
378
     * @return string
379
     */
380
    public function generatePeersPj(): string
381
    {
382
        if ($this->data_peers===null){
383
            $this->getSettings();
384
        }
385
        $lang              = $this->generalSettings['PBXLanguage'];
386
        $additionalModules = $this->di->getShared('pbxConfModules');
387
        $conf              = '';
388
389
        foreach ($this->data_peers as $peer) {
390
            $manual_attributes = Util::parseIniSettings($peer['manualattributes'] ?? '');
391
392
            $language = str_replace('_', '-', strtolower($lang));
393
            $language = (trim($language) === '') ? 'en-en' : $language;
394
395
            $calleridname = (trim($peer['calleridname']) === '') ? $peer['extension'] : $peer['calleridname'];
396
            $busylevel    = (trim($peer['busylevel']) === '') ? '1' : '' . $peer['busylevel'];
397
398
            $options = [
399
                'type'     => 'auth',
400
                'username' => $peer['extension'],
401
                'password' => $peer['secret'],
402
            ];
403
            $conf    .= "[{$peer['extension']}] \n";
404
            $conf    .= Util::overrideConfigurationArray($options, $manual_attributes, 'auth');
405
406
            $options = [
407
                'type'              => 'aor',
408
                'qualify_frequency' => '60',
409
                'qualify_timeout'   => '5',
410
                'max_contacts'      => '5',
411
            ];
412
            $conf    .= "[{$peer['extension']}] \n";
413
            $conf    .= Util::overrideConfigurationArray($options, $manual_attributes, 'aor');
414
415
            $dtmfmode = ($peer['dtmfmode'] === 'rfc2833') ? 'rfc4733' : $peer['dtmfmode'];
416
            $options  = [
417
                'type'                 => 'endpoint',
418
                // 'transport'            => 'transport-udp',
419
                'context'              => 'all_peers',
420
                'dtmf_mode'            => $dtmfmode,
421
                'disallow'             => 'all',
422
                'allow'                => $peer['codecs'],
423
                'rtp_symmetric'        => 'yes',
424
                'force_rport'          => 'yes',
425
                'rewrite_contact'      => 'yes',
426
                'ice_support'          => 'no',
427
                'direct_media'         => 'no',
428
                'callerid'             => "{$calleridname} <{$peer['extension']}>",
429
                'send_pai'             => 'yes',
430
                'call_group'           => '1',
431
                'pickup_group'         => '1',
432
                'sdp_session'          => 'mikopbx',
433
                'language'             => $language,
434
                'mailboxes'            => 'admin@voicemailcontext',
435
                'device_state_busy_at' => $busylevel,
436
                'aors'                 => $peer['extension'],
437
                'auth'                 => $peer['extension'],
438
                'outbound_auth'        => $peer['extension'],
439
                'acl'                  => "acl_{$peer['extension']}",
440
                'timers'               => ' no',
441
            ];
442
            self::getToneZone($options, $language);
443
444
            // ---------------- //
445
            $conf .= "[{$peer['extension']}] \n";
446
            $conf .= Util::overrideConfigurationArray($options, $manual_attributes, 'endpoint');
447
448
            foreach ($additionalModules as $Object) {
449
                $conf .= $Object->generatePeerPjAdditionalOptions($peer);
450
            }
451
        }
452
453
        foreach ($additionalModules as $Object) {
454
            // Prevent cycling, skip current class
455
            if (is_a($Object, __CLASS__)) {
456
                continue;
457
            }
458
            $conf .= $Object->generatePeersPj();
459
        }
460
461
        return $conf;
462
    }
463
464
    /**
465
     * Получение настроек.
466
     */
467
    public function getSettings(): void
468
    {
469
        $this->contexts_data  = [];
470
        // Настройки для текущего класса.
471
        $this->data_peers     = $this->getPeers();
472
        $this->data_providers = $this->getProviders();
473
        $this->data_rout      = $this->getOutRoutes();
474
        $this->technology     = self::getTechnology();
475
    }
476
477
    /**
478
     * Получение данных по SIP пирам.
479
     *
480
     * @return array
481
     */
482
    private function getPeers(): array
483
    {
484
        /** @var \MikoPBX\Common\Models\NetworkFilters $network_filter */
485
        /** @var \MikoPBX\Common\Models\Sip $sip_peer */
486
        /** @var \MikoPBX\Common\Models\Extensions $extension */
487
        /** @var \MikoPBX\Common\Models\Users $user */
488
        /** @var \MikoPBX\Common\Models\ExtensionForwardingRights $extensionForwarding */
489
490
        $data    = [];
491
        $db_data = Sip::find("type = 'peer' AND ( disabled <> '1')");
492
        foreach ($db_data as $sip_peer) {
493
            $arr_data       = $sip_peer->toArray();
494
            $network_filter = null;
495
            if (null != $sip_peer->networkfilterid) {
496
                $network_filter = NetworkFilters::findFirst($sip_peer->networkfilterid);
497
            }
498
            $arr_data['permit'] = ($network_filter === null) ? '' : $network_filter->permit;
499
            $arr_data['deny']   = ($network_filter === null) ? '' : $network_filter->deny;
500
501
            // Получим используемые кодеки.
502
            $arr_data['codecs'] = $this->getCodecs();
503
504
            // Имя сотрудника.
505
            $extension = Extensions::findFirst("number = '{$sip_peer->extension}'");
506
            if (null === $extension) {
507
                $arr_data['publicaccess'] = false;
508
                $arr_data['language']     = '';
509
                $arr_data['calleridname'] = $sip_peer->extension;
510
            } else {
511
                $arr_data['publicaccess'] = $extension->public_access;
512
                $arr_data['calleridname'] = $extension->callerid;
513
                $user                     = Users::findFirst($extension->userid);
514
                if (null !== $user) {
515
                    $arr_data['language'] = $user->language;
516
                    $arr_data['user_id']  = $user->id;
517
                }
518
            }
519
            $extensionForwarding = ExtensionForwardingRights::findFirst("extension = '{$sip_peer->extension}'");
520
            if (null === $extensionForwarding) {
521
                $arr_data['ringlength']              = '';
522
                $arr_data['forwarding']              = '';
523
                $arr_data['forwardingonbusy']        = '';
524
                $arr_data['forwardingonunavailable'] = '';
525
            } else {
526
                $arr_data['ringlength']              = $extensionForwarding->ringlength;
527
                $arr_data['forwarding']              = $extensionForwarding->forwarding;
528
                $arr_data['forwardingonbusy']        = $extensionForwarding->forwardingonbusy;
529
                $arr_data['forwardingonunavailable'] = $extensionForwarding->forwardingonunavailable;
530
            }
531
            $data[] = $arr_data;
532
        }
533
534
        return $data;
535
    }
536
537
    /**
538
     * Возвращает доступные пиру кодеки.
539
     *
540
     * @return array
541
     */
542
    private function getCodecs(): array
543
    {
544
        $arr_codecs = [];
545
        $filter     = [
546
            'conditions'=>'disabled="0"',
547
            'order' => 'type, priority',
548
        ];
549
        $codecs     = Codecs::find($filter);
550
        foreach ($codecs as $codec_data) {
551
            $arr_codecs[] = $codec_data->name;
552
        }
553
554
        return $arr_codecs;
555
    }
556
557
    /**
558
     * Получение данных по SIP провайдерам.
559
     *
560
     * @return array
561
     */
562
    private function getProviders(): array
563
    {
564
        /** @var \MikoPBX\Common\Models\Sip $sip_peer */
565
        /** @var \MikoPBX\Common\Models\NetworkFilters $network_filter */
566
        // Получим настройки всех аккаунтов.
567
        $data    = [];
568
        $db_data = Sip::find("type = 'friend' AND ( disabled <> '1')");
569
        foreach ($db_data as $sip_peer) {
570
            $arr_data                               = $sip_peer->toArray();
571
            $arr_data['receive_calls_without_auth'] = $sip_peer->receive_calls_without_auth;
572
            $network_filter                         = NetworkFilters::findFirst($sip_peer->networkfilterid);
573
            $arr_data['permit']                     = ($network_filter === null) ? '' : $network_filter->permit;
574
            $arr_data['deny']                       = ($network_filter === null) ? '' : $network_filter->deny;
575
576
            // Получим используемые кодеки.
577
            $arr_data['codecs'] = $this->getCodecs();
578
579
            $context_id = preg_replace("/[^a-z\d]/iu", '', $sip_peer->host . $sip_peer->port);
580
            if ( ! isset($this->contexts_data[$context_id])) {
581
                $this->contexts_data[$context_id] = [];
582
            }
583
            $this->contexts_data[$context_id][$sip_peer->uniqid] = $sip_peer->username;
584
585
            $arr_data['context_id'] = $context_id;
586
            $data[]                 = $arr_data;
587
        }
588
589
        return $data;
590
    }
591
592
    /**
593
     * Генератор исходящих контекстов для пиров.
594
     *
595
     * @return array
596
     */
597
    private function getOutRoutes(): array
598
    {
599
        if ($this->data_peers===null){
600
            $this->getSettings();
601
        }
602
        /** @var \MikoPBX\Common\Models\OutgoingRoutingTable $rout */
603
        /** @var \MikoPBX\Common\Models\OutgoingRoutingTable $routs */
604
        /** @var \MikoPBX\Common\Models\Sip $db_data */
605
        /** @var \MikoPBX\Common\Models\Sip $sip_peer */
606
607
        $data    = [];
608
        $routs   = OutgoingRoutingTable::find(['order' => 'priority']);
609
        $db_data = Sip::find("type = 'friend' AND ( disabled <> '1')");
610
        foreach ($routs as $rout) {
611
            foreach ($db_data as $sip_peer) {
612
                if ($sip_peer->uniqid !== $rout->providerid) {
613
                    continue;
614
                }
615
                $arr_data                = $rout->toArray();
616
                $arr_data['description'] = $sip_peer->description;
617
                $arr_data['uniqid']      = $sip_peer->uniqid;
618
                $data[]                  = $arr_data;
619
            }
620
        }
621
622
        return $data;
623
    }
624
625
626
627
    /**
628
     * Генератор extension для контекста peers.
629
     *
630
     * @return string
631
     */
632
    public function extensionGenContexts(): string
633
    {
634
        if ($this->data_peers===null){
635
            $this->getSettings();
636
        }
637
        // Генерация внутреннего номерного плана.
638
        $conf = '';
639
640
        foreach ($this->data_peers as $peer) {
641
            $conf .= "[peer_{$peer['extension']}] \n";
642
            $conf .= "include => internal \n";
643
            $conf .= "include => outgoing \n";
644
        }
645
646
        $contexts = [];
647
        // Входящие контексты.
648
        foreach ($this->data_providers as $provider) {
649
            $contexts_data = $this->contexts_data[$provider['context_id']];
650
            if (count($contexts_data) === 1) {
651
                $conf .= ExtensionsConf::generateIncomingContextPeers($provider['uniqid'], $provider['username'], '');
652
            } elseif ( ! in_array($provider['context_id'], $contexts, true)) {
653
                $conf       .= ExtensionsConf::generateIncomingContextPeers(
654
                    $contexts_data,
655
                    null,
656
                    $provider['context_id']
657
                );
658
                $contexts[] = $provider['context_id'];
659
            }
660
        }
661
662
        return $conf;
663
    }
664
665
    /**
666
     * Генерация хинтов.
667
     *
668
     * @return string
669
     */
670
    public function extensionGenHints(): string
671
    {
672
        if ($this->data_peers===null){
673
            $this->getSettings();
674
        }
675
        $conf = '';
676
        foreach ($this->data_peers as $peer) {
677
            $conf .= "exten => {$peer['extension']},hint,{$this->technology}/{$peer['extension']} \n";
678
        }
679
680
        return $conf;
681
    }
682
683
    public function extensionGenInternal(): string
684
    {
685
        if ($this->data_peers===null){
686
            $this->getSettings();
687
        }
688
        // Генерация внутреннего номерного плана.
689
        $conf = '';
690
        foreach ($this->data_peers as $peer) {
691
            $conf .= "exten => {$peer['extension']},1,Goto(internal-users,{$peer['extension']},1) \n";
692
        }
693
        $conf .= "\n";
694
695
        return $conf;
696
    }
697
698
    public function extensionGenInternalTransfer(): string
699
    {
700
        if ($this->data_peers===null){
701
            $this->getSettings();
702
        }
703
        // Генерация внутреннего номерного плана.
704
        $conf = '';
705
        foreach ($this->data_peers as $peer) {
706
            $conf .= "exten => {$peer['extension']},1,Set(__ISTRANSFER=transfer_) \n";
707
            $conf .= "	same => n,Goto(internal-users,{$peer['extension']},1) \n";
708
        }
709
        $conf .= "\n";
710
711
        return $conf;
712
    }
713
714
    /**
715
     * Returns PJSIP ot SIP uses at PBX
716
     *
717
     * @return string
718
     */
719
    public static function getTechnology(): string
720
    {
721
        return self::TYPE_PJSIP;
722
    }
723
}