Code

Added option to select asterisk extensions delimiter
[gosa.git] / gosa-plugins / gofon / gofon / phoneaccount / class_phoneAccount.inc
index 33ea306b51f75e1def6e41e3780e510f9e37e09e..b4f4dede09b12f06af36c6ecc8284ccfe41e9470 100644 (file)
@@ -3,9 +3,11 @@
 class phoneAccount extends plugin
 {
   /* Definitions */
-  var $plHeadline= "Phone";
+  var $plHeadline   = "Phone";
   var $plDescription= "This does something";
-  var $has_mailAccount= FALSE;
+  var $plIcon       = "plugins/gofon/images/phoneAccount.png";
+
+  var $delimiter = "|";
 
   /* Attributes */
   var $telephoneNumber        = array();
@@ -31,23 +33,34 @@ class phoneAccount extends plugin
   var $init_HomeServer        = "0";            // Contains the dn of the server that manage this account 
   var $goFonHomeServers       = array();        // Contains all available server configurations 
 
+  var $context                = "default";
+  var $sip_contexts           = array();
+  var $voice_context          = "default";
+  var $voicemail_contexts     = array();
+
   /* attribute list for save action */
   var $CopyPasteVars          = array("phoneNumbers","macroarray","macrostillavailable"/*"phoneNumbers" -Reset- */,
                                       "hardware_list","used_hardware");
 
-  var $attributes             = array("goFonDeliveryMode", "goFonFormat","cn","goFonHomeServer",
+  var $attributes             = array("goFonDeliveryMode", "goFonFormat","goFonHomeServer",
       "goFonHardware","goFonPIN","goFonVoicemailPIN","telephoneNumber", "goFonMacro","macro");
   var $objectclasses= array("goFonAccount");
 
   var $uid;
+  var $cn;
 
   var $view_logged = FALSE;
   var $multiple_support = TRUE;
+  var $mailAddress      = "";
+  var $has_mailAccount  = FALSE;
+  var $pager      = "";
 
   function phoneAccount (&$config, $dn= NULL, $parent= NULL)
   {
     plugin::plugin ($config, $dn, $parent);
 
+    $this->delimiter = $config->get_cfg_value("asteriskParameterDelimiter","|");
+
     /* Assemble phone numbers */
     if (isset($this->attrs['telephoneNumber'])){
       for ($i= 0; $i<$this->attrs['telephoneNumber']['count']; $i++){
@@ -56,19 +69,44 @@ class phoneAccount extends plugin
       }
     }
 
-    /* Set up has_mailAccount */
-    if (isset($this->attrs['objectClass'])){
-      if (in_array("gosaMailAccount", $this->attrs['objectClass'])){
-        $this->has_mailAccount= TRUE;
-      }
+    $this->sip_contexts = $this->get_asterisk_sip_contexts();
+    $this->voicemail_contexts = $this->get_asterisk_voicemail_contexts();
+
+    /* Set parent object to tab object */
+    if(is_object($parent)){
+      $this->parent = $parent->parent;
     }
 
-    /* Set uid */
-    if((isset($this->parent->by_object['user']->uid))&&(!empty($this->parent->by_object['user']->uid))){
-      $this->uid = $this->parent->by_object['user']->uid;
+    /* Get current uid and cn 
+     */
+    if(isset($this->attrs['uid'][0])){
+      $this->uid = $this->attrs['uid'][0];
     }
-    if((isset($this->parent->by_object['user']->cn))&&(!empty($this->parent->by_object['user']->cn))){
-      $this->cn  = $this->parent->by_object['user']->cn;
+    if(isset($this->attrs['cn'][0])){
+      $this->cn = $this->attrs['cn'][0];
+    }
+    if(isset($this->attrs['mail'][0])){
+      $this->mailAddress = $this->attrs['mail'][0];
+      $this->has_mailAccount = true;
+    }
+    if(isset($this->attrs['pager'][0])){
+      $this->pager = $this->attrs['pager'][0];
+    }
+
+    /* If there is a parent object present, use references 
+     */
+    if(isset($this->parent->by_object['user']->uid)){
+      $this->uid = &$this->parent->by_object['user']->uid;
+    }
+    if(isset($this->parent->by_object['user']->cn)){
+      $this->cn   =&$this->parent->by_object['user']->cn;
+    }
+    if(isset($this->parent->by_object['user']->pager)){
+      $this->pager   =&$this->parent->by_object['user']->pager;
+    }
+    if(isset($this->parent->by_object['mailAccount']->mail)){
+      $this->mailAddress      = &$this->parent->by_object['mailAccount']->mail;
+      $this->has_mailAccount  = &$this->parent->by_object['mailAccount']->is_account;
     }
 
     /* Check server configurations 
@@ -131,8 +169,8 @@ class phoneAccount extends plugin
     /* Get available phone hardware  
      * Search for all available phone hardware  
      */
-    $tmp = get_sub_list("(objectClass=goFonHardware)","phone",array(get_ou("phoneou")),
-                  $this->config->current['BASE'],array("cn","description"), GL_NO_ACL_CHECK);
+    $tmp = get_sub_list("(objectClass=goFonHardware)","phone",array(get_ou("phoneRDN")),
+                  $this->config->current['BASE'],array("cn","description"), GL_SUBSEARCH);
     foreach($tmp as $attrs){
       $cn= $attrs['cn'][0];
       $description= "";
@@ -150,16 +188,16 @@ class phoneAccount extends plugin
      */
     $deps_a = array(
         get_people_ou(),
-        get_ou("ogroupou"),
-        get_ou("serverou"),
-        get_ou("terminalou"),
-        get_ou("workstationou"),
-        get_ou("printerou"),
-        get_ou("componentou"),
-        get_ou("phoneou"));
+        get_ou("ogroupRDN"),
+        get_ou("serverRDN"),
+        get_ou("terminalRDN"),
+        get_ou("workstationRDN"),
+        get_ou("printerRDN"),
+        get_ou("componentRDN"),
+        get_ou("phoneRDN"));
 
     $tmp = get_sub_list("(goFonHardware=*)","phone",$deps_a,$this->config->current['BASE'],
-        array('cn','dn','goFonHardware'),GL_NO_ACL_CHECK);
+        array('cn','dn','goFonHardware'),GL_SUBSEARCH);
     foreach($tmp as $attrs){
       $cn = $attrs['goFonHardware'][0];
       if(isset($this->hardware_list[$cn])){
@@ -169,11 +207,11 @@ class phoneAccount extends plugin
 
 
     /* Get available Macros  
-     * Search for all Marcos that are visible and create 
+     * Search for all Macros that are visible and create 
      *  an array with name and parameters 
      */
-    $tmp = get_sub_list("(&(objectClass=goFonMacro)(goFonMacroVisible=1))","gofonmacro",array(get_ou("macroou")),
-                  $this->config->current['BASE'],array("displayName","goFonMacroParameter","dn","cn"), GL_NONE);
+    $tmp = get_sub_list("(&(objectClass=goFonMacro)(goFonMacroVisible=1))","gofonmacro",array(get_ou("phoneMacroRDN")),
+                  $this->config->current['BASE'],array("displayName","goFonMacroParameter","dn","cn"), GL_NO_ACL_CHECK | GL_SUBSEARCH );
     
 
     /* Add none for no macro*/
@@ -183,6 +221,16 @@ class phoneAccount extends plugin
     /* Fetch all Macros*/
     foreach($tmp as $attrs){
 
+      $ui = get_userinfo(); 
+      $acl = $ui->get_permissions($attrs['dn'],"gofonmacro/macro","");
+
+      /* Skip all macros we are not able to read 
+          execpt, the currently selected macro.
+       */
+      if(!preg_match("/r/",$acl) && !preg_match("/^".preg_quote($attrs['dn'], '/')."/",$this->goFonMacro)){
+        continue;
+      }
+
       /* unset Count, we don't need that here */
       unset($attrs['displayName']['count']);
 
@@ -200,23 +248,49 @@ class phoneAccount extends plugin
 
       /* Go through available parameters and parse all attributes, like parametername, type, default ...*/
       if((isset($attrs['goFonMacroParameter']))&&(is_array($attrs['goFonMacroParameter']))){
+          foreach($attrs['goFonMacroParameter'] as $pkey=>$pval){
+              /* Split Data in readable values, by delimiter !  */
+              $data = explode("!",$attrs['goFonMacroParameter'][$pkey]);
+
+              $string = $data[3];
+              $string=preg_replace("/%uid/i",$this->uid,$string);
+              $string=preg_replace("/%pager/i",$this->pager,$string);
+              $string=preg_replace("/%context/i",$this->context,$string);
+              $string=preg_replace("/%voicemailcontext/i",$this->voice_context,$string);
+
+              if(isset($this->cn)){
+                  $string=preg_replace("/%cn/i",$this->cn,$string);
+              }
 
-        foreach($attrs['goFonMacroParameter'] as $pkey=>$pval){
-          /* Split Data in readable values, by delimiter !  */
-          $data = split("!",$attrs['goFonMacroParameter'][$pkey]);
-
-          /* Set all attrs */
-          $id = $data[0];
-          $this->macroarray[$attrs['dn']][$id]['var']    ="var".$id;
-          $this->macroarray[$attrs['dn']][$id]['choosen']=$data[3]; 
-          $this->macroarray[$attrs['dn']][$id]['id']     =$id;
-          $this->macroarray[$attrs['dn']][$id]['name']   =$data[1];
-          $this->macroarray[$attrs['dn']][$id]['type']   =$data[2];
-          $this->macroarray[$attrs['dn']][$id]['default']=$data[3];
-          if($data[2] == "bool"){
-            $this->macroarray[$attrs['dn']][$id]['choosen']=$data[3];
-          }
-        }//foreach
+
+              $tmp = array();
+              foreach($this->phoneNumbers as $phonenum){
+                  $tmp[] = $phonenum;
+              }
+
+              for($i = 0 ; $i < 10; $i++){
+                  if(isset($tmp[$i])){
+                      $string = preg_replace("/%telephoneNumber_".($i+1)."/i",$tmp[$i],$string);
+                  }
+              }
+              if(isset($tmp[0])){
+                  $string = preg_replace("/%telephoneNumber/i",$tmp[0],$string);
+              }
+              $data[3] = $string;
+
+
+              /* Set all attrs */
+              $id = $data[0];
+              $this->macroarray[$attrs['dn']][$id]['var']    ="var".$id;
+              $this->macroarray[$attrs['dn']][$id]['choosen']=$data[3];
+              $this->macroarray[$attrs['dn']][$id]['id']     =$id;
+              $this->macroarray[$attrs['dn']][$id]['name']   =$data[1];
+              $this->macroarray[$attrs['dn']][$id]['type']   =$data[2];
+              $this->macroarray[$attrs['dn']][$id]['default']=$data[3];
+              if($data[2] == "bool"){
+                  $this->macroarray[$attrs['dn']][$id]['choosen']=$data[3];
+              }
+          }//foreach
       }//is_array
     }//while
 
@@ -225,7 +299,7 @@ class phoneAccount extends plugin
      * If we have a macro selected, parse it and set values 
      *  in $this->macroarray[$this->macro]. 
      */
-    $tmp = split("!",$this->goFonMacro);
+    $tmp = explode("!",$this->goFonMacro);
     if(is_array($tmp)){
 
       /* First value is the macroname */
@@ -245,7 +319,7 @@ class phoneAccount extends plugin
       foreach($tmp as $var){
 
         /* Split this, so we have $varar[0] = parameterID $varar[1] = SelectedValue */
-        $varar = split("#",$var);
+        $varar = explode("#",$var);
 
         /* Only insert if the parameter still exists */
         if(isset($this->macroarray[$this->macro][$varar[0]])){
@@ -258,24 +332,55 @@ class phoneAccount extends plugin
 
     $this->a_old_telenums = $this->phoneNumbers;
 
+
     /* Get voicemail PIN from MySQL DB 
      * Because every user can change his PIN directly from the phone
      *  without any update to the ldap
      * This means, the PIN in the DB is up to date
      */
     // Connect to DB server
-    if((is_callable("mysql_pconnect"))&&(isset($cur_cfg))&&(isset($cur_cfg['SERVER']))&&(isset($cur_cfg['LOGIN']))&&(isset($cur_cfg['PASSWORD']))){
+
+
+    $num = key($this->phoneNumbers);
+
+    if( (is_callable("mysql_pconnect"))&&
+        (isset($cur_cfg))&&
+        (isset($cur_cfg['SERVER']))&&
+        (isset($cur_cfg['LOGIN']))&&
+        (isset($cur_cfg['PASSWORD']))){
+
       $r_con =  @mysql_pconnect($cur_cfg['SERVER'],$cur_cfg['LOGIN'],$cur_cfg['PASSWORD']);
       if($r_con){
+
+        // Try to select the gophone database
         $r_db  =  @mysql_select_db($cur_cfg['DB'],$r_con);
-  
-        $query_tmp = "SELECT ".$cur_cfg['VOICE_TABLE'].".password FROM  ".$cur_cfg['VOICE_TABLE'].", ".
-                     $cur_cfg['SIP_TABLE']."  WHERE customer_id = sip_users.mailbox AND name='".$this->uid."'";
+        if(!$r_db){
+          msg_dialog::display(_("Warning"), msgPool::dbselect($cur_cfg['DB'],mysql_error()), WARNING_DIALOG);
+        }
 
-        $vp = mysql_fetch_row(mysql_query($query_tmp));
+        $query_tmp = "SELECT ".$cur_cfg['VOICE_TABLE'].".context as 'v_context', 
+                             ".$cur_cfg['SIP_TABLE'].".context, 
+                             ".$cur_cfg['VOICE_TABLE'].".password 
+                       FROM  ".$cur_cfg['VOICE_TABLE'].", 
+                             ".$cur_cfg['SIP_TABLE']." 
+                       WHERE ".$cur_cfg['VOICE_TABLE'].".mailbox = ".$num." 
+                          AND ".$cur_cfg['SIP_TABLE'].".name='".$this->uid."'";
+        $res = mysql_query($query_tmp);
+        $vp  = mysql_fetch_assoc($res);
+        if(!isset($vp['context'])){
+          $this->is_modified= TRUE;
+          msg_dialog::display(_("Warning"), sprintf(_("Cannot identify telephone extension in database, please try to save again.")), WARNING_DIALOG);
+        } 
         @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,$query_tmp, "Database query");
-        if((isset($vp[0]))&&(!empty($vp[0]))){
-          $this->goFonPINVoice = $vp[0];
+        if((isset($vp['password']))&&(!empty($vp['password']))){
+          $this->goFonPINVoice = $vp['password'];
+        }
+        if((isset($vp['context']))&&(!empty($vp['context']))){
+          $this->context = $vp['context'];
+        }
+        if((isset($vp['v_context']))&&(!empty($vp['v_context']))){
+          $this->voice_context = $vp['v_context'];
         }
       }
     }
@@ -287,6 +392,66 @@ class phoneAccount extends plugin
   }
 
 
+  /* Transaction will only work with InnoDB tables 
+   */
+  public static function checkRealtimeTables($config)
+  {
+    $ret =TRUE;
+
+    // Connect to DB server
+    if( (is_callable("mysql_pconnect"))&&
+        (isset($config))&&
+        (isset($config['SERVER']))&&
+        (isset($config['LOGIN']))&&
+        (isset($config['PASSWORD']))){
+
+      $r_con =  @mysql_pconnect($config['SERVER'],$config['LOGIN'],$config['PASSWORD']);
+      if($r_con){
+        $r_db  =  @mysql_select_db($config['DB'],$r_con);
+
+        /* Validate Table Type - it must be InnoDB to be able to use transactions 
+         */
+        $inno_tables = array("SIP_TABLE","EXT_TABLE","VOICE_TABLE","QUEUE_TABLE","QUEUE_MEMBER_TABLE"); 
+        foreach($inno_tables as $inno_table){
+          $sql = "show table status like '".$config[$inno_table]."';";
+          $res = mysql_query($sql);
+          $vp  = mysql_fetch_assoc($res);
+          if(!preg_match("/^InnoDB$/i",$vp['Engine'])){
+
+            /* Not an InnoDB Table type, try to modify type. 
+             */
+            $sql = "ALTER TABLE `".$config[$inno_table]."` ENGINE = INNODB; ";
+            $res = mysql_query($sql);
+            if(!$res){
+              @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>".$sql."</b>", 
+                  "<b>FAILED!</b>. Transactions will not work!");
+              $ret = FALSE;
+            }else{
+              @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>".$sql."</b>", 
+                  "<i>Table '".$config[$inno_table]."' is now of type InnoDB, this enables transactions.</i>");
+            }
+          }else{
+            @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"",
+                "<i>Table type of '".$config[$inno_table]."' OK, using transactions!</i>");
+          }
+        }
+      }
+    }
+    return($ret);
+  }
+
+  function stripInvalidChars($tele){
+    /* Strip invalid chars, but maintain a leading + for international numbers */
+    $t_tele= preg_replace("/[^0-9]/","",$tele);
+    if (preg_match('/^\+/', $tele)) {
+      $t_tele= "+".$t_tele;
+    }
+    return($t_tele);
+  }
+    
+
+
+
   /* This function generates the Database entries. 
    * The Parameter 'save' could be true or false.
    *  false - means only testing no database transactions.
@@ -334,7 +499,8 @@ class phoneAccount extends plugin
     $s_host         = NULL;                   // Contains host for Sip entry
     $s_qualify      = "yes";                  // Qualify entry
     $s_pin          = NULL;                   // Entry for secret
-    $s_type         = NULL;                   // Entry for phone type (friend , peer ..)
+    $s_type         = "friend";               // Entry for phone type (friend , peer ..)
+                                              // Set the default to the default of the db
 
     $sip_data_array = array();                // Contains complete sip entry, to generate SQL syntax
     $i_old_key      = false;                  // Contains index for first old phonenumber, to delete old entries corectly
@@ -351,24 +517,19 @@ class phoneAccount extends plugin
 
     $i_is_accounted = false;  // Ensure that extension entry, for name to number is only once in table
 
-    restore_error_handler();
-
     /* Prepare some basic attributes */
     $oldnums = array();
+
     foreach($this->a_old_telenums as $tele){
-      $oldnums[]= preg_replace("/[^0-9]/","",$tele);
+      $oldnums[]= $this->stripInvalidChars($tele);
     }
     foreach($this->phoneNumbers as $tele){
-      $newnums[]= preg_replace("/[^0-9]/","",$tele);
+      $newnums[]= $this->stripInvalidChars($tele);
     }
 
-    /* If deletion starts from userslist, cn uid are not set */
-    if((isset($this->parent->by_object['user']->uid))&&(!empty($this->parent->by_object['user']->uid))){
-      $this->uid = $this->parent->by_object['user']->uid;
-    }
-    if((isset($this->parent->by_object['user']->cn))&&(!empty($this->parent->by_object['user']->cn))){
-      $this->cn  = $this->parent->by_object['user']->cn;
-    }
+    if(empty($this->uid)) trigger_error("Uid is empty.");
+
+
     /* Create voicemail entry 
      */
     if((!isset($this->cn))||(empty($this->cn))){
@@ -377,13 +538,14 @@ class phoneAccount extends plugin
       $CNname= $this->cn;
     }
 
-    if((isset($this->parent))&&(isset($this->parent->by_object['mailAccount']))&&($this->parent->by_object['mailAccount']->is_account==true)){
-      $s_mail = $this->parent->by_object['mailAccount']->mail;
-    }else{
-      $s_mail = "";
+    $s_mail = "";
+    if($this->has_mailAccount){
+      $s_mail = $this->mailAddress;;
     }
+
     /* Get phonehardware to setup sip entry  */
     $ldap         = $this->config->get_ldap_link();
+    $ldap->cd ($this->config->current['BASE']);
     $r_res        = $ldap->search("(&(objectClass=goFonHardware)(cn=".$this->goFonHardware."))", array('*'));
     $a_ldap_attrs = $ldap->fetch();
 
@@ -474,6 +636,7 @@ class phoneAccount extends plugin
       }
     }
 
+
     /* Save means that we must save changes, not only test  */
     if($save == true){
     
@@ -485,14 +648,29 @@ class phoneAccount extends plugin
        * If there is an old entry, get callerid and remove voicemail and extensions 
        */
       if($old_connection){
+
+        /* Check table definitions
+         */
+        if(!phoneAccount::checkRealtimeTables($a_Remove)){
+          msg_dialog::display(_("Warning"),
+              sprintf(_("GOsa identified problems with your MySQL table definition!")),
+              WARNING_DIALOG);
+        }
+
         $query  = "SELECT id,name,callerid FROM ".$a_Remove['SIP_TABLE']." WHERE name='".$this->uid."';";
         $rid    = mysql_query($query,$old_connection);
-        @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,$query, "Database query");
+        @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,$query, 
+            "<i>Reguest callerid to be able to identify the user.</i>");
 
         /* Old entry found, remove it */
         $query_a = array();
         if(mysql_affected_rows($old_connection)){
           $result = mysql_fetch_assoc($rid);
+
+          /* Set mode to strict
+             Strict disallows the addition of entries that do not match the targets field length.
+           */
+          $query_a[]= "SET @@sql_mode = STRICT_ALL_TABLES;";
           $query_a[]= "DELETE FROM ".$a_Remove['SIP_TABLE']." WHERE name='".$this->uid."';";
           $query_a[]= "DELETE FROM ".$a_Remove['VOICE_TABLE']." WHERE customer_id='".$result['callerid']."';";
           $query_a[]= "DELETE FROM ".$a_Remove['EXT_TABLE']." WHERE exten='".$this->uid."';";
@@ -500,30 +678,68 @@ class phoneAccount extends plugin
             $query_a[]= "DELETE FROM ".$a_Remove['EXT_TABLE']." WHERE exten='".$s_telenums."';";
           }
 
-          foreach($query_a as $qry){
-                 @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,$qry, "Database query");
-            if(!mysql_query($qry,$old_connection)){
-              trigger_error(mysql_error($old_connection));
+          /* Start transaction, to be able to rollback 
+           */
+          @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>---Removing entry from old server---</b>","");
+
+          mysql_query("begin;",$old_connection);
+          @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>begin;</b>","<i>Starting transaction!</i>");
+
+          foreach($query_a as $query){
+            @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>".$query."</b>", "");
+            if(!mysql_query($query,$old_connection)){
+              $err = mysql_error($old_connection);
+              @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"\n".$err, "<b>FAILED</b>");
+              msg_dialog::display(_("Error"), 
+                  msgPool::mysqlerror($err,__CLASS__)."&nbsp;".
+                  "\n<p>"._("Please activate debugging for details!")."</p>",
+                  ERROR_DIALOG);
+
+              mysql_query("rollback;",$old_connection);
+              @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>rollback;</b>", "<b>ERROR</b> Rollback transaction!");
+              @mysql_close($old_connection);
+              return(false);
             } 
           }
+
+          /* Let changes get active, everything was fine;
+           */ 
+          mysql_query("commit;",$old_connection);
+          @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>commit;</b>", "");
+          @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>---Transaction sucessful!---</b>", "");
         }
       }
 
+
       /********************** 
        * Update / Insert sip_users entry  
        **********************/
 
+      /* Check table definitions
+       */
+      if(!phoneAccount::checkRealtimeTables($a_New)){
+        msg_dialog::display(_("Warning"),
+            sprintf(_("GOsa identified problems with your MySQL table definition!")),
+            WARNING_DIALOG);
+      }
+
+
       /* Set the first given phone number as callerid */
       reset($newnums);        
       $i_new_key = key($newnums);
       $sip_data_array['callerid']  =$newnums[$i_new_key];
-      $sip_data_array['mailbox']   =$newnums[$i_new_key];
+      $sip_data_array['mailbox']   =$newnums[$i_new_key]."@".$this->voice_context;
 
       /* Check if there is already an entry in sip_users for this uid */
       $SQL_query_array = array();
+
+      /* Enforce strict mode, ensures inout validation, e.g. target field length 
+       */
+      $SQL_query_array[] = "SET @@sql_mode = STRICT_ALL_TABLES;";
+
       $query = "SELECT * FROM ".$a_New['SIP_TABLE']." WHERE name='".$this->uid."';\n"; 
       $rid = mysql_query($query,$new_connection);
-      @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,$query, "Database query");
+      @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,$query, "Receive current mysql entries.");
       if(mysql_affected_rows($new_connection)){
 
         /********************** 
@@ -536,6 +752,7 @@ class phoneAccount extends plugin
         $sip_data_array['type']         = $s_type ;
         $sip_data_array['username']     = $this->uid;
         $sip_data_array['ipaddr']       = $s_ip;
+        $sip_data_array['context']      = $this->context;
 
         /* Remove not changed attributes, to avoid updating table with same values */
         foreach($sip_data_array as $name => $value){
@@ -554,25 +771,24 @@ class phoneAccount extends plugin
           $SQL_query_array[] = $query;
         }
       } else {
+
         /********************** 
          * Insert sip_users entry 
          **********************/
         //generate SIP entry
-        $sip_data_array['id']           = "";
         $sip_data_array['name']         = $this->uid;
         $sip_data_array['accountcode']  = NULL;          
         $sip_data_array['amaflags']     = NULL;
         $sip_data_array['callgroup']    = NULL;
         $sip_data_array['canreinvite']  = "no";
-        $sip_data_array['context']      = "default";
+        $sip_data_array['context']      = $this->context;
         $sip_data_array['defaultip']    = NULL;
         $sip_data_array['fromuser']     = NULL;
         $sip_data_array['fromdomain']   = NULL;
         $sip_data_array['host']         = $s_host;
         $sip_data_array['insecure']     = NULL;
         $sip_data_array['language']     = NULL;
-        $sip_data_array['mailbox']      = $newnums[$i_new_key];
+        $sip_data_array['mailbox']      = $newnums[$i_new_key]."@".$this->voice_context;
         $sip_data_array['md5secret']    = NULL;
         $sip_data_array['nat']          = "no";
         $sip_data_array['permit']       = NULL;
@@ -616,28 +832,39 @@ class phoneAccount extends plugin
        **********************/
 
       $customer_id = $newnums[$i_new_key];
+      $query  = "SELECT id,name,callerid FROM ".$a_New['SIP_TABLE']." WHERE name='".$this->uid."';";
+      $rid    = mysql_query($query,$new_connection);
+
+      @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,$query, "Receive callerid");
+      $result = mysql_fetch_assoc($rid);
+
+      $old_customer_id = ""; 
+      if($result){
+        $old_customer_id = $result['callerid'];
+      }
 
       $voice_data_array = array(
           "customer_id" => $customer_id,
           "mailbox"     => $customer_id,
           "password"    => $this->goFonVoicemailPIN,
           "fullname"    => $CNname,
+          "context"     => $this->voice_context,
           "email"       => $s_mail);
 
-      /* Set pager number if available */
-      if(isset($this->parent->by_object['user']->pager)){
-        $voice_data_array['pager']   = $this->parent->by_object['user']->pager;
-      }
+      $voice_data_array['pager']   = $this->pager;
 
       /* Check if there is already an entry in sip_users for this uid */
-      $query_tmp = "SELECT * FROM ".$a_New['VOICE_TABLE']." WHERE customer_id='".$customer_id."';\n";
+      $query_tmp = "SELECT * FROM ".$a_New['VOICE_TABLE']." WHERE customer_id='".$old_customer_id."';\n";
       $rid = mysql_query($query_tmp,$new_connection);
-      @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,$query_tmp, "Database query");
+
+      @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,$query_tmp, "Check if voicemail entry exists");
       if(mysql_affected_rows($new_connection)){
 
         /********************** 
          * Update Voice mail entry  
          **********************/
+
+        @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"", "<i>Voicemail entry exists, adding updating to queue.</i>");
         $result = mysql_fetch_assoc($rid)  ;
 
         foreach($voice_data_array as $name => $value){
@@ -646,14 +873,14 @@ class phoneAccount extends plugin
           }
         }
 
