Sipgate 2.0
authorAlexander Stintzing <a.stintzing@metaways.de>
Thu, 25 Oct 2012 19:19:57 +0000 (21:19 +0200)
committerPhilipp Schüle <p.schuele@metaways.de>
Mon, 29 Oct 2012 14:22:35 +0000 (15:22 +0100)
Change-Id: I1b1e78fa3900a65d038969a3edfa44dec1579ce6
Reviewed-on: https://gerrit.tine20.org/tine20/1250
Tested-by: jenkins user
Reviewed-by: Philipp Schüle <p.schuele@metaways.de>
58 files changed:
tests/tine20/AllTests.php
tests/tine20/Sipgate/AbstractTest.php [new file with mode: 0644]
tests/tine20/Sipgate/AllTests.php [new file with mode: 0644]
tests/tine20/Sipgate/ControllerTest.php [new file with mode: 0644]
tests/tine20/Sipgate/JsonTest.php [new file with mode: 0644]
tine20/Sipgate/Acl/Rights.php [new file with mode: 0644]
tine20/Sipgate/Backend/Account.php [new file with mode: 0644]
tine20/Sipgate/Backend/Api.php
tine20/Sipgate/Backend/Connection.php [new file with mode: 0644]
tine20/Sipgate/Backend/Factory.php [deleted file]
tine20/Sipgate/Backend/Line.php [new file with mode: 0644]
tine20/Sipgate/Config.php [new file with mode: 0644]
tine20/Sipgate/Controller.php
tine20/Sipgate/Controller/Account.php [new file with mode: 0644]
tine20/Sipgate/Controller/Connection.php [new file with mode: 0644]
tine20/Sipgate/Controller/Line.php [new file with mode: 0644]
tine20/Sipgate/Exception.php
tine20/Sipgate/Exception/Authorization.php [new file with mode: 0644]
tine20/Sipgate/Exception/Backend.php
tine20/Sipgate/Exception/MissingConfig.php [new file with mode: 0644]
tine20/Sipgate/Exception/NoConnection.php [new file with mode: 0644]
tine20/Sipgate/Exception/ResolveCredentials.php [new file with mode: 0644]
tine20/Sipgate/Frontend/Cli.php [new file with mode: 0644]
tine20/Sipgate/Frontend/Json.php
tine20/Sipgate/Model/Account.php [new file with mode: 0644]
tine20/Sipgate/Model/AccountAccountType.php [new file with mode: 0644]
tine20/Sipgate/Model/AccountFilter.php [new file with mode: 0644]
tine20/Sipgate/Model/AccountType.php [new file with mode: 0644]
tine20/Sipgate/Model/Connection.php [new file with mode: 0644]
tine20/Sipgate/Model/ConnectionFilter.php [new file with mode: 0644]
tine20/Sipgate/Model/ConnectionStatus.php [new file with mode: 0644]
tine20/Sipgate/Model/ConnectionTos.php [new file with mode: 0644]
tine20/Sipgate/Model/Line.php [new file with mode: 0644]
tine20/Sipgate/Model/LineFilter.php [new file with mode: 0644]
tine20/Sipgate/Preference.php
tine20/Sipgate/Setup/Initialize.php
tine20/Sipgate/Setup/Update/Release1.php [new file with mode: 0644]
tine20/Sipgate/Setup/calling-codes.xml [new file with mode: 0644]
tine20/Sipgate/Setup/setup.xml
tine20/Sipgate/Sipgate.jsb2
tine20/Sipgate/css/Sipgate.css
tine20/Sipgate/js/AccountEditDialog.js [new file with mode: 0644]
tine20/Sipgate/js/AccountFilterModel.js [new file with mode: 0644]
tine20/Sipgate/js/AccountGridPanel.js [new file with mode: 0644]
tine20/Sipgate/js/AddressbookGridPanelHook.js
tine20/Sipgate/js/AssignLinesGrid.js [new file with mode: 0644]
tine20/Sipgate/js/CallStateWindow.js
tine20/Sipgate/js/ConnectionGridPanel.js [new file with mode: 0644]
tine20/Sipgate/js/DialNumberDialog.js
tine20/Sipgate/js/ExceptionHandler.js [new file with mode: 0644]
tine20/Sipgate/js/LineFilterModel.js [new file with mode: 0644]
tine20/Sipgate/js/LineGridPanel.js [new file with mode: 0644]
tine20/Sipgate/js/LineSearchCombo.js [new file with mode: 0644]
tine20/Sipgate/js/Models.js [new file with mode: 0644]
tine20/Sipgate/js/SearchAddressDialog.js
tine20/Sipgate/js/Sipgate.js
tine20/Sipgate/js/SmsEditDialog.js
tine20/Sipgate/translations/template.pot

index 80fb0ba..ae017ba 100644 (file)
@@ -45,6 +45,7 @@ class AllTests
         $suite->addTest(Projects_AllTests::suite());
         $suite->addTest(HumanResources_AllTests::suite());
         $suite->addTest(Inventory_AllTests::suite());
+        $suite->addTest(Sipgate_AllTests::suite());
         $suite->addTest(Zend_AllTests::suite());
         
         return $suite;
diff --git a/tests/tine20/Sipgate/AbstractTest.php b/tests/tine20/Sipgate/AbstractTest.php
new file mode 100644 (file)
index 0000000..d49185e
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Tine 2.0 - http://www.tine20.org
+ *
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ */
+
+/**
+ * Test helper
+ */
+require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'TestHelper.php';
+
+/**
+ * Test class for Tinebase_Group
+ */
+class Sipgate_AbstractTest extends PHPUnit_Framework_TestCase
+{
+    /**
+     * testconfig
+     * @var array
+     */
+    protected $_testConfig = NULL;
+
+    /**
+     * Sets up the fixture.
+     * This method is called before a test is executed.
+     *
+     * @access protected
+     */
+    protected function setUp()
+    {
+        Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
+
+        $cfg = Tinebase_Core::getConfig();
+        if(!$cfg->sipgate) {
+            $this->markTestSkipped('No config to access the sipgate api is available.');
+        }
+        $this->_testConfig = $cfg->sipgate->toArray();
+        $this->_testConfig['description'] = 'unittest';
+        $this->_testConfig['accounttype'] = 'plus';
+    }
+
+    /**
+     * Tears down the fixture
+     * This method is called after a test is executed.
+     *
+     * @access protected
+     */
+    protected function tearDown()
+    {
+        Tinebase_TransactionManager::getInstance()->rollBack();
+    }
+}
diff --git a/tests/tine20/Sipgate/AllTests.php b/tests/tine20/Sipgate/AllTests.php
new file mode 100644 (file)
index 0000000..a4dd453
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Tine 2.0 - http://www.tine20.org
+ * 
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ */
+
+/**
+ * Test helper
+ */
+require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'TestHelper.php';
+
+if (! defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Sipgate_AllTests::main');
+}
+
+class Sipgate_AllTests
+{
+    public static function main ()
+    {
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+    
+    public static function suite ()
+    {
+        $suite = new PHPUnit_Framework_TestSuite('Tine 2.0 Sipgate All Tests');
+        $suite->addTestSuite('Sipgate_JsonTest');
+        $suite->addTestSuite('Sipgate_ControllerTest');
+        return $suite;
+    }
+}
+
+if (PHPUnit_MAIN_METHOD == 'Sipgate_AllTests::main') {
+    Sipgate_AllTests::main();
+}
diff --git a/tests/tine20/Sipgate/ControllerTest.php b/tests/tine20/Sipgate/ControllerTest.php
new file mode 100644 (file)
index 0000000..3d7c093
--- /dev/null
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Tine 2.0 - http://www.tine20.org
+ *
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ */
+
+/**
+ * Test class for Tinebase_Group
+ */
+class Sipgate_ControllerTest extends Sipgate_AbstractTest
+{
+    /**
+     * @var Sipgate_Controller_Account
+     */
+    protected $_instance = NULL;
+    protected $_startRecordId = NULL;
+
+    /**
+     * Runs the test methods of this class.
+     *
+     * @access public
+     * @static
+     */
+    public static function main()
+    {
+        $suite  = new PHPUnit_Framework_TestSuite('Tine 2.0 Sipgate Controller Tests');
+        PHPUnit_TextUI_TestRunner::run($suite);
+    }
+
+    public function testAccountController()
+    {
+        $this->_instance = Sipgate_Controller_Account::getInstance();
+        $newRecord = $this->_instance->create(new Sipgate_Model_Account($this->_testConfig), false);
+        $this->assertEquals($newRecord->password, NULL);
+        $record = $this->_instance->get($newRecord->getId());
+        $this->assertEquals($record->__get('password'), NULL);
+    }
+}
diff --git a/tests/tine20/Sipgate/JsonTest.php b/tests/tine20/Sipgate/JsonTest.php
new file mode 100644 (file)
index 0000000..fe0f931
--- /dev/null
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Tine 2.0 - http://www.tine20.org
+ *
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ */
+
+/**
+ * Test class for Sipgate_Frontend_Json
+ */
+class Sipgate_JsonTest extends Sipgate_AbstractTest
+{
+    /**
+     * @var Sipgate_Frontend_Json
+     */
+    protected $_instance = NULL;
+    protected $_controller = NULL;
+    protected $_createdId = NULL;
+    /**
+     * Runs the test methods of this class.
+     *
+     * @access public
+     * @static
+     */
+    public static function main()
+    {
+        $suite  = new PHPUnit_Framework_TestSuite('Tine 2.0 Sipgate Json Tests');
+        PHPUnit_TextUI_TestRunner::run($suite);
+    }
+    
+    /**
+     * Sets up the fixture.
+     * This method is called before a test is executed.
+     *
+     * @access protected
+     */
+    protected function setUp()
+    {
+        $this->_instance = new Sipgate_Frontend_Json();
+        parent::setUp();
+    }
+    
+    /**
+     * try to add a contract
+     *
+     */
+    public function testAccount()
+    {
+        try {
+            // test duplicate check
+            // test save
+            $record = $this->_instance->saveAccount($this->_testConfig);
+        } catch (Tinebase_Exception_Duplicate $e) {
+            // already in system
+            $this->assertEquals(629, $e->getCode());
+            $record = $e->getData()->getFirstRecord()->toArray(true);
+        }
+
+        $this->assertEquals(40, strlen($record['id']));
+        // test get
+        $record = $this->_instance->getAccount($record['id']);
+        $this->assertEquals(40, strlen($record['id']));
+
+        try {
+            // test duplicate check again if not in already
+            $this->_instance->saveAccount($this->_testConfig);
+        } catch (Tinebase_Exception_Duplicate $e) {
+            // good
+            $this->assertEquals(629, $e->getCode());
+        }
+
+    }
+}
diff --git a/tine20/Sipgate/Acl/Rights.php b/tine20/Sipgate/Acl/Rights.php
new file mode 100644 (file)
index 0000000..1382a5e
--- /dev/null
@@ -0,0 +1,116 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+
+/**
+ * this class handles the rights for the sipgate application
+ * @package     Tinebase
+ * @subpackage  Acl
+ */
+class Sipgate_Acl_Rights extends Tinebase_Acl_Rights_Abstract
+{
+   /**
+     * the right to manage accounts
+     * @static string
+     */
+    const MANAGE_ACCOUNTS        = 'manage_accounts';            // this enables the account module
+    const MANAGE_SHARED_ACCOUNTS = 'manage_shared_accounts';     // user is allowed to manage shared accounts
+    const MANAGE_PRIVATE_ACCOUNTS = 'manage_private_accounts';     // user is allowed to manage private accounts
+    
+    const SYNC_LINES = 'sync_lines';   // user is allowed to sync his lines
+    
+        
+    /**
+     * holds the instance of the singleton
+     *
+     * @var Sipgate_Acl_Rights
+     */
+    private static $_instance = NULL;
+    
+    /**
+     * the clone function
+     *
+     * disabled. use the singleton
+     */
+    private function __clone() 
+    {
+    }
+    
+    /**
+     * the constructor
+     *
+     */
+    private function __construct()
+    {
+        
+    }    
+    
+    /**
+     * the singleton pattern
+     *
+     * @return Sipgate_Acl_Rights
+     */
+    public static function getInstance() 
+    {
+        if (self::$_instance === NULL) {
+            self::$_instance = new Sipgate_Acl_Rights;
+        }
+        
+        return self::$_instance;
+    }
+    
+    /**
+     * get all possible application rights
+     *
+     * @return  array   all application rights
+     */
+    public function getAllApplicationRights()
+    {
+        return array_merge(parent::getAllApplicationRights(), array(
+            self::MANAGE_SHARED_ACCOUNTS,
+            self::MANAGE_PRIVATE_ACCOUNTS,
+            self::MANAGE_ACCOUNTS,
+            self::SYNC_LINES
+        ));
+    }
+
+    /**
+     * get translated right descriptions
+     * 
+     * @return  array with translated descriptions for this applications rights
+     */
+    public static function getTranslatedRightDescriptions()
+    {
+        $translate = Tinebase_Translation::getTranslation('Sipgate');
+        
+        $rightDescriptions = array(
+            self::MANAGE_ACCOUNTS  => array(
+                'text'          => $translate->_('manage accounts'),
+                'description'   => $translate->_('enables the account module in the application'),
+            ),
+            self::SYNC_LINES => array(
+                'text'          => $translate->_('sync lines'),
+                'description'   => $translate->_('allows the user to sync the call history'),
+                ),
+            self::MANAGE_SHARED_ACCOUNTS  => array(
+                'text'          => $translate->_('manage shared accounts'),
+                'description'   => $translate->_('add, edit and delete shared accounts'),
+            ),
+            self::MANAGE_PRIVATE_ACCOUNTS  => array(
+                'text'          => $translate->_('manage private accounts'),
+                'description'   => $translate->_('add, edit and delete private accounts'),
+            ),
+        );
+        
+        $rightDescriptions = array_merge($rightDescriptions, parent::getTranslatedRightDescriptions());
+        return $rightDescriptions;
+    }
+
+    
+}
diff --git a/tine20/Sipgate/Backend/Account.php b/tine20/Sipgate/Backend/Account.php
new file mode 100644 (file)
index 0000000..f2ce0e9
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+
+
+/**
+ * Sipgate Connection sql backend
+ *
+ * @package  Sipgate
+ */
+class Sipgate_Backend_Account extends Tinebase_Backend_Sql_Abstract
+{
+    /**
+     * Table name without prefix
+     *
+     * @var string
+     */
+    protected $_tableName = 'sipgate_account';
+
+    /**
+     * Model name
+     *
+     * @var string
+     */
+    protected $_modelName = 'Sipgate_Model_Account';
+    /**
+     * if modlog is active, we add 'is_deleted = 0' to select object in _getSelect()
+     * @var boolean
+     */
+    protected $_modlogActive = true;
+}
index e9d2616..ae74209 100644 (file)
@@ -5,8 +5,7 @@
  * @package     Sipgate
  * @license     http://www.gnu.org/licenses/agpl.html AGPL3
  * @author      Alexander Stintzing <alex@stintzing.net>
- * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
- * @version     $Id: Api.php 26 2011-05-03 01:42:01Z alex $
+ * @copyright   Copyright (c) 2011-2012 Metaways Infosystems GmbH (http://www.metaways.de)
  *
  */
 
@@ -33,58 +32,43 @@ class Sipgate_Backend_Api {
      * @var array
      */
 
-    protected $devices = false;
+    protected $devices = NULL;
 
     /**
+     * resolved account
+     * @var Sipgate_Model_Account
+     */
+    protected $_account = NULL;
+    
+    /**
      * Phone Devices
      * @var array
      */
+    
+    
+    protected $phoneDevices = NULL;
 
-    protected $phoneDevices = false;
-
-    protected $faxDevices = false;
-
-    protected $allDevices = false;
+    protected $faxDevices = NULL;
 
-    protected $_url;
+    protected $allDevices = NULL;
 
-    protected $_username;
-
-    protected $_password;
+    protected $_lastException = NULL;
 
     /**
      * the constructor
      *
      * don't use the constructor. use the singleton
      */
-    private function __construct($_username, $_password, $_url)    {
-
-        $this->_url = (empty($_url)) ? 'https://samurai.sipgate.net/RPC2' : $_url;
-        $this->_username = $_username;
-        $this->_password = $_password;
-
-        $this->_http = new Zend_Http_Client($this->_url);
-        $this->_http->setMethod('post');
-        $this->_http->setAuth($_username, $_password);
-
-        $this->_rpc = new Zend_XmlRpc_Client($this->_url,$this->_http->setAuth($_username, $_password));
-
-        $this->_rpc->call(
-            'samurai.ClientIdentify',
-        array(0 => new Zend_XmlRpc_Value_Struct(array(
-                'ClientName' => new Zend_XmlRpc_Value_String('Tine 2.0 Sipgate'),
-                'ClientVersion' =>new Zend_XmlRpc_Value_String('0.4'),
-                'ClientVendor' =>new Zend_XmlRpc_Value_String('Alexander Stintzing')
-        )))
-        );
+    private function __construct()
+    {
     }
 
-
     /**
      * don't clone. Use the singleton.
      *
      */
-    private function __clone() {}
+    private function __clone() {
+    }
 
     /**
      * holds the instance of the singleton
@@ -98,29 +82,184 @@ class Sipgate_Backend_Api {
      *
      * @return Sipgate_Backend_Api
      */
-    public static function getInstance($_username, $_password, $_url)
+    public static function getInstance()
     {
         if (self::$_instance === NULL) {
-            self::$_instance = new Sipgate_Backend_Api($_username, $_password, $_url);
+            self::$_instance = new Sipgate_Backend_Api();
         }
 
         return self::$_instance;
     }
 
     /**
+     * calls the samurai
+     * @param string $_sipUri
+     * @param Tinebase_DateTime $_start
+     * @param Tinebase_DateTime $_stop
+     * @return Zend_XmlRpc_Value_Struct
+     */
+    private function _samuraiItemizedEntriesGet($_sipUri, $_start, $_stop)
+    {
+        $localUriList[] = new Zend_XmlRpc_Value_String($_sipUri);
+        $structAr['LocalUriList'] = new Zend_XmlRpc_Value_Array($localUriList);
+
+        $structAr['PeriodStart'] = new Zend_XmlRpc_Value_DateTime($_start->toString());
+        $structAr['PeriodEnd'] = new Zend_XmlRpc_Value_DateTime($_stop->toString());
+        $struct = new Zend_XmlRpc_Value_Struct($structAr);
+
+        return $this->_rpc->call('samurai.ItemizedEntriesGet',array(0 => $struct));
+    }
+
+    /**
+     * calls the samurai
+     * @param string $_sipUri
+     * @param Tinebase_DateTime $_start
+     * @param Tinebase_DateTime $_stop
+     * @return Zend_XmlRpc_Value_Struct
+     */
+    private function _samuraiHistoryGetByDate($_sipUri, $_start, $_stop)
+    {
+        $localUriList[] = new Zend_XmlRpc_Value_String($_sipUri);
+        $structAr['LocalUriList'] = new Zend_XmlRpc_Value_Array($localUriList);
+
+        $structAr['PeriodStart'] = new Zend_XmlRpc_Value_DateTime($_start->toString());
+        $structAr['PeriodEnd'] = new Zend_XmlRpc_Value_DateTime($_stop->toString());
+        $struct = new Zend_XmlRpc_Value_Struct($structAr);
+
+        return $this->_rpc->call('samurai.HistoryGetByDate',array(0 => $struct));
+    }
+
+    /**
+     * connect
+     * @param String $_accountId     ID of the account if configured already or resolved Sipgate_Model_Account
+     * @param String $_username      Username if no account-id is given
+     * @param String $_password      Password if no account-id is given
+     * @param String $_accounttype   Accounttype if no account-id is given
+     */
+    public function connect($_accountId = NULL, $_username = NULL, $_password = NULL, $_accounttype = NULL)
+    {
+        if($_accountId) {
+            if($_accountId instanceof Sipgate_Model_Account) {
+                $this->_account = $_accountId;
+            } else {
+                $this->_account = Sipgate_Controller_Account::getInstance()->getResolved($_accountId);
+            }
+            $cfg = $this->_account->toArray();
+            if(!$cfg) {
+                throw new Sipgate_Exception_ResolveCredentials();
+            }
+        } else {
+            if($_username && $_password && $_accounttype) {
+                $cfg['username'] = $_username;
+                $cfg['password'] = $_password;
+                $cfg['accounttype'] = $_accounttype;
+            } else {
+                throw new Sipgate_Exception_MissingConfig();
+            }
+        }
+
+        if($cfg['accounttype'] == 'team') {
+            $url = 'https://api.sipgate.net/RPC2';
+        } else {
+            $url = 'https://samurai.sipgate.net/RPC2';
+        }
+
+        $this->_http = new Zend_Http_Client($url);
+        $this->_http->setMethod('post');
+        $this->_http->setAuth($cfg['username'], $cfg['password']);
+        $this->_rpc = new Zend_XmlRpc_Client($url, $this->_http);
+
+        try {
+            $this->identify();
+        } catch (Zend_XmlRpc_Client_HttpException $e) {
+            switch ($e->getCode()) {
+                case 401:
+                    // Set Account Invalid on auth error
+                    if($_accountId) {
+                        $this->_account->is_valid = false;
+                        $ac->update($this->_account);
+                    }
+                    throw new Sipgate_Exception_Authorization();
+                    break;
+                default: $this->_throwUnknownExeption($e);
+            }
+        } catch (Zend_Http_Client_Adapter_Exception $e) {
+            switch ($e->getCode()) {
+                case 0:
+                    if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) {
+                        Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " throws connection error exception: " . get_class($e));
+                        Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Code:    " . $e->getCode());
+                        Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Message: " . $e->getMessage());
+                    }
+                    throw new Sipgate_Exception_NoConnection();
+                    break;
+                default:
+                    $this->_throwUnknownExeption($e);
+            }
+        } catch (Exception $e) {
+            $this->_throwUnknownExeption($e);
+        }
+
+        return $this;
+    }
+    /**
+     * Identifies and Validates Connection
+     */
+    public function identify() {
+        $version = Tinebase_Application::getInstance()->getApplicationByName('Sipgate')->version;
+        $this->_rpc->call('samurai.ClientIdentify',
+            array(0 => new Zend_XmlRpc_Value_Struct(array(
+                'ClientName' => new Zend_XmlRpc_Value_String('Tine 2.0 Sipgate'),
+                'ClientVersion' => new Zend_XmlRpc_Value_String($version),
+                'ClientVendor' =>new Zend_XmlRpc_Value_String('Alexander Stintzing')
+            )))
+        );
+    }
+
+    /**
+     * Get Call History
+     * @param string $_sipUri
+     * @param Tinebase_DateTime $_start
+     * @param Tinebase_DateTime $_stop
+     * @return Zend_XmlRpc_Value_Struct
+     */
+    public function getCallHistory($_sipUri, $_start, $_stop) {
+        // TODO: combine with itemized entries
+        //$resp = $this->_samuraiItemizedEntriesGet($_sipUri, $_start, $_stop);
+
+        $resp = $this->_samuraiHistoryGetByDate($_sipUri, $_start, $_stop);
+
+        if($resp) {
+            $ret = array(
+                'history' => $resp['History'],
+                'totalcount' => count($resp['History'])
+            );
+        } else {
+            $ret = array(
+                'history' => NULL,
+                'totalcount' => NULL,
+            );
+        }
+
+        $ret['status_code'] = $resp['StatusCode'];
+        $ret['status_string'] = $resp['StatusString'];
+         
+        return $ret;
+    }
+    
+    /**
      * initiate new call
      *
      * @param string $_caller
      * @param string $_callee
      */
-    public function dialNumber($_caller,$_callee)
+    public function dialNumber($_caller, $_callee)
     {
         $structAr['LocalUri'] = new Zend_XmlRpc_Value_String($_caller);
         $structAr['RemoteUri'] = new Zend_XmlRpc_Value_String($_callee);
         $structAr['TOS'] = new Zend_XmlRpc_Value_String('voice');
-
         $struct = new Zend_XmlRpc_Value_Struct($structAr);
-
+        
         return $this->_rpc->call('samurai.SessionInitiate',array(0 => $struct));
     }
 
@@ -134,82 +273,36 @@ class Sipgate_Backend_Api {
     public function initiateConference($_caller,$_callees)
     {
         $structAr['LocalUri'] = new Zend_XmlRpc_Value_String($_caller);
-
         foreach($_callees as $callee) {
             $remotes[] = new Zend_XmlRpc_Value_String($_callee);
         }
-
         $structAr['RemoteUri'] = new Zend_XmlRpc_Value_Array($remotes);
-
         $structAr['TOS'] = new Zend_XmlRpc_Value_String('voice');
-
         $struct = new Zend_XmlRpc_Value_Struct($structAr);
-
         return $this->_rpc->call('samurai.SessionInitiateMulti',array(0 => $struct));
     }
 
-
-    /**
-     * Get Call History
-     * @param string $_sipUri
-     * @param string $_start
-     * @param string $_stop
-     * @param integer $_pstart
-     * @param integer $_plimit
-     * @return Zend_XmlRpc_Value_Struct
-     */
-    public function getCallHistory($_sipUri, $_start, $_stop, $_pstart, $_plimit) {
-         
-        $start = strtotime($_start);
-        $stop = strtotime($_stop);
-         
-        $localUriList[] = new Zend_XmlRpc_Value_String($_sipUri);
-        $structAr['LocalUriList'] = new Zend_XmlRpc_Value_Array($localUriList);
-
-        $structAr['PeriodStart'] = new Zend_XmlRpc_Value_DateTime($start);
-        $structAr['PeriodEnd'] = new Zend_XmlRpc_Value_DateTime($stop);
-        $struct = new Zend_XmlRpc_Value_Struct($structAr);
-
-
-
-        $resp = $this->_rpc->call('samurai.HistoryGetByDate',array(0 => $struct));
-        $ret = false;
-
-        if($resp) {
-            $history = array_reverse($resp['History'],false);
-
-            if($resp['StatusCode'] === 200) {
-                for ($i = $_pstart; $i < $_pstart + $_plimit; $i++) {
-                    if(!empty($history[$i])) $ret['items'][] = $history[$i];
-                    else break;
-                }
-                $ret['totalcount'] = count($resp['History']);
-            }
-        }
-        return $ret;
-    }
-
     /**
      * Get Call Information (itemizedEntries)
      * @param string $_sipUri
      * @return Zend_XmlRpc_Value_Struct
      */
-    //    public function getCallInfo($_sipUri) {
+    //        public function getCallInfo($_sipUri) {
     //
-    //        $localUriList[] = new Zend_XmlRpc_Value_String($_sipUri);
-    //        $structAr['LocalUriList'] = new Zend_XmlRpc_Value_Array($localUriList);
-    //        $structAr['PeriodStart'] = new Zend_XmlRpc_Value_DateTime(time()-604800);
-    //        $structAr['PeriodEnd'] = new Zend_XmlRpc_Value_DateTime(time());
-    //        $struct = new Zend_XmlRpc_Value_Struct($structAr);
+    //                $localUriList[] = new Zend_XmlRpc_Value_String($_sipUri);
+    //                $structAr['LocalUriList'] = new Zend_XmlRpc_Value_Array($localUriList);
+    //                $structAr['PeriodStart'] = new Zend_XmlRpc_Value_DateTime(time()-604800);
+    //                $structAr['PeriodEnd'] = new Zend_XmlRpc_Value_DateTime(time());
+    //                $struct = new Zend_XmlRpc_Value_Struct($structAr);
     //
-    //        $resp = $this->_rpc->call('samurai.HistoryGetByDate',array(0 => $struct));
-    //        $ret = false;
-    //        if($resp['StatusCode'] === 200) {
-    //            $ret = $resp['History'];
+    //                $resp = $this->_rpc->call('samurai.HistoryGetByDate',array(0 => $struct));
+    //                $ret = false;
+    //                if($resp['StatusCode'] === 200) {
+    //                        $ret = $resp['History'];
     //
+    //                }
+    //                return $ret;
     //        }
-    //        return $ret;
-    //    }
 
     /**
      * Get devices
@@ -261,7 +354,7 @@ class Sipgate_Backend_Api {
                 $this->allDevices[$i]['type'] = 'phone';
                 $i++;
             }
-            $ret = &$this->allDevices;
+            $ret['devices'] = &$this->allDevices;
         }
         if (($faxes = $this->getFaxDevices())) {
             foreach($faxes as $fax) {
@@ -270,6 +363,7 @@ class Sipgate_Backend_Api {
                 $i++;
             }
         }
+//         $ret['account_id'] = $this->_account_id;
         return $ret;
     }
 
@@ -300,6 +394,21 @@ class Sipgate_Backend_Api {
     }
 
     /**
+     *
+     * @param Exception $e
+     */
+    protected function _throwUnknownExeption(Exception $e)
+    {
+        if (Tinebase_Core::isLogLevel(Zend_Log::CRIT)) {
+            Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " throws unknown exception: " . get_class($e));
+            Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Code:    " . $e->getCode());
+            Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Message: " . $e->getMessage());
+        }
+        // TODO better general handling here
+        throw $e;
+    }
+
+    /**
      * send SMS
      *
      * @param string $_caller
@@ -307,19 +416,21 @@ class Sipgate_Backend_Api {
      * @param string $_content
      */
 
-    public function sendSms($_caller,$_callee,$_content)
+    public function sendSms($_caller = null, $_callee, $_content)
     {
-
         $_callee = preg_replace('/\+/','',$_callee);
-
-        $structAr['LocalUri'] = new Zend_XmlRpc_Value_String('sip:'.$_caller.'@sipgate.net');
+        $_caller = $_caller ? preg_replace('/\+/','',$_caller) : null;
+        
+        if($_caller) {
+            $structAr['LocalUri'] = new Zend_XmlRpc_Value_String('sip:'.$_caller.'@sipgate.net');
+        }
         $structAr['RemoteUri'] = new Zend_XmlRpc_Value_String('sip:'.$_callee.'@sipgate.net');
         $structAr['TOS'] = new Zend_XmlRpc_Value_String('text');
         $structAr['Content'] = new Zend_XmlRpc_Value_String($_content);
+        
         $struct = new Zend_XmlRpc_Value_Struct($structAr);
 
-        return $this->_rpc->call('samurai.SessionInitiate',array(0 => $struct));
-
+        return $this->_rpc->call('samurai.SessionInitiate', array(0 => $struct));
     }
 
 }
diff --git a/tine20/Sipgate/Backend/Connection.php b/tine20/Sipgate/Backend/Connection.php
new file mode 100644 (file)
index 0000000..deef364
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+
+
+/**
+ * Sipgate Connection sql backend
+ *
+ * @package  Voipmanager
+ */
+class Sipgate_Backend_Connection extends Tinebase_Backend_Sql_Abstract
+{
+    /**
+     * Table name without prefix
+     *
+     * @var string
+     */
+    protected $_tableName = 'sipgate_connection';
+
+    /**
+     * Model name
+     *
+     * @var string
+     */
+    protected $_modelName = 'Sipgate_Model_Connection';
+}
diff --git a/tine20/Sipgate/Backend/Factory.php b/tine20/Sipgate/Backend/Factory.php
deleted file mode 100644 (file)
index 29ed12c..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-/**
- * Tine 2.0
- * 
- * @package     Sipgate
- * @subpackage  Backend
- * @license     http://www.gnu.org/licenses/agpl.html AGPL3
- * @author      Alexander Stintzing <alex@stintzing.net>
- * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
- *
- */
-
-/**
- * sipgate backend factory class
- *
- * @package     Sipgate
- * @subpackage  Backend
- */
-class Sipgate_Backend_Factory
-{
-    /**
-     * object instance
-     *
-     * @var Addressbook_Backend_Factory
-     */
-    private static $_instance = NULL;
-
-    /**
-     * factory function to return a selected phone backend class
-     *
-     * @param   string $_type
-     * @return  Sipgate_Backend_Interface
-     * @throws  Sipgate_Exception_InvalidArgument
-     * @throws  Sipgate_Exception_NotFound
-     */
-    static public function factory()
-    {
-        if (isset(Tinebase_Core::getConfig()->sipgate)) {
-            $sipgateConfig = Tinebase_Core::getConfig()->sipgate;
-            $username   = $sipgateConfig->api_username;
-            $password   = $sipgateConfig->api_password;
-            $url         = $sipgateConfig->api_url;
-        } else {
-            throw new Sipgate_Exception_Backend('No settings found for sipgate backend in config file!');
-        }
-
-        $instance = Sipgate_Backend_Api::getInstance($username, $password, $url);
-
-        return $instance;
-    }
-}
diff --git a/tine20/Sipgate/Backend/Line.php b/tine20/Sipgate/Backend/Line.php
new file mode 100644 (file)
index 0000000..db35708
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+
+
+/**
+ * Sipgate Connection sql backend
+ *
+ * @package  Voipmanager
+ */
+class Sipgate_Backend_Line extends Tinebase_Backend_Sql_Abstract
+{
+    /**
+     * Table name without prefix
+     *
+     * @var string
+     */
+    protected $_tableName = 'sipgate_line';
+
+    /**
+     * Model name
+     *
+     * @var string
+     */
+    protected $_modelName = 'Sipgate_Model_Line';
+}
diff --git a/tine20/Sipgate/Config.php b/tine20/Sipgate/Config.php
new file mode 100644 (file)
index 0000000..da07453
--- /dev/null
@@ -0,0 +1,140 @@
+<?php
+/**
+ * @package     Sipgate
+ * @subpackage  Config
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+
+/**
+ * Sipgate config class
+ *
+ * @package     Sipgate
+ * @subpackage  Config
+ */
+class Sipgate_Config extends Tinebase_Config_Abstract
+{
+    /**
+     * Connection Status
+     * @var string
+     */
+    const CONNECTION_STATUS = 'connectionStatus';
+
+    /**
+     * Connection TOS
+     * @var string
+     */
+    const CONNECTION_TOS = 'connectionTos';
+
+    /**
+     * Account type (shared/private)
+     * @var string
+     */
+    const ACCOUNT_TYPE = 'accountType';
+    
+    /**
+     * Sipgate account type (plus/team) - plus means also basic
+     * @var string
+     */
+    const ACCOUNT_ACCOUNT_TYPE = 'accountAccountType';
+    
+    /**
+     * (non-PHPdoc)
+     * @see tine20/Tinebase/Config/Definition::$_properties
+     */
+    protected static $_properties = array(
+        self::CONNECTION_STATUS => array(
+            //_('Connection Status')
+            'label'                 => 'Connection Status',
+            //_('Possible connection states')
+            'description'           => 'Possible connection states',
+            'type'                  => 'keyFieldConfig',
+            'options'               => array('recordModel' => 'Sipgate_Model_ConnectionStatus'),
+            'clientRegistryInclude' => TRUE,
+            'default'               => 'accepted'
+        ),
+        self::CONNECTION_TOS => array(
+            //_('Connection TOS')
+            'label'                 => 'Connection TOS',
+            //_('Possible connection type of services')
+            'description'           => 'Possible connection type of services',
+            'type'                  => 'keyFieldConfig',
+            'options'               => array('recordModel' => 'Sipgate_Model_ConnectionTos'),
+            'clientRegistryInclude' => TRUE,
+            'default'               => 'voice'
+        ),
+        self::ACCOUNT_TYPE => array(
+            //_('Account Type')
+            'label'                 => 'Account Type',
+            //_('Private Accounts are editable only for the creating user. Shared accounts are editable for users with "edit shared" rights')
+            'description'           => 'Private Accounts are editable only for the creating user. Shared accounts are editable for users with "edit shared" rights',
+            'type'                  => 'keyFieldConfig',
+            'options'               => array('recordModel' => 'Sipgate_Model_AccountType'),
+            'clientRegistryInclude' => TRUE,
+            'default'               => 'shared'
+        ),
+        self::ACCOUNT_ACCOUNT_TYPE => array(
+            //_('Sipgate Account Type')
+            'label'                 => 'Sipgate Account Type',
+            //_('The type of your account as defined in the contract')
+            'description'           => 'The type of your account as defined in the contract',
+            'type'                  => 'keyFieldConfig',
+            'options'               => array('recordModel' => 'Sipgate_Model_AccountAccountType'),
+            'clientRegistryInclude' => TRUE,
+            'default'               => 'plus'
+        ),
+    );
+
+    /**
+     * (non-PHPdoc)
+     * @see tine20/Tinebase/Config/Abstract::$_appName
+     */
+    protected $_appName = 'Sipgate';
+
+    /**
+     * holds the instance of the singleton
+     *
+     * @var Tinebase_Config
+     */
+    private static $_instance = NULL;
+
+    /**
+     * the constructor
+     *
+     * don't use the constructor. use the singleton
+     */
+    private function __construct() {
+    }
+
+    /**
+     * the constructor
+     *
+     * don't use the constructor. use the singleton
+     */
+    private function __clone() {
+    }
+
+    /**
+     * Returns instance of Tinebase_Config
+     *
+     * @return Tinebase_Config
+     */
+    public static function getInstance()
+    {
+        if (self::$_instance === NULL) {
+            self::$_instance = new self();
+        }
+
+        return self::$_instance;
+    }
+
+    /**
+     * (non-PHPdoc)
+     * @see tine20/Tinebase/Config/Abstract::getProperties()
+     */
+    public static function getProperties()
+    {
+        return self::$_properties;
+    }
+}
index 58d036d..b6d780f 100644 (file)
 <?php
-/**
- * Tine 2.0
- *
- * @package     Sipgate
- * @license     http://www.gnu.org/licenses/agpl.html AGPL3
- * @author      Alexander Stintzing <alex@stintzing.net>
- * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
- * @version     $Id: Controller.php 26 2011-05-03 01:42:01Z alex $
- *
- */
-
-/**
- * controller class for the Sipgate application
- *
- * @package     Sipgate
- */
-class Sipgate_Controller extends Tinebase_Controller_Abstract
-{
-    /**
-     * call backend type
-     *
-     * @var string
-     */
-    protected $_callBackendType = NULL;
-
-    /**
-     * Application name
-     * @var string
-     */
-    protected $applicationName = NULL;
-
-    /**
-     * Holds the Preferences
-     * @var Sipgate_Preference
-     */
-    protected $_pref = NULL;
-
-    /**
-     * the constructor
-     *
-     * don't use the constructor. use the singleton
-     */
-    private function __construct() {
-        $this->_applicationName = 'Sipgate';
-        $this->_pref = new Sipgate_Preference();
-    }
-
-    /**
-     * don't clone. Use the singleton.
-     *
-     */
-    private function __clone() {
-    }
-
-    /**
-     * holds the instance of the singleton
-     *
-     * @var Sipgate_Controller
-     */
-    private static $_instance = NULL;
-
-    /**
-     * the singleton pattern
-     *
-     * @return Sipgate_Controller
-     */
-    public static function getInstance()
-    {
-        if (self::$_instance === NULL) {
-            self::$_instance = new Sipgate_Controller();
-        }
-
-        return self::$_instance;
-    }
-
-    /**
-     * dial number
-     *
-     * @param   int $_callee
-     * @return  mixed
-     */
-    public function dialNumber($_callee)
-    {
-        $caller = $this->_pref->{'phoneId'};
+// /**
+//  * Tine 2.0
+//  *
+//  * @package     Sipgate
+//  * @license     http://www.gnu.org/licenses/agpl.html AGPL3
+//  * @author      Alexander Stintzing <alex@stintzing.net>
+//  * @copyright   Copyright (c) 2011-2012 Metaways Infosystems GmbH (http://www.metaways.de)
+//  *
+//  */
+
+// /**
+//  * controller class for the Sipgate application
+//  * @package     Sipgate
+//  */
+// class Sipgate_Controller extends Tinebase_Controller_Abstract
+// {
+//     /**
+// <<<<<<< .merge_file_77tLhk
+//      * @see Tinebase_Controller_Abstract
+//      * @var unknown_type
+//      */
+//     protected $_applicationName = 'Sipgate';
+    
+//     protected $_credentialKey = 'NULL';
+// =======
+//      * call backend type
+//      *
+//      * @var string
+//      */
+//     protected $_callBackendType = NULL;
+
+//     /**
+//      * Application name
+//      * @var string
+//      */
+//     protected $applicationName = NULL;
+
+//     /**
+//      * Holds the Preferences
+//      * @var Sipgate_Preference
+//      */
+//     protected $_pref = NULL;
+
+//     /**
+//      * the constructor
+//      *
+//      * don't use the constructor. use the singleton
+//      */
+//     private function __construct() {
+//         $this->_applicationName = 'Sipgate';
+//         $this->_pref = new Sipgate_Preference();
+//     }
+
+//     /**
+//      * don't clone. Use the singleton.
+//      *
+//      */
+//     private function __clone() {
+//     }
+
+// >>>>>>> .merge_file_Tbopjl
+//     /**
+//      * holds the instance of the singleton
+//      *
+//      * @var Sipgate_Controller
+//      */
+//     private static $_instance = NULL;
+// <<<<<<< .merge_file_77tLhk
+// =======
+
+// >>>>>>> .merge_file_Tbopjl
+//     /**
+//      * the singleton pattern
+//      *
+//      * @return Sipgate_Controller
+//      */
+//     public static function getInstance()
+//     {
+//         if (self::$_instance === NULL) {
+//             self::$_instance = new Sipgate_Controller();
+//         }
+
+//         return self::$_instance;
+//     }
+// <<<<<<< .merge_file_77tLhk
+    
+//     /**
+//      * returns the globalcredentials for this app
+//      * @return array
+//      */
+//     public function getAccount()
+//     {
+//         if(!Tinebase_Core::getUser()->hasRight('Sipgate', 'admin')) {
+//             throw new Tinebase_Exception_AccessDenied(_('You do not have admin rights on Sales'));
+//         }
+        
+//         return new Sipgate_Model_Account_Shared();
+        
+// //         $cfg = Tinebase_Account::getInstance()->getAccount('Sipgate', Tinebase_Application::getInstance()->getApplicationByName($this->_applicationName)->getId(), false);
+
+// //         die(var_dump($credentials));
+// //         return array();
+//     }
+
+//     /**
+//      * save Sales settings
+//      *
+//      * @param string autogenerate credentials
+//      * @return Sales_Model_Account
+//      *
+//      * @todo generalize this
+//      */
+//     public function setAccount($_credentials)
+//     {
+//         if(!Tinebase_Core::getUser()->hasRight('Sipgate', 'admin')) {
+//             throw new Tinebase_Exception_AccessDenied(_('You do not have admin rights on Sipgate'));
+//         }
+//         $c = new Sipgate_Model_Account_Shared($_credentials);
+//         return $c;
+        
+// //         Tinebase_Config::getInstance()->setConfigForApplication($_name, $_value, $this->_applicationName);
+// //         return Sipgate_Backend_Config::getInstance()->setConfig($config);
+//     }
+//     /**
+//      * call backend type
+//      *
+//      * @var string
+//      */
+//     protected $_callBackendType = NULL;
+
+//     /**
+//      * Application name
+//      * @var string
+//      */
+//     protected $_applicationName = 'Sipgate';
+
+//     /**
+//      * Holds the Preferences
+//      * @var Sipgate_Preference
+//      */
+//     protected $_pref = NULL;
+
+//     /**
+//      * the constructor
+//      *
+//      * don't use the constructor. use the singleton
+//      */
+//     private function __construct() {
+// //         $this->_pref = new Sipgate_Preference();
+//     }
+
+//     /**
+//      * don't clone. Use the singleton.
+//      *
+//      */
+//     private function __clone() {
+//     }
+
+//     /**
+//      * holds the instance of the singleton
+//      *
+//      * @var Sipgate_Controller
+//      */
+//     private static $_instance = NULL;
+
+    
+
+//     /**
+//      * dial number
+//      *
+//      * @param   int $_callee
+//      * @return  mixed
+//      */
+//     public function dialNumber($_callee)
+//     {
+//         $caller = $this->_pref->{'phoneId'};
+
+//         $backend = Sipgate_Backend_Api::getInstance();
+
+//         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
+//             . ' Dialing number ' . $_callee . ' with phone id ' . $caller);
+
+//         return $backend->dialNumber($caller, $_callee);
+//     }
+
+//     /**
+//      * gets the Session Status by an Id
+//      * @param string $sessionId
+//      */
+//     public function getSessionStatus($sessionId) {
+//         if(empty($sessionId)) throw new Sipgate_Exception('No Session-Id in Controller submitted!');
+//         $backend = Sipgate_Backend_Api::getInstance();
+//         return $backend->getSessionStatus($sessionId);
+//     }
+
+//     /**
+//      * Closes the Session by an Id
+//      * @param string $sessionId
+//      */
+//     public function closeSession($sessionId) {
+//         if(empty($sessionId)) throw new Sipgate_Exception('No Session-Id in Controller submitted!');
+//         $backend = Sipgate_Backend_Api::getInstance();
+//         return $backend->closeSession($sessionId);
+//     }
+
+
+
+
+//     /**
+//      *
+//      * Gets the devices
+//      */
+//     public function getAllDevices() {
+
+
+
+//         $backend = Sipgate_Backend_Api::getInstance();
+//         return $backend->getAllDevices();
+//     }
+
+//     /**
+//      * Gets the Phones
+//      *
+//      * @return array
+//      */
+//     public function getPhoneDevices() {
+//         $backend = Sipgate_Backend_Api::getInstance();
+
+//         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Getting sipgate phones.');
+//         $result = $backend->getPhoneDevices();
+//         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . print_r($result, TRUE));
+
+//         return $result;
+//     }
+
+//     /**
+//      *
+//      * Gets the Faxes
+//      */
+//     public function getFaxDevices() {
+//         $backend = Sipgate_Backend_Api::getInstance();
+//         return $backend->getFaxDevices();
+//     }
+
+//     /**
+//      * Gets the CallHistory of the specified sipUri
+//      *
+//      * @param String $_sipUri
+//      */
+
+//     public function getCallHistory($_sipUri, $_start, $_stop, $_pstart, $_plimit) {
+
+//         return Sipgate_Backend_Api::getInstance()->getCallHistory($_sipUri, $_start, $_stop, $_pstart, $_plimit);
+//     }
+
+
+//     /**
+//      * send SMS
+//      *
+//      * @param   string $_number
+//      * @param   string $_content
+//      */
+//     public function sendSms($_number,$_content)
+//     {
+//         $_sender = $this->_pref->getValue('mobileNumber');
+//         $backend = Sipgate_Backend_Api::getInstance();
+//         return $backend->sendSms($_sender, $_number, $_content);
+//     }
+
+//     /**
+//      * Returns settings for crm app
+//      * - result is cached
+//      *
+//      * @param boolean $_resolve if some values should be resolved (here yet unused)
+//      * @return  Sipgate_Model_Config
+//      *
+//      * @todo check 'endslead' values
+//      * @todo generalize this / adopt Tinebase_Controller_Abstract::getConfigSettings()
+//      */
+//     public function getConfigSettings($_resolve = FALSE)
+//     {
+//         //        return array('success' => 1);
+//         //        $cache = Tinebase_Core::get('cache');
+//         //        $cacheId = convertCacheId('getSipgateSettings');
+//         //        $result = $cache->load($cacheId);
+//         //        if (! $result) {
+//         $settings = Tinebase_Config::getInstance()->getConfigAsArray('account_settings','Sipgate');
+//         if(!empty($settings)) {
+//             if($_resolve) {
+//                 $cc = Tinebase_Auth_CredentialCache::getInstance()->get($settings['ccId']);
+//                 $cc->key = 'sipgate_credential_cache';
+//                 Tinebase_Auth_CredentialCache::getInstance()->getCachedAccount($cc);
+//                 $settings['password'] = $cc->password;
+//             } else {
+//                 $settings['password'] = 'XXXXXX';
+//             }
+//         } else {
+//             $settings['password'] = 'XXXXXX';
+//         }
+//         $result = new Sipgate_Model_Config($settings);
+
+//         //            unset($settings['ccId']);
+//         //die(var_dump($settings));
+//         // save result and tag it with 'settings'
+//         //            $cache->save($cc, $cacheId, array('getSipgateSettings'));
+//         //        }
+
+//         return $result;
+//     }
+
+//     /**
+//      * save crm settings
+//      *
+//      * @param Crm_Model_Config $_settings
+//      * @return Crm_Model_Config
+//      *
+//      * @todo generalize this
+//      */
+//     public function saveConfigSettings($_values)
+//     {
+//         // Get Password
+//         if($_values['password'] == 'XXXXXX') {
+//             $settings = Tinebase_Config::getInstance()->getConfigAsArray('account_settings','Sipgate');
+//             $cc = Tinebase_Auth_CredentialCache::getInstance()->get($settings['ccId']);
+//             $cc->key = 'sipgate_credential_cache';
+//             Tinebase_Auth_CredentialCache::getInstance()->getCachedAccount($cc);
+//             $_values['password'] = $cc->password;
+//         }
+
+//         $values['accounttype'] = $_values['accounttype'];
+
+//         if ($_values['password'] && $_values['username']) {
+//             $cc = Tinebase_Auth_CredentialCache::getInstance()->cacheAccount($_values['username'], $_values['password'], 'sipgate_credential_cache');
+//             $ccRes = $cc->getCacheId();
+//             $values['ccId'] = $ccRes['id'];
+//             $values['username'] = $_values['username'];
+//         } else {
+//             return json_encode(array('success' => false));
+//         }
+
+//         $settings = new Sipgate_Model_Config($values);
+
+//         Tinebase_Config::getInstance()->setConfigForApplication('account_settings', Zend_Json::encode($settings->toArray()), $this->_applicationName);
+//         Tinebase_Core::get('cache')->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('sipgateSettings'));
+
+//         return $this->getConfigSettings();
+// =======
+
+//     /**
+//      * dial number
+//      *
+//      * @param   int $_callee
+//      * @return  mixed
+//      */
+//     public function dialNumber($_callee)
+//     {
+//         $caller = $this->_pref->{'phoneId'};
           
-        $backend = Sipgate_Backend_Factory::factory();
+//         $backend = Sipgate_Backend_Factory::factory();
         
-        if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ 
-          . ' Dialing number ' . $_callee . ' with phone id ' . $caller);
+//         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ 
+//           . ' Dialing number ' . $_callee . ' with phone id ' . $caller);
           
-        return $backend->dialNumber($caller, $_callee);
-    }
-
-    /**
-     * gets the Session Status by an Id
-     * @param string $sessionId
-     */
-    public function getSessionStatus($sessionId) {
-        if(empty($sessionId)) throw new Sipgate_Exception('No Session-Id in Controller submitted!');
-        $backend = Sipgate_Backend_Factory::factory();
-        return $backend->getSessionStatus($sessionId);
-    }
-
-    /**
-     * Closes the Session by an Id
-     * @param string $sessionId
-     */
-    public function closeSession($sessionId) {
-        if(empty($sessionId)) throw new Sipgate_Exception('No Session-Id in Controller submitted!');
-        $backend = Sipgate_Backend_Factory::factory();
-        return $backend->closeSession($sessionId);
-    }
-
-    /**
-     *
-     * Gets the devices
-     */
-    public function getAllDevices() {
-        $backend = Sipgate_Backend_Factory::factory();
-        return $backend->getAllDevices();
-    }
-
-    /**
-     * Gets the Phones
-     * 
-     * @return array
-     */
-    public function getPhoneDevices() {
-        $backend = Sipgate_Backend_Factory::factory();
+//         return $backend->dialNumber($caller, $_callee);
+//     }
+
+//     /**
+//      * gets the Session Status by an Id
+//      * @param string $sessionId
+//      */
+//     public function getSessionStatus($sessionId) {
+//         if(empty($sessionId)) throw new Sipgate_Exception('No Session-Id in Controller submitted!');
+//         $backend = Sipgate_Backend_Factory::factory();
+//         return $backend->getSessionStatus($sessionId);
+//     }
+
+//     /**
+//      * Closes the Session by an Id
+//      * @param string $sessionId
+//      */
+//     public function closeSession($sessionId) {
+//         if(empty($sessionId)) throw new Sipgate_Exception('No Session-Id in Controller submitted!');
+//         $backend = Sipgate_Backend_Factory::factory();
+//         return $backend->closeSession($sessionId);
+//     }
+
+//     /**
+//      *
+//      * Gets the devices
+//      */
+//     public function getAllDevices() {
+//         $backend = Sipgate_Backend_Factory::factory();
+//         return $backend->getAllDevices();
+//     }
+
+//     /**
+//      * Gets the Phones
+//      * 
+//      * @return array
+//      */
+//     public function getPhoneDevices() {
+//         $backend = Sipgate_Backend_Factory::factory();
         
-        if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ 
-          . ' Getting sipgate phones.');
+//         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ 
+//           . ' Getting sipgate phones.');
           
-        $result = $backend->getPhoneDevices();
+//         $result = $backend->getPhoneDevices();
         
-        if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . print_r($result, TRUE));
+//         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . print_r($result, TRUE));
         
