├── .gitattributes ├── .gitignore ├── Api ├── Gql │ ├── AdvanceSettings.php │ ├── Core.php │ ├── Devices.php │ ├── Dids.php │ ├── Extensions.php │ ├── Routes.php │ ├── Tech.php │ ├── Terminations.php │ ├── Trunks.php │ └── Users.php └── Rest │ └── Users.php ├── Backup.php ├── Backup ├── Ampusers.php ├── Astmodules.php ├── Corebase.php ├── Dahdichannels.php ├── Devices.php ├── Did.php ├── Routing.php ├── Trunks.php └── Users.php ├── Components ├── ComponentBase.php ├── Dahdichannels.php └── Outboundrouting.php ├── Console ├── Convert2pjsip.class.php └── Trunks.class.php ├── Core.class.php ├── Dialplan ├── dialparties.php ├── funcSipheaders.php ├── macroAutoBlkvm.php ├── macroAutoConfirm.php ├── macroConfirm.php ├── macroDial.php ├── macroDialone.php └── macroUserCallerid.php ├── LICENSE ├── README.md ├── Restore.php ├── Restore ├── Ampusers.php ├── Astmodules.php ├── Corebase.php ├── Dahdichannels.php ├── Devices.php ├── Did.php ├── Routing.php ├── Trunks.php └── Users.php ├── XML_Parser.php ├── XML_Unserializer.php ├── agi-bin ├── checksound.agi ├── dialparties.agi ├── directory ├── enumlookup.agi ├── fixlocalprefix ├── list-item-remove.php ├── outboundRouteEmail.php └── user_login_out.agi ├── assets ├── css │ └── core.css ├── js │ ├── advancedsettings │ │ └── advancedsettings.js │ ├── ampusers │ │ └── ampusers.js │ ├── astmodules │ │ └── astmodules.js │ ├── dahdichandids │ │ └── dahdichandids.js │ ├── devices │ │ └── devices.js │ ├── did │ │ └── did.js │ ├── extensions │ │ └── extensions.js │ ├── routing │ │ └── routing.js │ ├── trunks │ │ └── trunks.js │ └── users │ │ └── users.js └── less │ ├── ampusers │ └── bootstrap.less │ ├── devices │ └── bootstrap.less │ ├── did │ └── did.less │ ├── extensions │ └── bootstrap.less │ ├── routing │ └── boostrap.less │ ├── trunks │ └── boostrap.less │ └── users │ └── bootstrap.less ├── call-transfer-events.php ├── etc ├── extensions.conf ├── features.conf ├── http.conf ├── iax.conf ├── res_odbc.conf ├── rtp.conf ├── sip.conf ├── sip_notify.conf └── udptl.conf ├── export.html.php ├── functions.inc.php ├── functions.inc ├── Core_SipSettings.class.php ├── Driver.class.php ├── calltransfer-eventlistener.php ├── drivers │ ├── Custom.class.php │ ├── Dahdi.class.php │ ├── Iax2.class.php │ ├── PJSip.class.php │ ├── Sip.class.php │ └── Virtual.class.php ├── functions.deprecated.php └── macro-user-callerid.php ├── hooks └── logrotate ├── images ├── arrow_up_down.png ├── cog.png ├── core_add.png ├── core_delete.png ├── default-option.png ├── edit.png ├── email_edit.png ├── link.png ├── resultset_bottom.png ├── resultset_down.png ├── resultset_top.png ├── resultset_up.png ├── spinner.gif ├── telephone_delete.png ├── telephone_edit.png ├── telephone_key.png ├── user_add.png ├── user_delete.png ├── user_edit.png └── user_go.png ├── install.php ├── module.xml ├── node ├── fastagi-server.js └── lib │ ├── AGI.js │ └── carrier.js ├── page.advancedsettings.php ├── page.ampusers.php ├── page.astmodules.php ├── page.dahdichandids.php ├── page.devices.php ├── page.did.php ├── page.extensions.php ├── page.routing.php ├── page.trunks.php ├── page.users.php ├── phpunit.xml ├── sip_to_pjsip ├── .gitignore ├── astconfigparser.py ├── astdicts.py └── sip_to_pjsip.py ├── sounds └── en │ ├── agent-login.sln │ ├── agent-logoff.sln │ ├── exited-vm-will-be-transfered.sln │ ├── featurecode.sln │ ├── incoming-call-1-accept-2-decline.sln │ ├── incoming-call-no-longer-avail.sln │ ├── line-busy-transfer-menu.sln │ ├── please-enter-your-extension-then-press-pound.sln │ └── you-will-be-transfered-menu.sln ├── utests ├── API │ ├── AdvanceSettingsGqlApi.php │ ├── CoreDeviceGQLTest.php │ ├── CoreExtensionGQLTest.php │ └── DidsGQLTest.php ├── CoreClassTest.php └── dahdiChannelsTest.php └── views ├── ampusers └── bootnav.php ├── backupSettings.php ├── dahdichandids ├── bootnav.php ├── changrid.php ├── didForm.php ├── general.php └── view.php ├── devices.php ├── did ├── advanced_form.php ├── basic_form.php ├── didgrid.php └── rnav.php ├── extensions.php ├── quickCreate.php ├── rnav.php ├── routing ├── bootnav.php ├── form.php ├── grid.php ├── moh.php └── timecond.php ├── trunks ├── bootnav.php ├── custom.php ├── dahdi.php ├── dundi.php ├── header.php ├── main.php ├── misdn.php ├── pjsip.php ├── popover_main.php ├── sip.php ├── trunk_footer.php ├── trunk_header.php ├── trunkgrid.php └── zap.php └── users.php /.gitattributes: -------------------------------------------------------------------------------- 1 | amp_conf/htdocs/admin/assets/js/pbxlib.js merge=ours 2 | module.xml merge=ours 3 | *.po merge=merge-gettext-po 4 | *.pot merge=merge-gettext-po 5 | *.mo merge=ours 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | module.sig 3 | assets/less/** 4 | -------------------------------------------------------------------------------- /Api/Gql/Routes.php: -------------------------------------------------------------------------------- 1 | typeContainer->create('coretech','union'); 12 | $tech->setDescription(''); 13 | 14 | $tech->addResolveType(function($value, $context, $info) use ($tech) { 15 | foreach($tech->getResolveTypeCallbacks() as $cb) { 16 | $out = $cb($value, $context, $info); 17 | if(!is_null($out)) { 18 | return $out; 19 | } 20 | } 21 | return $this->typeContainer->get('unknowntech')->getObject(); 22 | }); 23 | 24 | $tech->addTypeCallback(function() { 25 | return [ 26 | $this->typeContainer->get('unknowntech')->getObject() 27 | ]; 28 | }); 29 | 30 | $unknowntech = $this->typeContainer->create('unknowntech'); 31 | $unknowntech->setDescription('A tech that does not have a GraphQL reference'); 32 | $unknowntech->addFieldCallback(function() { 33 | return [ 34 | 'tech' => [ 35 | 'type' => Type::nonNull(Type::id()), 36 | 'description' => 'The unknown tech id', 37 | 'resolve' => function($value, $args, $context, $info) { 38 | return $value['tech']; 39 | } 40 | ] 41 | ]; 42 | }); 43 | 44 | $pjsip = $this->typeContainer->create('pjsip','object'); 45 | $pjsip->addFieldCallback(function() { 46 | return [ 47 | 'tech' => [ 48 | 'type' => Type::nonNull(Type::id()), 49 | 'description' => 'The unknown tech id', 50 | 'resolve' => function($value, $args, $context, $info) { 51 | return $value['tech']; 52 | } 53 | ], 54 | 'secret' => [ 55 | 'type' => Type::string(), 56 | 'description' => 'Password (secret) configured for the device. Should be alphanumeric with at least 2 letters and numbers to keep secure' 57 | ], 58 | 'dtmfmode' => [ 59 | 'type' => Type::string(), 60 | 'description' => 'The DTMF signaling mode used by this device, usually RFC for most phones' 61 | ], 62 | 'account' => [ 63 | 'type' => Type::string() 64 | ], 65 | 'accountcode' => [ 66 | 'type' => Type::string() 67 | ], 68 | 'aggregate_mwi' => [ 69 | 'type' => Type::string() 70 | ], 71 | 'allow' => [ 72 | 'type' => Type::string() 73 | ], 74 | 'avpf' => [ 75 | 'type' => Type::string() 76 | ], 77 | 'callerid' => [ 78 | 'type' => Type::string() 79 | ], 80 | 'context' => [ 81 | 'type' => Type::string() 82 | ], 83 | 'defaultuser' => [ 84 | 'type' => Type::string() 85 | ], 86 | 'device_state_busy_at' => [ 87 | 'type' => Type::string() 88 | ], 89 | 'dial' => [ 90 | 'type' => Type::string() 91 | ], 92 | 'disallow' => [ 93 | 'type' => Type::string() 94 | ], 95 | 'force_rport' => [ 96 | 'type' => Type::string() 97 | ], 98 | 'icesupport' => [ 99 | 'type' => Type::string() 100 | ], 101 | 'mailbox' => [ 102 | 'type' => Type::string() 103 | ], 104 | 'match' => [ 105 | 'type' => Type::string() 106 | ], 107 | 'max_contacts' => [ 108 | 'type' => Type::string() 109 | ], 110 | 'maximum_expiration' => [ 111 | 'type' => Type::string() 112 | ], 113 | 'media_encryption' => [ 114 | 'type' => Type::string() 115 | ], 116 | 'media_encryption_optimistic' => [ 117 | 'type' => Type::string() 118 | ], 119 | 'media_use_received_transport' => [ 120 | 'type' => Type::string() 121 | ], 122 | 'minimum_expiration' => [ 123 | 'type' => Type::string() 124 | ], 125 | 'mwi_subscription' => [ 126 | 'type' => Type::string() 127 | ], 128 | 'namedcallgroup' => [ 129 | 'type' => Type::string() 130 | ], 131 | 'namedpickupgroup' => [ 132 | 'type' => Type::string() 133 | ], 134 | 'outbound_proxy' => [ 135 | 'type' => Type::string() 136 | ], 137 | 'qualifyfreq' => [ 138 | 'type' => Type::string() 139 | ], 140 | 'rewrite_contact' => [ 141 | 'type' => Type::string() 142 | ], 143 | 'rtcp_mux' => [ 144 | 'type' => Type::string() 145 | ], 146 | 'rtp_symmetric' => [ 147 | 'type' => Type::string() 148 | ], 149 | 'sendrpid' => [ 150 | 'type' => Type::string() 151 | ], 152 | 'sipdriver' => [ 153 | 'type' => Type::string() 154 | ], 155 | 'timers' => [ 156 | 'type' => Type::string() 157 | ], 158 | 'transport' => [ 159 | 'type' => Type::string() 160 | ], 161 | 'trustpid' => [ 162 | 'type' => Type::string() 163 | ], 164 | ]; 165 | }); 166 | 167 | $pjsip->addResolve(function($value, $args, $context, $info) { 168 | if(empty($this->list[$value['id']])) { 169 | $sql = "SELECT keyword, data FROM sip WHERE id = :id"; 170 | $sth = $this->freepbx->Database->prepare($sql); 171 | $sth->execute([":id" => $value['id']]); 172 | $this->list[$value['id']] = $sth->fetchAll(\PDO::FETCH_KEY_PAIR); 173 | } 174 | return isset($this->list[$value['id']][$info->fieldName]) ? $this->list[$value['id']][$info->fieldName] : null; 175 | }); 176 | 177 | $tech->addTypeCallback(function() { 178 | return [ 179 | $this->typeContainer->get('pjsip')->getObject() 180 | ]; 181 | }); 182 | 183 | $tech->addResolveTypeCallback(function($value, $context, $info) { 184 | try { 185 | return $this->typeContainer->get($value['tech'])->getObject(); 186 | } catch(\Exception $e) { 187 | return null; 188 | } 189 | }); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /Api/Gql/Terminations.php: -------------------------------------------------------------------------------- 1 | typeContainer->create('coreterminations'); 12 | $ssw->setDescription('Destination Termination Types'); 13 | $ssw->addFieldCallback(function() { 14 | return [ 15 | 'id' => [ 16 | 'type' => Type::id(), 17 | ], 18 | 'description' => [ 19 | 'type' => Type::string(), 20 | "description" => "Description of the termination type" 21 | ] 22 | ]; 23 | }); 24 | 25 | $destinations = $this->typeContainer->get('destination'); 26 | $destinations->addTypeCallback(function() { 27 | return [ 28 | $this->typeContainer->get('coreterminations')->getObject() 29 | ]; 30 | }); 31 | } 32 | */ 33 | } 34 | -------------------------------------------------------------------------------- /Api/Gql/Trunks.php: -------------------------------------------------------------------------------- 1 | [ 14 | 'description' => _('Read Trunk Information'), 15 | ] 16 | ]; 17 | } 18 | 19 | public function constructQuery() { 20 | $query = []; 21 | if($this->checkReadScope("trunk")) { 22 | $trunk = $this->typeContainer->get('trunk'); 23 | $query['trunks'] = [ 24 | 'type' => $this->typeContainer->get('trunk')->getListReference(), 25 | 'resolve' => function($root, $args) { 26 | return $this->freepbx->Core->listTrunks(); 27 | } 28 | ]; 29 | $query['trunk'] = [ 30 | 'type' => $this->typeContainer->get('trunk')->getReference(), 31 | 'args' => [ 32 | 'id' => [ 33 | 'type' => Type::int(), 34 | 'description' => 'Trunk ID', 35 | ] 36 | ], 37 | 'resolve' => function($root, $args) { 38 | return $this->freepbx->Core->getTrunkByID($args['id']); 39 | } 40 | ]; 41 | } 42 | return $query; 43 | } 44 | 45 | public function postInitTypes() { 46 | $destinations = $this->typeContainer->get('destination'); 47 | $destinations->addType($this->typeContainer->get('trunk')->getReference()); 48 | } 49 | 50 | public function initTypes() { 51 | $trunk = $this->typeContainer->create('trunk'); 52 | $trunk->setDescription('Where you control connectivity to the PSTN and your VoIP provider(s)'); 53 | $trunk->addFields([ 54 | 'id' => [ 55 | 'type' => Type::id(), 56 | 'resolve' => function($row) { 57 | return isset($row['trunkid']) ? $row['trunkid'] : null; 58 | } 59 | ], 60 | 'name' => [ 61 | 'type' => Type::string() 62 | ], 63 | 'tech' => [ 64 | 'type' => Type::string() 65 | ], 66 | 'outcid' => [ 67 | 'type' => Type::string() 68 | ], 69 | 'maxchans' => [ 70 | 'type' => Type::string() 71 | ], 72 | 'failscript' => [ 73 | 'type' => Type::string() 74 | ], 75 | 'dialoutprefix' => [ 76 | 'type' => Type::string() 77 | ], 78 | 'usercontext' => [ 79 | 'type' => Type::string() 80 | ], 81 | 'provider' => [ 82 | 'type' => Type::string() 83 | ], 84 | 'keepcid' => [ 85 | 'type' => Type::boolean(), 86 | 'resolve' => function($row) { 87 | return $row['keepcid'] === 'on'; 88 | } 89 | ], 90 | 'disabled' => [ 91 | 'type' => Type::boolean(), 92 | 'resolve' => function($row) { 93 | return $row['disabled'] === 'on'; 94 | } 95 | ], 96 | 'continue' => [ 97 | 'type' => Type::boolean(), 98 | 'resolve' => function($row) { 99 | return $row['continue'] === 'on'; 100 | } 101 | ], 102 | ]); 103 | } 104 | */ 105 | } 106 | -------------------------------------------------------------------------------- /Api/Rest/Users.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'description' => _('Read Core User information'), 10 | ] 11 | ]; 12 | } 13 | public function setupRoutes($app) { 14 | 15 | /** 16 | * @verb GET 17 | * @return - a list of users 18 | * @uri /core/users 19 | */ 20 | $freepbx = $this->freepbx; 21 | $app->get('/users', function ($request, $response, $args) use($freepbx) { 22 | $users = $freepbx->Core->getAllUsers(); 23 | $response->getBody()->write(json_encode($users)); 24 | return $response->withHeader('Content-Type', 'application/json'); 25 | })->add($this->checkReadScopeMiddleware('users')); 26 | 27 | /** 28 | * @verb GET 29 | * @returns - a user resource 30 | * @uri /core/users/:id 31 | */ 32 | $app->get('/users/{id}', function ($request, $response, $args) use($freepbx) { 33 | $base = $freepbx->Core->getUser($args['id']); 34 | 35 | // Now, find their voicemail information. 36 | $z = file("/etc/asterisk/voicemail.conf"); 37 | foreach ($z as $line) { 38 | $res = explode("=>", $line); 39 | if (!isset($res[1])) 40 | continue; 41 | 42 | if (trim($res[0]) == trim($args['id'])) { 43 | $base['vm'] = trim($res[1]); 44 | return $response->withJson($base); 45 | } 46 | } 47 | 48 | // No voicemail found. 49 | $response->getBody()->write(json_encode($base)); 50 | return $response->withHeader('Content-Type', 'application/json'); 51 | })->add($this->checkReadScopeMiddleware('users')); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Backup.php: -------------------------------------------------------------------------------- 1 | getClasses($id,$transaction) as $module) { 13 | $dirs[$module->className] = $module->getDirs(); 14 | $configs[$module->className] = $module->getConfigs(); 15 | foreach ($module->getFiles() as $file ){ 16 | $this->addFile($file['basename'], $file['path'], $file['basevar'], $module->className); 17 | } 18 | if (method_exists($module, 'getSpecialTables')) { 19 | $tables = $module->getSpecialTables(); 20 | if ($tables) { 21 | $this->dumpTableIntoFile($module->className, $tables, false, false); 22 | } 23 | } 24 | foreach($module->getDeps() as $dependency){ 25 | $this->addDependency($dependency); 26 | } 27 | } 28 | 29 | $configs['features'] = $this->dumpFeatureCodes(); 30 | $configs['settings'] = $this->dumpAdvancedSettings(); 31 | $configs['kvstore'] = $this->dumpKVStore(); 32 | $configs['backup'] = $this->FreePBX->Core->getAll('backup_'.$id); 33 | $this->addDirectories($dirs); 34 | $this->addConfigs($configs); 35 | } 36 | 37 | public function getClasses($id,$transaction){ 38 | $classList = new DirectoryIterator(__DIR__ . '/Backup'); 39 | $classes = new SplObjectStorage(); 40 | foreach ($classList as $classItem) { 41 | if($classItem->isDir()){ 42 | continue; 43 | } 44 | if($classItem->getExtension() !== 'php'){ 45 | continue; 46 | } 47 | if($classItem->getBasename() === 'Corebase.php'){ 48 | continue; 49 | } 50 | $classname = 'FreePBX\\modules\\Core\\Backup\\'.$classItem->getBasename('.php'); 51 | $classes->attach(new $classname($this->FreePBX, $id, $transaction)); 52 | } 53 | return $classes; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Backup/Ampusers.php: -------------------------------------------------------------------------------- 1 | FreePBX->Core->listAMPUsers('assoc',true); 10 | } 11 | public function getFiles(){ 12 | return []; 13 | } 14 | public function getDirs(){ 15 | return []; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /Backup/Astmodules.php: -------------------------------------------------------------------------------- 1 | FreePBX->ConfigFile('modules.conf')->config->ProcessedConfig; 8 | } 9 | public function getFiles(){ 10 | return []; 11 | } 12 | public function getDirs(){ 13 | return []; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Backup/Corebase.php: -------------------------------------------------------------------------------- 1 | className = substr(strrchr(get_class($this), '\\'), 1); 8 | $this->FreePBX = $freepbx; 9 | $this->backupID = $id; 10 | $this->transaction = $transaction; 11 | } 12 | public function getDeps(){ 13 | return []; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Backup/Dahdichannels.php: -------------------------------------------------------------------------------- 1 | FreePBX->Database); 8 | return $dahdichannels->listChannels(); 9 | } 10 | public function getFiles(){ 11 | return []; 12 | } 13 | public function getDirs(){ 14 | return []; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Backup/Devices.php: -------------------------------------------------------------------------------- 1 | FreePBX->Core->getAllDIDs(); 8 | } 9 | public function getFiles(){ 10 | return[]; 11 | } 12 | public function getDirs(){ 13 | return []; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Backup/Routing.php: -------------------------------------------------------------------------------- 1 | FreePBX->Database); 9 | $routes = $routing->listAll(); 10 | foreach($routes as $route){ 11 | $route['patterns'] = $routing->getRoutePatternsByID($route['route_id']); 12 | $route['trunks'] = $routing->getRouteTrunksById($route['route_id']); 13 | $final[] = $route; 14 | } 15 | return $final; 16 | } 17 | public function getFiles(){ 18 | return []; 19 | } 20 | public function getDirs(){ 21 | return []; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Backup/Trunks.php: -------------------------------------------------------------------------------- 1 | $this->FreePBX->Database->query("SELECT * FROM trunks")->fetchAll(\PDO::FETCH_ASSOC), 9 | "techTables" => [ 10 | "pjsip" => $this->FreePBX->Database->query("SELECT * FROM pjsip")->fetchAll(\PDO::FETCH_ASSOC), 11 | ], 12 | "dialpatterns" => $this->FreePBX->Database->query("SELECT * FROM trunk_dialpatterns")->fetchAll(\PDO::FETCH_ASSOC) 13 | ]; 14 | } 15 | public function getFiles(){ 16 | return []; 17 | } 18 | public function getDirs(){ 19 | return []; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Backup/Users.php: -------------------------------------------------------------------------------- 1 | FreePBX->Database->query("SELECT * FROM users")->fetchAll(\PDO::FETCH_ASSOC); 8 | $astdbConfigs = []; 9 | foreach ($users as $user) { 10 | $astdbConfigs[$user['extension']] = $this->FreePBX->Core->getAstdbConfigs($user['extension']); 11 | } 12 | return [ 13 | "users" => $users, 14 | "astdbConfigs" => $astdbConfigs 15 | ]; 16 | } 17 | public function getFiles(){ 18 | return []; 19 | } 20 | public function getDirs(){ 21 | return []; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Components/ComponentBase.php: -------------------------------------------------------------------------------- 1 | Database = \FreePBX::Database(); 10 | $this->logger = $logger; 11 | if(empty($logger)){ 12 | $this->logger = new \Psr\Log\NullLogger(); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Components/Dahdichannels.php: -------------------------------------------------------------------------------- 1 | 'delete', 15 | 'id' => 'delete', 16 | 'value' => _('Delete'), 17 | ]; 18 | } 19 | $buttons['reset'] = [ 20 | 'name' => 'reset', 21 | 'id' => 'reset', 22 | 'value' => _('Reset'), 23 | ]; 24 | $buttons['submit'] = [ 25 | 'name' => 'submit', 26 | 'id' => 'submit', 27 | 'value' => _('Submit') 28 | ]; 29 | 30 | if (!isset($request['view'])||$request['view'] == '') { 31 | $buttons = array(); 32 | } 33 | return $buttons; 34 | 35 | } 36 | 37 | public function listChannels(){ 38 | $sql = "SELECT * FROM dahdichandids ORDER BY channel"; 39 | $stmt = $this->Database->prepare($sql); 40 | $stmt->execute(); 41 | return $stmt->fetchAll(PDO::FETCH_ASSOC); 42 | } 43 | 44 | public function get($channel){ 45 | $sql = "SELECT * FROM dahdichandids WHERE channel = :channel LIMIT 1"; 46 | $stmt = $this->Database->prepare($sql); 47 | $stmt->execute([':channel' => $channel]); 48 | return $stmt->fetch(PDO::FETCH_ASSOC); 49 | } 50 | 51 | public function add($description, $channel, $did) { 52 | // A channel can only be a number 53 | if (!is_numeric($channel)) { 54 | return false; 55 | } 56 | 57 | $sql = "INSERT INTO dahdichandids (channel, description, did) VALUES (:channel, :description, :did)"; 58 | $stmt = $this->Database->prepare($sql); 59 | $stmt->execute([ 60 | ':channel' => $channel, 61 | ':description' => $description, 62 | ':did' => $did, 63 | ]); 64 | return true; 65 | } 66 | public function edit($description, $channel, $did){ 67 | $sql = "UPDATE dahdichandids SET description = :description, did = :did WHERE channel = :channel"; 68 | $stmt = $this->Database->prepare($sql); 69 | return $stmt->execute([ 70 | ':channel' => $channel, 71 | ':description' => $description, 72 | ':did' => $did, 73 | ]); 74 | } 75 | 76 | public function delete($channel){ 77 | $sql = "DELETE FROM dahdichandids WHERE channel = :channel"; 78 | $stmt = $this->Database->prepare($sql); 79 | return $stmt->execute([ 80 | ':channel' => $channel, 81 | ]); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Console/Convert2pjsip.class.php: -------------------------------------------------------------------------------- 1 | setName('convert2pjsip') 14 | ->setDescription(_('Convert legacy chan_sip extensions to chan_pjsip')) 15 | ->setDefinition(array( 16 | new InputOption('all', 'a', InputOption::VALUE_NONE, _('Convert all extensions to PJSIP')), 17 | new InputOption('range', 'r', InputOption::VALUE_REQUIRED, _('Specify a range of extensions to convert to PJSIP. Example: 5000-5100,6020,6030,6040')), 18 | )); 19 | } 20 | 21 | protected function execute(InputInterface $input, OutputInterface $output){ 22 | $convertAllExtensions = $input->getOption('all'); 23 | $rangeArgs = $input->getOption('range'); 24 | 25 | if (!$convertAllExtensions && !$rangeArgs) { 26 | $help = new HelpCommand(); 27 | $help->setCommand($this); 28 | $help->run($input, $output); 29 | return 1; 30 | } 31 | 32 | // get an array of extensions to convert from arguments 33 | $convertExtensions = []; 34 | if($rangeArgs) { 35 | $convertExtensions = $this->convertArgsToArray($rangeArgs); 36 | } 37 | 38 | // get a list of all sip extensions 39 | $extensions = \FreePBX::Core()->getAllDevicesByType('sip'); 40 | foreach($extensions as $exten) { 41 | if ($convertAllExtensions || in_array($exten['id'], $convertExtensions)) { 42 | try { 43 | \FreePBX::Core()->changeDeviceTech($exten['id'], 'pjsip'); 44 | $output->writeln(sprintf(_('Converted extension %s to PJSIP'), $exten['id'])); 45 | } catch(Exception $e) { 46 | $output->writeln(sprintf(_('There was an error converting extension %s to PJSIP:'), $exten['id'])); 47 | $output->writeln($e->getMessage()); 48 | } 49 | } 50 | } 51 | 52 | needreload(); 53 | $output->writeln(_("Extensions converted successfully!")); 54 | $output->writeln(_("Run 'fwconsole reload' to reload config")); 55 | return 0; 56 | } 57 | 58 | private function isValidExtension($value) { 59 | if (!is_numeric($value)) { 60 | throw new \Exception("Invalid extension: {$value}"); 61 | return false; 62 | } 63 | 64 | return true; 65 | } 66 | 67 | private function convertArgsToArray($args) { 68 | $argValues = preg_split('/,/', $args); 69 | 70 | $convertExtensions = array(); 71 | foreach($argValues as $exten) { 72 | if (empty($exten)) { 73 | continue; 74 | } 75 | 76 | $rangeSplit = preg_split('/-/', $exten); 77 | if (count($rangeSplit) === 1) { 78 | $this->isValidExtension($exten); 79 | $convertExtensions[] = $exten; 80 | continue; 81 | } 82 | 83 | if (count($rangeSplit) > 2) { 84 | throw new \Exception("Invalid extension range: {$exten}"); 85 | } 86 | 87 | $this->isValidExtension($rangeSplit[0]); 88 | $this->isValidExtension($rangeSplit[1]); 89 | $range = range($rangeSplit[0], $rangeSplit[1]); 90 | $convertExtensions = array_merge($range, $convertExtensions); 91 | } 92 | 93 | return array_values(array_unique($convertExtensions)); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /Console/Trunks.class.php: -------------------------------------------------------------------------------- 1 | setName('trunks') 17 | ->setDescription(_('Enable and disable trunks from the command line')) 18 | ->setDefinition(array( 19 | new InputOption('enable', null, InputOption::VALUE_REQUIRED, _('Enable given trunk')), 20 | new InputOption('disable', null, InputOption::VALUE_REQUIRED, _('Disable given trunk')), 21 | new InputOption('convert2pjsip', null, InputOption::VALUE_REQUIRED, _('Convert legacy chan_sip trunks to chan_pjsip trunks. eg: ')), 22 | new InputOption('list', null, InputOption::VALUE_NONE, _('list trunks')), 23 | new InputOption('xml', null, InputOption::VALUE_NONE, _('format list as json')), 24 | new InputOption('json', null, InputOption::VALUE_NONE, _('format list as xml')), 25 | new InputArgument('args', InputArgument::IS_ARRAY, '', null),)); 26 | } 27 | protected function execute(InputInterface $input, OutputInterface $output){ 28 | $args = $input->getArgument('args'); 29 | $converttopjsip = $input->getOption('convert2pjsip'); 30 | $ARGUSED = false; 31 | $trunks = $this->listTrunks(); 32 | $trunkids = array(); 33 | foreach($trunks as $trunk){ 34 | $trunkids[$trunk['trunkid']] = $trunk['trunkid']; 35 | } 36 | if($converttopjsip) { 37 | $ARGUSED = True; 38 | $trunkid=($converttopjsip !='all')? $converttopjsip: ''; 39 | \FreePBX::Core()->chansipToPJSIP($output,$trunkid); 40 | } 41 | if($input->getOption('disable')){ 42 | $ARGUSED = True; 43 | $id = $input->getOption('disable'); 44 | $output->writeln(sprintf(_('Disabling Trunk %s Run fwconsole reload'),$id)); 45 | $this->disableTrunk($id); 46 | } 47 | if($input->getOption('enable')){ 48 | $ARGUSED = True; 49 | $id = $input->getOption('enable'); 50 | $output->writeln(sprintf(_('Enabling Trunk %s Run fwconsole reload'),$id)); 51 | $this->enableTrunk($id); 52 | } 53 | if($input->getOption('list')){ 54 | $ARGUSED = True; 55 | if($input->getOption('json')){ 56 | $output->write(json_encode($trunks)); 57 | }elseif($input->getOption('xml')){ 58 | $xml = new \SimpleXMLElement(''); 59 | array_walk_recursive($trunks, array ($xml, 'addChild')); 60 | $output->write($xml->asXML()); 61 | }else{ 62 | $table = new Table($output); 63 | $table->setHeaders(array('ID',_('TECH'),_('Channel ID'), _('Disabled'))); 64 | $table->setRows($trunks); 65 | $table->render(); 66 | } 67 | } 68 | if(!$ARGUSED){ 69 | $table = new Table($output); 70 | $table->setHeaders(array('ID',_('TECH'),_('Channel ID'), _('Disabled'))); 71 | $table->setRows($trunks); 72 | $output->writeln(_('Choose an ID to enable/disable')); 73 | $helper = $this->getHelper('question'); 74 | $question = new ChoiceQuestion($table->render() ?? '',$trunkids,0); 75 | $id = $helper->ask($input, $output, $question); 76 | if($trunks[($id -1 )]['disabled'] == 'off'){ 77 | $output->writeln(sprintf(_('Disabling Trunk %s'),$id)); 78 | if($this->disableTrunk($id)){ 79 | $output->writeln(sprintf(_('Disabled Trunk %s Run fwconsole reload'),$id)); 80 | }else{ 81 | $output->writeln(sprintf(_('Unable to enable Trunk %s. This trunk type may not support this'))); 82 | } 83 | } 84 | if($trunks[($id -1)]['disabled'] == 'on'){ 85 | $output->writeln(_('Enabling Trunk ') . $id); 86 | if($this->enableTrunk($id)){ 87 | $output->writeln(sprintf(_('Enabled Trunk %s Run fwconsole reload'),$id)); 88 | }else{ 89 | $output->writeln(sprintf(_('Unable to enable Trunk %s. This trunk type may not support this'))); 90 | } 91 | } 92 | } 93 | } 94 | private function listTrunks(){ 95 | $db = \FreePBX::Database(); 96 | $sql = "SELECT `trunkid` , `tech` , `channelid` , `disabled` FROM `trunks` ORDER BY `trunkid`"; 97 | $ob = $db->query($sql,\PDO::FETCH_ASSOC); 98 | $gotRows = []; 99 | if($ob->rowCount()){ 100 | $gotRows = $ob->fetchAll(); 101 | } 102 | return $gotRows; 103 | } 104 | private function disableTrunk($id){ 105 | return \FreePBX::Core()->disableTrunk($id); 106 | } 107 | private function enableTrunk($id){ 108 | return \FreePBX::Core()->enableTrunk($id); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Dialplan/funcSipheaders.php: -------------------------------------------------------------------------------- 1 | add($c,$e,'', new \ext_noop('Sip Add Header function called. Adding ${ARG1} = ${ARG2}')); 14 | $ext->add($c,$e,'', new \ext_set('HASH(__SIPHEADERS,${ARG1})', '${ARG2}')); 15 | $ext->add($c,$e,'', new \ext_return()); 16 | 17 | /* 18 | * Apply a SIP Header to the call that's about to be made 19 | */ 20 | 21 | $c = 'func-apply-sipheaders'; 22 | 23 | $ext->add($c,$e,'', new \ext_noop('Applying SIP Headers to channel ${CHANNEL}')); 24 | $ext->add($c,$e,'', new \ext_set('Dchan','${CUT(CHANNEL,/,2)}')); 25 | $ext->add($c,$e,'', new \ext_set('TECH', '${CUT(CHANNEL,/,1)}')); 26 | $ext->add($c,$e,'', new \ext_set('SIPHEADERKEYS', '${HASHKEYS(SIPHEADERS)}')); 27 | $ext->add($c,$e,'', new \ext_while('$["${SET(sipkey=${SHIFT(SIPHEADERKEYS)})}" != ""]')); 28 | $ext->add($c,$e,'', new \ext_set('sipheader', '${HASH(SIPHEADERS,${sipkey})}')); 29 | $driver = \FreePBX::Config()->get("ASTSIPDRIVER"); 30 | if (in_array($driver,array("both","chan_sip"))) { 31 | $ext->add($c,$e,'', new \ext_execif('$["${sipheader}" = "unset" & "${TECH}" = "SIP"]','SIPRemoveHeader','${sipkey}:')); 32 | } 33 | if (in_array($driver,array("both","chan_pjsip"))) { 34 | $ext->add($c,$e,'', new \ext_execif('$["${sipheader}" = "unset" & "${TECH}" = "PJSIP"]','Set','PJSIP_HEADER(remove,${sipkey})=')); 35 | } 36 | 37 | if(\FreePBX::Config()->get('RFC7462')) { 38 | $ext->add($c,$e,'', new \ext_execif('$["${sipheader}" != "unset" & "${sipkey}" = "Alert-Info" & ${REGEX("^<[^>]*>" ${sipheader})} != 1 & ${REGEX("\;info=" ${sipheader})} != 1]', 'Set', 'sipheader=\;info=${sipheader}')); 39 | $ext->add($c,$e,'', new \ext_execif('$["${sipheader}" != "unset" & "${sipkey}" = "Alert-Info" & ${REGEX("^<[^>]*>" ${sipheader})} != 1]', 'Set', 'sipheader=${sipheader}')); 40 | } 41 | 42 | if(in_array($driver,array("both","chan_sip"))) { 43 | $ext->add($c,$e,'', new \ext_execif('$["${TECH}" = "SIP" & "${sipheader}" != "unset"]','SIPAddHeader','${sipkey}:${sipheader}')); 44 | } 45 | if(in_array($driver,array("both","chan_pjsip"))) { 46 | $ext->add($c,$e,'', new \ext_execif('$["${TECH}" = "PJSIP" & "${sipheader}" != "unset"]','Set','PJSIP_HEADER(add,${sipkey})=${sipheader}')); 47 | } 48 | $ext->add($c,$e,'', new \ext_endwhile('')); 49 | $ext->add($c,$e,'', new \ext_return()); 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Dialplan/macroAutoBlkvm.php: -------------------------------------------------------------------------------- 1 | add($context, $exten, '', new \ext_setvar('__GOSUB_RESULT','')); 21 | $ext->add($context, $exten, '', new \ext_set('CFIGNORE','')); 22 | $ext->add($context, $exten, '', new \ext_set('MASTER_CHANNEL(CFIGNORE)','')); 23 | $ext->add($context, $exten, '', new \ext_set('FORWARD_CONTEXT','from-internal')); 24 | $ext->add($context, $exten, '', new \ext_set('MASTER_CHANNEL(FORWARD_CONTEXT)','from-internal')); 25 | $ext->add($context, $exten, '', new \ext_macro('blkvm-clr')); 26 | $ext->add($context, $exten, '', new \ext_noop_trace('DIALEDPEERNUMBER: ${DIALEDPEERNUMBER} CID: ${CALLERID(all)}')); 27 | if ($config->get('AST_FUNC_MASTER_CHANNEL') && $config->get('AST_FUNC_CONNECTEDLINE')) { 28 | // Check that it is numeric so we don't pollute it with odd dialplan stuff like FMGL-blah from followme 29 | $ext->add($context, $exten, '', new \ext_execif('$[!${REGEX("[^0-9]" ${DIALEDPEERNUMBER})} && "${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]', 'Set', 'MASTER_CHANNEL(CONNECTEDLINE(num))=${DIALEDPEERNUMBER}')); 30 | $ext->add($context, $exten, '', new \ext_execif('$[!${REGEX("[^0-9]" ${DIALEDPEERNUMBER})} && "${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]', 'Set', 'MASTER_CHANNEL(CONNECTEDLINE(name))=${DB(AMPUSER/${DIALEDPEERNUMBER}/cidname)}')); 31 | } 32 | $ext->add($context, $exten, '', new \ext_return()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Dialplan/macroAutoConfirm.php: -------------------------------------------------------------------------------- 1 | add($context, $exten, '', new \ext_setvar('__GOSUB_RESULT','')); 20 | $ext->add($context, $exten, '', new \ext_set('CFIGNORE','')); 21 | $ext->add($context, $exten, '', new \ext_set('MASTER_CHANNEL(CFIGNORE)','')); 22 | $ext->add($context, $exten, '', new \ext_set('FORWARD_CONTEXT','from-internal')); 23 | $ext->add($context, $exten, '', new \ext_set('MASTER_CHANNEL(FORWARD_CONTEXT)','from-internal')); 24 | $ext->add($context, $exten, '', new \ext_macro('blkvm-clr')); 25 | $ext->add($context, $exten, '', new \ext_dbdel('RG/${ARG1}/${UNIQCHAN}')); 26 | $ext->add($context, $exten, '', new \ext_noop_trace('DIALEDPEERNUMBER: ${DIALEDPEERNUMBER} CID: ${CALLERID(all)}')); 27 | if ($config->get('AST_FUNC_MASTER_CHANNEL') && $config->get('AST_FUNC_CONNECTEDLINE')) { 28 | // Check that it is numeric so we don't pollute it with odd dialplan stuff like FMGL-blah from followme 29 | $ext->add($context, $exten, '', new \ext_execif('$[!${REGEX("[^0-9]" ${DIALEDPEERNUMBER})} && "${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]', 'Set', 'MASTER_CHANNEL(CONNECTEDLINE(num))=${DIALEDPEERNUMBER}')); 30 | $ext->add($context, $exten, '', new \ext_execif('$[!${REGEX("[^0-9]" ${DIALEDPEERNUMBER})} && "${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]', 'Set', 'MASTER_CHANNEL(CONNECTEDLINE(name))=${DB(AMPUSER/${DIALEDPEERNUMBER}/cidname)}')); 31 | } 32 | $ext->add($context, $exten, '', new \ext_return()); 33 | 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | ______ _____ ______ __ 3 | | ____| | __ \| _ \ \ / / 4 | | |__ _ __ ___ ___| |__) | |_) \ V / 5 | | __| '__/ _ \/ _ \ ___/| _ < > < 6 | | | | | | __/ __/ | | |_) / . \ 7 | |_| |_| \___|\___|_| |____/_/ \_\ 8 | Your Open Source Asterisk PBX GUI Solution 9 | ``` 10 | ### What? 11 | core 12 | This is a module for [FreePBX©](http://www.freepbx.org/ "FreePBX Home Page"). [FreePBX](http://www.freepbx.org/ "FreePBX Home Page") is an open source GUI (graphical user interface) that controls and manages [Asterisk©](http://www.asterisk.org/ "Asterisk Home Page") (PBX). FreePBX is licensed under GPL. 13 | [FreePBX](http://www.freepbx.org/ "FreePBX Home Page") is a completely modular GUI for Asterisk written in PHP and Javascript. Meaning you can easily write any module you can think of and distribute it free of cost to your clients so that they can take advantage of beneficial features in [Asterisk](http://www.asterisk.org/ "Asterisk Home Page") 14 | 15 | ### Setting up a FreePBX system 16 | [See our WIKI](http://wiki.freepbx.org/display/FOP/Install+FreePBX) 17 | ### License 18 | [This modules code is licensed as GPLv3+](http://www.gnu.org/licenses/gpl-3.0.txt) 19 | ### Contributing 20 | To contribute code or modules back into the [FreePBX](http://www.freepbx.org/ "FreePBX Home Page") ecosystem you must fully read our Code License Agreement. We are not able to look at or accept patches or code of any kind until this document is filled out. Please take a look at [http://wiki.freepbx.org/display/DC/Code+License+Agreement](http://wiki.freepbx.org/display/DC/Code+License+Agreement) for more information 21 | ### Issues 22 | Please file bug reports at http://issues.freepbx.org -------------------------------------------------------------------------------- /Restore/Ampusers.php: -------------------------------------------------------------------------------- 1 | FreePBX->Core->addAMPUser($user['username'], $user['password_sha1'], $user['extension_low'], $user['extension_high'], $user['deptname'], explode(';',$user['sections']), true); 12 | } 13 | return $this; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Restore/Astmodules.php: -------------------------------------------------------------------------------- 1 | FreePBX->Config->get('ASTETCDIR').'/modules.conf',''); 11 | $this->FreePBX->ConfigFile('modules.conf')->addEntry('modules', array('autoload = '.$configs['modules']['autoload'])); 12 | unset($configs['modules']['autoload']); 13 | foreach($configs['modules'] as $key => $section){ 14 | foreach ($section as $value) { 15 | $this->FreePBX->ConfigFile('modules.conf')->addEntry('modules', array( $key .' = ' . $value)); 16 | } 17 | } 18 | return $this; 19 | } 20 | } -------------------------------------------------------------------------------- /Restore/Corebase.php: -------------------------------------------------------------------------------- 1 | className = substr(strrchr(get_class($this), '\\'), 1); 8 | $this->transaction = $transaction; 9 | $this->FreePBX = $freepbx; 10 | } 11 | 12 | public function setConfigs($configs){ 13 | return $this; 14 | } 15 | public function setFiles(){ 16 | return $this; 17 | } 18 | public function setDirs(){ 19 | return $this; 20 | } 21 | public function setbackupinfo($backupinfo){ 22 | return $this; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Restore/Dahdichannels.php: -------------------------------------------------------------------------------- 1 | FreePBX->Database); 8 | foreach ($configs as $config) { 9 | $dahdichannels->delete($config['channel']); 10 | $dahdichannels->add($config['description'], $config['channel'], $config['did']); 11 | } 12 | return $this; 13 | } 14 | } -------------------------------------------------------------------------------- /Restore/Devices.php: -------------------------------------------------------------------------------- 1 | backupinfo = $backupinfo; 10 | return $this; 11 | } 12 | 13 | public function setConfigs($configs){ 14 | if(count($configs) > 0){ 15 | $this->updateDevices($configs); 16 | } 17 | $this->FreePBX->Core->devices2astdb(); 18 | return $this; 19 | } 20 | 21 | private function updateDevices($devices) { 22 | $sth = $this->FreePBX->Database->prepare("INSERT INTO devices (`id`, `tech`, `dial`, `devicetype`, `user`, `description`, `emergency_cid`, `hint_override`) VALUES (:id, :tech, :dial, :devicetype, :user, :description, :emergency_cid, :hint_override)"); 23 | foreach($devices['devices'] as $device) { 24 | $sth->execute($device); 25 | } 26 | foreach($devices['techTables'] as $tech => $rows) { 27 | $sth = $this->FreePBX->Database->prepare("INSERT INTO $tech (`id`, `keyword`, `data`, `flags`) VALUES (:id, :keyword, :data, :flags)"); 28 | foreach($rows as $row) { 29 | $sth->execute($row); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Restore/Did.php: -------------------------------------------------------------------------------- 1 | FreePBX->Core->delDID($did['extension'], $did['cidnum']); 9 | $this->FreePBX->Core->addDID($did); 10 | } 11 | return $this; 12 | } 13 | } -------------------------------------------------------------------------------- /Restore/Routing.php: -------------------------------------------------------------------------------- 1 | FreePBX->Database); 8 | foreach ($configs as $route) { 9 | $routing->editById($route['route_id'], $route['name'], $route['outcid'], $route['outcid_mode'], $route['password'], $route['emergency_route'], $route['intracompany_route'], $route['mohclass'], $route['time_group_id'], $route['patterns'], $route['trunks'], $route['seq'], $route['dest'], $route['time_mode'], $route['timezone'], $route['calendar_id'], $route['calendar_group_id']); 10 | } 11 | return $this; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Restore/Trunks.php: -------------------------------------------------------------------------------- 1 | backupinfo = $backupinfo; 10 | return $this; 11 | } 12 | public function setConfigs($configs){ 13 | $this->updateTrunks($configs); 14 | $backupinfo = $this->backupinfo; 15 | $items = isset($backupinfo["backup_items"])? json_decode($backupinfo["backup_items"]) : ''; 16 | if(isset($backupinfo['core_disabletrunks'])){ 17 | $disable_trunk = $backupinfo['core_disabletrunks']=='yes'?'yes':'no'; 18 | }else { 19 | $disable_trunk = "no"; 20 | if(isset($items) && is_array($items)) { 21 | foreach($items as $index => $data){ 22 | foreach($data as $item => $val){ 23 | if($item == "settings"){ 24 | foreach((array) $val as $result){ 25 | if($result->name == "core_disabletrunks" && ($result->value == "yes" || $result->value == "no")){ 26 | $disable_trunk = $result->value; 27 | } 28 | } 29 | } 30 | } 31 | } 32 | } 33 | } 34 | if ((isset($backupinfo['warmspareenabled']) && isset($backupinfo['warmspare_remotetrunks']) && $backupinfo['warmspareenabled'] == 'yes' && $backupinfo['warmspare_remotetrunks'] == 'yes')) { 35 | core_trunks_disable('reg', true); 36 | } 37 | if((!empty($disable_trunk) && $disable_trunk == 'yes')) { 38 | core_trunks_disable('*', true); 39 | } 40 | return $this; 41 | } 42 | 43 | private function updateTrunks($trunks) { 44 | $sth = $this->FreePBX->Database->prepare("INSERT INTO trunks (`trunkid`, `tech`, `channelid`, `name`, `outcid`, `keepcid`, `maxchans`, `failscript`, `dialoutprefix`, `usercontext`, `provider`, `disabled`, `continue`,`routedisplay`) VALUES (:trunkid, :tech, :channelid, :name, :outcid, :keepcid, :maxchans, :failscript, :dialoutprefix, :usercontext, :provider, :disabled, :continue,:routedisplay)"); 45 | foreach($trunks['trunks'] as $trunk) { 46 | if (!array_key_exists('routedisplay', $trunk)) { 47 | $trunk['routedisplay'] = 'on'; 48 | } 49 | $sth->execute($trunk); 50 | } 51 | foreach($trunks['techTables'] as $tech => $rows) { 52 | $sth = $this->FreePBX->Database->prepare("INSERT INTO $tech (`id`, `keyword`, `data`, `flags`) VALUES (:id, :keyword, :data, :flags)"); 53 | foreach($rows as $row) { 54 | $sth->execute($row); 55 | } 56 | } 57 | $sth = $this->FreePBX->Database->prepare("INSERT INTO trunk_dialpatterns (`trunkid`, `match_pattern_prefix`, `match_pattern_pass`, `prepend_digits`, `seq`) VALUES (:trunkid, :match_pattern_prefix, :match_pattern_pass, :prepend_digits, :seq)"); 58 | foreach($trunks['dialpatterns'] as $pattern) { 59 | $sth->execute($pattern); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Restore/Users.php: -------------------------------------------------------------------------------- 1 | updateUsers($configs['users']); 9 | $this->FreePBX->Core->users2astdb(); 10 | if( isset($configs['astdbConfigs'])){ 11 | $this->updateAstdbConfigs($configs['astdbConfigs']); 12 | } 13 | return $this; 14 | } 15 | 16 | private function updateUsers($users) { 17 | $sth = $this->FreePBX->Database->prepare("INSERT INTO users (`extension`, `password`, `name`, `voicemail`, `ringtimer`, `noanswer`, `recording`, `outboundcid`, `sipname`, `noanswer_cid`, `busy_cid`, `chanunavail_cid`, `noanswer_dest`, `busy_dest`, `chanunavail_dest`, `mohclass`) VALUES (:extension, :password, :name, :voicemail, :ringtimer, :noanswer, :recording, :outboundcid, :sipname, :noanswer_cid, :busy_cid, :chanunavail_cid, :noanswer_dest, :busy_dest, :chanunavail_dest, :mohclass)"); 18 | foreach($users as $user) { 19 | $sth->execute($user); 20 | } 21 | } 22 | 23 | private function updateAstdbConfigs($confs) { 24 | $this->FreePBX->Core->putAstdbConfigs($confs); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /agi-bin/checksound.agi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | vmx,n,TrySystem(/bin/ls ${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${ARG1}/${MODE}.[wW][aA][vV]) 20 | */ 21 | 22 | require_once "phpagi.php"; 23 | 24 | $AGI = new AGI(); 25 | $file = $argv[1]; 26 | 27 | if (file_exists($file.".wav") || file_exists($file.".WAV")) { 28 | $AGI->set_variable('SYSTEMSTATUS','SUCCESS'); 29 | } else { 30 | $AGI->set_variable('SYSTEMSTATUS','APPERROR'); 31 | debug("VmX requires: $file.wav or .WAV exist in order to function",1); 32 | } 33 | 34 | // EOF dialparties.agi 35 | exit( 0 ); 36 | 37 | // helper functions 38 | function get_var( $agi, $value) 39 | { 40 | $r = $agi->get_variable( $value ); 41 | 42 | if ($r['result'] == 1) 43 | { 44 | $result = $r['data']; 45 | return $result; 46 | } 47 | else 48 | return ''; 49 | } 50 | 51 | function debug($string, $level=3) 52 | { 53 | global $AGI; 54 | $AGI->verbose($string, $level); 55 | } 56 | 57 | ?> 58 | -------------------------------------------------------------------------------- /agi-bin/enumlookup.agi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | /dev/null 2>&1 ', $res, $var); 28 | if ($var != 127) { 29 | $diginstalled = 'true'; 30 | } 31 | // Are we going to use Google's DNS for ENUM? If not use standard DNS. 32 | // Note, for this to work you need to set USEGOOGLEDNSFORENUM = TRUE in amportal.conf 33 | $usegdns = get_var( $AGI, "ENUMUSEGOOGLEDNS" ); 34 | 35 | // Go through the ENUM providers and look for the number. 36 | foreach ($enums as $enum) { 37 | // If we are using Google DNS, do not use php dns_get_record 38 | if ($usegdns != "TRUE") { 39 | // Are we using php5 and can use get_dns_record? 40 | if (function_exists("dns_get_record")) { 41 | $arr = get_php5($lookup, $enum); 42 | } else { 43 | $AGI->verbose("ENUM lookup via php dns_get_record failed due to php5 not being installed", "0"); 44 | } 45 | } else { 46 | if($diginstalled) { 47 | $arr = get_dig($lookup, $enum); 48 | } else { 49 | $AGI->verbose("ENUM LOOKUPS DISABLED due to no dig command", "0"); 50 | } 51 | } 52 | if (isset($arr[0])) { 53 | foreach($arr as $key => $row) { 54 | $order[$key] = $row["order"]; 55 | $prio[$key] = $row["prio"]; 56 | $nextURI[] = $row['URI']; 57 | $row['URI'] = count($nextURI) - 1; 58 | $arr[$key] = $row; 59 | } 60 | array_multisort($order, SORT_ASC, SORT_NUMERIC, $prio, SORT_ASC, SORT_NUMERIC, $arr); 61 | foreach ($arr as $key => $row) { 62 | if(preg_match('/sip|iax/', strtolower($row['tech']))) { 63 | $URI = $row['URI']; 64 | $dialstr .= $nextURI[$URI]."%"; 65 | } 66 | } 67 | } 68 | } 69 | 70 | $AGI->verbose("Setting DIALARR to $dialstr", 3); 71 | $AGI->set_variable("DIALARR", $dialstr); 72 | if ($dialstr == '') { 73 | $AGI->set_variable("DIALSTATUS", 'CONGESTION'); 74 | } 75 | 76 | function get_dig($lookup, $enum) { 77 | global $AGI; 78 | global $usegdns; 79 | 80 | $arpa = ""; 81 | for ($i = 0; $i < strlen($lookup); $i++) { 82 | $arpa = $lookup[$i].".".$arpa; 83 | } 84 | if ($usegdns == TRUE) { 85 | $AGI->verbose("Looking up $lookup on $enum via shell command DIG and use google dns",3); 86 | $lines = trim(`dig @8.8.8.8 +short ${arpa}${enum} naptr`); 87 | } else { 88 | $AGI->verbose("Looking up $lookup on $enum via shell command DIG",3); 89 | $lines = trim(`dig +short ${arpa}${enum} naptr`); 90 | } 91 | $lines = explode("\n", $lines); 92 | foreach($lines as $line) { 93 | $line = trim($line); 94 | if (preg_match("/^;;/", $line)) 95 | continue; 96 | if (!isset($arr)) $arr = array(); 97 | $line = str_replace("\t", " ", $line); 98 | while(strstr($line, " ")) 99 | $line = str_replace(" ", " ", $line); 100 | $line = str_replace("\"", "", $line); 101 | $line = str_replace("\'", "", $line); 102 | $line = str_replace(" ", "|", $line); 103 | $bits = explode("|", $line); 104 | $bit = explode("!", stripslashes($bits[4])); 105 | $URI = preg_replace('/' . $bit[1] . '/', $bit[2], "+".$lookup); 106 | if($URI[3] == ":") 107 | $URI[3] = "/"; 108 | if($URI[4] == ":") 109 | $URI[4] = "/"; 110 | $arr[] = array("order" => $bits[0], "prio" => $bits[1], "tech" => $bits[3], "URI" => $URI); 111 | } 112 | if (isset($arr[0])) { 113 | return $arr; 114 | } else { 115 | return null; 116 | } 117 | } 118 | 119 | function get_php5($lookup, $enum) { 120 | global $AGI; 121 | 122 | $AGI->verbose("Looking up $lookup on $enum via dns_get_record",3); 123 | 124 | $arpa = ""; 125 | for ($i = 0; $i < strlen($lookup); $i++) { 126 | $arpa = $lookup[$i].".".$arpa; 127 | } 128 | $res = dns_get_record("$arpa$enum", DNS_NAPTR); 129 | foreach ($res as $entry) { 130 | if (!isset($arr)) $arr = array(); 131 | $bit = explode("!", $entry['regex']); 132 | $URI = preg_replace('/' . $bit[1] . '/', $bit[2], "+".$lookup); 133 | if($URI[3] == ":") $URI[3] = "/"; 134 | if($URI[4] == ":") $URI[4] = "/"; 135 | $arr[] = array("order" => $entry['order'], "prio" => $entry['pref'], "tech" => $entry['services'], "URI" => $URI); 136 | } 137 | if (isset($arr[0])) { 138 | return $arr; 139 | } else { 140 | return null; 141 | } 142 | } 143 | 144 | 145 | // helper functions 146 | function get_var( $agi, $value) 147 | { 148 | $r = $agi->get_variable( $value ); 149 | 150 | if ($r['result'] == 1) 151 | { 152 | $result = $r['data']; 153 | return $result; 154 | } 155 | else return ''; 156 | } 157 | 158 | -------------------------------------------------------------------------------- /agi-bin/fixlocalprefix: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | verbose("ERROR: This the fixlocalprefix script has been deprecated and does nothing"); 21 | exit(0); 22 | 23 | ?> 24 | -------------------------------------------------------------------------------- /agi-bin/list-item-remove.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | verbose("Missing list"); 28 | exit(1); 29 | } 30 | 31 | if (!isset($argv[2])) { 32 | $agi->verbose("Missing item"); 33 | exit(1); 34 | } 35 | 36 | if (!isset($argv[3])) { 37 | $agi->verbose("Missing return var name"); 38 | exit(1); 39 | } 40 | 41 | $arglist = $argv[1]; 42 | $argitem = $argv[2]; 43 | $argvarname = $argv[3]; 44 | 45 | if (isset($argv[4])) { 46 | $argsep = "&"; 47 | } else { 48 | $argsep = $argv[4]; 49 | } 50 | 51 | $newlist = str_replace($argitem.$argsep, "", $arglist.$argsep); 52 | 53 | if (substr($newlist, -1, 1) == $argsep) { 54 | $newlist = substr($newlist, 0, -1); 55 | } 56 | 57 | $agi->set_variable($argvarname, $newlist); 58 | ?> 59 | -------------------------------------------------------------------------------- /assets/css/core.css: -------------------------------------------------------------------------------- 1 | 2 | div.dialpatterns { 3 | max-height: 15em; 4 | max-width: 100%; 5 | width: 500px; 6 | overflow: auto; 7 | border: 1px solid #CCCCCC; 8 | white-space: nowrap; 9 | } 10 | #pattern_file { 11 | display: none; 12 | } 13 | .save, .adv_set_default{border-style: none;} 14 | .savetd, .save{display:none;} 15 | 16 | th { padding-top: 1em; border-bottom: 2px solid black; } 17 | tr>td:first-child { width: 20em; } 18 | 19 | #selectall, 20 | #unselectall { 21 | border: 1px solid grey !important; 22 | border-radius: 3px; 23 | } -------------------------------------------------------------------------------- /assets/js/ampusers/ampusers.js: -------------------------------------------------------------------------------- 1 | $('.fpbx-submit').submit(function() { 2 | var theForm = document.ampuser, 3 | username = theForm.username; 4 | 5 | if (username.value === "") { 6 | return warnInvalid(username, _("Username must not be blank")); 7 | } else if (!username.value.match('^[a-zA-Z][a-zA-Z0-9\.]+$')) { 8 | return warnInvalid(username, _("Username cannot start with a number, and can only contain letters and numbers")); 9 | } 10 | return true; 11 | }); 12 | 13 | $(function () { 14 | $("#selected").sortable({ 15 | connectWith : "#unselected", 16 | update: function(e, ui){ 17 | var selected = $("#selected li"); 18 | var valarray = []; 19 | selected.each(function(){valarray.push($(this).data('id'));}); 20 | $('input[name^="sections"]').each(function(){$(this).remove();}); 21 | if($("#unselected li").length !== 0){ 22 | $(valarray).each(function(){ 23 | $("#ampuser").append(''); 24 | }); 25 | }else{ 26 | $("#ampuser").append(''); 27 | } 28 | }, 29 | forcePlaceholderSize: true 30 | }); 31 | $("#unselected").sortable({ 32 | connectWith : "#selected", 33 | update: function(e, ui){ 34 | var selected = $("#selected li"); 35 | var valarray = []; 36 | selected.each(function(){valarray.push($(this).data('id'));}); 37 | $('input[name^="sections"]').each(function(){$(this).remove();}); 38 | if($("#unselected li").length !== 0){ 39 | $(valarray).each(function(){ 40 | $("#ampuser").append(''); 41 | }); 42 | }else{ 43 | $("#ampuser").append(''); 44 | } 45 | }, 46 | }); 47 | }); 48 | $("#selectall").click(function(e){ 49 | e.preventDefault(); 50 | 51 | $("#unselected li").each(function(){ 52 | var ci = $(this); 53 | $( "#selected" ).sortable('option','update')(null,{ 54 | item: ci.appendTo("#selected") 55 | }); 56 | }); 57 | }); 58 | 59 | $("#unselectall").click(function(e){ 60 | e.preventDefault(); 61 | $("#selected li").each(function(){ 62 | var ci = $(this); 63 | $( "#unselected" ).sortable('option','update')(null,{ 64 | item: ci.appendTo("#unselected") 65 | }); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /assets/js/astmodules/astmodules.js: -------------------------------------------------------------------------------- 1 | $(function(){ 2 | $(window).on('scroll', function () { 3 | var scrollPos = $(document).scrollTop(); 4 | $('#addform').css({ 5 | top: scrollPos 6 | }); 7 | }).scroll(); 8 | }); 9 | $(document).ready(function(){ 10 | var tabid = localStorage.getItem('astmodules.chosentab'); 11 | if(tabid !== null){ 12 | var thistab = $('a[href="'+tabid+'"]'); 13 | thistab.trigger("click"); 14 | } 15 | }); 16 | $("#addmodule").click(function(){ 17 | var currentTab = $(".fpbx-submit > ul li.active").data('name'); 18 | var modName = $("#module").val(); 19 | if(modName.match(/[a-zA-Z0-9_]+\.so/) === null){ 20 | fpbxToast(_("The field must match module_name.so")); 21 | return false; 22 | } 23 | $.get("ajax.php", 24 | { 25 | module: 'core', 26 | command: 'addastmodule', 27 | section: currentTab, 28 | astmod: modName 29 | }, 30 | function(data,status){ 31 | location.reload(); 32 | }); 33 | }); 34 | 35 | $('a[href="#amodnoload"],a[href="#amodpreload"],a[href="#amodload"]').on('click',function(e){ 36 | localStorage.setItem('astmodules.chosentab', e.target.hash); 37 | }); 38 | 39 | 40 | 41 | $("#amodnoload,#amodpreload,#amodload").on('post-body.bs.table',function(){ 42 | $('[id^="del"]').on('click', function(e){ 43 | e.preventDefault(); 44 | var currentTab = $(".fpbx-submit > ul li.active").data('name'); 45 | localStorage.setItem('astmodules.tab', currentTab); 46 | var modName = $(this).data('mod'); 47 | var row = $(this).closest('tr'); 48 | console.log(currentTab); 49 | $.get("ajax.php?module=core", 50 | { 51 | command: 'delastmodule', 52 | section: currentTab, 53 | astmod: modName 54 | }, 55 | function(data,status){ 56 | if(data){ 57 | row.remove(); 58 | fpbxToast(_('Modules updated')); 59 | } 60 | }); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /assets/js/dahdichandids/dahdichandids.js: -------------------------------------------------------------------------------- 1 | $('.fpbx-submit').submit(function() { 2 | if($("#channel").val().trim() === "") { 3 | return warnInvalid(channel, _("Channel must not be blank")); 4 | } 5 | if(!($('#channel').val().match(/^[0-9]+$/))) { 6 | return warnInvalid(channel, _("Invalid Channel Number, must be numeric")); 7 | } 8 | if($("#did").val().trim() === "") { 9 | return warnInvalid(did, _("Invalid DID, must be a non-blank DID")); 10 | } 11 | if($.inArray($("#channel").val(), channel_num) != -1){ 12 | return warnInvalid(channel, $("#channel").val() + _(" already used, please use a different channel.")); 13 | } 14 | }); 15 | 16 | $(document).on("click",'a[id^="del"]',function(){ 17 | var cmessage = _("Are you sure you want to delete this DID?"); 18 | if(!confirm(cmessage)){ 19 | return false; 20 | } 21 | var chan = $(this).data('channel'); 22 | var row = $('#row'+chan); 23 | $.ajax({ 24 | url: "config.php", 25 | data: { 26 | display:'dahdichandids', 27 | action:'delete', 28 | channel: chan 29 | }, 30 | type: "GET", 31 | dataType: "html", 32 | success: function(data){ 33 | location.reload(); 34 | }, 35 | error: function(xhr, status, e){ 36 | console.dir(xhr); 37 | console.log(status); 38 | console.log(e); 39 | } 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /assets/js/devices/devices.js: -------------------------------------------------------------------------------- 1 | var deleteExts = []; 2 | $("#table-all-devices-side").on("click-row.bs.table", function(row, $element) { 3 | window.location = "?display=devices&extdisplay="+$element.id; 4 | }); 5 | $(".btn-remove").click(function() { 6 | var btn = $(this); 7 | if(confirm(_("Are you sure you wish to delete these devices?"))) { 8 | btn.find("span").text(_("Deleting...")); 9 | btn.prop("disabled", true); 10 | $.post( "ajax.php", {command: "delete", module: "core", extensions: deleteExts, type: "devices"}, function(data) { 11 | if(data.status) { 12 | btn.find("span").text(_("Delete")); 13 | $(".ext-list").bootstrapTable('remove', { 14 | field: "id", 15 | values: deleteExts 16 | }); 17 | toggle_reload_button("show"); 18 | } else { 19 | btn.find("span").text(_("Delete")); 20 | btn.prop("disabled", true); 21 | alert(data.message); 22 | } 23 | }); 24 | } 25 | }); 26 | $("table").on("post-body.bs.table", function () { 27 | $(this).find(".clickable.delete").click(function() { 28 | var id = $(this).data("id"); 29 | if(confirm(_("Are you sure you wish to delete this device?"))) { 30 | $.post( "ajax.php", {command: "delete", module: "core", extensions: [id], type: "devices"}, function(data) { 31 | if(data.status) { 32 | $(".ext-list").bootstrapTable('remove', { 33 | field: "id", 34 | values: [id.toString()] 35 | }); 36 | toggle_reload_button("show"); 37 | } else { 38 | alert(data.message); 39 | } 40 | }); 41 | } 42 | }); 43 | }); 44 | $("table").on("page-change.bs.table", function () { 45 | $(".btn-remove").prop("disabled", true); 46 | deleteExts = []; 47 | }); 48 | $("table").on('check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table', function () { 49 | var toolbar = $(this).data("toolbar"), button = $(toolbar).find(".btn-remove"), id = $(this).prop("id"); 50 | button.prop('disabled', !$("#"+id).bootstrapTable('getSelections').length); 51 | deleteExts = $.map($("#"+id).bootstrapTable('getSelections'), function (row) { 52 | return row.id; 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /assets/js/did/did.js: -------------------------------------------------------------------------------- 1 | $("[name='privacyman']").change(function(){ 2 | if($(this).val() == "1"){ 3 | $("#pmmaxretries").attr('disabled', false); 4 | $("#pmminlength").attr('disabled', false); 5 | }else{ 6 | $("#pmmaxretries").attr('disabled', true); 7 | $("#pmminlength").attr('disabled', true); 8 | 9 | } 10 | }); 11 | $('.fpbx-submit').submit(function() { 12 | if (!validateDestinations($(this)[0], 1, true)){ 13 | return false; 14 | } 15 | if(!($('#extension').val().match(/^\+?[0-9a-dA-D#\*]+$/)) && ($('#extension').val().trim() != '') && ($('#extension').val().indexOf('_') !== 0)){ 16 | return warnInvalid($('#extension'), _("DID can only be numbers, A-D, * and #. DID may also start with a +. Patterns must begin with an _")); 17 | } 18 | var keywords = ["private","blocked","unknown","restricted","anonymous","unavailable","withheld"]; 19 | if(!isDialpattern($('#cidnum').val()) && !isEmpty($('#cidnum').val().trim()) && keywords.indexOf($('#cidnum').val().toLowerCase()) === -1){ 20 | return warnInvalid($('#cidnum'), _("CIDNUM can only be numbers, A-D, * and #. DID may also start with a +. Patterns must begin with an _ DID may also start with a +.")); 21 | } 22 | 23 | return validateDestinations($(".fpbx-submit")[0],1,true); 24 | }); 25 | -------------------------------------------------------------------------------- /assets/js/extensions/extensions.js: -------------------------------------------------------------------------------- 1 | var deleteExts = []; 2 | function coreSideTable(value, row, index) { 3 | console.log(value); 4 | return value; 5 | } 6 | $("#table-all-side").on("click-row.bs.table", function(row, $element) { 7 | window.location = "?display=extensions&extdisplay="+$element.extension; 8 | }); 9 | 10 | $(".btn-remove").click(function() { 11 | var btn = $(this); 12 | if(confirm(_("Are you sure you wish to delete these extensions?"))) { 13 | btn.find("span").text(_("Deleting...")); 14 | btn.prop("disabled", true); 15 | $.post( "ajax.php", {command: "delete", module: "core", extensions: deleteExts, type: "extensions"}, function(data) { 16 | if(data.status) { 17 | btn.find("span").text(_("Delete")); 18 | $(".ext-list").bootstrapTable('remove', { 19 | field: "extension", 20 | values: deleteExts 21 | }); 22 | $.each(deleteExts, function (i,v) { 23 | delete(extmap[v]); 24 | }) 25 | toggle_reload_button("show"); 26 | if (data.isCommercialDep) { 27 | $("#button_reload").trigger('click'); 28 | } 29 | } else { 30 | btn.find("span").text(_("Delete")); 31 | btn.prop("disabled", true); 32 | alert(data.message); 33 | } 34 | }); 35 | } 36 | }); 37 | $("table").on("post-body.bs.table", function () { 38 | $(this).find(".clickable.delete").click(function() { 39 | var id = $(this).data("id"); 40 | if(confirm(_("Are you sure you wish to delete this extension?"))) { 41 | $.post( "ajax.php", {command: "delete", module: "core", extensions: [id], type: "extensions"}, function(data) { 42 | if(data.status) { 43 | delete(extmap[id]); 44 | $(".ext-list").bootstrapTable('remove', { 45 | field: "extension", 46 | values: [id.toString()] 47 | }); 48 | toggle_reload_button("show"); 49 | if (data.isCommercialDep) { 50 | $("#button_reload").trigger('click'); 51 | } 52 | } else { 53 | alert(data.message); 54 | } 55 | }); 56 | } 57 | }); 58 | }); 59 | $("table").on("page-change.bs.table", function () { 60 | $(".btn-remove").prop("disabled", true); 61 | deleteExts = []; 62 | }); 63 | $("table").on('check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table', function () { 64 | var toolbar = $(this).data("toolbar"), button = $(toolbar).find(".btn-remove"), id = $(this).prop("id"); 65 | button.prop('disabled', !$("#"+id).bootstrapTable('getSelections').length); 66 | deleteExts = $.map($("#"+id).bootstrapTable('getSelections'), function (row) { 67 | return row.extension; 68 | }); 69 | }); 70 | $('#extension').on('change', function(){ 71 | $('#title-badge').remove(); 72 | if($('#extension').val() != '' || $('#action').val() == 'add'){ 73 | $('#title').append(''+$('#extension').val()+''); 74 | } 75 | }); 76 | -------------------------------------------------------------------------------- /assets/js/users/users.js: -------------------------------------------------------------------------------- 1 | var deleteExts = []; 2 | $("#table-all-users-side").on("click-row.bs.table", function(row, $element) { 3 | window.location = "?display=users&extdisplay="+$element.extension; 4 | }); 5 | $(".btn-remove").click(function() { 6 | var btn = $(this); 7 | if(confirm(_("Are you sure you wish to delete these users?"))) { 8 | btn.find("span").text(_("Deleting...")); 9 | btn.prop("disabled", true); 10 | $.post( "ajax.php", {command: "delete", module: "core", extensions: deleteExts, type: "users"}, function(data) { 11 | if(data.status) { 12 | btn.find("span").text(_("Delete")); 13 | $(".ext-list").bootstrapTable('remove', { 14 | field: "extension", 15 | values: deleteExts 16 | }); 17 | toggle_reload_button("show"); 18 | } else { 19 | btn.find("span").text(_("Delete")); 20 | btn.prop("disabled", true); 21 | alert(data.message); 22 | } 23 | }); 24 | } 25 | }); 26 | $("table").on("post-body.bs.table", function () { 27 | $(this).find(".clickable.delete").click(function() { 28 | var id = $(this).data("id"); 29 | if(confirm(_("Are you sure you wish to delete this user?"))) { 30 | $.post( "ajax.php", {command: "delete", module: "core", extensions: [id], type: "users"}, function(data) { 31 | if(data.status) { 32 | $(".ext-list").bootstrapTable('remove', { 33 | field: "extension", 34 | values: [id.toString()] 35 | }); 36 | toggle_reload_button("show"); 37 | } else { 38 | alert(data.message); 39 | } 40 | }); 41 | } 42 | }); 43 | }); 44 | $("table").on("page-change.bs.table", function () { 45 | $(".btn-remove").prop("disabled", true); 46 | deleteExts = []; 47 | }); 48 | $("table").on('check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table', function () { 49 | var toolbar = $(this).data("toolbar"), button = $(toolbar).find(".btn-remove"), id = $(this).prop("id"); 50 | button.prop('disabled', !$("#"+id).bootstrapTable('getSelections').length); 51 | deleteExts = $.map($("#"+id).bootstrapTable('getSelections'), function (row) { 52 | return row.extension; 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /assets/less/ampusers/bootstrap.less: -------------------------------------------------------------------------------- 1 | #sections { 2 | height: 300px; 3 | } 4 | -------------------------------------------------------------------------------- /assets/less/devices/bootstrap.less: -------------------------------------------------------------------------------- 1 | .clickable { 2 | cursor: pointer; 3 | color: #2779aa; 4 | margin-left: 5px; 5 | } 6 | 7 | #table-all-devices-side { 8 | tr { 9 | cursor: pointer; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /assets/less/did/did.less: -------------------------------------------------------------------------------- 1 | #didtablernav { 2 | tr { 3 | cursor: pointer; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /assets/less/extensions/bootstrap.less: -------------------------------------------------------------------------------- 1 | .clickable { 2 | cursor: pointer; 3 | color: #2779aa; 4 | margin-left: 5px; 5 | } 6 | 7 | #table-all-side { 8 | tr { 9 | cursor: pointer; 10 | } 11 | } 12 | 13 | .modal.paged { 14 | .fa.fa-question-circle { 15 | color: #0070a3; 16 | cursor: pointer; 17 | height: 10px; 18 | width: 10px; 19 | font-size: small; 20 | vertical-align: super; 21 | display: inline-block; 22 | text-align: center; 23 | margin: 2px; 24 | padding-right: 1.5px; 25 | padding-top: 1px; 26 | padding-left: 1px; 27 | font-weight: normal; 28 | } 29 | .help-block { 30 | display: none; 31 | } 32 | .help-block.active { 33 | display: block; 34 | } 35 | .form-group { 36 | label { 37 | font-weight: bold; 38 | } 39 | } 40 | } 41 | 42 | .tabpanel { 43 | .scroller-left { 44 | left: 15px; 45 | } 46 | .scroller-right { 47 | right: 15px; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /assets/less/routing/boostrap.less: -------------------------------------------------------------------------------- 1 | .table > thead > tr > th, 2 | .table > tbody > tr > th, 3 | .table > tfoot > tr > th, 4 | .table > thead > tr > td, 5 | .table > tbody > tr > td, 6 | .table > tfoot > tr > td { 7 | padding-bottom: 7px; 8 | line-height: inherit; 9 | vertical-align: middle; 10 | } 11 | 12 | .text-success { 13 | color: green; 14 | } 15 | .sort-handle { 16 | cursor: pointer; 17 | } 18 | /** 19 | * Mainly fixes for webkit browsers and their stupid forced border-radius 20 | * on select boxes 21 | * might be a mac thing as well 22 | * works fine in other broswsers 23 | */ 24 | .input-group { 25 | .input-group-addon.move { 26 | z-index: 3; 27 | position: relative; 28 | cursor: move; 29 | } 30 | select.form-control { 31 | width: 101%; 32 | left: -5px; 33 | } 34 | } 35 | 36 | #dptable { 37 | .input-group-addon:first-child { 38 | position: relative; 39 | left: 2px; 40 | } 41 | .input-group-addon:last-child { 42 | position: relative; 43 | right: 2px; 44 | } 45 | 46 | .input-group-addon { 47 | padding: 6px 3px; 48 | } 49 | 50 | .prepend { 51 | width: 120px; 52 | } 53 | 54 | .prefix { 55 | width: 90px; 56 | } 57 | 58 | .match { 59 | } 60 | 61 | .callerid { 62 | width: 105px; 63 | } 64 | > tbody > tr > td { 65 | padding: 3px; 66 | } 67 | } 68 | 69 | #routetrunks tr td { 70 | border-color: transparent !important; 71 | } 72 | -------------------------------------------------------------------------------- /assets/less/trunks/boostrap.less: -------------------------------------------------------------------------------- 1 | #dptable { 2 | .input-group-addon:first-child { 3 | position: relative; 4 | left: 2px; 5 | } 6 | .input-group-addon:last-child { 7 | position: relative; 8 | right: 2px; 9 | } 10 | 11 | .input-group-addon { 12 | padding: 6px 3px; 13 | } 14 | 15 | .prepend { 16 | width: 120px; 17 | } 18 | 19 | .prefix { 20 | width: 90px; 21 | } 22 | 23 | .match { 24 | } 25 | 26 | .callerid { 27 | width: 105px; 28 | } 29 | > tbody > tr > td { 30 | padding: 3px; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /assets/less/users/bootstrap.less: -------------------------------------------------------------------------------- 1 | .clickable { 2 | cursor: pointer; 3 | color: #2779aa; 4 | margin-left: 5px; 5 | } 6 | 7 | #table-all-users-side { 8 | tr { 9 | cursor: pointer; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /call-transfer-events.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php -q 2 | true, 8 | ); 9 | $bootstrap_settings['astman_options']['cachemode'] = false; 10 | include '/etc/freepbx.conf'; 11 | $freepbx = \FreePBX::Create(); 12 | $config = $freepbx->Config(); 13 | $monitordir = $config->get('ASTSPOOLDIR').'/monitor'; 14 | $format = $config->get('MIXMON_FORMAT'); 15 | include __DIR__.'/functions.inc/calltransfer-eventlistener.php'; 16 | -------------------------------------------------------------------------------- /etc/features.conf: -------------------------------------------------------------------------------- 1 | ;--------------------------------------------------------------------------------; 2 | ; Do NOT edit this file as it is auto-generated by FreePBX. All modifications to ; 3 | ; this file must be done via the web gui. There are alternative files to make ; 4 | ; custom modifications. ; 5 | ;--------------------------------------------------------------------------------; 6 | 7 | [general] 8 | #include features_general_additional.conf 9 | #include features_general_custom.conf 10 | 11 | [applicationmap] 12 | #include features_applicationmap_additional.conf 13 | #include features_applicationmap_custom.conf 14 | 15 | [featuremap] 16 | #include features_featuremap_additional.conf 17 | #include features_featuremap_custom.conf 18 | -------------------------------------------------------------------------------- /etc/http.conf: -------------------------------------------------------------------------------- 1 | ;--------------------------------------------------------------------------------; 2 | ; Do NOT edit this file as it is auto-generated by FreePBX. All modifications to ; 3 | ; this file must be done via the web gui. There are alternative files to make ; 4 | ; custom modifications. ; 5 | ;--------------------------------------------------------------------------------; 6 | ; 7 | ; This file is part of FreePBX. 8 | ; 9 | ; FreePBX is free software: you can redistribute it and/or modify 10 | ; it under the terms of the GNU General Public License as published by 11 | ; the Free Software Foundation, either version 2 of the License, or 12 | ; (at your option) any later version. 13 | ; 14 | ; FreePBX is distributed in the hope that it will be useful, 15 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | ; GNU General Public License for more details. 18 | ; 19 | ; You should have received a copy of the GNU General Public License 20 | ; along with FreePBX. If not, see . 21 | ; 22 | ; Copyright (C) 2013 SCHMOOZECOM INC (USA) 23 | 24 | #include http_additional.conf 25 | #include http_custom.conf 26 | -------------------------------------------------------------------------------- /etc/iax.conf: -------------------------------------------------------------------------------- 1 | ;--------------------------------------------------------------------------------; 2 | ; Do NOT edit this file as it is auto-generated by FreePBX. All modifications to ; 3 | ; this file must be done via the web gui. There are alternative files to make ; 4 | ; custom modifications. ; 5 | ;--------------------------------------------------------------------------------; 6 | [general] 7 | 8 | ; These will all be included in the [general] context 9 | #include iax_general_additional.conf 10 | #include iax_general_custom.conf 11 | #include iax_registrations_custom.conf 12 | #include iax_registrations.conf 13 | 14 | ; These should all be expected to come after the [general] context 15 | ; 16 | ;iax_custom.conf is the proper place to start creating new contexts that you 17 | ;might have a need for. Dundi IAX trunks is one example of when this file is needed. 18 | ; 19 | #include iax_custom.conf 20 | #include iax_additional.conf 21 | ; 22 | ;iax_custom_post.conf will allow you to modify FreePBX generated IAX setups so 23 | ;that you can add additional parameters to a auto-generated setup. 24 | ;if you have a auto-generated context of [foobar] and need to add a parameter 25 | ;to it then create this line [foobar](+) and place your additions on the next line 26 | ; 27 | #include iax_custom_post.conf 28 | 29 | -------------------------------------------------------------------------------- /etc/res_odbc.conf: -------------------------------------------------------------------------------- 1 | ;--------------------------------------------------------------------------------; 2 | ; Do NOT edit this file as it is auto-generated by FreePBX. All modifications to ; 3 | ; this file must be done via the web gui. There are alternative files to make ; 4 | ; custom modifications. ; 5 | ;--------------------------------------------------------------------------------; 6 | ; 7 | ; This file is part of FreePBX. 8 | ; 9 | ; FreePBX is free software: you can redistribute it and/or modify 10 | ; it under the terms of the GNU General Public License as published by 11 | ; the Free Software Foundation, either version 2 of the License, or 12 | ; (at your option) any later version. 13 | ; 14 | ; FreePBX is distributed in the hope that it will be useful, 15 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | ; GNU General Public License for more details. 18 | ; 19 | ; You should have received a copy of the GNU General Public License 20 | ; along with FreePBX. If not, see . 21 | ; 22 | ; Copyright (C) 2012 Astrogen LLC (USA) 23 | 24 | #include res_odbc_custom.conf 25 | #include res_odbc_additional.conf 26 | -------------------------------------------------------------------------------- /etc/rtp.conf: -------------------------------------------------------------------------------- 1 | ;--------------------------------------------------------------------------------; 2 | ; Do NOT edit this file as it is auto-generated by FreePBX. All modifications to ; 3 | ; this file must be done via the web gui. There are alternative files to make ; 4 | ; custom modifications. ; 5 | ;--------------------------------------------------------------------------------; 6 | ; 7 | ; This file is part of FreePBX. 8 | ; 9 | ; FreePBX is free software: you can redistribute it and/or modify 10 | ; it under the terms of the GNU General Public License as published by 11 | ; the Free Software Foundation, either version 2 of the License, or 12 | ; (at your option) any later version. 13 | ; 14 | ; FreePBX is distributed in the hope that it will be useful, 15 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | ; GNU General Public License for more details. 18 | ; 19 | ; You should have received a copy of the GNU General Public License 20 | ; along with FreePBX. If not, see . 21 | ; 22 | ; Copyright (C) 2012 Astrogen LLC (USA) 23 | 24 | #include rtp_additional.conf 25 | #include rtp_custom.conf 26 | -------------------------------------------------------------------------------- /etc/sip.conf: -------------------------------------------------------------------------------- 1 | ;--------------------------------------------------------------------------------; 2 | ; Do NOT edit this file as it is auto-generated by FreePBX. All modifications to ; 3 | ; this file must be done via the web gui. There are alternative files to make ; 4 | ; custom modifications. ; 5 | ;--------------------------------------------------------------------------------; 6 | [general] 7 | 8 | ; These files will all be included in the [general] context 9 | ; 10 | #include sip_general_additional.conf 11 | 12 | ;sip_general_custom.conf is the proper file location for placing any sip general 13 | ;options that you might need set. For example: enable and force the sip jitterbuffer. 14 | ;If these settings are desired they should be set the sip_general_custom.conf file. 15 | ; 16 | ; jbenable=yes 17 | ; jbforce=yes 18 | ; 19 | ;It is also the proper place to add the lines needed for sip nat'ing when going 20 | ;through a firewall. For nat'ing you'd need to add the following lines: 21 | ; nat=yes , externip= , localhost= , and optionally fromdomain= . 22 | ; 23 | #include sip_general_custom.conf 24 | 25 | ;sip_nat.conf is here for legacy support reasons and for those that upgrade 26 | ;from previous versions. If you have this file with lines in it please make 27 | ;sure they are not duplicated in sip_general_custom.conf, if so remove them 28 | ;from sip_nat.conf as sip_general_custom.conf will have precedence. 29 | #include sip_nat.conf 30 | 31 | ;sip_registrations_custom.conf is for any customizations you might need to do to 32 | ;the automatically generated registrations that FreePBX makes. 33 | ; 34 | #include sip_registrations_custom.conf 35 | #include sip_registrations.conf 36 | 37 | ; These files should all be expected to come after the [general] context 38 | ; 39 | #include sip_custom.conf 40 | #include sip_additional.conf 41 | 42 | ;sip_custom_post.conf If you have extra parameters that are needed for a 43 | ;extension to work to for example, those go here. So you have extension 44 | ;1000 defined in your system you start by creating a line [1000](+) in this 45 | ;file. Then on the next line add the extra parameter that is needed. 46 | ;When the sip.conf is loaded it will append your additions to the end of 47 | ;that extension. 48 | ; 49 | #include sip_custom_post.conf 50 | -------------------------------------------------------------------------------- /etc/sip_notify.conf: -------------------------------------------------------------------------------- 1 | ;--------------------------------------------------------------------------------; 2 | ; Do NOT edit this file as it is auto-generated by FreePBX. All modifications to ; 3 | ; this file must be done via the web gui. There are alternative files to make ; 4 | ; custom modifications. ; 5 | ;--------------------------------------------------------------------------------; 6 | ; 7 | 8 | #include sip_notify_custom.conf 9 | #include sip_notify_additional.conf 10 | -------------------------------------------------------------------------------- /etc/udptl.conf: -------------------------------------------------------------------------------- 1 | ;--------------------------------------------------------------------------------; 2 | ; Do NOT edit this file as it is auto-generated by FreePBX. All modifications to ; 3 | ; this file must be done via the web gui. There are alternative files to make ; 4 | ; custom modifications. ; 5 | ;--------------------------------------------------------------------------------; 6 | ; 7 | ; This file is part of FreePBX. 8 | ; 9 | ; FreePBX is free software: you can redistribute it and/or modify 10 | ; it under the terms of the GNU General Public License as published by 11 | ; the Free Software Foundation, either version 2 of the License, or 12 | ; (at your option) any later version. 13 | ; 14 | ; FreePBX is distributed in the hope that it will be useful, 15 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | ; GNU General Public License for more details. 18 | ; 19 | ; You should have received a copy of the GNU General Public License 20 | ; along with FreePBX. If not, see . 21 | ; 22 | ; Copyright (C) 2013 Schmooze Com, Inc 23 | 24 | ; 25 | ; UDPTL Configuration (UDPTL is one of the transports for T.38) 26 | ; 27 | ; NOTICE: Currently not including this file can result in Asterisk terminating. 28 | ; There is no support yet for configuring this in FreePBX, that 29 | ; functionality will come in the future when needed. The following are 30 | ; the default settings. Changes should be made in the custom file. 31 | ; 32 | ; DEFAULTS: 33 | ; 34 | ; UDPTL start and UDPTL end configure start and end addresses 35 | ; 36 | ; udptlstart=4000 37 | ; udptlend=4999 38 | ; 39 | ; Whether to enable or disable UDP checksums on UDPTL traffic 40 | ; 41 | ; udptlchecksums=no 42 | ; 43 | ; The number of error correction entries in a UDPTL packet 44 | ; 45 | ; udptlfecentries = 3 46 | ; 47 | ; The span over which parity is calculated for FEC in a UDPTL packet 48 | ; 49 | ; udptlfecspan = 3 50 | ; 51 | ; Some VoIP providers will only accept an offer with an even-numbered 52 | ; UDPTL port. Set this option so that Asterisk will only attempt to use 53 | ; even-numbered ports when negotiating T.38. Default is no. 54 | ; 55 | ; use_even_ports = no 56 | 57 | [general] 58 | #include udptl_custom.conf 59 | -------------------------------------------------------------------------------- /export.html.php: -------------------------------------------------------------------------------- 1 | escapeSimple($extdisplay)."'"; 21 | $name = sql($sql,'getOne'); 22 | if(isset($name) && !empty($name)) { 23 | //Get all dial patterns for this route 24 | $sql = "SELECT prepend_digits, match_pattern_prefix, match_pattern_pass, match_cid FROM outbound_route_patterns WHERE `route_id` = '".$db->escapeSimple($extdisplay)."'"; 25 | $csvdata = sql($sql,'getAll'); 26 | } 27 | } else { 28 | $csvdata = array(); 29 | } 30 | break; 31 | case "trunks": 32 | $extdisplay = str_replace('OUT_','',$extdisplay); 33 | //Setup Column headers. 34 | $header[0] = array("prepend", "prefix", "match pattern"); 35 | 36 | if(!empty($extdisplay)) { 37 | //Get trunk name 38 | $sql = "SELECT name FROM trunks WHERE `trunkid` = '".$db->escapeSimple($extdisplay)."'"; 39 | $name = sql($sql,'getOne'); 40 | if(isset($name) && !empty($name)) { 41 | //Get all dial patterns for this trunk 42 | $sql = "SELECT prepend_digits, match_pattern_prefix, match_pattern_pass FROM trunk_dialpatterns WHERE `trunkid` = '".$db->escapeSimple($extdisplay)."'"; 43 | $csvdata = sql($sql,'getAll'); 44 | } 45 | } else { 46 | $csvdata = array(); 47 | } 48 | break; 49 | } 50 | 51 | if(!empty($header)) { 52 | $final_data = array_merge($header,$csvdata); //Merge headers and data 53 | 54 | header("Content-type: text/csv"); //Declare to browser this is a CSV file 55 | header('Content-Disposition: attachment; filename="'.$name.'_'.$display.'_dial_patterns.csv"'); //Tell the browser it's an attachment (meaning don't display it) 56 | header("Cache-Control: no-cache, must-revalidate"); //No caching HTML 1.1 uhh who uses that!? 57 | header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); //No Caching set date to past..... 58 | 59 | $outstream = fopen("php://output",'w'); //Set PHP output to stream 60 | 61 | foreach ($final_data as $fields) { 62 | fputcsv($outstream, $fields); //Stream each line out 63 | } 64 | 65 | fclose($outstream); //Close stream 66 | } 67 | -------------------------------------------------------------------------------- /functions.inc/Core_SipSettings.class.php: -------------------------------------------------------------------------------- 1 | FreePBX = $freepbx; 7 | 8 | } 9 | 10 | public function doPage($pagename, &$text) { 11 | if ($pagename == "page.sipsettings.php") { 12 | $this->doSipsettingsPage($text); 13 | } else { 14 | throw new Exception("I don't know what to do with $pagename"); 15 | } 16 | } 17 | 18 | private function doSipsettingsPage(&$text) { 19 | // Split the entire page at EOL 20 | $foo = preg_split("/\n/", $text); 21 | 22 | // Grab the first line, we'll need this later. 23 | $header = array_shift($foo); 24 | 25 | // Tell people what SIP Driver(s) they're using. 26 | $driver = $this->FreePBX->Config->get_conf_setting('ASTSIPDRIVER'); 27 | if ($driver == "both") { 28 | $str = "Asterisk is currently using chan_sip AND chan_pjsip for SIP Traffic.
You can change this on the Advanced Settings Page
\n"; 29 | } else { 30 | $str = "Asterisk is currently using $driver for SIP Traffic.
You can change this on the Advanced Settings Page
\n"; 31 | } 32 | 33 | // Add it onto the front of the array 34 | array_unshift($foo, $header, $str); 35 | 36 | // and put it back together. Note, $text is a reference. Don't need to return it. 37 | $text = implode("\n", $foo); 38 | } 39 | } 40 | 41 | 42 | -------------------------------------------------------------------------------- /functions.inc/Driver.class.php: -------------------------------------------------------------------------------- 1 | freepbx = $freepbx; 14 | $this->database = $freepbx->Database; 15 | } 16 | 17 | /** 18 | * Get Information about Driver 19 | */ 20 | public function getInfo() { 21 | return array( 22 | "rawName" => null, 23 | "prettyName" > null, 24 | "asteriskSupport" => null 25 | ); 26 | } 27 | 28 | /** 29 | * Add a Device 30 | * @param int $id The extension/device number 31 | * @param array $settings [description] 32 | */ 33 | public function addDevice($id, $settings) { 34 | return false; 35 | } 36 | 37 | /** 38 | * Delete a device 39 | * @param int $id The extension/device number 40 | */ 41 | public function delDevice($id) { 42 | return true; 43 | } 44 | 45 | /** 46 | * Get a device 47 | * @param int $id The extension/device number 48 | */ 49 | public function getDevice($id) { 50 | return array(); 51 | } 52 | 53 | /** 54 | * Get default device settings 55 | * @param int $id The extension/device number 56 | * @param string $displayname The display name 57 | * @param int $flag Auto incrementing field id 58 | */ 59 | public function getDefaultDeviceSettings($id, $displayname, &$flag) { 60 | return false; 61 | } 62 | 63 | /** 64 | * Get Device Display 65 | * 66 | * Get all the options for display 67 | * 68 | * @param string $display The display 69 | * @param array $deviceInfo The Device Info 70 | * @param object $currentcomponent Current Component Object 71 | * @param string $primarySection The primary section ("Add Extension" or "Edit Extension") 72 | */ 73 | public function getDeviceDisplay($display, $deviceInfo, $currentcomponent, $primarySection) { 74 | return ""; 75 | } 76 | 77 | /** 78 | * Used for writing configurations out for each driver if needed 79 | */ 80 | public function genConfig() { 81 | return array(); 82 | } 83 | 84 | /** 85 | * Used for modifing configurations before final write 86 | * @param array $conf An array of configurations 87 | */ 88 | public function writeConfig($conf) { 89 | return $conf; 90 | } 91 | 92 | protected function filterValidCodecs($codecs) { 93 | return $this->freepbx->Core->filterValidCodecs($codecs); 94 | } 95 | 96 | // get a mapping of the devices to user description and vmcontext 97 | // used for fixed devices when generating tech.conf files to 98 | // override some of the mailbox options or remove them if novm 99 | // 100 | public static function devicesGetUserMappings() { 101 | if (!empty(static::$devicesGetUserMappings)) { 102 | return static::$devicesGetUserMappings; 103 | } 104 | $device_list = \FreePBX::Core()->getAllDevicesByType();; 105 | foreach ($device_list as $device) { 106 | $devices[$device['id']] = $device; 107 | } 108 | $user_list = \FreePBX::Core()->listUsers(true); 109 | foreach ($user_list as $user) { 110 | $users[$user[0]]['description'] = $user[1]; 111 | $users[$user[0]]['vmcontext'] = $user[2]; 112 | } 113 | foreach ($devices as $id => $device) { 114 | if ($device['devicetype'] == 'fixed' && !empty($users[$device['user']])) { 115 | $devices[$id]['vmcontext'] = $users[$device['user']]['vmcontext']; 116 | $devices[$id]['description'] = $users[$device['user']]['description']; 117 | } 118 | } 119 | static::$devicesGetUserMappings = $devices; 120 | return static::$devicesGetUserMappings; 121 | } 122 | 123 | // map the actual vmcontext and user devicename if the device is fixed 124 | public static function map_dev_user($account, $keyword, $data) { 125 | $dev_user_map = static::devicesGetUserMappings(); 126 | if(is_null(static::$removeMailboxSetting)) { 127 | static::$removeMailboxSetting = \FreePBX::Config()->get('DEVICE_REMOVE_MAILBOX'); 128 | } 129 | 130 | if (!empty($dev_user_map[$account]) && $dev_user_map[$account]['devicetype'] == 'fixed') { 131 | switch (strtolower($keyword)) { 132 | case 'callerid': 133 | $user_option = $dev_user_map[$account]['description'] . ' <' . $account . '>'; 134 | break; 135 | case 'mailboxes': 136 | case 'mailbox': 137 | if ((empty($dev_user_map[$account]['vmcontext']) || $dev_user_map[$account]['vmcontext'] == 'novm') 138 | && strtolower($data) == "$account" . "@device" 139 | && static::$removeMailboxSetting 140 | ) { 141 | // they have no vm so don't put a mailbox=line 142 | $user_option = ""; 143 | } elseif (strtolower($data) == "$account" . "@device" 144 | && !empty($dev_user_map[$account]['vmcontext']) 145 | && $dev_user_map[$account]['vmcontext'] != 'novm' 146 | ) { 147 | $user_option = $dev_user_map[$account]['user'] . "@" . $dev_user_map[$account]['vmcontext']; 148 | } else { 149 | $user_option = $data; 150 | } 151 | } 152 | $output = $keyword . "=" . $user_option . "\n"; 153 | } else { 154 | $output = $keyword . "=" . $data . "\n"; 155 | } 156 | return $output; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /functions.inc/calltransfer-eventlistener.php: -------------------------------------------------------------------------------- 1 | Events("on"); 5 | 6 | $astman->add_event_handler("AttendedTransfer", function($event, $data, $server, $port) { 7 | core_AttendedTransfer($data); 8 | }); 9 | 10 | $astman->add_event_handler("UnParkedCall", function($event, $data, $server, $port) { 11 | core_UnParkedCall($data,$event); 12 | }); 13 | $last_db_ping = time(); 14 | while (true) { 15 | if (time() > ($last_db_ping + (60 * 60))) { 16 | $last_db_ping = time(); 17 | } 18 | 19 | $response = $astman->wait_response(true); 20 | $reconnects = $astman->reconnects; 21 | 22 | while ($response === false && $reconnects > 0) { 23 | $astman->disconnect(); 24 | if ($astman->connect($astman->server . ':' . $astman->port, $astman->username, $astman->secret, $astman->events) !== false) { 25 | $response = true; 26 | } else { 27 | if ($reconnects > 1) { 28 | $astman->log("reconnect command failed, sleeping before next attempt"); 29 | sleep(1); 30 | } else { 31 | $astman->log("FATAL: no reconnect attempts left, command permanently failed"); 32 | exit(2); 33 | } 34 | } 35 | $reconnects--; 36 | } 37 | } 38 | 39 | function core_UnParkedCall($data,$type){ 40 | global $astman,$monitordir,$format; 41 | $ParkeeChannel = $data['ParkeeChannel']; 42 | //get the call recording file name from the channel 43 | $response = $astman->send_request('Command',array('Command'=>"core show channel ".$ParkeeChannel)); 44 | $responseArray = explode("\n",trim($response['data'])); 45 | $callfilename = preg_grep("/CALLFILENAME/",$responseArray); 46 | $monitor = preg_grep("/MIXMONITOR_FILENAME/",$responseArray); 47 | if(is_array($monitor)&& count($monitor) > 0) { 48 | $monitor = array_values($monitor); 49 | $file = explode('MIXMONITOR_FILENAME=',$monitor[0]); 50 | $filename = $file[1]; 51 | } 52 | if($filename != ""){ 53 | $re = $astman->mixmonitor($ParkeeChannel, "$filename", "ai(LOCAL_MIXMON_ID)"); 54 | dbug(" Starting Park call recording from Channel $ParkeeChannel with existing file $filename"); 55 | return ; 56 | } 57 | // no mix monitor file 58 | if(is_array($callfilename)&& count($callfilename) > 0) { 59 | $callfilename = array_values($callfilename); 60 | $file = explode('CALLFILENAME=',$callfilename[0]); 61 | $filename = $monitordir.'/'.date("Y/m/d/").$file[1].".".$format; 62 | $re = $astman->mixmonitor($ParkeeChannel, "$filename", "ai(LOCAL_MIXMON_ID)"); 63 | dbug(" Starting UnPark call recording from Channel $ParkeeChannel with existing file $filename"); 64 | } 65 | return; 66 | } 67 | function core_AttendedTransfer($data) { 68 | global $astman; 69 | $OrigTransfererChannel = $data['OrigTransfererChannel']; 70 | $TransfereeChannel = $data['TransfereeChannel']; 71 | //get the call recording file name from the channel 72 | $response = $astman->send_request('Command',array('Command'=>"core show channel ".$OrigTransfererChannel)); 73 | $responseArray = explode("\n",trim($response['data'])); 74 | $monitor = preg_grep("/MIXMONITOR_FILENAME/",$responseArray); 75 | if(is_array($monitor)&& count($monitor) > 0) { 76 | $monitor = array_values($monitor); 77 | $file = explode('MIXMONITOR_FILENAME=',$monitor[0]); 78 | $filename = $file[1]; 79 | } 80 | if($filename != ""){ 81 | $re = $astman->mixmonitor($TransfereeChannel, "$filename", "ai(LOCAL_MIXMON_ID)"); 82 | dbug(" Starting AttendedTransfer recording from Channel $TransfereeChannel with existing file $filename"); 83 | } 84 | return; 85 | } 86 | ?> 87 | -------------------------------------------------------------------------------- /functions.inc/drivers/Custom.class.php: -------------------------------------------------------------------------------- 1 | "custom", 8 | "hardware" => "custom_custom", 9 | "prettyName" => _("Generic Custom Driver"), 10 | "shortName" => _("Custom"), 11 | "description" => _("Custom Device") 12 | ); 13 | } 14 | 15 | public function addDevice($id, $settings) { 16 | return true; 17 | } 18 | 19 | public function delDevice($id) { 20 | return true; 21 | } 22 | 23 | public function getDevice($id) { 24 | return array(); 25 | } 26 | 27 | public function getDefaultDeviceSettings($id, $displayname, &$flag) { 28 | return array( 29 | "dial" => "", 30 | "settings" => array() 31 | ); 32 | } 33 | 34 | public function getDeviceDisplay($display, $deviceInfo, $currentcomponent, $primarySection) { 35 | $tmparr = array(); 36 | $tt = _("How to dial this device. This will be device specific. For example, a custom device which is really a remote SIP URI might be configured such as SIP/joe@somedomain.com"); 37 | $tmparr['dial'] = array('prompttext' => _("Dial"), 'value' => '', 'tt' => $tt, 'level' => 0); 38 | $devopts = $tmparr; 39 | return $devopts; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /functions.inc/drivers/Virtual.class.php: -------------------------------------------------------------------------------- 1 | "virtual", 8 | "hardware" => "virtual", 9 | "prettyName" => _("None (virtual exten)"), 10 | "shortName" => _("Virtual") 11 | ); 12 | } 13 | public function getDefaultDeviceSettings($id, $displayname, &$flag) { 14 | return array( 15 | "dial" => "", 16 | "settings" => array() 17 | ); 18 | } 19 | public function addDevice($id, $settings) { 20 | return true; 21 | } 22 | public function delDevice($id) { 23 | return true; 24 | } 25 | public function getDevice($id) { 26 | return array(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /hooks/logrotate: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat <<- EOF > /etc/logrotate.d/freepbx-core 4 | /var/log/asterisk/freepbx_dbug { 5 | size 500M 6 | missingok 7 | rotate 7 8 | dateext 9 | notifempty 10 | sharedscripts 11 | create 0664 asterisk asterisk 12 | su asterisk asterisk 13 | } 14 | 15 | /var/log/asterisk/freepbx_debug 16 | /var/log/asterisk/freepbx.log 17 | /var/log/asterisk/freepbx_security.log{ 18 | size 100M 19 | missingok 20 | rotate 7 21 | dateext 22 | notifempty 23 | sharedscripts 24 | create 0664 asterisk asterisk 25 | su asterisk asterisk 26 | } 27 | /var/log/asterisk/core-fastagi_*.log { 28 | size 50M 29 | missingok 30 | rotate 5 31 | notifempty 32 | dateext 33 | sharedscripts 34 | create 0664 asterisk asterisk 35 | su asterisk asterisk 36 | postrotate 37 | /usr/sbin/fwconsole pm2 --reload-logs -q 38 | endscript 39 | } 40 | EOF 41 | -------------------------------------------------------------------------------- /images/arrow_up_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/arrow_up_down.png -------------------------------------------------------------------------------- /images/cog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/cog.png -------------------------------------------------------------------------------- /images/core_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/core_add.png -------------------------------------------------------------------------------- /images/core_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/core_delete.png -------------------------------------------------------------------------------- /images/default-option.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/default-option.png -------------------------------------------------------------------------------- /images/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/edit.png -------------------------------------------------------------------------------- /images/email_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/email_edit.png -------------------------------------------------------------------------------- /images/link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/link.png -------------------------------------------------------------------------------- /images/resultset_bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/resultset_bottom.png -------------------------------------------------------------------------------- /images/resultset_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/resultset_down.png -------------------------------------------------------------------------------- /images/resultset_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/resultset_top.png -------------------------------------------------------------------------------- /images/resultset_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/resultset_up.png -------------------------------------------------------------------------------- /images/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/spinner.gif -------------------------------------------------------------------------------- /images/telephone_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/telephone_delete.png -------------------------------------------------------------------------------- /images/telephone_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/telephone_edit.png -------------------------------------------------------------------------------- /images/telephone_key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/telephone_key.png -------------------------------------------------------------------------------- /images/user_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/user_add.png -------------------------------------------------------------------------------- /images/user_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/user_delete.png -------------------------------------------------------------------------------- /images/user_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/user_edit.png -------------------------------------------------------------------------------- /images/user_go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/images/user_go.png -------------------------------------------------------------------------------- /node/fastagi-server.js: -------------------------------------------------------------------------------- 1 | const net = require('net'); 2 | const carrier = require('./lib/carrier.js'); 3 | const AGI = require('./lib/AGI.js'); 4 | 5 | process.env.ASTAGIDIR = process.env.ASTAGIDIR ? process.env.ASTAGIDIR : '/var/lib/asterisk/agi-bin'; 6 | 7 | process.chdir(process.env.ASTAGIDIR); 8 | 9 | const server = net.createServer((sock) => { 10 | let init = false; 11 | let settings = {}; 12 | let agi = null; 13 | let port = sock.remotePort; 14 | console.log(`[${port}] Asterisk connection opened`); 15 | 16 | carrier.carry(sock, function(line) { 17 | if(!line.length) { //line is blank (technically two newlines) 18 | init = true; 19 | settings.agi_ASTAGIDIR = process.env.ASTAGIDIR; 20 | settings.agi_port = port; 21 | agi = new AGI(settings); 22 | agi.on('exit',(code, signal) => { 23 | sock.end(); 24 | }) 25 | agi.on('data',(data) => { 26 | sock.write(data.toString('utf8')); 27 | }) 28 | return; 29 | } 30 | if(!init) { 31 | let idx = line.indexOf(":"); 32 | settings[line.substring(0,idx).trim()] = line.substring(idx+1).trim(); 33 | } else { 34 | agi.scriptStdin(line) 35 | } 36 | }); 37 | sock.on('close', () => { 38 | agi = null 39 | delete(agi) 40 | console.log(`[${port}] Asterisk connection closed`); 41 | }); 42 | sock.on('error', (err) => { 43 | console.log(`[${port}] Asterisk connection error: ${err.message}`); 44 | }); 45 | }); 46 | 47 | server.listen(4573, "127.0.0.1"); 48 | console.log(`FastAGI Server is ready to process calls`); 49 | -------------------------------------------------------------------------------- /node/lib/AGI.js: -------------------------------------------------------------------------------- 1 | const {spawn} = require('child_process'); 2 | const EventEmitter = require('events'); 3 | const path = require('path'); 4 | 5 | class AGI extends EventEmitter { 6 | constructor(settings) { 7 | super(); 8 | this.args = []; 9 | this.settings = settings; 10 | this.agiScript = null; 11 | this.exited = false; 12 | 13 | let i = 1; 14 | while(typeof settings['agi_arg_'+i] !== "undefined") { 15 | this.args.push(settings['agi_arg_'+i]); 16 | i++; 17 | } 18 | 19 | this.launch(); 20 | } 21 | 22 | kill() { 23 | this.agiScript.kill(); 24 | } 25 | 26 | /** 27 | * Launch AGI Script 28 | */ 29 | launch() { 30 | let scriptPath = `./${this.settings.agi_network_script}`; 31 | if(path.isAbsolute(this.settings.agi_network_script)) { 32 | scriptPath = this.settings.agi_network_script; 33 | } 34 | console.log(`[${this.settings.agi_port}] Launching ${scriptPath} with args: ${this.args.join(',')}`); 35 | 36 | this.agiScript = spawn(scriptPath, this.args, {cwd: this.settings.agi_ASTAGIDIR}); 37 | this.agiScript.stdout.on('data', this.scriptStdout.bind(this)); 38 | this.agiScript.on('exit', this.scriptExit.bind(this)); 39 | 40 | this.agiScript.stdout.on('error', (error) => { 41 | console.log(`[${this.settings.agi_port}][${this.settings.agi_uniqueid}] <<< ${JSON.stringify(error)}`); 42 | }); 43 | this.agiScript.stdin.on('error', (error) => { 44 | console.log(`[${this.settings.agi_port}][${this.settings.agi_uniqueid}] >>> ${JSON.stringify(error)}`); 45 | }); 46 | 47 | //push settings to script 48 | for (var key in this.settings) { 49 | console.log(`[${this.settings.agi_port}][${this.settings.agi_uniqueid}] >>> ${key}: ${this.settings[key]}`); 50 | this.agiScript.stdin.write(key+": "+this.settings[key]+"\n"); 51 | } 52 | console.log(`[${this.settings.agi_port}][${this.settings.agi_uniqueid}] >>> `); 53 | //done pushing settings return two newlines to tell script settings are over 54 | this.agiScript.stdin.write("\n\n"); 55 | } 56 | 57 | /** 58 | * Called when the AGI Script terminates 59 | * @param {integer} code 60 | * @param {string} signal 61 | */ 62 | scriptExit(code, signal) { 63 | console.log(`[${this.settings.agi_port}] Script ended with code ${code} and signal ${signal}`); 64 | this.exited = true; 65 | this.emit('exit', code, signal); 66 | } 67 | 68 | /** 69 | * Called when the script sends data from STDOUT 70 | * @param {string} data String of data from STDOUT from Script 71 | */ 72 | scriptStdout(data) { 73 | console.log(`[${this.settings.agi_port}][${this.settings.agi_uniqueid}] <<< ${data.toString('utf8').trim()}`); 74 | this.emit('data', data); 75 | } 76 | 77 | /** 78 | * Called when data needs to be sent to the script over STDIN 79 | * @param {string} data String of data to send to STDIN to script 80 | */ 81 | scriptStdin(data) { 82 | if(!this.exited && data.trim() === 'HANGUP') { 83 | console.log(`[${this.settings.agi_port}][${this.settings.agi_uniqueid}] >>> SENT HANGUP TO RUNNING AGI, KILLING AGI `); 84 | //channel is now dead so hangup 85 | this.kill(); 86 | } else if(!this.exited) { 87 | console.log(`[${this.settings.agi_port}][${this.settings.agi_uniqueid}] >>> ${data.trim()}`); 88 | this.agiScript.stdin.write(data+"\n"); 89 | } else if(this.exited) { 90 | console.log(`[${this.settings.agi_port}][${this.settings.agi_uniqueid}] >>TRIED TO SEND TO DEAD AGI>> ${data.trim()} `); 91 | } else { 92 | console.error(`[${this.settings.agi_port}][${this.settings.agi_uniqueid}] Strange state?????????`); 93 | } 94 | } 95 | } 96 | 97 | module.exports = AGI -------------------------------------------------------------------------------- /node/lib/carrier.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://github.com/pgte/carrier/blob/master/LICENSE 3 | */ 4 | var util = require('util'), 5 | events = require('events'), 6 | dgram = require('dgram'); 7 | 8 | function Carrier(reader, listener, encoding, separator) { 9 | var self = this; 10 | var eventName = (reader.constructor === dgram.Socket) ? 'message' : 'data'; 11 | var buffer = ''; 12 | 13 | self.reader = reader; 14 | encoding = encoding || 'utf-8'; 15 | separator = separator || /\r?\n/; 16 | 17 | if (listener) { 18 | self.addListener('line', listener); 19 | } 20 | 21 | if (typeof reader.setEncoding === 'function') { 22 | reader.setEncoding(encoding); 23 | } 24 | 25 | var defferredLineEmit = function(line) { 26 | process.nextTick(function() { 27 | self.emit('line', line); 28 | }); 29 | }; 30 | 31 | var onData = function carrierOnData(data) { 32 | if (data instanceof Buffer) { 33 | data = data.toString(encoding); 34 | } 35 | 36 | data = buffer + data; 37 | 38 | var lines = data.split(separator); 39 | var length = lines.length - 1; 40 | 41 | buffer = lines[length] || ''; 42 | 43 | for (var i = 0; i < length; i++) { 44 | defferredLineEmit(lines[i]); 45 | } 46 | }; 47 | 48 | var onEnd = function onEnd() { 49 | if (buffer) { 50 | defferredLineEmit(buffer); 51 | buffer = ''; 52 | } 53 | 54 | process.nextTick(function() { 55 | self.emit('end'); 56 | }); 57 | }; 58 | 59 | reader.on(eventName, onData); 60 | reader.on('end', onEnd); 61 | } 62 | 63 | util.inherits(Carrier, events.EventEmitter); 64 | 65 | exports.carry = function(reader, listener, encoding, separator) { 66 | return new Carrier(reader, listener, encoding, separator); 67 | } -------------------------------------------------------------------------------- /page.astmodules.php: -------------------------------------------------------------------------------- 1 | ModulesConf(); 3 | $pc = $mods->ProcessedConfig['modules']; 4 | $loadrows = 5 | $noloadrows = ''; 6 | $preloadrows = ''; 7 | if (isset($pc['noload'])) { 8 | $noloads = is_array($pc['noload']) ? $pc['noload'] : array($pc['noload']); 9 | foreach($noloads as $mod){ 10 | $noloadrows .= << 12 | $mod 13 | 14 | 15 | 16 | 17 | HERE; 18 | } 19 | } 20 | if (isset($pc['load'])) { 21 | $loads = is_array($pc['load']) ? $pc['load'] : array($pc['load']); 22 | foreach($loads as $mod){ 23 | $loadrows .= << 25 | $mod 26 | 27 | 28 | 29 | 30 | HERE; 31 | } 32 | } 33 | if (isset($pc['preload'])) { 34 | $preloads = is_array($pc['preload']) ? $pc['preload'] : array($pc['preload']); 35 | foreach($preloads as $mod){ 36 | $preloadrows .= << 38 | $mod 39 | 40 | 41 | 42 | 43 | HERE; 44 | } 45 | } 46 | ?> 47 | 48 |
49 |

50 |
51 | 52 |
53 | 54 |
55 | 56 |
57 | 58 |
59 |
60 |
61 |
62 |
63 |
64 | 81 |
82 |
83 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
98 |
99 |
100 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 |
115 |
116 |
117 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 |
132 |
133 |
134 |
135 |
136 |
137 | 142 |
143 |
144 |
145 | 146 | -------------------------------------------------------------------------------- /page.dahdichandids.php: -------------------------------------------------------------------------------- 1 | $description, 'channel' => $channel, 'did' => $did, 'action' => $action)); 21 | break; 22 | default: 23 | echo load_view(__DIR__."/views/dahdichandids/general.php"); 24 | break; 25 | } 26 | -------------------------------------------------------------------------------- /page.devices.php: -------------------------------------------------------------------------------- 1 | 4 |
5 |
6 |
7 | 15 | 21 | 30 |
31 | 32 |
33 |
34 | 54 |
55 |
56 |
57 | 60 |
61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
74 |
75 | getAllDriversInfo() as $driver) {?> 76 |
77 | 80 |
81 |
82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 |
94 |
95 | 96 |
97 |
98 | generateconfigpage(__DIR__."/views/devices.php"); 101 | } ?> 102 |
103 |
104 |
105 | 110 | -------------------------------------------------------------------------------- /page.did.php: -------------------------------------------------------------------------------- 1 | $extdisplay, 11 | 'old_extdisplay' => isset($old_extdisplay) ? $old_extdisplay : '', 12 | 'dispnum' => isset($dispnum) ? $dispnum : '', 13 | 'account' => isset($account) ? $account : '', 14 | 'goto' => isset($goto) ? $goto : '', 15 | 'ringing' => isset($ringing) ? $ringing : '', 16 | 'reversal' => isset($reversal) ? $reversal : '', 17 | 'description' => isset($description) ? $description : '', 18 | 'privacyman' => isset($privacyman) ? $privacyman : '', 19 | 'pmmaxretries' => isset($pmmaxretries) ? $pmmaxretries : '', 20 | 'pmminlength' => isset($pmminlength) ? $pmminlength : '', 21 | 'alertinfo' => isset($alertinfo) ? $alertinfo : '', 22 | 'mohclass' => isset($mohclass) ? $mohclass : '', 23 | 'grppre' => isset($grppre) ? $grppre : '', 24 | 'delay_answer' => isset($delay_answer) ? $delay_answer : '', 25 | 'pricid' => isset($pricid) ? $pricid : '', 26 | 'rnavsort' => isset($rnavsort) ? $rnavsort : '', 27 | 'didfilter' => isset($didfilter) ? $didfilter : '', 28 | 'rvolume' => isset($rvolume) ? $rvolume : '', 29 | 'indication_zone' => isset($indication_zone) ? $indication_zone : '', 30 | 'heading' => '