-        /* Only update entry if there is something to uopdate */
+        /* Only update entry if there is something to update */
         if(count($voice_data_array)){
           $query = "UPDATE ".$a_New['VOICE_TABLE']." SET ";
           foreach($voice_data_array as $key => $val){
             $query.= "".$key."='".$val."',"; 
           } 
           $query = preg_replace("/,$/","",$query);
-          $query.= " WHERE customer_id='".$customer_id."';";
+          $query.= " WHERE customer_id='".$old_customer_id."';";
           $SQL_query_array[] = $query;
         }
       }else{
@@ -661,8 +888,9 @@ class phoneAccount extends plugin
         /********************** 
          * Insert Voice mail entry  
          **********************/
-        $voice_data_array['context'] = "default";
-  
+        @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"", "<i>No voicemail entry found, add 'create' to queue.</i>");
+        $voice_data_array['context'] = $this->voice_context;
+
         /* There is currently no voice mail entry for this user. 
          * We should create one 
          */
@@ -679,40 +907,34 @@ class phoneAccount extends plugin
         $SQL_query_array[] ="INSERT INTO ".$a_New['VOICE_TABLE']." (".$s_voi_keys.") VALUES (".$s_voi_values.");";
       }
 
-     
+
       /********************** 
        * Remove/Insert extension entries
        **********************/