-        return $result;
-    }
-
-    /**
-     *
-     * Gets the Faxes
-     */
-    public function getFaxDevices() {
-        $backend = Sipgate_Backend_Factory::factory();
-        return $backend->getFaxDevices();
-    }
-
-    /**
-     * Gets the CallHistory of the specified sipUri
-     *
-     * @param String $_sipUri
-     */
-
-    public function getCallHistory($_sipUri, $_start, $_stop, $_pstart, $_plimit) {
-
-        return Sipgate_Backend_Factory::factory()->getCallHistory($_sipUri, $_start, $_stop, $_pstart, $_plimit);
-    }
-
-
-    /**
-     * send SMS
-     *
-     * @param   string $_number
-     * @param   string $_content
-     */
-    public function sendSms($_number,$_content)
-    {
-        $_sender = $this->_pref->getValue('mobileNumber');
-        $backend = Sipgate_Backend_Factory::factory();
-        return $backend->sendSms($_sender, $_number, $_content);
-    }
-
-
-}
+//         return $result;
+//     }
+
+//     /**
+//      *
+//      * Gets the Faxes
+//      */
+//     public function getFaxDevices() {
+//         $backend = Sipgate_Backend_Factory::factory();
+//         return $backend->getFaxDevices();
+//     }
+
+//     /**
+//      * Gets the CallHistory of the specified sipUri
+//      *
+//      * @param String $_sipUri
+//      */
+
+//     public function getCallHistory($_sipUri, $_start, $_stop, $_pstart, $_plimit) {
+
+//         return Sipgate_Backend_Factory::factory()->getCallHistory($_sipUri, $_start, $_stop, $_pstart, $_plimit);
+//     }
+
+
+//     /**
+//      * send SMS
+//      *
+//      * @param   string $_number
+//      * @param   string $_content
+//      */
+//     public function sendSms($_number,$_content)
+//     {
+//         $_sender = $this->_pref->getValue('mobileNumber');
+//         $backend = Sipgate_Backend_Factory::factory();
+//         return $backend->sendSms($_sender, $_number, $_content);
+//     }
+// >>>>>>> .merge_file_Tbopjl
+
+// //     }
+
+// }
diff --git a/tine20/Sipgate/Controller/Account.php b/tine20/Sipgate/Controller/Account.php
new file mode 100644 (file)
index 0000000..58edbc1
--- /dev/null
@@ -0,0 +1,301 @@
+<?php
+
+/**
+ * Tine 2.0
+ *
+ * @package     Sipgate
+ * @subpackage  Controller
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+
+/**
+ * Account Controller for Sipgate
+ *
+ * @package     Sipgate
+ * @subpackage  Controller
+ */
+class Sipgate_Controller_Account extends Tinebase_Controller_Record_Abstract
+{
+
+    /**
+     * check for container ACLs
+     *
+     * @var boolean
+     *
+     */
+    protected $_doContainerACLChecks = false;
+
+    /**
+     * do right checks - can be enabled/disabled by _setRightChecks
+     *
+     * @var boolean
+     */
+    protected $_doRightChecks = false;
+
+    /**
+     * forces not to apply default filters
+     * 
+     * @var boolean
+     */
+    private $_rightsLessSearch = false;
+
+    /**
+     * holds the instance of the singleton
+     *
+     * @var Sipgate_Controller_Account
+     */
+    private static $_instance = NULL;
+
+    /**
+     * the current credential key
+     * 
+     * @var string
+     */
+    private $_credential_key = NULL;
+
+    /**
+     * duplicate check fields / if this is NULL -> no duplicate check
+     *
+     * @var array
+     */
+    protected $_duplicateCheckFields = array(array('username'));
+    
+    /**
+     * the constructor
+     *
+     * don't use the constructor. use the singleton
+     */
+    private function __construct() {
+        $this->_applicationName = 'Sipgate';
+        $this->_modelName = 'Sipgate_Model_Account';
+        $this->_backend = new Sipgate_Backend_Account();
+        $cfg = Tinebase_Core::getConfig();
+        if($cfg->shared_credential_key) {
+            $this->_credential_key = $cfg->shared_credential_key;
+            if(strlen($this->_credential_key) != 24) {
+                throw new Exception('The shared_credential_key must have a length of 24. Your key has a length of '. strlen($this->_credential_key));
+            }
+        } else {
+            throw new Exception('You must configure a shared_credential_key in config.inc.php');
+        }
+    }
+
+    /**
+     * don't clone. Use the singleton.
+     */
+    private function __clone()
+    {
+    }
+
+    /**
+     * the singleton pattern
+     *
+     * @return Sipgate_Controller_Account
+     */
+    public static function getInstance()
+    {
+        if (self::$_instance === NULL) {
+            self::$_instance = new Sipgate_Controller_Account();
+        }
+
+        return self::$_instance;
+    }
+    
+    /**
+     * @param   Array $account
+     */
+    public function validateAccount($account)
+    {
+        $b = Sipgate_Backend_Api::getInstance();
+        if(empty($account['data']['username'])) {
+            $b->connect($account['data']['id']);
+        } else {
+            $b->connect(NULL, $account['data']['username'], $account['data']['password'], $account['data']['accounttype']);
+        }
+        return true;
+    }
+
+    /**
+     * @param Tinebase_Record_RecordSet $_records
+     */
+    public function resolveMultipleAccounts(Tinebase_Record_RecordSet $_records)
+    {
+        $accountIds = array_unique($_records->account_id);
+        $accounts = $this->getMultiple($accountIds);
+        foreach ($_records as $record) {
+            $idx = $accounts->getIndexById($record->account_id);
+            $record->account_id = $accounts[$idx];
+        }
+    }
+
+    /**
+     * returns resolved credentials
+     * 
+     * @param string $_id
+     * @throws Exception
+     * 
+     * @return Tinebase_Model_CredentialCache
+     */
+    public function getResolved($_id)
+    {
+        $record = $this->get($_id);
+        if(! $this->_resolveCredentials($record)) {
+            throw new Exception('Could not resolve Credentials!');
+        }
+        return $record;
+    }
+
+    /**
+     * resolve credentials
+     * 
+     * @return boolean
+     */
+    private function _resolveCredentials(&$_record)
+    {
+        Tinebase_Auth_CredentialCache::getInstance()->setCacheAdapter('Config');
+        $cc = Tinebase_Auth_CredentialCache::getInstance()->get($_record->credential_id);
+        $cc->key = $this->_credential_key;
+        $cc->username = NULL;
+        $cc->password = NULL;
+        Tinebase_Auth_CredentialCache::getInstance()->getCachedCredentials($cc);
+
+        if(! ($cc->password || $cc->username)) {
+            return false;
+        }
+
+        $_record->password = $cc->password;
+        $_record->username = $cc->username;
+
+        return true;
+    }
+
+    /**
+     * inspect creation of one record
+     * - add credentials and user id here
+     *
+     * @param   Tinebase_Record_Interface $_record
+     * @return  void
+     */
+    protected function _inspectBeforeCreate(Tinebase_Record_Interface $_record)
+    {
+        $cId = $this->_createCredentials($_record->username, $_record->password);
+        // add user id
+        $_record->credential_id = $cId;
+        $_record->password = NULL;
+        // username saved md5, so uniquity-check is possible
+        $_record->username = md5($_record->username);
+    }
+
+    protected function _inspectBeforeUpdate($_record, $_oldRecord)
+    {
+        // If password has changed
+        if(!empty($_record->password)) {
+            if(empty($_record->username)) {
+                $this->_resolveCredentials($_oldRecord);
+                $newCacheId = $this->_createCredentials($_oldRecord->username, $_record->password);
+                $_record->username = md5($_oldRecord->username);
+            } else {
+                $newCacheId = $this->_createCredentials($_record->username, $_record->password);
+            }
+            $_record->credential_id = $newCacheId;
+            // If password has not changed
+        } else {
+            $this->_resolveCredentials($_oldRecord);
+            $_record->username = md5($_oldRecord->username);
+            $_record->password = NULL;
+            $_record->credential_id = $_oldRecord->credential_id;
+        }
+        $lines = new Tinebase_Record_RecordSet('Sipgate_Model_Line');
+        foreach($_record->lines as $lineArray) {
+            Sipgate_Controller_Line::getInstance()->update(new Sipgate_Model_Line($lineArray));
+        }
+    }
+
+    /**
+     * inspects delete action
+     *
+     * @param array $_ids
+     * @return array of ids to actually delete
+     */
+    protected function _inspectDelete(array $_ids)
+    {
+        if(!is_array($_ids)) {
+            $_ids = array($_ids);
+        }
+        $filter = new Sipgate_Model_LineFilter(array(), 'OR');
+        
+        foreach($_ids as $id) {
+            $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'account_id', 'operator' => 'equals', 'value' => $id)));
+        }
+        Sipgate_Controller_Line::getInstance()->deleteByFilter($filter);
+        return $_ids;
+    }
+
+    /**
+     * create account credentials and return new credentials id
+     *
+     * @param string $_username
+     * @param string $_password
+     * @return boolean
+     */
+    protected function _createCredentials($_username = NULL, $_password = NULL)
+    {
+        Tinebase_Auth_CredentialCache::getInstance()->setCacheAdapter('Config');
+        $cc = new Tinebase_Model_CredentialCache(array(
+            'username' => $_username,
+            'password' => $_password,
+        ));
+
+        $ac = Tinebase_Auth_CredentialCache::getInstance()->cacheCredentials(
+            $cc->username,
+            $cc->password,
+            $this->_credential_key,
+            TRUE
+        );
+
+        return $ac->getId();
+    }
+
+    /**
+     * the method without rights and justice
+     * @param Tinebase_Model_Filter_FilterGroup $_filter
+     * @param Tinebase_Record_Interface $_pagination
+     * @param unknown_type $_getRelations
+     * @param unknown_type $_onlyIds
+     * @param unknown_type $_action
+     */
+    public function searchRightsLess(Tinebase_Model_Filter_FilterGroup $_filter = NULL, Tinebase_Record_Interface $_pagination = NULL, $_getRelations = FALSE, $_onlyIds = FALSE, $_action = 'get') {
+        $this->_rightsLessSearch = true;
+        $ret = $this->search($_filter, $_pagination, $_getRelations, $_onlyIds, $_action);
+        $this->_rightsLessSearch = false;
+        return $ret;
+    }
+    /**
+     * adds default filter on search
+     * @see Tinebase_Controller_Record_Abstract::_addDefaultFilter()
+     */
+    protected function _addDefaultFilter(Tinebase_Model_Filter_FilterGroup $_filter = NULL)
+    {
+        if($this->_rightsLessSearch || Tinebase_Core::getUser()->hasRight('Sipgate', 'admin')) {
+            return;
+        }
+        if(!Tinebase_Core::getUser()->hasRight('Sipgate', Sipgate_Acl_Rights::MANAGE_ACCOUNTS)) {
+            throw new Tinebase_Exception_AccessDenied('You don\'t have insufficient permissions to manage accounts!');
+        }
+
+        $fg = new Sipgate_Model_AccountFilter(array(), 'OR');
+        if (Tinebase_Core::getUser()->hasRight('Sipgate', Sipgate_Acl_Rights::MANAGE_PRIVATE_ACCOUNTS)) {
+            $fg1 = new Sipgate_Model_AccountFilter(array(), 'AND');
+            $fg1->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'type', 'operator' => 'equals', 'value' => 'private')));
+            $fg1->addFilter(new Tinebase_Model_Filter_Id(array('field' => 'created_by', 'operator' => 'equals', 'value' => Tinebase_Core::getUser()->getId())));
+            $fg->addFilterGroup($fg1);
+            $_filter->addFilterGroup($fg);
+        }
+
+        if (Tinebase_Core::getUser()->hasRight('Sipgate', Sipgate_Acl_Rights::MANAGE_SHARED_ACCOUNTS)) {
+            $fg->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'type', 'operator' => 'equals', 'value' => 'shared')));
+        }
+    }
+}
diff --git a/tine20/Sipgate/Controller/Connection.php b/tine20/Sipgate/Controller/Connection.php
new file mode 100644 (file)
index 0000000..00fcac1
--- /dev/null
@@ -0,0 +1,350 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Sipgate
+ * @subpackage  Controller
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ *
+ */
+
+/**
+ * contact controller for Sipgate
+ *
+ * @package     Sipgate
+ * @subpackage  Controller
+ */
+class Sipgate_Controller_Connection extends Tinebase_Controller_Record_Abstract
+{
+    /**
+     * prefix to remove from sip-uris
+     * @var array
+     */
+    protected $_stripPrefix = array('2300','2301','2400','1100');
+
+    /**
+     * check for container ACLs
+     * @var boolean
+     */
+    protected $_doContainerACLChecks = false;
+
+    /**
+     * @var Sipgate_Backend_Api
+     */
+    protected $_apiBackend = NULL;
+
+    /**
+     * do right checks - can be enabled/disabled by _setRightChecks
+     * @var boolean
+     */
+    protected $_doRightChecks = false;
+
+    /**
+     * the constructor
+     * don't use the constructor. use the singleton
+     */
+    private function __construct() {
+        $this->_applicationName = 'Sipgate';
+        $this->_modelName = 'Sipgate_Model_Connection';
+        $this->_backend = new Sipgate_Backend_Connection();
+    }
+
+    /**
+     * don't clone. Use the singleton.
+     */
+    private function __clone()
+    {
+    }
+
+    /**
+     * holds the instance of the singleton
+     *
+     * @var Sipgate_Controller_Connection
+     */
+    private static $_instance = NULL;
+
+    /**
+     * the singleton pattern
+     *
+     * @return Sipgate_Controller_Connection
+     */
+    public static function getInstance()
+    {
+        if (self::$_instance === NULL) {
+            self::$_instance = new Sipgate_Controller_Connection();
+        }
+
+        return self::$_instance;
+    }
+    /**
+     * sync line
+     * @param Sipgate_Model_Line $_line
+     * @param Tinebase_DateTime $_from
+     * @param Tinebase_DateTime $_to
+     * @param boolean $verbose
+     */
+    public function syncLine(Sipgate_Model_Line $_line, Tinebase_DateTime $_from = NULL, Tinebase_DateTime $_to = NULL, $verbose = false)
+    {
+        $app = Tinebase_Application::getInstance()->getApplicationByName('Sipgate');
+
+        if (! Tinebase_Core::getUser()->hasRight($app->getId(), Sipgate_Acl_Rights::SYNC_LINES)) {
+            throw new Tinebase_Exception_AccessDenied('You are not allowed to sync lines!');
+        }
+
+        if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
+            Tinebase_Core::getLogger()->debug('Synchronizing Line ' . $_line->sip_uri . '...');
+        }
+
+        $transactionId = Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
+        $count = 0;
+
+        if($_from == null) {
+            if($_line->last_sync == null) {
+                $_from = new Tinebase_DateTime();
+                $_from->subMonth(2);
+            } else {
+                $_from = $_line->last_sync;
+            }
+        }
+
+        $_to = $_to ? $_to : new Tinebase_DateTime();
+
+        // timezone corrections
+        $_from->setTimezone(Tinebase_Core::get(Tinebase_Core::USERTIMEZONE));
+        $_to->setTimezone(Tinebase_Core::get(Tinebase_Core::USERTIMEZONE));
+
+        if($verbose) {
+            echo 'Syncing line ' . $_line->sip_uri . ' from ' . $_from->getIso() . ' to ' . $_to->getIso() . PHP_EOL;
+        }
+
+        try {
+            if(!$this->_apiBackend) {
+                $this->_apiBackend = Sipgate_Backend_Api::getInstance()->connect($_line->account_id, $sipgate_user, $sipgate_pwd);
+            }
+            $response = $this->_apiBackend->getCallHistory($_line->__get('sip_uri'), $_from, $_to, 0, 1000);
+            if(is_array($response['history']) && $response['totalcount'] > 0) {
+                $paging = new Tinebase_Model_Pagination();
+
+                // find already synced entries
+                foreach($response['history'] as $call) {
+                    $entryIds[] = $call['EntryID'];
+                }
+                $filter = new Sipgate_Model_ConnectionFilter(array(), 'AND');
+                $filter->addFilter(new Tinebase_Model_Filter_Id('entry_id', 'in', $entryIds));
+                $result = Sipgate_Controller_Connection::getInstance()->search($filter, $paging, false, false);
+                $oldEntries = array();
+                foreach($result->getIterator() as $connection) {
+                    $oldEntries[] = $connection->entry_id;
+                }
+                unset($result, $connection, $filter);
+                $count = 0;
+                foreach($response['history'] as $call) {
+                    // skip sync if already in db
+                    if(in_array($call['EntryID'], $oldEntries)) {
+                        if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
+                            Tinebase_Core::getLogger()->debug('Skipping call Id' . $call['EntryID'] . '.');
+                        }
+                        continue;
+                    }
+
+                    $localNumber = $this->_getLocalNumber($call['LocalUri']);
+                    $remoteNumber = $this->_getRemoteNumber($call['RemoteUri'], $localNumber, true);
+
+                    $filter = new Addressbook_Model_ContactFilter(array(array("field" => "telephone", "operator" => "contains", "value" => $remoteNumber)));
+                    $s = Addressbook_Controller_Contact::getInstance()->search($filter, $paging);
+
+                    $now = new Tinebase_DateTime();
+                    $connection = new Sipgate_Model_Connection(array(
+                        'tos'           => $call['TOS'],
+                        'entry_id'      => $call['EntryID'],
+                        'local_uri'     => $call['LocalUri'],
+                        'remote_uri'    => $call['RemoteUri'],
+                        'status'        => $call['Status'],
+                        'local_number'  => '+' . $localNumber,
+                        'remote_number' => ($remoteNumber == 'anonymous' ) ? 'anonymous' : '+' . $remoteNumber,
+                        'line_id'       => $_line->getId(),
+                        'timestamp'     => strtotime($call['Timestamp']),
+                        'creation_time' => $now,
+                        // @TODO: also collect accounting info
+                        //                     'tarif'         => $call['TariffName'],
+                        //                     'duration'      => $call['Duration'],
+                        //                     'units_charged' => $call['UnitsCharged'],
+                        //                     'price_unit'    => $call['PricePerUnit']['TotalIncludingVat'],
+                        //                     'price_total'   => $call['Price']['TotalIncludingVat'],
+                        //                     'ticks_a'       => $call['TicksA'],
+                        //                     'ticks_b'       => $call['TicksB'],
+                        'contact_id'    => $s->getFirstRecord() ? $s->getFirstRecord()->getId() : null,
+                        // when contact gets deleted save name
+                        'contact_name'  => $s->getFirstRecord() ? $s->getFirstRecord()->n_fn : '',
+                    ));
+                    $count++;
+                    $this->create($connection);
+                    if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
+                        Tinebase_Core::getLogger()->debug('Creating call Id' . $call['EntryID'] . '.');
+                    }
+                }
+            }
+        } catch (Exception $e) {
+            Tinebase_TransactionManager::getInstance()->rollBack();
+            throw $e;
+        }
+
+        $_to->setTimezone('UTC');
+        $_line->last_sync = $_to;
+        Sipgate_Controller_Line::getInstance()->update($_line);
+
+        Tinebase_TransactionManager::getInstance()->commitTransaction($transactionId);
+
+        if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
+            Tinebase_Core::getLogger()->debug('Synchronizing Line ' . $_line->sip_uri . ' completed. Got ' . $count . ' new connections.');
+        }
+
+        return $count;
+    }
+
+    /**
+     * you can define default filters here
+     * @param Tinebase_Model_Filter_FilterGroup $_filter
+     */
+    protected function _addDefaultFilter(Tinebase_Model_Filter_FilterGroup $_filter = NULL)
+    {
+        $lines = Sipgate_Controller_Line::getInstance()->search(new Sipgate_Model_LineFilter());
+        if($lines->count()) {
+            $aclFilter = new Tinebase_Model_Filter_Text(array('field' => 'line_id', 'operator' => 'in', 'value' => $lines->id));
+            $aclFilter->setIsImplicit(true);
+            $_filter->addFilter($aclFilter);
+        } else {
+            $_filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'entry_id', 'operator' => 'equals', 'value' => 'impossible')));
+        }
+    }
+    
+    /**
+     * returns the local number by the localUri
+     */
+    protected function _getLocalNumber($localUri) {
+        return preg_replace('/\D*/i','', $localUri);
+    }
+
+    /**
+     * returns the remote number by the remoteUri and localUri ()
+     */
+    protected function _getRemoteNumber($remoteUri, $localUri, $localUriIsCleaned = null)
+    {
+        preg_match('/sip:(\d+)(e\d+)?@.*/', $remoteUri, $m);
+
+        if(!$localUriIsCleaned) {
+            $localUri = $this->_getSourceNumber($localUri);
+        }
+
+        if(empty($m)) {
+            // _('anonymous')
+            $remoteNumber = 'anonymous';
+        } elseif($m[2]) {    // called myself
+            $remoteNumber = $localUri;
+        } else {
+            $remoteNumber = str_replace($this->_stripPrefix, '', $m[1]);
+        }
+
+        return $remoteNumber;
+    }
+
+    /**
+     * synchronizes unassigned connections with contacts and clear old assignments
+     * @param Sipgate_Model_Line/Tinebase_Record_RecordSet $_line just work on this line
+     */
+    public function syncContacts($_line = NULL)
+    {
+        $lines = NULL;
+
+        if($_line) {
+            if ($_line instanceof Sipgate_Model_Line) {
+                $lines = new Tinebase_Record_RecordSet('Sipgate_Model_Line', array($_line->toArray()));
+            } elseif ($_line instanceof Tinebase_Record_RecordSet) {
+                $lines = $_line;
+            } else {
+                throw new Tinebase_Exception_InvalidArgument('$_line must be an instance of Tinebase_Record_RecordSet or Sipgate_Model_Line!');
+            }
+        }
+        // remove old assignments
+        $filter = new Sipgate_Model_ConnectionFilter(array());
+        $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'contact_id', 'operator' => 'not', 'value' => NULL)));
+
+        if($lines) {
+            $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'line_id', 'operator' => 'in', 'value' => $lines->id)));
+        }
+
+        $connections = $this->search($filter);
+
+        $contactIds = array_unique($connections->contact_id);
+        $filter = new Addressbook_Model_ContactFilter(array(), 'AND');
+        $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'id', 'operator' => 'in', 'value' => $contactIds)));
+        $contacts = Addressbook_Controller_Contact::getInstance()->search($filter);
+
+        foreach($contactIds as $cid) {
+            $contact = $contacts->filter('id', $cid)->getFirstRecord();
+            $numbers = array_unique($connections->filter('contact_id', $cid)->remote_number);
+
+            if($contact->n_fn != $connection->contact_name || (
+                ! in_array($contact->tel_assistent, $numbers) &&
+                ! in_array($contact->tel_car, $numbers) &&
+                ! in_array($contact->tel_cell, $numbers) &&
+                ! in_array($contact->tel_cell_private, $numbers) &&
+                ! in_array($contact->tel_fax, $numbers) &&
+                ! in_array($contact->tel_fax_home, $numbers) &&
+                ! in_array($contact->tel_home, $numbers) &&
+                ! in_array($contact->tel_other, $numbers) &&
+                ! in_array($contact->tel_pager, $numbers) &&
+                ! in_array($contact->tel_prefer, $numbers) &&
+                ! in_array($contact->tel_work, $numbers)
+            )) {
+                $filter = new Sipgate_Model_ConnectionFilter(array());
+                $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'contact_id', 'operator' => 'equals', 'value' => $cid)));
+                $this->updateMultiple($filter, array('contact_id' => null));
+            }
+        }
+
+        // add new assignments
+        $filter = new Sipgate_Model_ConnectionFilter(array(), 'AND');
+        $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'contact_id', 'operator' => 'equals', 'value' => null)));
+
+        if($lines) {
+            $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'line_id', 'operator' => 'in', 'value' => $lines->id)));
+        }
+
+        $connections = $this->search($filter);
+        $numbers = array_unique($connections->remote_number);
+
+        foreach($numbers as $number) {
+            if($number != 'anonymous') {
+                $filter = new Addressbook_Model_ContactFilter(array(array("field" => "telephone", "operator" => "contains", "value" => $number)));
+                $contact = Addressbook_Controller_Contact::getInstance()->search($filter)->getFirstRecord();
+                if($contact) {
+                    $ids = $connections->filter('remote_number', $number)->id;
+                    $filter = new Sipgate_Model_ConnectionFilter(array(array('field' => 'id', 'operator' => 'in', 'value' => $ids)));
+                    $this->updateMultiple($filter, array('contact_id' => $contact->getId(), 'contact_name' => $contact->n_fn));
+                }
+            }
+        }
+    }
+
+    /**
+     * Syncs all lines for the current user
+     */
+    public function syncLines(Tinebase_DateTime $_from = NULL, Tinebase_DateTime $_to = NULL, $_shared = false, $verbose = false)
+    {
+        $filter = new Sipgate_Model_AccountFilter(array('field' => 'created_by', 'operator' => 'equals', 'value' => $_shared ? NULL : Tinebase_Core::getUser()->getId()));
+        $pag = new Tinebase_Model_Pagination();
+        $accounts = Sipgate_Controller_Account::getInstance()->search($filter, $pag);
+
+        foreach($accounts->getIterator() as $account) {
+            $filter = new Sipgate_Model_ConnectionFilter(array('field' => 'account_id', 'operator' => 'equals', 'value' => $account->getId()));
+            $lines = Sipgate_Controller_Line::getInstance()->search($filter, $pag);
+
+            foreach($lines->getIterator() as $line) {
+                $count = $count + $this->syncLine($line, $_from, $_to, $verbose);
+            }
+        }
+    }
+}
diff --git a/tine20/Sipgate/Controller/Line.php b/tine20/Sipgate/Controller/Line.php
new file mode 100644 (file)
index 0000000..1fda8bb
--- /dev/null
@@ -0,0 +1,308 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Sipgate
+ * @subpackage  Controller
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ *
+ */
+
+/**
+ * contact controller for Sipgate
+ *
+ * @package     Sipgate
+ * @subpackage  Controller
+ */
+class Sipgate_Controller_Line extends Tinebase_Controller_Record_Abstract
+{
+    /**
+     * check for container ACLs
+     *
+     * @var boolean
+     *
+     */
+    protected $_doContainerACLChecks = false;
+
+    /**
+     * do right checks - can be enabled/disabled by _setRightChecks
+     *
+     * @var boolean
+     */
+    protected $_doRightChecks = false;
+
+    /**
+     * the constructor
+     *
+     * don't use the constructor. use the singleton
+     */
+    private function __construct() {
+        $this->_applicationName = 'Sipgate';
+        $this->_modelName = 'Sipgate_Model_Line';
+        $this->_backend = new Sipgate_Backend_Line();
+    }
+
+    /**
+     * don't clone. Use the singleton.
+     */
+    private function __clone()
+    {
+    }
+
+    /**
+     * holds the instance of the singleton
+     *
+     * @var Sipgate_Controller_Line
+     */
+    private static $_instance = NULL;
+
+    /**
+     * the singleton pattern
+     *
+     * @return Sipgate_Controller_Line
+     */
+    public static function getInstance()
+    {
+        if (self::$_instance === NULL) {
+            self::$_instance = new Sipgate_Controller_Line();
+        }
+
+        return self::$_instance;
+    }
+
+    /**
+     * resolves multiple lines
+     * 
+     * @param Tinebase_Record_RecordSet $_records
+     */
+    public function resolveMultipleLines(Tinebase_Record_RecordSet $_records)
+    {
+        $lineIds = array_unique($_records->line_id);
+        $lines = $this->getMultiple($lineIds);
+        foreach ($_records as $record) {
+            $idx = $lines->getIndexById($record->line_id);
+            $record->line_id = $lines[$idx];
+        }
+    }
+
+    /**
+     * Account-Id of the sipgate account
+     * 
+     * @param String $accountId
+     */
+    public function syncAccount($accountId = NULL)
+    {
+        $transactionId = Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
+
+        $account = Sipgate_Controller_Account::getInstance()->getResolved($accountId);
+
+        $ret = Sipgate_Backend_Api::getInstance()->connect($account)->getAllDevices();
+        $be = new Sipgate_Model_Line();
+
+        $createdLines = new Tinebase_Record_RecordSet('Sipgate_Model_Line');
+        $updatedLines = new Tinebase_Record_RecordSet('Sipgate_Model_Line');
+
+        foreach($ret['devices'] as $device) {
+            $filter = new Sipgate_Model_LineFilter(array(array('field' => 'sip_uri', 'operator' => 'equals', 'value' => $device['SipUri'])));
+            $result = $this->search($filter);
+            if($result->count() == 0) {
+                $lineArray = array(
+                    'account_id' => $accountId,
+                    'user_id'    => Tinebase_Core::getUser()->getId(),
+                    'sip_uri'    => $device['SipUri'],
+                    'uri_alias'  => $device['UriAlias'],
+                    'e164_out'   => $device['E164Out'],
+                    'e164_in'    => json_encode($device['E164In']),
+                    'tos'        => $device['TOS'][0],
+                    'creation_time' => time(),
+                    'last_sync' => null
+                );
+
+                $newLine = new Sipgate_Model_Line($lineArray);
+                $newLine = $this->create($newLine);
+                $createdLines->addRecord($newLine);
+            } else {
+                $updLine = $result->getFirstRecord();
+                $updLine->uri_alias = $device['UriAlias'];
+                $updLine->e164_out = $device['E164Out'];
+                $updLine->e164_in  = json_encode($device['E164In']);
+                $updLine->tos = $device['TOS'][0];
+                $updatedLines->addRecord($this->update($updLine));
+            }
+        }
+
+        Tinebase_TransactionManager::getInstance()->commitTransaction($transactionId);
+
+        $updatedAccount = Sipgate_Controller_Account::getInstance()->get($accountId);
+
+        return $updatedAccount;
+    }
+    
+    /**
+     * returns all Lines for the current User
+     */
+    public function getUsableLines() {
+        $filter = new Sipgate_Model_LineFilter(array(array('field' => 'user_id', 'operator' => 'equals', 'value' => Tinebase_Core::getUser()->getId())), 'AND');
+        return $this->search($filter);
+    }
+    
+    /**
+     * Dials a number by the given lineId
+     * 
+     * @param string $lineId
+     * @param string $number
+     * @throws Sipgate_Exception_Backend
+     */
+    public function dialNumber($lineId = NULL, $number = NULL) {
+        $line = $this->_getLineToOperateOn($lineId);
+
+        if(!$number) {
+            throw new Sipgate_Exception('Please use a number!');
+        } elseif(strpos($number,'+') == 0) { // number has already the international format
+            $number = 'sip:' . str_replace('+', '', $number) . '@sipgate.de';
+        } elseif(substr($number, 0, 2) == '00') { // number has the international format with 00 prefixed
+            $number = 'sip:+' . substr($number, 2) . '@sipgate.de';
+        } elseif(strpos($number,'0') == 0) {// number has the national format
+            $pref = new Sipgate_Preference();
+            $number = 'sip:' . $pref->getValue(Sipgate_Preference::INTERNATIONAL_PREFIX) . substr($number, 1) . '@sipgate.de';
+        } else {
+            throw new Sipgate_Exception('The number yout tried to call can not be resolved properly!');
+        }
+
+        return array(
+            'result' => Sipgate_Backend_Api::getInstance()->connect($line->account_id)->dialNumber($line->sip_uri, $number),
+            'line'   => $line
+        );
+    }
+
+    /**
+     * closes session (call)
+     * 
+     * @param string $sessionId
+     * @param array $line
+     */
+    public function closeSession($sessionId, $line)
+    {
+        $line = $this->_getLineToOperateOn($line['data']['id']);
+        return Sipgate_Backend_Api::getInstance()->connect($line->account_id)->closeSession($sessionId);
+    }
+
+    /**
+     * returns the session (call) status
+     * 
+     * @param string $sessionId
+     * @param array $line
+     */
+    public function getSessionStatus($sessionId, $line)
+    {
+        $line = $this->_getLineToOperateOn($line['data']['id']);
+        return Sipgate_Backend_Api::getInstance()->connect($line->account_id)->getSessionStatus($sessionId);
+    }
+
+    /**
+     * sendds an sms
+     * 
+     * @param array $values
+     * @param string $lineId
+     * 
+     * @return array
+     */
+    public function sendMessage($values, $lineId)
+    {
+        $line = $this->get($lineId);
+        $response = Sipgate_Backend_Api::getInstance()->connect($line->account_id)->sendSms($values['own_number'], $values['recipient_number'], $values['message']);
+        $ret = array('success' => false, 'result' => $response, 'values' => $values);
+        
+        if ($response['StatusCode'] == 200) {
+            $ret['success'] = true;
+        }
+        
+        return $ret;
+    }
+
+    /**
+     * returns line by line id and checks if it belongs to the user
+     * 
+     * @param string $lineId
+     * @throws Sipgate_Exception_Backend
+     * 
+     * @return Sipgate_Model_Line
+     */
+    protected function _getLineToOperateOn($lineId)
+    {
+        $line = $this->get($lineId);
+        if(!$line->user_id == Tinebase_Core::getUser()->getId()) {
+            throw new Sipgate_Exception_Backend('You have no access to this line!');
+        }
+        return $line;
+    }
+
+    /**
+     * inspects delete action
+     *
+     * @param array $_ids
+     * @return array of ids to actually delete
+     */
+    protected function _inspectDelete(array $_ids)
+    {
+        if(!is_array($_ids)) {
+            $_ids = array($_ids);
+        }
+
+        $filter = new Sipgate_Model_ConnectionFilter(array(), 'OR');
+
+        foreach($_ids as $id) {
+            $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'line_id', 'operator' => 'equals', 'value' => $id)));
+        }
+        Sipgate_Controller_Connection::getInstance()->deleteByFilter($filter);
+        return $_ids;
+    }
+
+    /**
+     * (non-PHPdoc)
+     * @see Tinebase_Controller_Record_Abstract::_addDefaultFilter()
+     */
+    protected function _addDefaultFilter(Tinebase_Model_Filter_FilterGroup $_filter = NULL)
+    {
+        $manageShared = Tinebase_Core::getUser()->hasRight('Sipgate', Sipgate_Acl_Rights::MANAGE_SHARED_ACCOUNTS);
+        $managePrivate = Tinebase_Core::getUser()->hasRight('Sipgate', Sipgate_Acl_Rights::MANAGE_PRIVATE_ACCOUNTS);
+        $manage = Tinebase_Core::getUser()->hasRight('Sipgate', Sipgate_Acl_Rights::MANAGE_ACCOUNTS);
+
+        $fg = new Sipgate_Model_LineFilter(array(), 'OR');
+
+        // fetch all assignes lines
+        $my = new Tinebase_Model_Filter_Id(
+            array('field' => 'user_id', 'operator' => 'equals', 'value' => Tinebase_Core::getUser()->getId())
+        );
+        $my->setIsImplicit(true);
+        $fg->addFilter($my);
+
+        if($manage) {
+            // fetch all private accounts of the user himself
+            if($managePrivate) {
+                $accountFilter = new Sipgate_Model_AccountFilter(array(), 'AND');
+                $accountFilter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'type', 'operator' => 'equals', 'value' => 'private')));
+                $r = Sipgate_Controller_Account::getInstance()->search($accountFilter);
+                if($r->count()) {
+                    $f = new Tinebase_Model_Filter_Id(array('field' => 'account_id', 'operator' => 'in', 'value' => $r->id));
+                    $f->setIsImplicit(true);
+                    $fg->addFilter($f);
+                }
+            }
+            // fetch shared accounts
+            if($manageShared) {
+                $accountFilter = new Sipgate_Model_AccountFilter(array(), 'AND');
+                $accountFilter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'type', 'operator' => 'equals', 'value' => 'shared')));
+                $r = Sipgate_Controller_Account::getInstance()->searchRightsLess($accountFilter);
+                if($r->count()) {
+                    $f = new Tinebase_Model_Filter_Id(array('field' => 'account_id', 'operator' => 'in', 'value' => $r->id));
+                    $f->setIsImplicit(true);
+                    $fg->addFilter($f);
+                }
+            }
+        }
+        $_filter->addFiltergroup($fg);
+    }
+}
index bbd634d..7dcc3b3 100644 (file)
@@ -1,9 +1,9 @@
 <?php
 /**
  * Tine 2.0
- * 
+ *
  * @package     Sipgate
- * @subpackage    Exception
+ * @subpackage  Exception
  * @license     http://www.gnu.org/licenses/agpl.html AGPL3
  * @author      Alexander Stintzing <alex@stintzing.net>
  * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
@@ -13,7 +13,7 @@
 
 /**
  * Sipgate exception
- * 
+ *
  * @package     Sipgate
  * @subpackage  Exception
  */