'._("Add Incoming Route").'

', 31 | ); 32 | 33 | if($extdisplay){ 34 | $extarray=explode('/',$extdisplay,2); 35 | $ininfo=core_did_get($extarray[0],$extarray[1]); 36 | if (is_array($ininfo) && !empty($ininfo)) { 37 | extract($ininfo); 38 | } 39 | $description = freepbx_htmlspecialchars($description ?? ''); 40 | $extension = freepbx_htmlspecialchars($extension ?? ''); 41 | $cidnum = freepbx_htmlspecialchars($cidnum ?? ''); 42 | $grppre = freepbx_htmlspecialchars($grppre ?? ''); 43 | $heading = '

'._("Route").': '; 44 | if($description){ 45 | $heading .= $description . '

'; 46 | }else{ 47 | $heading .= $extdisplay . ''; 48 | } 49 | 50 | 51 | $formdata['heading'] = $heading; 52 | $formdata['description'] = $description; 53 | $formdata['extension'] = $extension; 54 | $formdata['cidnum'] = $cidnum; 55 | $formdata['alertinfo'] = $alertinfo ?? ""; 56 | $formdata['grppre'] = $grppre; 57 | $formdata['destination'] = $destination ?? ""; 58 | $formdata['pricid'] = $pricid ?? ""; 59 | $formdata['alertinfo'] = $alertinfo ?? ""; 60 | $formdata['ringing'] = $ringing ?? ""; 61 | $formdata['fanswer'] = $fanswer ?? ""; 62 | $formdata['reversal'] = $reversal ?? ""; 63 | $formdata['delay_answer'] = $delay_answer ?? ""; 64 | $formdata['privacyman'] = $privacyman ?? ""; 65 | $formdata['pmmaxretries'] = $pmmaxretries ?? ""; 66 | $formdata['pmminlength'] = $pmminlength ?? ""; 67 | $formdata['pmminlength'] = $pmminlength ?? ""; 68 | $formdata['mohclass'] = $mohclass ?? ""; 69 | $formdata['rvolume'] = $rvolume ?? ""; 70 | $formdata['indication_zone'] = $indication_zone ?? ""; 71 | 72 | }else{ 73 | $extension = isset($extarray[0]) ? $extarray[0] : ''; 74 | $cidnum = isset($extarray[1]) ? $extarray[1] : ''; 75 | $extdisplay = ''; 76 | $heading = '