-      
-      /* Remove old entries */
-      $query = array();
-      $query[]= "DELETE FROM ".$a_New['EXT_TABLE']." WHERE exten=\"".$this->uid."\";";
+
+      /* Initiate transaction 
+       */
+      $SQL_query_array[]= "DELETE FROM ".$a_New['EXT_TABLE']." WHERE exten=\"".$this->uid."\";";
       $oldnums= array();
       foreach($oldnums as $s_telenums){
-        $query[]= "DELETE FROM ".$a_New['EXT_TABLE']." WHERE exten=\"".$s_telenums."\";";
+        $SQL_query_array[]= "DELETE FROM ".$a_New['EXT_TABLE']." WHERE exten=\"".$s_telenums."\";";
       }
       foreach($newnums as $s_telenums){
-        $query[]= "DELETE FROM ".$a_New['EXT_TABLE']." WHERE exten=\"".$s_telenums."\";";
-      }
-      foreach($query as $qry){
-        @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,$qry, "Database query");
-        if(!mysql_query($qry,$new_connection)){
-          trigger_error(mysql_error($new_connection));
-        } 
+        $SQL_query_array[]= "DELETE FROM ".$a_New['EXT_TABLE']." WHERE exten=\"".$s_telenums."\";";
       }
+
       /********************** 
        * Insert extension entries
        **********************/
