Total Complexity | 109 |
Total Lines | 987 |
Duplicated Lines | 0 % |
Changes | 9 | ||
Bugs | 0 | Features | 0 |
Complex classes like SIPConf often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use SIPConf, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
40 | class SIPConf extends CoreConfigClass |
||
41 | { |
||
42 | public const TYPE_PJSIP = 'PJSIP'; |
||
43 | private const TOPOLOGY_HASH_FILE = '/topology_hash'; |
||
44 | |||
45 | protected $data_peers; |
||
46 | protected $data_providers; |
||
47 | protected $data_rout; |
||
48 | protected array $dataSipHosts; |
||
49 | |||
50 | protected string $technology; |
||
51 | protected array $contexts_data; |
||
52 | |||
53 | protected string $description = 'pjsip.conf'; |
||
54 | |||
55 | /** |
||
56 | * |
||
57 | * @return array |
||
58 | */ |
||
59 | public function getDependenceModels(): array |
||
60 | { |
||
61 | return [Sip::class, Users::class, SipHosts::class]; |
||
62 | } |
||
63 | |||
64 | /** |
||
65 | * Проверка ключевых параметров. |
||
66 | * Если параметры изменены, то необходим рестарт Asterisk процесса. |
||
67 | * |
||
68 | * @return bool |
||
69 | */ |
||
70 | public function needAsteriskRestart(): bool |
||
71 | { |
||
72 | $di = Di::getDefault(); |
||
73 | if ($di === null) { |
||
74 | return false; |
||
75 | } |
||
76 | $mikoPBXConfig = new MikoPBXConfig(); |
||
77 | [$topology, $extIpAddress, $externalHostName, $subnets] = $this->getTopologyData(); |
||
78 | |||
79 | $generalSettings = $mikoPBXConfig->getGeneralSettings(); |
||
80 | $now_hash = md5($topology . $externalHostName . $extIpAddress . $generalSettings['SIPPort'] . implode('',$subnets)); |
||
81 | $old_hash = ''; |
||
82 | $varEtcDir = $di->getShared('config')->path('core.varEtcDir'); |
||
83 | if (file_exists($varEtcDir . self::TOPOLOGY_HASH_FILE)) { |
||
84 | $old_hash = file_get_contents($varEtcDir . self::TOPOLOGY_HASH_FILE); |
||
85 | } |
||
86 | |||
87 | return $old_hash !== $now_hash; |
||
88 | } |
||
89 | |||
90 | /** |
||
91 | * @return array |
||
92 | */ |
||
93 | private function getTopologyData(): array |
||
94 | { |
||
95 | $network = new Network(); |
||
96 | |||
97 | $topology = 'public'; |
||
98 | $extipaddr = ''; |
||
99 | $exthostname = ''; |
||
100 | $networks = $network->getEnabledLanInterfaces(); |
||
101 | $subnets = ['127.0.0.1/32']; |
||
102 | foreach ($networks as $if_data) { |
||
103 | $lan_config = $network->getInterface($if_data['interface']); |
||
104 | if (empty($lan_config['ipaddr']) || empty($lan_config['subnet'])) { |
||
105 | continue; |
||
106 | } |
||
107 | try { |
||
108 | $sub = new SubnetCalculator($lan_config['ipaddr'], $lan_config['subnet']); |
||
109 | } catch (Throwable $e) { |
||
110 | Util::sysLogMsg(self::class, $e->getMessage(), LOG_ERR); |
||
111 | continue; |
||
112 | } |
||
113 | $net = $sub->getNetworkPortion() . '/' . $lan_config['subnet']; |
||
114 | if ($if_data['topology'] === 'private' && in_array($net, $subnets, true) === false) { |
||
115 | $subnets[] = $net; |
||
116 | } |
||
117 | if (trim($if_data['internet']) === '1') { |
||
118 | $topology = trim($if_data['topology']); |
||
119 | $extipaddr = trim($if_data['extipaddr']); |
||
120 | $exthostname = trim($if_data['exthostname']); |
||
121 | } |
||
122 | } |
||
123 | |||
124 | $networks = NetworkFilters::find('local_network=1'); |
||
125 | foreach ($networks as $net) { |
||
126 | if (in_array($net->permit, $subnets, true) === false) { |
||
127 | $subnets[] = $net->permit; |
||
128 | } |
||
129 | } |
||
130 | |||
131 | return [ |
||
132 | $topology, |
||
133 | $extipaddr, |
||
134 | $exthostname, |
||
135 | $subnets, |
||
136 | ]; |
||
137 | } |
||
138 | |||
139 | /** |
||
140 | * Генератор extension для контекста peers. |
||
141 | * |
||
142 | * @return string |
||
143 | */ |
||
144 | public function extensionGenContexts(): string |
||
145 | { |
||
146 | if ($this->data_peers === null) { |
||
147 | $this->getSettings(); |
||
148 | } |
||
149 | // Генерация внутреннего номерного плана. |
||
150 | $conf = ''; |
||
151 | |||
152 | $contexts = []; |
||
153 | // Входящие контексты. |
||
154 | foreach ($this->data_providers as $provider) { |
||
155 | $contextsData = $this->contexts_data[$provider['context_id']]; |
||
156 | if (count($contextsData) === 1) { |
||
157 | $conf .= IncomingContexts::generate($provider['uniqid'], $provider['username']); |
||
158 | } elseif ( ! in_array($provider['context_id'], $contexts, true)) { |
||
159 | $conf .= IncomingContexts::generate( |
||
160 | $contextsData, |
||
161 | null, |
||
162 | $provider['context_id'] |
||
163 | ); |
||
164 | $contexts[] = $provider['context_id']; |
||
165 | } |
||
166 | } |
||
167 | |||
168 | return $conf; |
||
169 | } |
||
170 | |||
171 | /** |
||
172 | * Получение настроек. |
||
173 | */ |
||
174 | public function getSettings(): void |
||
175 | { |
||
176 | $this->contexts_data = []; |
||
177 | // Настройки для текущего класса. |
||
178 | $this->data_peers = $this->getPeers(); |
||
179 | $this->data_providers = $this->getProviders(); |
||
180 | $this->data_rout = $this->getOutRoutes(); |
||
181 | $this->technology = self::getTechnology(); |
||
182 | $this->dataSipHosts = self::getSipHosts(); |
||
183 | } |
||
184 | |||
185 | /** |
||
186 | * Получение данных по SIP пирам. |
||
187 | * |
||
188 | * @return array |
||
189 | */ |
||
190 | private function getPeers(): array |
||
191 | { |
||
192 | /** @var NetworkFilters $network_filter */ |
||
193 | /** @var Sip $sip_peer */ |
||
194 | /** @var Extensions $extension */ |
||
195 | /** @var Users $user */ |
||
196 | /** @var ExtensionForwardingRights $extensionForwarding */ |
||
197 | |||
198 | $data = []; |
||
199 | $db_data = Sip::find("type = 'peer' AND ( disabled <> '1')"); |
||
200 | foreach ($db_data as $sip_peer) { |
||
201 | $arr_data = $sip_peer->toArray(); |
||
202 | $network_filter = null; |
||
203 | if ( ! empty($sip_peer->networkfilterid)) { |
||
204 | $network_filter = NetworkFilters::findFirst($sip_peer->networkfilterid); |
||
205 | } |
||
206 | $arr_data['permit'] = ($network_filter === null) ? '' : $network_filter->permit; |
||
207 | $arr_data['deny'] = ($network_filter === null) ? '' : $network_filter->deny; |
||
208 | |||
209 | // Получим используемые кодеки. |
||
210 | $arr_data['codecs'] = $this->getCodecs(); |
||
211 | |||
212 | // Имя сотрудника. |
||
213 | $extension = Extensions::findFirst("number = '{$sip_peer->extension}'"); |
||
214 | if (null === $extension) { |
||
215 | $arr_data['publicaccess'] = false; |
||
216 | $arr_data['language'] = ''; |
||
217 | $arr_data['calleridname'] = $sip_peer->extension; |
||
218 | } else { |
||
219 | $arr_data['publicaccess'] = $extension->public_access; |
||
220 | $arr_data['calleridname'] = $extension->callerid; |
||
221 | $user = Users::findFirst($extension->userid); |
||
222 | if (null !== $user) { |
||
223 | $arr_data['language'] = $user->language; |
||
224 | $arr_data['user_id'] = $user->id; |
||
225 | } |
||
226 | } |
||
227 | $extensionForwarding = ExtensionForwardingRights::findFirst("extension = '{$sip_peer->extension}'"); |
||
228 | if (null === $extensionForwarding) { |
||
229 | $arr_data['ringlength'] = ''; |
||
230 | $arr_data['forwarding'] = ''; |
||
231 | $arr_data['forwardingonbusy'] = ''; |
||
232 | $arr_data['forwardingonunavailable'] = ''; |
||
233 | } else { |
||
234 | $arr_data['ringlength'] = $extensionForwarding->ringlength; |
||
235 | $arr_data['forwarding'] = $extensionForwarding->forwarding; |
||
236 | $arr_data['forwardingonbusy'] = $extensionForwarding->forwardingonbusy; |
||
237 | $arr_data['forwardingonunavailable'] = $extensionForwarding->forwardingonunavailable; |
||
238 | } |
||
239 | $data[] = $arr_data; |
||
240 | } |
||
241 | |||
242 | return $data; |
||
243 | } |
||
244 | |||
245 | /** |
||
246 | * Возвращает доступные пиру кодеки. |
||
247 | * |
||
248 | * @return array |
||
249 | */ |
||
250 | private function getCodecs(): array |
||
251 | { |
||
252 | $arr_codecs = []; |
||
253 | $filter = [ |
||
254 | 'conditions' => 'disabled="0"', |
||
255 | 'order' => 'type, priority', |
||
256 | ]; |
||
257 | $codecs = Codecs::find($filter); |
||
258 | foreach ($codecs as $codec_data) { |
||
259 | $arr_codecs[] = $codec_data->name; |
||
260 | } |
||
261 | |||
262 | return $arr_codecs; |
||
263 | } |
||
264 | |||
265 | /** |
||
266 | * Получение данных по SIP провайдерам. |
||
267 | * |
||
268 | * @return array |
||
269 | */ |
||
270 | private function getProviders(): array |
||
271 | { |
||
272 | /** @var Sip $sip_peer */ |
||
273 | /** @var NetworkFilters $network_filter */ |
||
274 | // Получим настройки всех аккаунтов. |
||
275 | $data = []; |
||
276 | $db_data = Sip::find("type = 'friend' AND ( disabled <> '1')"); |
||
277 | foreach ($db_data as $sip_peer) { |
||
278 | $arr_data = $sip_peer->toArray(); |
||
279 | $arr_data['receive_calls_without_auth'] = $sip_peer->receive_calls_without_auth; |
||
280 | $network_filter = NetworkFilters::findFirst($sip_peer->networkfilterid); |
||
281 | $arr_data['permit'] = ($network_filter === null) ? '' : $network_filter->permit; |
||
282 | $arr_data['deny'] = ($network_filter === null) ? '' : $network_filter->deny; |
||
283 | |||
284 | // Получим используемые кодеки. |
||
285 | $arr_data['codecs'] = $this->getCodecs(); |
||
286 | |||
287 | $context_id = preg_replace("/[^a-z\d]/iu", '', $sip_peer->host . $sip_peer->port); |
||
288 | if ( ! isset($this->contexts_data[$context_id])) { |
||
289 | $this->contexts_data[$context_id] = []; |
||
290 | } |
||
291 | $this->contexts_data[$context_id][$sip_peer->uniqid] = $sip_peer->username; |
||
292 | |||
293 | $arr_data['context_id'] = $context_id; |
||
294 | $data[] = $arr_data; |
||
295 | } |
||
296 | |||
297 | return $data; |
||
298 | } |
||
299 | |||
300 | /** |
||
301 | * Генератор исходящих контекстов для пиров. |
||
302 | * |
||
303 | * @return array |
||
304 | */ |
||
305 | private function getOutRoutes(): array |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * Returns PJSIP ot SIP uses at PBX |
||
335 | * |
||
336 | * @return string |
||
337 | */ |
||
338 | public static function getTechnology(): string |
||
341 | } |
||
342 | |||
343 | /** |
||
344 | * Возвращает массив хостов. |
||
345 | * |
||
346 | * @return array |
||
347 | */ |
||
348 | public static function getSipHosts(): array |
||
362 | } |
||
363 | |||
364 | /** |
||
365 | * Генерация хинтов. |
||
366 | * |
||
367 | * @return string |
||
368 | */ |
||
369 | public function extensionGenHints(): string |
||
370 | { |
||
371 | if ($this->data_peers === null) { |
||
372 | $this->getSettings(); |
||
373 | } |
||
374 | $conf = ''; |
||
375 | foreach ($this->data_peers as $peer) { |
||
376 | $hint = "{$this->technology}/{$peer['extension']}"; |
||
377 | if($this->generalSettings['UseWebRTC'] === '1') { |
||
378 | $hint.="&{$this->technology}/{$peer['extension']}-WS"; |
||
379 | } |
||
380 | $conf .= "exten => {$peer['extension']},hint,$hint&Custom:{$peer['extension']} \n"; |
||
381 | } |
||
382 | return $conf; |
||
383 | } |
||
384 | |||
385 | public function extensionGenInternal(): string |
||
398 | } |
||
399 | |||
400 | public function extensionGenInternalTransfer(): string |
||
414 | } |
||
415 | |||
416 | /** |
||
417 | * Генератор sip.conf |
||
418 | * |
||
419 | * @return void |
||
420 | */ |
||
421 | protected function generateConfigProtected(): void |
||
422 | { |
||
423 | $conf = $this->generateGeneralPj(); |
||
424 | $conf .= $this->generateProvidersPj(); |
||
425 | $conf .= $this->generatePeersPj(); |
||
426 | |||
427 | $astEtcDir = $this->config->path('asterisk.astetcdir'); |
||
428 | |||
429 | Util::fileWriteContent($astEtcDir . '/pjsip.conf', $conf); |
||
430 | $pjConf = '[log_mappings]' . "\n" . |
||
431 | 'type=log_mappings' . "\n" . |
||
432 | 'asterisk_error = 0' . "\n" . |
||
433 | 'asterisk_warning = 2' . "\n" . |
||
434 | 'asterisk_debug = 1,3,4,5,6' . "\n\n"; |
||
435 | file_put_contents($astEtcDir.'/pjproject.conf', $pjConf); |
||
436 | file_put_contents($astEtcDir.'/sorcery.conf', ''); |
||
437 | $this->updateAsteriskDatabase(); |
||
438 | } |
||
439 | |||
440 | /** |
||
441 | * Обновление маршрутизации в AstDB |
||
442 | * @return bool |
||
443 | */ |
||
444 | public function updateAsteriskDatabase():bool |
||
445 | { |
||
446 | if ($this->data_peers === null) { |
||
447 | $this->getSettings(); |
||
448 | } |
||
449 | $warError = false; |
||
450 | $db = new AstDB(); |
||
451 | foreach ($this->data_peers as $peer) { |
||
452 | // Помещаем в AstDB сведения по маршуртизации. |
||
453 | $ringLength = ($peer['ringlength'] === '0') ? '' : trim($peer['ringlength']); |
||
454 | $warError |= !$db->databasePut('FW_TIME', $peer['extension'], $ringLength); |
||
455 | $warError |= !$db->databasePut('FW', $peer['extension'], trim($peer['forwarding'])); |
||
456 | $warError |= !$db->databasePut('FW_BUSY', $peer['extension'], trim($peer['forwardingonbusy'])); |
||
457 | $warError |= !$db->databasePut('FW_UNAV', $peer['extension'], trim($peer['forwardingonunavailable'])); |
||
458 | } |
||
459 | |||
460 | return !$warError; |
||
461 | } |
||
462 | |||
463 | /** |
||
464 | * Генератора секции general pjsip.conf |
||
465 | * |
||
466 | * |
||
467 | * @return string |
||
468 | */ |
||
469 | private function generateGeneralPj(): string |
||
470 | { |
||
471 | $lang = $this->generalSettings['PBXLanguage']; |
||
472 | [$topology, $extIpAddress, $externalHostName, $subnets] = $this->getTopologyData(); |
||
473 | |||
474 | $codecs = $this->getCodecs(); |
||
475 | $codecConf = ''; |
||
476 | foreach ($codecs as $codec) { |
||
477 | $codecConf .= "allow = $codec\n"; |
||
478 | } |
||
479 | |||
480 | $pbxVersion = PbxSettings::getValueByKey('PBXVersion'); |
||
481 | $natConf = ''; |
||
482 | if ($topology === 'private') { |
||
483 | foreach ($subnets as $net) { |
||
484 | $natConf .= "local_net=$net\n"; |
||
485 | } |
||
486 | if ( ! empty($externalHostName)) { |
||
487 | $parts = explode(':', $externalHostName); |
||
488 | $natConf .= 'external_media_address=' . $parts[0] . "\n"; |
||
489 | $natConf .= 'external_signaling_address=' . $parts[0] . "\n"; |
||
490 | $natConf .= 'external_signaling_port=' . ($parts[1] ?? '5060'); |
||
491 | } elseif ( ! empty($extIpAddress)) { |
||
492 | $parts = explode(':', $extIpAddress); |
||
493 | $natConf .= 'external_media_address=' . $parts[0] . "\n"; |
||
494 | $natConf .= 'external_signaling_address=' . $parts[0] . "\n"; |
||
495 | $natConf .= 'external_signaling_port=' . ($parts[1] ?? '5060'); |
||
496 | } |
||
497 | } |
||
498 | |||
499 | $typeTransport = 'type = transport'; |
||
500 | $conf = "[global] \n" . |
||
501 | "type = global\n" . |
||
502 | "disable_multi_domain=yes\n" . |
||
503 | "endpoint_identifier_order=username,ip,anonymous\n" . |
||
504 | "user_agent = mikopbx-$pbxVersion\n\n" . |
||
505 | |||
506 | "[transport-udp]\n" . |
||
507 | "$typeTransport\n" . |
||
508 | "protocol = udp\n" . |
||
509 | "bind=0.0.0.0:{$this->generalSettings['SIPPort']}\n" . |
||
510 | "$natConf\n\n" . |
||
511 | |||
512 | "[transport-tcp]\n" . |
||
513 | "$typeTransport\n" . |
||
514 | "protocol = tcp\n" . |
||
515 | "bind=0.0.0.0:{$this->generalSettings['SIPPort']}\n" . |
||
516 | "$natConf\n\n" . |
||
517 | |||
518 | "[transport-wss]\n" . |
||
519 | "$typeTransport\n" . |
||
520 | "protocol = wss\n" . |
||
521 | "bind=0.0.0.0:{$this->generalSettings['SIPPort']}\n" . |
||
522 | "$natConf\n\n"; |
||
523 | |||
524 | $allowGuestCalls = PbxSettings::getValueByKey('PBXAllowGuestCalls'); |
||
525 | if ($allowGuestCalls === '1') { |
||
526 | $conf .= "[anonymous]\n" . |
||
527 | "type = endpoint\n" . |
||
528 | $codecConf . |
||
529 | "language=$lang\n" . |
||
530 | "timers = no\n" . |
||
531 | "context = public-direct-dial\n\n"; |
||
532 | } |
||
533 | |||
534 | $varEtcDir = $this->config->path('core.varEtcDir'); |
||
535 | $hash = md5($topology . $externalHostName . $extIpAddress . $this->generalSettings['SIPPort'] . implode('',$subnets)); |
||
536 | file_put_contents($varEtcDir.self::TOPOLOGY_HASH_FILE, $hash); |
||
537 | $conf .= "\n"; |
||
538 | return $conf; |
||
539 | } |
||
540 | |||
541 | /** |
||
542 | * Генератор секции провайдеров в sip.conf |
||
543 | * |
||
544 | * |
||
545 | * @return string |
||
546 | */ |
||
547 | private function generateProvidersPj(): string |
||
548 | { |
||
549 | $conf = ''; |
||
550 | $reg_strings = ''; |
||
551 | $prov_config = ''; |
||
552 | if ($this->data_providers === null) { |
||
553 | $this->getSettings(); |
||
554 | } |
||
555 | foreach ($this->data_providers as $provider) { |
||
556 | $manual_attributes = Util::parseIniSettings(base64_decode($provider['manualattributes'] ?? '')); |
||
557 | $provider['port'] = (trim($provider['port']) === '') ? '5060' : $provider['port']; |
||
558 | |||
559 | $reg_strings .= $this->generateProviderRegistrationAuth($provider, $manual_attributes); |
||
560 | $reg_strings .= $this->generateProviderRegistration($provider, $manual_attributes); |
||
561 | $prov_config .= $this->generateProviderOutAuth($provider, $manual_attributes); |
||
562 | |||
563 | $prov_config .= $this->generateProviderAor($provider, $manual_attributes); |
||
564 | $prov_config .= $this->generateProviderIdentify($provider, $manual_attributes); |
||
565 | $prov_config .= $this->generateProviderEndpoint($provider, $manual_attributes); |
||
566 | } |
||
567 | |||
568 | $conf .= $reg_strings; |
||
569 | $conf .= $prov_config; |
||
570 | |||
571 | return $conf; |
||
572 | } |
||
573 | |||
574 | /** |
||
575 | * Генерация Auth для секции Registration провайдера. |
||
576 | * |
||
577 | * @param array $provider |
||
578 | * @param array $manual_attributes |
||
579 | * |
||
580 | * @return string |
||
581 | */ |
||
582 | private function generateProviderRegistrationAuth( |
||
583 | array $provider, |
||
584 | array $manual_attributes |
||
585 | ): string { |
||
586 | $conf = ''; |
||
587 | if ($provider['noregister'] === '1') { |
||
588 | return $conf; |
||
589 | } |
||
590 | $options = [ |
||
591 | 'type' => 'registration-auth', |
||
592 | 'username' => $provider['username'], |
||
593 | 'password' => $provider['secret'], |
||
594 | ]; |
||
595 | $options = $this->overridePJSIPOptionsFromModules( |
||
596 | $provider['uniqid'], |
||
597 | $options, |
||
598 | CoreConfigClass::OVERRIDE_PROVIDER_PJSIP_OPTIONS |
||
599 | ); |
||
600 | $options['type'] = 'auth'; |
||
601 | $conf .= "[REG-AUTH-{$provider['uniqid']}]\n"; |
||
602 | $conf .= Util::overrideConfigurationArray($options, $manual_attributes, 'registration-auth'); |
||
603 | |||
604 | return $conf; |
||
605 | } |
||
606 | |||
607 | /** |
||
608 | * Calls an overridePJSIPOptions function from additional modules |
||
609 | * |
||
610 | * @param $extensionOrId |
||
611 | * @param $options |
||
612 | * @param $method |
||
613 | * |
||
614 | * @return array |
||
615 | */ |
||
616 | private function overridePJSIPOptionsFromModules($extensionOrId, $options, $method): array |
||
617 | { |
||
618 | $configClassObj = new ConfigClass(); |
||
619 | $modulesOverridingArrays = $configClassObj->hookModulesMethodWithArrayResult($method, [$extensionOrId, $options]); |
||
620 | foreach ($modulesOverridingArrays as $newOptionsSet) { |
||
621 | // How to make some order of overrides? |
||
622 | $options = $newOptionsSet; |
||
623 | } |
||
624 | return $options; |
||
625 | } |
||
626 | |||
627 | /** |
||
628 | * Генерация Registration провайдера. |
||
629 | * |
||
630 | * @param array $provider |
||
631 | * @param array $manual_attributes |
||
632 | * |
||
633 | * @return string |
||
634 | */ |
||
635 | private function generateProviderRegistration( |
||
636 | array $provider, |
||
637 | array $manual_attributes |
||
638 | ): string { |
||
639 | $conf = ''; |
||
640 | if ($provider['noregister'] === '1') { |
||
641 | return $conf; |
||
642 | } |
||
643 | $options = [ |
||
644 | 'type' => 'registration', |
||
645 | 'outbound_auth' => "REG-AUTH-{$provider['uniqid']}", |
||
646 | 'contact_user' => $provider['username'], |
||
647 | 'retry_interval' => '30', |
||
648 | 'max_retries' => '100', |
||
649 | 'forbidden_retry_interval' => '300', |
||
650 | 'fatal_retry_interval' => '300', |
||
651 | 'expiration' => $this->generalSettings['SIPDefaultExpiry'], |
||
652 | 'server_uri' => "sip:{$provider['host']}:{$provider['port']}", |
||
653 | 'client_uri' => "sip:{$provider['username']}@{$provider['host']}:{$provider['port']}", |
||
654 | ]; |
||
655 | $options = $this->overridePJSIPOptionsFromModules( |
||
656 | $provider['uniqid'], |
||
657 | $options, |
||
658 | CoreConfigClass::OVERRIDE_PROVIDER_PJSIP_OPTIONS |
||
659 | ); |
||
660 | $conf .= "[REG-{$provider['uniqid']}] \n"; |
||
661 | $conf .= Util::overrideConfigurationArray($options, $manual_attributes, 'registration'); |
||
662 | |||
663 | return $conf; |
||
664 | } |
||
665 | |||
666 | /** |
||
667 | * Генерация Auth провайдера. |
||
668 | * |
||
669 | * @param array $provider |
||
670 | * @param array $manual_attributes |
||
671 | * |
||
672 | * @return string |
||
673 | */ |
||
674 | private function generateProviderOutAuth(array $provider, array $manual_attributes): string { |
||
675 | $conf = ''; |
||
676 | if ('1' === $provider['receive_calls_without_auth'] || empty("{$provider['username']}{$provider['secret']}")) { |
||
677 | return $conf; |
||
678 | } |
||
679 | $options = [ |
||
680 | 'type' => 'endpoint-auth', |
||
681 | 'username' => $provider['username'], |
||
682 | 'password' => $provider['secret'], |
||
683 | ]; |
||
684 | $options = $this->overridePJSIPOptionsFromModules( |
||
685 | $provider['uniqid'], |
||
686 | $options, |
||
687 | CoreConfigClass::OVERRIDE_PROVIDER_PJSIP_OPTIONS |
||
688 | ); |
||
689 | $options['type'] = 'auth'; |
||
690 | $conf .= "[{$provider['uniqid']}-OUT]\n"; |
||
691 | $conf .= Util::overrideConfigurationArray($options, $manual_attributes, 'endpoint-auth'); |
||
692 | |||
693 | return $conf; |
||
694 | } |
||
695 | |||
696 | /** |
||
697 | * Генерация AOR для Endpoint. |
||
698 | * |
||
699 | * @param array $provider |
||
700 | * @param array $manual_attributes |
||
701 | * |
||
702 | * @return string |
||
703 | */ |
||
704 | private function generateProviderAor(array $provider, array $manual_attributes): string |
||
705 | { |
||
706 | $conf = ''; |
||
707 | $defaultuser = (trim($provider['defaultuser']) === '') ? $provider['username'] : $provider['defaultuser']; |
||
708 | if ( ! empty($defaultuser) && '1' !== $provider['receive_calls_without_auth']) { |
||
709 | $contact = "sip:$defaultuser@{$provider['host']}:{$provider['port']}"; |
||
710 | } else { |
||
711 | $contact = "sip:{$provider['host']}:{$provider['port']}"; |
||
712 | } |
||
713 | $options = [ |
||
714 | 'type' => 'aor', |
||
715 | 'max_contacts' => '1', |
||
716 | 'contact' => $contact, |
||
717 | 'maximum_expiration' => $this->generalSettings['SIPMaxExpiry'], |
||
718 | 'minimum_expiration' => $this->generalSettings['SIPMinExpiry'], |
||
719 | 'default_expiration' => $this->generalSettings['SIPDefaultExpiry'], |
||
720 | ]; |
||
721 | if ($provider['qualify'] === '1') { |
||
722 | $options['qualify_frequency'] = $provider['qualifyfreq']; |
||
723 | $options['qualify_timeout'] = '3.0'; |
||
724 | } |
||
725 | $options = $this->overridePJSIPOptionsFromModules( |
||
726 | $provider['uniqid'], |
||
727 | $options, |
||
728 | CoreConfigClass::OVERRIDE_PROVIDER_PJSIP_OPTIONS |
||
729 | ); |
||
730 | $conf .= "[{$provider['uniqid']}]\n"; |
||
731 | $conf .= Util::overrideConfigurationArray($options, $manual_attributes, 'aor'); |
||
732 | |||
733 | return $conf; |
||
734 | } |
||
735 | |||
736 | /** |
||
737 | * Генерация AOR для Endpoint. |
||
738 | * |
||
739 | * @param array $provider |
||
740 | * @param array $manual_attributes |
||
741 | * |
||
742 | * @return string |
||
743 | */ |
||
744 | private function generateProviderIdentify( |
||
745 | array $provider, |
||
746 | array $manual_attributes |
||
747 | ): string { |
||
748 | $conf = ''; |
||
749 | $providerHosts = $this->dataSipHosts[$provider['uniqid']] ?? []; |
||
750 | if ( ! in_array($provider['host'], $providerHosts, true)) { |
||
751 | $providerHosts[] = $provider['host']; |
||
752 | } |
||
753 | $options = [ |
||
754 | 'type' => 'identify', |
||
755 | 'endpoint' => $provider['uniqid'], |
||
756 | 'match' => implode(',', array_unique($providerHosts)), |
||
757 | ]; |
||
758 | $options = $this->overridePJSIPOptionsFromModules( |
||
759 | $provider['uniqid'], |
||
760 | $options, |
||
761 | CoreConfigClass::OVERRIDE_PROVIDER_PJSIP_OPTIONS |
||
762 | ); |
||
763 | $conf .= "[{$provider['uniqid']}]\n"; |
||
764 | $conf .= Util::overrideConfigurationArray($options, $manual_attributes, 'identify'); |
||
765 | |||
766 | return $conf; |
||
767 | } |
||
768 | |||
769 | /** |
||
770 | * Генерация Endpoint провайдера. |
||
771 | * |
||
772 | * @param array $provider |
||
773 | * @param array $manual_attributes |
||
774 | * |
||
775 | * @return string |
||
776 | */ |
||
777 | private function generateProviderEndpoint( |
||
778 | array $provider, |
||
779 | array $manual_attributes |
||
780 | ): string { |
||
781 | $conf = ''; |
||
782 | $fromdomain = (trim($provider['fromdomain']) === '') ? $provider['host'] : $provider['fromdomain']; |
||
783 | $from = (trim($provider['fromuser']) === '') ? "{$provider['username']}; username" : "{$provider['fromuser']}; fromuser"; |
||
784 | |||
785 | if($provider['disablefromuser'] === '1'){ |
||
786 | $from_user = null; |
||
787 | $contactUser = trim($provider['username']??''); |
||
788 | }else{ |
||
789 | $from_user = $from; |
||
790 | $contactUser = $from; |
||
791 | } |
||
792 | |||
793 | $language = $this->generalSettings['PBXLanguage']; |
||
794 | |||
795 | if (count($this->contexts_data[$provider['context_id']]) === 1) { |
||
796 | $context_id = $provider['uniqid']; |
||
797 | } else { |
||
798 | $context_id = $provider['context_id']; |
||
799 | } |
||
800 | $dtmfmode = ($provider['dtmfmode'] === 'rfc2833') ? 'rfc4733' : $provider['dtmfmode']; |
||
801 | $options = [ |
||
802 | 'type' => 'endpoint', |
||
803 | '100rel' => "no", |
||
804 | 'context' => "{$context_id}-incoming", |
||
805 | 'dtmf_mode' => $dtmfmode, |
||
806 | 'disallow' => 'all', |
||
807 | 'allow' => $provider['codecs'], |
||
808 | 'rtp_symmetric' => 'yes', |
||
809 | 'force_rport' => 'yes', |
||
810 | 'rewrite_contact' => 'yes', |
||
811 | 'ice_support' => 'no', |
||
812 | 'direct_media' => 'no', |
||
813 | 'from_user' => $from_user, |
||
814 | 'from_domain' => $fromdomain, |
||
815 | 'contact_user' => $contactUser, |
||
816 | 'sdp_session' => 'mikopbx', |
||
817 | 'language' => $language, |
||
818 | 'aors' => $provider['uniqid'], |
||
819 | 'timers' => ' no', |
||
820 | ]; |
||
821 | if ('1' !== $provider['receive_calls_without_auth'] && !empty("{$provider['username']}{$provider['secret']}")) { |
||
822 | $options['outbound_auth'] = "{$provider['uniqid']}-OUT"; |
||
823 | } |
||
824 | self::getToneZone($options, $language); |
||
825 | $options = $this->overridePJSIPOptionsFromModules( |
||
826 | $provider['uniqid'], |
||
827 | $options, |
||
828 | CoreConfigClass::OVERRIDE_PROVIDER_PJSIP_OPTIONS |
||
829 | ); |
||
830 | $conf .= "[{$provider['uniqid']}]\n"; |
||
831 | $conf .= Util::overrideConfigurationArray($options, $manual_attributes, 'endpoint'); |
||
832 | |||
833 | return $conf; |
||
834 | } |
||
835 | |||
836 | /** |
||
837 | * @param array $options |
||
838 | * @param string $lang |
||
839 | */ |
||
840 | public static function getToneZone(array &$options, string $lang): void |
||
859 | } |
||
860 | } |
||
861 | |||
862 | /** |
||
863 | * Генератор сеции пиров для sip.conf |
||
864 | * |
||
865 | * |
||
866 | * @return string |
||
867 | */ |
||
868 | public function generatePeersPj(): string |
||
869 | { |
||
870 | if ($this->data_peers === null) { |
||
871 | $this->getSettings(); |
||
872 | } |
||
873 | $lang = $this->generalSettings['PBXLanguage']; |
||
874 | $conf = ''; |
||
875 | |||
876 | foreach ($this->data_peers as $peer) { |
||
877 | $manual_attributes = Util::parseIniSettings($peer['manualattributes'] ?? ''); |
||
878 | $conf .= $this->generatePeerAuth($peer, $manual_attributes); |
||
879 | $conf .= $this->generatePeerAor($peer, $manual_attributes); |
||
880 | $conf .= $this->generatePeerEndpoint($lang, $peer, $manual_attributes); |
||
881 | } |
||
882 | |||
883 | $conf .= $this->hookModulesMethod(CoreConfigClass::GENERATE_PEERS_PJ); |
||
884 | |||
885 | return $conf; |
||
886 | } |
||
887 | |||
888 | /** |
||
889 | * Генерация AOR для Endpoint. |
||
890 | * |
||
891 | * @param array $peer |
||
892 | * @param array $manual_attributes |
||
893 | * |
||
894 | * @return string |
||
895 | */ |
||
896 | private function generatePeerAuth(array $peer, array $manual_attributes): string |
||
897 | { |
||
898 | $conf = ''; |
||
899 | $options = [ |
||
900 | 'type' => 'auth', |
||
901 | 'username' => $peer['extension'], |
||
902 | 'password' => $peer['secret'], |
||
903 | ]; |
||
904 | $options = $this->overridePJSIPOptionsFromModules( |
||
905 | $peer['extension'], |
||
906 | $options, |
||
907 | CoreConfigClass::OVERRIDE_PJSIP_OPTIONS |
||
908 | ); |
||
909 | $conf .= "[{$peer['extension']}] \n"; |
||
910 | $conf .= Util::overrideConfigurationArray($options, $manual_attributes, 'auth'); |
||
911 | |||
912 | return $conf; |
||
913 | } |
||
914 | |||
915 | /** |
||
916 | * Генерация AOR для Endpoint. |
||
917 | * |
||
918 | * @param array $peer |
||
919 | * @param array $manual_attributes |
||
920 | * |
||
921 | * @return string |
||
922 | */ |
||
923 | private function generatePeerAor(array $peer, array $manual_attributes): string |
||
924 | { |
||
925 | $conf = ''; |
||
926 | $options = [ |
||
927 | 'type' => 'aor', |
||
928 | 'qualify_frequency' => '60', |
||
929 | 'qualify_timeout' => '5', |
||
930 | 'max_contacts' => '5', |
||
931 | ]; |
||
932 | $options = $this->overridePJSIPOptionsFromModules( |
||
933 | $peer['extension'], |
||
934 | $options, |
||
935 | CoreConfigClass::OVERRIDE_PJSIP_OPTIONS |
||
936 | ); |
||
937 | $conf .= "[{$peer['extension']}]\n"; |
||
938 | $conf .= Util::overrideConfigurationArray($options, $manual_attributes, 'aor'); |
||
939 | |||
940 | if($this->generalSettings['UseWebRTC'] === '1'){ |
||
941 | $conf .= "[{$peer['extension']}-WS]\n"; |
||
942 | $conf .= Util::overrideConfigurationArray($options, $manual_attributes, 'aor'); |
||
943 | } |
||
944 | |||
945 | return $conf; |
||
946 | } |
||
947 | |||
948 | /** |
||
949 | * Генерация endpoint. |
||
950 | * |
||
951 | * @param $lang |
||
952 | * @param array $peer |
||
953 | * @param array $manual_attributes |
||
954 | * |
||
955 | * @return string |
||
956 | */ |
||
957 | private function generatePeerEndpoint( |
||
1027 | } |
||
1028 | |||
1029 | } |