'._("Add Incoming Route").'

'; 77 | 78 | $formdata['heading'] = $heading; 79 | $formdata['extension'] = $extension; 80 | $formdata['cidnum'] = $cidnum; 81 | $formdata['extdisplay'] = $extdisplay; 82 | } 83 | 84 | // If this is a direct did, e.g. from-did-direct,nnn,1 then make a link to the extension 85 | // 86 | $did_dest = !empty($destination) ? explode(',',$destination) : array(); 87 | if (isset($did_dest[0]) && $did_dest[0] == 'from-did-direct') { 88 | if (isset($amp_conf["AMPEXTENSIONS"]) && ($amp_conf["AMPEXTENSIONS"] == "deviceanduser")) { 89 | $editURL = '?display=users&extdisplay='.$did_dest[1]; 90 | $EXTorUSER = _("User"); 91 | }else{ 92 | $editURL = '?display=extensions&extdisplay='.$did_dest[1]; 93 | $EXTorUSER = _("Extension"); 94 | } 95 | $result = core_users_get($did_dest[1]); 96 | $name = $result['name'] ?? ''; 97 | $label = ' '.sprintf(_("Edit %s %s (%s)"),$EXTorUSER, $did_dest[1],$name).''; 98 | $link= "

".$label."

"; 99 | $formdata['userlink'] = $link; 100 | } 101 | $view = !empty($request['view']) ? $request['view'] : ''; 102 | $display_mode = "advanced"; 103 | $mode = \FreePBX::Config()->get("FPBXOPMODE"); 104 | if(!empty($mode)) { 105 | $display_mode = $mode; 106 | } 107 | 108 | switch($view){ 109 | case "form": 110 | if($display_mode == "basic") { 111 | $content = load_view(__DIR__.'/views/did/basic_form.php', $formdata); 112 | } else { 113 | $content = load_view(__DIR__.'/views/did/advanced_form.php', $formdata); 114 | } 115 | break; 116 | default: 117 | $content = load_view(__DIR__.'/views/did/didgrid.php'); 118 | break; 119 | } 120 | 121 | ?> 122 |
123 |