+
       // Get selected Macro Parameter and create parameter entry 
       if(isset($this->macroarray[$this->macro])){
         foreach($this->macroarray[$this->macro] as $key => $val ){
-          $s_parameter .= $val['choosen']."|";
+          $s_parameter .= $val['choosen'].$this->delimiter;
         }
-        $s_parameter = preg_replace("/\|$/","",$s_parameter);
+        $s_parameter = rtrim($s_parameter, $this->delimiter);
       }
-     
+
       $i = 0; 
       $EXT = array();
       if(!is_numeric($this->uid)){
@@ -720,7 +942,7 @@ class phoneAccount extends plugin
         $EXT[$i]['exten']   = $this->uid;
         $EXT[$i]['priority']= 1;
         $EXT[$i]['app']     = "Goto";
-        $EXT[$i]['appdata'] = $newnums[$i_new_key]."|1";
+        $EXT[$i]['appdata'] = $newnums[$i_new_key].$this->delimiter."1";
         $i ++;
       }
 
@@ -730,7 +952,7 @@ class phoneAccount extends plugin
         /* Hint Entry */
         $EXT[$i]['context'] = 'GOsa';
         $EXT[$i]['exten']   = $s_telenums;
-        $EXT[$i]['priority']= "Hint";
+        $EXT[$i]['priority']= 0;
         $EXT[$i]['app']     = 'SIP/'.$this->uid;
         $i ++;  
         /* SetCID */