diff --git a/tine20/Sipgate/Exception/Authorization.php b/tine20/Sipgate/Exception/Authorization.php
new file mode 100644 (file)
index 0000000..5e3ea3f
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Tine 2.0
+ * 
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @version     $Id: Backend.php 2 2011-04-26 17:27:39Z alex $
+ *
+ */
+
+/**
+ * Backend exception
+ * 
+ * @package     Sipgate
+ * @subpackage  Exception
+ */
+class Sipgate_Exception_Authorization extends Sipgate_Exception
+{
+    /**
+     * construct
+     * 
+     * @param string $_message
+     * @param integer $_code
+     * @return void
+     */
+    public function __construct($_message = 'Could not authenticate to sipgate.', $_code = 952) {
+        // _('Could not authenticate to sipgate.')
+        parent::__construct($_message, $_code);
+    }
+}
+
+?>
\ No newline at end of file
index 15b576a..b939a78 100644 (file)
  */
 class Sipgate_Exception_Backend extends Sipgate_Exception
 {
+    /**
+     * construct
+     * 
+     * @param string $_message
+     * @param integer $_code
+     * @return void
+     */
+    public function __construct($_message = 'General Backend Exception.', $_code = 950) {
+        // _('General Backend Exception.')
+        parent::__construct($_message, $_code);
+    }
 }
 
 ?>
\ No newline at end of file
diff --git a/tine20/Sipgate/Exception/MissingConfig.php b/tine20/Sipgate/Exception/MissingConfig.php
new file mode 100644 (file)
index 0000000..ebf59e7
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Tine 2.0
+ * 
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @version     $Id: Backend.php 2 2011-04-26 17:27:39Z alex $
+ *
+ */
+
+/**
+ * Backend exception
+ * 
+ * @package     Sipgate
+ * @subpackage  Exception
+ */
+class Sipgate_Exception_MissingConfig extends Sipgate_Exception
+{
+    /**
+     * construct
+     * 
+     * @param string $_message
+     * @param integer $_code
+     * @return void
+     */
+    public function __construct($_message = 'The sipgate configuration is missing.', $_code = 954) {
+        // _('The configuration is missing.')
+        parent::__construct($_message, $_code);
+    }
+}
+
+?>
\ No newline at end of file
diff --git a/tine20/Sipgate/Exception/NoConnection.php b/tine20/Sipgate/Exception/NoConnection.php
new file mode 100644 (file)
index 0000000..f90816e
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Tine 2.0
+ * 
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @version     $Id: Backend.php 2 2011-04-26 17:27:39Z alex $
+ *
+ */
+
+/**
+ * Backend exception
+ * 
+ * @package     Sipgate
+ * @subpackage  Exception
+ */
+class Sipgate_Exception_NoConnection extends Sipgate_Exception
+{
+    /**
+     * construct
+     * 
+     * @param string $_message
+     * @param integer $_code
+     * @return void
+     */
+    public function __construct($_message = 'Could not connect to sipgate.', $_code = 951) {
+        // _('Could not connect to sipgate.')
+        parent::__construct($_message, $_code);
+    }
+}
+
+?>
\ No newline at end of file
diff --git a/tine20/Sipgate/Exception/ResolveCredentials.php b/tine20/Sipgate/Exception/ResolveCredentials.php
new file mode 100644 (file)
index 0000000..de4d6d5
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Tine 2.0
+ * 
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @version     $Id: Backend.php 2 2011-04-26 17:27:39Z alex $
+ *
+ */
+
+/**
+ * Backend exception
+ * 
+ * @package     Sipgate
+ * @subpackage  Exception
+ */
+class Sipgate_Exception_ResolveCredentials extends Sipgate_Exception
+{
+    /**
+     * construct
+     * 
+     * @param string $_message
+     * @param integer $_code
+     * @return void
+     */
+    public function __construct($_message = 'Could not resolve account settings.', $_code = 953) {
+        // _('Could not resolve account settings.')
+        parent::__construct($_message, $_code);
+    }
+}
+
+?>
\ No newline at end of file
diff --git a/tine20/Sipgate/Frontend/Cli.php b/tine20/Sipgate/Frontend/Cli.php
new file mode 100644 (file)
index 0000000..d0cf772
--- /dev/null
@@ -0,0 +1,166 @@
+<?php
+/**
+ * Tine 2.0
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+
+/**
+ * cli server for Sipgate
+ *
+ * This class handles cli requests for the Sipgate
+ *
+ * @package     Sipgate
+ */
+class Sipgate_Frontend_Cli extends Tinebase_Frontend_Cli_Abstract
+{
+    /**
+     * the internal name of the application
+     *
+     * @var string
+     */
+    protected $_applicationName = 'Sipgate';
+
+    /**
+     * import config filename
+     *
+     * @var string
+     */
+    protected $_configFilename = 'importconfig.inc.php';
+
+    /**
+     * help array with function names and param descriptions
+     */
+    protected $_help = array(
+        'sync_connections' => array(
+            'description'   => 'Synchronizes the connections.',
+            'params'        => array(
+                'line_id'   => 'Line-ID if just this line should be synced',
+                'initial'   => 'If set, the last 3 months are synced',
+                'shared'    => 'Sync shared accounts. If not set, the accounts created by the calling user are synced.',
+                'verbose'   => 'Shows more information.'
+            )
+        ),
+        'take_config' => array(
+            'description' => 'Takes the config from config.inc.php and creates an account with the associated lines. An initial connection sync is also done.',
+            'params'        => array(
+                'shared'    => 'The created account is a shared one. Without this argument, a private account is created.'
+                )
+        ),
+        'sync_contacts' => array(
+            'description' => 'Synchronizes unassigned connections with contacts and clear old assignments (if contact is deleted).',
+        )
+    );
+    
+    /**
+     * Takes the config from config.inc.php and creates an account with the associated lines
+     * @param Zend_Console_Getopt $_opts 
+     */
+    public function take_config($_opts)
+    {
+        // resolve arguments
+        $args = $this->_parseArgs($_opts, array());
+        
+        $type  = (in_array('shared',  $args['other'])) ? 'shared' : 'private';
+        
+        if (@isset(Tinebase_Core::getConfig()->sipgate)) {
+            $conf = Tinebase_Core::getConfig()->sipgate;
+            if(@isset($conf->api_username) && @isset($conf->api_password)) {
+                echo 'Validate configuration from config.inc.php...' . PHP_EOL;
+                $accountData = array('data' => array(
+                    'accounttype' => (@isset($conf->api_url) && ($conf->api_url != 'https://samurai.sipgate.net/RPC2')) ? 'team' : 'plus',
+                    'description' => 'Created by update',
+                    'username' => $conf->api_username,
+                    'password' => $conf->api_password,
+                    'type' => $type,
+                ));
+                if(Sipgate_Controller_Account::getInstance()->validateAccount($accountData)) {
+                    echo 'Data from config.inc.php could be validated, creating account...' . PHP_EOL;
+                    try {
+                        $account = Sipgate_Controller_Account::getInstance()->create(new Sipgate_Model_Account($accountData['data']));
+                    } catch(Tinebase_Exception_Duplicate $e) {
+                        echo 'An account with this credentials exists already! Did you use this script twice?' . PHP_EOL;
+                        die();
+                    }
+                    
+                    if($account) {
+                        echo 'Account created. Trying to synchronize the lines..' . PHP_EOL;
+                        if(Sipgate_Controller_Line::getInstance()->syncAccount($account->getId())) {
+                            $opts = new Zend_Console_Getopt('abp:');
+                            $args = array('initial', 'verbose');
+                            
+                            if($type == 'shared') {
+                                $args[] = 'shared';
+                            }
+                            
+                            $opts->setArguments($args);
+                            
+                            echo 'Lines have been synchronized. Now syncing connections from the last two months, day per day. This could take some time.' . PHP_EOL;
+                            $this->sync_connections($opts);
+                            echo 'Connections has been synchronized. Now assign users to the line(s) to allow them to use the line(s)' . PHP_EOL;
+                            echo 'READY!' . PHP_EOL;
+                            
+                        } else {
+                            echo 'The lines for the account could not be created!' . PHP_EOL;
+                        }
+                    } else {
+                        echo 'The account could not be created!' . PHP_EOL;
+                    }
+                } else {
+                    echo 'The credentials found in config.inc.php could not be validated!' . PHP_EOL;
+                }
+            } else {
+                echo 'No username or password could be found in config.php.inc!' . PHP_EOL;
+            }
+        } else {
+            echo 'No sipgate config could be found in config.php.inc!' . PHP_EOL;
+        }
+    }
+
+    /**
+     * syncs all connections for the current user
+     * @param Zend_Console_Getopt $_opts
+     */
+    public function sync_connections($_opts)
+    {
+
+        // resolve arguments
+        $args = $this->_parseArgs($_opts, array());
+        
+        $initial = (in_array('initial', $args['other'])) ? true : false;
+        $shared  = (in_array('shared',  $args['other'])) ? true : false;
+        $verbose  = (in_array('verbose',  $args['other'])) ? true : false;
+
+        if($initial) {    // sync last 2 months, day per day
+            // prepare dates
+            $now = new Tinebase_DateTime();
+            $now->setTime(0,0,0);
+
+            $from = clone $now;
+            $from->subDay(1);
+
+            $to = clone $now;
+
+            $firstDay = clone $now;
+            $firstDay->subMonth(2);
+
+            // sync every day
+            while(! $firstDay->isLater($from)) {
+                Sipgate_Controller_Connection::getInstance()->syncLines($from, $to, $shared, $verbose);
+                $from->subDay(1);
+                $to->subDay(1);
+            }
+        } else {
+            Sipgate_Controller_Connection::getInstance()->syncLines(NULL, NULL, $shared);
+        }
+    }
+    /**
+     * assign contacts to calls without assignment, reassign if contact has changed
+     */
+    public function sync_contacts()
+    {
+        $connections = Sipgate_Controller_Connection::getInstance()->syncContacts();
+    }
+}
\ No newline at end of file
index 85c0105..8212da4 100644 (file)
@@ -5,9 +5,7 @@
  * @package     Sipgate
  * @license     http://www.gnu.org/licenses/agpl.html AGPL3
  * @author      Alexander Stintzing <alex@stintzing.net>
- * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
- * @version     $Id: Json.php 26 2011-05-03 01:42:01Z alex $
- *
+ * @copyright   Copyright (c) 2011-2012 Metaways Infosystems GmbH (http://www.metaways.de)
  */
 
 /**
  */
 class Sipgate_Frontend_Json extends Tinebase_Frontend_Json_Abstract
 {
+    protected $_resolveUserFields = array(
+        'Sipgate_Model_Account' => array('created_by', 'last_modified_by', 'deleted_by'),
+        'Sipgate_Model_Line'    => array('user_id')
+    );
+    /**
+     * the line controller
+     * @var Sipgate_Controller_Line
+     */
+    protected $_lineController = NULL;
+
+    /**
+     * the account controller
+     * @var Sipgate_Controller_Account
+     */
+    protected $_accountController = NULL;
+
+    /**
+     * the connection controller
+     * @var Sipgate_Controller_Connection
+     */
+    protected $_connectionController = NULL;
 
     /**
      * app name
@@ -28,171 +47,270 @@ class Sipgate_Frontend_Json extends Tinebase_Frontend_Json_Abstract
     protected $_applicationName = 'Sipgate';
 
     /**
-     * dial number
+     * the constructor
      *
-     * @param  String $_number phone number
-     * @return Array
      */
-    public function dialNumber($_number) {
-        $_number = 'sip:'.preg_replace('/\+/','',$_number).'@sipgate.net';
-        $resp = Sipgate_Controller::getInstance()->dialNumber($_number);
-        if($resp['StatusCode'] === 200) {
-            $ret = array('success' => true,'state' => $resp);
-        }
-        else {
-            $ret = array('error' => true,'response' => $resp);
-        }
-        return $ret;
+    public function __construct()
+    {
     }
 
     /**
+     * Return a single record
      *
-     * returns the Call History of the uri
-     * @param String $_sipUri
-     * @param Integer $_start
-     * @param Integer $_stop
-     * @param Integer $_pstart
-     * @param Integer $_plimit
+     * @param   string $id
+     * @return  array record data
      */
+    public function getAccount($id)
+    {
+        return $this->_get($id, Sipgate_Controller_Account::getInstance());
+    }
 
-    public function getCallHistory($_sipUri, $_start, $_stop, $_pstart = 0, $_plimit = 20) {
-
-        if(empty($_sipUri)) throw new Sipgate_Exception('Sip-Uri leer!');
-        if($_sipUri == 'root') return array();
+    /**
+     * creates/updates a record
+     *
+     * @param  array $recordData
+     * @return array created/updated record
+     */
+    public function saveAccount($recordData)
+    {
+        return $this->_save($recordData, Sipgate_Controller_Account::getInstance(), 'Account');
+    }
 
-        // Kein Plan, wo die Vorwahlen herkommen:
-        $stripPrefix = array('sip:2300','sip:2301','sip:2400','sip:','@sipgate.net','anonymous');
-        $stripRepl = array('','','','','');
+    /**
+     * validates a account
+     *
+     * @param  array $account
+     * @return array created/updated record
+     */
+    public function validateAccount($account)
+    {
+        return array('result' => array('success' => Sipgate_Controller_Account::getInstance()->validateAccount($account)));
+    }
 
-        $paging = array("start" => 0, "limit" => 1);
-        $ret = array();
-        $history = Sipgate_Controller::getInstance()->getCallHistory($_sipUri, $_start, $_stop, $_pstart, $_plimit);
-        if($history['totalcount'] > 0) {
-            foreach($history['items'] as &$hEntry) {
-                $rUri = str_replace($stripPrefix,$stripRepl,$hEntry['RemoteUri']);
-                $hEntry['Timestamp'] = strtotime($hEntry['Timestamp']);
-                $hEntry['LocalNumber'] = '+' . preg_replace('/\D*/i','',$hEntry['LocalUri']);
-                $filter = array(array("field" => "telephone","operator" => "contains","value" => $rUri));
-                $s = $this->_search($filter, $paging, Addressbook_Controller_Contact::getInstance(), 'Addressbook_Model_ContactFilter');
+    /**
+     * sends a message
+     * @param unknown_type $values
+     * @param unknown_type $lineId
+     */
+    public function sendMessage($values, $lineId) {
+        return Sipgate_Controller_Line::getInstance()->sendMessage($values, $lineId);
+    }
 
-                if($s['totalcount'] === '1') {
-                    $hEntry['RemoteParty'] = $s['results'][0]['n_fn'] . ' ( +' . $rUri . ' )';
-                    $hEntry['RemoteRecord'] = $s['results'][0];
-                }
-                else {
-                    if(empty($rUri)) $hEntry['RemoteParty'] = 'unknown';
-                    else $hEntry['RemoteParty'] = '+' . $rUri;
-                    $hEntry['RemoteRecord'] = false;
-                }
-                if(empty($rUri)) $hEntry['RemoteNumber'] = 'unknown';
-                else $hEntry['RemoteNumber'] = '+' . $rUri;
+    /**
+     * synchronizes the lines of an account
+     * @param string $accountId
+     */
+    public function syncLines($accountId) {
+        return $this->_recordToJson(Sipgate_Controller_Line::getInstance()->syncAccount($accountId));
+    }
 
-            }
-            $ret = &$history;
+    /**
+     * deletes existing records
+     *
+     * @param  array $ids
+     * @return string
+     */
+    public function deleteAccounts($ids)
+    {
+        return $this->_delete($ids, Sipgate_Controller_Account::getInstance());
+    }
 
+    /**
+     * Search for records matching given arguments
+     *
+     * @param  array $filter
+     * @param  array $paging
+     * @return array
+     */
+    public function searchAccounts($filter, $paging)
+    {
+        return $this->_search($filter, $paging, Sipgate_Controller_Account::getInstance(), 'Sipgate_Model_AccountFilter');
+    }
 
+    /**
+     * Return a single record
+     *
+     * @param   string $id
+     * @return  array record data
+     */
+    public function getConnection($id)
+    {
+        return $this->_get($id, Sipgate_Controller_Connection::getInstance());
+    }
 
-        }
+    /**
+     * Search for records matching given arguments
+     *
+     * @param  array $filter
+     * @param  array $paging
+     * @return array
+     */
+    public function searchConnections($filter, $paging)
+    {
+        return $this->_search($filter, $paging, Sipgate_Controller_Connection::getInstance(), 'Sipgate_Model_ConnectionFilter');
+    }
 
-        return $ret;
+    /**
+     * Return a single record
+     *
+     * @param   string $id
+     * @return  array record data
+     */
+    public function getLine($id)
+    {
+        return $this->_get($id, Sipgate_Controller_Line::getInstance());
     }
 
+    public function saveLine($recordData)
+    {
+        return $this->_save($recordData, Sipgate_Controller_Line::getInstance(), 'Line');
+    }
 
     /**
-     * send SMS
+     * Search for records matching given arguments
      *
-     * @param  int    $_number  phone number
-     * @param  int    $_content the content
+     * @param  array $filter
+     * @param  array $paging
      * @return array
      */
-    public function sendSms($_number,$_content)    {
+    public function searchLines($filter, $paging)
+    {
+        return $this->_search($filter, $paging, Sipgate_Controller_Line::getInstance(), 'Sipgate_Model_LineFilter', false);
+    }
 
-        //        $resp['responseText'] = '"response":{"StatusCode":200,"SessionID":"","StatusString":"Method success"}';
+    /**
+     * synchronizes the connections and the associated contacts for one or more lines
+     * @param array $lines
+     */
+    public function syncConnections($lines)
+    {
+        if(is_array($lines) && count($lines)>0) {
+            foreach($lines as $line) {
+                $ids[] = $line['id'];
+            }
+        }
+
+        $results = array();
+        $paging = new Tinebase_Model_Pagination();
+        $filter = new Sipgate_Model_LineFilter(array('AND', array()));
+        $filter->addFilter(new Tinebase_Model_Filter_Id('id', 'in', $ids));
+        $lines = Sipgate_Controller_Line::getInstance()->search($filter);
 
-        if(($resp = Sipgate_Controller::getInstance()->sendSms($_number,$_content)))
-            return array('success' => true,'response'  => $resp);
-        return array('success' => false,'response'  => $resp);
+        $totalcount = 0;
+        if($lines->count()) {
+            $scc = Sipgate_Controller_Connection::getInstance();
+            
+            $scc->syncContacts($lines);
+            
+            foreach($lines as $line) {
+                $count = $scc->syncLine($line);
+                $totalcount += $count;
+                $results[$line->getId()] = $count;
+            }
+        }
+        return array('success' => true, 'results' => $results, 'totalcount' => $totalcount);
     }
 
     /**
-     * @return array
+     * returns record prepared for json transport
+     *
+     * @param Tinebase_Record_Interface $_record
+     * @return array record data
      */
-    public function getPhoneDevices() {
-        $phones = Sipgate_Controller::getInstance()->getPhoneDevices();
-        if($phones) {
-            $ret = array('success' => true,'phones' => $phones);
-        }
-        else {
-            $ret = array('success' => false);
+    protected function _recordToJson($_record)
+    {
+        switch (get_class($_record)) {
+            case 'Sipgate_Model_Account':
+                $filter = new Sipgate_Model_LineFilter(array(), 'AND');
+                $filter->addFilter(new Tinebase_Model_Filter_Id(array('field' => 'account_id', 'operator' => 'equals', 'value' => $_record->id)));
+                $_record->lines = $this->_multipleRecordsToJson(Sipgate_Controller_Line::getInstance()->search($filter));
+                break;
+            case 'Sipgate_Model_Line':
+                Tinebase_User::getInstance()->resolveUsers($_record, $this->_resolveUserFields['Sipgate_Model_Line']);
+                $_record->account_id = Sipgate_Controller_Account::getInstance()->get($_record->account_id);
+                break;
         }
-        return $ret;
 
+        return parent::_recordToJson($_record);
     }
+
     /**
-     * @return array
+     * returns multiple records prepared for json transport
+     *
+     * @param Tinebase_Record_RecordSet $_records Tinebase_Record_Abstract
+     * @param Tinebase_Model_Filter_FilterGroup $_filter
+     * @param Tinebase_Model_Pagination $_pagination
+     * @return array data
      */
-    public function getFaxDevices() {
-        $faxes = Sipgate_Controller::getInstance()->getFaxDevices();
-        if($faxes) {
-            $ret = array('success' => true,'phones' => &$faxes);
+    protected function _multipleRecordsToJson(Tinebase_Record_RecordSet $_records, $_filter = NULL, $_pagination = null)
+    {
+        switch ($_records->getRecordClassName()) {
+            case 'Sipgate_Model_Connection':
+                Sipgate_Controller_Line::getInstance()->resolveMultipleLines($_records);
+                $this->_resolveMultipleContacts($_records);
+                break;
+            case 'Sipgate_Model_Line':
+                Sipgate_Controller_Account::getInstance()->resolveMultipleAccounts($_records);
+                Tinebase_User::getInstance()->resolveMultipleUsers($_records, $this->_resolveUserFields['Sipgate_Model_Line']);
+                break;
         }
-        else {
-            $ret = array('error' => true);
+        return parent::_multipleRecordsToJson($_records);
+    }
+
+    /**
+     * resolves mc
+     * @param Tinebase_Record_RecordSet $_records
+     */
+    protected function _resolveMultipleContacts(Tinebase_Record_RecordSet $_records)
+    {
+        $contactIds = array_unique($_records->contact_id);
+        $contacts = Addressbook_Controller_Contact::getInstance()->getMultiple($contactIds);
+        foreach ($_records as $record) {
+            $idx = $contacts->getIndexById($record->contact_id);
+            if($idx) {
+                $record->contact_id = $contacts[$idx];
+            } else {
+                $record->contact_id = NULL;
+            }
         }
-        return $ret;
     }
 
     /**
-     * get Session Status
+     * dial number
      *
-     * @param  string $sessionId
-     * @return array
+     * @param String $lineId line id
+     * @param String $number phone number
+     * @return Array
      */
-    public function getSessionStatus($sessionId) {
-        if(empty($sessionId)) throw new Sipgate_Exception('No Session-Id in JSON-Frontend submitted!');
-
-        if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug('getting Status ' . $sessionId);
-
-        return Sipgate_Controller::getInstance()->getSessionStatus($sessionId);
+    public function dialNumber($lineId = NULL, $number = NULL) {
+        $ret = Sipgate_Controller_Line::getInstance()->dialNumber($lineId, $number);
+        $ret['line'] = $this->_recordToJson($ret['line']);
+        return $ret;
     }
 
     /**
      * close Session
      *
      * @param string $sessionId
+     * @param array $line
      * @return array
      */
-
-    public function closeSession($sessionId) {
-        if(empty($sessionId)) throw new Sipgate_Exception('No Session-Id in JSON-Frontend submitted!');
-        return Sipgate_Controller::getInstance()->closeSession($sessionId);
+    public function closeSession($sessionId, $line) {
+        return Sipgate_Controller_Line::getInstance()->closeSession($sessionId, $line);
     }
 
     /**
-     * Returns registry data
+     * get Session Status
      *
-     * @return mixed array 'variable name' => 'data'
+     * @param string $sessionId
+     * @param array $line
+     * @return array
      */
-    public function getRegistryData()
-    {
-        try {
-            $phoneId = Tinebase_Core::getPreference($this->_applicationName)->getValue(Sipgate_Preference::PHONEID);
-            $faxId = Tinebase_Core::getPreference($this->_applicationName)->getValue(Sipgate_Preference::FAXID);
-            $mobileNumber = Tinebase_Core::getPreference($this->_applicationName)->getValue(Sipgate_Preference::MOBILENUMBER);
-            $devices = Sipgate_Controller::getInstance()->getAllDevices();
-        } catch (Sipgate_Exception_Backend $seb) {
-            Tinebase_Core::getLogger()->warn(__METHOD__ . ' (' . __LINE__ . ') Could not get Sipgate registry data: ' . $seb->getMessage());
-            return array();
-        } catch (Zend_Exception $ze) {
-            Tinebase_Core::getLogger()->warn(__METHOD__ . ' (' . __LINE__ . ') Could not connect to sipgate: ' . $ze->getMessage());
-            return array();
+    public function getSessionStatus($sessionId, $line) {
+        if(empty($sessionId)) {
+            throw new Sipgate_Exception('You have to submit a valid Session-ID!');
         }
-
-        return array(
-            'phoneId' => $phoneId,
-            'faxId' => $faxId,
-            'mobileNumber' => $mobileNumber,
-            'Devices' => $devices
-        );
+        if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug('getting Status ' . $sessionId);
+        return Sipgate_Controller_Line::getInstance()->getSessionStatus($sessionId, $line);
     }
 }
diff --git a/tine20/Sipgate/Model/Account.php b/tine20/Sipgate/Model/Account.php
new file mode 100644 (file)
index 0000000..0641ed9
--- /dev/null
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Sipgate
+ * @subpackage  Record
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ */
+
+/**
+ * class Sipgate_Model_Account
+ *
+ * @package     Sipgate
+ * @subpackage  Record
+ */
+class Sipgate_Model_Account extends Tinebase_Record_Abstract
+{
+    /**
+     * identifier
+     *
+     * @var string
+     */
+    protected $_identifier = 'id';
+
+    /**
+     * application the record belongs to
+     *
+     * @var string
+     */
+    protected $_application = 'Sipgate';
+
+    /**
+     * record validators
+     *
+     * @var array
+     */
+    protected $_validators = array(
+        'id'               => array('allowEmpty' => true),
+        'description'      => array('allowEmpty' => false),
+        'credential_id'    => array('allowEmpty' => true),
+        'accounttype'      => array('allowEmpty' => false),
+        'type'      => array('allowEmpty' => false),
+        'username'         => array('allowEmpty'  => true),
+        'password'         => array('allowEmpty'  => true),
+        'is_valid'         => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'mobile_number'    => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+
+        'created_by'            => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'creation_time'         => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'last_modified_by'      => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'last_modified_time'    => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'is_deleted'            => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'deleted_time'          => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'deleted_by'            => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        
+        // appended on the fly
+        
+        'lines'    => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+    );
+
+    /**
+     * name of fields containing datetime or or an array of datetime
+     * information
+     *
+     * @var array list of datetime fields
+     */
+    protected $_datetimeFields = array(
+        'creation_time',
+        'last_modified_time',
+        'deleted_time'
+    );
+}
diff --git a/tine20/Sipgate/Model/AccountAccountType.php b/tine20/Sipgate/Model/AccountAccountType.php
new file mode 100644 (file)
index 0000000..7ad2c64
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Sipgate
+ * @subpackage  Model
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ *
+ */
+
+/**
+ * Project AccountAccountType Record Class
+ *
+ * @package     Sipgate
+ * @subpackage  Model
+ */
+class Sipgate_Model_AccountAccountType extends Tinebase_Config_KeyFieldRecord
+{
+    /**
+     * application the record belongs to
+     *
+     * @var string
+     */
+    protected $_application = 'Sipgate';
+}
diff --git a/tine20/Sipgate/Model/AccountFilter.php b/tine20/Sipgate/Model/AccountFilter.php
new file mode 100644 (file)
index 0000000..1251234
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+/**
+ * Tine 2.0
+ * 
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ *
+ */
+
+/**
+ * Account filter Class
+ * @package     Sipgate
+ */
+class Sipgate_Model_AccountFilter extends Tinebase_Model_Filter_FilterGroup
+{
+    /**
+     * @var string class name of this filter group
+     *      this is needed to overcome the static late binding
+     *      limitation in php < 5.3
+     */
+    protected $_className = 'Sipgate_Model_AccountFilter';
+    
+    /**
+     * @var string application of this filter group
+     */
+    protected $_applicationName = 'Sipgate';
+    
+    /**
+     * @var string name of model this filter group is designed for
+     */
+    protected $_modelName = 'Sipgate_Model_Account';
+    
+    /**
+     * @var array filter model fieldName => definition
+     */
+    protected $_filterModel = array(
+        'id'          => array('filter' => 'Tinebase_Model_Filter_Id', 'options' => array('controller' => 'Sipgate_Controller_Account', 'modelName' => 'Sipgate_Model_Account')),
+        'description' => array('filter' => 'Tinebase_Model_Filter_Text'),
+        'type'        => array('filter' => 'Tinebase_Model_Filter_Text'),
+        'account_type'        => array('filter' => 'Tinebase_Model_Filter_Text'),#
+        'mobile_number'        => array('filter' => 'Tinebase_Model_Filter_Text'),
+        'created_by'  => array('filter' => 'Tinebase_Model_Filter_User')
+    );
+}
diff --git a/tine20/Sipgate/Model/AccountType.php b/tine20/Sipgate/Model/AccountType.php
new file mode 100644 (file)
index 0000000..248c272
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Sipgate
+ * @subpackage  Model
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ *
+ */
+
+/**
+ * Project AccountType Record Class
+ *
+ * @package     Sipgate
+ * @subpackage  Model
+ */
+class Sipgate_Model_AccountType extends Tinebase_Config_KeyFieldRecord
+{
+    /**
+     * application the record belongs to
+     *
+     * @var string
+     */
+    protected $_application = 'Sipgate';
+}
diff --git a/tine20/Sipgate/Model/Connection.php b/tine20/Sipgate/Model/Connection.php
new file mode 100644 (file)
index 0000000..498d75f
--- /dev/null
@@ -0,0 +1,106 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+
+/**
+ * class to hold contact data
+ *
+ * @package     Sipgate
+ */
+class Sipgate_Model_Connection extends Tinebase_Record_Abstract
+{
+    /**
+     * const to describe contact of current account id independent
+     *
+     * @var string
+     */
+    const CURRENTCONTACT = 'currentContact';
+
+    /**
+     * contact type: contact
+     *
+     * @var string
+     */
+    const CONTACTTYPE_CONTACT = 'contact';
+
+    /**
+     * contact type: user
+     *
+     * @var string
+     */
+    const CONTACTTYPE_USER = 'user';
+
+    /**
+     * key in $_validators/$_properties array for the filed which
+     * represents the identifier
+     *
+     * @var string
+     */
+    protected $_identifier = 'id';
+
+    /**
+     * application the record belongs to
+     *
+     * @var string
+     */
+    protected $_application = 'Sipgate';
+
+    /**
+     * list of zend inputfilter
+     *
+     * this filter get used when validating user generated content with Zend_Input_Filter
+     *
+     * @var array
+     */
+    protected $_filters = array(
+
+    );
+
+    /**
+     * list of zend validator
+     *
+     * this validators get used when validating user generated content with Zend_Input_Filter
+     *
+     * @var array
+     */
+    protected $_validators = array(
+        'id'            => array('allowEmpty' => true),
+        'entry_id'      => array('allowEmpty' => true),
+        'status'        => array('allowEmpty' => true),
+        'tos'           => array('allowEmpty' => true),
+        'local_uri'     => array('allowEmpty' => true),
+        'remote_uri'    => array('allowEmpty' => true),
+        'line_id'       => array('allowEmpty' => true),
+        'timestamp'     => array('allowEmpty' => true),
+        'creation_time' => array('allowEmpty' => true),
+        'tarif'         => array('allowEmpty' => true),
+        'duration'      => array('allowEmpty' => true),
+        'units_charged' => array('allowEmpty' => true),
+        'price_unit'    => array('allowEmpty' => true),
+        'price_total'   => array('allowEmpty' => true),
+        'ticks_a'       => array('allowEmpty' => true),
+        'ticks_b'       => array('allowEmpty' => true),
+        'contact_id'    => array('allowEmpty' => true),
+        'contact_name'    => array('allowEmpty' => true),
+        'local_number'  => array('allowEmpty' => true),
+        'remote_number' => array('allowEmpty' => true),
+    );
+
+    /**
+     * name of fields containing datetime or or an array of datetime information
+     *
+     * @var array list of datetime fields
+     */
+    protected $_datetimeFields = array(
+        'timestamp',
+        'creation_time',
+    );
+
+
+}
diff --git a/tine20/Sipgate/Model/ConnectionFilter.php b/tine20/Sipgate/Model/ConnectionFilter.php
new file mode 100644 (file)
index 0000000..848469f
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+/**
+ * Tine 2.0
+ * 
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ *
+ */
+
+/**
+ * Connection filter Class
+ * @package     Sipgate
+ */
+class Sipgate_Model_ConnectionFilter extends Tinebase_Model_Filter_FilterGroup
+{
+    /**
+     * @var string class name of this filter group
+     *      this is needed to overcome the static late binding
+     *      limitation in php < 5.3
+     */
+    protected $_className = 'Sipgate_Model_ConnectionFilter';
+    
+    /**
+     * @var string application of this filter group
+     */
+    protected $_applicationName = 'Sipgate';
+    
+    /**
+     * @var string name of model this filter group is designed for
+     */
+    protected $_modelName = 'Sipgate_Model_Connection';
+    
+    /**
+     * @var array filter model fieldName => definition
+     */
+    protected $_filterModel = array(
+        'query'                => array('filter' => 'Tinebase_Model_Filter_Query', 'options' => array('fields' => array('local_number', 'remote_number', 'contact_name'))),
+        'contact_id'           => array('filter' => 'Addressbook_Model_ContactIdFilter'),
+        'line_id'  => array('filter' => 'Tinebase_Model_Filter_ForeignId',
+            'options' => array(
+                'filtergroup'       => 'Sipgate_Model_LineFilter',
+                'controller'        => 'Sipgate_Controller_Line',
+           )
+        ),
+        'entry_id'  => array('filter' => 'Tinebase_Model_Filter_Text'),
+        'status'    => array('filter' => 'Tinebase_Model_Filter_Text'),
+        'tos'       => array('filter' => 'Tinebase_Model_Filter_Text'),
+        'id'        => array(
+            'filter' => 'Tinebase_Model_Filter_Id', 
+            'options' => array(
+                'modelName'  => 'Sipgate_Model_Connection',
+                'controller' => 'Sipgate_Controller_Connection',
+                )
+            ),
+    );
+}
diff --git a/tine20/Sipgate/Model/ConnectionStatus.php b/tine20/Sipgate/Model/ConnectionStatus.php
new file mode 100644 (file)
index 0000000..eac00b7
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Sipgate
+ * @subpackage  Model
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ *
+ */
+
+/**
+ * Project ConnectionStatus Record Class
+ *
+ * @package     Sipgate
+ * @subpackage  Model
+ */
+class Sipgate_Model_ConnectionStatus extends Tinebase_Config_KeyFieldRecord
+{
+    /**
+     * application the record belongs to
+     *
+     * @var string
+     */
+    protected $_application = 'Sipgate';
+}
diff --git a/tine20/Sipgate/Model/ConnectionTos.php b/tine20/Sipgate/Model/ConnectionTos.php
new file mode 100644 (file)
index 0000000..1412e5e
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Sipgate
+ * @subpackage  Model
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ *
+ */
+
+/**
+ * Project ConnectionTos Record Class
+ *
+ * @package     Sipgate
+ * @subpackage  Model
+ */
+class Sipgate_Model_ConnectionTos extends Tinebase_Config_KeyFieldRecord
+{
+    /**
+     * application the record belongs to
+     *
+     * @var string
+     */
+    protected $_application = 'Sipgate';
+}
\ No newline at end of file
diff --git a/tine20/Sipgate/Model/Line.php b/tine20/Sipgate/Model/Line.php
new file mode 100644 (file)
index 0000000..8fc52c9
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+
+/**
+ * class to hold contact data
+ *
+ * @property   account_id      id of associated user
+ * @property   email           the email address of the contact
+ * @property   n_family
+ * @property   n_fileas        display name
+ * @property   n_fn            the full name
+ * @property   n_given
+ * @property   type            type of contact
+ * @package     Sipgate
+ */
+class Sipgate_Model_Line extends Tinebase_Record_Abstract
+{
+
+    /**
+     * key in $_validators/$_properties array for the filed which
+     * represents the identifier
+     *
+     * @var string
+     */
+    protected $_identifier = 'id';
+
+    /**
+     * application the record belongs to
+     *
+     * @var string
+     */
+    protected $_application = 'Sipgate';
+
+    /**
+     * list of zend validator
+     *
+     * this validators get used when validating user generated content with Zend_Input_Filter
+     *
+     * @var array
+     */
+    protected $_validators = array(
+        'id'                    => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => NULL),
+        'account_id'            => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'user_id'               => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'uri_alias'             => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'sip_uri'               => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'tos'                   => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'e164_in'               => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'e164_out'              => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'creation_time'         => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'last_sync'             => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+    );
+
+    /**
+     * name of fields containing datetime or or an array of datetime information
+     *
+     * @var array list of datetime fields
+     */
+    protected $_datetimeFields = array(
+        'creation_time',
+        'last_sync'
+    );
+}
diff --git a/tine20/Sipgate/Model/LineFilter.php b/tine20/Sipgate/Model/LineFilter.php
new file mode 100644 (file)
index 0000000..8e03399
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2010-2010 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+
+/**
+ * Sipgate_Model_LineFilter
+ *
+ * @package     Sipgate
+ * @subpackage  Filter
+ */
+class Sipgate_Model_LineFilter extends Tinebase_Model_Filter_FilterGroup
+{
+    /**
+     * @var string class name of this filter group
+     *      this is needed to overcome the static late binding
+     *      limitation in php < 5.3
+     */
+    protected $_className = 'Sipgate_Model_LineFilter';
+
+    /**
+     * @var string application of this filter group
+     */
+    protected $_applicationName = 'Sipgate';
+
+    /**
+     * @var string name of model this filter group is designed for
+     */
+    protected $_modelName = 'Sipgate_Model_Line';
+
+    /**
+     * @var array filter model fieldName => definition
+     */
+    protected $_filterModel = array(
+        'id'          => array('filter' => 'Tinebase_Model_Filter_Id', 'options' => array('controller' => 'Sipgate_Controller_Line', 'modelName' => 'Sipgate_Model_Line')),
+        'query'       => array('filter' => 'Tinebase_Model_Filter_Query', 'options' => array('fields' => array('uri_alias', 'e164_in', 'e164_out'))),
+        'user_id'     => array('filter' => 'Tinebase_Model_Filter_User'),
+        'sip_uri'     => array('filter' => 'Tinebase_Model_Filter_Text'),
+        'entry_id'     => array('filter' => 'Tinebase_Model_Filter_Text'),
+        'account_id'  => array('filter' => 'Tinebase_Model_Filter_ForeignId',
+            'options' => array(
+                'filtergroup'       => 'Sipgate_Model_AccountFilter', 
+                'controller'        => 'Sipgate_Controller_Account',
+                'modelName'         => 'Sipgate_Model_Account'
+           )
+        ),
+        'tos'         => array('filter' => 'Tinebase_Model_Filter_Text'),
+        'last_sync'   => array('filter' => 'Tinebase_Model_Filter_DateTime'),
+        'creation_time'        => array('filter' => 'Tinebase_Model_Filter_Date'),
+    );
+}
index 270446e..21d738a 100644 (file)
@@ -3,11 +3,10 @@
  * Tine 2.0
  *
  * @package     Sipgate
- * @subpackage    Preference
+ * @subpackage  Preference
  * @license     http://www.gnu.org/licenses/agpl.html AGPL3
  * @author      Alexander Stintzing <alex@stintzing.net>
- * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
- * @version     $Id: Preference.php 11 2011-04-29 05:23:26Z alex $
+ * @copyright   Copyright (c) 2011-2012 Metaways Infosystems GmbH (http://www.metaways.de)
  *
  */
 
  */
 class Sipgate_Preference extends Tinebase_Preference_Abstract
 {
-    /**************************** application preferences/settings *****************/
-
-    /**
-     * The users phone
-     */
-    const PHONEID = 'phoneId';
-
-    /**
-     * The users fax
-     */
-    const FAXID = 'faxId';
-
-    /**
-     * The users mobile number
-     */
-    const MOBILENUMBER = 'mobileNumber';
-
-    /**
-     * @var string application
-     */
-    protected $_application = 'Sipgate';
-
-    /**************************** public functions *********************************/
-
-    /**
-     * get all possible application prefs
-     *
-     * @return  array   all application prefs
-     */
-    public function getAllApplicationPreferences() {
-        $allPrefs = array(
-        self::PHONEID,
-        self::FAXID,
-        self::MOBILENUMBER
-        );
-
-        return $allPrefs;
-    }
-
-    /**
-     * get translated right descriptions
-     *
-     * @return array with translated descriptions for this applications preferences
-     */
-    public function getTranslatedPreferences()
-    {
-        $translate = Tinebase_Translation::getTranslation($this->_application);
-
-        $prefDescriptions = array(
-        self::PHONEID  => array(
-                'label'         => $translate->_('Your phone'),
-                'description'   => $translate->_('This is your phone'),
-        ),
-        self::FAXID  => array(
-                'label'         => $translate->_('Your fax'),
-                'description'   => $translate->_('This is your fax'),
-        ),
-        self::MOBILENUMBER  => array(
-                'label'         => $translate->_('Your mobile number'),
-                'description'   => $translate->_('Used when sending SMS'),
-        ),
-        );
-
-        return $prefDescriptions;
-    }
-
-    private function getOptions($_preferenceName,$_options) {
-
-        $preference = $this->_getDefaultBasePreference($_preferenceName);
-
-        $doc = new DomDocument('1.0');
-        $options = $doc->createElement('options');
-        $doc->appendChild($options);
-
-        foreach ($_options as $opt) {
-            $value  = $doc->createElement('value');
-            $value->appendChild($doc->createTextNode($opt));
-            $label  = $doc->createElement('label');
-            $label->appendChild($doc->createTextNode($opt));
-
-            $option = $doc->createElement('option');
-            $option->appendChild($value);
-            $option->appendChild($label);
-            $options->appendChild($option);
+        /**************************** application preferences/settings *****************/
+
+        /**
+         * The users phone
+         */
+        const PHONEID = 'phoneId';
+
+        /**
+         * The users fax
+         */
+        const FAXID = 'faxId';
+
+        /**
+         * The users mobile number
+         */
+        const MOBILENUMBER = 'mobileNumber';
+        
+        /**
+         * the international prefix
+         */
+        const INTERNATIONAL_PREFIX = 'internationalPrefix';
+
+        /**
+         * @var string application
+         */
+        protected $_application = 'Sipgate';
+
+        /**************************** public functions *********************************/
+
+        /**
+         * get all possible application prefs
+         *
+         * @return  array   all application prefs
+         */
+        public function getAllApplicationPreferences() {
+
+                $allPrefs = array(
+                  self::PHONEID,
+                  self::FAXID,
+                  self::MOBILENUMBER,
+                  self::INTERNATIONAL_PREFIX
+                );
+
+                return $allPrefs;
         }
-        $preference->options = $doc->saveXML();
 
-        // save first option in pref value
-        $preference->value = (is_array($_options) && isset($_options[0])) ? $_options[0] : '';
-        
-        return $preference;
-    }
-
-    /**
-     * get preference defaults if no default is found in the database
-     *
-     * @param string $_preferenceName
-     * @param string|Tinebase_Model_User $_accountId
-     * @param string $_accountType
-     * @return Tinebase_Model_Preference
-     */
-    public function getApplicationPreferenceDefaults($_preferenceName, $_accountId = NULL, $_accountType = Tinebase_Acl_Rights::ACCOUNT_TYPE_USER)    {
-        switch($_preferenceName) {
-            case self::PHONEID:
-                $dev = array();
-                try {
-                    $_phones = Sipgate_Controller::getInstance()->getPhoneDevices();
-                    foreach($_phones as $phone) {
-                        $dev[] = $phone['SipUri'];
-                    }
-                } catch (Sipgate_Exception_Backend $seb) {
-                    Tinebase_Core::getLogger()->warn(__METHOD__ . ' (' . __LINE__ . ') Could not get Sipgate phone devices: ' . $seb->getMessage());
-                } catch (Zend_Exception $ze) {
-                    Tinebase_Core::getLogger()->warn(__METHOD__ . ' (' . __LINE__ . ') Could not connect to sipgate: ' . $ze->getMessage());
-                }
-                $pref = $this->getOptions($_preferenceName, $dev);
-                break;
-            case self::FAXID:
-                $dev = array();
-                try {
-                    $_faxes = Sipgate_Controller::getInstance()->getFaxDevices();
-                    if (is_array($_faxes)) {
-                        foreach($_faxes as $fax) {
-                            $dev[] = $fax['SipUri'];
+        /**
+         * get translated right descriptions
+         *
+         * @return array with translated descriptions for this applications preferences
+         */
+        public function getTranslatedPreferences()
+        {
+                $translate = Tinebase_Translation::getTranslation($this->_application);
+
+                $prefDescriptions = array(
+                    self::PHONEID  => array(
+                        'label'         => $translate->_('Your phone'),
+                        'description'   => $translate->_('This is your phone'),
+                    ),
+                    self::FAXID  => array(
+                        'label'         => $translate->_('Your fax'),
+                        'description'   => $translate->_('This is your fax'),
+                    ),
+    
+                    self::MOBILENUMBER  => array(
+                        'label'         => $translate->_('Your mobile number'),
+                        'description'   => $translate->_('Used when sending SMS'),
+                    ),
+                    
+                    self::INTERNATIONAL_PREFIX => array(
+                        'label'         => $translate->_('International calling code'),
+                        'description'   => $translate->_('Your international calling code (e.g. +1 in the United States, +49 in Germany)'),
+                        )
+                );
+
+                return $prefDescriptions;
+        }
+
+        private function getOptions($_preferenceName, $_options) {
+                $preference = $this->_getDefaultBasePreference($_preferenceName);
+
+                if($_preferenceName == self::INTERNATIONAL_PREFIX) {
+                    $file = dirname(__FILE__) . '/Setup/calling-codes.xml';
+                    $preference->options = file_get_contents($file);
+                } else {
+                    $doc = new DomDocument('1.0');
+                    $options = $doc->createElement('options');
+                    $doc->appendChild($options);
+                    foreach ($_options as $opt) {
+                        if($_preferenceName == self::FAXID || $_preferenceName == self::PHONEID) {
+                            if ($_preferenceName == self::FAXID && $opt->tos != 'fax') {
+                                continue;
+                            } elseif ($_preferenceName == self::PHONEID && $opt->tos != 'voice') {
+                                continue;
+                            }
+                            $id = $opt->id;
+                            $text = $opt->e164_out . ', ' . $opt->uri_alias . ', ' . $opt->sip_uri;
+                        } else {
+                            $id = $opt['id'];
+                            $text = $opt['text']; 
                         }
+                        $value  = $doc->createElement('value');
+                        $value->appendChild($doc->createTextNode($id));
+                        $label  = $doc->createElement('label');
+                        $label->appendChild($doc->createTextNode($text));
+                        
+                        $option = $doc->createElement('option');
+                        $option->appendChild($value);
+                        $option->appendChild($label);
+                        $options->appendChild($option);
                     }
-                } catch (Sipgate_Exception_Backend $seb) {
-                    Tinebase_Core::getLogger()->warn(__METHOD__ . ' (' . __LINE__ . ') Could not get Sipgate fax devices: ' . $seb->getMessage());
-                } catch (Zend_Exception $ze) {
-                    Tinebase_Core::getLogger()->warn(__METHOD__ . ' (' . __LINE__ . ') Could not connect to sipgate: ' . $ze->getMessage());
-                }
-                $pref = $this->getOptions($_preferenceName, $dev);
-                break;
-            case self::MOBILENUMBER:
-                $config = Tinebase_Core::getConfig()->sipgate;
-                if ($config && $config->numbers && $config->numbers->mobile) {
-                    $pref = $this->getOptions($_preferenceName, $config->numbers->mobile);
-                } else {
-                    $pref = $this->_getDefaultBasePreference($_preferenceName);
+                    $preference->options = $doc->saveXML();
+                    // save last option in pref value per default
+                    if($opt) $preference->value = $id;
                 }
-                break;
-            default:
-                throw new Tinebase_Exception_NotFound('Default preference with name ' . $_preferenceName . ' not found.');
+                
+                return $preference;
+        }
+
+        /**
+         * get preference defaults if no default is found in the database
+         *
+         * @param string $_preferenceName
+         * @param string|Tinebase_Model_User $_accountId
+         * @param string $_accountType
+         * @return Tinebase_Model_Preference
+         */
+
+        public function getApplicationPreferenceDefaults($_preferenceName, $_accountId = NULL, $_accountType = Tinebase_Acl_Rights::ACCOUNT_TYPE_USER)
+        {
+            if ($_preferenceName == self::MOBILENUMBER) {
+                $c = Addressbook_Controller_Contact::getInstance()->getContactByUserId(Tinebase_Core::getUser()->getId());
+                $possibleLines = array();
+                if(!empty($c->tel_cell)) $possibleLines[] = array('id' => 'tel_cell', 'text' => $c->tel_cell);
+                if(!empty($c->tel_cell_private)) $possibleLines[] = array('id' => 'tel_cell_private', 'text' => $c->tel_cell_private);
+                if(!empty($c->tel_other)) $possibleLines[] = array('id' => 'tel_other', 'text' => $c->tel_other);
+            } elseif ($_preferenceName != self::INTERNATIONAL_PREFIX) {
+                $possibleLines = Sipgate_Controller_Line::getInstance()->getUsableLines();
+            }
+            
+            switch($_preferenceName) {
+                case self::PHONEID:
+                    $pref = $this->getOptions($_preferenceName, $possibleLines);
+                    break;
+                case self::FAXID:
+                    $pref = $this->getOptions($_preferenceName, $possibleLines);
+                    break;
+                case self::MOBILENUMBER:
+                    $pref = $this->getOptions($_preferenceName, $possibleLines);
+                    break;
+                case self::INTERNATIONAL_PREFIX:
+                    $pref = $this->getOptions($_preferenceName);
+                    break;
+                default:
+                    throw new Tinebase_Exception_NotFound('Default preference with name ' . $_preferenceName . ' not found.');
+            }
+            return $pref;
         }
-        return $pref;
-    }
 
 }
+
index 05e72f6..8f9bf32 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /**
  * Tine 2.0
- * 
+ *
  * @package     Sipgate
  * @license     http://www.gnu.org/licenses/agpl.html AGPL3
  * @author      Alexander Stintzing <alex@stintzing.net>
 
 /**
  * class for Sipgate initialization
- * 
  * @package     Setup
  */
 class Sipgate_Setup_Initialize extends Setup_Initialize
 {
+    /**
+     * init key fields
+     */
+    function _initializeKeyfields()
+    {
+        // create status config
+        $cb = new Tinebase_Backend_Sql(array(
+            'modelName' => 'Tinebase_Model_Config',
+            'tableName' => 'config',
+        ));
+        $appId = Tinebase_Application::getInstance()->getApplicationByName('Sipgate')->getId();
+
+        $connectionStatusConfig = array(
+            'name'    => Sipgate_Config::CONNECTION_STATUS,
+            'records' => array(
+                array('id' => 'accepted', 'value' => 'accepted', 'icon' => "../../images/../Sipgate/res/call_accepted.png", 'system' => true),  //_('accepted')
+                array('id' => 'outgoing', 'value' => 'outgoing', 'icon' => "../../images/../Sipgate/res/call_outgoing.png", 'system' => true),  //_('outgoing')
+                array('id' => 'missed',   'value' => 'missed',   'icon' => "../../images/../Sipgate/res/call_missed.png", 'system' => true),  //_('missed')
+            ),
+        );
+
+        $cb->create(new Tinebase_Model_Config(array(
+            'application_id'    => $appId,
+            'name'              => Sipgate_Config::CONNECTION_STATUS,
+            'value'             => json_encode($connectionStatusConfig),
+        )));
+
+        // create tos config
+        $connectionTos = array(
+            'name'    => Sipgate_Config::CONNECTION_TOS,
+            'records' => array(
+                array('id' => 'voice', 'value' => 'Telephone Call',  'icon' => "../../images/oxygen/16x16/apps/kcall.png",   'system' => true),  //_('Telephone Call')
+                array('id' => 'fax',   'value' => 'Facsimile',       'icon' => "../../images/../Sipgate/res/16x16/kfax.png", 'system' => true),  //_('Facsimile')
+
+            ),
+        );
+
+        $cb->create(new Tinebase_Model_Config(array(
+            'application_id'    => $appId,
+            'name'              => Sipgate_Config::CONNECTION_TOS,
+            'value'             => json_encode($connectionTos),
+        )));
+        
+        $c = array(
+            'name'    => Sipgate_Config::ACCOUNT_ACCOUNT_TYPE,
+            'records' => array(
+                array('id' => 'plus', 'value' => 'basic/plus', 'icon' => "../../images/oxygen/16x16/places/user-identity.png", 'system' => true),  //_('basic/plus')
+                array('id' => 'team', 'value' => 'team',       'icon' => "../../images/oxygen/16x16/apps/system-users.png",    'system' => true),  //_('team')
+            ),
+        );
+
+        $cb->create(new Tinebase_Model_Config(array(
+            'application_id'    => $appId,
+            'name'              => Sipgate_Config::ACCOUNT_ACCOUNT_TYPE,
+            'value'             => json_encode($c),
+        )));
+
+        // create tos config
+        $c = array(
+            'name'    => Sipgate_Config::ACCOUNT_TYPE,
+            'records' => array(
+                array('id' => 'private', 'value' => 'private', 'icon' => "../../images/oxygen/16x16/places/user-identity.png", 'system' => true),  //_('private')
+                array('id' => 'shared',     'value' => 'shared',   'icon' => "../../images/oxygen/16x16/apps/system-users.png",    'system' => true),  //_('shared')
+
+            ),
+        );
+
+        $cb->create(new Tinebase_Model_Config(array(
+            'application_id'    => $appId,
+            'name'              => Sipgate_Config::ACCOUNT_TYPE,
+            'value'             => json_encode($c),
+        )));
+        
+    }
 }
\ No newline at end of file
diff --git a/tine20/Sipgate/Setup/Update/Release1.php b/tine20/Sipgate/Setup/Update/Release1.php
new file mode 100644 (file)
index 0000000..b46ddc4
--- /dev/null
@@ -0,0 +1,483 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Sipgate
+ * @subpackage  Setup
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL3
+ * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ */
+
+/**
+ * Sipgate updates for version 1.1
+ *
+ * @package     Sipgate
+ * @subpackage  Setup
+ */
+class Sipgate_Setup_Update_Release1 extends Setup_Update_Abstract
+{
+
+    /**
+     * update 0.1 -> 1.0
+     */
+    public function update_0()
+    {
+        $this->setApplicationVersion('Sipgate', '1.0');
+    }
+
+
+    /**
+     * update 1.0 -> 1.1
+     */
+    public function update_1()
+    {
+        $this->setApplicationVersion('Sipgate', '1.1');
+    }
+
+    public function update_2()
+    {
+        // create status config
+        $cb = new Tinebase_Backend_Sql(array(
+            'modelName' => 'Tinebase_Model_Config',
+            'tableName' => 'config',
+        ));
+        $appId = Tinebase_Application::getInstance()->getApplicationByName('Sipgate')->getId();
+
+        $connectionStatusConfig = array(
+            'name'    => Sipgate_Config::CONNECTION_STATUS,
+            'records' => array(
+                array('id' => 'accepted', 'value' => 'accepted', 'icon' => "../../images/../Sipgate/res/call_accepted.png", 'system' => true),  //_('accepted')
+                array('id' => 'outgoing', 'value' => 'outgoing', 'icon' => "../../images/../Sipgate/res/call_outgoing.png", 'system' => true),  //_('outgoing')
+                array('id' => 'missed',   'value' => 'missed',   'icon' => "../../images/../Sipgate/res/call_missed.png", 'system' => true),  //_('missed')
+            ),
+        );
+
+        $cb->create(new Tinebase_Model_Config(array(
+            'application_id'    => $appId,
+            'name'              => Sipgate_Config::CONNECTION_STATUS,
+            'value'             => json_encode($connectionStatusConfig),
+        )));
+
+        // create tos config
+        $connectionTos = array(
+            'name'    => Sipgate_Config::CONNECTION_TOS,
+            'records' => array(
+                array('id' => 'voice', 'value' => 'Telephone Call',  'icon' => "../../images/oxygen/16x16/apps/kcall.png",   'system' => true),  //_('Telephone Call')
+                array('id' => 'fax',   'value' => 'Facsimile',       'icon' => "../../images/../Sipgate/res/16x16/kfax.png", 'system' => true),  //_('Facsimile')
+
+            ),
+        );
+
+        $cb->create(new Tinebase_Model_Config(array(
+            'application_id'    => $appId,
+            'name'              => Sipgate_Config::CONNECTION_TOS,
+            'value'             => json_encode($connectionTos),
+        )));
+        $this->setApplicationVersion('Sipgate', '1.2');
+    }
+    
+    public function update_3()
+    {
+        $cb = new Tinebase_Backend_Sql(array(
+            'modelName' => 'Tinebase_Model_Config',
+            'tableName' => 'config',
+        ));
+        $appId = Tinebase_Application::getInstance()->getApplicationByName('Sipgate')->getId();
+
+        $c = array(
+            'name'    => Sipgate_Config::ACCOUNT_ACCOUNT_TYPE,
+            'records' => array(
+                array('id' => 'plus', 'value' => 'basic/plus', 'icon' => "../../images/oxygen/16x16/places/user-identity.png", 'system' => true),  //_('basic/plus')
+                array('id' => 'team', 'value' => 'team',       'icon' => "../../images/oxygen/16x16/apps/system-users.png",    'system' => true),  //_('team')
+            ),
+        );
+
+        $cb->create(new Tinebase_Model_Config(array(
+            'application_id'    => $appId,
+            'name'              => Sipgate_Config::ACCOUNT_ACCOUNT_TYPE,
+            'value'             => json_encode($c),
+        )));
+
+        // create tos config
+        $c = array(
+            'name'    => Sipgate_Config::ACCOUNT_TYPE,
+            'records' => array(
+                array('id' => 'private', 'value' => 'private', 'icon' => "../../images/oxygen/16x16/places/user-identity.png", 'system' => true),  //_('private')
+                array('id' => 'shared',     'value' => 'shared',   'icon' => "../../images/oxygen/16x16/apps/system-users.png",    'system' => true),  //_('shared')
+
+            ),
+        );
+
+        $cb->create(new Tinebase_Model_Config(array(
+            'application_id'    => $appId,
+            'name'              => Sipgate_Config::ACCOUNT_TYPE,
+            'value'             => json_encode($c),
+        )));
+
+        $this->setApplicationVersion('Sipgate', '1.4');
+    }
+    /**
+     * creates the new tables
+     */
+    public function update_4() {
+        $tableDefinition = '<table>
+            <name>sipgate_account</name>
+            <version>0</version>
+            <declaration>
+                <field>
+                    <name>id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>accounttype</name>
+                    <type>text</type>
+                    <length>10</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>type</name>
+                    <type>text</type>
+                    <length>10</length>
+                    <notnull>true</notnull>
+                    <default>shared</default>
+                </field>
+                <field>
+                    <name>credential_id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>false</notnull>
+                </field>
+                <field>
+                    <name>description</name>
+                    <type>text</type>
+                    <length>64</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>username</name>
+                    <type>text</type>
+                    <length>64</length>
+                    <notnull>false</notnull>
+                </field>
+                <field>
+                    <name>password</name>
+                    <type>text</type>
+                    <length>64</length>
+                    <notnull>false</notnull>
+                </field>
+                <field>
+                    <name>is_valid</name>
+                    <type>boolean</type>
+                    <default>false</default>
+                </field>
+                <field>
+                    <name>created_by</name>
+                    <type>text</type>
+                    <length>40</length>
+                </field>
+                <field>
+                    <name>creation_time</name>
+                    <type>datetime</type>
+                </field> 
+                <field>
+                    <name>last_modified_by</name>
+                    <type>text</type>
+                    <length>40</length>
+                </field>
+                <field>
+                    <name>last_modified_time</name>
+                    <type>datetime</type>
+                </field>
+                <field>
+                    <name>is_deleted</name>
+                    <type>boolean</type>
+                    <default>false</default>
+                </field>
+                <field>
+                    <name>deleted_by</name>
+                    <type>text</type>
+                    <length>40</length>
+                </field>            
+                <field>
+                    <name>deleted_time</name>
+                    <type>datetime</type>
+                </field>
+                <field>
+                    <name>mobile_number</name>
+                    <type>text</type>
+                    <length>64</length>
+                </field>
+                <index>
+                    <name>id</name>
+                    <primary>true</primary>
+                    <field>
+                        <name>id</name>
+                    </field>
+                </index>
+            </declaration>
+        </table>';
+        $table = Setup_Backend_Schema_Table_Factory::factory('Xml', $tableDefinition);
+        $this->_backend->createTable($table);
+        
+        $tableDefinition = '<table>
+            <name>sipgate_line</name>
+            <version>0</version>
+            <declaration>
+                <field>
+                    <name>id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>account_id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                </field> 
+                <field>
+                    <name>user_id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>false</notnull>
+                </field>
+                <field>
+                    <name>uri_alias</name>
+                    <type>text</type>
+                    <length>256</length>
+                </field>
+                <field>
+                    <name>sip_uri</name>
+                    <type>text</type>
+                    <length>256</length>
+                </field>
+                <field>
+                    <name>e164_out</name>
+                    <type>text</type>
+                    <length>256</length>
+                </field>
+                <field>
+                    <name>e164_in</name>
+                    <type>text</type>
+                    <length>256</length>
+                </field>
+                <field>
+                    <name>tos</name>
+                    <type>text</type>
+                    <length>10</length>
+                </field>
+                <field>
+                    <name>creation_time</name>
+                    <type>datetime</type>
+                </field>
+                <field>
+                    <name>last_sync</name>
+                    <type>datetime</type>
+                </field>
+                <index>
+                    <name>id</name>
+                    <primary>true</primary>
+                    <field>
+                        <name>id</name>
+                    </field>
+                </index>
+                <index>
+                    <name>sipgate_line::account_id--sipgate_account::id</name>
+                    <field>
+                        <name>account_id</name>
+                    </field>
+                    <foreign>true</foreign>
+                    <reference>
+                        <table>sipgate_account</table>
+                        <field>id</field>
+                    </reference>
+                </index>
+                <index>
+                    <name>sipgate_line::user_id--sipgate_user::id</name>
+                    <field>
+                        <name>user_id</name>
+                    </field>
+                    <foreign>true</foreign>
+                    <reference>
+                        <table>accounts</table>
+                        <field>id</field>
+                    </reference>
+                </index>
+            </declaration>
+        </table>';
+        $table = Setup_Backend_Schema_Table_Factory::factory('Xml', $tableDefinition);
+        $this->_backend->createTable($table);
+        
+        $tableDefinition = '<table>
+            <name>sipgate_connection</name>
+            <version>0</version>
+            <declaration>
+                <field>
+                    <name>id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>entry_id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>tos</name>
+                    <type>text</type>
+                    <length>10</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>local_uri</name>
+                    <type>text</type>
+                    <length>256</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>remote_uri</name>
+                    <type>text</type>
+                    <length>256</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>local_number</name>
+                    <type>text</type>
+                    <length>128</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>remote_number</name>
+                    <type>text</type>
+                    <length>128</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>status</name>
+                    <type>text</type>
+                    <length>8</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>line_id</name>
+                    <type>text</type>
+                    <length>40</length>
+                </field>
+                <field>
+                    <name>timestamp</name>
+                    <type>datetime</type>
+                </field>
+                <field>
+                    <name>creation_time</name>
+                    <type>datetime</type>
+                </field> 
+                <field>
+                    <name>tarif</name>
+                    <type>text</type>
+                    <length>256</length>
+                </field>
+                <field>
+                    <name>duration</name>
+                    <type>integer</type>
+                </field>
+                <field>
+                    <name>units_charged</name>
+                    <type>integer</type>
+                </field>
+                <field>
+                    <name>price_unit</name>
+                    <type>float</type>
+                </field>
+                <field>
+                    <name>price_total</name>
+                    <type>float</type>
+                </field>
+                <field>
+                    <name>ticks_a</name>
+                    <type>integer</type>
+                    <length>3</length>
+                </field>
+                <field>
+                    <name>ticks_b</name>
+                    <type>integer</type>
+                    <length>3</length>
+                </field>
+                <field>
+                    <name>contact_id</name>
+                    <type>text</type>
+                    <length>40</length>
+                </field>
+                <field>
+                    <name>contact_name</name>
+                    <type>text</type>
+                    <length>128</length>
+                    <notnull>false</notnull>
+                </field>
+                <index>
+                    <name>id</name>
+                    <primary>true</primary>
+                    <field>
+                        <name>id</name>
+                    </field>
+                </index>
+                <index>
+                    <name>entry_id</name>
+                    <field>
+                        <name>entry_id</name>
+                    </field>
+                </index>
+                <index>
+                    <name>creation_time</name>
+                    <field>
+                        <name>creation_time</name>
+                    </field>
+                </index>
+                <index>
+                    <name>timestamp</name>
+                    <field>
+                        <name>timestamp</name>
+                    </field>
+                </index>                
+                <index>
+                    <name>connection::contact_id--contact::id</name>
+                    <field>
+                        <name>contact_id</name>
+                    </field>
+                    <foreign>true</foreign>
+                    <reference>
+                        <table>addressbook</table>
+                        <field>id</field>
+                    </reference>
+                </index>
+                <index>
+                    <name>connection::line_id--line::id</name>
+                    <field>
+                        <name>line_id</name>
+                    </field>
+                    <foreign>true</foreign>
+                    <reference>
+                        <table>sipgate_line</table>
+                        <field>id</field>
+                    </reference>
+                </index>
+            </declaration>
+        </table>';
+        $table = Setup_Backend_Schema_Table_Factory::factory('Xml', $tableDefinition);
+        $this->_backend->createTable($table);
+        
+        $this->setApplicationVersion('Sipgate', '1.5');
+    }
+    /**
+     * creates an account if previous config was found
+     */
+    public function update_5()
+    {
+        
+        $this->setApplicationVersion('Sipgate', '2.0');
+    }
+}
diff --git a/tine20/Sipgate/Setup/calling-codes.xml b/tine20/Sipgate/Setup/calling-codes.xml
new file mode 100644 (file)
index 0000000..1fda2e0
--- /dev/null
@@ -0,0 +1,1253 @@
+<?xml version="1.0" encoding="utf-8"?>
+<options>
+    <option>
+        <value>+93</value>
+        <!-- _("+93 (Afghanistan)") -->
+        <label>+93 (Afghanistan)</label>
+    </option>
+    <option>
+        <value>+355</value>
+        <!-- _("+355 (Albania (Republic of))") -->
+        <label>+355 (Albania (Republic of))</label>
+    </option>
+    <option>
+        <value>+213</value>
+        <!-- _("+213 (Algeria (People's Democratic Republic of))") -->
+        <label>+213 (Algeria (People's Democratic Republic of))</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (American Samoa)") -->
+        <label>+1 (American Samoa)</label>
+    </option>
+    <option>
+        <value>+376</value>
+        <!-- _("+376 (Andorra (Principality of))") -->
+        <label>+376 (Andorra (Principality of))</label>
+    </option>
+    <option>
+        <value>+244</value>
+        <!-- _("+244 (Angola (Republic of))") -->
+        <label>+244 (Angola (Republic of))</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Anguilla)") -->
+        <label>+1 (Anguilla)</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Antigua and Barbuda)") -->
+        <label>+1 (Antigua and Barbuda)</label>
+    </option>
+    <option>
+        <value>+54</value>
+        <!-- _("+54 (Argentine Republic)") -->
+        <label>+54 (Argentine Republic)</label>
+    </option>
+    <option>
+        <value>+374</value>
+        <!-- _("+374 (Armenia (Republic of))") -->
+        <label>+374 (Armenia (Republic of))</label>
+    </option>
+    <option>
+        <value>+297</value>
+        <!-- _("+297 (Aruba)") -->
+        <label>+297 (Aruba)</label>
+    </option>
+    <option>
+        <value>+247</value>
+        <!-- _("+247 (Ascension)") -->
+        <label>+247 (Ascension)</label>
+    </option>
+    <option>
+        <value>+61</value>
+        <!-- _("+61 (Australia)") -->
+        <label>+61 (Australia)</label>
+    </option>
+    <option>
+        <value>+672</value>
+        <!-- _("+672 (Australian External Territories)") -->
+        <label>+672 (Australian External Territories)</label>
+    </option>
+    <option>
+        <value>+43</value>
+        <!-- _("+43 (Austria)") -->
+        <label>+43 (Austria)</label>
+    </option>
+    <option>
+        <value>+994</value>
+        <!-- _("+994 (Azerbaijani Republic)") -->
+        <label>+994 (Azerbaijani Republic)</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Bahamas (Commonwealth of the))") -->
+        <label>+1 (Bahamas (Commonwealth of the))</label>
+    </option>
+    <option>
+        <value>+973</value>
+        <!-- _("+973 (Bahrain (Kingdom of))") -->
+        <label>+973 (Bahrain (Kingdom of))</label>
+    </option>
+    <option>
+        <value>+880</value>
+        <!-- _("+880 (Bangladesh (People's Republic of))") -->
+        <label>+880 (Bangladesh (People's Republic of))</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Barbados)") -->
+        <label>+1 (Barbados)</label>
+    </option>
+    <option>
+        <value>+375</value>
+        <!-- _("+375 (Belarus (Republic of))") -->
+        <label>+375 (Belarus (Republic of))</label>
+    </option>
+    <option>
+        <value>+32</value>
+        <!-- _("+32 (Belgium)") -->
+        <label>+32 (Belgium)</label>
+    </option>
+    <option>
+        <value>+501</value>
+        <!-- _("+501 (Belize)") -->
+        <label>+501 (Belize)</label>
+    </option>
+    <option>
+        <value>+229</value>
+        <!-- _("+229 (Benin (Republic of))") -->
+        <label>+229 (Benin (Republic of))</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Bermuda)") -->
+        <label>+1 (Bermuda)</label>
+    </option>
+    <option>
+        <value>+975</value>
+        <!-- _("+975 (Bhutan (Kingdom of))") -->
+        <label>+975 (Bhutan (Kingdom of))</label>
+    </option>
+    <option>
+        <value>+591</value>
+        <!-- _("+591 (Bolivia (Republic of))") -->
+        <label>+591 (Bolivia (Republic of))</label>
+    </option>
+    <option>
+        <value>+387</value>
+        <!-- _("+387 (Bosnia and Herzegovina)") -->
+        <label>+387 (Bosnia and Herzegovina)</label>
+    </option>
+    <option>
+        <value>+267</value>
+        <!-- _("+267 (Botswana (Republic of))") -->
+        <label>+267 (Botswana (Republic of))</label>
+    </option>
+    <option>
+        <value>+55</value>
+        <!-- _("+55 (Brazil (Federative Republic of))") -->
+        <label>+55 (Brazil (Federative Republic of))</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (British Virgin Islands)") -->
+        <label>+1 (British Virgin Islands)</label>
+    </option>
+    <option>
+        <value>+673</value>
+        <!-- _("+673 (Brunei Darussalam)") -->
+        <label>+673 (Brunei Darussalam)</label>
+    </option>
+    <option>
+        <value>+359</value>
+        <!-- _("+359 (Bulgaria (Republic of))") -->
+        <label>+359 (Bulgaria (Republic of))</label>
+    </option>
+    <option>
+        <value>+226</value>
+        <!-- _("+226 (Burkina Faso)") -->
+        <label>+226 (Burkina Faso)</label>
+    </option>
+    <option>
+        <value>+257</value>
+        <!-- _("+257 (Burundi (Republic of))") -->
+        <label>+257 (Burundi (Republic of))</label>
+    </option>
+    <option>
+        <value>+855</value>
+        <!-- _("+855 (Cambodia (Kingdom of))") -->
+        <label>+855 (Cambodia (Kingdom of))</label>
+    </option>
+    <option>
+        <value>+237</value>
+        <!-- _("+237 (Cameroon (Republic of))") -->
+        <label>+237 (Cameroon (Republic of))</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Canada)") -->
+        <label>+1 (Canada)</label>
+    </option>
+    <option>
+        <value>+238</value>
+        <!-- _("+238 (Cape Verde (Republic of))") -->
+        <label>+238 (Cape Verde (Republic of))</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Cayman Islands)") -->
+        <label>+1 (Cayman Islands)</label>
+    </option>
+    <option>
+        <value>+236</value>
+        <!-- _("+236 (Central African Republic)") -->
+        <label>+236 (Central African Republic)</label>
+    </option>
+    <option>
+        <value>+235</value>
+        <!-- _("+235 (Chad (Republic of))") -->
+        <label>+235 (Chad (Republic of))</label>
+    </option>
+    <option>
+        <value>+56</value>
+        <!-- _("+56 (Chile)") -->
+        <label>+56 (Chile)</label>
+    </option>
+    <option>
+        <value>+86</value>
+        <!-- _("+86 (China (People's Republic of))") -->
+        <label>+86 (China (People's Republic of))</label>
+    </option>
+    <option>
+        <value>+57</value>
+        <!-- _("+57 (Colombia (Republic of))") -->
+        <label>+57 (Colombia (Republic of))</label>
+    </option>
+    <option>
+        <value>+269</value>
+        <!-- _("+269 (Comoros (Union of the))") -->
+        <label>+269 (Comoros (Union of the))</label>
+    </option>
+    <option>
+        <value>+242</value>
+        <!-- _("+242 (Congo (Republic of the))") -->
+        <label>+242 (Congo (Republic of the))</label>
+    </option>
+    <option>
+        <value>+682</value>
+        <!-- _("+682 (Cook Islands)") -->
+        <label>+682 (Cook Islands)</label>
+    </option>
+    <option>
+        <value>+506</value>
+        <!-- _("+506 (Costa Rica)") -->
+        <label>+506 (Costa Rica)</label>
+    </option>
+    <option>
+        <value>+225</value>
+        <!-- _("+225 (Côte d'Ivoire (Republic of))") -->
+        <label>+225 (Côte d'Ivoire (Republic of))</label>
+    </option>
+    <option>
+        <value>+385</value>
+        <!-- _("+385 (Croatia (Republic of))") -->
+        <label>+385 (Croatia (Republic of))</label>
+    </option>
+    <option>
+        <value>+53</value>
+        <!-- _("+53 (Cuba)") -->
+        <label>+53 (Cuba)</label>
+    </option>
+    <option>
+        <value>+357</value>
+        <!-- _("+357 (Cyprus (Republic of))") -->
+        <label>+357 (Cyprus (Republic of))</label>
+    </option>
+    <option>
+        <value>+420</value>
+        <!-- _("+420 (Czech Republic)") -->
+        <label>+420 (Czech Republic)</label>
+    </option>
+    <option>
+        <value>+850</value>
+        <!-- _("+850 (Democratic People's Republic of Korea)") -->
+        <label>+850 (Democratic People's Republic of Korea)</label>
+    </option>
+    <option>
+        <value>+243</value>
+        <!-- _("+243 (Democratic Republic of the Congo)") -->
+        <label>+243 (Democratic Republic of the Congo)</label>
+    </option>
+    <option>
+        <value>+670</value>
+        <!-- _("+670 (Democratic Republic of Timor-Leste)") -->
+        <label>+670 (Democratic Republic of Timor-Leste)</label>
+    </option>
+    <option>
+        <value>+45</value>
+        <!-- _("+45 (Denmark)") -->
+        <label>+45 (Denmark)</label>
+    </option>
+    <option>
+        <value>+246</value>
+        <!-- _("+246 (Diego Garcia)") -->
+        <label>+246 (Diego Garcia)</label>
+    </option>
+    <option>
+        <value>+253</value>
+        <!-- _("+253 (Djibouti (Republic of))") -->
+        <label>+253 (Djibouti (Republic of))</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Dominica (Commonwealth of))") -->
+        <label>+1 (Dominica (Commonwealth of))</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Dominican Republic)") -->
+        <label>+1 (Dominican Republic)</label>
+    </option>
+    <option>
+        <value>+593</value>
+        <!-- _("+593 (Ecuador)") -->
+        <label>+593 (Ecuador)</label>
+    </option>
+    <option>
+        <value>+20</value>
+        <!-- _("+20 (Egypt (Arab Republic of))") -->
+        <label>+20 (Egypt (Arab Republic of))</label>
+    </option>
+    <option>
+        <value>+503</value>
+        <!-- _("+503 (El Salvador (Republic of))") -->
+        <label>+503 (El Salvador (Republic of))</label>
+    </option>
+    <option>
+        <value>+240</value>
+        <!-- _("+240 (Equatorial Guinea (Republic of))") -->
+        <label>+240 (Equatorial Guinea (Republic of))</label>
+    </option>
+    <option>
+        <value>+291</value>
+        <!-- _("+291 (Eritrea)") -->
+        <label>+291 (Eritrea)</label>
+    </option>
+    <option>
+        <value>+372</value>
+        <!-- _("+372 (Estonia (Republic of))") -->
+        <label>+372 (Estonia (Republic of))</label>
+    </option>
+    <option>
+        <value>+251</value>
+        <!-- _("+251 (Ethiopia (Federal Democratic Republic of))") -->
+        <label>+251 (Ethiopia (Federal Democratic Republic of))</label>
+    </option>
+    <option>
+        <value>+500</value>
+        <!-- _("+500 (Falkland Islands (Malvinas))") -->
+        <label>+500 (Falkland Islands (Malvinas))</label>
+    </option>
+    <option>
+        <value>+298</value>
+        <!-- _("+298 (Faroe Islands)") -->
+        <label>+298 (Faroe Islands)</label>
+    </option>
+    <option>
+        <value>+679</value>
+        <!-- _("+679 (Fiji (Republic of))") -->
+        <label>+679 (Fiji (Republic of))</label>
+    </option>
+    <option>
+        <value>+358</value>
+        <!-- _("+358 (Finland)") -->
+        <label>+358 (Finland)</label>
+    </option>
+    <option>
+        <value>+33</value>
+        <!-- _("+33 (France)") -->
+        <label>+33 (France)</label>
+    </option>
+    <option>
+        <value>+594</value>
+        <!-- _("+594 (French Guiana (French Department of))") -->
+        <label>+594 (French Guiana (French Department of))</label>
+    </option>
+    <option>
+        <value>+689</value>
+        <!-- _("+689 (French Polynesia (Territoire français d'outre-mer))") -->
+        <label>+689 (French Polynesia (Territoire français d'outre-mer))</label>
+    </option>
+    <option>
+        <value>+241</value>
+        <!-- _("+241 (Gabonese Republic)") -->
+        <label>+241 (Gabonese Republic)</label>
+    </option>
+    <option>
+        <value>+220</value>
+        <!-- _("+220 (Gambia (Republic of the))") -->
+        <label>+220 (Gambia (Republic of the))</label>
+    </option>
+    <option>
+        <value>+995</value>
+        <!-- _("+995 (Georgia)") -->
+        <label>+995 (Georgia)</label>
+    </option>
+    <option>
+        <value>+49</value>
+        <!-- _("+49 (Germany (Federal Republic of))") -->
+        <label>+49 (Germany (Federal Republic of))</label>
+    </option>
+    <option>
+        <value>+233</value>
+        <!-- _("+233 (Ghana)") -->
+        <label>+233 (Ghana)</label>
+    </option>
+    <option>
+        <value>+350</value>
+        <!-- _("+350 (Gibraltar)") -->
+        <label>+350 (Gibraltar)</label>
+    </option>
+    <option>
+        <value>+30</value>
+        <!-- _("+30 (Greece)") -->
+        <label>+30 (Greece)</label>
+    </option>
+    <option>
+        <value>+299</value>
+        <!-- _("+299 (Greenland (Denmark))") -->
+        <label>+299 (Greenland (Denmark))</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Grenada)") -->
+        <label>+1 (Grenada)</label>
+    </option>
+    <option>
+        <value>+388</value>
+        <!-- _("+388 (Group of countries, shared code)") -->
+        <label>+388 (Group of countries, shared code)</label>
+    </option>
+    <option>
+        <value>+590</value>
+        <!-- _("+590 (Guadeloupe (French Department of))") -->
+        <label>+590 (Guadeloupe (French Department of))</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Guam)") -->
+        <label>+1 (Guam)</label>
+    </option>
+    <option>
+        <value>+502</value>
+        <!-- _("+502 (Guatemala (Republic of))") -->
+        <label>+502 (Guatemala (Republic of))</label>
+    </option>
+    <option>
+        <value>+224</value>
+        <!-- _("+224 (Guinea (Republic of))") -->
+        <label>+224 (Guinea (Republic of))</label>
+    </option>
+    <option>
+        <value>+245</value>
+        <!-- _("+245 (Guinea-Bissau (Republic of))") -->
+        <label>+245 (Guinea-Bissau (Republic of))</label>
+    </option>
+    <option>
+        <value>+592</value>
+        <!-- _("+592 (Guyana)") -->
+        <label>+592 (Guyana)</label>
+    </option>
+    <option>
+        <value>+509</value>
+        <!-- _("+509 (Haiti (Republic of))") -->
+        <label>+509 (Haiti (Republic of))</label>
+    </option>
+    <option>
+        <value>+504</value>
+        <!-- _("+504 (Honduras (Republic of))") -->
+        <label>+504 (Honduras (Republic of))</label>
+    </option>
+    <option>
+        <value>+852</value>
+        <!-- _("+852 (Hong Kong, China)") -->
+        <label>+852 (Hong Kong, China)</label>
+    </option>
+    <option>
+        <value>+36</value>
+        <!-- _("+36 (Hungary (Republic of))") -->
+        <label>+36 (Hungary (Republic of))</label>
+    </option>
+    <option>
+        <value>+354</value>
+        <!-- _("+354 (Iceland)") -->
+        <label>+354 (Iceland)</label>
+    </option>
+    <option>
+        <value>+91</value>
+        <!-- _("+91 (India (Republic of))") -->
+        <label>+91 (India (Republic of))</label>
+    </option>
+    <option>
+        <value>+62</value>
+        <!-- _("+62 (Indonesia (Republic of))") -->
+        <label>+62 (Indonesia (Republic of))</label>
+    </option>
+    <option>
+        <value>+871</value>
+        <!-- _("+871 (Inmarsat (Atlantic Ocean-East))") -->
+        <label>+871 (Inmarsat (Atlantic Ocean-East))</label>
+    </option>
+    <option>
+        <value>+874</value>
+        <!-- _("+874 (Inmarsat (Atlantic Ocean-West))") -->
+        <label>+874 (Inmarsat (Atlantic Ocean-West))</label>
+    </option>
+    <option>
+        <value>+873</value>
+        <!-- _("+873 (Inmarsat (Indian Ocean))") -->
+        <label>+873 (Inmarsat (Indian Ocean))</label>
+    </option>
+    <option>
+        <value>+872</value>
+        <!-- _("+872 (Inmarsat (Pacific Ocean))") -->
+        <label>+872 (Inmarsat (Pacific Ocean))</label>
+    </option>
+    <option>
+        <value>+870</value>
+        <!-- _("+870 (Inmarsat SNAC)") -->
+        <label>+870 (Inmarsat SNAC)</label>
+    </option>
+    <option>
+        <value>+800</value>
+        <!-- _("+800 (International Freephone Service)") -->
+        <label>+800 (International Freephone Service)</label>
+    </option>
+    <option>
+        <value>+881</value>
+        <!-- _("+881 (International Mobile, shared code)") -->
+        <label>+881 (International Mobile, shared code)</label>
+    </option>
+    <option>
+        <value>+882</value>
+        <!-- _("+882 (International Networks, shared code)") -->
+        <label>+882 (International Networks, shared code)</label>
+    </option>
+    <option>
+        <value>+979</value>
+        <!-- _("+979 (International Premium Rate Service (IPRS))") -->
+        <label>+979 (International Premium Rate Service (IPRS))</label>
+    </option>
+    <option>
+        <value>+808</value>
+        <!-- _("+808 (International Shared Cost Service (ISCS))") -->
+        <label>+808 (International Shared Cost Service (ISCS))</label>
+    </option>
+    <option>
+        <value>+98</value>
+        <!-- _("+98 (Iran (Islamic Republic of))") -->
+        <label>+98 (Iran (Islamic Republic of))</label>
+    </option>
+    <option>
+        <value>+964</value>
+        <!-- _("+964 (Iraq (Republic of))") -->
+        <label>+964 (Iraq (Republic of))</label>
+    </option>
+    <option>
+        <value>+353</value>
+        <!-- _("+353 (Ireland)") -->
+        <label>+353 (Ireland)</label>
+    </option>
+    <option>
+        <value>+972</value>
+        <!-- _("+972 (Israel (State of))") -->
+        <label>+972 (Israel (State of))</label>
+    </option>
+    <option>
+        <value>+39</value>
+        <!-- _("+39 (Italy)") -->
+        <label>+39 (Italy)</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Jamaica)") -->
+        <label>+1 (Jamaica)</label>
+    </option>
+    <option>
+        <value>+81</value>
+        <!-- _("+81 (Japan)") -->
+        <label>+81 (Japan)</label>
+    </option>
+    <option>
+        <value>+962</value>
+        <!-- _("+962 (Jordan (Hashemite Kingdom of))") -->
+        <label>+962 (Jordan (Hashemite Kingdom of))</label>
+    </option>
+    <option>
+        <value>+7</value>
+        <!-- _("+7 (Kazakhstan (Republic of))") -->
+        <label>+7 (Kazakhstan (Republic of))</label>
+    </option>
+    <option>
+        <value>+254</value>
+        <!-- _("+254 (Kenya (Republic of))") -->
+        <label>+254 (Kenya (Republic of))</label>
+    </option>
+    <option>
+        <value>+686</value>
+        <!-- _("+686 (Kiribati (Republic of))") -->
+        <label>+686 (Kiribati (Republic of))</label>
+    </option>
+    <option>
+        <value>+82</value>
+        <!-- _("+82 (Korea (Republic of))") -->
+        <label>+82 (Korea (Republic of))</label>
+    </option>
+    <option>
+        <value>+965</value>
+        <!-- _("+965 (Kuwait (State of))") -->
+        <label>+965 (Kuwait (State of))</label>
+    </option>
+    <option>
+        <value>+996</value>
+        <!-- _("+996 (Kyrgyz Republic)") -->
+        <label>+996 (Kyrgyz Republic)</label>
+    </option>
+    <option>
+        <value>+856</value>
+        <!-- _("+856 (Lao People's Democratic Republic)") -->
+        <label>+856 (Lao People's Democratic Republic)</label>
+    </option>
+    <option>
+        <value>+371</value>
+        <!-- _("+371 (Latvia (Republic of))") -->
+        <label>+371 (Latvia (Republic of))</label>
+    </option>
+    <option>
+        <value>+961</value>
+        <!-- _("+961 (Lebanon)") -->
+        <label>+961 (Lebanon)</label>
+    </option>
+    <option>
+        <value>+266</value>
+        <!-- _("+266 (Lesotho (Kingdom of))") -->
+        <label>+266 (Lesotho (Kingdom of))</label>
+    </option>
+    <option>
+        <value>+231</value>
+        <!-- _("+231 (Liberia (Republic of))") -->
+        <label>+231 (Liberia (Republic of))</label>
+    </option>
+    <option>
+        <value>+218</value>
+        <!-- _("+218 (Libya (Socialist People's Libyan Arab Jamahiriya))") -->
+        <label>+218 (Libya (Socialist People's Libyan Arab Jamahiriya))</label>
+    </option>
+    <option>
+        <value>+423</value>
+        <!-- _("+423 (Liechtenstein (Principality of))") -->
+        <label>+423 (Liechtenstein (Principality of))</label>
+    </option>
+    <option>
+        <value>+370</value>
+        <!-- _("+370 (Lithuania (Republic of))") -->
+        <label>+370 (Lithuania (Republic of))</label>
+    </option>
+    <option>
+        <value>+352</value>
+        <!-- _("+352 (Luxembourg)") -->
+        <label>+352 (Luxembourg)</label>
+    </option>
+    <option>
+        <value>+853</value>
+        <!-- _("+853 (Macao, China)") -->
+        <label>+853 (Macao, China)</label>
+    </option>
+    <option>
+        <value>+261</value>
+        <!-- _("+261 (Madagascar (Republic of))") -->
+        <label>+261 (Madagascar (Republic of))</label>
+    </option>
+    <option>
+        <value>+265</value>
+        <!-- _("+265 (Malawi)") -->
+        <label>+265 (Malawi)</label>
+    </option>
+    <option>
+        <value>+60</value>
+        <!-- _("+60 (Malaysia)") -->
+        <label>+60 (Malaysia)</label>
+    </option>
+    <option>
+        <value>+960</value>
+        <!-- _("+960 (Maldives (Republic of))") -->
+        <label>+960 (Maldives (Republic of))</label>
+    </option>
+    <option>
+        <value>+223</value>
+        <!-- _("+223 (Mali (Republic of))") -->
+        <label>+223 (Mali (Republic of))</label>
+    </option>
+    <option>
+        <value>+356</value>
+        <!-- _("+356 (Malta)") -->
+        <label>+356 (Malta)</label>
+    </option>
+    <option>
+        <value>+692</value>
+        <!-- _("+692 (Marshall Islands (Republic of the))") -->
+        <label>+692 (Marshall Islands (Republic of the))</label>
+    </option>
+    <option>
+        <value>+596</value>
+        <!-- _("+596 (Martinique (French Department of))") -->
+        <label>+596 (Martinique (French Department of))</label>
+    </option>
+    <option>
+        <value>+222</value>
+        <!-- _("+222 (Mauritania (Islamic Republic of))") -->
+        <label>+222 (Mauritania (Islamic Republic of))</label>
+    </option>
+    <option>
+        <value>+230</value>
+        <!-- _("+230 (Mauritius (Republic of))") -->
+        <label>+230 (Mauritius (Republic of))</label>
+    </option>
+    <option>
+        <value>+269</value>
+        <!-- _("+269 (Mayotte)") -->
+        <label>+269 (Mayotte)</label>
+    </option>
+    <option>
+        <value>+52</value>
+        <!-- _("+52 (Mexico)") -->
+        <label>+52 (Mexico)</label>
+    </option>
+    <option>
+        <value>+691</value>
+        <!-- _("+691 (Micronesia (Federated States of))") -->
+        <label>+691 (Micronesia (Federated States of))</label>
+    </option>
+    <option>
+        <value>+373</value>
+        <!-- _("+373 (Moldova (Republic of))") -->
+        <label>+373 (Moldova (Republic of))</label>
+    </option>
+    <option>
+        <value>+377</value>
+        <!-- _("+377 (Monaco (Principality of))") -->
+        <label>+377 (Monaco (Principality of))</label>
+    </option>
+    <option>
+        <value>+976</value>
+        <!-- _("+976 (Mongolia)") -->
+        <label>+976 (Mongolia)</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Montserrat)") -->
+        <label>+1 (Montserrat)</label>
+    </option>
+    <option>
+        <value>+212</value>
+        <!-- _("+212 (Morocco (Kingdom of))") -->
+        <label>+212 (Morocco (Kingdom of))</label>
+    </option>
+    <option>
+        <value>+258</value>
+        <!-- _("+258 (Mozambique (Republic of))") -->
+        <label>+258 (Mozambique (Republic of))</label>
+    </option>
+    <option>
+        <value>+95</value>
+        <!-- _("+95 (Myanmar (Union of))") -->
+        <label>+95 (Myanmar (Union of))</label>
+    </option>
+    <option>
+        <value>+264</value>
+        <!-- _("+264 (Namibia (Republic of))") -->
+        <label>+264 (Namibia (Republic of))</label>
+    </option>
+    <option>
+        <value>+674</value>
+        <!-- _("+674 (Nauru (Republic of))") -->
+        <label>+674 (Nauru (Republic of))</label>
+    </option>
+    <option>
+        <value>+977</value>
+        <!-- _("+977 (Nepal)") -->
+        <label>+977 (Nepal)</label>
+    </option>
+    <option>
+        <value>+31</value>
+        <!-- _("+31 (Netherlands (Kingdom of the))") -->
+        <label>+31 (Netherlands (Kingdom of the))</label>
+    </option>
+    <option>
+        <value>+599</value>
+        <!-- _("+599 (Netherlands Antilles)") -->
+        <label>+599 (Netherlands Antilles)</label>
+    </option>
+    <option>
+        <value>+687</value>
+        <!-- _("+687 (New Caledonia (Territoire français d'outre-mer))") -->
+        <label>+687 (New Caledonia (Territoire français d'outre-mer))</label>
+    </option>
+    <option>
+        <value>+64</value>
+        <!-- _("+64 (New Zealand)") -->
+        <label>+64 (New Zealand)</label>
+    </option>
+    <option>
+        <value>+505</value>
+        <!-- _("+505 (Nicaragua)") -->
+        <label>+505 (Nicaragua)</label>
+    </option>
+    <option>
+        <value>+227</value>
+        <!-- _("+227 (Niger (Republic of the))") -->
+        <label>+227 (Niger (Republic of the))</label>
+    </option>
+    <option>
+        <value>+234</value>
+        <!-- _("+234 (Nigeria (Federal Republic of))") -->
+        <label>+234 (Nigeria (Federal Republic of))</label>
+    </option>
+    <option>
+        <value>+683</value>
+        <!-- _("+683 (Niue)") -->
+        <label>+683 (Niue)</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Northern Mariana Islands (Commonwealth of the))") -->
+        <label>+1 (Northern Mariana Islands (Commonwealth of the))</label>
+    </option>
+    <option>
+        <value>+47</value>
+        <!-- _("+47 (Norway)") -->
+        <label>+47 (Norway)</label>
+    </option>
+    <option>
+        <value>+968</value>
+        <!-- _("+968 (Oman (Sultanate of))") -->
+        <label>+968 (Oman (Sultanate of))</label>
+    </option>
+    <option>
+        <value>+92</value>
+        <!-- _("+92 (Pakistan (Islamic Republic of))") -->
+        <label>+92 (Pakistan (Islamic Republic of))</label>
+    </option>
+    <option>
+        <value>+680</value>
+        <!-- _("+680 (Palau (Republic of))") -->
+        <label>+680 (Palau (Republic of))</label>
+    </option>
+    <option>
+        <value>+507</value>
+        <!-- _("+507 (Panama (Republic of))") -->
+        <label>+507 (Panama (Republic of))</label>
+    </option>
+    <option>
+        <value>+675</value>
+        <!-- _("+675 (Papua New Guinea)") -->
+        <label>+675 (Papua New Guinea)</label>
+    </option>
+    <option>
+        <value>+595</value>
+        <!-- _("+595 (Paraguay (Republic of))") -->
+        <label>+595 (Paraguay (Republic of))</label>
+    </option>
+    <option>
+        <value>+51</value>
+        <!-- _("+51 (Peru)") -->
+        <label>+51 (Peru)</label>
+    </option>
+    <option>
+        <value>+63</value>
+        <!-- _("+63 (Philippines (Republic of the))") -->
+        <label>+63 (Philippines (Republic of the))</label>
+    </option>
+    <option>
+        <value>+48</value>
+        <!-- _("+48 (Poland (Republic of))") -->
+        <label>+48 (Poland (Republic of))</label>
+    </option>
+    <option>
+        <value>+351</value>
+        <!-- _("+351 (Portugal)") -->
+        <label>+351 (Portugal)</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Puerto Rico)") -->
+        <label>+1 (Puerto Rico)</label>
+    </option>
+    <option>
+        <value>+974</value>
+        <!-- _("+974 (Qatar (State of))") -->
+        <label>+974 (Qatar (State of))</label>
+    </option>
+    <option>
+        <value>+886</value>
+        <!-- _("+886 (Reserved)") -->
+        <label>+886 (Reserved)</label>
+    </option>
+    <option>
+        <value>+970</value>
+        <!-- _("+970 (Reserved)") -->
+        <label>+970 (Reserved)</label>
+    </option>
+    <option>
+        <value>+875</value>
+        <!-- _("+875 (Reserved - Maritime Mobile Service Applications)") -->
+        <label>+875 (Reserved - Maritime Mobile Service Applications)</label>
+    </option>
+    <option>
+        <value>+876</value>
+        <!-- _("+876 (Reserved - Maritime Mobile Service Applications)") -->
+        <label>+876 (Reserved - Maritime Mobile Service Applications)</label>
+    </option>
+    <option>
+        <value>+877</value>
+        <!-- _("+877 (Reserved - Maritime Mobile Service Applications)") -->
+        <label>+877 (Reserved - Maritime Mobile Service Applications)</label>
+    </option>
+    <option>
+        <value>+969</value>
+        <!-- _("+969 (Reserved - reservation currently under investigation)") -->
+        <label>+969 (Reserved - reservation currently under investigation)</label>
+    </option>
+    <option>
+        <value>+888</value>
+        <!-- _("+888 (Reserved for future global service)") -->
+        <label>+888 (Reserved for future global service)</label>
+    </option>
+    <option>
+        <value>+879</value>
+        <!-- _("+879 (Reserved for national non-commercial purposes)") -->
+        <label>+879 (Reserved for national non-commercial purposes)</label>
+    </option>
+    <option>
+        <value>+999</value>
+        <!-- _("+999 (Reserved for possible future use within the Telecommunications for Disaster Relief (TDR) concept)") -->
+        <label>+999 (Reserved for possible future use within the Telecommunications for Disaster Relief (TDR) concept)</label>
+    </option>
+    <option>
+        <value>+262</value>
+        <!-- _("+262 (Reunion (French Department of))") -->
+        <label>+262 (Reunion (French Department of))</label>
+    </option>
+    <option>
+        <value>+40</value>
+        <!-- _("+40 (Romania)") -->
+        <label>+40 (Romania)</label>
+    </option>
+    <option>
+        <value>+7</value>
+        <!-- _("+7 (Russian Federation)") -->
+        <label>+7 (Russian Federation)</label>
+    </option>
+    <option>
+        <value>+250</value>
+        <!-- _("+250 (Rwanda (Republic of))") -->
+        <label>+250 (Rwanda (Republic of))</label>
+    </option>
+    <option>
+        <value>+290</value>
+        <!-- _("+290 (Saint Helena)") -->
+        <label>+290 (Saint Helena)</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Saint Kitts and Nevis)") -->
+        <label>+1 (Saint Kitts and Nevis)</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Saint Lucia)") -->
+        <label>+1 (Saint Lucia)</label>
+    </option>
+    <option>
+        <value>+508</value>
+        <!-- _("+508 (Saint Pierre and Miquelon (Collectivité territoriale de la République française))") -->
+        <label>+508 (Saint Pierre and Miquelon (Collectivité territoriale de la République française))</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Saint Vincent and the Grenadines)") -->
+        <label>+1 (Saint Vincent and the Grenadines)</label>
+    </option>
+    <option>
+        <value>+685</value>
+        <!-- _("+685 (Samoa (Independent State of))") -->
+        <label>+685 (Samoa (Independent State of))</label>
+    </option>
+    <option>
+        <value>+378</value>
+        <!-- _("+378 (San Marino (Republic of))") -->
+        <label>+378 (San Marino (Republic of))</label>
+    </option>
+    <option>
+        <value>+239</value>
+        <!-- _("+239 (Sao Tome and Principe (Democratic Republic of))") -->
+        <label>+239 (Sao Tome and Principe (Democratic Republic of))</label>
+    </option>
+    <option>
+        <value>+966</value>
+        <!-- _("+966 (Saudi Arabia (Kingdom of))") -->
+        <label>+966 (Saudi Arabia (Kingdom of))</label>
+    </option>
+    <option>
+        <value>+221</value>
+        <!-- _("+221 (Senegal (Republic of))") -->
+        <label>+221 (Senegal (Republic of))</label>
+    </option>
+    <option>
+        <value>+381</value>
+        <!-- _("+381 (Serbia and Montenegro)") -->
+        <label>+381 (Serbia and Montenegro)</label>
+    </option>
+    <option>
+        <value>+248</value>
+        <!-- _("+248 (Seychelles (Republic of))") -->
+        <label>+248 (Seychelles (Republic of))</label>
+    </option>
+    <option>
+        <value>+232</value>
+        <!-- _("+232 (Sierra Leone)") -->
+        <label>+232 (Sierra Leone)</label>
+    </option>
+    <option>
+        <value>+65</value>
+        <!-- _("+65 (Singapore (Republic of))") -->
+        <label>+65 (Singapore (Republic of))</label>
+    </option>
+    <option>
+        <value>+421</value>
+        <!-- _("+421 (Slovak Republic)") -->
+        <label>+421 (Slovak Republic)</label>
+    </option>
+    <option>
+        <value>+386</value>
+        <!-- _("+386 (Slovenia (Republic of))") -->
+        <label>+386 (Slovenia (Republic of))</label>
+    </option>
+    <option>
+        <value>+677</value>
+        <!-- _("+677 (Solomon Islands)") -->
+        <label>+677 (Solomon Islands)</label>
+    </option>
+    <option>
+        <value>+252</value>
+        <!-- _("+252 (Somali Democratic Republic)") -->
+        <label>+252 (Somali Democratic Republic)</label>
+    </option>
+    <option>
+        <value>+27</value>
+        <!-- _("+27 (South Africa (Republic of))") -->
+        <label>+27 (South Africa (Republic of))</label>
+    </option>
+    <option>
+        <value>+34</value>
+        <!-- _("+34 (Spain)") -->
+        <label>+34 (Spain)</label>
+    </option>
+    <option>
+        <value>+94</value>
+        <!-- _("+94 (Sri Lanka (Democratic Socialist Republic of))") -->
+        <label>+94 (Sri Lanka (Democratic Socialist Republic of))</label>
+    </option>
+    <option>
+        <value>+249</value>
+        <!-- _("+249 (Sudan (Republic of the))") -->
+        <label>+249 (Sudan (Republic of the))</label>
+    </option>
+    <option>
+        <value>+597</value>
+        <!-- _("+597 (Suriname (Republic of))") -->
+        <label>+597 (Suriname (Republic of))</label>
+    </option>
+    <option>
+        <value>+268</value>
+        <!-- _("+268 (Swaziland (Kingdom of))") -->
+        <label>+268 (Swaziland (Kingdom of))</label>
+    </option>
+    <option>
+        <value>+46</value>
+        <!-- _("+46 (Sweden)") -->
+        <label>+46 (Sweden)</label>
+    </option>
+    <option>
+        <value>+41</value>
+        <!-- _("+41 (Switzerland (Confederation of))") -->
+        <label>+41 (Switzerland (Confederation of))</label>
+    </option>
+    <option>
+        <value>+963</value>
+        <!-- _("+963 (Syrian Arab Republic)") -->
+        <label>+963 (Syrian Arab Republic)</label>
+    </option>
+    <option>
+        <value>+992</value>
+        <!-- _("+992 (Tajikistan (Republic of))") -->
+        <label>+992 (Tajikistan (Republic of))</label>
+    </option>
+    <option>
+        <value>+255</value>
+        <!-- _("+255 (Tanzania (United Republic of))") -->
+        <label>+255 (Tanzania (United Republic of))</label>
+    </option>
+    <option>
+        <value>+66</value>
+        <!-- _("+66 (Thailand)") -->
+        <label>+66 (Thailand)</label>
+    </option>
+    <option>
+        <value>+389</value>
+        <!-- _("+389 (The Former Yugoslav Republic of Macedonia)") -->
+        <label>+389 (The Former Yugoslav Republic of Macedonia)</label>
+    </option>
+    <option>
+        <value>+228</value>
+        <!-- _("+228 (Togolese Republic)") -->
+        <label>+228 (Togolese Republic)</label>
+    </option>
+    <option>
+        <value>+690</value>
+        <!-- _("+690 (Tokelau)") -->
+        <label>+690 (Tokelau)</label>
+    </option>
+    <option>
+        <value>+676</value>
+        <!-- _("+676 (Tonga (Kingdom of))") -->
+        <label>+676 (Tonga (Kingdom of))</label>
+    </option>
+    <option>
+        <value>+991</value>
+        <!-- _("+991 (Trial of a proposed new international telecommunication public correspondence service, shared code)") -->
+        <label>+991 (Trial of a proposed new international telecommunication public correspondence service, shared code)</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Trinidad and Tobago)") -->
+        <label>+1 (Trinidad and Tobago)</label>
+    </option>
+    <option>
+        <value>+216</value>
+        <!-- _("+216 (Tunisia)") -->
+        <label>+216 (Tunisia)</label>
+    </option>
+    <option>
+        <value>+90</value>
+        <!-- _("+90 (Turkey)") -->
+        <label>+90 (Turkey)</label>
+    </option>
+    <option>
+        <value>+993</value>
+        <!-- _("+993 (Turkmenistan)") -->
+        <label>+993 (Turkmenistan)</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (Turks and Caicos Islands)") -->
+        <label>+1 (Turks and Caicos Islands)</label>
+    </option>
+    <option>
+        <value>+688</value>
+        <!-- _("+688 (Tuvalu)") -->
+        <label>+688 (Tuvalu)</label>
+    </option>
+    <option>
+        <value>+256</value>
+        <!-- _("+256 (Uganda (Republic of))") -->
+        <label>+256 (Uganda (Republic of))</label>
+    </option>
+    <option>
+        <value>+380</value>
+        <!-- _("+380 (Ukraine)") -->
+        <label>+380 (Ukraine)</label>
+    </option>
+    <option>
+        <value>+971</value>
+        <!-- _("+971 (United Arab Emirates)") -->
+        <label>+971 (United Arab Emirates)</label>
+    </option>
+    <option>
+        <value>+44</value>
+        <!-- _("+44 (United Kingdom of Great Britain and Northern Ireland)") -->
+        <label>+44 (United Kingdom of Great Britain and Northern Ireland)</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (United States of America)") -->
+        <label>+1 (United States of America)</label>
+    </option>
+    <option>
+        <value>+1</value>
+        <!-- _("+1 (United States Virgin Islands)") -->
+        <label>+1 (United States Virgin Islands)</label>
+    </option>
+    <option>
+        <value>+878</value>
+        <!-- _("+878 (Universal Personal Telecommunication Service (UPT))") -->
+        <label>+878 (Universal Personal Telecommunication Service (UPT))</label>
+    </option>
+    <option>
+        <value>+598</value>
+        <!-- _("+598 (Uruguay (Eastern Republic of))") -->
+        <label>+598 (Uruguay (Eastern Republic of))</label>
+    </option>
+    <option>
+        <value>+998</value>
+        <!-- _("+998 (Uzbekistan (Republic of))") -->
+        <label>+998 (Uzbekistan (Republic of))</label>
+    </option>
+    <option>
+        <value>+678</value>
+        <!-- _("+678 (Vanuatu (Republic of))") -->
+        <label>+678 (Vanuatu (Republic of))</label>
+    </option>
+    <option>
+        <value>+39</value>
+        <!-- _("+39 (Vatican City State)") -->
+        <label>+39 (Vatican City State)</label>
+    </option>
+    <option>
+        <value>+379</value>
+        <!-- _("+379 (Vatican City State)") -->
+        <label>+379 (Vatican City State)</label>
+    </option>
+    <option>
+        <value>+58</value>
+        <!-- _("+58 (Venezuela (Bolivarian Republic of))") -->
+        <label>+58 (Venezuela (Bolivarian Republic of))</label>
+    </option>
+    <option>
+        <value>+84</value>
+        <!-- _("+84 (Viet Nam (Socialist Republic of))") -->
+        <label>+84 (Viet Nam (Socialist Republic of))</label>
+    </option>
+    <option>
+        <value>+681</value>
+        <!-- _("+681 (Wallis and Futuna (Territoire français d'outre-mer))") -->
+        <label>+681 (Wallis and Futuna (Territoire français d'outre-mer))</label>
+    </option>
+    <option>
+        <value>+967</value>
+        <!-- _("+967 (Yemen (Republic of))") -->
+        <label>+967 (Yemen (Republic of))</label>
+    </option>
+    <option>
+        <value>+260</value>
+        <!-- _("+260 (Zambia (Republic of))") -->
+        <label>+260 (Zambia (Republic of))</label>
+    </option>
+    <option>
+        <value>+263</value>
+        <!-- _("+263 (Zimbabwe (Republic of))") -->
+        <label>+263 (Zimbabwe (Republic of))</label>
+    </option>
+</options>
\ No newline at end of file
index 19cbc67..61793ba 100644 (file)
 <?xml version="1.0" encoding="utf-8"?>
 <application>
     <name>Sipgate</name>
-    <version>1.0</version>
+    <version>2.0</version>
     <order>25</order>
     <depends>
         <application>Admin</application>
         <application>Addressbook</application>
     </depends>
+    <tables>
+        <table>
+            <name>sipgate_account</name>
+            <version>0</version>
+            <declaration>
+                <field>
+                    <name>id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>accounttype</name>
+                    <type>text</type>
+                    <length>10</length>
+                    <notnull>true</notnull>
+                    <default>plus</default>
+                </field>
+                <field>
+                    <name>type</name>
+                    <type>text</type>
+                    <length>10</length>
+                    <notnull>true</notnull>
+                    <default>shared</default>
+                </field>
+                <field>
+                    <name>credential_id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>false</notnull>
+                </field>
+                <field>
+                    <name>description</name>
+                    <type>text</type>
+                    <length>64</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>username</name>
+                    <type>text</type>
+                    <length>64</length>
+                    <notnull>false</notnull>
+                </field>
+                <field>
+                    <name>password</name>
+                    <type>text</type>
+                    <length>64</length>
+                    <notnull>false</notnull>
+                </field>
+                <field>
+                    <name>is_valid</name>
+                    <type>boolean</type>
+                    <default>false</default>
+                </field>
+                <field>
+                    <name>created_by</name>
+                    <type>text</type>
+                    <length>40</length>
+                </field>
+                <field>
+                    <name>creation_time</name>
+                    <type>datetime</type>
+                </field> 
+                <field>
+                    <name>last_modified_by</name>
+                    <type>text</type>
+                    <length>40</length>
+                </field>
+                <field>
+                    <name>last_modified_time</name>
+                    <type>datetime</type>
+                </field>
+                <field>
+                    <name>is_deleted</name>
+                    <type>boolean</type>
+                    <default>false</default>
+                </field>
+                <field>
+                    <name>deleted_by</name>
+                    <type>text</type>
+                    <length>40</length>
+                </field>            
+                <field>
+                    <name>deleted_time</name>
+                    <type>datetime</type>
+                </field>
+                <field>
+                    <name>mobile_number</name>
+                    <type>text</type>
+                    <length>64</length>
+                </field>
+                <index>
+                    <name>id</name>
+                    <primary>true</primary>
+                    <field>
+                        <name>id</name>
+                    </field>
+                </index>
+            </declaration>
+        </table>
+        <table>
+            <name>sipgate_line</name>
+            <version>0</version>
+            <declaration>
+                <field>
+                    <name>id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>account_id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                </field> 
+                <field>
+                    <name>user_id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>false</notnull>
+                </field>
+                <field>
+                    <name>uri_alias</name>
+                    <type>text</type>
+                    <length>256</length>
+                </field>
+                <field>
+                    <name>sip_uri</name>
+                    <type>text</type>
+                    <length>256</length>
+                </field>
+                <field>
+                    <name>e164_out</name>
+                    <type>text</type>
+                    <length>256</length>
+                </field>
+                <field>
+                    <name>e164_in</name>
+                    <type>text</type>
+                    <length>256</length>
+                </field>
+                <field>
+                    <name>tos</name>
+                    <type>text</type>
+                    <length>10</length>
+                </field>
+                <field>
+                    <name>creation_time</name>
+                    <type>datetime</type>
+                </field>
+                <field>
+                    <name>last_sync</name>
+                    <type>datetime</type>
+                </field>
+                <index>
+                    <name>id</name>
+                    <primary>true</primary>
+                    <field>
+                        <name>id</name>
+                    </field>
+                </index>
+                <index>
+                    <name>sipgate_line::account_id--sipgate_account::id</name>
+                    <field>
+                        <name>account_id</name>
+                    </field>
+                    <foreign>true</foreign>
+                    <reference>
+                        <table>sipgate_account</table>
+                        <field>id</field>
+                    </reference>
+                </index>
+                <index>
+                    <name>sipgate_line::user_id--sipgate_user::id</name>
+                    <field>
+                        <name>user_id</name>
+                    </field>
+                    <foreign>true</foreign>
+                    <reference>
+                        <table>accounts</table>
+                        <field>id</field>
+                    </reference>
+                </index>
+            </declaration>
+        </table>
+        <table>
+            <name>sipgate_connection</name>
+            <version>0</version>
+            <declaration>
+                <field>
+                    <name>id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>entry_id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>tos</name>
+                    <type>text</type>
+                    <length>10</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>local_uri</name>
+                    <type>text</type>
+                    <length>256</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>remote_uri</name>
+                    <type>text</type>
+                    <length>256</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>local_number</name>
+                    <type>text</type>
+                    <length>128</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>remote_number</name>
+                    <type>text</type>
+                    <length>128</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>status</name>
+                    <type>text</type>
+                    <length>8</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>line_id</name>
+                    <type>text</type>
+                    <length>40</length>
+                </field>
+                <field>
+                    <name>timestamp</name>
+                    <type>datetime</type>
+                </field>
+                <field>
+                    <name>creation_time</name>
+                    <type>datetime</type>
+                </field> 
+                <field>
+                    <name>tarif</name>
+                    <type>text</type>
+                    <length>256</length>
+                </field>
+                <field>
+                    <name>duration</name>
+                    <type>integer</type>
+                </field>
+                <field>
+                    <name>units_charged</name>
+                    <type>integer</type>
+                </field>
+                <field>
+                    <name>price_unit</name>
+                    <type>float</type>
+                </field>
+                <field>
+                    <name>price_total</name>
+                    <type>float</type>
+                </field>
+                <field>
+                    <name>ticks_a</name>
+                    <type>integer</type>
+                    <length>3</length>
+                </field>
+                <field>
+                    <name>ticks_b</name>
+                    <type>integer</type>
+                    <length>3</length>
+                </field>
+                <field>
+                    <name>contact_id</name>
+                    <type>text</type>
+                    <length>40</length>
+                </field>
+                <field>
+                    <name>contact_name</name>
+                    <type>text</type>
+                    <length>128</length>
+                    <notnull>false</notnull>
+                </field>
+                <index>
+                    <name>id</name>
+                    <primary>true</primary>
+                    <field>
+                        <name>id</name>
+                    </field>
+                </index>
+                <index>
+                    <name>entry_id</name>
+                    <field>
+                        <name>entry_id</name>
+                    </field>
+                </index>
+                <index>
+                    <name>creation_time</name>
+                    <field>
+                        <name>creation_time</name>
+                    </field>
+                </index>
+                <index>
+                    <name>timestamp</name>
+                    <field>
+                        <name>timestamp</name>
+                    </field>
+                </index>                
+                <index>
+                    <name>connection::contact_id--contact::id</name>
+                    <field>
+                        <name>contact_id</name>
+                    </field>
+                    <foreign>true</foreign>
+                    <reference>
+                        <table>addressbook</table>
+                        <field>id</field>
+                    </reference>
+                </index>
+                <index>
+                    <name>connection::line_id--line::id</name>
+                    <field>
+                        <name>line_id</name>
+                    </field>
+                    <foreign>true</foreign>
+                    <reference>
+                        <table>sipgate_line</table>
+                        <field>id</field>
+                    </reference>
+                </index>
+            </declaration>
+        </table>
+    </tables>
 </application>
\ No newline at end of file
index 196e434..6cc82aa 100644 (file)
           "path": "js/"
         },
         {
+          "text": "Models.js",
+          "path": "js/"
+        },
+        {
+          "text": "LineSearchCombo.js",
+          "path": "js/"
+        },
+        {
+          "text": "ExceptionHandler.js",
+          "path": "js/"
+        },
+        {
+          "text": "AccountFilterModel.js",
+          "path": "js/"
+        },
+        {
+          "text": "AccountGridPanel.js",
+          "path": "js/"
+        },
+        {
+          "text": "LineFilterModel.js",
+          "path": "js/"
+        },
+        {
+          "text": "LineGridPanel.js",
+          "path": "js/"
+        },
+        {
+          "text": "AccountEditDialog.js",
+          "path": "js/"
+        },
+        {
+          "text": "ConnectionGridPanel.js",
+          "path": "js/"
+        },
+        {
           "text": "AddressbookGridPanelHook.js",
           "path": "js/"
         },
         {
+          "text": "AssignLinesGrid.js",
+          "path": "js/"
+        },
+        {
           "text": "SearchAddressDialog.js",
           "path": "js/"
         },     
index 6c52c41..7d13480 100644 (file)
@@ -8,36 +8,60 @@
  *
  */
 
-.SipgateIconCls {background-image:url("../../images/oxygen/16x16/apps/kcall.png") !important;}
+.SipgateConnection, .SipgateIconCls {background-image:url("../../images/oxygen/16x16/apps/kcall.png") !important;}
+.SipgateLine {background-image:url("../../images/oxygen/16x16/devices/network-wired.png") !important;}
+.SipgateAccount {background-image:url("../../images/oxygen/16x16/categories/preferences-system-network.png") !important;}
 .x-btn-medium .SipgateIconCls {background-image:url("../../images/oxygen/22x22/apps/kcall.png") !important;}
 .x-btn-large .SipgateIconCls {background-image:url("../../images/oxygen/32x32/apps/kcall.png") !important;}
+/*
+.SipgateTreeNode_fax {background-image:url("../../images/../Sipgate/res/16x16/kfax.png") !important; height: 16px; width: 16px}
+.SipgateTreeNode_voice {background-image:url("../../images/oxygen/16x16/apps/kcall.png") !important; height: 16px; width: 16px}
+*/
+/* 
+.SipgateGridLineType_fax, .SipgateGridLineType_voice {display:inline-block; margin: -1px; height: 14px; width: 20px; background-position: 0 -2px; background-repeat: no-repeat}
+.SipgateGridLineType_fax {background-image:url("../../images/../Sipgate/res/16x16/kfax.png") !important;}
+.SipgateGridLineType_voice {background-image:url("../../images/oxygen/16x16/apps/kcall.png") !important;}
 
-.SipgateTreeNode_fax {background-image:url("../../images/../Sipgate/res/16x16/kfax.png") !important;}
-.SipgateTreeNode_phone {background-image:url("../../images/oxygen/16x16/apps/kcall.png") !important;}
-
+ */
+ .action_Validate {background-image:url("../../images/oxygen/16x16/actions/tools-wizard.png") !important;}
+.action_ValidateSuccessful {background-image:url("../../images/oxygen/16x16/actions/games-solve.png") !important;}
+.action_Save {background-image:url("../../images/oxygen/16x16/actions/dialog-ok-apply.png") !important;}
 
-.SipgateCallStatePhone {background-image:url("../../images/../Sipgate/res/phone-connecting.png") !important;margin:13px}
+.action_Sync {
+    background-image:url("../../images/oxygen/16x16/actions/view-refresh.png") !important;
+}
+.x-btn-medium .action_Sync {
+    background-image:url("../../images/oxygen/22x22/actions/view-refresh.png") !important;
+} 
+.x-btn-large .action_Sync {
+    background-image:url("../../images/oxygen/32x32/actions/view-refresh.png") !important;
+} 
+.SipgateCallStatePhone {background-repeat: no-repeat;background-image:url("../../images/../Sipgate/res/phone-connecting.png") !important;}
 .SipgateCallStatePhone.established  {background-image:url("../../images/../Sipgate/res/phone-connected.png") !important}
 .SipgateCallStatePhone.error  {background-image:url("../../images/../Sipgate/res/phone-error.png") !important}
 
 .SipgateSendSms {height:100%;width:100%;background-repeat:no-repeat;background-position:right bottom;}
 .SipgateSendSms.ok {background-image:url("../../images/../Sipgate/res/phone-connected.png") !important}
 .SipgateSendSms.error {background-image:url("../../images/../Sipgate/res/phone-error.png") !important}
-
+/* 
 .SipgateCallStateList {height:12px;width:24px}
 .SipgateCallStateList.missed {background-image:url("../../images/../Sipgate/res/call_missed.png") !important}
 .SipgateCallStateList.accepted {background-image:url("../../images/../Sipgate/res/call_accepted.png") !important}
 .SipgateCallStateList.outgoing {background-image:url("../../images/../Sipgate/res/call_outgoing.png") !important}
+ */
+.SipgateAssignUsers {background-image:url("../../images/oxygen/16x16/actions/add-users.png") !important;}
 
+.action_AddNumber {
+    background-image: url("../../images/oxygen/16x16/apps/kaddressbook.png") !important;
+    }
 
-#csw-my-phone, #csw-line {float:left}
-#csw-other-phone {float:right;}
-#csw-line {}
-#csw-call-info{text-align: center;padding-top:10px}
+.x-btn-medium .action_AddNumber {
+    background-image: url("../../images/oxygen/22x22/apps/kaddressbook.png") !important;
+    }
 
-.action_AddNumber {
-       background-image:url("../../images/oxygen/16x16/apps/kaddressbook.png") !important;
-       }
+.x-btn-large .action_AddNumber {
+    background-image: url("../../images/oxygen/32x32/apps/kaddressbook.png") !important;
+    }
 
 .action_DialNumber {
     background-image:url("../../images/oxygen/16x16/devices/audio-headset.png") !important;
diff --git a/tine20/Sipgate/js/AccountEditDialog.js b/tine20/Sipgate/js/AccountEditDialog.js
new file mode 100644 (file)
index 0000000..ee3e1a3
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Tine 2.0
+ * 
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <a.stintzing@metaways.de>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ *
+ */
+Ext.namespace('Tine.Sipgate');
+
+/**
+ * Account edit dialog
+ * 
+ * @namespace   Tine.Sipgate
+ * @class       Tine.Sipgate.AccountEditDialog
+ * @extends     Tine.widgets.dialog.EditDialog
+ */
+Tine.Sipgate.AccountEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
+    /**
+     * @private
+     */
+    labelAlign: 'side',
+    
+    /**
+     * @private
+     */
+    windowNamePrefix: 'AccountEditWindow_',
+    appName: 'Sipgate',
+    recordClass: Tine.Sipgate.Model.Account,
+    recordProxy: Tine.Sipgate.accountBackend,
+    
+    evalGrants: false,
+    
+    lineGridPanel: null,
+    
+    toggleFields: ['type', 'accounttype', 'username', 'password', 'password_repeat'],
+    credentialFields: ['username','password','password_repeat'],
+    
+    onRender: function(ct, position) {
+        Tine.Sipgate.AccountEditDialog.superclass.onRender.call(this, ct, position);
+        this.validateMask = new Ext.LoadMask(ct, {msg: this.app.i18n._('Validating account...')});
+        this.syncMask = new Ext.LoadMask(ct, {msg: this.app.i18n._('Synchronizing lines...')});
+    },
+    
+    initButtons: function() {
+        this.fbar = [
+            '->',
+            this.action_validateAccount,
+            this.action_saveAccount,
+            this.action_syncAccount,
+            this.action_cancel,
+            this.action_saveAndClose
+       ];
+    },
+    
+    initActions: function() {
+        this.action_saveAccount = new Ext.Action({
+            text: this.app.i18n._('Save Account'),
+            allowMultiple: false,
+            tooltip : this.app.i18n._('Saves the account (without closing window)'),
+            handler : this.onSaveAccount,
+            iconCls : 'action_Save',
+            scope : this
+        });
+        this.action_syncAccount = new Ext.Action({
+            text: this.app.i18n._('Synchronize Lines'),
+            allowMultiple: false,
+            tooltip : this.app.i18n._('Synchronizes the selected account (creates or updates the associated lines)'),
+            handler : this.onSyncAccount,
+            iconCls : 'action_Sync',
+            scope : this
+        });
+        this.action_validateAccount = new Ext.Action({
+            text: this.app.i18n._('Validate Account'),
+            allowMultiple: false,
+            tooltip : this.app.i18n._('Validates the selected account (creates or updates the associated lines)'),
+            handler : this.onValidateAccount,
+            iconCls : 'action_Validate',
+            disabledClass: 'action_ValidateSuccessful',
+            scope : this
+        });
+        Tine.Sipgate.AccountEditDialog.superclass.initActions.call(this);
+    },
+    
+    onSyncAccount: function() {
+        if (this.record.get('created_by')) {
+            if(this.isValid(null)) {
+                this.syncMask.show();
+                this.recordProxy.syncLines(this.record.get('id'), this.onSyncSuccess, this.onRequestFailed, this);
+            }
+        } else {
+            Ext.Msg.show({
+               title:   this.app.i18n._('The account is not saved already!'),
+               msg:     this.app.i18n._('Please save yout account before syncing!'),
+               icon:    Ext.MessageBox.INFO,
+               buttons: Ext.Msg.OK
+            });
+        }
+    },
+    
+    onSyncSuccess: function(record) {
+        this.lineGridPanel.enable();
+        this.record = record;
+        this.lineGridPanel.onRecordLoad();
+        if(this.syncMask) this.syncMask.hide();
+        Ext.Msg.show({
+               title:   this.app.i18n._('The lines have been synced sucessfully!'),
+               msg:     String.format(this.app.i18n._('The account has now {0} lines. Go on assigning user accounts to the new lines in the next tab.'), record.get('lines').length),
+               icon:    Ext.MessageBox.INFO,
+               buttons: Ext.Msg.OK
+            });
+    },
+    
+    onSaveAccount: function() {
+        if(this.isValid(null, true)) {
+            Tine.Sipgate.AccountEditDialog.superclass.onApplyChanges.call(this, null, null, false);
+        }
+    },
+    
+    onValidateAccount: function() {
+        if(this.isValid(true)) {
+            this.validateMask.show();
+            this.onRecordUpdate();
+            this.recordProxy.validateAccount(this.record, this.onValidateSuccess, this.onRequestFailed, this);
+        } else {
+            Ext.MessageBox.alert(_('Errors'), this.getValidationErrorMessage());
+        }
+        
+    },
+    
+    onValidateSuccess: function() {
+        this.record.set('is_valid', true);
+        this.setValidated(true);
+        this.validateMask.hide();
+    },
+    
+    resetValidated: function(manual) {
+        this.getForm().findField('is_valid').setValue(0);
+        this.getForm().findField('is_valid').disable();
+        
+        Ext.each(this.credentialFields, function(fieldname) {
+                this.getForm().findField(fieldname).allowBlank = false;
+            }, this);
+
+        Ext.each(this.toggleFields, function(fieldname) {
+            this.getForm().findField(fieldname).enable();
+        }, this);
+        
+        this.action_validateAccount.enable();
+        this.action_validateAccount.setIconClass('action_Validate');
+    },
+    
+    setValidated: function(s) {
+        if(s) {
+            Ext.each(this.credentialFields, function(fieldname) {
+                this.getForm().findField(fieldname).allowBlank = true;
+                this.getForm().findField(fieldname).reset();
+            }, this);
+        }
+        this.getForm().findField('is_valid').setValue(1);
+        Ext.each(this.toggleFields, function(fieldname) {
+            this.getForm().findField(fieldname).disable();
+        }, this);
+        this.getForm().findField('is_valid').enable();
+        this.action_validateAccount.disable();
+        this.action_validateAccount.setIconClass('action_ValidateSuccessful');
+    },
+
+    onRecordUpdate: function() {
+        // update record from form only when not validated
+        if(! this.getForm().findField('is_valid').getValue()) {
+            Tine.Sipgate.AccountEditDialog.superclass.onRecordUpdate.call(this);
+        } else { // sync lines, when validated already
+            if(this.lineGridPanel.store) {
+                var lines = [];
+                this.lineGridPanel.store.purgeListeners();
+                this.lineGridPanel.store.each(function(record) {
+                    record.set('account_id', this.record.get('id'));
+                    record.set('user_id', record.get('user_id') ? record.get('user_id').accountId : null);
+                    lines.push(record.data);
+                }, this);
+                this.record.set('lines', lines);
+                this.record.set('mobile_number', this.getForm().findField('mobile_number').getValue());
+                this.record.set('description',   this.getForm().findField('description').getValue());
+            }
+        }
+    },
+    
+    onRecordLoad: function() {
+        if (! this.rendered) {
+            this.onRecordLoad.defer(250, this);
+            return;
+        }
+       
+        Tine.Sipgate.AccountEditDialog.superclass.onRecordLoad.call(this);
+        if(!this.record.get('is_valid')) {
+            this.resetValidated();
+        } else {
+            this.setValidated(true);
+        }
+        
+        if(this.record.get('lines') && this.record.get('lines').length > 0) {
+            this.lineGridPanel.onRecordLoad();
+        } else {
+            this.lineGridPanel.disable();
+        }
+    },
+    
+    onRequestFailed: function(exception) {
+        this.resetValidated();
+        this.validateMask.hide();
+        this.syncMask.hide();
+        if(this.loadMask) this.loadMask.hide();
+        Tine.Sipgate.handleRequestException(exception);
+    },
+    
+    /**
+     * returns dialog
+     * 
+     * NOTE: when this method gets called, all initalisation is done.
+     */
+    getFormItems: function() {
+        
+        this.lineGridPanel = new Tine.Sipgate.AssignLinesGrid({app: this.app, editDialog: this});
+        
+        return {
+            xtype: 'tabpanel',
+            border: false,
+            plain:true,
+            activeTab: 0,
+            border: false,
+            plugins: [{
+                ptype : 'ux.tabpanelkeyplugin'
+            }],
+            items:[
+                {
+                title: this.app.i18n.n_('Account', 'Account', 1),
+                autoScroll: true,
+                border: false,
+                frame: true,
+                layout: 'border',
+                items: [{
+                    region: 'center',
+                    xtype: 'columnform',
+                    labelAlign: 'top',
+                    formDefaults: {
+                        xtype:'textfield',
+                        anchor: '100%',
+                        labelSeparator: '',
+                        columnWidth: .333,
+                        allowBlank: false
+                    },
+                    items: [[
+                        { 
+                            fieldLabel: this.app.i18n._('Description'),
+                            name: 'description'
+                        }, 
+                        new Tine.Tinebase.widgets.keyfield.ComboBox({
+                                fieldLabel: this.app.i18n._('Account Type'),
+                                name: 'accounttype',
+                                app: 'Sipgate',
+                                value: 'plus',
+                                keyFieldName: 'accountAccountType',
+                                listeners: {
+                                    scope: this,
+                                    select: function(combo,b,c) {
+                                        if(combo.getValue() == 'team') {
+                                            this.getForm().findField('mobile_number').disable();
+                                        } else {
+                                            this.getForm().findField('mobile_number').enable();
+                                        }
+                                    }
+                                }
+                        }),
+                        new Tine.Tinebase.widgets.keyfield.ComboBox({
+                                fieldLabel: this.app.i18n._('Type'),
+                                name: 'type',
+                                value: 'shared',
+                                app: 'Sipgate',
+                                keyFieldName: 'accountType'
+                        })], [{
+                            name: 'mobile_number',
+                            fieldLabel: this.app.i18n._('Mobile Number')
+                        }], 
+                        [{
+                            fieldLabel: this.app.i18n._('Sipgate Username'),
+                            name: 'username',
+                            emptyText: this.app.i18n._('Hidden due to security reasons.')
+                        }, {
+                            fieldLabel: this.app.i18n._('Password'),
+                            name: 'password',
+                            inputType:'password'
+                        }, {
+                            fieldLabel: this.app.i18n._('Passwort Repeat'),
+                            name: 'password_repeat',
+                            inputType:'password'
+                        }], [{ 
+                            xtype: 'checkbox',
+                            name: 'is_valid',
+                            fieldLabel: this.app.i18n._('Is Validated'),
+                            listeners: {
+                                scope:this,
+                                check: function(check) {
+                                    if (check.getValue() == false) {
+                                        this.resetValidated(1);
+                                    }
+                                }
+                            }
+                        }
+                        ]] 
+                }]
+            }, this.lineGridPanel
+            ]
+        };
+    },
+    
+    isValid: function(calledFromOnValidate) {
+        var isValid = true;
+        if(!this.record.get('is_valid')) {
+            isValid = isValid & Tine.Sipgate.AccountEditDialog.superclass.isValid.call(this);
+            
+            if(this.getForm().findField('password').getValue() != this.getForm().findField('password_repeat').getValue()) {
+                this.getForm().findField('password').markInvalid('The Fields "Password" and "Password Repeat" must have the same values!');
+                this.getForm().findField('password_repeat').markInvalid('The Fields "Password" and "Password Repeat" must have the same values!');
+                isValid = false;
+            }
+            if(this.getForm().findField('username').getValue() != this.usernameEmptyText) {
+                if(this.getForm().findField('username').getValue() == '') {
+                    this.getForm().findField('username').markInvalid();
+                    isValid = false;
+                }
+            }
+        } else {
+            isValid = true;
+        }
+        if(!calledFromOnValidate && isValid) {
+            if(!this.getForm().findField('is_valid').getValue()) {
+                Ext.MessageBox.alert(_('Errors'), this.app.i18n._('Please validate the account settings before saving!'));
+                isValid = false;
+            }
+        }
+        return isValid;
+    }
+});
+
+/**
+ * Sipgate Edit Popup
+ */
+Tine.Sipgate.AccountEditDialog.openWindow = function (config) {
+    var window = Tine.WindowFactory.getWindow({
+        width: 800,
+        height: 470,
+        name: Tine.Sipgate.AccountEditDialog.prototype.windowNamePrefix + Ext.id(),
+        contentPanelConstructor: 'Tine.Sipgate.AccountEditDialog',
+        contentPanelConstructorConfig: config
+    });
+    return window;
+};
diff --git a/tine20/Sipgate/js/AccountFilterModel.js b/tine20/Sipgate/js/AccountFilterModel.js
new file mode 100644 (file)
index 0000000..4a88bd2
--- /dev/null
@@ -0,0 +1,47 @@
+/**
+ * Tine 2.0
+ * 
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+Ext.ns('Tine.Sipgate');
+
+Tine.Sipgate.AccountFilterModel = Ext.extend(Tine.widgets.grid.ForeignRecordFilter, {
+    
+    /**
+     * @cfg {Record} foreignRecordClass needed for explicit defined filters
+     */
+    foreignRecordClass : Tine.Sipgate.Model.Account,
+    ownRecordClass: Tine.Sipgate.Model.Line,
+    /**
+     * @cfg {String} linkType {relation|foreignId} needed for explicit defined filters
+     */
+    linkType: 'foreignId',
+    
+    /**
+     * @cfg {String} filterName server side filterGroup Name, needed for explicit defined filters
+     */
+    filterName: 'AccountFilter',
+    
+    /**
+     * @cfg {String} ownField for explicit filterRow
+     */
+    ownField: 'account_id',
+    /**
+     * @private
+     */
+    initComponent: function() {
+        this.app = Tine.Tinebase.appMgr.get('Sipgate');
+        this.label = this.app.i18n._('Account');
+        
+        this.pickerConfig = this.pickerConfig || {};
+        Ext.applyIf(this.pickerConfig, {showClosed: true});
+        
+        Tine.Sipgate.AccountFilterModel.superclass.initComponent.call(this);
+    }
+});
+
+Tine.widgets.grid.FilterToolbar.FILTERS['sipgate.account'] = Tine.Sipgate.AccountFilterModel;
\ No newline at end of file
diff --git a/tine20/Sipgate/js/AccountGridPanel.js b/tine20/Sipgate/js/AccountGridPanel.js
new file mode 100644 (file)
index 0000000..f19d905
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Tine 2.0
+ * 
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+Ext.ns('Tine.Sipgate');
+
+/**
+ * Account grid panel
+ * 
+ * @namespace   Tine.Sipgate
+ * @class       Tine.Sipgate.GridPanel
+ * @extends     Tine.widgets.grid.GridPanel
+ * 
+ * <p>Account Grid Panel</p>
+ * <p><pre>
+ * </pre></p>
+ * 
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * 
+ * @param       {Object} config
+ * @constructor
+ * Create a new Tine.Sipgate.GridPanel
+ */
+Tine.Sipgate.AccountGridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
+    /**
+     * record class
+     * @cfg {Tine.Sipgate.Model.Account} recordClass
+     */
+    recordClass: Tine.Sipgate.Model.Account,
+    evalGrants: false,
+    /**
+     * grid specific
+     * @private
+     */
+    defaultSortInfo: {field: 'accounttype', direction: 'DESC'},
+    gridConfig: {
+        autoExpandColumn: 'description'
+    },
+    /**
+     * possible TOS
+     * @type {Object}
+     */
+    lineTypes: null,
+    /**
+     * inits this cmp
+     * @private
+     */
+    initComponent: function() {
+        this.lineTypes = {
+            voice:  this.app.i18n._('Telephone'),
+            fax:    this.app.i18n._('Fax')
+        };
+        this.recordProxy = Tine.Sipgate.accountBackend;
+        this.gridConfig.columns = this.getColumns();
+        
+        this.initFilterToolbar();
+        this.plugins.push(this.filterToolbar);
+        
+        Tine.Sipgate.AccountGridPanel.superclass.initComponent.call(this);
+    },
+    
+    /**
+     * initializes filter toolbar
+     */
+    initFilterToolbar: function() {
+        this.filterToolbar = new Tine.widgets.grid.FilterToolbar({
+            filterModels: Tine.Sipgate.Model.Account.getFilterModel(),
+            defaultFilter: 'query',
+            filters: [],
+            plugins: [
+                new Tine.widgets.grid.FilterToolbarQuickFilterPlugin()
+            ]
+        });
+    },  
+    
+    /**
+     * returns cm
+     * 
+     * @return Ext.grid.ColumnModel
+     * @private
+     */
+    getColumns: function(){
+        return [{
+                id : 'type',
+                header : this.app.i18n._('Type'),
+                dataIndex : 'type',
+                sortable: true,
+                hidden: false,
+                renderer: Tine.Tinebase.widgets.keyfield.Renderer.get('Sipgate', 'accountType'),
+                scope: this,
+                width: 100
+            }, {
+                id : 'accounttype',
+                header : this.app.i18n._('Account Type'),
+                dataIndex : 'accounttype',
+                sortable: true,
+                hidden: false,
+                renderer: Tine.Tinebase.widgets.keyfield.Renderer.get('Sipgate', 'accountAccountType'),
+                scope: this,
+                width: 100
+            }, {
+                id : 'mobile_number',
+                header : this.app.i18n._('Mobile Number'),
+                dataIndex : 'mobile_number',
+                sortable: true,
+                hidden: false,
+                scope: this,
+                width: 100
+            }, {
+                id : 'description',
+                header : this.app.i18n._('Uri Alias'),
+                dataIndex : 'description',
+                sortable: true,
+                hidden : false
+            }].concat(this.getModlogColumns());
+    },
+    
+    initActions: function() {
+        this.actions_dialNumber = new Ext.Action({
+            text : this.app.i18n._('Dial number'),
+            tooltip : this.app.i18n._('Initiates a new outgoing call'),
+            handler : this.onDialPhoneNumber,
+            iconCls : 'action_DialNumber',
+            scope : this
+        });
+        Tine.Sipgate.AccountGridPanel.superclass.initActions.call(this);
+    },
+    
+    getActionToolbarItems: function() {
+        return [
+            Ext.apply(new Ext.Button(this.actions_dialNumber), {
+                scale: 'medium',
+                rowspan: 2,
+                iconAlign: 'top'
+            })
+        ];
+    },
+    /**
+     * opens the dial number dialog 
+     */
+    onDialPhoneNumber: function() {
+        var lineId = Tine.Sipgate.registry.get('preferences').get('phoneId');
+        Tine.Sipgate.DialNumberDialog.openWindow({lineId: lineId});
+    }
+});
index 69b1074..c8ab960 100644 (file)
@@ -55,7 +55,6 @@ Tine.Sipgate.AddressbookGridPanelHook = function(config) {
 
 
     Ext.ux.ItemRegistry.registerItem('Addressbook-GridPanel-ActionToolbar-leftbtngrp', this.callContactBtn, 30);
-//    Ext.ux.ItemRegistry.registerItem('Addressbook-GridPanel-ContextMenu', '-', 120);
     Ext.ux.ItemRegistry.registerItem('Addressbook-GridPanel-ContextMenu', this.callContactAction, 130);
      
     this.composeSmsAction = new Ext.Action({
@@ -118,7 +117,7 @@ Ext.apply(Tine.Sipgate.AddressbookGridPanelHook.prototype, {
      * @type Ext.Button
      * @private
      */
-    composeSmsBtn: null,    
+    composeSmsBtn: null,
     
     /**
      * @property ContactGridPanel
@@ -139,7 +138,7 @@ Ext.apply(Tine.Sipgate.AddressbookGridPanelHook.prototype, {
      * @type Ext.menu.Menu
      * @private
      */
-    smsMenu: null,    
+    smsMenu: null,
     
     /**
      * get addressbook contact grid panel
@@ -176,8 +175,12 @@ Ext.apply(Tine.Sipgate.AddressbookGridPanelHook.prototype, {
         } else if (!Ext.isEmpty(contact.data.tel_home)) {
             number = contact.data.tel_home;
         }
-
-        Tine.Sipgate.dialPhoneNumber(number,contact);
+        var lineId = Tine.Sipgate.registry.get('preferences').get('phoneId');
+        if(lineId) {
+            Tine.Sipgate.lineBackend.dialNumber(lineId, number, contact);
+        } else {
+            Tine.Sipgate.DialNumberDialog.openWindow({number: number, contact: contact});
+        }
     },
 
     /**
@@ -207,6 +210,7 @@ Ext.apply(Tine.Sipgate.AddressbookGridPanelHook.prototype, {
         }
         
         var popUpWindow = Tine.Sipgate.SmsEditDialog.openWindow({
+            contact: contact,
             number: number
         });
         
diff --git a/tine20/Sipgate/js/AssignLinesGrid.js b/tine20/Sipgate/js/AssignLinesGrid.js
new file mode 100644 (file)
index 0000000..9ba2094
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Tine 2.0
+ * 
+ * @package     Crm
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2009-2010 Metaways Infosystems GmbH (http://www.metaways.de)
+ *
+ */
+
+Ext.namespace('Tine.Sipgate');
+
+/**
+ * admin settings panel
+ * 
+ * @namespace   Tine.Sipgate
+ * @class       Tine.Sipgate.AssignLinesGrid
+ * @extends     Ext.grid.EditorGridPanel
+ * 
+ * <p>Sipgate Assign Accounts Panel</p>
+ * 
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2009-2010 Metaways Infosystems GmbH (http://www.metaways.de)
+ * 
+ * Create a new Tine.Sipgate.AssignLinesGrid
+ */
+Tine.Sipgate.AssignLinesGrid = Ext.extend(Ext.grid.EditorGridPanel, {
+
+    frame: true,
+    border: true,
+    autoScroll: true,
+    layout: 'fit',
+    clicksToEdit: 1,
+    mode: 'local',
+    
+    defaultSortInfo: {field: 'sip_uri', direction: 'ASC'},
+    autoExpandColumn: 'e164_in',
+    
+    recordClass: Tine.Sipgate.Model.Line,
+    recordProxy: Tine.Sipgate.lineBackend,
+    /*
+     * config
+     */
+    app: null,
+    editDialog: null,
+    store: null,
+    
+    initComponent: function() {
+        if (!this.app) {
+            this.app = Tine.Tinebase.appMgr.get(this.appName);
+        }
+        
+        this.on('afteredit', this.onAfterRowEdit, this);
+
+        this.title = this.app.i18n._('Assign Lines');
+        this.cm = this.getColumnModel();
+        Tine.Sipgate.AssignLinesGrid.superclass.initComponent.call(this);
+    },
+    
+    onClose: function() {
+        this.fireEvent('cancel');
+        this.purgeListeners();
+        this.window.close();
+    },
+    
+    onRecordLoad: function() {
+        if(! this.store) {
+            this.store = new Tine.Tinebase.data.RecordStore({
+                recordProxy: this.recordProxy,
+                recordClass: this.recordClass,
+                autoSave: false
+            }, this);
+        } else {
+            this.store.removeAll(true);
+        }
+
+        Ext.each(this.editDialog.record.get('lines'), function(ar) {
+            this.store.add(new Tine.Sipgate.Model.Line(ar));
+        }, this);
+    },
+
+    
+    
+    /**
+     * returns column model
+     * 
+     * @return Ext.grid.ColumnModel
+     * @private
+     */
+    getColumnModel: function() {
+        return new Ext.grid.ColumnModel({
+            defaults: {
+                sortable: false,
+                width: 160
+            }, 
+            columns: [
+                { id: 'id', header: this.app.i18n._('Id'), dataIndex: 'id', hidden: true },
+                { id: 'tos', header: this.app.i18n._('Type'), dataIndex: 'tos', width: 100, renderer: Tine.Tinebase.widgets.keyfield.Renderer.get('Sipgate', 'connectionTos') },
+                { id: 'uri_alias', header: this.app.i18n._('Uri Alias'), dataIndex: 'uri_alias' },
+                { id: 'sip_uri', header: this.app.i18n._('Sip Uri'), dataIndex: 'sip_uri' },
+                { id: 'e164_out', header: this.app.i18n._('Outgoing'), dataIndex: 'e164_out', width: 100, disabled: true},
+                { id: 'e164_in', header: this.app.i18n._('Incoming'), dataIndex: 'e164_in', width: 100, disabled: true, 
+                  renderer: Tine.Sipgate.common.renderE164In
+                  },
+                { id: 'user_id', dataIndex: 'user_id', header: this.app.i18n._('Assigned User'), renderer: Tine.Tinebase.common.accountRenderer,
+                  scope: this, editor: Tine.widgets.form.RecordPickerManager.get('Addressbook', 'Contact', {
+                    useAccountRecord: true,
+                    userOnly: true,
+                    blurOnSelect: true,
+                    listeners: {
+                        scope: this,
+                        select: this.onChange
+                    }
+                    })
+                }
+           ]
+       });
+    },
+
+    onChange: function(combo) {
+        this.lastSelectedRecord = combo.selectedRecord;
+    },
+    
+    onAfterRowEdit: function(o) {
+        if(!this.lastSelectedRecord) {
+            this.onAfterRowEdit.defer(100, this, [o]);
+            return;
+        }
+
+        var accountStruct =  {
+            accountId: this.lastSelectedRecord.get('account_id'),
+            accountDisplayName: this.lastSelectedRecord.get('n_fileas'),
+            accountFullName: this.lastSelectedRecord.get('n_fn'),
+            accountLastName: this.lastSelectedRecord.get('n_family'),
+            accountFirstName: this.lastSelectedRecord.get('n_given'),
+            contactId: this.lastSelectedRecord.get('id')
+        }
+        
+        o.record.set('user_id', accountStruct);
+        o.grid.store.removeAt(o.row);
+        o.grid.store.insert(o.row, o.record);
+        this.lastSelectedRecord = null;
+        this.view.refresh();
+    }
+});
index 14d9c01..632a098 100644 (file)
@@ -22,29 +22,85 @@ Tine.Sipgate.CallStateWindow = Ext.extend(Ext.FormPanel, {
     deferredRender : false,
     buttonAlign : null,
     bufferResize : 500,
-    id: 'callstate-window',
+    
+    /**
+     * the session id of the call to control
+     * @type {String} sessionId
+     */
     sessionId : null,
     
+    /**
+     * number
+     * @type {String} number
+     */
+    number: null,
+    
+    /**
+     * line
+     * @type Tine.Sipgate.Model.Line
+     */
+    line: null,
+     
+    /**
+     * contact
+     * @type Tine.Addressbook.Model.Contact
+     */
+    contact: null,
+    
+    /**
+     * name of the callee or number (auto)
+     * @type {String}
+     */
+    calleeName: null,
+    
+    /**
+     * task
+     * @type 
+     */
+    task: null,
+    
     initComponent : function() {
         
         this.addEvents('cancel');
         if (!this.app) {
             this.app = Tine.Tinebase.appMgr.get(this.appName);
         }
-        Tine.log.debug('initComponent: appName: ', this.appName);
-        Tine.log.debug('initComponent: app: ', this.app);
-        Tine.log.debug('Info After: ',this.info);
-
+        this.calleeName = this.contact ? Ext.util.Format.htmlEncode(this.contact.get('n_fn')) : Ext.util.Format.htmlEncode(this.number);
         // init actions
         this.initActions();
         // init buttons and tbar
         this.initButtons();
         // init items
         this.items = this.getFormItems();
-        
         Tine.Sipgate.CallStateWindow.superclass.initComponent.call(this);
     },
     
+    start: function(config) {
+        this.line = config.hasOwnProperty('line') ? config.line : null;
+        this.sessionId = config.hasOwnProperty('sessionId') ? config.sessionId /*.replace(/monitor\d_/,'')*/ : null;
+        Tine.log.info('observing call with sessionId:');
+        Tine.log.info(this.sessionId);
+        this.action_cancel.enable();
+        this.startTask();
+        this.myPhoneContainer.getEl().frame("ff0000", 1);
+    },
+    
+    startTask: function() {
+        this.task = Ext.TaskMgr.start({
+            scope: this,
+            interval : 1000,
+            run : function() {
+                this.getState();
+            }
+        });
+    },
+    
+    stopTask: function() {
+        if (this.task) {
+            Ext.TaskMgr.stop(this.task);
+        }
+    },
+    
     initActions : function() {
         this.action_cancel = new Ext.Action({
             text : this.app.i18n._(this.cancelButtonText) ? this.app.i18n._(this.cancelButtonText) : _('Cancel'),
@@ -58,121 +114,138 @@ Tine.Sipgate.CallStateWindow = Ext.extend(Ext.FormPanel, {
     },
     initButtons: function() {
         this.fbar = [ '->', this.action_cancel ];
-
     },
     
     onCancel : function() {
-        Tine.log.debug('in onCancel csw',this.sessionId);
-        if(this.sessionId != false) Tine.Sipgate.closeSession(this.sessionId);
-        Tine.log.debug('in onCancel csw2');
-        this.fireEvent('cancel');
-        
+        this.stopTask();
+        Tine.Sipgate.lineBackend.closeSession(this.sessionId, this.line, this.updateState, null, this);
         this.purgeListeners();
         this.window.close();
     },
     
-    getFormItems: function() {
-        return {
+    getState: function() {
+        Tine.Sipgate.lineBackend.getSessionStatus(this.sessionId, this.line, this.updateState, null, this);
+    },
     
-            border : false,
-            frame : true,
-            layout : 'border',    
-            
-                items : [
-                        {
-                            region : 'center',
-                            xtype: 'container',
-                            height: 64,
-                            id: 'csw-update-container',
-                            items: [
-                                {
-                                    xtype: 'container',
-                                    height: 64,
-                                    width: 64,
-                                    id: 'csw-my-phone',
-                                    cls: 'SipgateCallStatePhone'
-                                },
-                                {
-                                    xtype: 'container',
-                                    height: 58,
-                                    width: 77,
-                                    style: '{float:left}',
-                                    
-                                    id: 'csw-line',
-                                    cls: 'SipgateCallStateLine',
-                                    items: [
-                                        {
-                                            xtype: 'displayfield',
-                                            value: this.app.i18n._('connecting...') + ' ' + this.info.name,
-                                            width: 77,
-                                            height: 48,
-                                            id: 'csw-call-info'
-                                        }
-                                    ]
-                                },
-                                {
-                                    xtype: 'container',
-                                    width: 64,
-                                    height: 64,
-                                    
-                                    style: '[{float:left},{clear:both}]',
-                                    id: 'csw-other-phone',
-                                    cls: 'SipgateCallStatePhone'
-                                }
-                            ]
-                        }
-                    ]
+    updateState: function(state) {
+        Tine.log.info('updating state:')
+        Tine.log.info(state);
+        var callingState = 2;
         
+        if(! state.hasOwnProperty('SessionStatus')) {
+            switch (state.StatusCode) {
+                case 512:
+                    this.callInfoContainer.update(this.app.i18n._('The call can\'t be observed anymore. Lost SessionID.'));
+                    this.stopTask();
+                    break;
+                default:
+                    this.callInfoContainer.update(this.app.i18n._('The call can\'t be observed anymore due to an unknown error.'));
+                    this.stopTask();
+            }
+            return;
+        }
+        
+        switch (state.SessionStatus) {
+            case 'first dial' :
+                callingState = 0;
+                this.callInfoContainer.update(String.format(this.app.i18n._('Please pick up your phone to get connected to {0}.'), this.calleeName));
+                this.myPhoneContainer.getEl().frame("ff0000", 1);
+                break;
+            case 'second dial' :
+                this.callInfoContainer.update(String.format(this.app.i18n._('Connecting to {0}.'), this.calleeName));
+                this.myPhoneContainer.addClass('established');
+                this.otherPhoneContainer.getEl().frame("ff0000",1);
+                callingState = 1;
+                break;
+            case 'established' :
+                this.otherPhoneContainer.addClass('established');
+                this.callInfoContainer.update(String.format(this.app.i18n._('Connected to {0}.'), this.calleeName));
+                break;
+            case 'call 1 busy':
+            case 'call 1 failed':
+                this.myPhoneContainer.addClass('error');
+                this.callInfoContainer.update(this.app.i18n._('call 1 busy'));
+                this.stopTask();
+                break;
+            case 'call 2 busy':
+            case 'call 2 failed':
+                this.otherPhoneContainer.addClass('error');
+                this.myPhoneContainer.removeClass('established');
+                this.callInfoContainer.update(String.format(this.app.i18n._('Connecting to {0} failed. {0} is busy or has rejected the call.'), this.calleeName));
+                this.stopTask();
+                break;
+            case 'hungup' :
+                switch (callingState) {
+                    case 1 :
+                        this.callInfoContainer.update(this.app.i18n._('hungup before other called'));
+                        break;
+                    default :
+                        this.callInfoContainer.update(this.app.i18n._('hungup'));
+                }
+                this.myPhoneContainer.removeClass('established');
+                this.otherPhoneContainer.removeClass('established');
+                this.stopTask();
+                break;
+            case 'call canceled':
+                this.stopTask();
+                break;
+            default :
+                this.callInfoContainer.update(state.SessionStatus);
+                this.stopTask();
+        }
+    },
+    
+    getFormItems: function() {
+        return {
+            border: false,
+            frame: true,
+            layout: 'border',
+            items: [{
+                layout: 'border',
+                region : 'center',
+                xtype: 'container',
+                ref: '../updateContainer',
+                items: [
+                    {
+                        region: 'west',
+                        xtype: 'container',
+                        boxMaxHeight: 64,
+                        width: 64,
+                        ref:'../../myPhoneContainer',
+                        cls: 'SipgateCallStatePhone',
+                        margins: '15'
+                    }, {
+                        margins: {top:20, right:10, bottom:0, left:10},
+                        region: 'center',
+                        xtype: 'displayfield',
+                        value: String.format(this.app.i18n._('Initializing call to {0}'), this.calleeName),
+                        ref: '../../callInfoContainer'
+                    }, {
+                        margins: '15',
+                        xtype: 'container',
+                        width: 64,
+                        boxMaxHeight: 64,
+                        region: 'east',
+                        ref: '../../otherPhoneContainer',
+                        cls: 'SipgateCallStatePhone'
+                    }
+                ]
+            }]
         };
     }
-
 });
 
 /**
  * @param {Object} info
- * 
  * @return {Ext.ux.Window}
  */
-
-Tine.Sipgate.CallStateWindow.openWindow = function(info) {
-
-    Tine.log.debug('Info: ', info);
-    var _number = info.info.number;
-    Tine.log.debug('Num: ', _number);
-    
+Tine.Sipgate.CallStateWindow.openWindow = function(config) {
     var window = Tine.WindowFactory.getExtWindow({
-        title : Tine.Tinebase.appMgr.get('Sipgate').i18n._('Connecting to: ') + ' ' + _number,
-        width : 320,
+        title : Tine.Tinebase.appMgr.get('Sipgate').i18n._('Connecting to: ') + ' ' + config.number,
+        width : 360,
         height : 160,
         contentPanelConstructor : 'Tine.Sipgate.CallStateWindow',
-        contentPanelConstructorConfig : info
-        
-
+        contentPanelConstructorConfig : config
     });
-    window.addListener('close', function() {
-        Tine.Sipgate.CallStateWindow.stopTask();
-        });
-
     return window;
-};
-
-Tine.Sipgate.CallStateWindow.startTask = function(sessionId,contact) {
-
-    Tine.Sipgate.CallUpdateWindowTask = Ext.TaskMgr.start({
-        interval : 2000,
-        run : function() {
-            Tine.Sipgate.updateCallStateWindow(sessionId,contact);
-        }
-    });
-};
-
-
-Tine.Sipgate.CallStateWindow.stopTask = function() {
-    if(Tine.Sipgate.CallUpdateWindowTask) {
-        Ext.TaskMgr.stop(Tine.Sipgate.CallUpdateWindowTask);
-        Tine.Sipgate.CallUpdateWindowTask = null;
-    }
-};
-
-
-
+};
\ No newline at end of file
diff --git a/tine20/Sipgate/js/ConnectionGridPanel.js b/tine20/Sipgate/js/ConnectionGridPanel.js
new file mode 100644 (file)
index 0000000..8229b38
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Tine 2.0
+ * 
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+Ext.ns('Tine.Sipgate');
+
+/**
+ * Connection grid panel
+ * 
+ * @namespace   Tine.Sipgate
+ * @class       Tine.Sipgate.GridPanel
+ * @extends     Tine.widgets.grid.GridPanel
+ * 
+ * <p>Connection Grid Panel</p>
+ * <p><pre>
+ * </pre></p>
+ * 
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * 
+ * @param       {Object} config
+ * @constructor
+ * Create a new Tine.Sipgate.GridPanel
+ */
+Tine.Sipgate.ConnectionGridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
+    /**
+     * record class
+     * @cfg {Tine.Sipgate.Model.Connection} recordClass
+     */
+    recordClass: Tine.Sipgate.Model.Connection,
+    evalGrants: false,
+    /**
+     * grid specific
+     * @private
+     */
+    defaultSortInfo: {field: 'timestamp', direction: 'ASC'},
+    gridConfig: {
+        autoExpandColumn: 'contact_name'
+    },
+     
+    /**
+     * inits this cmp
+     * @private
+     */
+    initComponent: function() {
+        this.recordProxy = Tine.Sipgate.connectionBackend;
+        this.gridConfig.columns = this.getColumns();
+        
+        this.initFilterToolbar();
+        this.plugins.push(this.filterToolbar);
+        
+        Tine.Sipgate.ConnectionGridPanel.superclass.initComponent.call(this);
+    },
+    
+    /**
+     * initializes filter toolbar
+     */
+    initFilterToolbar: function() {
+        this.filterToolbar = new Tine.widgets.grid.FilterToolbar({
+            filterModels: Tine.Sipgate.Model.Connection.getFilterModel(),
+            defaultFilter: 'query',
+            filters: [],
+            plugins: [
+                new Tine.widgets.grid.FilterToolbarQuickFilterPlugin()
+            ]
+        });
+    },  
+    
+    /**
+     * returns cm
+     * 
+     * @return Ext.grid.ColumnModel
+     * @private
+     */
+    getColumns: function(){
+        return [{
+                id : 'tos',
+                header : this.app.i18n._('TOS'),
+                dataIndex : 'tos',
+                width : 35,
+                renderer: Tine.Tinebase.widgets.keyfield.Renderer.get('Sipgate', 'connectionTos'),
+                scope: this,
+                sortable: true
+            }, {
+                id : 'status',
+                header : this.app.i18n._('Status'),
+                dataIndex : 'status',
+                width : 35,
+                renderer: Tine.Tinebase.widgets.keyfield.Renderer.get('Sipgate', 'connectionStatus'),
+                scope: this,
+                sortable: true
+            }, {
+                id : 'remote_number',
+                header : this.app.i18n._('Remote Number'),
+                dataIndex : 'remote_number',
+                sortable: true,
+                hidden : false
+            }, {
+                id : 'local_number',
+                header : this.app.i18n._('Local Number'),
+                dataIndex : 'local_number',
+                sortable: true,
+                hidden : false
+            }, {
+                id : 'line_id',
+                header : this.app.i18n._('Line'),
+                dataIndex : 'line_id',
+                sortable: true,
+                hidden : false,
+                renderer: this.lineRenderer
+            }, {
+                id : 'timestamp',
+                header : this.app.i18n._('Call started'),
+                renderer: Tine.Tinebase.common.dateTimeRenderer,
+                dataIndex : 'timestamp',
+                sortable: true,
+                hidden : false
+            }, {
+                id : 'contact_id',
+                header : this.app.i18n._('Contact'),
+                dataIndex : 'contact_id',
+                sortable: true,
+                renderer: this.contactRenderer,
+                hidden:false
+            }
+        ];
+    },
+
+    /**
+     * renders the contact assigned to this connection
+     * @param {Object} value
+     * @param {Object} cell
+     * @param {Object} record
+     * @return {String}
+     */
+    contactRenderer: function(value, cell, record) {
+        if(value) {
+            return value.n_fn;
+        } else {
+            return record.get('contact_name');
+        }
+    },
+
+    /**
+     * returns the context menu
+     * @return {Ext.menu.Menu}
+     */
+    getContextMenu: function() {
+        if (! this.contextMenu) {
+            var items = [];
+            
+            items.push(this.actions_addNumber);
+            items.push(this.actions_dialNumber);
+            
+            this.contextMenu = new Ext.menu.Menu({
+                items: items,
+                plugins: [{
+                    ptype: 'ux.itemregistry',
+                    key:   this.app.appName + '-GridPanel-ContextMenu'
+                }]
+            });
+            
+            this.actionUpdater.addActions(items);
+        }
+        return this.contextMenu;
+    },
+
+    /**
+     * returns action toolbar items
+     * @return {Array}
+     */
+    getActionToolbarItems: function() {
+        return [
+            Ext.apply(new Ext.Button(this.actions_dialNumber), {
+                scale: 'medium',
+                rowspan: 2,
+                iconAlign: 'top'
+            }),
+            Ext.apply(new Ext.Button(this.actions_addNumber), {
+                scale: 'medium',
+                rowspan: 2,
+                iconAlign: 'top'
+            })
+        ];
+    },
+
+    /**
+     * initializes the actions
+     */
+    initActions: function() {
+        this.actions_addNumber = new Ext.Action({
+            text : this.app.i18n._('Save number'),
+            tooltip : this.app.i18n._('Adds this number to the Addressbook'),
+            handler : this.onAddNumber,
+            iconCls : 'action_AddNumber',
+            scope : this
+        });
+            
+        this.actions_dialNumber = new Ext.Action({
+            text : this.app.i18n._('Dial number'),
+            tooltip : this.app.i18n._('Initiates a new outgoing call'),
+            handler : this.onDialPhoneNumber,
+            iconCls : 'action_DialNumber',
+            scope : this
+        });
+        this.action_addInNewWindow = new Ext.Action({
+            disabled: ! Tine.Tinebase.common.hasRight('manage_accounts', 'Sipgate'),
+            actionType: 'add',
+            text: this.app.i18n._('Add Account'),
+            handler: this.onAddAccountInNewWindow,
+            iconCls: (this.newRecordIcon !== null) ? this.newRecordIcon : this.app.appName + 'IconCls',
+            scope: this
+        });
+        this.getActionToolbar();
+    },
+
+    onAddNumber: function() {
+        // check if addressbook app is available
+        if (!Tine.Addressbook || !Tine.Tinebase.common.hasRight('run', 'Addressbook')) {
+            return;
+        }
+        var number = this.getGrid().getSelectionModel().getSelections()[0].get('remote_number');
+        var window = Tine.Sipgate.SearchAddressDialog.openWindow({
+            number : number
+        });
+    },
+
+    onDialPhoneNumber: function() {
+        var sel = this.grid.getSelectionModel().getSelections(),
+            contact = null,
+            number = null;
+
+        if(sel.length > 0) {
+            number = sel[0]['data']['remote_number'];
+            contact = sel[0]['data']['contact_id'] ? new Tine.Addressbook.Model.Contact(sel[0]['data']['contact_id']) : null;
+        }
+
+        var lineId = Tine.Sipgate.registry.get('preferences').get('phoneId');
+
+        if(lineId && number) {
+            Tine.Sipgate.lineBackend.dialNumber(lineId, number, contact);
+        } else {
+            Tine.Sipgate.DialNumberDialog.openWindow({number: number, contact: contact});
+        }
+    },
+    /**
+     * calls the AccountEditDialog
+     */
+    onAddAccountInNewWindow: function() {
+        var cp = this.app.getMainScreen().getCenterPanel('Account');
+        cp.onEditInNewWindow.call(cp, [{actionType: 'add'}]);
+    },
+    /**
+     * renders the line
+     * @param {Object} value
+     * @return {String}
+     */
+    lineRenderer: function(value) {
+        return value.uri_alias;
+    }
+});
index 2e4dc04..ed1d462 100644 (file)
@@ -1,40 +1,56 @@
-/**
+/*
  * Tine 2.0
  * 
- * @package Sipgate
- * @license http://www.gnu.org/licenses/agpl.html AGPL3
- * @author Alexander Stintzing <alex@stintzing.net>
- * @copyright Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
- * @version $Id: DialNumberDialog.js 26 2011-05-03 01:42:01Z alex $
- * 
+ * @package     Sipgate
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ *
  */
+Ext.ns('Tine.Sipgate');
 
-Ext.namespace('Tine.Sipgate');
+/**
+ * @namespace   Tine.widgets.dialog
+ * @class       Tine.widgets.dialog.AddToRecordPanel
+ * @extends     Ext.FormPanel
+ * @author      Alexander Stintzing <alex@stintzing.net>
+ */
 
 Tine.Sipgate.DialNumberDialog = Ext.extend(Ext.FormPanel, {
 
+    /**
+     * the assigned contact if any
+     * @type Tine.Addressbook.Model.Contact
+     */
+    contact: null,
+    /**
+     * the number to call
+     * @type {String}
+     */
+    number: null,
+    
     // private
     appName : 'Sipgate',
-    
+    app: null,
     layout : 'fit',
     border : false,
-    cls : 'tw-editdialog',    
-    
-    bodyStyle : 'padding:5px',
+    cls : 'tw-editdialog',
     labelAlign : 'top',
-
     anchor : '100% 100%',
     deferredRender : false,
     buttonAlign : null,
-    id: 'sipgate-dialnumber-dialog',
     bufferResize : 500,
-
-    // private
-    initComponent : function() {
-        this.addEvents('cancel', 'send', 'close');
+    
+    /**
+     * initializes the component
+     */
+    initComponent: function() {
+         
         if (!this.app) {
             this.app = Tine.Tinebase.appMgr.get(this.appName);
         }
+
         Tine.log.debug('initComponent: appName: ', this.appName);
         Tine.log.debug('initComponent: app: ', this.app);
 
@@ -42,118 +58,160 @@ Tine.Sipgate.DialNumberDialog = Ext.extend(Ext.FormPanel, {
         this.initActions();
         // init buttons and tbar
         this.initButtons();
+        
         // get items for this dialog
         this.items = this.getFormItems();
 
         Tine.Sipgate.DialNumberDialog.superclass.initComponent.call(this);
+        
+        var phoneId = Tine.Sipgate.registry.get('preferences').get('phoneId');
+        
+        this.on('callstatewindowclose', this.onCancel, this);
+        
+        if(phoneId) {
+            this.linePicker.getStore().baseParams.filter = [{field: 'id', operator: 'equals', value: phoneId}];
+            this.linePicker.getStore().suspendEvents();
+            this.linePicker.getStore().load({callback: this.lineAutoSet, scope:this});
+