124 |
125 |
126 |
127 |
128 |
129 | 130 |
131 |
132 |
133 |
134 |
135 |
136 | -------------------------------------------------------------------------------- /page.routing.php: -------------------------------------------------------------------------------- 1 | '; 25 | $pageinfo .= _('This page is used to manage your outbound routing.'); 26 | $pageinfo .= ''; 27 | switch($request['view']){ 28 | case "form": 29 | if(isset($request['id'])){ 30 | $extdisplay = $request['id']; 31 | $id = $request['id']; 32 | $route_info = core_routing_get($extdisplay); 33 | $dialpattern_array = core_routing_getroutepatternsbyid($extdisplay); 34 | $trunkpriority = core_routing_getroutetrunksbyid($extdisplay); 35 | $emailInfo = core_routing_getrouteemailbyid($extdisplay); 36 | $routepass = $route_info['password']; 37 | $emergency = $route_info['emergency_route']; 38 | $intracompany = $route_info['intracompany_route']; 39 | $mohsilence = $route_info['mohclass']; 40 | $outcid = $route_info['outcid']; 41 | $outcid_mode = $route_info['outcid_mode']; 42 | $time_group_id = $route_info['time_group_id']; 43 | $time_mode = $route_info['time_mode']; 44 | $timezone = $route_info['timezone']; 45 | $calendar_id = $route_info['calendar_id']; 46 | $calendar_group_id = $route_info['calendar_group_id']; 47 | $route_seq = $route_info['seq']; 48 | $routename = $route_info['name']; 49 | $dest = $route_info['dest']; 50 | $notification_on = $route_info['notification_on']; 51 | $routelist = core_routing_list(); 52 | $subhead = sprintf('%s: %s',$subhead,$routename); 53 | $viewinfo = array( 54 | 'formAction' => 'editroute', 55 | 'extdisplay' => $extdisplay, 56 | 'id' => $id, 57 | 'route_info' => $route_info, 58 | 'dialpattern_array' => $dialpattern_array, 59 | 'trunkpriority' => $trunkpriority, 60 | 'routepass' => $routepass, 61 | 'emergency' => $emergency, 62 | 'intracompany' => $intracompany, 63 | 'mohsilence' => $mohsilence, 64 | 'outcid' => $outcid, 65 | 'outcid_mode' => $outcid_mode, 66 | 'time_group_id' => $time_group_id, 67 | 'time_mode' => $time_mode, 68 | 'timezone' => $timezone, 69 | 'calendar_id' => $calendar_id, 70 | 'calendar_group_id' => $calendar_group_id, 71 | 'route_seq' => $route_seq, 72 | 'routename' => $routename, 73 | 'dest' => $dest, 74 | 'notification_on' => $notification_on, 75 | 'emailInfo' => $emailInfo, 76 | 'hooks' => \FreePBX::Core()->hookTabs($request['display']), 77 | 'hooksAdditionalContent' => \FreePBX::Core()->hookAdditionalContent($request['display']) 78 | ); 79 | $subhead .= ": ". $routename; 80 | }else{ 81 | $sql = "SELECT MAX(`seq`) as max FROM outbound_route_sequence"; 82 | $res = \FreePBX::Database()->query($sql)->fetch(\PDO::FETCH_COLUMN); 83 | $route_seq = is_numeric($res) ? $res + 1 : 0; 84 | if (!isset($dialpattern_array)) { 85 | $dialpattern_array = array(); 86 | } 87 | $viewinfo = array( 88 | 'formAction' => 'addroute', 89 | 'route_seq' => $route_seq, 90 | 'dialpattern_array' => $dialpattern_array, 91 | 'trunkpriority' => $trunkpriority ?? '', 92 | 'hooks' => \FreePBX::Core()->hookTabs($request['display']), 93 | ); 94 | } 95 | $content = load_view(__DIR__.'/views/routing/form.php', $viewinfo); 96 | $pageinfo = ''; 97 | break; 98 | default: 99 | //$pageinfo = ''; 100 | $routelist = core_routing_list(); 101 | $content = load_view(__DIR__.'/views/routing/grid.php', array('routelist' => $routelist)); 102 | break; 103 | } 104 | ?> 105 | 106 |
107 |