@@ -746,10 +968,10 @@ class phoneAccount extends plugin
           $macroname = preg_replace("/,.*$/","",$this->macro);        
           $macroname = preg_replace("/^.*=/","",$macroname);        
           $s_app = "Macro";$macroname;
-          $s_par = $macroname."|".$s_parameter; 
+          $s_par = $macroname.$this->delimiter.$s_parameter; 
         }else{
           $s_app = "Dial";
-          $s_par = 'SIP/'.$this->uid."|20|r";
+          $s_par = 'SIP/'.$this->uid.$this->delimiter."20".$this->delimiter."r";
         }
 
         $EXT[$i]['context'] = 'GOsa';
@@ -778,16 +1000,35 @@ class phoneAccount extends plugin
         $SQL_syn ="";
       }
 
-      // Perform queries ...
-      if($this->goFonHardware != "automatic"){
-        foreach($SQL_query_array as $query){
-          @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,$query, "Database query");
-          if(!@mysql_query($query,$new_connection)){
-            $this->generate_error =  msgPool::dbquery("GOfon",@mysql_error($old_connection));
-            return false;
-          }
-        }
+      /* Start transaction, to be able to rollback 
+       */
+      @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>---Insert/Update new entry---</b>","");
+
+      mysql_query("begin;",$new_connection);
+      @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>begin;</b>","<i>Starting transaction!</i>");
+
+      foreach($SQL_query_array as $query){
+        @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>".$query."</b>", "");
+        if(!mysql_query($query,$new_connection)){
+          $err = mysql_error($new_connection);
+          @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"\n".$err, "<b>FAILED</b>");
+          msg_dialog::display(_("Error"), 
+              msgPool::mysqlerror($err,__CLASS__)."&nbsp;".
+              "\n<p>"._("Please activate debugging for details!")."</p>",
+              ERROR_DIALOG);
+
+          mysql_query("rollback;",$new_connection);
+          @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>rollback;</b>", "<b>ERROR</b> Rollback transaction!");
+          @mysql_close($new_connection);
+          return(false);
+        } 
       }
+     
+      /* Let changes get active, everything was fine;
+       */ 
+      mysql_query("commit;",$new_connection);
+      @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>commit;</b>", "Perform transaction!");
+      @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>---Transaction sucessful!---</b>", "");
     }
     @mysql_close($new_connection);
     return true;
@@ -807,10 +1048,11 @@ class phoneAccount extends plugin
 
     $display = "";
     $SkipWrite = (!isset($this->parent) || !$this->parent) && !session::is_set('edit');