108 |

109 | 110 |
111 |
112 |
113 |
114 |
115 | 116 |
117 |
118 |
119 |
120 |
121 |
122 | -------------------------------------------------------------------------------- /page.users.php: -------------------------------------------------------------------------------- 1 | 4 |
5 |
6 |
7 |
8 | 9 |
10 | 18 | 24 | generateconfigpage(__DIR__."/views/users.php"); 34 | if($view == "add" || (!is_null($extdisplay) && trim($extdisplay) != '')) { 35 | echo $page; 36 | } else { ?> 37 |
38 | 45 |
46 |
47 |
48 | 51 |   52 |
53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 |
69 |
70 |
71 |
72 | 73 |
74 |
75 |
76 | 96 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 25 | 26 | 27 | . 28 | 29 | vendor 30 | utests 31 | 32 | 33 | 34 | 35 | 36 | utests 37 | 38 | 39 | -------------------------------------------------------------------------------- /sip_to_pjsip/.gitignore: -------------------------------------------------------------------------------- 1 | *.conf 2 | -------------------------------------------------------------------------------- /sounds/en/agent-login.sln: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/sounds/en/agent-login.sln -------------------------------------------------------------------------------- /sounds/en/agent-logoff.sln: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/sounds/en/agent-logoff.sln -------------------------------------------------------------------------------- /sounds/en/exited-vm-will-be-transfered.sln: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/sounds/en/exited-vm-will-be-transfered.sln -------------------------------------------------------------------------------- /sounds/en/featurecode.sln: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/sounds/en/featurecode.sln -------------------------------------------------------------------------------- /sounds/en/incoming-call-1-accept-2-decline.sln: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/sounds/en/incoming-call-1-accept-2-decline.sln -------------------------------------------------------------------------------- /sounds/en/incoming-call-no-longer-avail.sln: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/sounds/en/incoming-call-no-longer-avail.sln -------------------------------------------------------------------------------- /sounds/en/line-busy-transfer-menu.sln: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/sounds/en/line-busy-transfer-menu.sln -------------------------------------------------------------------------------- /sounds/en/please-enter-your-extension-then-press-pound.sln: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/sounds/en/please-enter-your-extension-then-press-pound.sln -------------------------------------------------------------------------------- /sounds/en/you-will-be-transfered-menu.sln: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreePBX/core/7e95004022fa9ab5a910f59febfc9eb8cde874f0/sounds/en/you-will-be-transfered-menu.sln -------------------------------------------------------------------------------- /utests/API/DidsGQLTest.php: -------------------------------------------------------------------------------- 1 | core; 20 | } 21 | /** 22 | * tearDownAfterClass 23 | * 24 | * @return void 25 | */ 26 | public static function tearDownAfterClass() { 27 | parent::tearDownAfterClass(); 28 | } 29 | 30 | public function test_allInboundRoutes_return_true() { 31 | $response = $this->request("query { 32 | allInboundRoutes{ 33 | inboundRoutes { 34 | destinationConnection 35 | } 36 | } 37 | }"); 38 | $json = (string)$response->getBody(); 39 | $this->assertEquals('{"data":{"allInboundRoutes":{"inboundRoutes":[{"destinationConnection":"Extensions: 9919988 FreePBXUCPTemplateCreator"},{"destinationConnection":"Queues:111 kg-test"}]}}}', $json); 40 | //status 200 success check 41 | $this->assertEquals(200, $response->getStatusCode()); 42 | } 43 | 44 | public function test_allInboundRoutes_return_false() { 45 | $mockHelper = $this->getMockBuilder(\Freepbx\modules\Core::class) 46 | ->disableOriginalConstructor()->setMethods(array('getAllDIDs'))->getMock(); 47 | 48 | $mockHelper->method('getAllDIDs')->willReturn([]); 49 | 50 | self::$freepbx->Core = $mockHelper; 51 | $response = $this->request("query { 52 | allInboundRoutes { 53 | inboundRoutes { 54 | destinationConnection 55 | } 56 | } 57 | }"); 58 | $json = (string)$response->getBody(); 59 | $this->assertEquals('{"data":{"allInboundRoutes":{"inboundRoutes":[]}}}', $json); 60 | $this->assertEquals(200, $response->getStatusCode()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /utests/CoreClassTest.php: -------------------------------------------------------------------------------- 1 | Core; 18 | } 19 | 20 | public function testCore_changeDeviceTech_whenChangingSipDeviceToPjsip_shouldBeSuccessful() { 21 | $testExtension = '969800'; 22 | 23 | // Cleaning up any previous tests 24 | self::$app->delDevice($testExtension); 25 | $settings = self::$app->generateDefaultDeviceSettings( 26 | 'sip', 27 | $testExtension, 28 | 'sip change test' 29 | ); 30 | self::$app->addDevice($testExtension, "sip", $settings); 31 | 32 | self::$app->changeDeviceTech($testExtension, 'pjsip'); 33 | 34 | $device = self::$app->getDevice($testExtension); 35 | 36 | $this->assertEquals("969800", $device['id']); 37 | $this->assertEquals("pjsip", $device['tech']); 38 | $this->assertEquals("PJSIP/969800", $device['dial']); 39 | $this->assertEquals("fixed", $device['devicetype']); 40 | $this->assertEquals("sip change test", $device['description']); 41 | $this->assertEquals("969800", $device['account']); 42 | $this->assertEquals("sip change test <969800>", $device['callerid']); 43 | $this->assertEquals("969800@device", $device['mailbox']); 44 | $this->assertEquals("chan_pjsip", $device['sipdriver']); 45 | $this->assertNull(null, $device['emergency_cid']); 46 | } 47 | 48 | public function testCore_changeDeviceTech_whenChangingPjsipDeviceToSip_shouldBeSuccessful() { 49 | $testExtension = '969800'; 50 | 51 | // Cleaning up any previous tests 52 | self::$app->delDevice($testExtension); 53 | $settings = self::$app->generateDefaultDeviceSettings( 54 | 'pjsip', 55 | $testExtension, 56 | 'pjsip change test' 57 | ); 58 | self::$app->addDevice($testExtension, "pjsip", $settings); 59 | 60 | self::$app->changeDeviceTech($testExtension, 'sip'); 61 | 62 | $device = self::$app->getDevice($testExtension); 63 | 64 | $this->assertEquals("969800", $device['id']); 65 | $this->assertEquals("sip", $device['tech']); 66 | $this->assertEquals("SIP/969800", $device['dial']); 67 | $this->assertEquals("fixed", $device['devicetype']); 68 | $this->assertEquals("pjsip change test", $device['description']); 69 | $this->assertEquals("969800", $device['account']); 70 | $this->assertEquals("pjsip change test <969800>", $device['callerid']); 71 | $this->assertEquals("969800@device", $device['mailbox']); 72 | $this->assertEquals("chan_sip", $device['sipdriver']); 73 | $this->assertNull(null, $device['emergency_cid']); 74 | } 75 | 76 | public function testCore_changeDeviceTech_whenDeviceDoesntExist_shouldThrowError() { 77 | $testExtension = '969800'; 78 | 79 | // Cleaning up any previous tests 80 | self::$app->delDevice($testExtension); 81 | 82 | try { 83 | self::$app->changeDeviceTech($testExtension, 'pjsip'); 84 | $this->fail('Expected exception not thrown'); 85 | } catch(Exception $e) { 86 | $this->assertEquals( 87 | 'Unable to change device driver. Unable to fetch the device', 88 | $e->getMessage() 89 | ); 90 | } 91 | } 92 | 93 | public function testCore_changeDeviceTech_whenChangingDeviceToPjsip_andDeviceAlreadyPjsip_shouldThrowError() { 94 | $testExtension = '969800'; 95 | 96 | // Cleaning up any previous tests 97 | self::$app->delDevice($testExtension); 98 | $settings = self::$app->generateDefaultDeviceSettings( 99 | 'pjsip', 100 | $testExtension, 101 | 'sip change test' 102 | ); 103 | self::$app->addDevice($testExtension, "pjsip", $settings); 104 | 105 | try { 106 | self::$app->changeDeviceTech($testExtension, 'pjsip'); 107 | $this->fail('Expected exception not thrown'); 108 | } catch(Exception $e) { 109 | $this->assertEquals( 110 | 'Unable to change device driver. The device is already set to the specified driver', 111 | $e->getMessage() 112 | ); 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /utests/dahdiChannelsTest.php: -------------------------------------------------------------------------------- 1 | "Foobar one", 19 | 'did' => '1234567', 20 | 'channel' => 1, 21 | ]; 22 | 23 | public static function setUpBeforeClass(){ 24 | include __DIR__.'/../Components/Dahdichannels.php'; 25 | } 26 | 27 | public function testDahdichannels_add_whenAllIsWell_shouldAddChannelSuccessfully(){ 28 | $dc = new Dahdichannels(); 29 | 30 | // delete channels in case it's lingering from an old test 31 | $dc->delete(1); 32 | 33 | $ret = $dc->add('Foobar one', 1, '1234567'); 34 | $this->assertTrue($ret); 35 | } 36 | 37 | public function testDahichannels_add_whenStringPassedForChannel_shouldReturnFalse(){ 38 | $dc = new Dahdichannels(); 39 | 40 | $ret = $dc->add('Foobar one', "FAIL", '1234567'); 41 | $this->assertFalse($ret); 42 | } 43 | 44 | 45 | public function testDahdichannels_add_whenDuplicateRecordCreated_shouldThrowException(){ 46 | $dc = new Dahdichannels(); 47 | 48 | // delete channels in case it's lingering from an old test 49 | $dc->delete(1); 50 | 51 | // create test record 52 | $ret = $dc->add('Foobar one', 1, '1234567'); 53 | 54 | try{ 55 | $ret = $dc->add('Foobar one', 1, '1234567'); 56 | $this->fail("Should have thrown an exception"); 57 | } catch (Exception $e){ 58 | $this->assertEquals(23000, $e->getCode()); 59 | } 60 | 61 | } 62 | } -------------------------------------------------------------------------------- /views/ampusers/bootnav.php: -------------------------------------------------------------------------------- 1 |
2 |   3 |
4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 23 | -------------------------------------------------------------------------------- /views/backupSettings.php: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 |
20 |
21 |
22 |
23 | 24 |
25 |
26 | 27 | 28 | > 29 | 30 | > 31 | 32 | 33 |
34 |
35 |
36 |
37 | 38 | -------------------------------------------------------------------------------- /views/dahdichandids/bootnav.php: -------------------------------------------------------------------------------- 1 |
2 |   3 |   4 |
5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 27 | -------------------------------------------------------------------------------- /views/dahdichandids/changrid.php: -------------------------------------------------------------------------------- 1 | 9 | $channel 10 | $description 11 | $did 12 | 13 |    14 | 15 | 16 | 17 | HERE; 18 | } 19 | ?> 20 |
21 |    22 |
23 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 | -------------------------------------------------------------------------------- /views/dahdichandids/didForm.php: -------------------------------------------------------------------------------- 1 | 17 | 25 | 26 |
27 | 28 | 29 |
30 |
31 |
32 |
33 |
34 |
35 | 36 | 37 |
38 |
39 | > 40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | 48 |
49 |
50 |
51 | 52 | 53 |
54 |
55 |
56 |
57 |
58 |
59 | 60 | 61 |
62 |
63 | 64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | 72 |
73 |
74 |
75 | 76 | 77 |
78 |
79 |
80 |
81 |
82 |
83 | 84 | 85 |
86 |
87 | 88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | 96 |
97 |
98 |
99 | 100 |
101 | -------------------------------------------------------------------------------- /views/dahdichandids/general.php: -------------------------------------------------------------------------------- 1 |
context = from-analog

in your chan_dahdi.conf configuration effecting the specified channel(s). Once you have assigned DIDs you can use standard Inbound Routes with the specified DIDs to route your calls."); 3 | ?> 4 |
5 |

6 | 7 |
8 |
9 |
10 |
11 |
12 | 13 |
14 |
15 |
16 |
17 |
18 |
19 | -------------------------------------------------------------------------------- /views/dahdichandids/view.php: -------------------------------------------------------------------------------- 1 |
context = from-analog

in your chan_dahdi.conf configuration effecting the specified channel(s). Once you have assigned DIDs you can use standard Inbound Routes with the specified DIDs to route your calls."); 3 | ?> 4 | 5 |
6 |

7 | 8 |
9 |
10 |
11 |
12 |
13 | $did, 'description' => $description, 'channel' => $channel, 'action' => $action))?> 14 |
15 |
16 |
17 |
18 |
19 |
20 | -------------------------------------------------------------------------------- /views/devices.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 | 9 | 20 |
21 | $sections) { ?> 22 |
23 |
24 | $elements) { ?> 25 |

26 |
27 | 28 |
29 | 30 |
31 |
32 |
33 |
34 |
35 | 36 | 37 | 38 | 39 |
40 |
41 |
42 |
43 |
44 |
45 | 46 |
47 |
48 | 49 |
50 |
51 | 52 | 53 |
54 |
55 |
56 | 57 |
58 | 59 |
60 |
61 | 62 |
63 |
64 | 65 |
66 | 67 | 68 | 69 |
70 |
71 | 100 | -------------------------------------------------------------------------------- /views/did/didgrid.php: -------------------------------------------------------------------------------- 1 |
2 |   3 |
4 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 60 | -------------------------------------------------------------------------------- /views/did/rnav.php: -------------------------------------------------------------------------------- 1 |
2 |   3 |   4 |
5 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 40 | -------------------------------------------------------------------------------- /views/extensions.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 | 9 |
10 | 23 |
24 | $sections) { ?> 25 |
26 |
27 | $elements) { ?> 28 |
">

29 |
"> 30 | 31 |
32 | 33 |
34 |
35 |
36 |
37 |
38 | 39 | 40 | 41 | 42 |
43 |
44 |
45 |
46 |
47 |
48 | 49 |
50 |
51 | 52 |
53 |
54 | 55 | 56 |
57 |
58 |
59 | 60 |
61 | 62 |
63 |
64 | 65 |
66 |
67 | 68 |
69 |
70 | 71 | 72 | 73 |
74 |
75 | 106 | -------------------------------------------------------------------------------- /views/quickCreate.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 | 7 |
8 |
9 | 33 |
34 |
35 |
36 |
37 |
38 | 39 |
40 |
    41 | getAllDriversInfo() as $driver) {?> 42 |
  • :
  • 43 | 44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | 54 | 55 |
56 |
57 |
58 |
59 |
60 |
61 | 62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | 70 | 71 |
72 |
73 |
74 |
75 |
76 |
77 | 78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | 86 | 87 |
88 |
89 |
90 |
91 |
92 |
93 | 94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | 102 | 103 |
104 |
105 |
106 |
107 |
108 |
109 |
Format: "caller name" <#######>

Leave this field blank to disable the outbound CallerID feature for this user.')?>
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | 118 | 119 |
120 |
121 |
122 |
123 |
124 |
125 | 126 |
127 |
128 |
129 | -------------------------------------------------------------------------------- /views/rnav.php: -------------------------------------------------------------------------------- 1 | username); $sections = !empty($ret['sections']) ? $ret['sections'] : array(); ?> 2 | 3 | 4 | 5 |
6 | 7 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 |
32 | getAllDriversInfo() as $driver) { ?> 33 | 34 | 35 |
36 | 37 |
38 | 39 | 40 | 41 | 42 |
43 | 44 | 45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 |
54 | 55 |
56 |
57 | 58 | 59 |
60 |
61 | 62 | 63 | 64 | 65 |
66 | 77 |
78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 |
86 | 87 |
88 |
89 | 90 | getAllDriversInfo() as $driver) { 92 | ?> 95 |
96 |
97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /views/routing/bootnav.php: -------------------------------------------------------------------------------- 1 |
2 |   3 |   4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 18 | -------------------------------------------------------------------------------- /views/routing/grid.php: -------------------------------------------------------------------------------- 1 |  '; 17 | }else{ 18 | $attributes .= ' '; 19 | } 20 | if($intracompany_route != ''){ 21 | $attributes .= ' '; 22 | }else{ 23 | $attributes .= ' '; 24 | } 25 | if($password != ''){ 26 | $attributes .= ' '; 27 | }else{ 28 | $attributes .= ' '; 29 | } 30 | if($time_group_id != 0){ 31 | $attributes .= ' '; 32 | }else{ 33 | $attributes .= ' '; 34 | } 35 | $cidicon = ''; 36 | if($route['outcid_mode'] == "override_extension"){ 37 | $cidicon = ''; 38 | } 39 | 40 | $routerows .= << 42 |   $name 43 | $outcid $cidicon 44 | $attributes 45 | 46 |    47 | 48 |    49 | 50 | HERE; 51 | 52 | } 53 | ?> 54 |
55 |   56 |
57 |
58 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
80 |
81 | -------------------------------------------------------------------------------- /views/routing/moh.php: -------------------------------------------------------------------------------- 1 | '.$ttext."\n"; 11 | } 12 | } 13 | ?> 14 | 15 | 16 |
17 |
18 |
19 |
20 |
21 |
22 | 23 | 24 |
25 |
26 | 29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | 37 |
38 |
39 |
40 | 41 | -------------------------------------------------------------------------------- /views/trunks/bootnav.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 | 13 |
14 |   15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 32 | -------------------------------------------------------------------------------- /views/trunks/custom.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 |
6 |
7 |
8 |
9 | 10 | 11 |
12 |
13 | 14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | $OUTNUM$
examples:
")?>CAPI/XXXXXXXX/$OUTNUM$
H323/$OUTNUM$@XX.XX.XX.XX
OH323/$OUTNUM$@XX.XX.XX.XX:XXXX
vpb/1-1/$OUTNUM$
22 |
23 |
24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /views/trunks/dahdi.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 |
6 |
7 |
8 |
9 | 10 | 11 |
12 |
13 | 14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
The default setting is g0 (group zero).")?>
22 |
23 |
24 |
25 | 26 | -------------------------------------------------------------------------------- /views/trunks/dundi.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 |
6 |
7 |
8 |
9 | 10 | 11 |
12 |
13 | 14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | 22 |
23 |
24 |
25 | 26 | -------------------------------------------------------------------------------- /views/trunks/header.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /views/trunks/main.php: -------------------------------------------------------------------------------- 1 |
2 |

3 |
4 | 5 |
6 |
7 |
8 |
9 |
10 |
11 | $trunks, 'trunk_types' => $trunk_types))?> 12 |
13 |
14 |
15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /views/trunks/misdn.php: -------------------------------------------------------------------------------- 1 | '.$gp.'\n'; 9 | } 10 | ?> 11 | 12 | 13 | 14 |
15 |
16 |
17 |
18 |
19 |
20 | 21 | 22 |
23 |
24 | 27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
mISDN Port Groups to configure).")?>
35 |
36 |
37 |
38 | -------------------------------------------------------------------------------- /views/trunks/popover_main.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | listTrunkTypes() as $type => $label) { ?> 5 |
6 | 7 |
8 | 9 |

10 |
11 | 12 |
13 |
14 |
15 |
16 |
17 |
18 | $trunks, 'trunk_types' => $trunk_types))?> 19 |
20 |
21 |
22 |
23 |
24 | 25 |
26 | -------------------------------------------------------------------------------- /views/trunks/trunk_footer.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 31 | 84 | 85 | 102 | -------------------------------------------------------------------------------- /views/trunks/trunkgrid.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 | 13 |
14 |
15 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 49 | 50 | 51 | 52 |
46 | 47 | 48 |
53 | -------------------------------------------------------------------------------- /views/trunks/zap.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 |
6 |
7 |
8 |
9 | 10 | 11 |
12 |
13 | 14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
The default setting is g0 (group zero).")?>
22 |
23 |
24 |
25 | 26 | -------------------------------------------------------------------------------- /views/users.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 | 9 | 14 |
15 | $sections) { ?> 16 |
17 |
18 | $elements) { ?> 19 |

20 |
21 | 22 |
23 | 24 |
25 |
26 |
27 |
28 |
29 | 30 | 31 | 32 | 33 |
34 |
35 |
36 |
37 |
38 |
39 | 40 |
41 |
42 | 43 |
44 |
45 | 46 | 47 |
48 |
49 |
50 | 51 |
52 | 53 |
54 |
55 | 56 |
57 |
58 | 59 |
60 | 61 | 62 | 63 |
64 |
65 | 104 | --------------------------------------------------------------------------------