+
     if(empty($this->macro)&&(!empty($this->goFonMacro))){
 
       /* Go through already saved values, for a parameter */
-      $tmp = split("!",$this->goFonMacro);
+      $tmp = explode("!",$this->goFonMacro);
 
       /* it is possible that nothing has been saved yet */
       if(is_array($tmp)){
@@ -832,7 +1074,7 @@ class phoneAccount extends plugin
         foreach($tmp as $var){
 
           /* Split this, so we have $varar[0] = parameterID $varar[1] = SelectedValue */
-          $varar = split("#",$var);
+          $varar = explode("#",$var);
 
           /* Only insert if the parameter still exists */
           if(isset($this->macroarray[$this->macro][$varar[0]])){
@@ -845,7 +1087,7 @@ class phoneAccount extends plugin
     
     /* Do we represent a valid account? */
     if (!$this->is_account && $this->parent === NULL){
-      $display= "<img alt=\"\" src=\"images/stop.png\" align=\"middle\">&nbsp;<b>".
+      $display= "<img alt=\"\" src=\"images/small-error.png\" align=\"middle\">&nbsp;<b>".
         msgPool::noValidExtension(_("Phone"))."</b>";
       $display.= back_to_main();
       return ($display);
@@ -858,7 +1100,7 @@ class phoneAccount extends plugin
 
     /* Do we represent a valid account? */
     if (!$this->is_account && $this->parent === NULL){
-      $display= "<img alt=\"\" src=\"images/stop.png\" align=\"middle\">&nbsp;<b>".
+      $display= "<img alt=\"\" src=\"images/small-error.png\" align=\"middle\">&nbsp;<b>".
         msgPool::noValidExtension(_("Phone"))."</b>";
       $display.= back_to_main();
       return($display);
@@ -900,6 +1142,12 @@ class phoneAccount extends plugin
     $smarty->assign("macros",$this->macros);   
     $smarty->assign("macro", $this->macro);   
 
+    /* Assign contexts */
+    $smarty->assign("voicemail_contexts",$this->voicemail_contexts);
+    $smarty->assign("sip_contexts",$this->sip_contexts);
+    $smarty->assign("context" ,$this->context);
+    $smarty->assign("voice_context" ,$this->voice_context);
+
     /* check if there is a FON server created */
     if(!count($this->goFonHomeServer)){
       msg_dialog::display(_("Configuration error"), msgPool::noserver(_("GOfon")), WARNING_DIALOG);
@@ -926,6 +1174,9 @@ class phoneAccount extends plugin
           $string = $paras['default'];
 
           $string=preg_replace("/%uid/i",$this->uid,$string);
+          $string=preg_replace("/%pager/i",$this->pager,$string);
+          $string=preg_replace("/%context/i",$this->context,$string);
+          $string=preg_replace("/%voicemailcontext/i",$this->voice_context,$string);
 
           if(isset($this->cn)){
             $string=preg_replace("/%cn/i",$this->cn,$string);
@@ -964,7 +1215,7 @@ class phoneAccount extends plugin
 
           case "combo":
             $str= "<select name='".$var."' ".$dis." >";
-          foreach(split(":",$default) as $choice){
+          foreach(explode(":",$default) as $choice){
             if($choosen==$choice){
               $str.= "\n<option value='".$choice."' selected>".$choice."&nbsp;</option>";
             }else{
@@ -1002,8 +1253,11 @@ class phoneAccount extends plugin
 
     /* Add phone number */
     if (isset($_POST["add_phonenumber"]) && $_POST['phonenumber']){
-      if (tests::is_phone_nr($_POST['phonenumber'])){
-        $number= $_POST["phonenumber"];
+
+      if(strlen(trim($_POST["phonenumber"])) > 20 ){
+        msg_dialog::display(_("Error"), msgPool::toobig("Phone number"), ERROR_DIALOG);
+      }elseif (tests::is_phone_nr($_POST['phonenumber'])){
+        $number= trim($_POST["phonenumber"]);
         $this->phoneNumbers[$number]= $number;
         $this->is_modified= TRUE;
       } else {
@@ -1022,7 +1276,7 @@ class phoneAccount extends plugin
     /* Assign acls */
     $tmp = $this->plInfo();
     foreach($tmp['plProvidedAcls'] as $name => $translation){
-      $smarty->assign($name."ACL",$this->getacl($name));
+      $smarty->assign($name."ACL",$this->getacl($name,$SkipWrite));
     }
 
     /* Transfer ACL's */
@@ -1076,7 +1330,15 @@ class phoneAccount extends plugin
 
 
     foreach($this->attributes as $attr){
-      if(in_array($attr,$this->multi_boxes)){
+      if(in_array_strict($attr,$this->multi_boxes)){
+        $smarty->assign("use_".$attr,TRUE);
+      }else{
+        $smarty->assign("use_".$attr,FALSE);
+      }
+    }
+
+    foreach(array("goFonVoiceMailContext","goFonContext") as $attr){
+      if(in_array_strict($attr,$this->multi_boxes)){
         $smarty->assign("use_".$attr,TRUE);
       }else{
         $smarty->assign("use_".$attr,FALSE);
@@ -1112,6 +1374,7 @@ class phoneAccount extends plugin
 
       /* Every macro in the select box are available */
       if((isset($_POST['macro']))){
+        $this->macro = $_POST['macro'];
         $this->macrostillavailable=true;
       }
 
@@ -1119,6 +1382,22 @@ class phoneAccount extends plugin
         $this->is_modified =true;
       }
 
+      /* Save context */
+      if(isset($_POST['context'])){
+        if($this->context != $_POST['context']){
+          $this->is_modified= TRUE;
+        }
+        $this->context= $_POST['context'];
+      }
+
+      /* Save voice context */
+      if(isset($_POST['voice_context'])){
+        if($this->voice_context != $_POST['voice_context']){
+          $this->is_modified= TRUE;
+        }
+        $this->voice_context= $_POST['voice_context'];
+      }
+
       if(is_array($this->phoneNumbers)){
         foreach($this->phoneNumbers as $telenumms) {
           $nummsinorder[]=$telenumms; 
@@ -1131,9 +1410,11 @@ class phoneAccount extends plugin
       /* get all Postvars */
       if(isset($this->macroarray[$this->macro])){
 
-        if($this->acl_is_writeable("goFonMarco",$SkipWrite)){
+
+        if($this->acl_is_writeable("goFonMacro",$SkipWrite)){
           foreach($this->macroarray[$this->macro] as $key => $paras){
 
+            $old_macro_settings = $this->macroarray[$this->macro][$key]; 
             $backup = $this->macroarray[$this->macro][$key];
 
             if(isset($_POST[$paras['var']])){
@@ -1147,15 +1428,19 @@ class phoneAccount extends plugin
             if(isset($_POST['post_success'])){
               if($this->macroarray[$this->macro][$key]['type']=="bool"){
                 if(isset($_POST[$this->macroarray[$this->macro][$key]['var']])) {
-                  $this->macroarray[$this->macro][$key]['choosen']=$_POST[$paras['var']];
+                  $this->macroarray[$this->macro][$key]['choosen']=1;
                 }else{
-                  $this->macroarray[$this->macro][$key]['choosen']=false;
+                  $this->macroarray[$this->macro][$key]['choosen']=0;
                 }
               }
             }
+            if(array_differs($old_macro_settings,$this->macroarray[$this->macro][$key])){
+              $this->is_modified = TRUE;
+            }
           }
+
           if(count(array_diff($this->macroarray[$this->macro][$key],$backup))){
-            $this->modified = TRUE;
+            $this->is_modified = TRUE;
           }
         }
       }
@@ -1188,8 +1473,9 @@ class phoneAccount extends plugin
     }
 
     if ($this->initially_was_account != $this->is_account || $this->is_modified){
-      if(!$this->generate_mysql_entension_entries()){
-        $message[] = $this->generate_error;
+      $str = $this->generate_mysql_entension_entries(false);
+      if(empty($str)){
+        msg_dialog::display(_("Error"), $str, ERROR_DIALOG);
       }
     }
 
@@ -1198,6 +1484,27 @@ class phoneAccount extends plugin
       $message[]= msgPool::required("Phone number");
     }
 
+    /* Do not allow to save duplicate phone numbers 
+     *  this may destroy the extensions table.
+     */ 
+    $ldap = $this->config->get_ldap_link();
+    $ldap->cd($this->config->current['BASE']);  
+    $numberFilter = "";
+    foreach($this->phoneNumbers as $number){
+      $numberFilter .= "(telephoneNumber={$number})";
+    }
+    $ldap->search("(&(!(uid=".$this->uid."))(objectClass=goFonAccount)(|{$numberFilter}))",array("dn","telephoneNumber"));
+    $res = array();
+    while($attrs = $ldap->fetch()){
+      unset($attrs['telephoneNumber']['count']);
+      $res = array_merge($res,array_intersect($attrs['telephoneNumber'], $this->phoneNumbers));
+    }
+    $res = array_unique($res);
+    if(count($res)){
+      $message[] = msgPool::duplicated(_("Phone number"))."&nbsp;<br>".
+        implode(array_intersect($res, $this->phoneNumbers), ", ");
+    }
+
     /* check for ! in any parameter setting*/
     if(isset($this->macroarray[$this->macro])){
       foreach($this->macroarray[$this->macro] as $val){
@@ -1246,11 +1553,11 @@ class phoneAccount extends plugin
 
     $this->attrs['goFonForwarding']=array();
 
-    if ($this->initially_was_account != $this->is_account || $this->is_modified){
-      $str = $this->generate_mysql_entension_entries(true);
-      if(empty($str)){
-        msg_dialog::display(_("Error"), $str, ERROR_DIALOG);
-      }
+    /*
+     */
+    $str = $this->generate_mysql_entension_entries(true);
+    if(!$str){
+      msg_dialog::display(_("Error"),_("An error occured while updating the database entries!") , ERROR_DIALOG);
     }
 
     if($this->attrs['goFonMacro']==""){
@@ -1297,7 +1604,7 @@ class phoneAccount extends plugin
     plugin::adapt_from_template($dn, $skip);
 
     /* Assemble phone numbers */
-    if (isset($this->attrs['telephoneNumber']) && !in_array("telephoneNumber", $skip)){
+    if (isset($this->attrs['telephoneNumber']) && !in_array_strict("telephoneNumber", $skip)){
       for ($i= 0; $i<$this->attrs['telephoneNumber']['count']; $i++){
         $number= $this->attrs['telephoneNumber'][$i];
         $this->phoneNumbers[$number]= $number;
@@ -1310,18 +1617,20 @@ class phoneAccount extends plugin
   {
     if(!$this->initially_was_account) return;
 
-    foreach($this->attributes as $key=>$val){
-      if(in_array($val,array("uid","cn"))){
-        unset($this->attributes[$key]);
-        unset($this->$val);
-      }
-    }
     if(count($this->goFonHomeServers) && !empty($this->init_HomeServer) && is_callable("mysql_pconnect")){
 
       // Get Configuration for initial Mysql database Server
       $a_SETUP = $this->goFonHomeServers[$this->init_HomeServer];
       $s_parameter  ="";
 
+      /* Check table definitions
+       */
+      if(!phoneAccount::checkRealtimeTables($a_SETUP)){
+        msg_dialog::display(_("Warning"),
+            sprintf(_("GOsa identified problems with your MySQL table definition!")),
+            WARNING_DIALOG);
+      }
+
       // Connect to DB server
       $r_con =  @mysql_pconnect($a_SETUP['SERVER'],$a_SETUP['LOGIN'],$a_SETUP['PASSWORD']);
 
@@ -1343,15 +1652,7 @@ class phoneAccount extends plugin
       }
 
       $SQL="";
-
-      /* If deletion starts from userslist, cn uid are not set */
-      if((isset($this->parent->by_object['user']->uid))&&(!empty($this->parent->by_object['user']->uid))){
-        $this->uid = $this->parent->by_object['user']->uid;
-      }
-
-      if((isset($this->parent->by_object['user']->cn))&&(!empty($this->parent->by_object['user']->cn))){
-        $this->cn  = $this->parent->by_object['user']->cn;
-      }
+      $SQL[]= "SET @@sql_mode = STRICT_ALL_TABLES;";
 
       $first_num = false;
       // Delete old entries
@@ -1362,17 +1663,54 @@ class phoneAccount extends plugin
         $SQL[] = "DELETE FROM ".$a_SETUP['EXT_TABLE']." WHERE exten='".$s_telenums."';\n";
       }
 
-      $SQL[] = "DELETE FROM ".$a_SETUP['VOICE_TABLE']." WHERE customer_id='".$first_num."';";
+
+      $query  = "SELECT id,name,callerid FROM ".$a_SETUP['SIP_TABLE']." WHERE name='".$this->uid."';";
+      $rid    = mysql_query($query,$r_con);
+      @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,$query, "Database query");
+      $result = mysql_fetch_assoc($rid);
+      $callerid = $first_num;
+      if($result){
+        $callerid = $result['callerid'];
+      }
+
+      /* Set mode to strict
+         Strict disallows the addition of entries that do not match the targets field length.
+       */
+      $SQL[] = "DELETE FROM ".$a_SETUP['VOICE_TABLE']." WHERE customer_id='".$callerid."';";
       $SQL[] = "DELETE FROM ".$a_SETUP['EXT_TABLE']." WHERE exten='".$this->uid."';\n";
       $SQL[] = "DELETE FROM ".$a_SETUP['SIP_TABLE']." WHERE name='".$this->uid."';\n";
 
+      /* Start transaction, to be able to rollback
+       */
+      @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>---Removing entry from server---</b>","");
+
+      mysql_query("begin;",$r_con);
+      @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>begin;</b>","<i>Starting transaction!</i>");
+
       foreach($SQL as $query){
-        @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,$query, "Database query");
-        if(!@mysql_query($query,$r_con)){
-          msg_dialog::display(_("Error"), msgPool::dbquery("GOfon",@mysql_error()), ERROR_DIALOG);
-          return false;
+        @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>".$query."</b>", "");
+
+        if(!mysql_query($query,$r_con)){
+          $err = mysql_error($r_con);
+          @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"\n".$err, "<b>FAILED</b>");
+          msg_dialog::display(_("Error"),
+              msgPool::mysqlerror($err,__CLASS__)."&nbsp;".
+              "\n<p>"._("Please activate debugging for details!")."</p>",
+              ERROR_DIALOG);
+
+          mysql_query("rollback;",$r_con);
+          @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>rollback;</b>", "<b>ERROR</b> Rollback transaction!");
+          @mysql_close($r_con);
+          return(false);
         }
       }
+
+      /* Let changes get active, everything was fine;
+       */
+      mysql_query("commit;",$r_con);
+      @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>commit;</b>", "");
+      @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,"<b>---Transaction sucessful!---</b>", "");
+
     }else{
       msg_dialog::display(_("Configuration error"), msgPool::missingext("php-mysql"), WARNING_DIALOG);
       return false;
@@ -1402,7 +1740,7 @@ class phoneAccount extends plugin
     $ldap->cd($this->config->current['BASE']);
     $ldap->search("(&(objectClass=goFonQueue)(member=*))", array("member"));
     while($attr = $ldap->fetch()){
-      if(in_array($this->dn,$attr['member'])){
+      if(in_array_strict($this->dn,$attr['member'])){
         $new =new ogrouptabs($this->config, $this->config->data['TABS']['OGROUPTABS'],$attr['dn']);
         unset($new->by_object['ogroup']->memberList[$this->dn]);
         unset($new->by_object['ogroup']->member[$this->dn]);
@@ -1442,8 +1780,6 @@ class phoneAccount extends plugin
     }
 
     foreach($this->phoneNumbers as $num){
-      if(!isset($this->cn)) $this->cn = "";
-
       if((isset($numbers[$num]))&&(($numbers[$num]['uid'][0]!=$this->uid))){
         if(isset($numbers[$num]['uid'][0])){
           return sprintf(_("The specified telephonenumber '%s' is already assigned to '%s'."),$num,$numbers[$num]['uid'][0]);
@@ -1507,17 +1843,19 @@ class phoneAccount extends plugin
           "plSelfModify"    => TRUE,
           "plDepends"       => array("user"),
           "plPriority"      => 7,                                 // Position in tabs
-          "plSection"       => "personal",                        // This belongs to personal
-          "plCategory"      => array("gofonreport" => array("description" => _("GOfon reports"),
-              "objectClass" => "")),
+          "plSection"         => array("personal" => _("My account")),
+          "plCategory"        => array("users"),
+
 
           "plOptions"       => array(),
 
           "plProvidedAcls"  => array(
             "telephoneNumber"     => _("Telephone number"),
-            "goFonHomeServer"     => _("Home server"),
             "goFonMacro"          => _("Macro settings"),
             "goFonHardware"       => _("Phone hardware"),
+            "goFonHomeServer"     => _("Home server"),
+            "goFonContext"          => _("Phone context"),
+            "goFonVoiceMailContext" => _("Voice mail context"),
             "goFonPIN"            => _("Telephone pin"),
             "goFonVoicemailPIN"   => _("Voicemail pin"))
           ));
@@ -1568,6 +1906,7 @@ class phoneAccount extends plugin
       }
 
       if(isset($_POST['macro']) && $_POST['macro'] != $this->macro){
+        $this->macro = $_POST['macro'];
         $this->is_modified =true;
       }
 
@@ -1589,7 +1928,7 @@ class phoneAccount extends plugin
           }
         }
         if(count(array_diff($this->macroarray[$this->macro][$key],$backup))){
-          $this->modified = TRUE;
+          $this->is_modified = TRUE;
         }
       }
     }
@@ -1599,30 +1938,30 @@ class phoneAccount extends plugin
   {
     $message = plugin::multiple_check();
 
-    if(!count($this->goFonHomeServers) && in_array("goFonHomeServers",$this->multi_boxes)){
+    if(!count($this->goFonHomeServers) && in_array_strict("goFonHomeServers",$this->multi_boxes)){
       $message[] = _("There is currently no asterisk server defined!");
     }
 
-    if(empty($this->goFonHomeServer) && in_array("goFonHomeServers",$this->multi_boxes)){
+    if(empty($this->goFonHomeServer) && in_array_strict("goFonHomeServers",$this->multi_boxes)){
       $message[] = _("Asterisk server is invalid!");
     }
 
-    if(in_array("goFonVoicemailPIN",$this->multi_boxes) && 
+    if(in_array_strict("goFonVoicemailPIN",$this->multi_boxes) && 
         ( (strlen($this->goFonVoicemailPIN)==0)||
           (strlen($this->goFonVoicemailPIN)>4))){
       $message[]=(_("Voicemail PIN must be 4 characters long!"));
     }else{
-      if(preg_match("/[^0-9]/",$this->goFonVoicemailPIN) && in_array("goFonVoicemailPIN",$this->multi_boxes) ){
+      if(preg_match("/[^0-9]/",$this->goFonVoicemailPIN) && in_array_strict("goFonVoicemailPIN",$this->multi_boxes) ){
         $message[]=(_("Voicemail PIN contains invalid characters!"));
       }
     }
 
-    if(preg_match("/[^0-9a-z]/i",$this->goFonPIN) && in_array("goFonPIN",$this->multi_boxes)){
+    if(preg_match("/[^0-9a-z]/i",$this->goFonPIN) && in_array_strict("goFonPIN",$this->multi_boxes)){
       $message[]=(_("Phone pin contains invalid characters!"));
     }
 
     /* check for ! in any parameter setting*/
-    if(isset($this->macroarray[$this->macro]) && in_array("macro",$this->multi_boxes)){
+    if(isset($this->macroarray[$this->macro]) && in_array_strict("macro",$this->multi_boxes)){
       foreach($this->macroarray[$this->macro] as $val){
         if((strstr($val['choosen'],"!"))||(strstr($val['choosen'],"#"))){
           $message[] = sprintf(_("The parameter %s contains invalid char. '!,#' is used as delimiter"),$val['name']);
@@ -1636,13 +1975,40 @@ class phoneAccount extends plugin
   function get_multi_edit_values()
   {
     $ret = plugin::get_multi_edit_values();
-    if(in_array("macro",$this->multi_boxes)){
+    if(in_array_strict("macro",$this->multi_boxes)){
       $ret['macro'] = $this->macro;
       $ret['macroarray'] = $this->macroarray;
       $ret['macros'] = $this->macros;
     }
     return($ret);
   }
+
+
+  /* Return asterisk contexts
+   * Additionaly read contexts from file.
+   */
+  function get_asterisk_voicemail_contexts()
+  {
+    return($this->get_asterisk_contexts(CONFIG_DIR."/asterisk/voicemail_context.conf"));
+  }
+  function get_asterisk_sip_contexts()
+  {
+    return($this->get_asterisk_contexts(CONFIG_DIR."/asterisk/sip_context.conf"));
+  }
+  function get_asterisk_contexts($file)
+  {
+    $contexts = array();
+    if(file_exists($file) && is_readable($file)){
+      foreach(file($file) as $context){
+        $contexts[] = trim($context);
+      }
+    }else{
+      msg_dialog::display(_("Warning"), msgPool::cannotReadFile($file),WARNING_DIALOG);
+      $contexts[] = "default";
+    }
+    array_unique($contexts);
+    return($contexts);
+  }
 }
 
 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: