CVE-2016-7781 (published 2017-03-07T16:59Z)

SQL injection vulnerability in framework/modules/blog/controllers/blogController.php in Exponent CMS 2.3.9 and earlier allows remote attackers to execute arbitrary SQL commands via the author parameter.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 9.8, CRITICAL (CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-89
cwe_name: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
description: The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
extended_description: 
            
            
         
         

Fix information:
repo_url: https://github.com/exponentcms/exponent-cms
commit_details: repo_url: https://github.com/exponentcms/exponent-cms
author: dleffler
author_date: 2016-09-28 15:21:21-04:00
msg: iniitial effort to greatly enhance system security (xss, sql inject, file exploit, rce, etc...)
repository: repo_url: https://github.com/exponentcms/exponent-cms
repo_name: exponentcms/exponent-cms
description: Content Management, Simple.
repo_language: PHP
owner: exponentcms
file_changes: filename: expController.php
change_type: ModificationType.MODIFY
diff: @@ -41,11 +41,19 @@ abstract class expController {
         'create'    => 'Create',
         'edit'      => 'Edit',
         'delete'    => 'Delete',
-        'approve'  => 'Approval',
+    );
+    protected $m_permissions = array(  // standard set of actions requiring manage permission for all modules
+        'activate'  => 'Activate',
+        'approve'   => 'Approve',
+        'merge'     => 'Merge',
+        'rerank'    => 'ReRank',
+        'import'    => 'Import Items',
+        'export'    => 'Export Items'
     );
     protected $remove_permissions = array();  // $permissions not applicable for this module from above list
-    protected $add_permissions = array();  // additional $permissions processed for this module
-    public $requires_login = array(); // actions/methods which ONLY require user be logged in to access...$permissions take priority
+    protected $add_permissions = array();  // additional $permissions processed and visible  for this module
+    protected $manage_permissions = array();  // additional actions requiring manage permission in addition to $m_permissions
+    public $requires_login = array();  // actions/methods which ONLY require user be logged in to access...$permissions take priority
 
     public $filepath = ''; // location of this controller's files
     public $viewpath = ''; // location of this controllers views; defaults to controller file location
@@ -131,6 +139,8 @@ abstract class expController {
         $this->config = $config->config;
 
         $this->params = $params;
+        if (ENABLE_WORKFLOW)
+            $this->permissions = array_merge($this->permissions, array('approve'=>'Approval'));
     }
 
     /**
@@ -294,7 +304,7 @@ abstract class expController {
         $modelname = $this->basemodel_name;
 
         // get the tag being passed
-        $tag = new expTag($this->params['tag']);
+        $tag = new expTag(expString::escape($this->params['tag']));
 
         // find all the id's of the portfolios for this module
         $item_ids = $db->selectColumn($modelname, 'id', $this->aggregateWhereClause());
@@ -328,7 +338,7 @@ abstract class expController {
         assign_to_template(array(
             'page'        => $page,
             'items'       => $page->records,
-            'moduletitle' => ucfirst($modelname) . ' ' . gt('items tagged with') . ' "' . expString::sanitize($this->params['tag']) . '"',
+            'moduletitle' => ucfirst($modelname) . ' ' . gt('items tagged with') . ' "' . expString::escape($this->params['tag']) . '"',
             'rank'        => ($order === 'rank') ? 1 : 0
         ));
     }
@@ -454,7 +464,7 @@ abstract class expController {
         if (isset($this->params['id'])) {
             $id = $this->params['id'];
         } elseif (isset($this->params['title'])) {
-            $id = $this->params['title'];
+            $id = expString::escape($this->params['title']);
         }
 
         $record = new $modelname($id);
@@ -485,6 +495,7 @@ abstract class expController {
         $modelname = $this->basemodel_name;
         // first we'll check to see if this matches the sef_url field...if not then we'll look for the
         // title field
+        $this->params['title'] = expString::escape($this->params['title']);  // escape title to prevent sql injection
         $record = $this->$modelname->find('first', "sef_url='" . $this->params['title'] . "'");
         if (!is_object($record)) {
             $record = $this->$modelname->find('first', "title='" . $this->params['title'] . "'");
@@ -1012,7 +1023,7 @@ abstract class expController {
     public function rss() {
         require_once(BASE . 'external/feedcreator.class.php');
 
-        $id = isset($this->params['title']) ? $this->params['title'] : (isset($this->params['id']) ? $this->params['id'] : null);
+        $id = isset($this->params['title']) ? expString::escape($this->params['title']) : (isset($this->params['id']) ? $this->params['id'] : null);
         if (empty($id)) {
             $module = !empty($this->params['module']) ? $this->params['module'] : $this->params['controller'];
             $id = array('module' => $module, 'src' => $this->params['src']);
@@ -1143,7 +1154,7 @@ abstract class expController {
     }
 
     /**
-     * permission functions to aggregate a module's permissions based on add/remove permissions
+     * permission functions to aggregate a module's visible permissions based on add/remove permissions
      *
      * @return array
      */
@@ -1157,6 +1168,21 @@ abstract class expController {
         return $perms;
     }
 
+    /**
+     * permission functions to aggregate a module's permissions based on add/remove and manage permissions
+     *
+     * @return array
+     */
+    public function permissions_all() {
+        //set the permissions array
+        $perms = array();
+        foreach ($this->permissions as $perm => $name) {
+            if (!in_array($perm, $this->remove_permissions)) $perms[$perm] = $name;
+        }
+        $perms = array_merge($perms, $this->m_permissions, $this->add_permissions, $this->manage_permissions);
+        return $perms;
+    }
+
     // create a psuedo global permission specific to the module; return true grants permission, false continues with other permission checks
     public static function checkPermissions($permission, $location) {
         return false;

programming_language: PHP
filename: expFramework.php
change_type: ModificationType.MODIFY
diff: @@ -285,13 +285,13 @@ function renderAction(array $parms=array()) {
 
     // initialize the controller.
     $src = isset($parms['src']) ? $parms['src'] : null;
-    $controller = new $fullControllerName($src, $parms);    
-    
+    $controller = new $fullControllerName($src, $parms);
+
     //Set up the correct template to use for this action
     global $template;
     $view = !empty($parms['view']) ? $parms['view'] : $action;
     $template = expTemplate::get_template_for_action($controller, $view, $controller->loc);
-    
+
     //setup default model(s) for this controller's actions to use
     foreach ($controller->getModels() as $model) {
         $controller->$model = new $model(null,false,false);   //added null,false,false to reduce unnecessary queries. FJD
@@ -324,28 +324,30 @@ function renderAction(array $parms=array()) {
     }
 
     // check the perms for this action
-    $perms = $controller->permissions();
-    
+    $perms = $controller->permissions_all();
+
+    $common_action = null;
+    // action convention for controllers that manage more than one model (datatype).
+    // if you preface the name action name with a common crud action name we can check perms on
+    // it with the developer needing to specify any...better safe than sorry.
+    // i.e if the action is edit_mymodel it will be checked against the edit permission
+    if (stristr($parms['action'], '_'))
+        $parts = explode("_", $parms['action']);
+    else
+        $parts = preg_split('/(?=[A-Z])/', $parms['action']);  // account for actions with camelCase action/perm such as editItem
+    $common_action = isset($parts[0]) ? $parts[0] : null;
     // we have to treat the update permission a little different..it's tied to the create/edit
     // permissions.  Really the only way this will fail will be if someone bypasses the perm check
     // on the edit form somehow..like a hacker trying to bypass the form and just submit straight to
     // the action. To safeguard, we'll catch if the action is update and change it either to create or
     // edit depending on whether an id param is passed to. that should be sufficient.
-    $common_action = null;
-    //FIXME do we also need to account for actions with camelcase action/perm such as editItem ???
-    if ($parms['action'] == 'update') {
+    if ($parms['action'] == 'update' || $common_action == 'update') {
         $perm_action = (!isset($parms['id']) || $parms['id'] == 0) ? 'create' : 'edit';
-    } elseif ($parms['action'] == 'edit' && (!isset($parms['id']) || $parms['id'] == 0)) {
+    } elseif (($parms['action'] == 'edit' || $common_action == 'edit') && (!isset($parms['id']) || $parms['id'] == 0)) {
         $perm_action = 'create';
     } elseif ($parms['action'] == 'saveconfig') {
         $perm_action = 'configure';
     } else {
-        // action convention for controllers that manage more than one model (datatype). 
-        // if you preface the name action name with a common crud action name we can check perms on 
-        // it with the developer needing to specify any...better safe than sorry.
-        // i.e if the action is edit_mymodel it will be checked against the edit permission
-        if (stristr($parms['action'], '_')) $parts = explode("_", $parms['action']);
-        $common_action = isset($parts[0]) ? $parts[0] : null;
         $perm_action = $parms['action'];
     }
 
@@ -424,7 +426,7 @@ function renderAction(array $parms=array()) {
     } elseif (array_key_exists($perm_action, $controller->requires_login)) {
         // check if the action requires the user to at least be logged in
         if (!$user->isLoggedIn()) {
-            $msg = empty($controller->requires_login[$perm_action]) ? gt("You must be logged in to perform this action") : $controller->requires_login[$perm_action];
+            $msg = empty($controller->requires_login[$perm_action]) ? gt("You must be logged in to perform this action") : gt($controller->requires_login[$perm_action]);
             flash('error', $msg);
             notfoundController::handle_not_authorized();
             expHistory::redirecto_login();
@@ -432,16 +434,16 @@ function renderAction(array $parms=array()) {
     } elseif (array_key_exists($common_action, $controller->requires_login)) {
         // check if the action requires the user to at least be logged in
         if (!$user->isLoggedIn()) {
-            $msg = empty($controller->requires_login[$common_action]) ? gt("You must be logged in to perform this action") : $controller->requires_login[$common_action];
+            $msg = empty($controller->requires_login[$common_action]) ? gt("You must be logged in to perform this action") : gt($controller->requires_login[$common_action]);
             flash('error', $msg);
             notfoundController::handle_not_authorized();
             expHistory::redirecto_login();
         }
-    } 
-    
+    }
+
     // register this controllers permissions to the view for in view perm checks
     $template->register_permissions(array_keys($perms), $controller->loc);
-    
+
     // globalizing $user inside all templates
     $template->assign('user', $user);
 
@@ -486,7 +488,7 @@ function redirect_to($params=array(), $secure=false) {
     $link = (!is_array($params)) ? $params : $router->makeLink($params, false, $secure);
     header("Location: " . $link);
     exit();
-}   
+}
 
 function flash($name, $msg) {
     expQueue::flash($name, $msg);
@@ -514,7 +516,7 @@ function show_msg_queue($name=null) {
  */
 function assign_to_template(array $vars=array()) {
     global $template;
-    
+
     if (empty($template) || count($vars) == 0) return false;
     foreach ($vars as $key=>$val) {
         $template->assign($key, $val);
@@ -540,7 +542,7 @@ function get_common_template($view, $loc, $controllername='') {
     $controller = new stdClass();
     $controller->baseclassname = empty($controllername) ? 'common' : $controllername;
     $controller->loc = $loc;
-    
+
     $themepath = BASE . 'themes/' . DISPLAY_THEME . '/modules/common/views/' . $controllername . '/' . $view . '.tpl';
     $basenewuipath = BASE . 'framework/modules/common/views/' . $controllername . '/' . $view . '.newui.tpl';
     $basepath = BASE . 'framework/modules/common/views/' . $controllername . '/' . $view . '.tpl';
@@ -581,19 +583,19 @@ function get_config_templates($controller, $loc) {
     return expTemplate::get_config_templates($controller, $loc);
 
 //    global $db;
-    
+
     // set paths we will search in for the view
     $commonpaths = array(
         BASE.'framework/modules/common/views/configure',
         BASE.'themes/'.DISPLAY_THEME.'/modules/common/views/configure',
     );
-    
+
     $modpaths = array(
         $controller->viewpath.'/configure',
 	    BASE.'themes/'.DISPLAY_THEME.'/modules/'.$controller->relative_viewpath.'/configure'
     );
-    
-    // get the common configuration files    
+
+    // get the common configuration files
     $common_views = expTemplate::find_config_views($commonpaths, $controller->remove_configs);
     foreach ($common_views as $key=>$value) {
         $common_views[$key]['name'] = gt($value['name']);
@@ -608,7 +610,7 @@ function get_config_templates($controller, $loc) {
         $module_views[$key]['name'] = gt($value['name']);
     }
 
-    // look for a config form for this module's current view    
+    // look for a config form for this module's current view
 //    $controller->loc->mod = expModules::getControllerClassName($controller->loc->mod);
     //check to see if hcview was passed along, indicating a hard-coded module
 //    if (!empty($controller->params['hcview'])) {
@@ -625,7 +627,7 @@ function get_config_templates($controller, $loc) {
 //            $module_views[$viewname]['file'] =$path.'/'.$viewconfig;
 //        }
 //    }
-    
+
     // sort the views highest to lowest by filename
     // we are reverse sorting now so our array merge
     // will overwrite property..we will run array_reverse
@@ -671,7 +673,7 @@ function find_config_views($paths=array(), $excludes=array()) {
             }
         }
     }
-    
+
     return $views;
 }
 
@@ -759,12 +761,12 @@ function get_action_views($ctl, $action, $human_readable) {
 //    $controller = new $controllerName();
     $controller = expModules::getController($ctl);
 
-    // set path information 
+    // set path information
     $paths = array(
         $controller->viewpath,
         BASE.'themes/'.DISPLAY_THEME.'/modules/'.$controller->relative_viewpath,
     );
-    
+
     $views = array();
     foreach ($paths as $path) {
         if (is_readable($path)) {
@@ -804,7 +806,7 @@ function get_filedisplay_views() {
         BASE.'framework/modules/common/views/file/',
         BASE.'themes/'.DISPLAY_THEME.'modules/common/views/file/',
     );
-    
+
     $views = array();
     foreach ($paths as $path) {
         if (is_readable($path)) {
@@ -817,7 +819,7 @@ function get_filedisplay_views() {
             }
         }
     }
-    
+
     return $views;
 }
 

programming_language: PHP
filename: expRecord.php
change_type: ModificationType.MODIFY
diff: @@ -104,7 +104,7 @@ class expRecord {
         $needs_approval = $this->needs_approval && ENABLE_WORKFLOW;
 
         // if the user passed in arguments to this constructor then we need to
-        // retrieve objects 
+        // retrieve objects
 
         // If a number was sent in, we assume this is a DB record ID, so pull it
         if (!is_object($params) && !is_array($params)) {
@@ -122,7 +122,7 @@ class expRecord {
                 $params = array('title'=> $params);
             }
         } else {
-            // Otherwise we assume that in inbound is an array or Object to be processed as is.        
+            // Otherwise we assume that in inbound is an array or Object to be processed as is.
             $this->build($params);
         }
 
@@ -135,7 +135,7 @@ class expRecord {
             $this->publish_date = $this->created_at;
         }
 
-        // setup the exception array if it's not there.  This array tells the getAssociatedObjectsForThisModel() function which 
+        // setup the exception array if it's not there.  This array tells the getAssociatedObjectsForThisModel() function which
         // modules NOT to setup.  This stops us from getting infinite loops with many to many relationships.
         if (is_array($params)){
             $params['except']         = isset($params['except']) ? $params['except'] : array();
@@ -180,6 +180,11 @@ class expRecord {
         //eDebug("Supports Revisions:" . $this->supports_revisions);
 //        if ($this->supports_revisions && $range != 'revisions') $sql .= " AND revision_id=(SELECT MAX(revision_id) FROM `" . $db->prefix . $this->tablename . "` WHERE $where)";
 //        $sql .= empty($order) ? '' : ' ORDER BY ' . $order;
+        $order = expString::escape($order);
+        if ($limit !== null)
+            $limit = intval($limit);
+        if ($limitstart !== null)
+            $limitstart = intval($limitstart);
         $supports_revisions = $this->supports_revisions && ENABLE_WORKFLOW;
         if (ENABLE_WORKFLOW && $this->needs_approval) {
             $needs_approval = $user->id;
@@ -361,10 +366,10 @@ class expRecord {
         foreach ($table as $col=> $colDef) {
             // check if the DB column has a corresponding value in the params array
             // if not, we check to see if the column is boolean...if so we set it to false
-            // if not, then we check to see if we had a previous value in this particular 
+            // if not, then we check to see if we had a previous value in this particular
             // record.  if so we reset it to itself so we don't lose the existing value.
-            // this is good for when the developer is trying to update just a field or two 
-            // in an existing record. 
+            // this is good for when the developer is trying to update just a field or two
+            // in an existing record.
             if (array_key_exists($col, $params)) {
                 $value = is_array($params) ? $params[$col] : $params->$col;
                 if ($colDef[0] == DB_DEF_INTEGER || $colDef[0] == DB_DEF_ID) {
@@ -464,7 +469,7 @@ class expRecord {
 
         // Save this object's associated objects to the database.
         // FIXME: we're not going to do this automagically until we get the refreshing figured out.
-        //$this->saveAssociatedObjects(); 
+        //$this->saveAssociatedObjects();
 
         //Only grab fields that are valid and save this object
         $saveObj = new stdClass();
@@ -534,7 +539,7 @@ class expRecord {
         }
 
         // safeguard again loc data not being pass via forms...sometimes this happens when you're in a router
-        // mapped view and src hasn't been passed in via link to the form 
+        // mapped view and src hasn't been passed in via link to the form
         if (isset($this->id) && empty($this->location_data)) {
             $loc = $db->selectValue($this->tablename, 'location_data', 'id=' . $this->id);
             if (!empty($loc)) $this->location_data = $loc;

programming_language: PHP
filename: mysqli.php
change_type: ModificationType.MODIFY
diff: @@ -351,7 +351,7 @@ class mysqli_database extends database {
 	 * @param int|null $where
 	 * @return void
 	 */
-    function columnUpdate($table, $col, $val, $where=1) {         
+    function columnUpdate($table, $col, $val, $where=1) {
         $res = @mysqli_query($this->connection, "UPDATE `" . $this->prefix . "$table` SET `$col`='" . $val . "' WHERE $where");
         /*if ($res == null)
             return array();
@@ -484,8 +484,8 @@ class mysqli_database extends database {
     function selectObjectBySql($sql) {
         //$logFile = "C:\\xampp\\htdocs\\supserg\\tmp\\queryLog.txt";
         //$lfh = fopen($logFile, 'a');
-        //fwrite($lfh, $sql . "\n");    
-        //fclose($lfh);                 
+        //fwrite($lfh, $sql . "\n");
+        //fclose($lfh);
         $res = @mysqli_query($this->connection, $this->injectProof($sql));
         if ($res == null)
             return null;
@@ -740,8 +740,8 @@ class mysqli_database extends database {
 	 */
 	function lockTable($table,$lockType="WRITE") {
         $sql = "LOCK TABLES `" . $this->prefix . "$table` $lockType";
-       
-        $res = mysqli_query($this->connection, $sql); 
+
+        $res = mysqli_query($this->connection, $sql);
         return $res;
     }
 
@@ -750,11 +750,11 @@ class mysqli_database extends database {
 	 */
 	function unlockTables() {
         $sql = "UNLOCK TABLES";
-        
+
         $res = mysqli_query($this->connection, $sql);
         return $res;
     }
-    
+
 	/**
      * Insert an Object into some table in the Database
      *
@@ -768,7 +768,7 @@ class mysqli_database extends database {
      * @return int|void
      */
     function insertObject($object, $table) {
-        //if ($table=="text") eDebug($object,true); 
+        //if ($table=="text") eDebug($object,true);
         $sql = "INSERT INTO `" . $this->prefix . "$table` (";
         $values = ") VALUES (";
         foreach (get_object_vars($object) as $var => $val) {
@@ -828,7 +828,7 @@ class mysqli_database extends database {
             $object->revision_id++;
             //if ($table=="text") eDebug($object);
             $res = $this->insertObject($object, $table);
-            //if ($table=="text") eDebug($object,true); 
+            //if ($table=="text") eDebug($object,true);
             $this->trim_revisions($table, $object->$identifier, WORKFLOW_REVISION_LIMIT);
             return $res;
         }
@@ -838,7 +838,7 @@ class mysqli_database extends database {
             //if($is_revisioned && $var=='revision_id') $val++;
             if ($var{0} != '_') {
                 if (is_array($val) || is_object($val)) {
-                    $val = serialize($val);   
+                    $val = serialize($val);
                     $sql .= "`$var`='".$val."',";
                 } else {
                     $sql .= "`$var`='" . $this->escapeString($val) . "',";
@@ -850,7 +850,7 @@ class mysqli_database extends database {
             $sql .= $this->injectProof($where);
         else
             $sql .= "`" . $identifier . "`=" . $object->$identifier;
-        //if ($table == 'text') eDebug($sql,true);        
+        //if ($table == 'text') eDebug($sql,true);
         $res = (@mysqli_query($this->connection, $sql) != false);
         return $res;
     }
@@ -1109,7 +1109,7 @@ class mysqli_database extends database {
     }
 
 	/**
-	 * Unescape a string based on the database connection
+	 * Escape a string based on the database connection
 	 * @param $string
 	 * @return string
 	 */
@@ -1162,7 +1162,7 @@ class mysqli_database extends database {
      * @param string $sql The name of the table/object to look at
      * @return array
      */
-    function selectArraysBySql($sql) {        
+    function selectArraysBySql($sql) {
         $res = @mysqli_query($this->connection, $this->injectProof($sql));
         if ($res == null)
             return array();
@@ -1294,7 +1294,7 @@ class mysqli_database extends database {
 		while($row = mysqli_fetch_object($res)) {
 			$records[] = $row->Field;
 		}
-		
+
 		return $records;
 	}
 

programming_language: PHP
filename: expDatabase.php
change_type: ModificationType.MODIFY
diff: @@ -1099,14 +1099,14 @@ abstract class database {
 	abstract function inError();
 
 	/**
-	 * Unescape a string based on the database connection
+	 * Escape a string based on the database connection
 	 * @param $string
 	 * @return string
 	 */
 	abstract function escapeString($string);
 
     /**
-   	 * Unescape a string based on the database connection
+   	 * Attempt to prevent a sql injection
    	 * @param $string
    	 * @return string
    	 */

programming_language: PHP
filename: expPaginator.php
change_type: ModificationType.MODIFY
diff: @@ -23,14 +23,14 @@
  * and paginate them and optionally group the by category.
  * It automagically handles the calls to other pages
  * and has built-in sorting using the defined column headers.
- * 
+ *
  * Usage Example:
- *  
+ *
  * <code>
  *
  * $page = new expPaginator(array(
  *      'model'=>'faq',
- *      'where'=>1, 
+ *      'where'=>1,
  *      'limit'=>25,
  *      'order'=>'rank',
  *      'controller'=>$this->baseclassname,
@@ -38,7 +38,7 @@
  *      'columns'=>array('In FAQ'=>'include_in_faq', 'Submitted'=>'created_at', 'Submitted By'=>'submitter_name'),
  *  ));
  * </code>
- * 
+ *
  * @package Subsystems
  * @subpackage Subsystems
  */
@@ -52,7 +52,7 @@ class expPaginator {
     public $search_string = '';
 	public $sql = '';
     public $count_sql = '';
-	public $where = '';	
+	public $where = '';
 	public $controller = '';
 	public $action = '';
 	public $order = '';
@@ -91,7 +91,7 @@ class expPaginator {
 	/**#@+
      * @access public
      * @var array
-     */	
+     */
 	public $pages = array();
 	public $records = array();
     public $cats = array();
@@ -106,21 +106,21 @@ class expPaginator {
 	 * @return \expPaginator
 	 */
 	public function __construct($params=array()) {
-		global $router,$db;
+		global $router, $db;
 
         $this->pages_to_show = expTheme::is_mobile() ? 6 : 10; // fewer paging links for small devices
 		$this->where = empty($params['where']) ? null : $params['where'];
 		$this->records = empty($params['records']) ? array() : $params['records'];
 //		$this->limit = empty($params['limit']) ? 10 : $params['limit'];
-        $this->limit = empty($params['limit']) ? 0 : $params['limit'];
+        $this->limit = empty($params['limit']) ? 0 : intval($params['limit']);
         $this->page = empty($params['page']) ? 1 : intval($params['page']);
 		$this->action = empty($params['action']) ? '' : $params['action'];
 		$this->controller = empty($params['controller']) ? '' : $params['controller'];
 		$this->sql = empty($params['sql']) ? '' : $params['sql'];
         $this->count_sql = empty($params['count_sql']) ? '' : $params['count_sql'];
-		$this->order = empty($params['order']) ? 'id' : $params['order'];
-		$this->dir = empty($params['dir']) ? 'ASC' : $params['dir'];
-		$this->src = empty($params['src']) ? null : $params['src'];
+		$this->order = empty($params['order']) ? 'id' : expString::escape($params['order']);
+		$this->dir = empty($params['dir']) || !in_array($params['dir'], array('ASC', 'DESC')) ? 'ASC' : $params['dir'];
+		$this->src = empty($params['src']) ? null : expString::escape($params['src']);
         $this->categorize = empty($params['categorize']) ? false : $params['categorize'];
         $this->uncat = !empty($params['uncat']) ? $params['uncat'] : gt('Not Categorized');
         $this->groups = !empty($params['groups']) ? $params['groups'] : array();
@@ -137,7 +137,7 @@ class expPaginator {
             $this->model = $params['model'];
             $class = new $this->model(null, false, false);
         }
-	
+
 	    // auto-include the CSS for pagination links
 	    expCSS::pushToHead(array(
 //		    "unique"=>"pagination",
@@ -145,7 +145,7 @@ class expPaginator {
             'corecss'=>'pagination'
 		    )
 		);
-		
+
 		if ($this->limit)
             $this->start = (($this->page * $this->limit) - $this->limit);
         if ($this->start < 0)
@@ -167,12 +167,12 @@ class expPaginator {
 		        }
 		    }
 		}
-		
+
 		//setup the default ordering of records
 		// if we are in an action, see if the action is for this controller/action..if so pull the order
 		// and order direction from the request params...this is how the params are passed via the column
 		// headers.
-		$this->order_direction = $this->dir;	
+		$this->order_direction = $this->dir;
 
         // allow passing of a single order/dir as stored in config
         if (strstr($this->order," ")) {
@@ -180,6 +180,10 @@ class expPaginator {
             $this->order = $orderby[0];
             $this->order_direction = $orderby[1];
         }
+        if(!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $this->order))
+            $this->order = 'id';
+        if (!in_array($this->order_direction, array('ASC', 'DESC')))
+            $this->order_direction = 'ASC';
         if ($this->dontsort)
             $sort = null;
         else
@@ -209,13 +213,13 @@ class expPaginator {
             //this is MUCH faster if you supply a proper count_sql param using a COUNT() function; if not,
             //we'll run the standard sql and do a queryRows with it
 			//$this->total_records = $this->count_sql == '' ? $db->queryRows($this->sql) : $db->selectValueBySql($this->count_sql); //From Merge
-                        
+
 //			$this->total_records =  $db->countObjectsBySql($this->count_sql); //$db->queryRows($this->sql); //From most current Trunk
 
             if (!empty($sort)) $this->sql .= ' ORDER BY '.$sort;
             if (!empty($this->count_sql)) $this->total_records = $db->countObjectsBySql($this->count_sql);
 			if (!empty($this->limit)) $this->sql .= ' LIMIT '.$this->start.','.$this->limit;
-			
+
 			$this->records = array();
 			if (isset($this->model) || isset($params['model_field'])) {
 			    foreach($db->selectObjectsBySql($this->sql) as $record) {
@@ -227,7 +231,7 @@ class expPaginator {
 			} else {
 			    $this->records = $db->selectObjectsBySql($this->sql);
 			}
-		}	
+		}
 
         // next we'll sort them based on categories if needed
         if (!empty($this->categorize) && $this->categorize && empty($this->dontsort))
@@ -314,7 +318,7 @@ class expPaginator {
 			$this->firstrecord = 0;
 			$this->lastrecord = 0;
 		}
-			
+
 		// get the page parameters from the router to build the links
         $page_params = $router->params;
 //		$page_params = $this->cleanParams($router->params);
@@ -343,6 +347,10 @@ class expPaginator {
                 if ($this->controller == $mod && $this->action == $router->params['action']) {
                     $this->order = isset($router->params['order']) ? $router->params['order'] : $this->order;
                     $this->order_direction = isset($router->params['dir']) ? $router->params['dir'] : $this->dir;
+                    if(!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $this->order))
+                        $this->order = 'id';
+                    if (!in_array($this->order_direction, array('ASC', 'DESC')))
+                        $this->order_direction = 'ASC';
                 }
             } else {
                 if (isset($params->controller)) {
@@ -353,12 +361,12 @@ class expPaginator {
             }
             $page_params['controller'] = $mod;  // we can't be passing an empty controller or module to the router
         }
-		
+
 		if (!empty($this->action))
             $page_params['action'] =  $this->action;
 		if (!empty($this->src))
             $page_params['src'] =  $this->src;
-		
+
 		if (isset($page_params['section']))
             unset($page_params['section']);
 
@@ -370,10 +378,10 @@ class expPaginator {
 
 		//build a couple more links we can use in the views.
 		$this->pagelink = $router->makeLink($page_params, false, false, true);
-		
+
 		// if don't have enough records for more than one page then we're done.
 		//if ($this->total_records <= $this->limit) return true;
-		
+
 		$this->total_pages = ($this->limit > 0) ? ceil($this->total_records/$this->limit) : 0;
 
         // correct current page # to be within limits of number of pages
@@ -407,7 +415,7 @@ class expPaginator {
 		    $this->last_pagelink = $this->first_pagelink + $this->pages_to_show - 1;
 		    if ($this->last_pagelink > $this->total_pages) {
 		        $this->first_pagelink = max(1, $this->total_pages - $this->pages_to_show) + 1;
-		        $this->last_pagelink = $this->total_pages; 
+		        $this->last_pagelink = $this->total_pages;
 		    }
 		} else {
 			$this->first_pagelink = 1;
@@ -433,19 +441,19 @@ class expPaginator {
         }
 
 		// setup the links to the remaining pages being displayed.
-		for($i=$this->first_pagelink; $i<=$this->last_pagelink; $i++) { 
+		for($i=$this->first_pagelink; $i<=$this->last_pagelink; $i++) {
 			$page_params['page'] = $i;
 			$this->pages[$i] = $router->makeLink($page_params, false, false, true);
-		} 	
+		}
 
 		$links_template = expTemplate::get_common_template('pagination_links', null, 'common');
 		$links_template->assign('page', $this);
 		$this->links = $links_template->render();
-		
+
 		$this->makeHeaderCols($page_params);  // headers for table view
-         
+
         $sortparams = array_merge($page_params, $router->params);
-		
+
 		//From Merge ****
         if (isset($router->params['page']))
             $sortparams['page'] = $router->params['page'];
@@ -454,47 +462,47 @@ class expPaginator {
         //End From Merge ****
 
 		$this->makeSortDropdown($sortparams);  // used on non-table views
-       
+
         $table_template = expTemplate::get_common_template('pagination_table', null, 'common');
         $table_template->assign('page', $this);
         $this->table = $table_template->render();  // table view
-        
+
 	}
-	
+
 	//From Merge
     private function cleanParams($params) {
         $defaultParams = array('title'=>'','module'=>'','controller'=>'','src'=>'','id'=>'','dir'=>'','_common'=>'');
         $newParams = array();
-        $func = new ReflectionClass($this);       
+        $func = new ReflectionClass($this);
         foreach ($params as $pKey=>$pVal) {
             $propname = $pKey;
             if (array_key_exists($propname,$defaultParams)) {
-                $newParams[$propname] = $params[$propname];                
-            }               
-        }        
+                $newParams[$propname] = $params[$propname];
+            }
+        }
         foreach ($func->getProperties() as $p) {
             $propname = $p->name;
             if (array_key_exists($propname,$params)) {
-                $newParams[$propname] = $params[$propname];                
-            }               
-        }        
-        
+                $newParams[$propname] = $params[$propname];
+            }
+        }
+
         return $newParams;
     }
-    
+
     public function makeHeaderCols($params) {
         global $router;
 
         if (!empty($this->columns) && is_array($this->columns)) {
             $this->header_columns = '';
-            
+
             // get the parameters used to make this page.
             if (!expTheme::inAction()) {
                 unset($params['section']);
                 if (empty($params['controller'])) $params['controller'] = $this->controller;
                 if (empty($params['action'])) $params['action'] = $this->action;
             }
-            
+
 //            $current = '';
             if (isset($params['order'])) {
                 $current = $params['order'];
@@ -502,20 +510,20 @@ class expPaginator {
             } else {
                 $current = $this->order;
             }
-            
+
             //loop over the columns and build out a list of <th>'s to be used in the page table
             foreach ($this->columns as $colname=>$col) {
                 // if this is the column we are sorting on right now we need to setup some class info
                 $class = isset($this->class) ? $this->class : 'page';
                 $params['dir'] = 'ASC';
-                
+
                 if ($col == $current) {
                     $class  = 'current '.strtolower($this->order_direction);
                     $params['dir'] = $this->order_direction == 'ASC' ? 'DESC' : 'ASC';
-                } 
+                }
 
                 $params['order'] = $col;
-                
+
                 $this->header_columns .= '<th class="'.$class.'">';
                 // if this column is empty then it's not supposed to be a sortable column
 
@@ -524,7 +532,7 @@ class expPaginator {
                     $this->columns[$colname] = ' ';
                 } else if($colname=="actupon") {
                     $this->header_columns .= '<input type=checkbox name=selall id=selall value=1 class="select-all"/>';
-                    
+
 //                    $js = "
 //                    YUI(EXPONENT.YUI3_CONFIG).use('node', function(Y) {
 //                        Y.all('input[type=checkbox]').on('click',function(e){
@@ -565,12 +573,12 @@ class expPaginator {
                         $this->header_columns .= '<a href="'.$router->makeLink($params, false, false, true).'" alt="sort by '.$colname.'" rel="nofollow">'.$colname.'</a>';
                     }
                 }
-                
+
                 $this->header_columns .= '</th>';
             }
         }
     }
-    
+
     //here if we want to modify the record for some reason. e.g. Using in search results w/ products
     private function runCallback() {
         foreach ($this->records as &$record) {
@@ -585,9 +593,9 @@ class expPaginator {
                     }
                 }
             }
-        }    
+        }
     }
-    
+
 	public function makeSortDropdown($params) {
 		global $router;
 
@@ -600,7 +608,7 @@ class expPaginator {
 				if (empty($params['controller'])) $params['controller'] = $this->controller;
 				if (empty($params['action'])) $params['action'] = $this->action;
 			}
-			
+
 			/*$current = '';
 			if (isset($params['order'])) {
 				$current = $params['order'];
@@ -608,7 +616,7 @@ class expPaginator {
 			} else {
 				$current = $this->order;
 			}  */
-			
+
 			//loop over the columns and build out a list of <th>'s to be used in the page table
            // eDebug($router);
             $defaultParams['controller'] = $params['controller'];
@@ -617,13 +625,13 @@ class expPaginator {
                 $defaultParams['title'] = $params['title'];
             if (isset($params['page']))
                 $defaultParams['page'] = $params['page'];
-            
+
             $this->sort_dropdown[$router->makeLink($defaultParams, false, false, true)] = "Default";
 			foreach ($this->columns as $colname=>$col) {
 				// if this is the column we are sorting on right now we need to setup some class info
 				/*$class = isset($this->class) ? $this->class : 'page';
 				$params['dir'] = 'ASC';*/
-				
+
 				/*if ($col == $current) {
 					$class  = 'current';
 					$class .= ' '.$this->order_direction;
@@ -632,27 +640,27 @@ class expPaginator {
 					} else {
 						$params['dir'] = $this->order_direction == 'ASC' ? 'DESC' : 'ASC';
 					}
-				} 
+				}
                 */
-				$params['order'] = $col;      				                        
-				
-				if (!empty($col)) {	
+				$params['order'] = $col;
+
+				if (!empty($col)) {
                     if ($colname == 'Price') {
-                        $params['dir'] = 'ASC'; 
+                        $params['dir'] = 'ASC';
                         $this->sort_dropdown[$router->makeLink($params, false, false, true)] = $colname . " - Lowest to Highest";
-                        $params['dir'] = 'DESC'; 
+                        $params['dir'] = 'DESC';
                         $this->sort_dropdown[$router->makeLink($params, false, false, true)] = $colname . " - Highest to Lowest";
                     } else {
-                        $params['dir'] = 'ASC'; 
+                        $params['dir'] = 'ASC';
                         $this->sort_dropdown[$router->makeLink($params, false, false, true)] = $colname . " - A-Z";
                         $params['dir'] = 'DESC';
                         $this->sort_dropdown[$router->makeLink($params, false, false, true)] = $colname . " - Z-A";
-                    }	
-				}                  								
+                    }
+				}
 			}
 		}
 	}
-	
+
     /** exdoc
      * Object/Array sorting comparison function -- sorts by a specified column in ascending order.
      * @node Subsystems:expPaginator

programming_language: PHP
filename: expSettings.php
change_type: ModificationType.MODIFY
diff: @@ -191,13 +191,13 @@ class expSettings
 //                $value = str_replace(array('\r\n', '\r', '\n'), "", $value);
                 $str .= "exponent_unhtmlentities('$value')";
             } elseif (is_int($value)) {
-                $str .= "'" . $value . "'";
+                $str .= "'" . intval($value) . "'";
             } else {
                 if ($directive != 'SESSION_TIMEOUT') {
-                    $str .= "'" . str_replace("'", "\'", $value) . "'";  //FIXME is this still necessary since we stripslashes above???
+                    $str .= "'" . expString::escape(str_replace("'", "\'", $value)) . "'";  //FIXME is this still necessary since we stripslashes above???
                 } //                    $str .= "'".$value."'";
                 else {
-                    $str .= "'" . str_replace("'", '', $value) . "'";
+                    $str .= "'" . expString::escape(str_replace("'", '', $value)) . "'";
                 }
             }
             $str .= ");\n";
@@ -584,6 +584,10 @@ class expSettings
      */
     public static function activateProfile($profile)
     {
+        if (!empty($profile) && (strpos($profile, '..') !== false || strpos($profile, '/') !== false)) {
+            header('Location: ' . URL_FULL);
+            exit();  // attempt to hack the site
+        }
         if (is_readable(BASE . "framework/conf/profiles/$profile.php") && expUtil::isReallyWritable(
                 BASE . "framework/conf"
             )
@@ -635,4 +639,4 @@ class expSettings
 
 expSettings::initialize();  // auto-initialize when loaded
 
-?>
\ No newline at end of file
+?>

programming_language: PHP
filename: expString.php
change_type: ModificationType.MODIFY
diff: @@ -34,7 +34,7 @@ class expString {
      */
 	static function convertUTF($string) {
 		return $string = str_replace('?', '', htmlspecialchars($string, ENT_IGNORE, 'UTF-8'));
-	} 
+	}
 
     /**
      * Routine to check if string is valid UTF string
@@ -46,7 +46,7 @@ class expString {
 	static function validUTF($string) {
 		if(!mb_check_encoding($string, 'UTF-8') OR !($string === mb_convert_encoding(mb_convert_encoding($string, 'UTF-32', 'UTF-8' ), 'UTF-8', 'UTF-32'))) {
 			return false;
-		}		
+		}
 		return true;
 	}
 
@@ -105,9 +105,9 @@ class expString {
         $str = str_replace("¾","&#190;",$str);
 		$str = str_replace("™","&trade;", $str);
 		$str = trim($str);
-		
+
         if ($unescape) {
-			$str = stripcslashes($str);  
+			$str = stripcslashes($str);
 		} else {
 	        $str = addslashes($str);
         }
@@ -130,15 +130,15 @@ class expString {
         $str = str_replace("&quot;",'"',$str);
         $str = str_replace("&#39;","'",$str);
         $str = str_replace("&rsquo;","'",$str);
-        $str = str_replace("&lsquo;","'",$str);        
+        $str = str_replace("&lsquo;","'",$str);
         $str = str_replace("&#174;","",$str);
         $str = str_replace("�","-", $str);
-        $str = str_replace("�","-", $str); 
+        $str = str_replace("�","-", $str);
         $str = str_replace("�", '"', $str);
         $str = str_replace("&rdquo;",'"', $str);
         $str = str_replace("�", '"', $str);
         $str = str_replace("&ldquo;",'"', $str);
-        $str = str_replace("\r\n"," ",$str); 
+        $str = str_replace("\r\n"," ",$str);
         $str = str_replace("�"," 1/4",$str);
         $str = str_replace("&#188;"," 1/4", $str);
         $str = str_replace("�"," 1/2",$str);
@@ -148,9 +148,9 @@ class expString {
         $str = str_replace("�", "(TM)", $str);
         $str = str_replace("&trade;","(TM)", $str);
         $str = str_replace("&reg;","(R)", $str);
-        $str = str_replace("�","(R)",$str);        
-        $str = str_replace("&","&amp;",$str);      
-		$str = str_replace(">","&gt;",$str);      		
+        $str = str_replace("�","(R)",$str);
+        $str = str_replace("&","&amp;",$str);
+		$str = str_replace(">","&gt;",$str);
         return trim($str);
 	}
 
@@ -449,7 +449,7 @@ class expString {
 
     public static function parseAndTrimImport($str, $isHTML = false) { //�Death from above�? �
         //echo "1<br>"; eDebug($str);
-        global $db;
+//        global $db;
 
         $str = str_replace("�", "&rsquo;", $str);
         $str = str_replace("�", "&lsquo;", $str);
@@ -471,13 +471,13 @@ class expString {
         //$str = htmlspecialchars($str);
         //$str = utf8_encode($str);
 //        if (DB_ENGINE=='mysqli') {
-//	        $str = @mysqli_real_escape_string($db->connection,trim(str_replace("�", "&trade;", $str)));
+//	        $str = self::escape(trim(str_replace("�", "&trade;", $str)));
 //        } elseif(DB_ENGINE=='mysql') {
-//            $str = @mysql_real_escape_string(trim(str_replace("�", "&trade;", $str)),$db->connection);
+//            $str = self::escape(trim(str_replace("�", "&trade;", $str)));
 //        } else {
 //	        $str = trim(str_replace("�", "&trade;", $str));
 //        }
-        $str = @$db->escapeString($db->connection, trim(str_replace("�", "&trade;", $str)));
+        $str = self::escape(trim(str_replace("�", "&trade;", $str)));
         //echo "2<br>"; eDebug($str,die);
         return $str;
     }

programming_language: PHP
filename: expTheme.php
change_type: ModificationType.MODIFY
diff: @@ -241,13 +241,19 @@ class expTheme
             $config['meta']['ie_compat'] = true;
         }
 
-        $str = '<title>' . $metainfo['title'] . "</title>\n";
+        $str = '';
         if ($config['meta']['content_type']) {
-            $str .= "\t" . '<meta http-equiv="Content-Type" content="text/html; charset=' . LANG_CHARSET . '" ' . XHTML_CLOSING . '>' . "\n";
+            $str .= '<meta charset="' . LANG_CHARSET . XHTML_CLOSING . '>' . "\n";  // html5
+            $str .= "\t" . '<meta http-equiv="Content-Type" content="text/html; charset=' . LANG_CHARSET . '" ' . XHTML_CLOSING . '>' . "\n";  // html4 or xhtml?
         }
+        if ($config['meta']['ie_compat']) {
+            // turn off ie compatibility mode which will break the display
+            $str .= "\t" . '<meta http-equiv="X-UA-Compatible" content="IE=edge"' . XHTML_CLOSING . '>' . "\n";
+        }
+        $str .= "\t" . '<title>' . $metainfo['title'] . "</title>\n";
         $locale = strtolower(str_replace('_', '-', LOCALE));
         if ($config['meta']['content_language']) {
-            $str .= "\t" . '<meta content="' . $locale . '" http-equiv="Content-Language" ' . XHTML_CLOSING . '>' . "\n";
+            $str .= "\t" . '<meta http-equiv="Content-Language" content="' . $locale . '" ' . XHTML_CLOSING . '>' . "\n";
         }
         if ($config['meta']['generator']) {
             $str .= "\t" . '<meta name="Generator" content="Exponent Content Management System - v' . expVersion::getVersion(
@@ -361,9 +367,6 @@ class expTheme
             //Win 8/IE 10 work around
             $str .= "\t" . '<!--[if IE 10]><link rel="stylesheet" href="' . PATH_RELATIVE . 'external/ie10-viewport-bug-workaround.css" type="text/css"' . XHTML_CLOSING . '><![endif]-->' . "\n";
             $str .= "\t" . '<!--[if IE 10]><script src="' . PATH_RELATIVE . 'external/ie10-viewport-bug-workaround.js"></script><![endif]-->' . "\n";
-
-            // turn off ie compatibility mode which will break the display
-            $str .= "\t" . '<meta http-equiv="X-UA-Compatible" content="IE=edge"' . XHTML_CLOSING . '>' . "\n";
         }
 
         return $str;
@@ -1970,4 +1973,4 @@ class expTheme
 
 }
 
-?>
\ No newline at end of file
+?>

programming_language: PHP
filename: addressController.php
change_type: ModificationType.MODIFY
diff: @@ -22,17 +22,17 @@
  */
 
 class addressController extends expController {
-	public $useractions = array(
+//	public $useractions = array(
 //        'myaddressbook'=>'Show my addressbook'
-    );
+//    );
     protected $remove_permissions = array(
         'create',
         'edit',
         'delete'
     );
-    protected $add_permissions = array(
-        'import' => 'Import External Addresses',
-//        'export' => 'Export External Addresses'
+    protected $manage_permissions = array(
+//        'import' => 'Import External Addresses',
+        'process' => 'Import External Addresses'
     );
 	public $remove_configs = array(
         'aggregation',
@@ -59,7 +59,7 @@ class addressController extends expController {
 //        redirect_to(array("controller"=>'address',"action"=>'myaddressbook'));
         $this->myaddressbook();
 	}
-    
+
     public function edit()
     {
         if((isset($this->params['id']))) $record = new address(intval($this->params['id']));
@@ -75,7 +75,7 @@ class addressController extends expController {
             ));
         }
     }
-    
+
 	public function myaddressbook() {
 		global $user;
 
@@ -87,7 +87,7 @@ class addressController extends expController {
             'addresses'=>$this->address->find('all', 'user_id='.$userid)
         ));
 	}
-	
+
 	function show() {
 	    expHistory::set('viewable', $this->params);
 		assign_to_template(array(
@@ -111,7 +111,7 @@ class addressController extends expController {
 			// check to see how many other addresses this user has already.
 			$count = $this->address->find('count', 'user_id='.$user->id);
 			// if this is first address save for this user we'll make this the default
-			if ($count == 0) 
+			if ($count == 0)
             {
                 $this->params['is_default'] = 1;
                 $this->params['is_billing'] = 1;
@@ -123,22 +123,22 @@ class addressController extends expController {
 			$this->address->update($this->params);
 		}
         else { //if (ecomconfig::getConfig('allow_anonymous_checkout')){
-            //user is not logged in, but allow anonymous checkout is enabled so we'll check 
+            //user is not logged in, but allow anonymous checkout is enabled so we'll check
             //a few things that we don't check in the parent 'stuff and create a user account.
             $this->params['is_default'] = 1;
             $this->params['is_billing'] = 1;
-            $this->params['is_shipping'] = 1; 
+            $this->params['is_shipping'] = 1;
             $this->address->update($this->params);
         }
-		expHistory::back(); 
+		expHistory::back();
 	}
-	
+
 	public function delete() {
 	    global $user;
 
         $count = $this->address->find('count', 'user_id=' . $user->id);
         if($count > 1)
-        {    
+        {
             $address = new address($this->params['id']);
 	        if ($user->isAdmin() || ($user->id == $address->user_id)) {
                 if ($address->is_billing)
@@ -147,7 +147,7 @@ class addressController extends expController {
                     $billAddress->is_billing = true;
                     $billAddress->save();
                 }
-                if ($address->is_shipping) 
+                if ($address->is_shipping)
                 {
                     $shipAddress = $this->address->find('first', 'user_id=' . $user->id . " AND id != " . $address->id);
                     $shipAddress->is_shipping = true;
@@ -162,33 +162,33 @@ class addressController extends expController {
         }
 	    expHistory::back();
 	}
-    
+
     public function activate_address()
     {
         global $db, $user;
 
         $object = new stdClass();
         $object->id = $this->params['id'];
-        $db->setUniqueFlag($object, 'addresses', $this->params['is_what'], "user_id=" . $user->id);
+        $db->setUniqueFlag($object, 'addresses', expString::escape($this->params['is_what']), "user_id=" . $user->id);
         flash("message", gt("Successfully updated address."));
-        expHistory::back(); 
+        expHistory::back();
     }
-    
+
     public function manage()
     {
         expHistory::set('manageable',$this->params);
         $gc = new geoCountry();
         $countries = $gc->find('all');
-        
-        $gr = new geoRegion();             
+
+        $gr = new geoRegion();
         $regions = $gr->find('all',null,'rank asc,name asc');
-        
+
         assign_to_template(array(
             'countries'=>$countries,
             'regions'=>$regions
         ));
     }
-    
+
     public function manage_update()
     {
         global $db;
@@ -199,16 +199,16 @@ class addressController extends expController {
         foreach($this->params['country'] as $country_id=>$is_active)
         {
             $gc = new geoCountry($country_id);
-            $gc->active = true;            
-            $gc->save();            
+            $gc->active = true;
+            $gc->save();
         }
         //country default
         $db->columnUpdate('geo_country','is_default',0,'is_default=1');
         if(isset($this->params['country_default']))
         {
-            $gc = new geoCountry($this->params['country_default']);            
-            $db->setUniqueFlag($gc,'geo_country','is_default','id=' . $gc->id);    
-            $gc->refresh();            
+            $gc = new geoCountry(intval($this->params['country_default']));
+            $db->setUniqueFlag($gc,'geo_country','is_default','id=' . $gc->id);
+            $gc->refresh();
         }
         //regions
         $db->columnUpdate('geo_region','active',0,'active=1');
@@ -217,7 +217,7 @@ class addressController extends expController {
             $gr = new geoRegion($region_id);
             $gr->active = true;
             if(isset($this->params['region_rank'][$region_id])) $gr->rank = $this->params['region_rank'][$region_id];
-            $gr->save();            
+            $gr->save();
         }
         flash('message',gt('Address configurations successfully updated.'));
         redirect_to(array('controller'=>'address','action'=>'manage'));

programming_language: PHP
filename: administrationController.php
change_type: ModificationType.MODIFY
diff: @@ -24,17 +24,17 @@
 
 class administrationController extends expController {
     public $basemodel_name = 'expRecord';
-    protected $add_permissions = array(
+    protected $manage_permissions = array(
+        'change'=>'Change Settings',
 	    'clear'=>'Clear Caches',  //FIXME this requires a logged in user to perform?
 	    "fix"=>"Fix Database",
 	    "install"=>"Installation",
+        'mass'=>'Mass Mailing',
+        'save'=>'Save Settings',
 	    "theme"=>"Manage Themes",
 	    'test_smtp'=>'Test SMTP Server Settings',
 	    'toggle'=>'Toggle Settings',
-        'mass'=>'Mass Mailing',
-        'update'=>'Update Settings',
-        'change'=>'Change Settings',
-        'save'=>'Save Settings',
+//        'update'=>'Update Settings',
     );
 
     static function displayname() { return gt("Administration Controls"); }
@@ -62,7 +62,7 @@ class administrationController extends expController {
 
     public function manage_unused_tables() {
         global $db;
-        
+
         expHistory::set('manageable', $this->params);
         $unused_tables = array();
         $used_tables = array();
@@ -114,12 +114,12 @@ class administrationController extends expController {
                 $unused_tables[$basename]->rows = $db->countObjects($basename);
             }
         }
-        
+
         assign_to_template(array(
             'unused_tables'=>$unused_tables
         ));
     }
-    
+
     public function delete_unused_tables() {
         global $db;
 
@@ -128,7 +128,7 @@ class administrationController extends expController {
             $basename = str_replace($db->prefix, '', $table);
             $count += $db->dropTable($basename);
         }
-        
+
         flash('message', gt('Deleted').' '.$count.' '.gt('unused tables').'.');
         expHistory::back();
     }
@@ -147,14 +147,14 @@ class administrationController extends expController {
         ));
 	}
 
-	public function fixsessions() {
-	    global $db;
-
-//		$test = $db->sql('CHECK TABLE '.$db->prefix.'sessionticket');
-		$fix = $db->sql('REPAIR TABLE '.$db->prefix.'sessionticket');
-		flash('message', gt('Sessions Table was Repaired'));
-		expHistory::back();
-	}
+//	public function fix_sessions() {
+//	    global $db;
+//
+////		$test = $db->sql('CHECK TABLE '.$db->prefix.'sessionticket');
+//		$fix = $db->sql('REPAIR TABLE '.$db->prefix.'sessionticket');
+//		flash('message', gt('Sessions Table was Repaired'));
+//		expHistory::back();
+//	}
 
 	public function fix_database() {
 	    global $db;
@@ -218,7 +218,6 @@ class administrationController extends expController {
                     $newSecRef->refcount = 1;
 //                    $newSecRef->is_original = 1;
 					$eloc = expUnserialize($container->external);
-//					$section = $db->selectObject('sectionref',"module='containermodule' AND source='".$eloc->src."'");
                     $section = $db->selectObject('sectionref',"module='container' AND source='".$eloc->src."'");
 					if (!empty($section)) {
 						$newSecRef->section = $section->id;
@@ -286,28 +285,28 @@ class administrationController extends expController {
 		}
 
         // sort the top level menus alphabetically by filename
-		ksort($menu);		
+		ksort($menu);
 		$sorted = array();
 		foreach($menu as $m) $sorted[] = $m;
-        
+
         // slingbar position
         if (isset($_COOKIE['slingbar-top'])){
             $top = $_COOKIE['slingbar-top'];
         } else {
             $top = SLINGBAR_TOP;
         }
-        
+
 		assign_to_template(array(
             'menu'=>(bs3()) ? $sorted : json_encode($sorted),
             "top"=>$top
         ));
     }
-    
+
 //    public function index() {
 //        redirect_to(array('controller'=>'administration', 'action'=>'toolbar'));
 ////        $this->toolbar();
 //    }
-    
+
     public function update_SetSlingbarPosition() {
         setcookie('slingbar-top', $this->params['top']);
         expHistory::back();
@@ -385,7 +384,7 @@ class administrationController extends expController {
         }
     	expHistory::back();
     }
-    
+
 	public function toggle_dev() {
         if (!expUtil::isReallyWritable(BASE.'framework/conf/config.php')) {  // we can't write to the config.php file
             flash('error',gt('The file /framework/conf/config.php is NOT Writeable. You will be unable to change Error Reporting settings.'));
@@ -1047,7 +1046,7 @@ class administrationController extends expController {
             'themes'=>$themes
         ));
     }
-    
+
     public function theme_switch() {
         if (!expUtil::isReallyWritable(BASE.'framework/conf/config.php')) {  // we can't write to the config.php file
             flash('error',gt('The file /framework/conf/config.php is NOT Writeable. You will be unable to change the theme.'));
@@ -1074,8 +1073,8 @@ class administrationController extends expController {
 //        expTheme::removeSmartyCache();
         expSession::clearAllUsersSessionCache();
     	expHistory::returnTo('manageable');
-    }	
-    
+    }
+
 	public function theme_preview() {
 		expSession::set('display_theme',$this->params['theme']);
 		$sv = isset($this->params['sv'])?$this->params['sv']:'';
@@ -1179,13 +1178,13 @@ class administrationController extends expController {
             '0'=>'-- '.gt('Please Select an Anti-Spam Control').' --',
             "recaptcha"=>'reCAPTCHA'
         );
-        
+
         //THEMES FOR RECAPTCHA
         $as_themes = array(
             "light"=>gt('Light (Default)'),
         	"dark"=>gt('Dark'),
         );
-        
+
         // Available Themes
         $themes = array();
         if (is_readable(BASE.'themes')) {
@@ -1243,16 +1242,16 @@ class administrationController extends expController {
         $attribution = expSettings::dropdownData('attribution');
 
         // These funcs need to be moved up in to new subsystems
-        
+
         // Date/Time Format
         $datetime_format = expSettings::dropdownData('datetime_format');
 
         // Date Format
         $date_format = expSettings::dropdownData('date_format');
-        
+
         // Time Format
         $time_format = expSettings::dropdownData('time_format');
-        
+
         // Start of Week
 //        $start_of_week = glist(expSettings::dropdownData('start_of_week'));
         $daysofweek = event::dayNames();
@@ -1260,7 +1259,7 @@ class administrationController extends expController {
 
         // File Permissions
         $file_permisions = glist(expSettings::dropdownData('file_permissions'));
-        
+
         // File Permissions
         $dir_permissions = glist(expSettings::dropdownData('dir_permissions'));
 

programming_language: PHP
filename: bannerController.php
change_type: ModificationType.MODIFY
diff: @@ -22,6 +22,12 @@
  */
 
 class bannerController extends expController {
+    public $useractions = array(
+        'showall'=>'Display Banner(s)'
+    );
+    protected $manage_permissions = array(
+        'reset' => 'Reset Stats'
+    );
     public $remove_configs = array(
         'aggregation',
         'categories',
@@ -34,43 +40,40 @@ class bannerController extends expController {
         'tags',
         'twitter',
     ); // all options: ('aggregation','categories','comments','ealerts','facebook','files','module_title','pagination','rss','tags','twitter',)
-    public $useractions = array(
-        'showall'=>'Display Banner(s)'
-    );
 
     static function displayname() { return gt("Banners"); }
     static function description() { return gt("Display banners on your website and track 'clicks'."); }
-    
+
     public function showall() {
         $banners = array();
         if (!empty($this->config['banners'])) {
             // only show banners that this module is configured to show.
             // do not show banners that have gone over their impression limit
             // do not show banners that have gone over their click limit
-            // randomly grab one banner to be displayed 
+            // randomly grab one banner to be displayed
             // increase the impression count for this banner
-            $where = 'id IN ('.implode(',', $this->config['banners']).')';    
+            $where = 'id IN ('.implode(',', $this->config['banners']).')';
             $where .= ' AND (impression_limit > impressions || impression_limit=0)';
             $where .= ' AND (click_limit > clicks || click_limit=0)';
             $limit = isset($this->config['limit']) ? $this->config['limit'] : 1;
             $banners = $this->banner->find('all', $where , 'RAND()', $limit);
-            foreach($banners as $banner) {            
+            foreach($banners as $banner) {
                 $banner->increaseImpressions();
             }
         }
-        
+
         // assign banner to the template and show it!
         assign_to_template(array(
             'banners'=>$banners
         ));
     }
-    
+
     public function click() {
         $banner = new banner($this->params['id']);
         $banner->increaseClicks();
         redirect_to($banner->url);
     }
-    
+
     public function create() {
 //        global $db;
         //make sure we have companies.
@@ -85,15 +88,15 @@ class bannerController extends expController {
             parent::create();
         }
     }
-    
+
     public function manage() {
         expHistory::set('manageable', $this->params);
-        
+
         // build out a SQL query that gets all the data we need and is sortable.
         $sql  = 'SELECT b.*, c.title as companyname, f.expfiles_id as file_id ';
         $sql .= 'FROM '.DB_TABLE_PREFIX.'_banner b, '.DB_TABLE_PREFIX.'_companies c , '.DB_TABLE_PREFIX.'_content_expFiles f ';
         $sql .= 'WHERE b.companies_id = c.id AND (b.id = f.content_id AND f.content_type="banner")';
-		
+
 		$page = new expPaginator(array(
 			'model'=>'banner',
 			'sql'=>$sql,
@@ -114,12 +117,12 @@ class bannerController extends expController {
             'page'=>$page
         ));
     }
-    
+
     public function configure() {
         $this->config['defaultbanner'] = array();
         if (!empty($this->config['defaultbanner_id'])) {
             $this->config['defaultbanner'][] = new expFile($this->config['defaultbanner_id']);
-        }  
+        }
 	    parent::configure();
 	    $banners = $this->banner->find('all', null, 'companies_id');
 	    assign_to_template(array(
@@ -127,12 +130,12 @@ class bannerController extends expController {
             'title'=>static::displayname()
         ));
 	}
-	
+
 	public function saveconfig() {
 	    $this->params['defaultbanner_id'] = isset($this->params['expFile'][0]) ? $this->params['expFile'][0] : 0;
    	    parent::saveconfig();
 	}
-	
+
 	public function export() {
         // gather all the data
         $banners = $this->banner->find('all');
@@ -140,15 +143,15 @@ class bannerController extends expController {
         foreach ($banners as $l) {
             $out .='"'.$l->id.'","'.$l->title.'","'.$l->url.'","'.$l->company->title.'","'.$l->impression_limit.'","'.$l->click_limit.'","'.$l->impressions.'","'.$l->clicks.'"' . "\n";
         }
-        
+
         // open the file
         $dir =  BASE.'tmp';
-        $filename = 'banner_export' . date("m-d-Y") . '.csv';        
+        $filename = 'banner_export' . date("m-d-Y") . '.csv';
         $fh = fopen ($dir .'/'. $filename, 'w');
 
         // Put all values from $out to export.csv.
         fputs($fh, $out);
-        fclose($fh);        
+        fclose($fh);
 
         // push the file to the user
         $export = new expFile(array('directory'=>$dir, 'filename'=>$filename));  //FIXME we are using a full path BASE instead of relative to root
@@ -163,8 +166,8 @@ class bannerController extends expController {
         banner::resetImpressions();
 //        $db->sql ('UPDATE '.$db->prefix.'banner SET clicks=0 WHERE 1');
         banner::resetClicks();
-        
-        // let the user know we did stuff.      
+
+        // let the user know we did stuff.
         flash('message', gt("Banner statistics reset."));
         expHistory::back();
     }

programming_language: PHP
filename: blogController.php
change_type: ModificationType.MODIFY
diff: @@ -29,15 +29,13 @@ class blogController extends expController {
         'dates'=>"Show Post Dates",
         'comments'=>"Show Recent Post Comments",
     );
+    protected $manage_permissions = array(
+//        'approve'=>"Approve Comments",
+    );
     public $remove_configs = array(
 //        'categories',
 //        'ealerts'
     ); // all options: ('aggregation','categories','comments','ealerts','facebook','files','module_title','pagination','rss','tags','twitter',)
-    protected $add_permissions = array(
-        'approve'=>"Approve Comments",
-        'import'=>'Import Blog Items',
-        'export'=>'Export Blog Items'
-    );
 
     static function displayname() { return gt("Blog"); }
     static function description() { return gt("Run a blog on your site."); }
@@ -168,6 +166,7 @@ class blogController extends expController {
 	public function showall_by_author() {
 	    expHistory::set('viewable', $this->params);
 
+        $this->params['author'] = expString::escape($this->params['author']);
         $user = user::getUserByName($this->params['author']);
 		$page = new expPaginator(array(
             'model'=>$this->basemodel_name,
@@ -194,7 +193,7 @@ class blogController extends expController {
 	    $id = isset($this->params['title']) ? $this->params['title'] : $this->params['id'];
         $record = new blog($id);
         if (empty($record->id))
-            redirect_to(array('controller'=>'notfound','action'=>'page_not_found','title'=>$this->params['title']));
+            redirect_to(array('controller'=>'notfound','action'=>'page_not_found','title'=>expString::escape($this->params['title'])));
 
 	    // since we are probably getting here via a router mapped url
 	    // some of the links (tags in particular) require a source, we will
@@ -231,7 +230,7 @@ class blogController extends expController {
 
         // setup some objects
         $tagobj = new expTag();
-        $modelname = empty($this->params['model']) ? $this->basemodel_name : $this->params['model'];
+        $modelname = empty($this->params['model']) ? $this->basemodel_name : expString::escape($this->params['model']);
         $model = new $modelname();
 
         // start building the sql query

programming_language: PHP
filename: expCatController.php
change_type: ModificationType.MODIFY
diff: @@ -23,6 +23,9 @@
  */
 
 class expCatController extends expController {
+    protected $manage_permissions = array(
+        'change' => 'Change Cats'
+    );
 
 	/**
 	 * name of module

programming_language: PHP
filename: expCommentController.php
change_type: ModificationType.MODIFY
diff: @@ -24,29 +24,30 @@
 
 class expCommentController extends expController {
     public $base_class = 'expComment';
-    protected $add_permissions = array(
-        'approve'=>"Approve Comments"
-    );
-   	protected $remove_permissions = array(
+    protected $remove_permissions = array(
         'create'
     );
+    protected $add_permissions = array(
+        'approve'=>"Approve Comments",
+        'bulk'=>"Bulk Actions"
+    );
 
     static function displayname() { return gt("Comments"); }
     static function description() { return gt("Use this module to add comments to a page."); }
-    
+
 	function edit() {
 	    if (empty($this->params['content_id'])) {
 	        flash('message',gt('An error occurred: No content id set.'));
-            expHistory::back();  
-	    } 
+            expHistory::back();
+	    }
         /* The global constants can be overridden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
 //        $require_login = empty($this->params['require_login']) ? COMMENTS_REQUIRE_LOGIN : $this->params['require_login'];
 //        $require_approval = empty($this->params['require_approval']) ? COMMENTS_REQUIRE_APPROVAL : $this->params['require_approval'];
 //        $require_notification = empty($this->params['require_notification']) ? COMMENTS_REQUIRE_NOTIFICATION : $this->params['require_notification'];
 //        $notification_email = empty($this->params['notification_email']) ? COMMENTS_NOTIFICATION_EMAIL : $this->params['notification_email'];
-        
-        
+
+
 	    $id = empty($this->params['id']) ? null : $this->params['id'];
 	    $comment = new expComment($id);
         //FIXME here is where we might sanitize the comment before displaying/editing it
@@ -55,8 +56,8 @@ class expCommentController extends expController {
             'content_type'=>$this->params['content_type'],
 		    'comment'=>$comment
 		));
-	}	
-	
+	}
+
 	function manage() {
 	    expHistory::set('manageable', $this->params);
 
@@ -68,7 +69,7 @@ class expCommentController extends expController {
 //        $require_approval = empty($this->params['require_approval']) ? COMMENTS_REQUIRE_APPROVAL : $this->params['require_approval'];
 //        $require_notification = empty($this->params['require_notification']) ? COMMENTS_REQUIRE_NOTIFICATION : $this->params['require_notification'];
 //        $notification_email = empty($this->params['notification_email']) ? COMMENTS_NOTIFICATION_EMAIL : $this->params['notification_email'];
-	    
+
 	    $sql  = 'SELECT c.*, cnt.* FROM '.DB_TABLE_PREFIX.'_expComments c ';
         $sql .= 'JOIN '.DB_TABLE_PREFIX.'_content_expComments cnt ON c.id=cnt.expcomments_id ';
         if (!empty($this->params['content_id']) && !empty($this->params['content_type'])) {
@@ -80,7 +81,7 @@ class expCommentController extends expController {
 
         $page = new expPaginator(array(
 //            'model'=>'expComment',
-            'sql'=>$sql, 
+            'sql'=>$sql,
             'limit'=>10,
             'order'=>$order,
             'dir'=>$dir,
@@ -115,10 +116,10 @@ class expCommentController extends expController {
 
         /* The global constants can be overridden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
-        $require_login = empty($this->params['require_login']) ? COMMENTS_REQUIRE_LOGIN : $this->params['require_login'];
-        $require_approval = empty($this->params['require_approval']) ? COMMENTS_REQUIRE_APPROVAL : $this->params['require_approval'];
-        $require_notification = empty($this->params['require_notification']) ? COMMENTS_REQUIRE_NOTIFICATION : $this->params['require_notification'];
-        $notification_email = empty($this->params['notification_email']) ? COMMENTS_NOTIFICATION_EMAIL : $this->params['notification_email'];
+        $require_login = empty($this->params['require_login']) ? COMMENTS_REQUIRE_LOGIN : intval($this->params['require_login']);
+        $require_approval = empty($this->params['require_approval']) ? COMMENTS_REQUIRE_APPROVAL : intval($this->params['require_approval']);
+        $require_notification = empty($this->params['require_notification']) ? COMMENTS_REQUIRE_NOTIFICATION : intval($this->params['require_notification']);
+        $notification_email = empty($this->params['notification_email']) ? COMMENTS_NOTIFICATION_EMAIL : expString::escape($this->params['notification_email']);
 
 //        $sql  = 'SELECT c.*, ua.image, u.username FROM '.$db->prefix.'expComments c ';
 //        $sql .= 'JOIN '.$db->prefix.'content_expComments cnt ON c.id=cnt.expcomments_id ';
@@ -128,14 +129,14 @@ class expCommentController extends expController {
 
         $sql  = 'SELECT c.* FROM '.$db->prefix.'expComments c ';
         $sql .= 'JOIN '.$db->prefix.'content_expComments cnt ON c.id=cnt.expcomments_id ';
-        $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".$this->params['content_type']."' ";
+        $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".expString::escape($this->params['content_type'])."' ";
         if (!$user->isAdmin()) {
             $sql .= 'AND c.approved=1';
         }
 
         $comments = new expPaginator(array(
             //'model'=>'expComment',
-            'sql'=>$sql, 
+            'sql'=>$sql,
 //            'limit'=>999,
             'order'=>'created_at',
             'page'=>(isset($this->params['page']) ? $this->params['page'] : 1),
@@ -157,18 +158,18 @@ class expCommentController extends expController {
 
         if (empty($this->params['config']['disable_nested_comments'])) $comments->records = self::arrangecomments($comments->records);
         // eDebug($sql, true);
-        
+
         // count the unapproved comments
         if ($require_approval == 1 && $user->isAdmin()) {
             $sql  = 'SELECT count(com.id) as c FROM '.$db->prefix.'expComments com ';
             $sql .= 'JOIN '.$db->prefix.'content_expComments cnt ON com.id=cnt.expcomments_id ';
-            $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".$this->params['content_type']."' ";
+            $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".expString::escape($this->params['content_type'])."' ";
             $sql .= 'AND com.approved=0';
             $unapproved = $db->countObjectsBySql($sql);
         } else {
             $unapproved = 0;
-        }        
-        
+        }
+
         $this->config = $this->params['config'];
         $type = !empty($this->params['type']) ? $this->params['type'] : gt('Comment');
         $ratings = !empty($this->params['ratings']) ? true : false;
@@ -177,7 +178,7 @@ class expCommentController extends expController {
             'comments'=>$comments,
             'config'=>$this->params['config'],
             'unapproved'=>$unapproved,
-			'content_id'=>$this->params['content_id'], 
+			'content_id'=>$this->params['content_id'],
 			'content_type'=>$this->params['content_type'],
 			'user'=>$user,
 			'hideform'=>$this->params['hideform'],
@@ -324,7 +325,7 @@ class expCommentController extends expController {
 
     function update() {
         global $user;
-        
+
         /* The global constants can be overridden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
 //        $require_login = empty($this->params['require_login']) ? COMMENTS_REQUIRE_LOGIN : $this->params['require_login'];
@@ -339,19 +340,19 @@ class expCommentController extends expController {
         if (!(ANTI_SPAM_USERS_SKIP && $user->isLoggedIn())) {
             expValidator::check_antispam($this->params, gt('Your comment was not posted.') . ' ' . gt("Anti-spam verification failed.  Please try again. Please try again."));
         }
-        
+
         // figure out the name and email address
         if (!empty($user->id) && empty($this->params['id'])) {
             $this->params['name'] = $user->firstname." ".$user->lastname;
             $this->params['email'] = $user->email;
         }
-                        
+
         // save the comment
         if (empty($require_approval)) {
             $this->expComment->approved=1;
         }
         $this->expComment->update($this->params);
-        
+
         // attach the comment to the datatype it belongs to (blog, news, etc..);
 //        $obj = new stdClass();
 //		$obj->content_type = $this->params['content_type'];
@@ -366,7 +367,7 @@ class expCommentController extends expController {
 		    $msg .= ' '.gt('Your comment is now pending approval. You will receive an email to').' ';
 		    $msg .= $this->expComment->email.' '.gt('letting you know when it has been approved.');
 		}
-		
+
 		if ($require_notification && !$user->isAdmin()) {
 		    $this->sendNotification($this->expComment,$this->params);
 		}
@@ -375,55 +376,55 @@ class expCommentController extends expController {
         }
 
 		flash('message', $msg);
-		
+
 		expHistory::back();
 	}
-	
+
 	public function approve() {
 	    expHistory::set('editable', $this->params);
-        
-        /* The global constants can be overriden by passing appropriate params */ 
+
+        /* The global constants can be overriden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
 //        $require_login = empty($this->params['require_login']) ? COMMENTS_REQUIRE_LOGIN : $this->params['require_login'];
 //        $require_approval = empty($this->params['require_approval']) ? COMMENTS_REQUIRE_APPROVAL : $this->params['require_approval'];
 //        $require_notification = empty($this->params['require_notification']) ? COMMENTS_REQUIRE_NOTIFICATION : $this->params['require_notification'];
 //        $notification_email = empty($this->params['notification_email']) ? COMMENTS_NOTIFICATION_EMAIL : $this->params['notification_email'];
-	    
+
 	    if (empty($this->params['id'])) {
 	        flash('error', gt('No ID supplied for comment to approve'));
 	        expHistory::back();
 	    }
-	    
+
 	    $comment = new expComment($this->params['id']);
 	    assign_to_template(array(
             'comment'=>$comment
         ));
 	}
-	
+
 	public function approve_submit() {
 	    if (empty($this->params['id'])) {
 	        flash('error', gt('No ID supplied for comment to approve'));
 	        expHistory::back();
 	    }
-        
-        /* The global constants can be overriden by passing appropriate params */ 
+
+        /* The global constants can be overriden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
 //        $require_login = empty($this->params['require_login']) ? COMMENTS_REQUIRE_LOGIN : $this->params['require_login'];
 //        $require_approval = empty($this->params['require_approval']) ? COMMENTS_REQUIRE_APPROVAL : $this->params['require_approval'];
 //        $require_notification = empty($this->params['require_notification']) ? COMMENTS_REQUIRE_NOTIFICATION : $this->params['require_notification'];
 //        $notification_email = empty($this->params['notification_email']) ? COMMENTS_NOTIFICATION_EMAIL : $this->params['notification_email'];
-	    
+
 	    $comment = new expComment($this->params['id']);
 	    $comment->body = $this->params['body'];
 	    $comment->approved = $this->params['approved'];
 	    $comment->save();
 	    expHistory::back();
 	}
-	
+
 	public function approve_toggle() {
 	    if (empty($this->params['id'])) return;
-        
-        /* The global constants can be overriden by passing appropriate params */ 
+
+        /* The global constants can be overriden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
 //        $require_login = empty($this->params['require_login']) ? COMMENTS_REQUIRE_LOGIN : $this->params['require_login'];
 //        $require_approval = empty($this->params['require_approval']) ? COMMENTS_REQUIRE_APPROVAL : $this->params['require_approval'];
@@ -479,42 +480,42 @@ class expCommentController extends expController {
 
 	public function delete() {
 	    global $db;
-        
-        /* The global constants can be overriden by passing appropriate params */ 
+
+        /* The global constants can be overriden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
 //        $require_login = empty($this->params['require_login']) ? COMMENTS_REQUIRE_LOGIN : $this->params['require_login'];
 //        $require_approval = empty($this->params['require_approval']) ? COMMENTS_REQUIRE_APPROVAL : $this->params['require_approval'];
 //        $require_notification = empty($this->params['require_notification']) ? COMMENTS_REQUIRE_NOTIFICATION : $this->params['require_notification'];
 //        $notification_email = empty($this->params['notification_email']) ? COMMENTS_NOTIFICATION_EMAIL : $this->params['notification_email'];
-	    
+
 	    if (empty($this->params['id'])) {
 	        flash('error', gt('Missing id for the comment you would like to delete'));
 	        expHistory::back();
 	    }
-	    
+
 	    // delete the comment
         $comment = new expComment($this->params['id']);
         $comment->delete();
-        
+
         // delete the association too
-        $db->delete($comment->attachable_table, 'expcomments_id='.$this->params['id']);        
-        
+        $db->delete($comment->attachable_table, 'expcomments_id='.$this->params['id']);
+
         // send the user back where they came from.
         expHistory::back();
 	}
-	
+
 	private function sendNotification($comment,$params) {
 //	    global $db;
 	    if (empty($comment)) return false;
-        
+
         //eDebug($comment,1);
-        /* The global constants can be overriden by passing appropriate params */ 
+        /* The global constants can be overriden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
 //        $require_login = empty($this->params['require_login']) ? COMMENTS_REQUIRE_LOGIN : $this->params['require_login'];
 //        $require_approval = empty($this->params['require_approval']) ? COMMENTS_REQUIRE_APPROVAL : $this->params['require_approval'];
 //        $require_notification = empty($this->params['require_notification']) ? COMMENTS_REQUIRE_NOTIFICATION : $this->params['require_notification'];
         $notification_email = empty($this->params['notification_email']) ? COMMENTS_NOTIFICATION_EMAIL : $this->params['notification_email'];
-	    
+
 	    // setup some email variables.
 	    $subject = gt('Notification of a New Comment Posted to').' '.URL_BASE;
         $tos = explode(',', str_replace(' ', '', $notification_email));
@@ -526,7 +527,7 @@ class expCommentController extends expController {
 
         $posting = makelink(array('controller'=>$params['content_type'], 'action'=>'show', 'title'=>$model->sef_url));
         $editlink = makelink(array('controller'=>'expComment', 'action'=>'edit', 'content_id'=>$params['content_id'], 'content_type'=>$params['content_type'], 'id'=>$comment->id));
-        
+
         // make the email body
         $body = '<h1>'.gt('New Comment Posted').'</h1>';
         $body .= '<h2>'.gt('Posted By').'</h2>';
@@ -540,29 +541,29 @@ class expCommentController extends expController {
         //1$body .= "<br><br>";
         $body .= '<h3>'.gt('Edit / Approve comment').'</h3>';
         $body .= '<a href="'.$editlink.'">'.$editlink.'</a>';
-        
+
         // create the mail message
-        $mail = new expMail();        
+        $mail = new expMail();
         $mail->quickSend(array(
                 'html_message'=>$body,
 			    'to'=>$tos,
 				'from'=>array(trim(SMTP_FROMADDRESS) => trim(ORGANIZATION_NAME)),
 			    'subject'=>$subject,
         ));
-        
+
         return true;
 	}
 
 	private function sendApprovalNotification($comment,$params) {
 	    if (empty($comment)) return false;
-        
-        /* The global constants can be overriden by passing appropriate params */ 
+
+        /* The global constants can be overriden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
 //        $require_login = empty($this->params['require_login']) ? COMMENTS_REQUIRE_LOGIN : $this->params['require_login'];
 //        $require_approval = empty($this->params['require_approval']) ? COMMENTS_REQUIRE_APPROVAL : $this->params['require_approval'];
 //        $require_notification = empty($this->params['require_notification']) ? COMMENTS_REQUIRE_NOTIFICATION : $this->params['require_notification'];
         $notification_email = empty($this->params['notification_email']) ? COMMENTS_NOTIFICATION_EMAIL : $this->params['notification_email'];
-	    
+
 	    // setup some email variables.
 	    $subject = gt('Notification of Comment Approval on').' '.URL_BASE;
         $tos = explode(',', str_replace(' ', '', $notification_email));
@@ -587,14 +588,14 @@ class expCommentController extends expController {
         $body .= '<a href="'.$posting.'">'.$posting.'</a>';
 
         // create the mail message
-        $mail = new expMail();        
+        $mail = new expMail();
         $mail->quickSend(array(
                 'html_message'=>$body,
 			    'to'=>$tos,
 			    'from'=>array(trim(SMTP_FROMADDRESS) => trim(ORGANIZATION_NAME)),
 			    'subject'=>$subject,
         ));
-        
+
         return true;
 	}
 

programming_language: PHP
filename: expDefinableFieldController.php
change_type: ModificationType.MODIFY
diff: @@ -47,7 +47,7 @@ class expDefinableFieldController extends expController {
    	 * default view for individual field
    	 */
    	function show() {
-        assign_to_template(array('record'=>$record,'tag'=>$tag));  //FIXME $record & $tag are undefined
+//        assign_to_template(array('record'=>$record,'tag'=>$tag));  //FIXME $record & $tag are undefined
     }
 
 	/**
@@ -55,7 +55,7 @@ class expDefinableFieldController extends expController {
 	 */
 	function manage() {
         global $db;
-		
+
         expHistory::set('manageable', $this->params);
 		$fields = $db->selectObjects("expDefinableFields",'1','rank');
 		$types = expTemplate::listControlTypes();
@@ -63,10 +63,10 @@ class expDefinableFieldController extends expController {
 		array_unshift($types,'['.gt('Please Select'.']'));
         assign_to_template(array('fields'=>$fields, 'types'=>$types));
     }
-	
+
 	function edit() {
 		global $db;
-		 
+
 		$control_type = "";
 		$ctl = null;
 		if (isset($this->params['id'])) {
@@ -80,7 +80,7 @@ class expDefinableFieldController extends expController {
 		}
 		if ($control_type == "") $control_type = $this->params['control_type'];
 		$form = call_user_func(array($control_type,"form"),$ctl);
-		if ($ctl) { 
+		if ($ctl) {
 			$form->controls['identifier']->disabled = true;
 			$form->meta("id",$ctl->id);
 			$form->meta("identifier",$ctl->identifier);
@@ -91,10 +91,10 @@ class expDefinableFieldController extends expController {
 		$form->meta("type", $control_type);
 		$types = expTemplate::listControlTypes();
 
-		assign_to_template(array('form_html'=>$form->toHTML(), 'types'=>$types[$control_type]));			
+		assign_to_template(array('form_html'=>$form->toHTML(), 'types'=>$types[$control_type]));
 	}
-	
-	function save() {	
+
+	function save() {
 		global $db;
 		$ctl = null;
 		$control = null;
@@ -106,30 +106,30 @@ class expDefinableFieldController extends expController {
 			}
 		}
 
-		if (call_user_func(array($_POST['control_type'],'useGeneric')) == true) { 	
+		if (call_user_func(array($_POST['control_type'],'useGeneric')) == true) {
 			$ctl = call_user_func(array('genericcontrol','update'),expString::sanitize($_POST),$ctl);
 		} else {
 			$ctl = call_user_func(array($_POST['control_type'],'update'),expString::sanitize($_POST),$ctl);
 		}
-		
+
 		if ($ctl != null) {
 			$name = substr(preg_replace('/[^A-Za-z0-9]/','_',$ctl->identifier),0,20);
-	
+
 			if (!isset($this->params['id'])) {
 				$control->name =  $name;
 			}
-	
+
             if (!empty($ctl->pattern)) $ctl->pattern = addslashes($ctl->pattern);
 			$control->data = serialize($ctl);
 			$control->type = $this->params['type'];
-			
+
 			if (isset($control->id)) {
 				$db->updateObject($control,'expDefinableFields');
 			} else {
 				$db->insertObject($control,'expDefinableFields');
 			}
 		}
-		
+
 		redirect_to(array('controller'=>'expDefinableField','action'=>'manage'));
 	}
 

programming_language: PHP
filename: expHTMLEditorController.php
change_type: ModificationType.MODIFY
diff: @@ -24,6 +24,14 @@
 
 class expHTMLEditorController extends expController
 {
+    protected $manage_permissions = array(
+        'activate' => "Activate",
+        'preview'  => "Preview Editor Toolbars"
+    );
+    public $requires_login = array(
+        'preview'=>'Preview Editor',
+    );
+
     static function displayname()
     {
         return gt("Editors");
@@ -49,11 +57,6 @@ class expHTMLEditorController extends expController
         return false;
     }
 
-    protected $add_permissions = array(
-        'activate' => "Activate",
-        'preview'  => "Preview Editor Toolbars"
-    );
-
     function __construct($src = null, $params = array())
     {
         parent:: __construct($src, $params);

programming_language: PHP
filename: expSimpleNoteController.php
change_type: ModificationType.MODIFY
diff: @@ -24,8 +24,8 @@
 
 class expSimpleNoteController extends expController {
     public $base_class = 'expSimpleNote';
-    protected $add_permissions = array(
-        'approve'=>"Approve Comments"
+    protected $manage_permissions = array(
+        'approve'=>"Approve Notes"
     );
 //    protected $remove_permissions = array(
 //        'edit',
@@ -35,18 +35,18 @@ class expSimpleNoteController extends expController {
     static function displayname() { return gt("Simple Notes"); }
     static function description() { return gt("Use this module to add Simple Notes attached to something (product, order, etc)"); }
     static function author() { return "Jonathan Worent @ OIC Group, Inc"; }
-    
+
     function edit() {
         global $user;
-        
-        /* The global constants can be overriden by passing appropriate params */ 
+
+        /* The global constants can be overriden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
         $require_login = empty($this->params['require_login']) ? SIMPLENOTE_REQUIRE_LOGIN : $this->params['require_login'];
         $require_approval = empty($this->params['require_approval']) ? SIMPLENOTE_REQUIRE_APPROVAL : $this->params['require_approval'];
         $require_notification = empty($this->params['require_notification']) ? SIMPLENOTE_REQUIRE_NOTIFICATION : $this->params['require_notification'];
         $notification_email = empty($this->params['notification_email']) ? SIMPLENOTE_NOTIFICATION_EMAIL : $this->params['notification_email'];
-        
-        if (empty($this->params['formtitle'])) 
+
+        if (empty($this->params['formtitle']))
         {
             if (empty($this->params['id']))
             {
@@ -61,7 +61,7 @@ class expSimpleNoteController extends expController {
         {
             $formtitle = $this->params['formtitle'];
         }
-        
+
         $id = empty($this->params['id']) ? null : $this->params['id'];
         $simpleNote = new expSimpleNote($id);
         //FIXME here is where we might sanitize the note before displaying/editing it
@@ -78,26 +78,26 @@ class expSimpleNoteController extends expController {
             'content_id'=>$this->params['content_id'],
             'tab'=>empty($this->params['tab'])?0:$this->params['tab']
         ));
-    }    
-    
+    }
+
     function manage() {
         expHistory::set('manageable', $this->params);
-        
-        /* The global constants can be overriden by passing appropriate params */ 
+
+        /* The global constants can be overriden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
         $require_login = empty($this->params['require_login']) ? SIMPLENOTE_REQUIRE_LOGIN : $this->params['require_login'];
         $require_approval = empty($this->params['require_approval']) ? SIMPLENOTE_REQUIRE_APPROVAL : $this->params['require_approval'];
         $require_notification = empty($this->params['require_notification']) ? SIMPLENOTE_REQUIRE_NOTIFICATION : $this->params['require_notification'];
         $notification_email = empty($this->params['notification_email']) ? SIMPLENOTE_NOTIFICATION_EMAIL : $this->params['notification_email'];
-        
+
         $sql  = 'SELECT n.* FROM '.DB_TABLE_PREFIX.'_expSimpleNote n ';
         $sql .= 'JOIN '.DB_TABLE_PREFIX.'_content_expSimpleNote cnt ON n.id=cnt.expsimplenote_id ';
         $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".$this->params['content_type']."' ";
         $sql .= 'AND n.approved=0';
-        
+
         $page = new expPaginator(array(
 //            'model'=>'expSimpleNote',  // brings in all of model
-            'sql'=>$sql, 
+            'sql'=>$sql,
             'limit'=>10,
             'order'=>'created_at',
             'dir'=>'DESC',
@@ -110,7 +110,7 @@ class expSimpleNoteController extends expController {
                 gt('Comment')=>'body'
             ),
         ));
-        
+
         //FIXME here is where we might sanitize the notes before displaying them
 
         assign_to_template(array(
@@ -122,26 +122,26 @@ class expSimpleNoteController extends expController {
             'tab'=>$this->params['tab']
         ));
     }
-    
+
     function getNotes() {
         global $user, $db;
-        
-        /* The global constants can be overriden by passing appropriate params */ 
+
+        /* The global constants can be overriden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
-        $require_login = empty($this->params['require_login']) ? SIMPLENOTE_REQUIRE_LOGIN : $this->params['require_login'];
-        $require_approval = empty($this->params['require_approval']) ? SIMPLENOTE_REQUIRE_APPROVAL : $this->params['require_approval'];
-        $require_notification = empty($this->params['require_notification']) ? SIMPLENOTE_REQUIRE_NOTIFICATION : $this->params['require_notification'];
-        $notification_email = empty($this->params['notification_email']) ? SIMPLENOTE_NOTIFICATION_EMAIL : $this->params['notification_email'];
-        
-        
+        $require_login = empty($this->params['require_login']) ? SIMPLENOTE_REQUIRE_LOGIN : intval($this->params['require_login']);
+        $require_approval = empty($this->params['require_approval']) ? SIMPLENOTE_REQUIRE_APPROVAL : intval($this->params['require_approval']);
+        $require_notification = empty($this->params['require_notification']) ? SIMPLENOTE_REQUIRE_NOTIFICATION : intval($this->params['require_notification']);
+        $notification_email = empty($this->params['notification_email']) ? SIMPLENOTE_NOTIFICATION_EMAIL : expString::escape($this->params['notification_email']);
+
+
         $sql  = 'SELECT n.* FROM '.$db->prefix.'expSimpleNote n ';
         $sql .= 'JOIN '.$db->prefix.'content_expSimpleNote cnt ON n.id=cnt.expsimplenote_id ';
-        $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".$this->params['content_type']."' ";
+        $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".expString::escape($this->params['content_type'])."' ";
         $sql .= 'AND n.approved=1';
-        
+
         $simplenotes = new expPaginator(array(
             //'model'=>'expSimpleNote',
-            'sql'=>$sql, 
+            'sql'=>$sql,
             'limit'=>10,
             'order'=>'created_at',
             'dir'=>'DESC',
@@ -152,24 +152,24 @@ class expSimpleNoteController extends expController {
                 gt('Readable Column Name')=>'Column Name'
             ),
         ));
-        
-        // count the unapproved comments
+
+        // count the unapproved notes
         if ($require_approval == 1 && $user->isAdmin()) {
             $sql  = 'SELECT count(com.id) as c FROM '.$db->prefix.'expSimpleNote com ';
             $sql .= 'JOIN '.$db->prefix.'content_expSimpleNote cnt ON com.id=cnt.expsimplenote_id ';
-            $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".$this->params['content_type']."' ";
+            $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".expString::escape($this->params['content_type'])."' ";
             $sql .= 'AND com.approved=0';
             $unapproved = $db->countObjectsBySql($sql);
         } else {
             $unapproved = 0;
-        }        
- 
+        }
+
         //FIXME here is where we might sanitize the notes before displaying them
 
         assign_to_template(array(
             'simplenotes'=>$simplenotes,
-            'unapproved'=>$unapproved, 
-            'content_id'=>$this->params['content_id'], 
+            'unapproved'=>$unapproved,
+            'content_id'=>$this->params['content_id'],
             'content_type'=>$this->params['content_type'],
             'user'=>$user,
             'hideform'=>$this->params['hideform'],
@@ -186,28 +186,28 @@ class expSimpleNoteController extends expController {
 
     function update() {
         global $db, $user, $history;
-        
-        /* The global constants can be overriden by passing appropriate params */ 
+
+        /* The global constants can be overriden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
         $require_login = empty($this->params['require_login']) ? SIMPLENOTE_REQUIRE_LOGIN : $this->params['require_login'];
         $require_approval = empty($this->params['require_approval']) ? SIMPLENOTE_REQUIRE_APPROVAL : $this->params['require_approval'];
         $require_notification = empty($this->params['require_notification']) ? SIMPLENOTE_REQUIRE_NOTIFICATION : $this->params['require_notification'];
         $notification_email = empty($this->params['notification_email']) ? SIMPLENOTE_NOTIFICATION_EMAIL : $this->params['notification_email'];
-        
+
         // figure out the name and email address
         if (!empty($user->id)) {
             $this->params['name'] = $user->firstname." ".$user->lastname;
             $this->params['email'] = $user->email;
         }
-        
-        // if simplenotes are configed to require approvals set this to 0 otherwise we 
+
+        // if simplenotes are configed to require approvals set this to 0 otherwise we
         // will just go ahead and turn the approval on for this comment.
         $this->expSimpleNote->approved = ($require_approval == 1 && !$user->isAdmin()) ? 0 : 1;
-        
+
         // save the note
         //FIXME here is where we might sanitize the note before saving it
         $this->expSimpleNote->update($this->params);
-        
+
         // attach the note to the datatype it belongs to (product, order, etc..);
 //        $obj = new stdClass();
 //        $obj->content_type = $this->params['content_type'];
@@ -222,14 +222,14 @@ class expSimpleNoteController extends expController {
             $msg .= ' '.gt('Your note is now pending approval. You will receive an email to').' ';
             $msg .= $this->expSimpleNote->email.' '.gt('letting you know when it has been approved.');
         }
-        
+
         if ($require_notification && !$user->isAdmin()) {
             $this->sendNotification($this->expComment);
         }
-        
+
         flash('message', $msg);
-        
-        
+
+
         $lastUrl = makelink($history->history[$history->history['lasts']['type']][count($history->history[$history->history['lasts']['type']])-1]['params']);
         if (!empty($this->params['tab']))
         {
@@ -237,22 +237,22 @@ class expSimpleNoteController extends expController {
         }
         redirect_to($lastUrl);
     }
-    
+
     public function approve() {
         expHistory::set('editable', $this->params);
-        
-        /* The global constants can be overriden by passing appropriate params */ 
+
+        /* The global constants can be overriden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
         $require_login = empty($this->params['require_login']) ? SIMPLENOTE_REQUIRE_LOGIN : $this->params['require_login'];
         $require_approval = empty($this->params['require_approval']) ? SIMPLENOTE_REQUIRE_APPROVAL : $this->params['require_approval'];
         $require_notification = empty($this->params['require_notification']) ? SIMPLENOTE_REQUIRE_NOTIFICATION : $this->params['require_notification'];
         $notification_email = empty($this->params['notification_email']) ? SIMPLENOTE_NOTIFICATION_EMAIL : $this->params['notification_email'];
-        
+
         if (empty($this->params['id'])) {
             flash('error', gt('No ID supplied for note to approve'));
             $lastUrl = expHistory::getLast('editable');
         }
-        
+
         $simplenote = new expSimpleNote($this->params['id']);
         assign_to_template(array(
             'simplenote'=>$simplenote,
@@ -263,28 +263,28 @@ class expSimpleNoteController extends expController {
             'tab'=>$this->params['tab']
         ));
     }
-    
+
     public function approve_submit() {
         global $history;
-        
+
         if (empty($this->params['id'])) {
             flash('error', gt('No ID supplied for comment to approve'));
             $lastUrl = expHistory::getLast('editable');
         }
-        
-        /* The global constants can be overriden by passing appropriate params */ 
+
+        /* The global constants can be overriden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
         $require_login = empty($this->params['require_login']) ? SIMPLENOTE_REQUIRE_LOGIN : $this->params['require_login'];
         $require_approval = empty($this->params['require_approval']) ? SIMPLENOTE_REQUIRE_APPROVAL : $this->params['require_approval'];
         $require_notification = empty($this->params['require_notification']) ? SIMPLENOTE_REQUIRE_NOTIFICATION : $this->params['require_notification'];
         $notification_email = empty($this->params['notification_email']) ? SIMPLENOTE_NOTIFICATION_EMAIL : $this->params['notification_email'];
-        
+
         $simplenote = new expSimpleNote($this->params['id']);
         //FIXME here is where we might sanitize the note before approving it
         $simplenote->body = $this->params['body'];
         $simplenote->approved = $this->params['approved'];
         $simplenote->save();
-        
+
         $lastUrl = makelink($history->history[$history->history['lasts']['type']][count($history->history[$history->history['lasts']['type']])-1]['params']);
         if (!empty($this->params['tab']))
         {
@@ -292,24 +292,24 @@ class expSimpleNoteController extends expController {
         }
         redirect_to($lastUrl);
     }
-    
+
     public function approve_toggle() {
         global $history;
-        
+
         if (empty($this->params['id'])) return;
-        
-        /* The global constants can be overriden by passing appropriate params */ 
+
+        /* The global constants can be overriden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
         $require_login = empty($this->params['require_login']) ? SIMPLENOTE_REQUIRE_LOGIN : $this->params['require_login'];
         $require_approval = empty($this->params['require_approval']) ? SIMPLENOTE_REQUIRE_APPROVAL : $this->params['require_approval'];
         $require_notification = empty($this->params['require_notification']) ? SIMPLENOTE_REQUIRE_NOTIFICATION : $this->params['require_notification'];
         $notification_email = empty($this->params['notification_email']) ? SIMPLENOTE_NOTIFICATION_EMAIL : $this->params['notification_email'];
-        
-        
+
+
         $simplenote = new expSimpleNote($this->params['id']);
         $simplenote->approved = $simplenote->approved == 1 ? 0 : 1;
         $simplenote->save();
-        
+
         $lastUrl = makelink($history->history[$history->history['lasts']['type']][count($history->history[$history->history['lasts']['type']])-1]['params']);
         if (!empty($this->params['tab']))
         {
@@ -317,29 +317,29 @@ class expSimpleNoteController extends expController {
         }
         redirect_to($lastUrl);
     }
-    
+
     public function delete() {
         global $db, $history;
-        
-        /* The global constants can be overriden by passing appropriate params */ 
+
+        /* The global constants can be overriden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
         $require_login = empty($this->params['require_login']) ? SIMPLENOTE_REQUIRE_LOGIN : $this->params['require_login'];
         $require_approval = empty($this->params['require_approval']) ? SIMPLENOTE_REQUIRE_APPROVAL : $this->params['require_approval'];
         $require_notification = empty($this->params['require_notification']) ? SIMPLENOTE_REQUIRE_NOTIFICATION : $this->params['require_notification'];
         $notification_email = empty($this->params['notification_email']) ? SIMPLENOTE_NOTIFICATION_EMAIL : $this->params['notification_email'];
-        
+
         if (empty($this->params['id'])) {
             flash('error', gt('Missing id for the comment you would like to delete'));
             $lastUrl = expHistory::getLast('editable');
         }
-        
+
         // delete the note
         $simplenote = new expSimpleNote($this->params['id']);
         $rows = $simplenote->delete();
-        
+
         // delete the assocication too
-        $db->delete($simplenote->attachable_table, 'expsimplenote_id='.$this->params['id']);        
-        
+        $db->delete($simplenote->attachable_table, 'expsimplenote_id='.$this->params['id']);
+
         // send the user back where they came from.
         $lastUrl = expHistory::getLast('editable');
         if (!empty($this->params['tab']))
@@ -348,38 +348,38 @@ class expSimpleNoteController extends expController {
         }
         redirect_to($lastUrl);
     }
-    
+
     private function sendNotification($simplenote) {
         if (empty($simplenote)) return false;
-        
-        /* The global constants can be overriden by passing appropriate params */ 
+
+        /* The global constants can be overriden by passing appropriate params */
         //sure wish I could do this once in the constructor. sadly $this->params[] isn't set yet
-        $require_login = empty($this->params['require_login']) ? SIMPLENOTE_REQUIRE_LOGIN : $this->params['require_login'];
-        $require_approval = empty($this->params['require_approval']) ? SIMPLENOTE_REQUIRE_APPROVAL : $this->params['require_approval'];
-        $require_notification = empty($this->params['require_notification']) ? SIMPLENOTE_REQUIRE_NOTIFICATION : $this->params['require_notification'];
-        $notification_email = empty($this->params['notification_email']) ? SIMPLENOTE_NOTIFICATION_EMAIL : $this->params['notification_email'];
-        
+        $require_login = empty($this->params['require_login']) ? SIMPLENOTE_REQUIRE_LOGIN : intval($this->params['require_login']);
+        $require_approval = empty($this->params['require_approval']) ? SIMPLENOTE_REQUIRE_APPROVAL : intval($this->params['require_approval']);
+        $require_notification = empty($this->params['require_notification']) ? SIMPLENOTE_REQUIRE_NOTIFICATION : intval($this->params['require_notification']);
+        $notification_email = empty($this->params['notification_email']) ? SIMPLENOTE_NOTIFICATION_EMAIL : expString::escape($this->params['notification_email']);
+
         // setup some email variables.
         $subject = 'Notification of a New Note Posted to '.URL_BASE;
         $tos = explode(',', str_replace(' ', '', $notification_email));
         $editlink = makelink(array('controller'=>'expSimpleNote', 'action'=>'edit', 'id'=>$simplenote->id));
-        
+
         // make the email body
         $body  = gt('Posted By').':&#160;'.$simplenote->name."<br>";
         $body .= gt('Posters Email').':&#160;'.$simplenote->email."<br><br>";
         $body .= $simplenote->body."<br><br>";
         $body .= gt('You can view, edit and optionally approved this comment by going to').' ';
         $body .= '<a href="'.$editlink.'">'.$editlink.'</a>';
-        
+
         // create the mail message
-        $mail = new expMail();        
+        $mail = new expMail();
         $mail->quickSend(array(
                 'html_message'=>$body,
                 'to'=>$tos,
                 'from'=>array(trim(SMTP_FROMADDRESS) => trim(ORGANIZATION_NAME)),
                 'subject'=>$subject,
         ));
-        
+
         return true;
     }
 

programming_language: PHP
filename: expTagController.php
change_type: ModificationType.MODIFY
diff: @@ -23,6 +23,12 @@
  */
 
 class expTagController extends expController {
+    protected $manage_permissions = array(
+//        'import' => 'Import Tags',
+//        'importTags' => 'Import Tags',
+//        'export' => 'Export Tags',
+        'change' => 'Change Tags',
+    );
 	/**
 	 * name of module
 	 * @return string
@@ -59,7 +65,7 @@ class expTagController extends expController {
         if (isset($this->params['id'])) {
             $id = $this->params['id'];
         } elseif (isset($this->params['title'])) {
-            $id = $this->params['title'];
+            $id = expString::escape($this->params['title']);
             $tag = $id;
         }
 

programming_language: PHP
filename: eaasController.php
change_type: ModificationType.MODIFY
diff: @@ -41,10 +41,6 @@ class eaasController extends expController {
         'tags',
         'twitter',
     ); // all options: ('aggregation','categories','comments','ealerts','facebook','files','pagination','rss','tags','twitter',)
-    protected $add_permissions = array(
-        // 'approve'=>"Approve Comments"
-    );
-
     public $tabs = array(
         'aboutus'=>'About Us', 
         'blog'=>'Blog', 
@@ -54,7 +50,6 @@ class eaasController extends expController {
         'filedownload'=>'File Downloads', 
         'news'=>'News'
     );
-
     protected $data = array();
     
     static function displayname() { return gt("Exponent as a Service"); }

programming_language: PHP
filename: ealertController.php
change_type: ModificationType.MODIFY
diff: @@ -23,7 +23,9 @@
 
 class ealertController extends expController {
     public $basemodel_name = 'expeAlerts';
-
+    protected $manage_permissions = array(
+        'send'=>'Send E-Alert',
+    );
 	public $remove_configs = array(
         'aggregation',
         'categories',
@@ -36,10 +38,10 @@ class ealertController extends expController {
         'tags',
         'twitter',
     ); // all options: ('aggregation','categories','comments','ealerts','facebook','files','module_title','pagination','rss','tags','twitter',)
-	
+
     static function displayname() { return gt("E-Alerts"); }
     static function description() { return gt("This module will allow users to sign up for email alerts on a module by module basis."); }
-    
+
     static function hasSources() {
         return false;
     }
@@ -52,12 +54,12 @@ class ealertController extends expController {
             'subscriptions'=>$subscriptions
         ));
     }
-    
+
     public function send_confirm() {
         global $db;
 
         // find this E-Alert in the database
-        $src = empty($this->params['src']) ? null : $this->params['src'];
+        $src = empty($this->params['src']) ? null : expString::escape($this->params['src']);
         $ealert = $db->selectObject('expeAlerts', 'module="'.$this->params['orig_controller'].'" AND src="'.$src.'"');
         if (!empty($ealert->autosend_ealerts)) {
             redirect_to(array('controller'=>'ealert','action'=>'send_auto','model'=>$this->params['model'],'id'=>$this->params['id'], 'src'=>$this->params['src']));
@@ -69,17 +71,17 @@ class ealertController extends expController {
         // setup the content for the view
         $subject = $record->title;
         $body = $record->body;
-        
+
         // figure out how many subscribers there are
         $number_of_subscribers = $db->countObjects('user_subscriptions', 'expeAlerts_id='.$ealert->id);
-        
+
         assign_to_template(array(
             'record'=>$record,
             'number_of_subscribers'=>$number_of_subscribers,
             'ealert'=>$ealert
         ));
     }
-    
+
     public function send_process() {
         global $db, $router;
 
@@ -90,22 +92,22 @@ class ealertController extends expController {
         $obj->body .= '<hr><a href="'.$link.'">'.gt('View posting').'.</a>';
         $obj->created_at = time();
         $id = $db->insertObject($obj, 'expeAlerts_temp');
-        
+
         $bot = new expBot(array(
             'url'=>PATH_RELATIVE."index.php?controller=ealert&action=send&id=".$id.'&ealert_id='.$this->params['id'],
             'method'=>'POST',
         ));
-        
+
         $bot->fire();
         flash('message', gt("E-Alerts are being sent to subscribers."));
         expHistory::back();
     }
-    
+
     public function send_auto() {
         global $db, $router;
 
         // find this E-Alert in the database
-        $src = empty($this->params['src']) ? null : $this->params['src'];
+        $src = empty($this->params['src']) ? null : expString::escape($this->params['src']);
         $ealert = $db->selectObject('expeAlerts', 'module="'.$this->params['model'].'" AND src="'.$src.'"');
 
          // find the content for the E-Alerts
@@ -136,22 +138,22 @@ class ealertController extends expController {
 
     public function send() {
         global $db, $router;
-        
+
         // get the message body we saved in the temp table
         $message = $db->selectObject('expeAlerts_temp', 'id='.$this->params['id']);
-        
+
         // look up the subscribers
         $sql  = 'SELECT s.* FROM '.$db->prefix.'user_subscriptions es ';
         $sql .= 'LEFT JOIN '.$db->prefix.'user s ON s.id=es.user_id WHERE es.expeAlerts_id='.$this->params['ealert_id'];
         $subscribers = $db->selectObjectsBySql($sql);
-        
+
         $count = 1;
         $total = count($subscribers);
         foreach($subscribers as $subscriber) {
 //            $link = $router->makelink(array('controller'=>'ealert', 'action'=>'subscriptions', 'id'=>$subscriber->id, 'key'=>$subscriber->hash));
 //            $body  = $message->body;
 //            $body .= '<br><a href="'.$link.'">'.gt('Click here to change your E-Alert subscription settings').'.</a>';
-            
+
             $mail = new expMail();
             $mail->quickSend(array(
                 'html_message'=>$message->body,
@@ -159,13 +161,13 @@ class ealertController extends expController {
                 'from'=>array(trim(SMTP_FROMADDRESS) => trim(ORGANIZATION_NAME)),
 		        'subject'=>$message->subject,
             ));
-            
+
             $message->edited_at = time();
             $message->status = 'Sent message '.$count.' of '.$total;
             $db->updateObject($message, 'expeAlerts_temp');
             $count++;
-        } 
-        
+        }
+
         $db->delete('expeAlerts_temp', 'id='.$message->id);
     }
 
@@ -201,154 +203,158 @@ class ealertController extends expController {
     /**
      * @deprecated
      */
-    public function subscriptions() {
-        global $db;
-        
-        expHistory::set('manageable', $this->params);
-        // make sure we have what we need.
-        if (empty($this->params['key'])) expQueue::flashAndFlow('error', gt('The security key for account was not supplied.'));
-        if (empty($this->params['id'])) expQueue::flashAndFlow('error', gt('The subscriber id for account was not supplied.'));
-        
-        // verify the id/key pair    
-        $sub = new subscribers($this->params['id']);
-        if (empty($sub->id)) expQueue::flashAndFlow('error', gt('We could not find any subscriptions matching the ID and Key you provided.'));
-        
-        // get this users subscriptions
-        $subscriptions = $db->selectColumn('expeAlerts_subscribers', 'expeAlerts_id', 'subscribers_id='.$sub->id);
-        
-        // get a list of all available E-Alerts
-        $ealerts = new expeAlerts();
-        assign_to_template(array(
-            'subscriber'=>$sub,
-            'subscriptions'=>$subscriptions,
-            'ealerts'=>$ealerts->find('all')
-        ));
-    }
-    
+//    public function subscriptions() {
+//        global $db;
+//
+//        expHistory::set('manageable', $this->params);
+//        // make sure we have what we need.
+//        if (empty($this->params['key'])) expQueue::flashAndFlow('error', gt('The security key for account was not supplied.'));
+//        if (empty($this->params['id'])) expQueue::flashAndFlow('error', gt('The subscriber id for account was not supplied.'));
+//
+//        // verify the id/key pair
+//        $sub = new subscribers($this->params['id']);
+//        if (empty($sub->id)) expQueue::flashAndFlow('error', gt('We could not find any subscriptions matching the ID and Key you provided.'));
+//
+//        // get this users subscriptions
+//        $subscriptions = $db->selectColumn('expeAlerts_subscribers', 'expeAlerts_id', 'subscribers_id='.$sub->id);
+//
+//        // get a list of all available E-Alerts
+//        $ealerts = new expeAlerts();
+//        assign_to_template(array(
+//            'subscriber'=>$sub,
+//            'subscriptions'=>$subscriptions,
+//            'ealerts'=>$ealerts->find('all')
+//        ));
+//    }
+
     /**
      * @deprecated
      */
-    public function subscription_update() {
-        global $db;
-        
-        // make sure we have what we need.
-        if (empty($this->params['email'])) expQueue::flashAndFlow('error', gt('You must supply an email address to sign up for email alerts.'));
-        if (empty($this->params['key'])) expQueue::flashAndFlow('error', gt('The security key for account was not supplied.'));
-        if (empty($this->params['id'])) expQueue::flashAndFlow('error', gt('The subscriber id for account was not supplied.'));
-        
-        // find the subscriber and validate the security key
-        $subscriber = new subscribers($this->params['id']);
-        if ($subscriber->hash != $this->params['key']) expQueue::flashAndFlow('error', gt('The security key you supplied does not match the one we have on file.'));
-        
-        // delete any old subscriptions and add the user to new subscriptions
-        $db->delete('expeAlerts_subscribers', 'subscribers_id='.$subscriber->id);
-        foreach($this->params['ealerts'] as $ea_id) {
-            $obj = new stdClass();
-            $obj->subscribers_id = $subscriber->id;
-            $obj->expeAlerts_id = $ea_id;
-            $db->insertObject($obj, 'expeAlerts_subscribers');
-        }
-        
-        $count = count($this->params['ealerts']);
-        
-        if ($count > 0) {
-            flash('message', gt("Your subscriptions have been updated.  You are now subscriber to")." ".$count.' '.gt('E-Alerts.'));
-        } else {
-            flash('error', gt("You have been unsubscribed from all E-Alerts."));
-        }
-        
-        expHistory::back();
-    }
-    
+//    public function subscription_update() {
+//        global $db;
+//
+//        // make sure we have what we need.
+//        if (empty($this->params['email'])) expQueue::flashAndFlow('error', gt('You must supply an email address to sign up for email alerts.'));
+//        if (empty($this->params['key'])) expQueue::flashAndFlow('error', gt('The security key for account was not supplied.'));
+//        if (empty($this->params['id'])) expQueue::flashAndFlow('error', gt('The subscriber id for account was not supplied.'));
+//
+//        // find the subscriber and validate the security key
+//        $subscriber = new subscribers($this->params['id']);
+//        if ($subscriber->hash != $this->params['key']) expQueue::flashAndFlow('error', gt('The security key you supplied does not match the one we have on file.'));
+//
+//        // delete any old subscriptions and add the user to new subscriptions
+//        $db->delete('expeAlerts_subscribers', 'subscribers_id='.$subscriber->id);
+//        foreach($this->params['ealerts'] as $ea_id) {
+//            $obj = new stdClass();
+//            $obj->subscribers_id = $subscriber->id;
+//            $obj->expeAlerts_id = $ea_id;
+//            $db->insertObject($obj, 'expeAlerts_subscribers');
+//        }
+//
+//        $count = count($this->params['ealerts']);
+//
+//        if ($count > 0) {
+//            flash('message', gt("Your subscriptions have been updated.  You are now subscriber to")." ".$count.' '.gt('E-Alerts.'));
+//        } else {
+//            flash('error', gt("You have been unsubscribed from all E-Alerts."));
+//        }
+//
+//        expHistory::back();
+//    }
+
     /**
      * @deprecated
      */
-    public function signup() {
-        global $db;
-        // check the anti-spam control
-        expValidator::check_antispam($this->params, gt("Anti-spam verification failed.  Please try again."));
-        
-        // make sure we have what we need.
-        if (empty($this->params['email'])) expQueue::flashAndFlow('error', gt('You must supply an email address to sign up for email alerts.'));
-        if (empty($this->params['ealerts'])) expQueue::flashAndFlow('error', gt('You did not select any E-Alert topics to subscribe to.'));
-        
-        // find or create the subscriber
-        $id = $db->selectValue('subscribers', 'id', 'email="'.$this->params['email'].'"');
-        $subscriber = new subscribers($id);
-        if (empty($subscriber->id)) {
-            $subscriber->email = trim($this->params['email']);
-            $subscriber->hash = md5($subscriber->email.time());
-            $subscriber->save();
-        }
-        
-        // delete any old subscriptions and add the user to new subscriptions
-        $db->delete('expeAlerts_subscribers', 'subscribers_id='.$subscriber->id);
-        foreach($this->params['ealerts'] as $ea_id) {
-            $obj = new stdClass();
-            $obj->subscribers_id = $subscriber->id;
-            $obj->expeAlerts_id = $ea_id;
-            $db->insertObject($obj, 'expeAlerts_subscribers');
-        }
-  
-        // send a confirmation email to the user.    
-        $ealerts = $db->selectObjects('expeAlerts', 'id IN ('.implode(',', $this->params['ealerts']).')');
-        $body = expTemplate::get_template_for_action($this, 'email/confirmation_email', $this->loc);
-        $body->assign('ealerts', $ealerts);
-        $body->assign('subscriber', $subscriber);
-        
-        $mail = new expMail();
-        $mail->quickSend(array(
-                'html_message'=>$body->render(),
-		        'to'=>$subscriber->email,
-                'from'=>array(trim(SMTP_FROMADDRESS) => trim(ORGANIZATION_NAME)),
-		        'subject'=>gt('Please confirm your E-Alert subscriptions'),
-        ));
-        
-        redirect_to(array('controller'=>'ealert', 'action'=>'pending', 'id'=>$subscriber->id));
-    }
-    
+//    public function signup() {
+//        global $db;
+//        // check the anti-spam control
+//        expValidator::check_antispam($this->params, gt("Anti-spam verification failed.  Please try again."));
+//
+//        // make sure we have what we need.
+//        if (empty($this->params['email'])) expQueue::flashAndFlow('error', gt('You must supply an email address to sign up for email alerts.'));
+//        if (empty($this->params['ealerts'])) expQueue::flashAndFlow('error', gt('You did not select any E-Alert topics to subscribe to.'));
+//
+//        // find or create the subscriber
+//        $id = $db->selectValue('subscribers', 'id', 'email="'.$this->params['email'].'"');
+//        $subscriber = new subscribers($id);
+//        if (empty($subscriber->id)) {
+//            $subscriber->email = trim($this->params['email']);
+//            $subscriber->hash = md5($subscriber->email.time());
+//            $subscriber->save();
+//        }
+//
+//        // delete any old subscriptions and add the user to new subscriptions
+//        $db->delete('expeAlerts_subscribers', 'subscribers_id='.$subscriber->id);
+//        foreach($this->params['ealerts'] as $ea_id) {
+//            $obj = new stdClass();
+//            $obj->subscribers_id = $subscriber->id;
+//            $obj->expeAlerts_id = $ea_id;
+//            $db->insertObject($obj, 'expeAlerts_subscribers');
+//        }
+//
+//        // send a confirmation email to the user.
+//        $ealerts = $db->selectObjects('expeAlerts', 'id IN ('.implode(',', $this->params['ealerts']).')');
+//        $body = expTemplate::get_template_for_action($this, 'email/confirmation_email', $this->loc);
+//        $body->assign('ealerts', $ealerts);
+//        $body->assign('subscriber', $subscriber);
+//
+//        $mail = new expMail();
+//        $mail->quickSend(array(
+//                'html_message'=>$body->render(),
+//		        'to'=>$subscriber->email,
+//                'from'=>array(trim(SMTP_FROMADDRESS) => trim(ORGANIZATION_NAME)),
+//		        'subject'=>gt('Please confirm your E-Alert subscriptions'),
+//        ));
+//
+//        redirect_to(array('controller'=>'ealert', 'action'=>'pending', 'id'=>$subscriber->id));
+//    }
+
     /**
      * @deprecated
      */
-    public function pending() {
+//    public function pending() {
+////        global $db;
+//
+//        // make sure we have what we need.
+//        if (empty($this->params['id'])) expQueue::flashAndFlow('error', gt('Your subscriber ID was not supplied.'));
+//
+//        // find the subscriber and their pending subscriptions
+//        $ealerts = expeAlerts::getPendingBySubscriber($this->params['id']);
+//        $subscriber = new subscribers($this->params['id']);
+//
+//        // render the template
+//        assign_to_template(array(
+//            'subscriber'=>$subscriber,
+//            'ealerts'=>$ealerts
+//        ));
+//    }
+
+    /**
+     * @deprecated
+     */
+//    public function confirm() {
 //        global $db;
-        
-        // make sure we have what we need.
-        if (empty($this->params['id'])) expQueue::flashAndFlow('error', gt('Your subscriber ID was not supplied.'));
+//
+//        // make sure we have what we need.
+//        if (empty($this->params['key'])) expQueue::flashAndFlow('error', gt('The security key for account was not supplied.'));
+//        if (empty($this->params['id'])) expQueue::flashAndFlow('error', gt('The subscriber id for account was not supplied.'));
+//
+//        // verify the id/key pair
+//        $id = $db->selectValue('subscribers','id', 'id='.$this->params['id'].' AND hash="'.$this->params['key'].'"');
+//        if (empty($id)) expQueue::flashAndFlow('error', gt('We could not find any subscriptions matching the ID and Key you provided.'));
+//
+//        // activate this users pending subscriptions
+//        $sub = new stdClass();
+//        $sub->enabled = 1;
+//        $db->updateObject($sub, 'expeAlerts_subscribers', 'subscribers_id='.$id);
+//
+//        // find the users active subscriptions
+//        $ealerts = expeAlerts::getBySubscriber($id);
+//        assign_to_template(array(
+//            'ealerts'=>$ealerts
+//        ));
+//    }
 
-        // find the subscriber and their pending subscriptions
-        $ealerts = expeAlerts::getPendingBySubscriber($this->params['id']);
-        $subscriber = new subscribers($this->params['id']);
-        
-        // render the template
-        assign_to_template(array(
-            'subscriber'=>$subscriber,
-            'ealerts'=>$ealerts
-        ));
-    }
-    
-    public function confirm() {
-        global $db;
-        
-        // make sure we have what we need.
-        if (empty($this->params['key'])) expQueue::flashAndFlow('error', gt('The security key for account was not supplied.'));
-        if (empty($this->params['id'])) expQueue::flashAndFlow('error', gt('The subscriber id for account was not supplied.'));
-        
-        // verify the id/key pair    
-        $id = $db->selectValue('subscribers','id', 'id='.$this->params['id'].' AND hash="'.$this->params['key'].'"');
-        if (empty($id)) expQueue::flashAndFlow('error', gt('We could not find any subscriptions matching the ID and Key you provided.'));
-        
-        // activate this users pending subscriptions
-        $sub = new stdClass();
-        $sub->enabled = 1;
-        $db->updateObject($sub, 'expeAlerts_subscribers', 'subscribers_id='.$id);
-        
-        // find the users active subscriptions
-        $ealerts = expeAlerts::getBySubscriber($id);
-        assign_to_template(array(
-            'ealerts'=>$ealerts
-        ));
-    }
 }
 
 ?>
\ No newline at end of file

programming_language: PHP
filename: billingController.php
change_type: ModificationType.MODIFY
diff: @@ -22,14 +22,15 @@
  */
 
 class billingController extends expController {
-    protected $add_permissions = array(
-        'activate'=>'Activate Payment Options'
+    protected $manage_permissions = array(
+        'select'=>'Select Feature',
+        'toggle'=>'Toggle Feature',
     );
-    
+
     static function displayname() { return gt("e-Commerce Billing Controller"); }
     static function description() { return ""; }
 	static function hasSources() { return false; }
-	
+
 	function selectBillingCalculator() {
 		$billing = new billing();
 		$billing->billingmethod->update($this->params);
@@ -45,12 +46,12 @@ class billingController extends expController {
 	}
 
 	function selectBillingOptions() {
-		
+
 	}
-	
+
 	function manage() {
 	    global $db;
-	    
+
 	    expHistory::set('manageable', $this->params);
 //	    $classes = array();
         $dir = BASE."framework/modules/ecommerce/billingcalculators";
@@ -68,7 +69,7 @@ class billingController extends expController {
                             $obj = new billingcalculator(array(
                                 'title'=>$calcobj->name(),
 //                                'user_title'=>$calcobj->title,
-                                'body'=>$calcobj->description(), 
+                                'body'=>$calcobj->description(),
                                 'calculator_name'=>$classname,
                                 'enabled'=>false));
                             $obj->save();
@@ -77,15 +78,15 @@ class billingController extends expController {
                 }
             }
         }
-        
+
         $bcalc = new billingcalculator();
         $calculators = $bcalc->find('all');
         assign_to_template(array(
             'calculators'=>$calculators
         ));
 	}
-	
-	public function activate(){	
+
+	public function activate(){
 	    if (isset($this->params['id'])) {
 	        $calc = new billingcalculator($this->params['id']);
 	        $calc->update($this->params);
@@ -121,7 +122,7 @@ class billingController extends expController {
             'title'=>static::displayname()
         ));
     }
-    
+
     public function saveconfig() {
         $calc = new billingcalculator($this->params['id']);
         $conf = serialize($calc->calculator->parseConfig($this->params));

programming_language: PHP
filename: ecomconfigController.php
change_type: ModificationType.MODIFY
diff: @@ -26,7 +26,10 @@ class ecomconfigController extends expController {
     protected $add_permissions = array(
         'show'=>'View Admin Options'
     );
-	
+    protected $manage_permissions = array(
+        'options'=>'Display Options'
+    );
+
     static function displayname() { return gt("e-Commerce Configuration Manager"); }
     static function description() { return gt("Use this module to configure your e-Commerce store"); }
     static function hasSources() { return false; }
@@ -34,20 +37,20 @@ class ecomconfigController extends expController {
     function show() {
         expHistory::set('manageable', $this->params);
     }
-    
+
     /*****************************************************************/
     /***************  PRODUCT OPTIONS *******************************/
     /*****************************************************************/
     function edit_optiongroup_master() {
         expHistory::set('editable', $this->params);
-        
+
         $id = isset($this->params['id']) ? $this->params['id'] : null;
-        $record = new optiongroup_master($id);       
+        $record = new optiongroup_master($id);
         assign_to_template(array(
             'record'=>$record
         ));
     }
-    
+
     function update_optiongroup_master() {
         global $db;
 
@@ -55,72 +58,72 @@ class ecomconfigController extends expController {
         $og = new optiongroup_master($id);
         $oldtitle = $og->title;
         $og->update($this->params);
-        
+
         // if the title of the master changed we should update the option groups that are already using it.
         if ($oldtitle != $og->title) {
             $db->sql('UPDATE '.$db->prefix.'optiongroup SET title="'.$og->title.'" WHERE title="'.$oldtitle.'"');
         }
-        
+
         expHistory::back();
     }
-    
+
     function delete_optiongroup_master() {
         global $db;
-        
+
         $mastergroup = new optiongroup_master($this->params);
-        
+
         // delete all the options for this optiongroup master
         foreach ($mastergroup->option_master as $masteroption) {
             $db->delete('option', 'option_master_id='.$masteroption->id);
             $masteroption->delete();
         }
-        
+
         // delete the mastergroup
         $db->delete('optiongroup', 'optiongroup_master_id='.$mastergroup->id);
         $mastergroup->delete();
-        
+
         expHistory::back();
     }
-    
+
     function delete_option_master() {
         global $db;
 
         $masteroption = new option_master($this->params['id']);
-        
+
         // delete any implementations of this option master
         $db->delete('option', 'option_master_id='.$masteroption->id);
         $masteroption->delete('optiongroup_master_id=' . $masteroption->optiongroup_master_id);
         //eDebug($masteroption);
         expHistory::back();
     }
-    
+
     function edit_option_master() {
         expHistory::set('editable', $this->params);
-        
+
         $params = isset($this->params['id']) ? $this->params['id'] : $this->params;
-        $record = new option_master($params);      
+        $record = new option_master($params);
         assign_to_template(array(
             'record'=>$record
         ));
     }
-    
-    function update_option_master() {        
+
+    function update_option_master() {
         global $db;
 
         $id = empty($this->params['id']) ? null : $this->params['id'];
         $opt = new option_master($id);
         $oldtitle = $opt->title;
-        
+
         $opt->update($this->params);
-        
+
         // if the title of the master changed we should update the option groups that are already using it.
         if ($oldtitle != $opt->title) {
-            
+
         }$db->sql('UPDATE '.$db->prefix.'option SET title="'.$opt->title.'" WHERE option_master_id='.$opt->id);
-        
+
         expHistory::back();
     }
-    
+
     public function options() {
         expHistory::set('viewable', $this->params);
         $optiongroup = new optiongroup_master();
@@ -129,19 +132,19 @@ class ecomconfigController extends expController {
             'optiongroups'=>$optiongroups
         ));
     }
-    
+
     function rerank_optionmaster() {
         $om = new option_master($this->params['id']);
         $om->rerank($this->params['push'], 'optiongroup_master_id=' . $this->params['master_id']);
         expHistory::back();
     }
-    
+
     /*****************************************************************/
     /***************  DISCOUNTS        *******************************/
     /*****************************************************************/
     public function manage_discounts() {
         expHistory::set('manageable', $this->params);
-		
+
         $page = new expPaginator(array(
             'model'=>'discounts',
 			'sql'=>'SELECT * FROM '.DB_TABLE_PREFIX.'_discounts',
@@ -158,16 +161,16 @@ class ecomconfigController extends expController {
             'page'=>$page
         ));
     }
-    
+
       public function edit_discount() {
         $id = empty($this->params['id']) ? null : $this->params['id'];
         $discount = new discounts($id);
-        
+
         //grab all user groups
         $group = new group();
-        
+
         //create two 'default' groups:
-        $groups = array( 
+        $groups = array(
                 -1 => 'ALL LOGGED IN USERS',
                 -2 => 'ALL NON-LOGGED IN USERS'
                 );
@@ -183,17 +186,17 @@ class ecomconfigController extends expController {
            };
        }
        //find our selected groups for this discount already
-       // eDebug($discount);                        
+       // eDebug($discount);
        $selected_groups = array();
        if (!empty($discount->group_ids))
        {
             $selected_groups = expUnserialize($discount->group_ids);
        }
-       
+
        if ($discount->minimum_order_amount == "") $discount->minimum_order_amount = 0;
        if ($discount->discount_amount == "") $discount->discount_amount = 0;
        if ($discount->discount_percent == "") $discount->discount_percent = 0;
-       
+
         // get the shipping options and their methods
         $shipping_services = array();
         $shipping_methods = array();
@@ -205,7 +208,7 @@ class ecomconfigController extends expController {
                 $shipping_methods[$calcid] = $calc->availableMethods();
             }
         }
-        
+
        assign_to_template(array(
            'discount'=>$discount,
            'groups'=>$groups,
@@ -214,7 +217,7 @@ class ecomconfigController extends expController {
            'shipping_methods'=>$shipping_methods
        ));
     }
-    
+
     public function update_discount() {
         $id = empty($this->params['id']) ? null : $this->params['id'];
         $discount = new discounts($id);
@@ -224,12 +227,12 @@ class ecomconfigController extends expController {
         } else {
             $this->params['required_shipping_calculator_id'] = 0;
         }
-        
+
         $discount->update($this->params);
         expHistory::back();
     }
-    
-    public function activate_discount(){    
+
+    public function activate_discount(){
         if (isset($this->params['id'])) {
             $discount = new discounts($this->params['id']);
             $discount->update($this->params);
@@ -238,10 +241,10 @@ class ecomconfigController extends expController {
                 //redirect_to(array('controller'=>'billing', 'action'=>'configure', 'id'=>$discount->id));
             //}
         }
-        
+
         expHistory::back();
     }
-    
+
     /*****************************************************************/
     /***************  PROMO CODE       *******************************/
     /*****************************************************************/
@@ -264,7 +267,7 @@ class ecomconfigController extends expController {
 	    $code->update($this->params);
 	    expHistory::back();
 	}
-	
+
     /*****************************************************************/
     /***************  GROUP DISCOUNTS  *******************************/
     /*****************************************************************/
@@ -289,7 +292,7 @@ class ecomconfigController extends expController {
 
 	public function update_groupdiscounts() {
 	    global $db;
-	    
+
 	    if (empty($this->params['id'])) {
 	        // look for existing discounts for the same group
 	        $existing_id = $db->selectValue('groupdiscounts', 'id', 'group_id='.$this->params['group_id']);
@@ -300,32 +303,32 @@ class ecomconfigController extends expController {
 	    $gd->update($this->params);
 	    expHistory::back();
 	}
-	
+
 	function rerank_groupdiscount() {
         $gd = new groupdiscounts($this->params['id']);
         $gd->rerank($this->params['push']);
         expHistory::back();
     }
-    
+
     /*****************************************************************/
     /***************  GENERAL STORE CONFIG  *******************************/
     /*****************************************************************/
     function configure() {
         expHistory::set('editable', $this->params);
         // little bit of trickery so that that categories can have their own configs
-        
+
         $this->loc->src = "@globalstoresettings";
         $config = new expConfig($this->loc);
         $this->config = $config->config;
         $pullable_modules = expModules::listInstalledControllers($this->baseclassname, $this->loc);
         $views = expTemplate::get_config_templates($this, $this->loc);
-        
-        $gc = new geoCountry();             
+
+        $gc = new geoCountry();
         $countries = $gc->find('all');
-        
-        $gr = new geoRegion();             
+
+        $gr = new geoRegion();
         $regions = $gr->find('all');
-        
+
         assign_to_template(array(
             'config'=>$this->config,
             'pullable_modules'=>$pullable_modules,
@@ -334,7 +337,7 @@ class ecomconfigController extends expController {
             'regions'=>$regions,
             'title'=>static::displayname()
         ));
-    }   
+    }
 
     function saveconfig() {
         $this->params['min_order'] = substr($this->params['min_order'], 1) ;
@@ -354,16 +357,16 @@ class ecomconfigController extends expController {
 	/*****************************************************************/
     /***************  Upcharge Rate   *******************************/
     /*****************************************************************/
-	
+
 	 function manage_upcharge() {
 		$this->loc->src = "@globalstoresettings";
         $config = new expConfig($this->loc);
 		$this->config = $config->config;
 
-		$gc = new geoCountry();             
+		$gc = new geoCountry();
         $countries = $gc->find('all');
-        
-        $gr = new geoRegion();             
+
+        $gr = new geoRegion();
         $regions = $gr->find('all',null,'rank asc,name asc');
         assign_to_template(array(
             'countries'=>$countries,
@@ -371,12 +374,12 @@ class ecomconfigController extends expController {
             'upcharge'=>!empty($this->config['upcharge'])?$this->config['upcharge']:''
         ));
 	 }
-	 
+
 	 function update_upcharge() {
         $this->loc->src = "@globalstoresettings";
         $config = new expConfig($this->loc);
 		$this->config = $config->config;
-		
+
 		//This will make sure that only the country or region that given a rate value will be saved in the db
 		$upcharge = array();
 		foreach($this->params['upcharge'] as $key => $item) {
@@ -385,12 +388,12 @@ class ecomconfigController extends expController {
 			}
 		}
 		$this->config['upcharge'] = $upcharge;
-		
+
         $config->update(array('config'=>$this->config));
         flash('message', gt('Configuration updated'));
         expHistory::back();
     }
-	
+
 }
 
 ?>
\ No newline at end of file

programming_language: PHP
filename: eventregistrationController.php
change_type: ModificationType.MODIFY
diff: @@ -31,14 +31,18 @@ function compare($x, $y) {
 
 class eventregistrationController extends expController {
     public $basemodel_name = 'eventregistration';
-
     public $useractions = array(
         'showall'     => 'Show all events',
         'eventsCalendar'                  => 'Calendar View',
         'upcomingEvents'                  => 'Upcoming Events',
 //        'showByTitle' => "Show events by title",
     );
-
+    protected $add_permissions = array(
+//        'emailRegistrants'=> 'Email Registrants',
+    );
+    protected $manage_permissions = array(
+        'emailRegistrants'=> 'Email Registrants',
+    );
     // hide the configs we don't need
     public $remove_configs = array(
         'aggregation',
@@ -52,11 +56,6 @@ class eventregistrationController extends expController {
         'twitter',
     );  // all options: ('aggregation','categories','comments','ealerts','facebook','files','module_title','pagination','rss','tags','twitter',)
 
-    protected $add_permissions = array(
-        'view_registrants'=> 'View Registrants',
-        'emailRegistrants'=> 'Email Registrants',
-    );
-
     static function displayname() {
         return gt("e-Commerce Online Event Registration");
     }

programming_language: PHP
filename: orderController.php
change_type: ModificationType.MODIFY
diff: @@ -22,30 +22,32 @@
  */
 
 class orderController extends expController {
-    protected $add_permissions = array(
-        'showall'             => 'Manage',
-        'show'                => 'View Orders',
-        'setStatus'           => 'Change Status',
-        'edit_payment_info'   => 'Edit Payment Info',
+    protected $manage_permissions = array(
+        'add_order_item'      => 'Add Order Item',
+        'download'      => 'Download Label',
+//        'create_new_order'    => 'Create A New Order',
+//        'createReferenceOrder'=> 'Create Reference Order',
+//        'edit_address'        => 'Edit Address',
+//        'edit_invoice_id'     => 'Edit Invoice Id',
+//        'edit_order_item'     => 'Edit Order Item',
+//        'edit_payment_info'   => 'Edit Payment Info',
+//        'edit_shipping_method'=> 'Edit Shipping Method',
+//        'edit_totals'         => 'Edit Totals',
+        'email'         => 'Send Email',
+        'quickfinder'=> 'Do a quick order lookup',
         'save_payment_info'=> 'Save Payment Info',
-        'edit_address'        => 'Edit Address',
         'save_address'=> 'Save Address',
-        'edit_order_item'     => 'Edit Order Item',
         'save_order_item'=> 'Save Order Item',
-        'add_order_item'      => 'Add Order Item',
-        'save_new_order_item'=> 'Save New Order Item',
-        'edit_totals'         => 'Edit Totals',
+//        'save_new_order_item'=> 'Save New Order Item',
         'save_totals'=> 'Save Totals',
-        'edit_invoice_id'     => 'Edit Invoice Id',
         'save_invoice_id'=> 'Save Invoice Id',
-        'update_sales_reps'   => 'Manage Sales Reps',
-        'quickfinder'=> 'Do a quick order lookup',
-        'edit_shipping_method'=> 'Edit Shipping Method',
         'save_shipping_method'=> 'Save Shipping Method',
-        'create_new_order'    => 'Create A New Order',
         'save_new_order'=> 'Save a new order',
-        'createReferenceOrder'=> 'Create Reference Order',
-        'save_reference_order'=> 'Save Reference Order'
+        'save_reference_order'=> 'Save Reference Order',
+        'set'           => 'Change Status',
+        'showall'             => 'Manage',
+        'show'                => 'View Orders',
+        'update'                => 'update order',
     );
 
     static function displayname() {
@@ -66,21 +68,21 @@ class orderController extends expController {
         for($i=0; $i<$count; $i++) {
             // get the cart
             $cart = $db->selectObject('orders','purchased=0');
-            
+
             // check to make sure this isn't an active session
             $ticket = $db->selectObject('sessionticket', "ticket='".$cart->sessionticket_ticket."'");
             if (empty($ticket)) {
                 // delete all the order items for this cart and their shippingmethods
                 foreach($db->selectObjects('orderitems', 'orders_id='.$cart->id) as $oi) {
                     $db->delete('shippingmethods', 'id='.$oi->shippingmethods_id);
-                    $db->delete('orderitems', 'orders_id='.$cart->id);    
+                    $db->delete('orderitems', 'orders_id='.$cart->id);
                 }
-                
+
                 // delete the billing methods for this cart.
                 $db->delete('billingmethods', 'orders_id='.$cart->id);
                 $db->delete('orders', 'id='.$cart->id);
-            }           
-            
+            }
+
         } */
 
         // find orders with a "closed" status type
@@ -247,7 +249,7 @@ class orderController extends expController {
         //check here for the hash in the params, or session set w/ perms to view...shs = xaf7y0s87d7elshd70 etc
         //if present, prompt user for the order number and email address on the order
         //and if they pass, show the order to them. Need to maybe set something in the session then for subsequent
-        //viewing of the order?        
+        //viewing of the order?
         if ($user->id != $order->user_id) {
             if ($user->isAdmin()) {
                 redirect_to(array('controller'=> 'order', 'action'=> 'show', 'id'=> $this->params['id']));
@@ -415,7 +417,7 @@ class orderController extends expController {
             foreach ($orders as $order) {
                 if ($user->isAdmin()) {
                     $invoice .= renderAction(array('controller'=> 'order', 'action'=> 'show', 'view'=> 'show_printable', 'id'=> $order['id'], 'printerfriendly'=> '1', 'no_output'=> 'true'));
-                    //eDebug($order['id'] . ": " . $timer->mark());                        
+                    //eDebug($order['id'] . ": " . $timer->mark());
                 } else {
                     $invoice .= renderAction(array('controller'=> 'order', 'action'=> 'myOrder', 'view'=> 'show_printable', 'id'=> $order['id'], 'printerfriendly'=> '1', 'no_output'=> 'true'));
                 }
@@ -550,7 +552,7 @@ exit();
 // END OF FILE
 //============================================================+
 
-            
+
             // create new PDF document
             $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
 
@@ -878,7 +880,7 @@ exit();
 //            $db->insertObject($noteObj, 'content_expSimpleNote');
             $note->attachNote('order', $order->id);
 
-            //eDebug($note,true);            
+            //eDebug($note,true);
         } else {
             flash('error', gt('The email was NOT sent. An email address was not found for this customer'));
             expHistory::back();
@@ -920,7 +922,7 @@ exit();
 
         if (empty($router->params['action'])) return false;
 
-        // figure out what metadata to pass back based on the action 
+        // figure out what metadata to pass back based on the action
         // we are in.
         $action   = $router->params['action'];
         $metainfo = array('title'=>'', 'keywords'=>'', 'description'=>'', 'canonical'=> '', 'noindex' => true, 'nofollow' => true);
@@ -957,7 +959,7 @@ exit();
     function captureAuthorization() {
         //eDebug($this->params,true);
         $order = new order($this->params['id']);
-        /*eDebug($this->params); 
+        /*eDebug($this->params);
         //eDebug($order,true);*/
         //eDebug($order,true);
         //$billing = new billing();
@@ -1293,7 +1295,7 @@ exit();
 
         //eDebug($this->params,true);
         $order = new order($this->params['original_orderid']);
-        //eDebug($order,true); 
+        //eDebug($order,true);
         //x
         $newOrder                  = new order();
         $newOrder->order_status_id = $this->params['order_status_id'];
@@ -1348,8 +1350,8 @@ exit();
         $newBillingMethod->billing_options      = serialize($tObj);
         $newBillingMethod->save();
 
-        //eDebug(expUnserialize($order->billingmethod[0]->billing_options));        
-        //eDebug(expUnserialize($order->billingmethod[0]->billingtransaction[0]->billing_options),true); 
+        //eDebug(expUnserialize($order->billingmethod[0]->billing_options));
+        //eDebug(expUnserialize($order->billingmethod[0]->billingtransaction[0]->billing_options),true);
 
         $newBillingTransaction                       = new billingtransaction();
 //        $newBillingTransaction->billingcalculator_id = 6; ///setting to manual/passthru
@@ -1377,7 +1379,7 @@ exit();
             $newOi->products_name           = $this->params['products_name'][$oikey];
             $newOi->products_price          = $this->params['products_price'][$oikey];
             $newOi->products_price_adjusted = $this->params['products_price'][$oikey];
-            //$newOi->products_tax = 0;        
+            //$newOi->products_tax = 0;
             $newOi->shippingmethods_id = $newShippingMethod->id;
             $newOi->save();
         }
@@ -1406,7 +1408,7 @@ exit();
 //        global $user, $db;
         //eDebug($this->params,true);
         //$order = new order($this->params['original_orderid']);
-        //eDebug($order,true); 
+        //eDebug($order,true);
 
         $newAddy = new address();
         if ($this->params['customer_type'] == 1) {
@@ -1490,8 +1492,8 @@ exit();
         $newBillingMethod->email                = $newAddy->email;
         $newBillingMethod->save();
 
-        //eDebug(expUnserialize($order->billingmethod[0]->billing_options));        
-        //eDebug(expUnserialize($order->billingmethod[0]->billingtransaction[0]->billing_options),true); 
+        //eDebug(expUnserialize($order->billingmethod[0]->billing_options));
+        //eDebug(expUnserialize($order->billingmethod[0]->billingtransaction[0]->billing_options),true);
 
         $newBillingTransaction                       = new billingtransaction();
 //        $newBillingTransaction->billingcalculator_id = 6; ///setting to manual/passthru
@@ -1666,7 +1668,7 @@ exit();
         $oi->product           = new product($oi->product->id, true, true);
         if ($oi->product->parent_id != 0) {
             $parProd = new product($oi->product->parent_id);
-            //$oi->product->optiongroup = $parProd->optiongroup;   
+            //$oi->product->optiongroup = $parProd->optiongroup;
             $oi->product = $parProd;
         }
         //FIXME we don't use selectedOpts?
@@ -1776,20 +1778,20 @@ exit();
         //$this->user_input_fields = expUnserialize($this->user_input_fields);
         //eDebug($this,true);
         if (!empty($oi->product->user_input_fields)) foreach ($oi->product->user_input_fields as $uifkey=> $uif) {
-            /*if ($uif['is_required'] || (!$uif['is_required'] && strlen($params['user_input_fields'][$uifkey]) > 0)) 
+            /*if ($uif['is_required'] || (!$uif['is_required'] && strlen($params['user_input_fields'][$uifkey]) > 0))
             {
                 if (strlen($params['user_input_fields'][$uifkey]) < $uif['min_length'])
                 {
-                    //flash('error', 'test');    
-                    //redirect_to(array('controller'=>cart, 'action'=>'displayForm', 'form'=>'addToCart', 'product_id'=>$this->id, 'product_type'=>$this->product_type));  
+                    //flash('error', 'test');
+                    //redirect_to(array('controller'=>cart, 'action'=>'displayForm', 'form'=>'addToCart', 'product_id'=>$this->id, 'product_type'=>$this->product_type));
                     $params['error'] .= $uif['name'].' field has a minimum requirement of ' . $uif['min_length'] . ' characters.<br/>';
-                    
+
                 }else if (strlen($params['user_input_fields'][$uifkey]) > $uif['max_length'] && $uif['max_length'] > 0)
                 {
-                    //flash('error', );    
-                    //redirect_to(array('controller'=>cart, 'action'=>'displayForm', 'form'=>'addToCart', 'product_id'=>$this->id, 'product_type'=>$this->product_type));      
+                    //flash('error', );
+                    //redirect_to(array('controller'=>cart, 'action'=>'displayForm', 'form'=>'addToCart', 'product_id'=>$this->id, 'product_type'=>$this->product_type));
                     $params['error'] .= $uif['name'].' field has a maximum requirement of ' . $uif['max_length'] . ' characters.<br/>';
-                } 
+                }
             }*/
             $user_input_info[] = array($uif['name']=> $this->params['user_input_fields'][$uifkey]);
         }
@@ -1798,7 +1800,7 @@ exit();
 
         $oi->options           = serialize($options);
         $oi->user_input_fields = serialize($user_input_info);
-        //eDebug($oi);        
+        //eDebug($oi);
         $oi->save();
         $oi->refresh();
         //eDebug($oi,true);
@@ -1856,7 +1858,7 @@ exit();
         $order = new order($this->params['orderid']);
         if (isset($this->params['prod-quantity'])) {
             //we are adding multiple children, so we approach a bit different
-            //we'll send over the product_id of the parent, along with id's and quantities of children we're adding 
+            //we'll send over the product_id of the parent, along with id's and quantities of children we're adding
             foreach ($this->params['prod-quantity'] as $qkey=> &$quantity) {
                 if (in_array($qkey, $this->params['prod-check'])) {
                     $this->params['children'][$qkey] = $quantity;
@@ -2007,14 +2009,14 @@ exit();
         /*$o = new order();
         $b = new billingmethod();
         $s = new shippingmethod();
-        
+
         $search = intval($this->params['ordernum']);
         if (is_int($oid) && $oid > 0)
         {
             $orders = $o->find('all',"invoice_id LIKE '%".$oid."%'");
             if(count($orders == 1))
             {
-                redirect_to(array('controller'=>'order','action'=>'show','id'=>$order[0]->id));            
+                redirect_to(array('controller'=>'order','action'=>'show','id'=>$order[0]->id));
             }
             else
             {
@@ -2033,7 +2035,7 @@ exit();
             $order = $o->find('first','invoice_id='.$oid);
             if(!empty($order->id))
             {
-                redirect_to(array('controller'=>'order','action'=>'show','id'=>$order->id));            
+                redirect_to(array('controller'=>'order','action'=>'show','id'=>$order->id));
             }
             else
             {
@@ -2042,7 +2044,7 @@ exit();
         }
         else
         {
-            flashAndFlow('message','Invalid order number.');        
+            flashAndFlow('message','Invalid order number.');
         }*/
     }
 
@@ -2071,7 +2073,7 @@ exit();
         if (isset($sessAr) && isset($this->params['cid']) && $this->params['cid'] == $sessAr['cid']) {
             $tmpCart = new order($sessAr['cid']);
             if (isset($tmpCart->id)) {
-                //eDebug($tmpCart,true); 
+                //eDebug($tmpCart,true);
                 $shippingMethod = $tmpCart->shippingmethod;
                 $billingMethod  = $tmpCart->billingmethod[0];
 
@@ -2125,7 +2127,7 @@ exit();
         global $db;
 
         $sql = "select DISTINCT(a.id) as id, a.firstname as firstname, a.middlename as middlename, a.lastname as lastname, a.organization as organization, a.email as email ";
-        $sql .= "from " . $db->prefix . "addresses as a "; //R JOIN " . 
+        $sql .= "from " . $db->prefix . "addresses as a "; //R JOIN " .
         //$db->prefix . "billingmethods as bm ON bm.addresses_id=a.id ";
         $sql .= " WHERE match (a.firstname,a.lastname,a.email,a.organization) against ('" . $this->params['query'] .
             "*' IN BOOLEAN MODE) ";
@@ -2148,7 +2150,7 @@ exit();
         global $db;
 
         $sql = "select DISTINCT(a.id) as id, a.source as source, a.firstname as firstname, a.middlename as middlename, a.lastname as lastname, a.organization as organization, a.email as email ";
-        $sql .= "from " . $db->prefix . "external_addresses as a "; //R JOIN " . 
+        $sql .= "from " . $db->prefix . "external_addresses as a "; //R JOIN " .
         //$db->prefix . "billingmethods as bm ON bm.addresses_id=a.id ";
         $sql .= " WHERE match (a.firstname,a.lastname,a.email,a.organization) against ('" . $this->params['query'] .
             "*' IN BOOLEAN MODE) ";

programming_language: PHP
filename: order_statusController.php
change_type: ModificationType.MODIFY
diff: @@ -22,14 +22,17 @@
  */
 
 class order_statusController extends expController {
+    protected $manage_permissions = array(
+        'toggle'=>'Toggle Status'
+    );
     static function displayname() { return gt("e-Commerce Order Statuses"); }
     static function description() { return gt("Manage e-Commerce order status codes"); }
     static function hasSources() { return false; }
     static function hasContent() { return false; }
-    
+
     public function manage() {
         expHistory::set('viewable', $this->params);
-        
+
         $page = new expPaginator(array(
 			'model'=>'order_status',
 			'where'=>1,
@@ -45,10 +48,10 @@ class order_statusController extends expController {
             'page'=>$page
         ));
     }
-    
+
     public function manage_messages() {
         expHistory::set('manageable', $this->params);
-        
+
         $page = new expPaginator(array(
 			'model'=>'order_status_messages',
 			'where'=>1,
@@ -65,7 +68,7 @@ class order_statusController extends expController {
             'page'=>$page
         ));
     }
-    
+
     public function edit_message() {
         $id = isset($this->params['id']) ? $this->params['id'] : null;
         $msg = new order_status_messages($id);
@@ -74,28 +77,28 @@ class order_statusController extends expController {
         ));
         //$msg->update($this->params);
     }
-    
+
     public function update_message() {
         $id = isset($this->params['id']) ? $this->params['id'] : null;
         $msg = new order_status_messages($id);
         $msg->update($this->params);
         expHistory::back();
     }
-    
+
     public function delete_message() {
         if (empty($this->params['id'])) return false;
         $msg = new order_status_messages($this->params['id']);
         $msg->delete();
         expHistory::back();
     }
-    
+
     public function toggle_closed() {
         global $db;
 
         $db->toggle('order_status', 'treat_as_closed', 'id='.$this->params['id']);
         expHistory::back();
     }
-    
+
     public function toggle_default() {
         global $db;
 
@@ -103,17 +106,17 @@ class order_statusController extends expController {
         $db->setUniqueFlag($order_status, 'order_status', 'is_default');
         expHistory::back();
     }
-    
+
     public function showall() {
         redirect_to(array('controller'=>'order_status', 'action'=>'manage'));
 //        $this->manage();
     }
-    
+
     public function show() {
         redirect_to(array('controller'=>'order_status', 'action'=>'manage'));
 //        $this->manage();
     }
-    
+
 }
 
 ?>
\ No newline at end of file

programming_language: PHP
filename: purchaseOrderController.php
change_type: ModificationType.MODIFY
diff: @@ -22,24 +22,17 @@
  */
 
 class purchaseOrderController extends expController {
-
 	public $basemodel_name = 'purchase_order';
-	protected $add_permissions = array(
-        'manage'=>'Manage Purchase Orders',
-        'edit'=>'Edit Purchase Orders',
-        'manage_vendors'=>'Manage Vendors',
+	protected $manage_permissions = array(
         'show_vendor'=>'Show Vendor Details',
-        'edit_vendor'=>'Edit Vendor',
-        'update_vendor'=>'Update Vendor',
-        'delete_vendor'=>'Delete vendors',
     );
-	
+
     static function displayname() { return gt("e-Commerce Purchase Order Manager"); }
     static function description() { return gt("Use this module to create and manage purchase orders for your ecommerce store."); }
-	
+
 	function manage () {
 	    expHistory::set('viewable', $this->params);
-		
+
 		$vendor = new vendor();
 		$vendors = $vendor->find('all');
 		if(!empty($this->params['vendor'])) {
@@ -47,34 +40,34 @@ class purchaseOrderController extends expController {
 		} else {
 			$purchase_orders = $this->purchase_order->find('all');
 		}
-		
+
 		assign_to_template(array(
             'purchase_orders'=>$purchase_orders,
             'vendors' => $vendors,
             'vendor_id' => @$this->params['vendor']
         ));
 	}
-	
+
 	function edit () {
 //	    global $db;
 	    assign_to_template(array(
             'record'=>$this->params
         ));
 	}
-    
+
 	function manage_vendors () {
 	    expHistory::set('viewable', $this->params);
 		$vendor = new vendor();
-		
+
 		$vendors = $vendor->find('all');
 		assign_to_template(array(
             'vendors'=>$vendors
         ));
 	}
-	
+
 	function show_vendor () {
 		$vendor = new vendor();
-		
+
 		if(isset($this->params['id'])) {
 			$vendor = $vendor->find('first', 'id =' .$this->params['id']);
 			$vendor_title = $vendor->title;
@@ -88,17 +81,17 @@ class purchaseOrderController extends expController {
                 $vendor->classname,
                 $vendor->identifier
             );
-		
+
 			assign_to_template(array(
                 'vendor_title' => $vendor_title,
                 'vendor'=>$vendor
             ));
 		}
 	}
-	
+
 	function edit_vendor() {
 		$vendor = new vendor();
-		
+
 		if(isset($this->params['id'])) {
 			$vendor = $vendor->find('first', 'id =' .$this->params['id']);
 			assign_to_template(array(
@@ -106,34 +99,34 @@ class purchaseOrderController extends expController {
             ));
 		}
 	}
-	
+
 	function update_vendor() {
 		$vendor = new vendor();
-		
+
 		$vendor->update($this->params['vendor']);
         expHistory::back();
     }
-	
+
 	function delete_vendor() {
 		global $db;
-		
+
         if (!empty($this->params['id'])){
 			$db->delete('vendor', 'id =' .$this->params['id']);
 		}
         expHistory::back();
     }
-	
+
 	public function getPurchaseOrderByJSON() {
-		
+
 		if(!empty($this->params['vendor'])) {
 			$purchase_orders = $this->purchase_order->find('all', 'vendor_id=' . $this->params['vendor']);
 		} else {
 			$purchase_orders = $this->purchase_order->find('all');
 		}
-		
+
 		echo json_encode($purchase_orders);
 	}
-    
+
 }
 
 ?>
\ No newline at end of file

programming_language: PHP
filename: shippingController.php
change_type: ModificationType.MODIFY
diff: @@ -22,8 +22,11 @@
  */
 
 class shippingController extends expController {
-    protected $add_permissions = array(
-        'toggle'=>'Enable/Disable Options'
+    protected $manage_permissions = array(
+        'editspeed'=>'Edit Shipping Speed',
+        'save'=>'Save Configuration',
+        'select'=>'Select Feature',
+        'toggle'=>'Enable/Disable Options',
     );
 
     static function displayname() { return gt("e-Commerce Shipping Controller"); }
@@ -38,16 +41,16 @@ class shippingController extends expController {
 	    global $db;
 
 		$shipping = new shipping();
-		
+
 		// update the shippingmethod
 		$shipping->shippingmethod->update(array('shippingcalculator_id'=>$this->params['shippingcalculator_id'],'option'=>null,'option_title'=>null));
-		
+
 		// fetch the calculator
 		$calcname = $db->selectValue('shippingcalculator', 'calculator_name', 'id='.$this->params['shippingcalculator_id']);
 		//eDebug($this->params['shippingcalculator_id']);
 		//eDebug($calcname);
 		$shipping->calculator = new $calcname($this->params['shippingcalculator_id']);
-		
+
 		$ar = new expAjaxReply(200, 'ok', $shipping, array('controller'=>'cart', 'action'=>'checkout'),true);
 		$ar->send();
 	}
@@ -77,26 +80,26 @@ class shippingController extends expController {
 		$ar = new expAjaxReply(200, 'ok', new address($shipping->shippingmethod->addresses_id), array('controller'=>'cart', 'action'=>'checkout'),true);
 		$ar->send();
 	}
-	
+
     /**
      * Ajax method to set a shipping 'gift' message
      */
 	function leaveMessage() {
 		if (!empty($this->params['shippingmessageid'])) {
 		    $sm = new shippingmethod($this->params['shippingmessageid']);
-		    
+
 		    if ($this->params['nosave'] == false) {
-		        $sm->to = empty($this->params['shpmessageto']) ? null : $this->params['shpmessageto'];   
-		        $sm->from = empty($this->params['shpmessagefrom']) ? null : $this->params['shpmessagefrom']; 
-		        $sm->message = empty($this->params['shpmessage']) ? null : $this->params['shpmessage']; 
+		        $sm->to = empty($this->params['shpmessageto']) ? null : $this->params['shpmessageto'];
+		        $sm->from = empty($this->params['shpmessagefrom']) ? null : $this->params['shpmessagefrom'];
+		        $sm->message = empty($this->params['shpmessage']) ? null : $this->params['shpmessage'];
 		        $sm->save();
 		    }
 		}
-		
+
 		$ar = new expAjaxReply(200, 'ok', $sm, array('controller'=>'cart', 'action'=>'checkout'),true);
-		$ar->send();		
+		$ar->send();
 	}
-	
+
 	function renderOptions() {  //FIXME do we ever call this?
 //	    global $db, $order;
         global $order; //FIXME we do NOT want the global $order
@@ -119,15 +122,15 @@ class shippingController extends expController {
                 $opt = $shipping->pricelist[$shipping->shippingmethod->option];
             }
         }
-        
+
         $shipping->shippingmethod->update(array('option'=>$opt['id'],'option_title'=>$opt['title'],'shipping_cost'=>$opt['cost']));
-        
+
         assign_to_template(array(
             'shipping'=>$shipping,
             'order'=>$order
         ));
 	}
-	
+
     /**
      * Ajax method to return a shipping calculator object within a shipping object
      */
@@ -136,10 +139,10 @@ class shippingController extends expController {
 	    $ar = new expAjaxReply(200, 'ok', $shipping->listPrices(), array('controller'=>'cart', 'action'=>'checkout'),true);
 		$ar->send();
 	}
-	
+
 	function manage() {
 	    global $db;
-	    
+
 	    expHistory::set('manageable', $this->params);
 	    $calculators = array();
         $dir = BASE."framework/modules/ecommerce/shippingcalculators";
@@ -151,10 +154,10 @@ class shippingController extends expController {
                 if (is_file("$dir/$file") && substr("$dir/$file", -4) == ".php") {
                     include_once("$dir/$file");
                     $classname = substr($file, 0, -4);
-                    $id = $db->selectValue('shippingcalculator', 'id', 'calculator_name="'.$classname.'"');                    
+                    $id = $db->selectValue('shippingcalculator', 'id', 'calculator_name="'.$classname.'"');
                     if (empty($id)) {
                         $calcobj = new $classname($this->params);
-                        if ($calcobj->isSelectable() == true) {                            
+                        if ($calcobj->isSelectable() == true) {
                             $calcobj->update(array('title'=>$calcobj->name(),'body'=>$calcobj->description(),'calculator_name'=>$classname,'enabled'=>false));
                         }
                     } else {
@@ -176,8 +179,8 @@ class shippingController extends expController {
             'calculators'=>$calculators
         ));
 	}
-	
-		
+
+
 	public function toggle() {
 	    global $db;
 
@@ -222,18 +225,18 @@ class shippingController extends expController {
             'title'=>static::displayname()
         ));
     }
-    
+
     public function saveconfig() {
         global $db;
 
         if (empty($this->params['id'])) return false;
         $calcname = $db->selectValue('shippingcalculator', 'calculator_name', 'id='.$this->params['id']);
         $calc = new $calcname($this->params['id']);
-        $conf = serialize($calc->parseConfig($this->params));        
+        $conf = serialize($calc->parseConfig($this->params));
         $calc->update(array('config'=>$conf));
         expHistory::back();
     }
-	
+
 	public function editspeed() {
         global $db;
 
@@ -243,9 +246,9 @@ class shippingController extends expController {
         assign_to_template(array(
             'calculator'=>$calc
         ));
-		
+
     }
-	
+
 	public function saveEditSpeed() {
 		global $db;
 
@@ -255,7 +258,7 @@ class shippingController extends expController {
 		$db->insertObject($obj, $this->params['table']);
 		redirect_to(array('controller'=>'shipping', 'action'=>'configure', 'id'=>$this->params['shippingcalculator_id']));
 	}
-	
+
 	public function deleteSpeed() {
 		global $db;
 

programming_language: PHP
filename: storeCategoryController.php
change_type: ModificationType.MODIFY
diff: @@ -22,18 +22,11 @@
  */
 
 class storeCategoryController extends expNestedNodeController {
-    static function displayname() {
-        return gt("e-Commerce Category Manager");
-    }
-
-    static function description() {
-        return gt("This module is for managing categories in your store.");
-    }
-
-    protected $add_permissions = array(
+    protected $manage_permissions = array(
+//        'import' => 'Import Category',
+//        'importCategory' => 'Import Category',
         'fix_categories' => 'to run this action.'
     );
-
     // hide the configs we don't need
     public $remove_configs = array(
         'aggregation',
@@ -49,6 +42,14 @@ class storeCategoryController extends expNestedNodeController {
         'twitter',
     ); // all options: ('aggregation','categories','comments','ealerts','facebook','files','module_title','pagination','rss','tags','twitter',)
 
+    static function displayname() {
+        return gt("e-Commerce Category Manager");
+    }
+
+    static function description() {
+        return gt("This module is for managing categories in your store.");
+    }
+
     static function canImportData() {
         return true;
     }
@@ -190,18 +191,18 @@ class storeCategoryController extends expNestedNodeController {
         expHistory::set('viewable', $this->params);
         //         $category = new storeCategory();
         //         $categories = $category->getFullTree();
-        //         
+        //
         //         // foreach($categories as $i=>$val){
         //         //  if (!empty($this->values) && in_array($val->id,$this->values)) {
         //         //      $this->tags[$i]->value = true;
         //         //  } else {
         //         //      $this->tags[$i]->value = false;
         //         //  }
-        //         //  $this->tags[$i]->draggable = $this->draggable; 
-        //         //  $this->tags[$i]->checkable = $this->checkable; 
+        //         //  $this->tags[$i]->draggable = $this->draggable;
+        //         //  $this->tags[$i]->checkable = $this->checkable;
         //         // }
         //
-        // $obj = json_encode($categories);  
+        // $obj = json_encode($categories);
     }
 
     public function update() {
@@ -405,7 +406,7 @@ class storeCategoryController extends expNestedNodeController {
         // and adds the lft and rgt extents correctly for a nested set
 
         /*function nestify($categories) {
-            // Trees mapped            
+            // Trees mapped
             $trees = array();
             $trackParents = array();
             $depth=0;
@@ -439,10 +440,10 @@ class storeCategoryController extends expNestedNodeController {
                         $counter++;
                         $l--;
                     }
-                    
+
                     $categories[$key]['lft'] = $counter;
                     //???$counter++;
-                }        
+                }
                 $prevDepth=$val['depth'];
             }
 
@@ -497,7 +498,7 @@ class storeCategoryController extends expNestedNodeController {
         // eDebug(toHierarchy(nestify(flattenArray($TheTree))),1);
 
         /*$flat_fixed_cats = nestify(flattenArray($TheTree));
-                
+
         foreach ($flat_fixed_cats as $k=>$v) {
             $cat = new storeCategory($v['id']);
             $cat->lft = $v['lft'];
@@ -508,13 +509,13 @@ class storeCategoryController extends expNestedNodeController {
           */
         //-Show Array Structure--//
         // print_r($TheTree);
-        // 
-        // 
+        //
+        //
         // //--Print the Categories, and send their children to DrawBranch--//
         // //--The code below allows you to keep track of what category you're currently drawing--//
-        // 
+        //
         // printf("<ul>");
-        // 
+        //
         // foreach($TheTree as $MyNode) {
         //     printf("<li>{$MyNode['Name']}</li>");
         //     if(is_array($MyNode["Children"]) && !empty($MyNode["Children"])) {
@@ -523,17 +524,17 @@ class storeCategoryController extends expNestedNodeController {
         // }
         // printf("</ul>");
         // //--Recursive printer, should draw a child, and any of its children--//
-        // 
+        //
         // function DrawBranch($Node){
         //     printf("<ul>");
-        // 
+        //
         //     foreach($Node as $Entity) {
         //         printf("<li>{$Entity['Name']}</li>");
-        // 
+        //
         //         if(is_array($Entity["Children"]) && !empty($Entity["Children"])) {
         //             DrawBranch($Entity["Children"]);
         //         }
-        // 
+        //
         //         printf("</ul>");
         //     }
         // }

programming_language: PHP
filename: storeController.php
change_type: ModificationType.MODIFY
diff: @@ -24,7 +24,6 @@
 
 class storeController extends expController {
     public $basemodel_name = 'product';
-
     public $useractions = array(
         'showall'                         => 'Products - All Products and Categories',
         'showallFeaturedProducts'         => 'Products - Only Featured',
@@ -40,7 +39,30 @@ class storeController extends expController {
         'quicklinks'                      => 'Links - User Links',
         'showGiftCards'                   => 'Gift Cards UI',
     );
-
+    protected $manage_permissions = array(
+        'batch_process'               => 'Batch capture order transactions',
+        'cleanNonUnicodeProducts'     => 'Clean all non-unicode charset products',
+        'copyProduct'                 => "Copy Product",
+//        'delete_children'             => "Delete Children",
+        'reimport'                    => 'ReImport Products',
+        'findDupes'                   => 'Fix Duplicate SEF Names',
+//        'manage_sales_reps'           => 'Manage Sales Reps',
+//        'import_external_addresses'   => 'Import addresses from other sources',
+        'showallImpropercategorized'  => 'View products in top level categories that should not be',
+        'showallUncategorized'        => 'View all uncategorized products',
+        'nonUnicodeProducts'          => 'View all non-unicode charset products',
+        'process_orders'              => 'Batch capture order transactions',
+        'processModelAliases'         => 'Process uploaded model aliases',
+        'saveModelAliases'            => 'Save uploaded model aliases',
+//        'deleteProcessedModelAliases' => 'Delete processed uploaded model aliases',
+//        'delete_model_alias'          => 'Process model aliases',
+//        'update_model_alias'          => 'Save model aliases',
+//        'edit_model_alias'            => 'Delete model aliases',
+//        'import'                      => 'Import Products',
+//        'importProduct'               => 'Import Products',
+//        'export'                      => 'Export Products',
+        'uploadModelAliases'          => 'Upload model aliases',
+    );
     // hide the configs we don't need
     public $remove_configs = array(
         'aggregation',
@@ -54,31 +76,6 @@ class storeController extends expController {
         'twitter',
     );  // all options: ('aggregation','categories','comments','ealerts','facebook','files','module_title','pagination','rss','tags','twitter',)
 
-    //protected $permissions = array_merge(array("test"=>'Test'), array('copyProduct'=>"Copy Product"));
-    protected $add_permissions = array(
-        'copyProduct'                 => "Copy Product",
-        'delete_children'             => "Delete Children",
-        'reimport'                    => 'ReImport Products',
-        'findDupes'                   => 'Fix Duplicate SEF Names',
-        'manage_sales_reps'           => 'Manage Sales Reps',
-        'batch_process'               => 'Batch capture order transactions',
-        'process_orders'              => 'Batch capture order transactions',
-        'import_external_addresses'   => 'Import addresses from other sources',
-        'showallImpropercategorized'  => 'View products in top level categories that should not be',
-        'showallUncategorized'        => 'View all uncategorized products',
-        'nonUnicodeProducts'          => 'View all non-unicode charset products',
-        'cleanNonUnicodeProducts'     => 'Clean all non-unicode charset products',
-        'uploadModelAliases'          => 'Upload model aliases',
-        'processModelAliases'         => 'Process uploaded model aliases',
-        'saveModelAliases'            => 'Save uploaded model aliases',
-        'deleteProcessedModelAliases' => 'Delete processed uploaded model aliases',
-        'delete_model_alias'          => 'Process model aliases',
-        'update_model_alias'          => 'Save model aliases',
-        'edit_model_alias'            => 'Delete model aliases',
-        'import'                      => 'Import Products',
-        'export'                      => 'Export Products',
-    );
-
     static function displayname() {
         return gt("e-Commerce Store Front");
     }
@@ -508,13 +505,13 @@ class storeController extends expController {
 
         /*if(isset($router->params['action']))
         {
-            $ancestors = $this->category->pathToNode();       
+            $ancestors = $this->category->pathToNode();
         }else if(isset($router->params['section']))
         {
             $current = $db->selectObject('section',' id= '.$router->params['section']);
             $ancestors[] = $current;
             if( $current->parent != -1 || $current->parent != 0 )
-            {                   
+            {
                 while ($db->selectObject('section',' id= '.$router->params['section']);)
                     if ($section->id == $id) {
                         $current = $section;
@@ -523,7 +520,7 @@ class storeController extends expController {
                 }
             }
             eDebug($sections);
-            $ancestors = $this->category->pathToNode();       
+            $ancestors = $this->category->pathToNode();
         }*/
 
         $ancestors = $this->category->pathToNode();
@@ -1274,7 +1271,7 @@ class storeController extends expController {
                     }
                 }
             }
-            //eDebug($editable_options[$group->title]);        
+            //eDebug($editable_options[$group->title]);
         }
         //die();
 
@@ -1496,7 +1493,7 @@ class storeController extends expController {
         if (empty($this->params['id'])) return false;
         $product_type = $db->selectValue('product', 'product_type', 'id=' . $this->params['id']);
         $product = new $product_type($this->params['id'], true, false);
-        //eDebug($product_type);  
+        //eDebug($product_type);
         //eDebug($product, true);
         //if (!empty($product->product_type_id)) {
         //$db->delete($product_type, 'id='.$product->product_id);
@@ -1635,18 +1632,18 @@ class storeController extends expController {
     public function deleteChildren() {
         //eDebug($data[0],true);
         //if($id!=null) $this->params['id'] = $id;
-        //eDebug($this->params,true);        
+        //eDebug($this->params,true);
         $product = new product($this->params['id']);
         //$product = $product->find("first", "previous_id =" . $previous_id);
         //eDebug($product, true);
-        if (empty($product->id)) // || empty($product->previous_id)) 
+        if (empty($product->id)) // || empty($product->previous_id))
         {
             flash('error', gt('There was an error deleting the child products.'));
             expHistory::back();
         }
         $childrenToDelete = $product->find('all', 'parent_id=' . $product->id);
         foreach ($childrenToDelete as $ctd) {
-            //fwrite($lfh, "Deleting:" . $ctd->id . "\n");                             
+            //fwrite($lfh, "Deleting:" . $ctd->id . "\n");
             $ctd->delete();
         }
     }
@@ -1822,7 +1819,7 @@ class storeController extends expController {
         if (!$user->isAdmin()) $sql .= '(p.active_type=0 OR p.active_type=1) AND ';
         $sql .= " match (p.title,p.model,p.body) against ('" . $this->params['query'] . "*' IN BOOLEAN MODE) AND p.parent_id=0 ";
         $sql .= " HAVING relevance > 0 ";
-        //$sql .= "GROUP BY p.id "; 
+        //$sql .= "GROUP BY p.id ";
         $sql .= "order by modelmatch,titlematch,relevance desc LIMIT 10";
 
         eDebug($sql);
@@ -1851,32 +1848,32 @@ class storeController extends expController {
         */
         /*echo "Here?";
         $inv = 30234;
-        $req = 'a29f9shsgh32hsf80s7';        
+        $req = 'a29f9shsgh32hsf80s7';
         $amt = 101.00;
         for($count=1;$count<=25;$count+=2)
-        {   
+        {
             $data[2] = $inv + $count;
             $amt += $count*$count;
-            $successSet[$count]['message'] = "Sucessfully imported row " . $count . ", order: " . $data[2] . "<br/>";                
+            $successSet[$count]['message'] = "Sucessfully imported row " . $count . ", order: " . $data[2] . "<br/>";
             $successSet[$count]['order_id'] = $data[2];
             $successSet[$count]['amount'] = $amt;
             $successSet[$count]['request_id'] = $req;
             $successSet[$count]['reference_id'] = $req;
             $successSet[$count]['authorization_code'] = $req;
-            $successSet[$count]['shipping_tracking_number'] = '1ZNF453937547';    
+            $successSet[$count]['shipping_tracking_number'] = '1ZNF453937547';
             $successSet[$count]['carrier'] = 'UPS';
         }
         for($count=2;$count<=25;$count+=2)
-        {   
-            $data[2] = $inv + $count;                
-            $amt += $count*$count;        
+        {
+            $data[2] = $inv + $count;
+            $amt += $count*$count;
             $errorSet[$count]['error_code'] = '42';
             $errorSet[$count]['message'] = "No go for some odd reason. Try again.";
             $errorSet[$count]['order_id'] = $data[2];
             $errorSet[$count]['amount'] = $amt;
         }
-        
-        assign_to_template(array('errorSet'=>$errorSet, 'successSet'=>$successSet));     
+
+        assign_to_template(array('errorSet'=>$errorSet, 'successSet'=>$successSet));
         return;*/
 
         ###########
@@ -1885,7 +1882,7 @@ class storeController extends expController {
         $template = expTemplate::get_template_for_action(new orderController(), 'setStatus', $this->loc);
 
         //eDebug($_FILES);
-        //eDebug($this->params,true); 
+        //eDebug($this->params,true);
         set_time_limit(0);
         //$file = new expFile($this->params['expFile']['batch_process_upload'][0]);
         if (!empty($_FILES['batch_upload_file']['error'])) {
@@ -1925,7 +1922,7 @@ class storeController extends expController {
 
         // read in the header line
         $data = fgetcsv($handle, 10000, ",");
-        //eDebug($data);      
+        //eDebug($data);
 //        $dataset = array();
         $carrier = '';
         if (trim($data[0]) == 'ShipmentInformationShipmentID') {
@@ -2000,8 +1997,8 @@ class storeController extends expController {
                     $result = $calc->delayed_capture($bm, $order->grand_total, $order);
                     if ($result->errorCode == 0) {
                         //we've succeeded.  transaction already created and billing info updated.
-                        //just need to set the order shipping info, check and see if we send user an email, and set statuses.  
-                        //shipping info:                                      
+                        //just need to set the order shipping info, check and see if we send user an email, and set statuses.
+                        //shipping info:
                         $successSet[$count]['order_id'] = $data[2];
                         $successSet[$count]['message'] = "Sucessfully captured order " . $data[2] . " and set shipping information.";
                         $successSet[$count]['amount'] = $order->grand_total;
@@ -2013,7 +2010,7 @@ class storeController extends expController {
                     } else {
                         //failed capture, so we report the error but still set the shipping information
                         //because it's already out the door
-                        //$failMessage = "Attempted to delay capture order " . $data[2] . " and it failed with the following error: " . $result->errorCode . " - " .$result->message;   
+                        //$failMessage = "Attempted to delay capture order " . $data[2] . " and it failed with the following error: " . $result->errorCode . " - " .$result->message;
                         //if the user seelected to set a different status for failed orders, set it here.
                         /*if(isset($this->params['order_status_fail'][0]) && $this->params['order_status_fail'][0] > -1)
                         {
@@ -2024,10 +2021,10 @@ class storeController extends expController {
                             $change->to_status_id = $this->params['order_status_fail'][0];
                             $change->orders_id = $order->id;
                             $change->save();
-                            
+
                             // update the status of the order
                             $order->order_status_id = $this->params['order_status_fail'][0];
-                            $order->save();                             
+                            $order->save();
                         }*/
                         $errorSet[$count]['error_code'] = $result->errorCode;
                         $errorSet[$count]['message'] = "Capture failed: " . $result->message . "<br/>Setting shipping information.";
@@ -2035,11 +2032,11 @@ class storeController extends expController {
                         $errorSet[$count]['amount'] = $order->grand_total;
                         $errorSet[$count]['shipping_tracking_number'] = $data[0];
                         $errorSet[$count]['carrier'] = $carrier;
-                        //continue;   
+                        //continue;
                     }
                 } else {
-                    //dont suppose we do anything here, as it may be set to approved manually 
-                    //$errorSet[$count] = "Order " . $data[2] . " does not use a billing method with delayed capture ability.";  
+                    //dont suppose we do anything here, as it may be set to approved manually
+                    //$errorSet[$count] = "Order " . $data[2] . " does not use a billing method with delayed capture ability.";
                     $successSet[$count]['message'] = 'No capture processing available for order:' . $data[2] . '. Setting shipping information.';
                     $successSet[$count]['order_id'] = $data[2];
                     $successSet[$count]['amount'] = $order->grand_total;
@@ -2126,7 +2123,7 @@ class storeController extends expController {
                 }
             }
 
-            //eDebug($product);        
+            //eDebug($product);
         }
         fclose($handle);
         ini_set('auto_detect_line_endings',$line_end);
@@ -2231,7 +2228,7 @@ class storeController extends expController {
 
         // read in the header line and discard it
         $data = fgetcsv($handle, 10000, ",");
-        //eDebug($data);      
+        //eDebug($data);
 //        $dataset = array();
 
         //mc=1, nt=2, amm=3

programming_language: PHP
filename: taxController.php
change_type: ModificationType.MODIFY
diff: @@ -24,13 +24,6 @@
 class taxController extends expController {
     public $basemodel_name = 'taxclass';
 
-    protected $add_permissions = array(
-        'manage_zones' => 'Manages Zones',
-        'edit_zone'    => 'Add/Edit Zone',
-        'update_zone'  => 'Update Zone',
-        'delete_zone'  => 'Delete Zone'
-    );
-
     static function displayname() {
         return gt("e-Commerce Tax Class Manager");
     }

programming_language: PHP
filename: donation.php
change_type: ModificationType.MODIFY
diff: @@ -65,10 +65,10 @@ class donation extends product {
 
         $sql = "product_type='donation'";
         if (!empty($where)) $sql .= $where;
-        $sql .= empty($order) ? '' : ' ORDER BY ' . $order;
+        $sql .= empty($order) ? '' : ' ORDER BY ' . expString::escape($order);
 
         if (strcasecmp($range, 'all') == 0) {
-            $sql .= empty($limit) ? '' : ' LIMIT ' . $limitstart . ',' . $limit;
+            $sql .= empty($limit) ? '' : ' LIMIT ' . intval($limitstart) . ',' . intval($limit);
             return $db->selectExpObjects($this->tablename, $sql, $this->classname);
         } elseif (strcasecmp($range, 'first') == 0) {
             $sql .= ' LIMIT 0,1';

programming_language: PHP
filename: eventController.php
change_type: ModificationType.MODIFY
diff: @@ -1,1773 +1,1774 @@
-<?php
-
-##################################################
-#
-# Copyright (c) 2004-2016 OIC Group, Inc.
-#
-# This file is part of Exponent
-#
-# Exponent is free software; you can redistribute
-# it and/or modify it under the terms of the GNU
-# General Public License as published by the Free
-# Software Foundation; either version 2 of the
-# License, or (at your option) any later version.
-#
-# GPL: http://www.gnu.org/licenses/gpl.txt
-#
-##################################################
-
-/**
- * @subpackage Controllers
- * @package    Modules
- */
-
-class eventController extends expController {
-//    public $basemodel_name = 'event';
-    public $useractions = array(
-        'showall' => 'Show Calendar',
-    );
-//    public $codequality = 'beta';
-
-    public $remove_configs = array(
-        'comments',
-        'ealerts',
-//        'facebook',
-        'files',
-        'pagination',
-        'rss',
-//        'twitter',
-    );  // all options: ('aggregation','categories','comments','ealerts','facebook','files','pagination','rss','tags','twitter',)
-
-    static function displayname() {
-        return "Events";
-    }
-
-    static function description() {
-        return "Manage events and schedules, and optionally publish them.";
-    }
-
-    static function author() {
-        return "Dave Leffler";
-    }
-
-    static function isSearchable() {
-        return true;
-    }
-
-    function searchName() {
-        return gt("Calendar Event");
-    }
-
-    function searchCategory() {
-        return gt('Event');
-    }
-
-    /**
-     * can this module import data?
-     *
-     * @return bool
-     */
-    public static function canImportData() {
-        return true;
-    }
-
-    function showall() {
-        global $user;
-
-        expHistory::set('viewable', $this->params);
-        $locsql = $this->aggregateWhereClause();
-        $time = (isset($this->params['time']) ? $this->params['time'] : time());
-        assign_to_template(array(
-            'time' => $time,
-            'daynames' => event::dayNames(),
-        ));
-
-        $regcolor = !empty($this->config['registrations_color']) ? $this->config['registrations_color'] : null;
-
-        $ed = new eventdate();
-        $viewtype = 'default';
-        $viewrange = 'all';
-        $view = !empty($this->params['view']) ? $this->params['view'] : 'showall';
-        switch ($view) {
-            case 'showall_Administration':
-                $viewtype = "administration";
-                break;
-            case 'showall_Past Events':
-                $viewrange = "past";
-                break;
-            case 'showall_Monthly Summary':
-            case 'showall_Mini-Calendar':
-            case 'minical':
-                $viewtype = "minical";
-                break;
-            case 'showall_Monthly List':
-            case 'showall_List':
-            case 'monthlist':
-                $viewtype = "byday";
-                $viewrange = "month";
-                break;
-            case 'showall_Week':
-            case 'week':
-                $viewtype = "byday";
-                $viewrange = "week";
-                break;
-            case 'showall_Day':
-            case 'day':
-                $viewtype = "byday";
-                $viewrange = "day";
-                break;
-            case 'showall_announcement':
-            case 'showall_Upcoming Events':
-            case 'showall_Upcoming Events - Headlines':
-                $viewrange = "upcoming";
-                break;
-            case 'showall':
-            case 'month':
-                $viewtype = "monthly";
-                break;
-            default :
-                $view_params = explode('_',$view);
-                if (!empty($view_params[1])) $viewtype = $view_params[1];
-                if (!empty($view_params[2])) $viewrange = $view_params[2];
-        }  // end switch $view
-
-        switch ($viewtype) {
-            case "minical":
-                $monthly = expDateTime::monthlyDaysTimestamp($time);
-                $info = getdate($time);
-                $timefirst = mktime(0, 0, 0, $info['mon'], 1, $info['year']);
-                $now = getdate(time());
-                $currentday = $now['mday'];
-                $endofmonth = date('t', $time);
-                foreach ($monthly as $weekNum => $week) {
-                    foreach ($week as $dayNum => $day) {
-                        if ($dayNum == $now['mday']) {
-                            $currentweek = $weekNum;
-                        }
-                        if ($dayNum <= $endofmonth) {
-//                            $monthly[$weekNum][$dayNum]['number'] = ($monthly[$weekNum][$dayNum]['ts'] != -1) ? $db->countObjects("eventdate", $locsql . " AND date >= " . expDateTime::startOfDayTimestamp($day['ts']) . " AND date <= " . expDateTime::endOfDayTimestamp($day['ts'])) : -1;
-                            $monthly[$weekNum][$dayNum]['number'] = ($monthly[$weekNum][$dayNum]['ts'] != -1) ? $ed->find("count", $locsql . " AND date >= " . expDateTime::startOfDayTimestamp($day['ts']) . " AND date <= " . expDateTime::endOfDayTimestamp($day['ts'])) : -1;
-                        }
-                    }
-                }
-                $prevmonth = mktime(0, 0, 0, date("m", $timefirst) - 1, date("d", $timefirst) + 10, date("Y", $timefirst));
-                $nextmonth = mktime(0, 0, 0, date("m", $timefirst) + 1, date("d", $timefirst) + 10, date("Y", $timefirst));
-                assign_to_template(array(
-                    "monthly"     => $monthly,
-                    "currentweek" => $currentweek,
-                    "currentday"  => $currentday,
-                    "now"         => $timefirst,
-                    "prevmonth"   => $prevmonth,
-                    "thismonth"   => $timefirst,
-                    "nextmonth"   => $nextmonth,
-                ));
-                break;  // end switch $viewtype minicalendar
-            case "byday":  //note aggregates events by groups of days
-                // Remember this is the code for weekly view and monthly listview
-                // Test your fixes on both views
-                //   		$startperiod = 0;
-                //			$totaldays = 0;
-                switch ($viewrange) {
-                    case "day":
-                        $startperiod = expDateTime::startOfDayTimestamp($time);
-                        $totaldays = 1;
-                        $next = expDateTime::endOfDayTimestamp($startperiod);
-                        if (!empty($this->config['starttype'])) $startperiod = $time;
-                        $this->params['time'] = $time;
-                        assign_to_template(array(
-                            "prev_timestamp3" => strtotime('-3 days', $startperiod),
-                            "prev_timestamp2" => strtotime('-2 days', $startperiod),
-                            "prev_timestamp"  => strtotime('-1 days', $startperiod),
-                            "next_timestamp"  => strtotime('+1 days', $startperiod),
-                            "next_timestamp2" => strtotime('+2 days', $startperiod),
-                            "next_timestamp3" => strtotime('+3 days', $startperiod),
-                            'params'      => $this->params
-                        ));
-                        break;
-                    case "week":
-                        $startperiod = expDateTime::startOfWeekTimestamp($time);
-                        $totaldays = 7;
-                        $next = strtotime('+7 days', $startperiod);
-//                        $next = expDateTime::endOfWeekTimestamp($startperiod);
-                        if (!empty($this->config['starttype'])) $startperiod = $time;
-                        $this->params['time'] = $time;
-                        assign_to_template(array(
-                            "prev_timestamp3" => strtotime('-21 days', $startperiod),
-                            "prev_timestamp2" => strtotime('-14 days', $startperiod),
-                            "prev_timestamp"  => strtotime('-7 days', $startperiod),
-                            "next_timestamp"  => $next,
-                            "next_timestamp2" => strtotime('+14 days', $startperiod),
-                            "next_timestamp3" => strtotime('+21 days', $startperiod),
-                            'params'      => $this->params
-                        ));
-                        break;
-                    case "twoweek":
-                        $startperiod = expDateTime::startOfWeekTimestamp($time);
-                        $totaldays = 14;
-                        $next = strtotime('+14 days', $startperiod);
-                        if (!empty($this->config['starttype'])) $startperiod = $time;
-                        assign_to_template(array(
-                            "prev_timestamp3" => strtotime('-42 days', $startperiod),
-                            "prev_timestamp2" => strtotime('-28 days', $startperiod),
-                            "prev_timestamp"  => strtotime('-14 days', $startperiod),
-                            "next_timestamp"  => $next,
-                            "next_timestamp2" => strtotime('+28 days', $startperiod),
-                            "next_timestamp3" => strtotime('+42 days', $startperiod),
-                        ));
-                        break;
-                    case "month":
-                    default: // range = month
-                        $startperiod = expDateTime::startOfMonthTimestamp($time);
-                        $totaldays = date('t', $time);
-                        $next = strtotime('+1 months', $startperiod);
-//                        $next = expDateTime::endOfMonthTimestamp($startperiod);
-                        $this->params['time'] = $time;
-                        assign_to_template(array(
-                            "prev_timestamp3" => strtotime('-3 months', $startperiod),
-                            "prev_timestamp2" => strtotime('-2 months', $startperiod),
-                            "prev_timestamp"  => strtotime('-1 months', $startperiod),
-                            "next_timestamp"  => $next,
-                            "next_timestamp2" => strtotime('+2 months', $startperiod),
-                            "next_timestamp3" => strtotime('+3 months', $startperiod),
-                            'params'      => $this->params
-                        ));
-                        break;
-                }  // end switch $viewrange
-
-                //                $days = array();
-                // added per Ignacio
-                //			$endofmonth = date('t', $time);
-                $extitems = $this->getExternalEvents($startperiod, $next);
-                if (!empty($this->config['aggregate_registrations'])) 
-                    $regitems = eventregistrationController::getRegEventsForDates($startperiod, $next, $regcolor);
-                for ($i = 1; $i <= $totaldays; $i++) {
-                    //                    $info = getdate($time);
-                    //                    switch ($viewrange) {
-                    //                        case "week":
-                    //                            $start = mktime(0,0,0,$info['mon'],$i,$info['year']);  //FIXME this can't be right?
-                    //                            break;
-                    //                        case "twoweek":
-                    ////                            $start = mktime(0,0,0,$info['mon'],$info['mday']+($i-1),$info['year']);  //FIXME this can't be right?
-                    //                  		    $start = $startperiod + ($i*86400);
-                    //                            break;
-                    //                        default:  // range = month
-                    //                            $start = mktime(0,0,0,$info['mon'],$i,$info['year']);
-                    //                    }
-                    $start = expDateTime::startOfDayTimestamp($startperiod + ($i * 86400) - 86400);
-                    $edates = $ed->find("all", $locsql . " AND date >= " . expDateTime::startOfDayTimestamp($start) . " AND date <= " . expDateTime::endOfDayTimestamp($start));
-//                    $days[$start] = $this->getEventsForDates($edates, true, isset($this->config['only_featured']) ? true : false);
-                    $days[$start] = $this->event->getEventsForDates($edates, true, isset($this->config['only_featured']) ? true : false);
-                    //                    for ($j = 0; $j < count($days[$start]); $j++) {
-                    //                        $thisloc = expCore::makeLocation($this->loc->mod,$this->loc->src,$days[$start][$j]->id);
-                    //                        $days[$start][$j]->permissions = array(
-                    //                            "manage"=>(expPermissions::check("manage",$thisloc) || expPermissions::check("manage",$this->loc)),
-                    //                            "edit"=>(expPermissions::check("edit",$thisloc) || expPermissions::check("edit",$this->loc)),
-                    //                            "delete"=>(expPermissions::check("delete",$thisloc) || expPermissions::check("delete",$this->loc))
-                    //                        );
-                    //                    }
-                    if (!empty($extitems[$start]))
-                        $days[$start] = array_merge($extitems[$start], $days[$start]);
-                    if (!empty($regitems[$start]))
-                        $days[$start] = array_merge($regitems[$start], $days[$start]);
-                    $days[$start] = expSorter::sort(array('array' => $days[$start], 'sortby' => 'eventstart', 'order' => 'ASC'));
-                }
-                assign_to_template(array(
-                    "time" => $startperiod,
-                    'days' => $days,
-                    "now"  => $startperiod,
-                ));
-                break;  // end switch $viewtype byday
-            case "monthly":  //note this is a simply array of events for the requested month
-                // build a month array of weeks with an array of days
-                //                $monthly = array();
-                //                $counts = array();
-                $info = getdate($time);
-                $nowinfo = getdate(time());
-                if ($info['mon'] != $nowinfo['mon']) $nowinfo['mday'] = -10;
-                // Grab non-day numbers only (before end of month)
-//                $week = 0;
-                $currentweek = -1;
-                $timefirst = mktime(0, 0, 0, $info['mon'], 1, $info['year']);
-                $week = (int)date('W',$timefirst);
-                if ($week >= 52 && $info['mon'] == 1) $week = 1;
-                $infofirst = getdate($timefirst);
-                $monthly[$week] = array(); // initialize for non days
-                $counts[$week] = array();
-                if (($infofirst['wday'] == 0) && (DISPLAY_START_OF_WEEK == 1)) {
-                    for ($i = -6; $i < (1 - DISPLAY_START_OF_WEEK); $i++) {
-                        $monthly[$week][$i] = array();
-                        $counts[$week][$i] = -1;
-                    }
-                    $weekday = $infofirst['wday'] + 7; // day number in grid.  if 7+, switch weeks
-                } else {
-                    for ($i = 1 - $infofirst['wday']; $i < (1 - DISPLAY_START_OF_WEEK); $i++) {
-                        $monthly[$week][$i] = array();
-                        $counts[$week][$i] = -1;
-                    }
-                    $weekday = $infofirst['wday']; // day number in grid.  if 7+, switch weeks
-                }
-                // Grab day counts
-                $endofmonth = date('t', $time);
-                $extitems = $this->getExternalEvents($timefirst, expDateTime::endOfMonthTimestamp($timefirst));
-                if (!empty($this->config['aggregate_registrations'])) 
-                    $regitems = eventregistrationController::getRegEventsForDates($timefirst, expDateTime::endOfMonthTimestamp($timefirst), $regcolor);
-                for ($i = 1; $i <= $endofmonth; $i++) {
-                    $start = mktime(0, 0, 0, $info['mon'], $i, $info['year']);
-                    if ($i == $nowinfo['mday']) $currentweek = $week;
-                    $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfDayTimestamp($start) . " AND date <= " . expDateTime::endOfDayTimestamp($start) . ")");
-//                    $monthly[$week][$i] = $this->getEventsForDates($dates, true, isset($this->config['only_featured']) ? true : false);
-                    $monthly[$week][$i] = $this->event->getEventsForDates($dates, true, isset($this->config['only_featured']) ? true : false);
-                    if (!empty($extitems[$start]))
-                        $monthly[$week][$i] = array_merge($extitems[$start], $monthly[$week][$i]);
-                    if (!empty($regitems[$start]))
-                        $monthly[$week][$i] = array_merge($regitems[$start], $monthly[$week][$i]);
-                    $monthly[$week][$i] = expSorter::sort(array('array' => $monthly[$week][$i], 'sortby' => 'eventstart', 'order' => 'ASC'));
-                    $counts[$week][$i] = count($monthly[$week][$i]);
-                    if ($weekday >= (6 + DISPLAY_START_OF_WEEK)) {
-                        $week++;
-                        $monthly[$week] = array(); // allocate an array for the next week
-                        $counts[$week] = array();
-                        $weekday = DISPLAY_START_OF_WEEK;
-                    } else $weekday++;
-                }
-                // Grab non-day numbers only (after end of month)
-                for ($i = 1; $weekday && $i < (8 + DISPLAY_START_OF_WEEK - $weekday); $i++) {
-                    $monthly[$week][$i + $endofmonth] = array();
-                    $counts[$week][$i + $endofmonth] = -1;
-                }
-                $this->params['time'] = $time;
-                assign_to_template(array(
-                    "currentweek" => $currentweek,
-                    "monthly"     => $monthly,
-                    "counts"      => $counts,
-                    "prevmonth3"  => strtotime('-3 months', $timefirst),
-                    "prevmonth2"  => strtotime('-2 months', $timefirst),
-                    "prevmonth"   => strtotime('-1 months', $timefirst),
-                    "nextmonth"   => strtotime('+1 months', $timefirst),
-                    "nextmonth2"  => strtotime('+2 months', $timefirst),
-                    "nextmonth3"  => strtotime('+3 months', $timefirst),
-                    "now"         => $timefirst,
-                    "today"       => expDateTime::startOfDayTimestamp(time()),
-                    'params'      => $this->params
-                ));
-                break;  // end switch $viewtype monthly
-            case "administration":  //note a simple list of all upcoming events, except no external nor registration events
-                // Check perms and return if cant view
-                if (!$user) return;
-                $continue = (expPermissions::check("manage", $this->loc) ||
-                    expPermissions::check("create", $this->loc) ||
-                    expPermissions::check("edit", $this->loc) ||
-                    expPermissions::check("delete", $this->loc)
-                ) ? 1 : 0;
-                $dates = $ed->find("all", $locsql . " AND date >= " . expDateTime::startOfDayTimestamp(time()));
-//                $items = $this->getEventsForDates($dates);
-                $items = $this->event->getEventsForDates($dates);
-                //                if (!$continue) {
-                //                    foreach ($items as $i) {
-                //                        $iloc = expCore::makeLocation($this->loc->mod,$this->loc->src,$i->id);
-                //                        if (expPermissions::check("edit",$iloc) ||
-                //                            expPermissions::check("delete",$iloc) ||
-                //                            expPermissions::check("manage",$iloc)
-                //                        ) {
-                //                            $continue = true;
-                //                        }
-                //                    }
-                //                }
-                if (!$continue) return;
-                //                for ($i = 0; $i < count($items); $i++) {
-                //                    $thisloc = expCore::makeLocation($this->loc->mod,$this->loc->src,$items[$i]->id);
-                //    //				if ($user && $items[$i]->poster == $user->id) $canviewapproval = 1;
-                //                    $items[$i]->permissions = array(
-                //                        "manage"=>(expPermissions::check("manage",$thisloc) || expPermissions::check("manage",$this->loc)),
-                //                        "edit"=>(expPermissions::check("edit",$thisloc) || expPermissions::check("edit",$this->loc)),
-                //                        "delete"=>(expPermissions::check("delete",$thisloc) || expPermissions::check("delete",$this->loc))
-                //                    );
-                //                }
-                $items = expSorter::sort(array('array' => $items, 'sortby' => 'eventstart', 'order' => 'ASC'));
-                assign_to_template(array(
-                    'items' => $items,
-                ));
-                break;  // end switch $viewtype administration
-            case "default":  //note a simple list of events based on $viewrange
-            default;
-                //                $items = null;
-                //                $dates = null;
-                $day = expDateTime::startOfDayTimestamp(time());
-                $sort_asc = true; // For the getEventsForDates call
-                //                $moreevents = false;
-                switch ($viewrange) {
-                    case "upcoming":  // events in the future
-                        if (!empty($this->config['enable_ical']) && !empty($this->config['rss_limit']) && $this->config['rss_limit'] > 0) {
-                            $eventlimit = " AND date <= " . ($day + ($this->config['rss_limit'] * 86400));
-                        } else {
-                            $eventlimit = "";
-                        }
-                        $dates = $ed->find("all", $locsql . " AND date >= " . $day . $eventlimit . " ORDER BY date ASC ");
-                        $begin = $day;
-                        $end = null;
-                        //					$moreevents = count($dates) < $db->countObjects("eventdate",$locsql." AND date >= $day");
-                        break;
-                    case "past":  // events in the past
-                        $dates = $ed->find("all", $locsql . " AND date < $day ORDER BY date DESC ");
-                        //					$moreevents = count($dates) < $db->countObjects("eventdate",$locsql." AND date < $day");
-                        $sort_asc = false;
-                        $begin = null;
-                        $end = $day;
-                        break;
-                    case "today":  // events occuring today
-                        $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfDayTimestamp($day) . " AND date <= " . expDateTime::endOfDayTimestamp($day) . ")");
-                        $begin = $day;
-                        $end = expDateTime::endOfDayTimestamp($day);
-                        break;
-                    case "day":  // events for a specific day (same as byday day?)
-                        $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfDayTimestamp($time) . " AND date <= " . expDateTime::endOfDayTimestamp($time) . ")");
-                        $begin = expDateTime::startOfDayTimestamp($time);
-                        $end = expDateTime::endOfDayTimestamp($time);
-                        break;
-                    case "next":  // future events
-                        $dates = array($ed->find("all", $locsql . " AND date >= $time"));
-                        $begin = expDateTime::startOfDayTimestamp($time);
-                        $end = null;
-                        break;
-                    case "month": // events for a specific month (same as monthly?)
-//                        $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfMonthTimestamp(time()) . " AND date <= " . expDateTime::endOfMonthTimestamp(time()) . ")");
-                        $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfMonthTimestamp($time) . " AND date <= " . expDateTime::endOfMonthTimestamp($time) . ")");
-                        $begin = expDateTime::startOfMonthTimestamp($time);
-                        $end = expDateTime::endOfMonthTimestamp($time);
-                        break;
-                    case "all":  // all events
-                    default;
-                        $dates = $ed->find("all", $locsql);
-                        $begin = null;
-                        $end = null;
-                }
-//                $items = $this->getEventsForDates($dates, $sort_asc, isset($this->config['only_featured']) ? true : false, true);
-                $items = $this->event->getEventsForDates($dates, $sort_asc, isset($this->config['only_featured']) ? true : false, true);
-                if ($viewrange != 'past') {
-                    $extitems = $this->getExternalEvents($begin, $end);
-                    // we need to flatten these down to simple array of events
-                    $extitem = array();
-                    foreach ($extitems as $days) {
-                        foreach ($days as $event) {
-                            if (empty($event->eventdate->date) || ($viewrange == 'upcoming' && $event->eventdate->date < time()))
-                                break;
-                            if (empty($event->eventstart))
-                                $event->eventstart = $event->eventdate->date;
-                            $extitem[] = $event;
-                        }
-                    }
-                    $items = array_merge($items, $extitem);
-                    
-                    if (!empty($this->config['aggregate_registrations']))
-                        $regitems = eventregistrationController::getRegEventsForDates($begin, $end, $regcolor);
-                    // we need to flatten these down to simple array of events
-                    $regitem = array();
-                    if (!empty($regitems)) foreach ($regitems as $days) {
-                        foreach ($days as $value) {
-                            $regitem[] = $value;
-                        }
-                    }
-                    $items = array_merge($items, $regitem);
-
-                    // remove today's events that have already ended
-                    if ($viewtype == 'default' && $viewrange == 'upcoming') {
-                        foreach ($items as $key=>$item) {
-                            if (!$item->is_allday && $item->eventend < time()) {
-                                //fixme we've left events ending earlier in the day, but already cancelled out tomorrow's event
-                                unset($items[$key]);
-                            } else {
-                                break;  // they are chronological so we can end
-                            }
-                        }
-                    }
-                }
-                $items = expSorter::sort(array('array' => $items, 'sortby' => 'eventstart', 'order' => 'ASC'));
-                // Upcoming events can be configured to show a specific number of events.
-                // The previous call gets all events in the future from today
-                // If configured, cut the array to the configured number of events
-                //			if ($template->viewconfig['num_events']) {
-                //				switch ($viewrange) {
-                //					case "upcoming":
-                //					case "past":
-                //						$moreevents = $template->viewconfig['num_events'] < count($items);
-                //						break;
-                //				}
-                //				$items = array_slice($items, 0, $template->viewconfig['num_events']);
-                //			}
-                //                for ($i = 0; $i < count($items); $i++) {
-                //                    $thisloc = expCore::makeLocation($this->loc->mod,$this->loc->src,$items[$i]->id);
-                //                    $items[$i]->permissions = array(
-                //                        'manage'=>(expPermissions::check('manage',$thisloc) || expPermissions::check('manage',$this->loc)),
-                //                        'edit'=>(expPermissions::check('edit',$thisloc) || expPermissions::check('edit',$this->loc)),
-                //                        'delete'=>(expPermissions::check('delete',$thisloc) || expPermissions::check('delete',$this->loc))
-                //                    );
-                //                }
-                assign_to_template(array(
-                    'items' => $items,
-                    "now"   => $day,
-                ));
-        }
-    }
-
-    /**
-     * default view for individual item
-     */
-    function show() {
-        expHistory::set('viewable', $this->params);
-        if (!empty($this->params['date_id'])) {  // specific event instance
-            $eventdate = new eventdate($this->params['date_id']);
-            $eventdate->event = new event($eventdate->event_id);
-        } else {  // we'll default to the first event of this series
-            $event = new event($this->params['id']);
-            $eventdate = new eventdate($event->eventdate[0]->id);
-        }
-        if (empty($eventdate->id))
-            redirect_to(array('controller'=>'notfound','action'=>'page_not_found','title'=>'event'));
-
-        if (!empty($eventdate->event->feedback_form) && $eventdate->event->feedback_form != 'Disallow Feedback') {
-            assign_to_template(array(
-                'feedback_form' => $eventdate->event->feedback_form,
-            ));
-        }
-
-        assign_to_template(array(
-            'event' => $eventdate,
-        ));
-    }
-
-    function edit() {
-        global $template;
-
-        parent::edit();
-        $allforms = array();
-        $allforms[""] = gt('Disallow Feedback');
-        // calculate which event date is the one being edited
-        $event_key = 0;
-        foreach ($template->tpl->tpl_vars['record']->value->eventdate as $key=>$d) {
-       	    if ($d->id == $this->params['date_id']) $event_key = $key;
-       	}
-
-        assign_to_template(array(
-            'allforms'     => array_merge($allforms, expTemplate::buildNameList("forms", "event/email", "tpl", "[!_]*")),
-            'checked_date' => !empty($this->params['date_id']) ? $this->params['date_id'] : null,
-            'event_key'    => $event_key,
-        ));
-    }
-
-    /**
-     * Delete a recurring event by asking for which event dates to delete
-     *
-     */
-    function delete_recurring() {
-        $item = $this->event->find('first', 'id=' . $this->params['id']);
-        if ($item->is_recurring == 1) { // need to give user options
-            expHistory::set('editable', $this->params);
-            assign_to_template(array(
-                'checked_date' => $this->params['date_id'],
-                'event'        => $item,
-            ));
-        } else { // Process a regular delete
-            $item->delete();
-        }
-    }
-
-    /**
-     * Delete selected event dates for a recurring event and event if all event dates deleted
-     *
-     */
-    function delete_selected() {
-        $item = $this->event->find('first', 'id=' . $this->params['id']);
-        if ($item && $item->is_recurring == 1) {
-            $event_remaining = false;
-            $eventdates = $item->eventdate[0]->find('all', 'event_id=' . $item->id);
-            foreach ($eventdates as $ed) {
-                if (array_key_exists($ed->id, $this->params['dates'])) {
-                    $ed->delete();
-                } else {
-                    $event_remaining = true;
-                }
-            }
-            if (!$event_remaining) {
-                $item->delete(); // model will also ensure we delete all event dates
-            }
-            expHistory::back();
-        } else {
-            notfoundController::handle_not_found();
-        }
-    }
-
-    function delete_all_past() {
-        $locsql = $this->aggregateWhereClause();
-        $ed = new eventdate();
-        $dates = $ed->find("all", $locsql . " AND date < " . strtotime('-1 months', time()));
-        foreach ($dates as $date) {
-            $date->delete(); // event automatically deleted if all assoc eventdates are deleted
-        }
-        expHistory::back();
-    }
-
-    /**
-   	 * get the metainfo for this module
-   	 * @return array
-   	 */
-   	function metainfo() {
-       global $router;
-
-        $action = $router->params['action'];
-        $metainfo = array('title' => '', 'keywords' => '', 'description' => '', 'canonical'=> '', 'noindex' => false, 'nofollow' => false);
-        // look for event date_id which expController::metainfo won't detect
-//        if (!empty($router->params['action']) && $router->params['action'] == 'show' && !isset($router->params['id']) && isset($router->params['date_id'])) {
-        switch ($action) {
-            case 'show':
-                if (!isset($router->params['id']) && isset($router->params['date_id'])) {
-                    // look up the record.
-                    $object = new eventdate((int)$router->params['date_id']);
-                    // set the meta info
-                    if (!empty($object)) {
-                        if (!empty($object->event->body)) {
-                            $desc = str_replace('"',"'",expString::summarize($object->event->body,'html','para'));
-                        } else {
-                            $desc = SITE_DESCRIPTION;
-                        }
-                        if (!empty($object->expTag)) {
-                            $keyw = '';
-                            foreach ($object->expTag as $tag) {
-                                if (!empty($keyw)) $keyw .= ', ';
-                                $keyw .= $tag->title;
-                            }
-                        } else {
-                            $keyw = SITE_KEYWORDS;
-                        }
-                        $metainfo['title'] = empty($object->event->meta_title) ? $object->event->title : $object->event->meta_title;
-                        $metainfo['keywords'] = empty($object->event->meta_keywords) ? $keyw : $object->event->meta_keywords;
-                        $metainfo['description'] = empty($object->event->meta_description) ? $desc : $object->event->meta_description;
-                        $metainfo['canonical'] = empty($object->event->canonical) ? $router->plainPath() : $object->event->canonical;
-                        $metainfo['noindex'] = empty($object->event->meta_noindex) ? false : $object->event->meta_noindex;
-                        $metainfo['nofollow'] = empty($object->event->meta_nofollow) ? false : $object->event->meta_nofollow;
-                        return $metainfo;
-                        break;
-                    }
-                }
-            default:
-                return parent::metainfo();
-        }
-    }
-
-    /**
-     * function to build a string to pull in all events within requested date range
-     */
-    function build_daterange_sql($timestamp, $endtimestamp=null, $field='date', $multiday=false) {
-        if (empty($endtimestamp)) {
-            $date_sql = "((".$field." >= " . expDateTime::startOfDayTimestamp($timestamp) . " AND ".$field." <= " . expDateTime::endOfDayTimestamp($timestamp) . ")";
-        } else {
-            $date_sql = "((".$field." >= " . expDateTime::startOfDayTimestamp($timestamp) . " AND ".$field." <= " . expDateTime::endOfDayTimestamp($endtimestamp) . ")";
-        }
-        if ($multiday)
-            $date_sql .= " OR (" . expDateTime::startOfDayTimestamp($timestamp) . " BETWEEN ".$field." AND dateFinished)";
-        $date_sql .= ")";
-        return $date_sql;
-    }
-
-    function send_feedback() {
-        $success = false;
-        if (isset($this->params['id'])) {
-            $ed = new eventdate($this->params['id']);
-//            $email_addrs = array();
-            if ($ed->event->feedback_email != '') {
-                $msgtemplate = expTemplate::get_template_for_action($this, 'email/_' . $this->params['formname'], $this->loc);
-                $msgtemplate->assign('params', $this->params);
-                $msgtemplate->assign('event', $ed);
-                $email_addrs = explode(',', $ed->event->feedback_email);
-                //This is an easy way to remove duplicates
-                $email_addrs = array_flip(array_flip($email_addrs));
-                $email_addrs = array_map('trim', $email_addrs);
-                $mail = new expMail();
-                $success += $mail->quickSend(array(
-                    "text_message" => $msgtemplate->render(),
-                    'to'           => $email_addrs,
-                    'from'         => !empty($this->params['email']) ? $this->params['email'] : trim(SMTP_FROMADDRESS),
-                    'subject'      => $this->params['subject'],
-                ));
-            }
-        }
-
-        if ($success) {
-            flashAndFlow('message', gt('Your feedback was successfully sent.'));
-        } else {
-            flashAndFlow('error', gt('We could not send your feedback.  Please contact your administrator.'));
-        }
-    }
-
-    function ical() {
-        if (isset($this->params['date_id']) || isset($this->params['title']) || isset($this->params['src'])) {
-            $cfg = new expConfig();
-            $configs = $cfg->find('all', "location_data LIKE '%event%'"); // get all event module configs
-            foreach ($configs as $config) {
-                $loc = expUnserialize($config->location_data);
-                if (!empty($this->params['title'])) {
-                    if ($this->params['title'] == $config->config['feed_sef_url']) {
-                        $this->config = $config->config;
-                        break;
-                    }
-                } elseif (!empty($this->params['src'])) {
-                    if ($this->params['src'] == $loc->src) {
-                        $this->config = $config->config;
-                        break;
-                    }
-                }
-            }
-            $this->loc = $loc;
-
-            if ($this->config['enable_ical']) {
-                $ed = new eventdate();
-                if (isset($this->params['date_id'])) { // get single specific event only
-//                    $dates = array($db->selectObject("eventdate","id=".$this->params['date_id']));
-                    $dates = $ed->find('first', "id=" . $this->params['date_id']);
-                    $Filename = "Event-" . $this->params['date_id'];
-                } else {
-                    $locsql = $this->aggregateWhereClause();
-
-                    $day = expDateTime::startOfDayTimestamp(time());
-                    if (!empty($this->config['enable_ical']) && isset($this->config['rss_limit']) && ($this->config['rss_limit'] > 0)) {
-                        $rsslimit = " AND date <= " . ($day + ($this->config['rss_limit'] * 86400));
-                    } else {
-                        $rsslimit = "";
-                    }
-
-                    if (isset($this->params['time'])) {
-                        $time = $this->params['time']; // get current month's events
-//                        $dates = $db->selectObjects("eventdate",$locsql." AND (date >= ".expDateTime::startOfMonthTimestamp($time)." AND date <= ".expDateTime::endOfMonthTimestamp($time).")");
-                        $dates = $ed->find('all', $locsql . " AND (date >= " . expDateTime::startOfMonthTimestamp($time) . " AND date <= " . expDateTime::endOfMonthTimestamp($time) . ")");
-                    } else {
-                        $time = date('U', strtotime("midnight -1 month", time())); // previous month also
-//                        $dates = $db->selectObjects("eventdate",$locsql." AND date >= ".expDateTime::startOfDayTimestamp($time).$rsslimit);
-                        $dates = $ed->find('all', $locsql . " AND date >= " . expDateTime::startOfDayTimestamp($time) . $rsslimit);
-                    }
-                    //			$title = $db->selectValue('container', 'title', "internal='".serialize($loc)."'");
-                    $title = $this->config['feed_title'];
-                    $Filename = preg_replace('/\s+/', '', $title); // without whitespace
-                }
-
-                if (!function_exists("quoted_printable_encode")) { // function added in php v5.3.0
-                    function quoted_printable_encode($input, $line_max = 75) {
-                        $hex = array('0', '1', '2', '3', '4', '5', '6', '7',
-                            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
-                        $lines = preg_split("/(?:\r\n|\r|\n)/", $input);
-                        $linebreak = "=0D=0A=\r\n";
-                        /* the linebreak also counts as characters in the mime_qp_long_line
-                         * rule of spam-assassin */
-                        $line_max = $line_max - strlen($linebreak);
-                        $escape = "=";
-                        $output = "";
-                        $cur_conv_line = "";
-                        $length = 0;
-                        $whitespace_pos = 0;
-                        $addtl_chars = 0;
-
-                        // iterate lines
-                        for ($j = 0, $jMax = count($lines); $j < $jMax; $j++) {
-                            $line = $lines[$j];
-                            $linlen = strlen($line);
-
-                            // iterate chars
-                            for ($i = 0; $i < $linlen; $i++) {
-                                $c = substr($line, $i, 1);
-                                $dec = ord($c);
-
-                                $length++;
-
-                                if ($dec == 32) {
-                                    // space occurring at end of line, need to encode
-                                    if (($i == ($linlen - 1))) {
-                                        $c = "=20";
-                                        $length += 2;
-                                    }
-
-                                    $addtl_chars = 0;
-                                    $whitespace_pos = $i;
-                                } elseif (($dec == 61) || ($dec < 32) || ($dec > 126)) {
-                                    $h2 = floor($dec / 16);
-                                    $h1 = floor($dec % 16);
-                                    $c = $escape . $hex["$h2"] . $hex["$h1"];
-                                    $length += 2;
-                                    $addtl_chars += 2;
-                                }
-
-                                // length for wordwrap exceeded, get a newline into the text
-                                if ($length >= $line_max) {
-                                    $cur_conv_line .= $c;
-
-                                    // read only up to the whitespace for the current line
-                                    $whitesp_diff = $i - $whitespace_pos + $addtl_chars;
-
-                                    /* the text after the whitespace will have to be read
-                                     * again ( + any additional characters that came into
-                                     * existence as a result of the encoding process after the whitespace)
-                                     *
-                                     * Also, do not start at 0, if there was *no* whitespace in
-                                     * the whole line */
-                                    if (($i + $addtl_chars) > $whitesp_diff) {
-                                        $output .= substr($cur_conv_line, 0, (strlen($cur_conv_line) -
-                                            $whitesp_diff)) . $linebreak;
-                                        $i = $i - $whitesp_diff + $addtl_chars;
-                                    } else {
-                                        $output .= $cur_conv_line . $linebreak;
-                                    }
-
-                                    $cur_conv_line = "";
-                                    $length = 0;
-                                    $whitespace_pos = 0;
-                                } else {
-                                    // length for wordwrap not reached, continue reading
-                                    $cur_conv_line .= $c;
-                                }
-                            } // end of for
-
-                            $length = 0;
-                            $whitespace_pos = 0;
-                            $output .= $cur_conv_line;
-                            $cur_conv_line = "";
-
-                            if ($j <= count($lines) - 1) {
-                                $output .= $linebreak;
-                            }
-                        } // end for
-
-                        return trim($output);
-                    } // end quoted_printable_encode
-                }
-
-                $tz = DISPLAY_DEFAULT_TIMEZONE;
-                $msg = "BEGIN:VCALENDAR\n";
-                $msg .= "VERSION:2.0\n"; // version for iCalendar files vs vCalendar files
-                $msg .= "CALSCALE:GREGORIAN\n";
-                $msg .= "METHOD: PUBLISH\n";
-                $msg .= "PRODID:<-//ExponentCMS//EN>\n";
-                if (isset($this->config['rss_cachetime']) && ($this->config['rss_cachetime'] > 0)) {
-                    $msg .= "X-PUBLISHED-TTL:PT" . $this->config['rss_cachetime'] . "M\n";
-                }
-                $msg .= "X-WR-CALNAME:$Filename\n";
-
-//                $items = $this->getEventsForDates($dates);
-                $items = $this->event->getEventsForDates($dates);
-
-                for ($i = 0, $iMax = count($items); $i < $iMax; $i++) {
-
-                    // Convert events stored in local time to GMT
-                    $eventstart = new DateTime(date('r', $items[$i]->eventstart), new DateTimeZone($tz));
-                    $eventstart->setTimezone(new DateTimeZone('GMT'));
-                    $eventend = new DateTime(date('r', $items[$i]->eventend), new DateTimeZone($tz));
-                    $eventend->setTimezone(new DateTimeZone('GMT'));
-                    if ($items[$i]->is_allday) {
-                        $dtstart = "DTSTART;VALUE=DATE:" . date("Ymd", $items[$i]->eventstart) . "\n";
-                        $dtend = "DTEND;VALUE=DATE:" . date("Ymd", strtotime("midnight +1 day", $items[$i]->eventstart)) . "\n";
-                    } else {
-                        $dtstart = "DTSTART;VALUE=DATE-TIME:" . $eventstart->format("Ymd\THi00") . "Z\n";
-                        if ($items[$i]->eventend) {
-                            $dtend = "DTEND;VALUE=DATE-TIME:" . $eventend->format("Ymd\THi00") . "Z\n";
-                        } else {
-                            $dtend = "DTEND;VALUE=DATE-TIME:" . $eventstart->format("Ymd\THi00") . "Z\n";
-                        }
-                    }
-
-                    $body = trim(strip_tags(str_replace(array("<br />", "<br>", "br/>", "</p>"), "\n", $items[$i]->body)));
-                    if ($items[$i]->is_cancelled) $body = gt('This Event Has Been Cancelled') . ' - ' . $body;
-                    $body = str_replace(array("\r"), "", $body);
-                    $body = str_replace(array("&#160;"), " ", $body);
-                    $body = expString::convertSmartQuotes($body);
-                    if (!isset($this->params['style'])) {
-                        // it's going to Outlook so remove all formatting from body text
-                        $body = quoted_printable_encode($body);
-                    } elseif ($this->params['style'] == "g") {
-                        // It's going to Google (doesn't like quoted-printable, but likes html breaks)
-                        $body = str_replace(array("\n"), "<br />", $body);
-                    } else {
-                        // It's going elsewhere (doesn't like quoted-printable)
-                        $body = str_replace(array("\n"), " -- ", $body);
-                    }
-                    $title = $items[$i]->title;
-
-                    $msg .= "BEGIN:VEVENT\n";
-                    $msg .= $dtstart . $dtend;
-                    $msg .= "UID:" . $items[$i]->date_id . "\n";
-                    $msg .= "DTSTAMP:" . date("Ymd\THis", time()) . "Z\n";
-                    if ($title) {
-                        $msg .= "SUMMARY:$title\n";
-                    }
-                    if ($body) {
-                        $msg .= "DESCRIPTION;ENCODING=QUOTED-PRINTABLE:" . $body . "\n";
-                    }
-                    //	if($link_url) { $msg .= "URL: $link_url\n";}
-                    if (!empty($this->config['usecategories'])) {
-                        if (!empty($items[$i]->expCat[0]->title)) {
-                            $msg .= "CATEGORIES:".$items[$i]->expCat[0]->title."\n";
-                        } else {
-                            $msg .= "CATEGORIES:".$this->config['uncat']."\n";
-                        }
-                    }
-                    $msg .= "END:VEVENT\n";
-                }
-                $msg .= "END:VCALENDAR";
-
-                // Kick it out as a file download
-                ob_end_clean();
-
-                //	$mime_type = (EXPONENT_USER_BROWSER == 'IE' || EXPONENT_USER_BROWSER == 'OPERA') ? 'application/octet-stream;' : "text/x-vCalendar";
-                //	$mime_type = "text/x-vCalendar";
-                $mime_type = 'text/Calendar';
-                header('Content-Type: ' . $mime_type);
-                header('Expires: ' . gmdate('D, d M Y H:i:s') . ' GMT');
-                header('Content-length: ' . strlen($msg));
-                header('Content-Transfer-Encoding: binary');
-                header('Content-Encoding:');
-                //	header("Content-Disposition: inline; filename=".$Filename.".ics");
-                header('Content-Disposition: attachment; filename="' . $Filename . '.ics"');
-                // IE need specific headers
-                //	if (EXPONENT_USER_BROWSER == 'IE') {
-                header('Cache-Control: no-cache, must-revalidate');
-                header('Pragma: public');
-                header('Vary: User-Agent');
-                //	} else {
-                header('Pragma: no-cache');
-                //	}
-                echo $msg;
-                exit();
-            } else {
-                notfoundController::handle_not_found();
-            }
-        } else {
-            notfoundController::handle_not_found();
-        }
-    }
-
-    function send_reminders() {
-        if (isset($this->params['title']) || isset($this->params['src'])) {
-            $cfg = new expConfig();
-            $configs = $cfg->find('all', "location_data LIKE '%event%'"); // get all event module configs
-            foreach ($configs as $config) {
-                $loc = expUnserialize($config->location_data);
-                if (!empty($this->params['title'])) {
-                    if ($this->params['title'] == $config->config['feed_sef_url']) {
-                        $this->config = $config->config;
-                        break;
-                    }
-                } elseif (!empty($this->params['src'])) {
-                    if ($this->params['src'] == $loc->src) {
-                        $this->config = $config->config;
-                        break;
-                    }
-                }
-            }
-
-            if (empty($this->config['reminder_active'])) {
-                notfoundController::handle_not_found();
-                return;
-            }
-            if (!empty($this->config['reminder_code']) && (empty($this->params['code']) || ($this->params['code'] != $this->config['reminder_code']))) {
-                notfoundController::handle_not_authorized();
-                return;
-            }
-
-            $this->loc = $loc;
-            $locsql = $this->aggregateWhereClause();
-
-            $view = (isset($this->params['view']) ? $this->params['view'] : '');
-            if ($view == "") {
-                $view = "send_reminders"; // default reminder view
-            }
-
-//            $template = expTemplate::get_template_for_action($this, $view, $this->loc);
-            global $template;
-
-            $title = $this->config['feed_title'];
-            $template->assign('moduletitle', $title);
-
-            $time = (isset($this->params['time']) ? $this->params['time'] : time());
-            $time = (int)$time;
-
-            $template->assign("time", $time);
-
-            $startperiod = expDateTime::startOfDayTimestamp($time);
-            if (!empty($this->params['days'])) {
-                $totaldays = $this->params['days'];
-            } else {
-                $totaldays = 7; // default 7 days of events
-            }
-
-            $count = 0;
-            $info = getdate($startperiod);
-            for ($i = 0; $i < $totaldays; $i++) {
-                $start = mktime(0, 0, 0, $info['mon'], $info['mday'] + $i, $info['year']);
-                $ed = new eventdate();
-                $edates = $ed->find('all', $locsql . " AND (date >= " . expDateTime::startOfDayTimestamp($start) . " AND date <= " . expDateTime::endOfDayTimestamp($start) . ")");
-                $days[$start] = array();
-//                $days[$start] = $this->getEventsForDates($edates);
-                $days[$start] = $this->event->getEventsForDates($edates);
-                for ($j = 0, $jMax = count($days[$start]); $j < $jMax; $j++) {
-                    $thisloc = expCore::makeLocation($loc->mod, $loc->src, $days[$start][$j]->id);
-                    $days[$start][$j]->permissions = array(
-                        "manage" => (expPermissions::check("manage", $thisloc) || expPermissions::check("manage", $loc)),
-                        "edit"   => (expPermissions::check("edit", $thisloc) || expPermissions::check("edit", $loc)),
-                        "delete" => (expPermissions::check("delete", $thisloc) || expPermissions::check("delete", $loc))
-                    );
-                }
-                $counts[$start] = count($days[$start]);
-                $count += count($days[$start]);
-                $days[$start] = expSorter::sort(array('array' => $days[$start], 'sortby' => 'eventstart', 'order' => 'ASC'));
-            }
-            $template->assign("days", $days);
-            $template->assign("counts", $counts);
-            $template->assign("start", $startperiod);
-            $template->assign("totaldays", $totaldays);
-
-            if ($count == 0) {
-                flash('error',gt('No Events to Send!'));
-                echo show_msg_queue('error');
-                return;
-            }
-
-            if (bs3())
-                $css = file_get_contents(BASE . "external/bootstrap3/css/bootstrap.css");
-            elseif (bs2())
-                $css = file_get_contents(BASE . "external/bootstrap/css/bootstrap.css");
-            else
-                $css = file_get_contents(BASE . "framework/modules/events/assets/css/calendar.css");
-            $template->assign("css", $css);
-            $template->assign("config", $this->config);
-            $template->assign("src", $loc->src);
-
-            // format and send email
-            $subject = $this->config['email_title_reminder'] . " - $title";
-            $from_addr = $this->config['email_address_reminder'];
-            $headers = array(
-                "From"     => $from = $this->config['email_from_reminder'],
-                "Reply-to" => $reply = $this->config['email_reply_reminder']
-            );
-
-            // set up the html message
-            $template->assign("showdetail", !empty($this->config['email_showdetail']));
-            $htmlmsg = $template->render();
-
-            // now the same thing for the text message
-            $msg = preg_replace('/(<script[^>]*>.+?<\/script>|<style[^>]*>.+?<\/style>)/s', '', $htmlmsg); // remove any script or style blocks
-            $msg = trim(strip_tags(str_replace(array("<br />", "<br>", "br/>"), "\n", $msg)));
-
-            // Saved.  do notifs
-            $emails = array();
-            if (!empty($this->config['user_list'])) foreach ($this->config['user_list'] as $c) {
-                $u = user::getUserById($c);
-                $emails[$u->email] = trim(user::getUserAttribution($u->id));
-            }
-            if (!empty($this->config['group_list'])) foreach ($this->config['group_list'] as $c) {
-                $grpusers = group::getUsersInGroup($c);
-                foreach ($grpusers as $u) {
-                    $emails[$u->email] = trim(user::getUserAttribution($u->id));
-                }
-            }
-            if (!empty($this->config['address_list'])) foreach ($this->config['address_list'] as $c) {
-                $emails[] = $c;
-            }
-            if (empty($emails)) {
-                flash('error',gt('No One to Send Reminders to!'));
-                echo show_msg_queue('error');
-                return;
-            }
-
-            $emails = array_flip(array_flip($emails));
-            $emails = array_map('trim', $emails);
-//            $headers = array(
-//                "MIME-Version" => "1.0",
-//                "Content-type" => "text/html; charset=" . LANG_CHARSET
-//            );
-            $mail = new expMail();
-            $mail->quickSend(array(
-//                'headers'      => $headers,
-                'html_message' => $htmlmsg,
-                "text_message" => $msg,
-                'to'           => $emails,
-                'from'         => array(trim($this->config['email_address_reminder']) => $this->config['email_from_reminder']),
-                'subject'      => $subject,
-            ));
-
-            flash('message',gt('The following reminder was sent via email'));
-            echo show_msg_queue();
-//            echo($htmlmsg);
-        } else {
-            flash('error',gt('No Calendar Selected!'));
-            echo show_msg_queue('error');
-        }
-    }
-
-    /** @deprecated moved to event model
-     * @param $edates
-     * @param bool $sort_asc
-     * @param bool $featuredonly
-     * @param bool $condense
-     * @return array
-     */
-    function getEventsForDates($edates, $sort_asc = true, $featuredonly = false, $condense = false) {
-        global $eventid;
-
-        $events = array();
-        $featuresql = "";
-        if ($featuredonly) $featuresql = " AND is_featured=1";
-        foreach ($edates as $edate) {
-            $evs = $this->event->find('all', "id=" . $edate->event_id . $featuresql);
-            foreach ($evs as $key=>$event) {
-                if ($condense) {
-                    $eventid = $event->id;
-                    $multiday_event = array_filter($events, create_function('$event', 'global $eventid; return $event->id === $eventid;'));
-                    if (!empty($multiday_event)) {
-                        unset($evs[$key]);
-                        continue;
-                    }
-                }
-                $evs[$key]->eventstart += $edate->date;
-                $evs[$key]->eventend += $edate->date;
-                $evs[$key]->date_id = $edate->id;
-                if (!empty($event->expCat)) {
-                    $catcolor = empty($event->expCat[0]->color) ? null : trim($event->expCat[0]->color);
-//                    if (substr($catcolor,0,1)=='#') $catcolor = '" style="color:'.$catcolor.';';
-                    $evs[$key]->color = $catcolor;
-                }
-            }
-            if (count($events) < 500) {  // magic number to not crash loop?
-                $events = array_merge($events, $evs);
-            } else {
-//                $evs[$key]->title = gt('Too many events to list').', '.(count($edates)-count($events)).' '.gt('not displayed!');
-//                $events = array_merge($events, $evs);
-                flash('notice',gt('Too many events to list').', '.(count($edates)-count($events)).' '.gt('not displayed!'));
-                break; // keep from breaking system by too much data
-            }
-        }
-        $events = expSorter::sort(array('array' => $events, 'sortby' => 'eventstart', 'order' => $sort_asc ? 'ASC' : 'DESC'));
-        return $events;
-    }
-
-    function getExternalEvents($startdate, $enddate, $multiday = false) {
-        global $db;
-
-        $extevents = array();
-        $dy = 0;  // index of events array
-        if (!empty($this->config['pull_gcal'])) foreach ($this->config['pull_gcal'] as $key=>$extgcalurl) {
-//            $dy = count($extevents);  // index of events array
-            $cache_hit = false;
-            $gcal_cname = str_replace(array("/",":","&","?"),"_",$extgcalurl);
-            $cache_fname = BASE.'tmp/cache/'.$gcal_cname.".cache";
-            if (file_exists($cache_fname)) {
-                $cache = unserialize(file_get_contents($cache_fname));
-                if ($startdate >= $cache['start_date'] || $startdate >= $cache['first_date']) {
-                    $events = $db->selectObjects('event_cache','feed="'.$extgcalurl.'" AND ' . self::build_daterange_sql($startdate,$enddate,'eventdate',true));
-                    foreach ($events as $event) {
-                        if ($multiday) {
-                            $extevents[$event->eventdate][$dy] = $event;
-                            $extevents[$event->eventdate][$dy]->feedkey = $key;
-                            $extevents[$event->eventdate][$dy]->location_data = 'gcalevent' . $key;
-                            $extevents[$event->eventdate][$dy]->color = !empty($this->config['pull_gcal_color'][$key]) ? $this->config['pull_gcal_color'][$key] : null;
-                            if ($event->is_allday) {
-                                $extevents[$event->eventdate][$dy]->eventstart = $event->eventdate;
-                            }
-                            $dy++;
-                        } else {
-                            $endit = !empty($event->dateFinished) ? $event->dateFinished : $event->eventdate;
-//                            for ($i = $startdate; $i < $enddate; $i += 86400) {
-                            for ($i = $event->eventdate; $i <= $endit; $i += 86400) {
-                                if ((!empty($event->dateFinished) && $i > $event->dateFinished) || (empty($event->dateFinished) && $i > $event->eventdate)) {
-                                    break;
-                                } else {
-                                    $extevents[$i][$dy] = clone($event);
-                                    $extevents[$i][$dy]->eventdate = (int)$i;
-                                    $extevents[$i][$dy]->eventstart = ($event->eventstart - $event->eventdate);
-                                    $extevents[$i][$dy]->eventend = ($event->eventend - (!empty($event->dateFinished)?$event->dateFinished:$event->eventdate));
-                                    $extevents[$i][$dy]->eventstart = ($extevents[$i][$dy]->eventstart) + $i;
-                                    $extevents[$i][$dy]->eventend = ($extevents[$i][$dy]->eventend) + $i;
-                                    $extevents[$i][$dy]->feedkey = $key;
-                                    $extevents[$i][$dy]->location_data = 'gcalevent' . $key;
-                                    $extevents[$i][$dy]->color = !empty($this->config['pull_gcal_color'][$key]) ? $this->config['pull_gcal_color'][$key] : null;
-                                    $dy++;
-                                }
-                            }
-                        }
-                    }
-                    $cache_hit = true;
-                }
-            }
-            if (!$cache_hit) { // pull in the external events
-                foreach ($this->get_gcal_events($extgcalurl, $startdate, $enddate, $dy, $key, $multiday) as $date=>$events) {
-                    foreach ($events as $event) {
-                        $extevents[$date][] = $event;
-                    }
-                }
-            }
-        }
-        if (!empty($this->config['pull_ical'])) foreach ($this->config['pull_ical'] as $key=>$exticalurl) {
-//            $dy = count($extevents);  // index of events array
-            $cache_hit = false;
-            $ical_cname = str_replace(array("/",":","&","?"),"_",$exticalurl);
-            $cache_fname = BASE.'tmp/cache/'.$ical_cname.".cache";
-            if (file_exists($cache_fname)) {
-                $cache = unserialize(file_get_contents($cache_fname));
-                if ($startdate >= $cache['start_date'] || $startdate >= $cache['first_date']) {
-                    $events = $db->selectObjects('event_cache','feed="'.$exticalurl.'" AND ' . self::build_daterange_sql($startdate,$enddate,'eventdate',true));
-                    foreach ($events as $event) {
-                        $extevents[$event->eventdate][$dy] = $event;
-                        $extevents[$event->eventdate][$dy]->location_data = 'icalevent' . $key;
-                        $extevents[$event->eventdate][$dy]->color = !empty($this->config['pull_ical_color'][$key]) ? $this->config['pull_ical_color'][$key] : null;
-                        $dy++;
-                    }
-                    $cache_hit = true;
-                }
-            }
-            if (!$cache_hit) {  // pull in the external events
-                foreach ($this->get_ical_events($exticalurl, $startdate, $enddate, $dy, $key, $multiday) as $date=>$events) {
-                    foreach ($events as $event) {
-                        $extevents[$date][] = $event;
-                    }
-                }
-            }
-        }
-        return $extevents;
-    }
-
-    public function get_gcal_events($extgcalurl, $startdate, $enddate=null, &$dy=0, $key=0, $multiday=false) {
-        $extevents = array();
-        if (!empty($startdate)) $begin = date("Y-m-d\Th:i:sP", expDateTime::startOfDayTimestamp($startdate));
-        if (!empty($enddate)) $end = date("Y-m-d\Th:i:sP", expDateTime::endOfDayTimestamp($enddate));
-            else $end = date("Y-m-d\Th:i:sP", (expDateTime::endOfDayTimestamp($startdate + ((3600*24)*30))));
-
-        if (substr($extgcalurl, -5) == 'basic') {
-            $extgcalurl = substr($extgcalurl, 0, - 5) . 'full';
-        }
-        $feed = $extgcalurl . "?orderby=starttime&singleevents=true";
-        if (!empty($startdate)) $feed .= "&start-min=" . $begin;
-        if (!empty($enddate)) $feed .= "&start-max=" . $end;
-
-        // XML method
-//            $s = simplexml_load_file($feed);
-//            foreach ($s->entry as $item) {
-//                $gd = $item->children('http://schemas.google.com/g/2005');
-//                if (!empty($gd->when)) {
-//                   $dtstart = $gd->when->attributes()->startTime;
-//                } elseif (!empty($gd->recurrence)){
-//                   $dtstart = $gd->recurrence->when->attributes()->startTime;
-//                } else {
-//                    $dtstart = $item->attributes()->When;
-//                }
-//                //FIXME must convert $dtstart timezone
-//                $eventdate = expDateTime::startOfDayTimestamp(strtotime($dtstart));
-//                $ourtzoffsets = (int)(date('O',$eventdate)) * 36;
-//                $theirtzoffset = -((int)(substr($dtstart,-5,2)) * 3600);
-//                $tzoffset = $ourtzoffsets - $theirtzoffset;
-//                $extevents[$eventdate][$dy] = new stdClass();
-//                $extevents[$eventdate][$dy]->eventdate = $eventdate;
-//                $extevents[$eventdate][$dy]->eventstart += strtotime($dtstart) + $tzoffset;
-//                if (!empty($gd->when)) {
-//                    $dtend = $gd->when->attributes()->endTime;
-//                } elseif (!empty($gd->recurrence)) {
-//                    $dtend = $gd->recurrence->when->attributes()->endTime;
-//                }
-//                //FIXME must convert $dtend timezone
-//                if (!empty($dtend)) $extevents[$eventdate][$dy]->eventend += strtotime($dtend) + $tzoffset;
-//                // dtstart required, one occurrence, (orig. start date)
-//                $extevents[$eventdate][$dy]->title = $item->title;
-//                $extevents[$eventdate][$dy]->body = $item->content;
-        // End XML method
-
-        // DOM method
-        $doc = new DOMDocument();
-        $doc->load($feed);
-        $entries = $doc->getElementsByTagName("entry");
-        foreach ($entries as $item) {
-            $times = $item->getElementsByTagName("when");
-            $dtstart = $times->item(0)->getAttributeNode("startTime")->value;
-            $eventdate = expDateTime::startOfDayTimestamp(strtotime($dtstart));
-            $extevents[$eventdate][$dy] = new stdClass();
-            $extevents[$eventdate][$dy]->eventdate = $eventdate;
-            $dtend = @$times->item(0)->getAttributeNode("endTime")->value;
-            $ourtzoffsets = (int)date('O',$eventdate) * 36;
-            $theirtzoffset = -((int)substr($dtstart,-5,2) * 3600);
-            $tzoffset = $ourtzoffsets - $theirtzoffset;
-            if (strlen($dtstart) > 10) {
-                $extevents[$eventdate][$dy]->eventstart = ((int)substr($dtstart, 11, 2) * 3600) + ((int)substr($dtstart, 14, 2) * 60) + $tzoffset;
-//                    if (date("I", $eventdate)) $extevents[$eventdate][$dy]->eventstart += 3600;
-                $extevents[$eventdate][$dy]->eventend = ((int)substr($dtend, 11, 2) * 3600) + ((int)substr($dtend, 14, 2) * 60) + $tzoffset;
-//                    if (date("I", $eventdate)) $extevents[$eventdate][$dy]->eventend += 3600;
-            } else {
-                $extevents[$eventdate][$dy]->eventstart = null;
-                $extevents[$eventdate][$dy]->is_allday = 1;
-            }
-            $extevents[$eventdate][$dy]->eventstart += $eventdate;
-            $extevents[$eventdate][$dy]->eventend += $eventdate;
-            if (empty($dtend)) $extevents[$eventdate][$dy]->eventend = $extevents[$eventdate][$dy]->eventstart;
-
-            $titles = $item->getElementsByTagName("title");
-            $extevents[$eventdate][$dy]->title = $titles->item(0)->nodeValue;
-            $contents = $item->getElementsByTagName("content");
-            $extevents[$eventdate][$dy]->body = $contents->item(0)->nodeValue;
-            // End DOM method
-
-//                    $extevents[$eventdate][$dy]->location_data = serialize(expCore::makeLocation('extevent',$extcal->id));
-            $extevents[$eventdate][$dy]->location_data = 'gcalevent' . $key;
-            $extevents[$eventdate][$dy]->color = !empty($this->config['pull_gcal_color'][$key]) ? $this->config['pull_gcal_color'][$key] : null;
-            $dy++;
-        }
-        return $extevents;
-    }
-
-    public function get_ical_events($exticalurl, $startdate=null, $enddate=null, &$dy=0, $key=0, $multiday=false) {
-        $extevents = array();
-//            require_once BASE . 'external/iCalcreator.class.php';
-        require_once BASE . 'external/iCalcreator-2.22/iCalcreator.php';
-        $v = new vcalendar(); // initiate new CALENDAR
-        if (stripos($exticalurl, 'http') === 0) {
-            $v->setConfig('url', $exticalurl);
-        } else {
-            $v->setConfig('directory', dirname($exticalurl));
-            $v->setConfig('filename', basename($exticalurl));
-        }
-        $v->parse();
-        if ($startdate === null) {
-            $startYear = false;
-            $startMonth = false;
-            $startDay = false;
-        } else {
-            $startYear = date('Y', $startdate);
-            $startMonth = date('n', $startdate);
-            $startDay = date('j', $startdate);
-        }
-        if ($enddate === null) {
-            $endYear = $startYear+1;
-            $endMonth = $startMonth;
-            $endDay = $startDay;
-        } else {
-            $endYear = date('Y', $enddate);
-            $endMonth = date('n', $enddate);
-            $endDay = date('j', $enddate);
-        }
-        // get all events within period split out recurring events as single events per each day
-        $eventArray = $v->selectComponents($startYear, $startMonth, $startDay, $endYear, $endMonth, $endDay, 'vevent');
-        // Set the timezone to GMT
-        @date_default_timezone_set('GMT');
-        $tzarray = getTimezonesAsDateArrays($v);
-        // Set the default timezone
-        @date_default_timezone_set(DISPLAY_DEFAULT_TIMEZONE);
-        if (!empty($eventArray)) foreach ($eventArray as $year => $yearArray) {
-            if (!empty($yearArray)) foreach ($yearArray as $month => $monthArray) {
-                if (!empty($monthArray)) foreach ($monthArray as $day => $dailyEventsArray) {
-                    if (!empty($dailyEventsArray)) foreach ($dailyEventsArray as $vevent) {
-                        // process each event
-                        $yesterday = false;
-                        $currdate = $vevent->getProperty('x-current-dtstart');
-                        $thisday = explode('-', $currdate[1]);
-                        $thisday2 = substr($thisday[2], 0, 2);
-                        // if member of a recurrence set,
-                        // returns array( 'x-current-dtstart', <DATE>)
-                        // <DATE> = (string) date("Y-m-d [H:i:s][timezone/UTC offset]")
-                        $dtstart = $vevent->getProperty('dtstart', false, true);
-                        $dtend = $vevent->getProperty('dtend', false, true);
-                        if (empty($dtend))
-                            $dtend = $dtstart;
-
-                        // calculate the cumulative timezone offset in seconds to convert to local/system time
-                        $tzoffsets = array();
-                        $date_tzoffset = 0;
-                        if (!empty($tzarray)) {
-//                                $ourtzoffsets = -(iCalUtilityFunctions::_tz2offset(date('O',time())));
-                            $ourtzoffsets = -(iCalUtilityFunctions::_tz2offset(date('O',self::_date2timestamp($dtstart['value']))));
-                            // Set the timezone to GMT
-                            @date_default_timezone_set('GMT');
-                            if (!empty($dtstart['params']['TZID'])) $tzoffsets = getTzOffsetForDate($tzarray, $dtstart['params']['TZID'], $dtstart['value']);
-                            // Set the default timezone
-                            @date_default_timezone_set(DISPLAY_DEFAULT_TIMEZONE);
-                            if (isset($tzoffsets['offsetSec'])) $date_tzoffset = $ourtzoffsets + $tzoffsets['offsetSec'];
-                        }
-                        if (empty($tzoffsets)) {
-                            $date_tzoffset = -(iCalUtilityFunctions::_tz2offset(date('O',self::_date2timestamp($dtstart['value']))));
-                        }
-                        //FIXME we must have the real timezone offset for the date by this point
-
-                        //FIXME this is for the google ical feed which is bad!
-                        if ($dtstart['value']['day'] != (int)$thisday2 && (isset($dtstart['value']['day']) && isset($dtend['value']['hour']))&&
-                            !((int)$dtstart['value']['hour'] == 0 && (int)$dtstart['value']['min'] == 0  && (int)$dtstart['value']['sec'] == 0
-                                && (int)$dtend['value']['hour'] == 0 && (int)$dtend['value']['min'] == 0  && (int)$dtend['value']['sec'] == 0
-                                && ((((int)$dtstart['value']['day'] - (int)$dtend['value']['day']) == -1) || (((int)$dtstart['value']['month'] - (int)$dtend['value']['month']) == -1) || (((int)$dtstart['value']['month'] - (int)$dtend['value']['month']) == -11)))) {
-                            $dtst = strtotime($currdate[1]);
-                            $dtst1 = iCalUtilityFunctions::_timestamp2date($dtst);
-                            $dtstart['value']['year'] = $dtst1['year'];
-                            $dtstart['value']['month'] = $dtst1['month'];
-                            $dtstart['value']['day'] = $dtst1['day'];
-                            $currenddate = $vevent->getProperty('x-current-dtend');
-                            $dtet = strtotime($currenddate[1]);
-                            $dtet1 = iCalUtilityFunctions::_timestamp2date($dtet);
-                            $dtend['value']['year'] = $dtet1['year'];
-                            $dtend['value']['month'] = $dtet1['month'];
-                            $dtend['value']['day'] = $dtet1['day'];
-//                                $date_tzoffset = 0;
-                        }
-
-                        if (!empty($dtstart['value']['hour']) && !((int)$dtstart['value']['hour'] == 0 && (int)$dtstart['value']['min'] == 0  && (int)$dtstart['value']['sec'] == 0
-                                                            && (int)$dtend['value']['hour'] == 0 && (int)$dtend['value']['min'] == 0  && (int)$dtend['value']['sec'] == 0
-                                                            && ((((int)$dtstart['value']['day'] - (int)$dtend['value']['day']) == -1) || (((int)$dtstart['value']['month'] - (int)$dtend['value']['month']) == -1) || (((int)$dtstart['value']['month'] - (int)$dtend['value']['month']) == -11)))) {
-                            $eventdate = expDateTime::startOfDayTimestamp(self::_date2timestamp($dtstart['value']) - $date_tzoffset);
-//                                $eventend = expDateTime::startOfDayTimestamp(self::_date2timestamp($dtend['value']) - $date_tzoffset);
-                            $extevents[$eventdate][$dy] = new stdClass();
-                            $extevents[$eventdate][$dy]->eventdate = new stdClass();
-                            $extevents[$eventdate][$dy]->eventdate->date = $eventdate;
-//                                if ((int)($dtstart['value']['hour']) == 0 && (int)($dtstart['value']['min']) == 0  && (int)($dtstart['value']['sec']) == 0
-//                                    && (int)($dtend['value']['hour']) == 0 && (int)($dtend['value']['min']) == 0  && (int)($dtend['value']['sec']) == 0
-//                                    && ((((int)($dtstart['value']['day']) - (int)($dtend['value']['day'])) == -1) || (((int)($dtstart['value']['month']) - (int)($dtend['value']['month'])) == -1) || (((int)($dtstart['value']['month']) - (int)($dtend['value']['month'])) == -11))) {
-////                                    if ($dtstart['value']['day'] != (int)($thisday2)) {
-//                                    if (date('d',$eventdate) != $thisday2) {
-////                                    if (date('d',$eventdate) != date('d',$eventend)) {
-//                                        $yesterday = true;
-//                                    } else {
-//                                        $extevents[$eventdate][$dy]->eventstart = null;
-//                                        $extevents[$eventdate][$dy]->is_allday = 1;
-//                                    }
-//                                } else {
-                                if (date('d',$eventdate) != $thisday2) {
-//                                    if (date('d',$eventdate) != date('d',$eventend)) {
-                                    $yesterday = true;
-                                } else {
-                                    $extevents[$eventdate][$dy]->eventstart = ($dtstart['value']['hour'] * 3600) + ($dtstart['value']['min'] * 60) - $date_tzoffset;
-//                                        if (date("I", $eventdate)) $extevents[$eventdate][$dy]->eventstart += 3600; // adjust for daylight savings time
-                                }
-//                                }
-                        } else {
-                            // this is an all day event
-                            $eventdate = expDateTime::startOfDayTimestamp(self::_date2timestamp($dtstart['value']));
-//                                $eventend = expDateTime::startOfDayTimestamp(self::_date2timestamp($dtend['value']));
-                            $extevents[$eventdate][$dy] = new stdClass();
-                            $extevents[$eventdate][$dy]->eventdate = new stdClass();
-                            $extevents[$eventdate][$dy]->eventdate->date = $eventdate;
-//                                if ($dtstart['value']['day'] != (int)($thisday2)) {
-                            if (date('d',$eventdate) != $thisday2) {
-//                                if (date('d',$eventdate) != date('d',$eventend)) {
-                                $yesterday = true;
-                            } else {
-                                $extevents[$eventdate][$dy]->eventstart = null;
-                                $extevents[$eventdate][$dy]->is_allday = 1;
-                            }
-                        }
-
-                        // set the end time if needed
-                        if (!$yesterday && isset($dtend['value']['hour']) && empty($extevents[$eventdate][$dy]->is_allday)) {
-//                                if ($dtend['value']['day'] != (int)($thisday2)) {
-//                                if ((date('d',$eventend) != $thisday2)) {
-//                                    $yesterday = true;
-//                                } else {
-                            $extevents[$eventdate][$dy]->eventend = ($dtend['value']['hour'] * 3600) + ($dtend['value']['min'] * 60) - $date_tzoffset;
-//                                if (date("I", $eventdate)) $extevents[$eventdate][$dy]->eventend += 3600; // adjust for daylight savings time
-//                                }
-                        }
-
-                        // convert the start and end times to a full date
-                        if (isset($extevents[$eventdate][$dy]->eventstart) && $extevents[$eventdate][$dy]->eventstart != null)
-                            $extevents[$eventdate][$dy]->eventstart += $eventdate;
-                        if (isset($extevents[$eventdate][$dy]->eventend))
-                            $extevents[$eventdate][$dy]->eventend += $eventdate;
-
-                        // dtstart required, one occurrence, (orig. start date)
-                        $extevents[$eventdate][$dy]->title = $vevent->getProperty('summary');
-                        $body = $vevent->getProperty('description');
-                        // convert end of lines
-                        $body = nl2br(str_replace("\\n"," <br>\n",$body));
-                        $body = str_replace("\n"," <br>\n",$body);
-                        $body = str_replace(array('==0A','=0A','=C2=A0')," <br>\n",$body);
-                        $extevents[$eventdate][$dy]->body = $body;
-                        $extevents[$eventdate][$dy]->location_data = 'icalevent' . $key;
-                        $extevents[$eventdate][$dy]->color = !empty($this->config['pull_ical_color'][$key]) ? $this->config['pull_ical_color'][$key] : null;
-                        if (!$yesterday && $eventdate >= $startdate) {
-                            $dy++;
-                        } else {
-                            unset($extevents[$eventdate][$dy]);
-                        }
-                    }
-                }
-            }
-        }
-        return $extevents;
-    }
-
-    public static function _date2timestamp( $datetime, $wtz=null ) {
-      if( !isset( $datetime['hour'] )) $datetime['hour'] = 0;
-      if( !isset( $datetime['min'] ))  $datetime['min']  = 0;
-      if( !isset( $datetime['sec'] ))  $datetime['sec']  = 0;
-      if( empty( $wtz ) && ( !isset( $datetime['tz'] ) || empty(  $datetime['tz'] )))
-        return mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year'] );
-      $output = $offset = 0;
-      if( empty( $wtz )) {
-        if( iCalUtilityFunctions::_isOffset( $datetime['tz'] )) {
-          $offset = iCalUtilityFunctions::_tz2offset( $datetime['tz'] ) * -1;
-          $wtz    = 'UTC';
-        }
-        else
-          $wtz    = $datetime['tz'];
-      }
-      if(( 'Z' == $wtz ) || ( 'GMT' == strtoupper( $wtz )))
-        $wtz      = 'UTC';
-      try {
-        $strdate  = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', $datetime['year'], $datetime['month'], $datetime['day'], $datetime['hour'], $datetime['min'], $datetime['sec'] );
-        $d        = new DateTime( $strdate, new DateTimeZone( $wtz ));
-        if( 0    != $offset )  // adjust for offset
-          $d->modify( $offset.' seconds' );
-        $output   = $d->format( 'U' );
-        unset( $d );
-      }
-      catch( Exception $e ) {
-        $output = mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year'] );
-      }
-      return $output;
-    }
-
-    /**
-     * build/update the external event cache
-     *
-     */
-    public function build_cache() {
-        global $db;
-
-        // get our requested config
-        $cfg = new expConfig();
-        $configs = $cfg->find('all', "location_data LIKE '%event%'"); // get all event module configs
-        foreach ($configs as $config) {
-            $loc = expUnserialize($config->location_data);
-            if (!empty($this->params['title'])) {
-                if ($this->params['title'] == $config->config['feed_sef_url']) {
-                    $this->config = $config->config;
-                    break;
-                }
-            } elseif (!empty($this->params['src'])) {
-                if ($this->params['src'] == $loc->src) {
-                    $this->config = $config->config;
-                    break;
-                }
-            }
-        }
-
-        // next loop through our config pull urls
-
-        // google xml pull
-        if (!empty($this->config['pull_gcal'])) foreach ($this->config['pull_gcal'] as $key=>$extgcalurl) {
-            $start = expDateTime::startOfMonthTimestamp(time());
-            $gcal_cname = str_replace(array("/",":","&","?"),"_",$extgcalurl);
-            $cache_fname = BASE.'tmp/cache/'.$gcal_cname.".cache";
-            $db->delete('event_cache', "feed='" . $extgcalurl . "' AND eventdate > " . $start);  // replace future events
-            // loop through 12 months, 1 month at a time
-            for ($i=1; $i < 13; $i++) {
-                $end = expDateTime::endOfMonthTimestamp($start);
-                $tmp = 0;
-                $extevents = $this->get_gcal_events($extgcalurl, $start, $end, $tmp, 0, true);
-//                $extevents = $this->get_gcal_events($extgcalurl, null, null, 0, 0, 0, true);
-                foreach ($extevents as $day) {
-                    foreach ($day as $extevent) {
-                        $event_cache = new stdClass();
-                        $event_cache->feed = $extgcalurl;
-                        $event_cache->event_id = $extevent->event_id;
-                        $event_cache->title = $extevent->title;
-                        $event_cache->body = $extevent->body;
-                        $event_cache->eventdate = $extevent->eventdate->date;
-                        if (isset($extevent->dateFinished) && $extevent->dateFinished != -68400)
-                            $event_cache->dateFinished = $extevent->dateFinished;
-                        if (isset($extevent->eventstart))
-                            $event_cache->eventstart = $extevent->eventstart;
-                        if (isset($extevent->eventend))
-                            $event_cache->eventend = $extevent->eventend;
-                        if (isset($extevent->is_allday))
-                            $event_cache->is_allday = $extevent->is_allday;
-                        $found = false;
-                        if ($extevent->eventdate->date < $start)   // prevent duplicating events crossing month boundaries
-                            $found = $db->selectObject('event_cache','feed="'.$extgcalurl.'" AND event_id="'.$event_cache->event_id.'" AND eventdate='.$event_cache->eventdate);
-                        if (!$found)
-                            $db->insertObject($event_cache,'event_cache');
-                    }
-                }
-                $start = expDateTime::startOfMonthTimestamp($end + 1024);
-            }
-            $cache_contents = serialize(array('start_date'=>$start,'first_date'=>(int)$db->selectValue('event_cache','eventdate','feed="'.$extgcalurl.'" ORDER BY eventdate'),'refresh_date'=>time()));
-            file_put_contents($cache_fname, $cache_contents);
-        }
-
-        // ical pull
-        $start = expDateTime::startOfMonthTimestamp(time());
-        if (!empty($this->config['pull_ical'])) foreach ($this->config['pull_ical'] as $key=>$exticalurl) {
-            $ical_cname = str_replace(array("/",":","&","?"),"_",$exticalurl);
-            $cache_fname = BASE.'tmp/cache/'.$ical_cname.".cache";
-            $db->delete('event_cache', "feed='" . $exticalurl . "' AND eventdate > " . $start);
-            // get 1 years worth of events
-            $extevents = $this->get_ical_events($exticalurl, $start);
-            foreach ($extevents as $day) {
-                foreach ($day as $extevent) {
-                    $event_cache = new stdClass();
-                    $event_cache->feed = $exticalurl;
-                    $event_cache->title = $extevent->title;
-                    $event_cache->body = $extevent->body;
-                    $event_cache->eventdate = $extevent->eventdate->date;
-                    if (isset($extevent->dateFinished))
-                        $event_cache->dateFinished = $extevent->dateFinished;
-                    $event_cache->eventstart = $extevent->eventstart;
-                    if (isset($extevent->eventend))
-                        $event_cache->eventend = $extevent->eventend;
-                    if (isset($extevent->is_allday))
-                        $event_cache->is_allday = $extevent->is_allday;
-                    $db->insertObject($event_cache, 'event_cache');
-                }
-            }
-            $cache_contents = serialize(array('start_date'=>$start,'first_date'=>(int)$db->selectValue('event_cache','eventdate','feed="'.$exticalurl.'" ORDER BY eventdate'),'refresh_date'=>time()));
-            file_put_contents($cache_fname, $cache_contents);
-        }
-        flash('message', gt('External Calendar Event cache updated'));
-        echo show_msg_queue();
-    }
-
-    function import() {
-        $pullable_modules = expModules::listInstalledControllers($this->baseclassname);
-        $modules = new expPaginator(array(
-            'records' => $pullable_modules,
-            'controller' => $this->loc->mod,
-            'action' => $this->params['action'],
-            'order'   => isset($this->params['order']) ? $this->params['order'] : 'section',
-            'dir'     => isset($this->params['dir']) ? $this->params['dir'] : '',
-            'page'    => (isset($this->params['page']) ? $this->params['page'] : 1),
-            'columns' => array(
-                gt('Title') => 'title',
-                gt('Page')  => 'section'
-            ),
-        ));
-
-        assign_to_template(array(
-            'modules' => $modules,
-        ));
-    }
-
-    function import_select()
-    {
-        if (empty($this->params['import_aggregate'])) {
-            expValidator::setErrorField('import_aggregate[]');
-            expValidator::failAndReturnToForm(gt('You must select a module.'), $this->params);
-        }
-        $extevents = array();
-        unset(
-            $this->params['begin'],
-            $this->params['end']
-        );  // always use date value
-        $begin = yuidatetimecontrol::parseData('begin', $this->params);
-        $end = yuidatetimecontrol::parseData('end', $this->params);
-        if ($this->params['file_type'] == 'file') {
-            //Get the temp directory to put the uploaded file
-            $directory = "tmp";
-
-            //Get the file save it to the temp directory
-            if (!empty($_FILES["import_file"]) && $_FILES["import_file"]["error"] == UPLOAD_ERR_OK) {
-                $file = expFile::fileUpload(
-                    "import_file",
-                    false,
-                    false,
-                    time() . "_" . $_FILES['import_file']['name'],
-                    $directory . '/'
-                );
-                if ($file === null) {
-                    switch ($_FILES["import_file"]["error"]) {
-                        case UPLOAD_ERR_INI_SIZE:
-                        case UPLOAD_ERR_FORM_SIZE:
-                            $this->params['_formError'] = gt(
-                                'The file you attempted to upload is too large.  Contact your system administrator if this is a problem.'
-                            );
-                            break;
-                        case UPLOAD_ERR_PARTIAL:
-                            $this->params['_formError'] = gt('The file was only partially uploaded.');
-                            break;
-                        case UPLOAD_ERR_NO_FILE:
-                            $this->params['_formError'] = gt('No file was uploaded.');
-                            break;
-                        default:
-                            $this->params['_formError'] = gt(
-                                'A strange internal error has occurred.  Please contact the Exponent Developers.'
-                            );
-                            break;
-                    }
-                    expSession::set("last_POST", $this->params);
-                    header("Location: " . $_SERVER['HTTP_REFERER']);
-                    exit("");
-                } else {
-                    $extevents = $this->get_ical_events($directory . "/" . $file->filename, $begin, $end);
-                }
-            } else {
-               expValidator::setErrorField('import_file');
-               expValidator::failAndReturnToForm(gt('File failed to upload.'), $this->params);  // file upload error
-            }
-        } else {
-            if (empty($this->params['ext_feed'])) {
-                expValidator::setErrorField('ext_feed');
-                expValidator::failAndReturnToForm(gt('You must enter a feed url.'), $this->params);
-            }
-            $extevents = $this->get_ical_events($this->params['ext_feed'], $begin, $end);
-        }
-
-        $src = $this->params['import_aggregate'][0];
-        $count = 0;
-        foreach ($extevents as $day) {
-            foreach ($day as $extevent) {
-                $event = array();
-                $event['title'] = $extevent->title;
-                $event['body'] = $extevent->body;
-                $event['eventdate'] = $extevent->eventdate->date;
-                $event['eventstart'] = $extevent->eventstart;
-                $event['eventstart'] -= $event['eventdate'];
-                if (isset($extevent->eventend))
-                    $event['eventend'] = $extevent->eventend;
-                else
-                    $event['eventend'] = $extevent->eventstart;
-                $event['eventend'] -= $event['eventdate'];
-                if (isset($extevent->is_allday))
-                    $event['is_allday'] = $extevent->is_allday;
-                $event['module'] = 'event';
-                $event['src'] = $src;
-                $item = new event();  // create new populated record to auto-set things
-                $item->update($event);
-                $count++;
-            }
-        }
-
-        unlink($directory . "/" . $file->filename);
-
-        // update search index
-        $this->addContentToSearch();
-
-        flashAndFlow('message', $count . ' ' . gt('events were imported.'));
-    }
-
-    /** @deprecated
-     * function to build a control requested via ajax
-     * we the html just like the control smarty function
-     * @deprecated
-     */
-    public function buildControl() {
-        $control = new colorcontrol();
-        if (!empty($this->params['value'])) $control->value = $this->params['value'];
-        if ($this->params['value'][0] != '#') $this->params['value'] = '#' . $this->params['value'];
-        $control->default = $this->params['value'];
-        if (!empty($this->params['hide'])) $control->hide = $this->params['hide'];
-        if (isset($this->params['flip'])) $control->flip = $this->params['flip'];
-        $this->params['name'] = !empty($this->params['name']) ? $this->params['name'] : '';
-        $control->name  = $this->params['name'];
-        $this->params['id'] = !empty($this->params['id']) ? $this->params['id'] : '';
-        $control->id  = isset($this->params['id']) && $this->params['id'] != "" ? $this->params['id'] : "";
-        //echo $control->id;
-        if (empty($control->id)) $control->id = $this->params['name'];
-        if (empty($control->name)) $control->name = $this->params['id'];
-
-        // attempt to translate the label
-        if (!empty($this->params['label'])) {
-            $this->params['label'] = gt($this->params['label']);
-        } else {
-            $this->params['label'] = null;
-        }
-        echo $control->toHTML($this->params['label'], $this->params['name']);
-//        $ar = new expAjaxReply(200, gt('The control was created'), json_encode(array('data'=>$code)));
-//        $ar->send();
-    }
-
-}
-
+<?php
+
+##################################################
+#
+# Copyright (c) 2004-2016 OIC Group, Inc.
+#
+# This file is part of Exponent
+#
+# Exponent is free software; you can redistribute
+# it and/or modify it under the terms of the GNU
+# General Public License as published by the Free
+# Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# GPL: http://www.gnu.org/licenses/gpl.txt
+#
+##################################################
+
+/**
+ * @subpackage Controllers
+ * @package    Modules
+ */
+
+class eventController extends expController {
+//    public $basemodel_name = 'event';
+    public $useractions = array(
+        'showall' => 'Show Calendar',
+    );
+//    protected $manage_permissions = array(
+//        'import' => 'Import Calendar',
+//    );
+    public $remove_configs = array(
+        'comments',
+        'ealerts',
+//        'facebook',
+        'files',
+        'pagination',
+        'rss',
+//        'twitter',
+    );  // all options: ('aggregation','categories','comments','ealerts','facebook','files','pagination','rss','tags','twitter',)
+
+    static function displayname() {
+        return "Events";
+    }
+
+    static function description() {
+        return "Manage events and schedules, and optionally publish them.";
+    }
+
+    static function author() {
+        return "Dave Leffler";
+    }
+
+    static function isSearchable() {
+        return true;
+    }
+
+    function searchName() {
+        return gt("Calendar Event");
+    }
+
+    function searchCategory() {
+        return gt('Event');
+    }
+
+    /**
+     * can this module import data?
+     *
+     * @return bool
+     */
+    public static function canImportData() {
+        return true;
+    }
+
+    function showall() {
+        global $user;
+
+        expHistory::set('viewable', $this->params);
+        $locsql = $this->aggregateWhereClause();
+        $time = (isset($this->params['time']) ? intval($this->params['time']) : time());
+        assign_to_template(array(
+            'time' => $time,
+            'daynames' => event::dayNames(),
+        ));
+
+        $regcolor = !empty($this->config['registrations_color']) ? $this->config['registrations_color'] : null;
+
+        $ed = new eventdate();
+        $viewtype = 'default';
+        $viewrange = 'all';
+        $view = !empty($this->params['view']) ? $this->params['view'] : 'showall';
+        switch ($view) {
+            case 'showall_Administration':
+                $viewtype = "administration";
+                break;
+            case 'showall_Past Events':
+                $viewrange = "past";
+                break;
+            case 'showall_Monthly Summary':
+            case 'showall_Mini-Calendar':
+            case 'minical':
+                $viewtype = "minical";
+                break;
+            case 'showall_Monthly List':
+            case 'showall_List':
+            case 'monthlist':
+                $viewtype = "byday";
+                $viewrange = "month";
+                break;
+            case 'showall_Week':
+            case 'week':
+                $viewtype = "byday";
+                $viewrange = "week";
+                break;
+            case 'showall_Day':
+            case 'day':
+                $viewtype = "byday";
+                $viewrange = "day";
+                break;
+            case 'showall_announcement':
+            case 'showall_Upcoming Events':
+            case 'showall_Upcoming Events - Headlines':
+                $viewrange = "upcoming";
+                break;
+            case 'showall':
+            case 'month':
+                $viewtype = "monthly";
+                break;
+            default :
+                $view_params = explode('_',$view);
+                if (!empty($view_params[1])) $viewtype = $view_params[1];
+                if (!empty($view_params[2])) $viewrange = $view_params[2];
+        }  // end switch $view
+
+        switch ($viewtype) {
+            case "minical":
+                $monthly = expDateTime::monthlyDaysTimestamp($time);
+                $info = getdate($time);
+                $timefirst = mktime(0, 0, 0, $info['mon'], 1, $info['year']);
+                $now = getdate(time());
+                $currentday = $now['mday'];
+                $endofmonth = date('t', $time);
+                foreach ($monthly as $weekNum => $week) {
+                    foreach ($week as $dayNum => $day) {
+                        if ($dayNum == $now['mday']) {
+                            $currentweek = $weekNum;
+                        }
+                        if ($dayNum <= $endofmonth) {
+//                            $monthly[$weekNum][$dayNum]['number'] = ($monthly[$weekNum][$dayNum]['ts'] != -1) ? $db->countObjects("eventdate", $locsql . " AND date >= " . expDateTime::startOfDayTimestamp($day['ts']) . " AND date <= " . expDateTime::endOfDayTimestamp($day['ts'])) : -1;
+                            $monthly[$weekNum][$dayNum]['number'] = ($monthly[$weekNum][$dayNum]['ts'] != -1) ? $ed->find("count", $locsql . " AND date >= " . expDateTime::startOfDayTimestamp($day['ts']) . " AND date <= " . expDateTime::endOfDayTimestamp($day['ts'])) : -1;
+                        }
+                    }
+                }
+                $prevmonth = mktime(0, 0, 0, date("m", $timefirst) - 1, date("d", $timefirst) + 10, date("Y", $timefirst));
+                $nextmonth = mktime(0, 0, 0, date("m", $timefirst) + 1, date("d", $timefirst) + 10, date("Y", $timefirst));
+                assign_to_template(array(
+                    "monthly"     => $monthly,
+                    "currentweek" => $currentweek,
+                    "currentday"  => $currentday,
+                    "now"         => $timefirst,
+                    "prevmonth"   => $prevmonth,
+                    "thismonth"   => $timefirst,
+                    "nextmonth"   => $nextmonth,
+                ));
+                break;  // end switch $viewtype minicalendar
+            case "byday":  //note aggregates events by groups of days
+                // Remember this is the code for weekly view and monthly listview
+                // Test your fixes on both views
+                //   		$startperiod = 0;
+                //			$totaldays = 0;
+                switch ($viewrange) {
+                    case "day":
+                        $startperiod = expDateTime::startOfDayTimestamp($time);
+                        $totaldays = 1;
+                        $next = expDateTime::endOfDayTimestamp($startperiod);
+                        if (!empty($this->config['starttype'])) $startperiod = $time;
+                        $this->params['time'] = $time;
+                        assign_to_template(array(
+                            "prev_timestamp3" => strtotime('-3 days', $startperiod),
+                            "prev_timestamp2" => strtotime('-2 days', $startperiod),
+                            "prev_timestamp"  => strtotime('-1 days', $startperiod),
+                            "next_timestamp"  => strtotime('+1 days', $startperiod),
+                            "next_timestamp2" => strtotime('+2 days', $startperiod),
+                            "next_timestamp3" => strtotime('+3 days', $startperiod),
+                            'params'      => $this->params
+                        ));
+                        break;
+                    case "week":
+                        $startperiod = expDateTime::startOfWeekTimestamp($time);
+                        $totaldays = 7;
+                        $next = strtotime('+7 days', $startperiod);
+//                        $next = expDateTime::endOfWeekTimestamp($startperiod);
+                        if (!empty($this->config['starttype'])) $startperiod = $time;
+                        $this->params['time'] = $time;
+                        assign_to_template(array(
+                            "prev_timestamp3" => strtotime('-21 days', $startperiod),
+                            "prev_timestamp2" => strtotime('-14 days', $startperiod),
+                            "prev_timestamp"  => strtotime('-7 days', $startperiod),
+                            "next_timestamp"  => $next,
+                            "next_timestamp2" => strtotime('+14 days', $startperiod),
+                            "next_timestamp3" => strtotime('+21 days', $startperiod),
+                            'params'      => $this->params
+                        ));
+                        break;
+                    case "twoweek":
+                        $startperiod = expDateTime::startOfWeekTimestamp($time);
+                        $totaldays = 14;
+                        $next = strtotime('+14 days', $startperiod);
+                        if (!empty($this->config['starttype'])) $startperiod = $time;
+                        assign_to_template(array(
+                            "prev_timestamp3" => strtotime('-42 days', $startperiod),
+                            "prev_timestamp2" => strtotime('-28 days', $startperiod),
+                            "prev_timestamp"  => strtotime('-14 days', $startperiod),
+                            "next_timestamp"  => $next,
+                            "next_timestamp2" => strtotime('+28 days', $startperiod),
+                            "next_timestamp3" => strtotime('+42 days', $startperiod),
+                        ));
+                        break;
+                    case "month":
+                    default: // range = month
+                        $startperiod = expDateTime::startOfMonthTimestamp($time);
+                        $totaldays = date('t', $time);
+                        $next = strtotime('+1 months', $startperiod);
+//                        $next = expDateTime::endOfMonthTimestamp($startperiod);
+                        $this->params['time'] = $time;
+                        assign_to_template(array(
+                            "prev_timestamp3" => strtotime('-3 months', $startperiod),
+                            "prev_timestamp2" => strtotime('-2 months', $startperiod),
+                            "prev_timestamp"  => strtotime('-1 months', $startperiod),
+                            "next_timestamp"  => $next,
+                            "next_timestamp2" => strtotime('+2 months', $startperiod),
+                            "next_timestamp3" => strtotime('+3 months', $startperiod),
+                            'params'      => $this->params
+                        ));
+                        break;
+                }  // end switch $viewrange
+
+                //                $days = array();
+                // added per Ignacio
+                //			$endofmonth = date('t', $time);
+                $extitems = $this->getExternalEvents($startperiod, $next);
+                if (!empty($this->config['aggregate_registrations']))
+                    $regitems = eventregistrationController::getRegEventsForDates($startperiod, $next, $regcolor);
+                for ($i = 1; $i <= $totaldays; $i++) {
+                    //                    $info = getdate($time);
+                    //                    switch ($viewrange) {
+                    //                        case "week":
+                    //                            $start = mktime(0,0,0,$info['mon'],$i,$info['year']);  //FIXME this can't be right?
+                    //                            break;
+                    //                        case "twoweek":
+                    ////                            $start = mktime(0,0,0,$info['mon'],$info['mday']+($i-1),$info['year']);  //FIXME this can't be right?
+                    //                  		    $start = $startperiod + ($i*86400);
+                    //                            break;
+                    //                        default:  // range = month
+                    //                            $start = mktime(0,0,0,$info['mon'],$i,$info['year']);
+                    //                    }
+                    $start = expDateTime::startOfDayTimestamp($startperiod + ($i * 86400) - 86400);
+                    $edates = $ed->find("all", $locsql . " AND date >= " . expDateTime::startOfDayTimestamp($start) . " AND date <= " . expDateTime::endOfDayTimestamp($start));
+//                    $days[$start] = $this->getEventsForDates($edates, true, isset($this->config['only_featured']) ? true : false);
+                    $days[$start] = $this->event->getEventsForDates($edates, true, isset($this->config['only_featured']) ? true : false);
+                    //                    for ($j = 0; $j < count($days[$start]); $j++) {
+                    //                        $thisloc = expCore::makeLocation($this->loc->mod,$this->loc->src,$days[$start][$j]->id);
+                    //                        $days[$start][$j]->permissions = array(
+                    //                            "manage"=>(expPermissions::check("manage",$thisloc) || expPermissions::check("manage",$this->loc)),
+                    //                            "edit"=>(expPermissions::check("edit",$thisloc) || expPermissions::check("edit",$this->loc)),
+                    //                            "delete"=>(expPermissions::check("delete",$thisloc) || expPermissions::check("delete",$this->loc))
+                    //                        );
+                    //                    }
+                    if (!empty($extitems[$start]))
+                        $days[$start] = array_merge($extitems[$start], $days[$start]);
+                    if (!empty($regitems[$start]))
+                        $days[$start] = array_merge($regitems[$start], $days[$start]);
+                    $days[$start] = expSorter::sort(array('array' => $days[$start], 'sortby' => 'eventstart', 'order' => 'ASC'));
+                }
+                assign_to_template(array(
+                    "time" => $startperiod,
+                    'days' => $days,
+                    "now"  => $startperiod,
+                ));
+                break;  // end switch $viewtype byday
+            case "monthly":  //note this is a simply array of events for the requested month
+                // build a month array of weeks with an array of days
+                //                $monthly = array();
+                //                $counts = array();
+                $info = getdate($time);
+                $nowinfo = getdate(time());
+                if ($info['mon'] != $nowinfo['mon']) $nowinfo['mday'] = -10;
+                // Grab non-day numbers only (before end of month)
+//                $week = 0;
+                $currentweek = -1;
+                $timefirst = mktime(0, 0, 0, $info['mon'], 1, $info['year']);
+                $week = (int)date('W',$timefirst);
+                if ($week >= 52 && $info['mon'] == 1) $week = 1;
+                $infofirst = getdate($timefirst);
+                $monthly[$week] = array(); // initialize for non days
+                $counts[$week] = array();
+                if (($infofirst['wday'] == 0) && (DISPLAY_START_OF_WEEK == 1)) {
+                    for ($i = -6; $i < (1 - DISPLAY_START_OF_WEEK); $i++) {
+                        $monthly[$week][$i] = array();
+                        $counts[$week][$i] = -1;
+                    }
+                    $weekday = $infofirst['wday'] + 7; // day number in grid.  if 7+, switch weeks
+                } else {
+                    for ($i = 1 - $infofirst['wday']; $i < (1 - DISPLAY_START_OF_WEEK); $i++) {
+                        $monthly[$week][$i] = array();
+                        $counts[$week][$i] = -1;
+                    }
+                    $weekday = $infofirst['wday']; // day number in grid.  if 7+, switch weeks
+                }
+                // Grab day counts
+                $endofmonth = date('t', $time);
+                $extitems = $this->getExternalEvents($timefirst, expDateTime::endOfMonthTimestamp($timefirst));
+                if (!empty($this->config['aggregate_registrations']))
+                    $regitems = eventregistrationController::getRegEventsForDates($timefirst, expDateTime::endOfMonthTimestamp($timefirst), $regcolor);
+                for ($i = 1; $i <= $endofmonth; $i++) {
+                    $start = mktime(0, 0, 0, $info['mon'], $i, $info['year']);
+                    if ($i == $nowinfo['mday']) $currentweek = $week;
+                    $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfDayTimestamp($start) . " AND date <= " . expDateTime::endOfDayTimestamp($start) . ")");
+//                    $monthly[$week][$i] = $this->getEventsForDates($dates, true, isset($this->config['only_featured']) ? true : false);
+                    $monthly[$week][$i] = $this->event->getEventsForDates($dates, true, isset($this->config['only_featured']) ? true : false);
+                    if (!empty($extitems[$start]))
+                        $monthly[$week][$i] = array_merge($extitems[$start], $monthly[$week][$i]);
+                    if (!empty($regitems[$start]))
+                        $monthly[$week][$i] = array_merge($regitems[$start], $monthly[$week][$i]);
+                    $monthly[$week][$i] = expSorter::sort(array('array' => $monthly[$week][$i], 'sortby' => 'eventstart', 'order' => 'ASC'));
+                    $counts[$week][$i] = count($monthly[$week][$i]);
+                    if ($weekday >= (6 + DISPLAY_START_OF_WEEK)) {
+                        $week++;
+                        $monthly[$week] = array(); // allocate an array for the next week
+                        $counts[$week] = array();
+                        $weekday = DISPLAY_START_OF_WEEK;
+                    } else $weekday++;
+                }
+                // Grab non-day numbers only (after end of month)
+                for ($i = 1; $weekday && $i < (8 + DISPLAY_START_OF_WEEK - $weekday); $i++) {
+                    $monthly[$week][$i + $endofmonth] = array();
+                    $counts[$week][$i + $endofmonth] = -1;
+                }
+                $this->params['time'] = $time;
+                assign_to_template(array(
+                    "currentweek" => $currentweek,
+                    "monthly"     => $monthly,
+                    "counts"      => $counts,
+                    "prevmonth3"  => strtotime('-3 months', $timefirst),
+                    "prevmonth2"  => strtotime('-2 months', $timefirst),
+                    "prevmonth"   => strtotime('-1 months', $timefirst),
+                    "nextmonth"   => strtotime('+1 months', $timefirst),
+                    "nextmonth2"  => strtotime('+2 months', $timefirst),
+                    "nextmonth3"  => strtotime('+3 months', $timefirst),
+                    "now"         => $timefirst,
+                    "today"       => expDateTime::startOfDayTimestamp(time()),
+                    'params'      => $this->params
+                ));
+                break;  // end switch $viewtype monthly
+            case "administration":  //note a simple list of all upcoming events, except no external nor registration events
+                // Check perms and return if cant view
+                if (!$user) return;
+                $continue = (expPermissions::check("manage", $this->loc) ||
+                    expPermissions::check("create", $this->loc) ||
+                    expPermissions::check("edit", $this->loc) ||
+                    expPermissions::check("delete", $this->loc)
+                ) ? 1 : 0;
+                $dates = $ed->find("all", $locsql . " AND date >= " . expDateTime::startOfDayTimestamp(time()));
+//                $items = $this->getEventsForDates($dates);
+                $items = $this->event->getEventsForDates($dates);
+                //                if (!$continue) {
+                //                    foreach ($items as $i) {
+                //                        $iloc = expCore::makeLocation($this->loc->mod,$this->loc->src,$i->id);
+                //                        if (expPermissions::check("edit",$iloc) ||
+                //                            expPermissions::check("delete",$iloc) ||
+                //                            expPermissions::check("manage",$iloc)
+                //                        ) {
+                //                            $continue = true;
+                //                        }
+                //                    }
+                //                }
+                if (!$continue) return;
+                //                for ($i = 0; $i < count($items); $i++) {
+                //                    $thisloc = expCore::makeLocation($this->loc->mod,$this->loc->src,$items[$i]->id);
+                //    //				if ($user && $items[$i]->poster == $user->id) $canviewapproval = 1;
+                //                    $items[$i]->permissions = array(
+                //                        "manage"=>(expPermissions::check("manage",$thisloc) || expPermissions::check("manage",$this->loc)),
+                //                        "edit"=>(expPermissions::check("edit",$thisloc) || expPermissions::check("edit",$this->loc)),
+                //                        "delete"=>(expPermissions::check("delete",$thisloc) || expPermissions::check("delete",$this->loc))
+                //                    );
+                //                }
+                $items = expSorter::sort(array('array' => $items, 'sortby' => 'eventstart', 'order' => 'ASC'));
+                assign_to_template(array(
+                    'items' => $items,
+                ));
+                break;  // end switch $viewtype administration
+            case "default":  //note a simple list of events based on $viewrange
+            default;
+                //                $items = null;
+                //                $dates = null;
+                $day = expDateTime::startOfDayTimestamp(time());
+                $sort_asc = true; // For the getEventsForDates call
+                //                $moreevents = false;
+                switch ($viewrange) {
+                    case "upcoming":  // events in the future
+                        if (!empty($this->config['enable_ical']) && !empty($this->config['rss_limit']) && $this->config['rss_limit'] > 0) {
+                            $eventlimit = " AND date <= " . ($day + ($this->config['rss_limit'] * 86400));
+                        } else {
+                            $eventlimit = "";
+                        }
+                        $dates = $ed->find("all", $locsql . " AND date >= " . $day . $eventlimit . " ORDER BY date ASC ");
+                        $begin = $day;
+                        $end = null;
+                        //					$moreevents = count($dates) < $db->countObjects("eventdate",$locsql." AND date >= $day");
+                        break;
+                    case "past":  // events in the past
+                        $dates = $ed->find("all", $locsql . " AND date < $day ORDER BY date DESC ");
+                        //					$moreevents = count($dates) < $db->countObjects("eventdate",$locsql." AND date < $day");
+                        $sort_asc = false;
+                        $begin = null;
+                        $end = $day;
+                        break;
+                    case "today":  // events occuring today
+                        $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfDayTimestamp($day) . " AND date <= " . expDateTime::endOfDayTimestamp($day) . ")");
+                        $begin = $day;
+                        $end = expDateTime::endOfDayTimestamp($day);
+                        break;
+                    case "day":  // events for a specific day (same as byday day?)
+                        $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfDayTimestamp($time) . " AND date <= " . expDateTime::endOfDayTimestamp($time) . ")");
+                        $begin = expDateTime::startOfDayTimestamp($time);
+                        $end = expDateTime::endOfDayTimestamp($time);
+                        break;
+                    case "next":  // future events
+                        $dates = array($ed->find("all", $locsql . " AND date >= $time"));
+                        $begin = expDateTime::startOfDayTimestamp($time);
+                        $end = null;
+                        break;
+                    case "month": // events for a specific month (same as monthly?)
+//                        $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfMonthTimestamp(time()) . " AND date <= " . expDateTime::endOfMonthTimestamp(time()) . ")");
+                        $dates = $ed->find("all", $locsql . " AND (date >= " . expDateTime::startOfMonthTimestamp($time) . " AND date <= " . expDateTime::endOfMonthTimestamp($time) . ")");
+                        $begin = expDateTime::startOfMonthTimestamp($time);
+                        $end = expDateTime::endOfMonthTimestamp($time);
+                        break;
+                    case "all":  // all events
+                    default;
+                        $dates = $ed->find("all", $locsql);
+                        $begin = null;
+                        $end = null;
+                }
+//                $items = $this->getEventsForDates($dates, $sort_asc, isset($this->config['only_featured']) ? true : false, true);
+                $items = $this->event->getEventsForDates($dates, $sort_asc, isset($this->config['only_featured']) ? true : false, true);
+                if ($viewrange != 'past') {
+                    $extitems = $this->getExternalEvents($begin, $end);
+                    // we need to flatten these down to simple array of events
+                    $extitem = array();
+                    foreach ($extitems as $days) {
+                        foreach ($days as $event) {
+                            if (empty($event->eventdate->date) || ($viewrange == 'upcoming' && $event->eventdate->date < time()))
+                                break;
+                            if (empty($event->eventstart))
+                                $event->eventstart = $event->eventdate->date;
+                            $extitem[] = $event;
+                        }
+                    }
+                    $items = array_merge($items, $extitem);
+
+                    if (!empty($this->config['aggregate_registrations']))
+                        $regitems = eventregistrationController::getRegEventsForDates($begin, $end, $regcolor);
+                    // we need to flatten these down to simple array of events
+                    $regitem = array();
+                    if (!empty($regitems)) foreach ($regitems as $days) {
+                        foreach ($days as $value) {
+                            $regitem[] = $value;
+                        }
+                    }
+                    $items = array_merge($items, $regitem);
+
+                    // remove today's events that have already ended
+                    if ($viewtype == 'default' && $viewrange == 'upcoming') {
+                        foreach ($items as $key=>$item) {
+                            if (!$item->is_allday && $item->eventend < time()) {
+                                //fixme we've left events ending earlier in the day, but already cancelled out tomorrow's event
+                                unset($items[$key]);
+                            } else {
+                                break;  // they are chronological so we can end
+                            }
+                        }
+                    }
+                }
+                $items = expSorter::sort(array('array' => $items, 'sortby' => 'eventstart', 'order' => 'ASC'));
+                // Upcoming events can be configured to show a specific number of events.
+                // The previous call gets all events in the future from today
+                // If configured, cut the array to the configured number of events
+                //			if ($template->viewconfig['num_events']) {
+                //				switch ($viewrange) {
+                //					case "upcoming":
+                //					case "past":
+                //						$moreevents = $template->viewconfig['num_events'] < count($items);
+                //						break;
+                //				}
+                //				$items = array_slice($items, 0, $template->viewconfig['num_events']);
+                //			}
+                //                for ($i = 0; $i < count($items); $i++) {
+                //                    $thisloc = expCore::makeLocation($this->loc->mod,$this->loc->src,$items[$i]->id);
+                //                    $items[$i]->permissions = array(
+                //                        'manage'=>(expPermissions::check('manage',$thisloc) || expPermissions::check('manage',$this->loc)),
+                //                        'edit'=>(expPermissions::check('edit',$thisloc) || expPermissions::check('edit',$this->loc)),
+                //                        'delete'=>(expPermissions::check('delete',$thisloc) || expPermissions::check('delete',$this->loc))
+                //                    );
+                //                }
+                assign_to_template(array(
+                    'items' => $items,
+                    "now"   => $day,
+                ));
+        }
+    }
+
+    /**
+     * default view for individual item
+     */
+    function show() {
+        expHistory::set('viewable', $this->params);
+        if (!empty($this->params['date_id'])) {  // specific event instance
+            $eventdate = new eventdate($this->params['date_id']);
+            $eventdate->event = new event($eventdate->event_id);
+        } else {  // we'll default to the first event of this series
+            $event = new event($this->params['id']);
+            $eventdate = new eventdate($event->eventdate[0]->id);
+        }
+        if (empty($eventdate->id))
+            redirect_to(array('controller'=>'notfound','action'=>'page_not_found','title'=>'event'));
+
+        if (!empty($eventdate->event->feedback_form) && $eventdate->event->feedback_form != 'Disallow Feedback') {
+            assign_to_template(array(
+                'feedback_form' => $eventdate->event->feedback_form,
+            ));
+        }
+
+        assign_to_template(array(
+            'event' => $eventdate,
+        ));
+    }
+
+    function edit() {
+        global $template;
+
+        parent::edit();
+        $allforms = array();
+        $allforms[""] = gt('Disallow Feedback');
+        // calculate which event date is the one being edited
+        $event_key = 0;
+        foreach ($template->tpl->tpl_vars['record']->value->eventdate as $key=>$d) {
+       	    if ($d->id == $this->params['date_id']) $event_key = $key;
+       	}
+
+        assign_to_template(array(
+            'allforms'     => array_merge($allforms, expTemplate::buildNameList("forms", "event/email", "tpl", "[!_]*")),
+            'checked_date' => !empty($this->params['date_id']) ? $this->params['date_id'] : null,
+            'event_key'    => $event_key,
+        ));
+    }
+
+    /**
+     * Delete a recurring event by asking for which event dates to delete
+     *
+     */
+    function delete_recurring() {
+        $item = $this->event->find('first', 'id=' . $this->params['id']);
+        if ($item->is_recurring == 1) { // need to give user options
+            expHistory::set('editable', $this->params);
+            assign_to_template(array(
+                'checked_date' => $this->params['date_id'],
+                'event'        => $item,
+            ));
+        } else { // Process a regular delete
+            $item->delete();
+        }
+    }
+
+    /**
+     * Delete selected event dates for a recurring event and event if all event dates deleted
+     *
+     */
+    function delete_selected() {
+        $item = $this->event->find('first', 'id=' . $this->params['id']);
+        if ($item && $item->is_recurring == 1) {
+            $event_remaining = false;
+            $eventdates = $item->eventdate[0]->find('all', 'event_id=' . $item->id);
+            foreach ($eventdates as $ed) {
+                if (array_key_exists($ed->id, $this->params['dates'])) {
+                    $ed->delete();
+                } else {
+                    $event_remaining = true;
+                }
+            }
+            if (!$event_remaining) {
+                $item->delete(); // model will also ensure we delete all event dates
+            }
+            expHistory::back();
+        } else {
+            notfoundController::handle_not_found();
+        }
+    }
+
+    function delete_all_past() {
+        $locsql = $this->aggregateWhereClause();
+        $ed = new eventdate();
+        $dates = $ed->find("all", $locsql . " AND date < " . strtotime('-1 months', time()));
+        foreach ($dates as $date) {
+            $date->delete(); // event automatically deleted if all assoc eventdates are deleted
+        }
+        expHistory::back();
+    }
+
+    /**
+   	 * get the metainfo for this module
+   	 * @return array
+   	 */
+   	function metainfo() {
+       global $router;
+
+        $action = $router->params['action'];
+        $metainfo = array('title' => '', 'keywords' => '', 'description' => '', 'canonical'=> '', 'noindex' => false, 'nofollow' => false);
+        // look for event date_id which expController::metainfo won't detect
+//        if (!empty($router->params['action']) && $router->params['action'] == 'show' && !isset($router->params['id']) && isset($router->params['date_id'])) {
+        switch ($action) {
+            case 'show':
+                if (!isset($router->params['id']) && isset($router->params['date_id'])) {
+                    // look up the record.
+                    $object = new eventdate((int)$router->params['date_id']);
+                    // set the meta info
+                    if (!empty($object)) {
+                        if (!empty($object->event->body)) {
+                            $desc = str_replace('"',"'",expString::summarize($object->event->body,'html','para'));
+                        } else {
+                            $desc = SITE_DESCRIPTION;
+                        }
+                        if (!empty($object->expTag)) {
+                            $keyw = '';
+                            foreach ($object->expTag as $tag) {
+                                if (!empty($keyw)) $keyw .= ', ';
+                                $keyw .= $tag->title;
+                            }
+                        } else {
+                            $keyw = SITE_KEYWORDS;
+                        }
+                        $metainfo['title'] = empty($object->event->meta_title) ? $object->event->title : $object->event->meta_title;
+                        $metainfo['keywords'] = empty($object->event->meta_keywords) ? $keyw : $object->event->meta_keywords;
+                        $metainfo['description'] = empty($object->event->meta_description) ? $desc : $object->event->meta_description;
+                        $metainfo['canonical'] = empty($object->event->canonical) ? $router->plainPath() : $object->event->canonical;
+                        $metainfo['noindex'] = empty($object->event->meta_noindex) ? false : $object->event->meta_noindex;
+                        $metainfo['nofollow'] = empty($object->event->meta_nofollow) ? false : $object->event->meta_nofollow;
+                        return $metainfo;
+                        break;
+                    }
+                }
+            default:
+                return parent::metainfo();
+        }
+    }
+
+    /**
+     * function to build a string to pull in all events within requested date range
+     */
+    function build_daterange_sql($timestamp, $endtimestamp=null, $field='date', $multiday=false) {
+        if (empty($endtimestamp)) {
+            $date_sql = "((".$field." >= " . expDateTime::startOfDayTimestamp($timestamp) . " AND ".$field." <= " . expDateTime::endOfDayTimestamp($timestamp) . ")";
+        } else {
+            $date_sql = "((".$field." >= " . expDateTime::startOfDayTimestamp($timestamp) . " AND ".$field." <= " . expDateTime::endOfDayTimestamp($endtimestamp) . ")";
+        }
+        if ($multiday)
+            $date_sql .= " OR (" . expDateTime::startOfDayTimestamp($timestamp) . " BETWEEN ".$field." AND dateFinished)";
+        $date_sql .= ")";
+        return $date_sql;
+    }
+
+    function send_feedback() {
+        $success = false;
+        if (isset($this->params['id'])) {
+            $ed = new eventdate($this->params['id']);
+//            $email_addrs = array();
+            if ($ed->event->feedback_email != '') {
+                $msgtemplate = expTemplate::get_template_for_action($this, 'email/_' . expString::escape($this->params['formname']), $this->loc);
+                $msgtemplate->assign('params', $this->params);
+                $msgtemplate->assign('event', $ed);
+                $email_addrs = explode(',', $ed->event->feedback_email);
+                //This is an easy way to remove duplicates
+                $email_addrs = array_flip(array_flip($email_addrs));
+                $email_addrs = array_map('trim', $email_addrs);
+                $mail = new expMail();
+                $success += $mail->quickSend(array(
+                    "text_message" => $msgtemplate->render(),
+                    'to'           => $email_addrs,
+                    'from'         => !empty($this->params['email']) ? $this->params['email'] : trim(SMTP_FROMADDRESS),
+                    'subject'      => $this->params['subject'],
+                ));
+            }
+        }
+
+        if ($success) {
+            flashAndFlow('message', gt('Your feedback was successfully sent.'));
+        } else {
+            flashAndFlow('error', gt('We could not send your feedback.  Please contact your administrator.'));
+        }
+    }
+
+    function ical() {
+        if (isset($this->params['date_id']) || isset($this->params['title']) || isset($this->params['src'])) {
+            $cfg = new expConfig();
+            $configs = $cfg->find('all', "location_data LIKE '%event%'"); // get all event module configs
+            foreach ($configs as $config) {
+                $loc = expUnserialize($config->location_data);
+                if (!empty($this->params['title'])) {
+                    if ($this->params['title'] == $config->config['feed_sef_url']) {
+                        $this->config = $config->config;
+                        break;
+                    }
+                } elseif (!empty($this->params['src'])) {
+                    if ($this->params['src'] == $loc->src) {
+                        $this->config = $config->config;
+                        break;
+                    }
+                }
+            }
+            $this->loc = $loc;
+
+            if ($this->config['enable_ical']) {
+                $ed = new eventdate();
+                if (isset($this->params['date_id'])) { // get single specific event only
+//                    $dates = array($db->selectObject("eventdate","id=".$this->params['date_id']));
+                    $dates = $ed->find('first', "id=" . $this->params['date_id']);
+                    $Filename = "Event-" . $this->params['date_id'];
+                } else {
+                    $locsql = $this->aggregateWhereClause();
+
+                    $day = expDateTime::startOfDayTimestamp(time());
+                    if (!empty($this->config['enable_ical']) && isset($this->config['rss_limit']) && ($this->config['rss_limit'] > 0)) {
+                        $rsslimit = " AND date <= " . ($day + ($this->config['rss_limit'] * 86400));
+                    } else {
+                        $rsslimit = "";
+                    }
+
+                    if (isset($this->params['time'])) {
+                        $time = intval($this->params['time']); // get current month's events
+//                        $dates = $db->selectObjects("eventdate",$locsql." AND (date >= ".expDateTime::startOfMonthTimestamp($time)." AND date <= ".expDateTime::endOfMonthTimestamp($time).")");
+                        $dates = $ed->find('all', $locsql . " AND (date >= " . expDateTime::startOfMonthTimestamp($time) . " AND date <= " . expDateTime::endOfMonthTimestamp($time) . ")");
+                    } else {
+                        $time = date('U', strtotime("midnight -1 month", time())); // previous month also
+//                        $dates = $db->selectObjects("eventdate",$locsql." AND date >= ".expDateTime::startOfDayTimestamp($time).$rsslimit);
+                        $dates = $ed->find('all', $locsql . " AND date >= " . expDateTime::startOfDayTimestamp($time) . $rsslimit);
+                    }
+                    //			$title = $db->selectValue('container', 'title', "internal='".serialize($loc)."'");
+                    $title = $this->config['feed_title'];
+                    $Filename = preg_replace('/\s+/', '', $title); // without whitespace
+                }
+
+                if (!function_exists("quoted_printable_encode")) { // function added in php v5.3.0
+                    function quoted_printable_encode($input, $line_max = 75) {
+                        $hex = array('0', '1', '2', '3', '4', '5', '6', '7',
+                            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
+                        $lines = preg_split("/(?:\r\n|\r|\n)/", $input);
+                        $linebreak = "=0D=0A=\r\n";
+                        /* the linebreak also counts as characters in the mime_qp_long_line
+                         * rule of spam-assassin */
+                        $line_max = $line_max - strlen($linebreak);
+                        $escape = "=";
+                        $output = "";
+                        $cur_conv_line = "";
+                        $length = 0;
+                        $whitespace_pos = 0;
+                        $addtl_chars = 0;
+
+                        // iterate lines
+                        for ($j = 0, $jMax = count($lines); $j < $jMax; $j++) {
+                            $line = $lines[$j];
+                            $linlen = strlen($line);
+
+                            // iterate chars
+                            for ($i = 0; $i < $linlen; $i++) {
+                                $c = substr($line, $i, 1);
+                                $dec = ord($c);
+
+                                $length++;
+
+                                if ($dec == 32) {
+                                    // space occurring at end of line, need to encode
+                                    if (($i == ($linlen - 1))) {
+                                        $c = "=20";
+                                        $length += 2;
+                                    }
+
+                                    $addtl_chars = 0;
+                                    $whitespace_pos = $i;
+                                } elseif (($dec == 61) || ($dec < 32) || ($dec > 126)) {
+                                    $h2 = floor($dec / 16);
+                                    $h1 = floor($dec % 16);
+                                    $c = $escape . $hex["$h2"] . $hex["$h1"];
+                                    $length += 2;
+                                    $addtl_chars += 2;
+                                }
+
+                                // length for wordwrap exceeded, get a newline into the text
+                                if ($length >= $line_max) {
+                                    $cur_conv_line .= $c;
+
+                                    // read only up to the whitespace for the current line
+                                    $whitesp_diff = $i - $whitespace_pos + $addtl_chars;
+
+                                    /* the text after the whitespace will have to be read
+                                     * again ( + any additional characters that came into
+                                     * existence as a result of the encoding process after the whitespace)
+                                     *
+                                     * Also, do not start at 0, if there was *no* whitespace in
+                                     * the whole line */
+                                    if (($i + $addtl_chars) > $whitesp_diff) {
+                                        $output .= substr($cur_conv_line, 0, (strlen($cur_conv_line) -
+                                            $whitesp_diff)) . $linebreak;
+                                        $i = $i - $whitesp_diff + $addtl_chars;
+                                    } else {
+                                        $output .= $cur_conv_line . $linebreak;
+                                    }
+
+                                    $cur_conv_line = "";
+                                    $length = 0;
+                                    $whitespace_pos = 0;
+                                } else {
+                                    // length for wordwrap not reached, continue reading
+                                    $cur_conv_line .= $c;
+                                }
+                            } // end of for
+
+                            $length = 0;
+                            $whitespace_pos = 0;
+                            $output .= $cur_conv_line;
+                            $cur_conv_line = "";
+
+                            if ($j <= count($lines) - 1) {
+                                $output .= $linebreak;
+                            }
+                        } // end for
+
+                        return trim($output);
+                    } // end quoted_printable_encode
+                }
+
+                $tz = DISPLAY_DEFAULT_TIMEZONE;
+                $msg = "BEGIN:VCALENDAR\n";
+                $msg .= "VERSION:2.0\n"; // version for iCalendar files vs vCalendar files
+                $msg .= "CALSCALE:GREGORIAN\n";
+                $msg .= "METHOD: PUBLISH\n";
+                $msg .= "PRODID:<-//ExponentCMS//EN>\n";
+                if (isset($this->config['rss_cachetime']) && ($this->config['rss_cachetime'] > 0)) {
+                    $msg .= "X-PUBLISHED-TTL:PT" . $this->config['rss_cachetime'] . "M\n";
+                }
+                $msg .= "X-WR-CALNAME:$Filename\n";
+
+//                $items = $this->getEventsForDates($dates);
+                $items = $this->event->getEventsForDates($dates);
+
+                for ($i = 0, $iMax = count($items); $i < $iMax; $i++) {
+
+                    // Convert events stored in local time to GMT
+                    $eventstart = new DateTime(date('r', $items[$i]->eventstart), new DateTimeZone($tz));
+                    $eventstart->setTimezone(new DateTimeZone('GMT'));
+                    $eventend = new DateTime(date('r', $items[$i]->eventend), new DateTimeZone($tz));
+                    $eventend->setTimezone(new DateTimeZone('GMT'));
+                    if ($items[$i]->is_allday) {
+                        $dtstart = "DTSTART;VALUE=DATE:" . date("Ymd", $items[$i]->eventstart) . "\n";
+                        $dtend = "DTEND;VALUE=DATE:" . date("Ymd", strtotime("midnight +1 day", $items[$i]->eventstart)) . "\n";
+                    } else {
+                        $dtstart = "DTSTART;VALUE=DATE-TIME:" . $eventstart->format("Ymd\THi00") . "Z\n";
+                        if ($items[$i]->eventend) {
+                            $dtend = "DTEND;VALUE=DATE-TIME:" . $eventend->format("Ymd\THi00") . "Z\n";
+                        } else {
+                            $dtend = "DTEND;VALUE=DATE-TIME:" . $eventstart->format("Ymd\THi00") . "Z\n";
+                        }
+                    }
+
+                    $body = trim(strip_tags(str_replace(array("<br />", "<br>", "br/>", "</p>"), "\n", $items[$i]->body)));
+                    if ($items[$i]->is_cancelled) $body = gt('This Event Has Been Cancelled') . ' - ' . $body;
+                    $body = str_replace(array("\r"), "", $body);
+                    $body = str_replace(array("&#160;"), " ", $body);
+                    $body = expString::convertSmartQuotes($body);
+                    if (!isset($this->params['style'])) {
+                        // it's going to Outlook so remove all formatting from body text
+                        $body = quoted_printable_encode($body);
+                    } elseif ($this->params['style'] == "g") {
+                        // It's going to Google (doesn't like quoted-printable, but likes html breaks)
+                        $body = str_replace(array("\n"), "<br />", $body);
+                    } else {
+                        // It's going elsewhere (doesn't like quoted-printable)
+                        $body = str_replace(array("\n"), " -- ", $body);
+                    }
+                    $title = $items[$i]->title;
+
+                    $msg .= "BEGIN:VEVENT\n";
+                    $msg .= $dtstart . $dtend;
+                    $msg .= "UID:" . $items[$i]->date_id . "\n";
+                    $msg .= "DTSTAMP:" . date("Ymd\THis", time()) . "Z\n";
+                    if ($title) {
+                        $msg .= "SUMMARY:$title\n";
+                    }
+                    if ($body) {
+                        $msg .= "DESCRIPTION;ENCODING=QUOTED-PRINTABLE:" . $body . "\n";
+                    }
+                    //	if($link_url) { $msg .= "URL: $link_url\n";}
+                    if (!empty($this->config['usecategories'])) {
+                        if (!empty($items[$i]->expCat[0]->title)) {
+                            $msg .= "CATEGORIES:".$items[$i]->expCat[0]->title."\n";
+                        } else {
+                            $msg .= "CATEGORIES:".$this->config['uncat']."\n";
+                        }
+                    }
+                    $msg .= "END:VEVENT\n";
+                }
+                $msg .= "END:VCALENDAR";
+
+                // Kick it out as a file download
+                ob_end_clean();
+
+                //	$mime_type = (EXPONENT_USER_BROWSER == 'IE' || EXPONENT_USER_BROWSER == 'OPERA') ? 'application/octet-stream;' : "text/x-vCalendar";
+                //	$mime_type = "text/x-vCalendar";
+                $mime_type = 'text/Calendar';
+                header('Content-Type: ' . $mime_type);
+                header('Expires: ' . gmdate('D, d M Y H:i:s') . ' GMT');
+                header('Content-length: ' . strlen($msg));
+                header('Content-Transfer-Encoding: binary');
+                header('Content-Encoding:');
+                //	header("Content-Disposition: inline; filename=".$Filename.".ics");
+                header('Content-Disposition: attachment; filename="' . $Filename . '.ics"');
+                // IE need specific headers
+                //	if (EXPONENT_USER_BROWSER == 'IE') {
+                header('Cache-Control: no-cache, must-revalidate');
+                header('Pragma: public');
+                header('Vary: User-Agent');
+                //	} else {
+                header('Pragma: no-cache');
+                //	}
+                echo $msg;
+                exit();
+            } else {
+                notfoundController::handle_not_found();
+            }
+        } else {
+            notfoundController::handle_not_found();
+        }
+    }
+
+    function send_reminders() {
+        if (isset($this->params['title']) || isset($this->params['src'])) {
+            $cfg = new expConfig();
+            $configs = $cfg->find('all', "location_data LIKE '%event%'"); // get all event module configs
+            foreach ($configs as $config) {
+                $loc = expUnserialize($config->location_data);
+                if (!empty($this->params['title'])) {
+                    if ($this->params['title'] == $config->config['feed_sef_url']) {
+                        $this->config = $config->config;
+                        break;
+                    }
+                } elseif (!empty($this->params['src'])) {
+                    if ($this->params['src'] == $loc->src) {
+                        $this->config = $config->config;
+                        break;
+                    }
+                }
+            }
+
+            if (empty($this->config['reminder_active'])) {
+                notfoundController::handle_not_found();
+                return;
+            }
+            if (!empty($this->config['reminder_code']) && (empty($this->params['code']) || ($this->params['code'] != $this->config['reminder_code']))) {
+                notfoundController::handle_not_authorized();
+                return;
+            }
+
+            $this->loc = $loc;
+            $locsql = $this->aggregateWhereClause();
+
+            $view = (isset($this->params['view']) ? $this->params['view'] : '');
+            if ($view == "") {
+                $view = "send_reminders"; // default reminder view
+            }
+
+//            $template = expTemplate::get_template_for_action($this, $view, $this->loc);
+            global $template;
+
+            $title = $this->config['feed_title'];
+            $template->assign('moduletitle', $title);
+
+            $time = (isset($this->params['time']) ? intval($this->params['time']) : time());
+            $time = (int)$time;
+
+            $template->assign("time", $time);
+
+            $startperiod = expDateTime::startOfDayTimestamp($time);
+            if (!empty($this->params['days'])) {
+                $totaldays = $this->params['days'];
+            } else {
+                $totaldays = 7; // default 7 days of events
+            }
+
+            $count = 0;
+            $info = getdate($startperiod);
+            for ($i = 0; $i < $totaldays; $i++) {
+                $start = mktime(0, 0, 0, $info['mon'], $info['mday'] + $i, $info['year']);
+                $ed = new eventdate();
+                $edates = $ed->find('all', $locsql . " AND (date >= " . expDateTime::startOfDayTimestamp($start) . " AND date <= " . expDateTime::endOfDayTimestamp($start) . ")");
+                $days[$start] = array();
+//                $days[$start] = $this->getEventsForDates($edates);
+                $days[$start] = $this->event->getEventsForDates($edates);
+                for ($j = 0, $jMax = count($days[$start]); $j < $jMax; $j++) {
+                    $thisloc = expCore::makeLocation($loc->mod, $loc->src, $days[$start][$j]->id);
+                    $days[$start][$j]->permissions = array(
+                        "manage" => (expPermissions::check("manage", $thisloc) || expPermissions::check("manage", $loc)),
+                        "edit"   => (expPermissions::check("edit", $thisloc) || expPermissions::check("edit", $loc)),
+                        "delete" => (expPermissions::check("delete", $thisloc) || expPermissions::check("delete", $loc))
+                    );
+                }
+                $counts[$start] = count($days[$start]);
+                $count += count($days[$start]);
+                $days[$start] = expSorter::sort(array('array' => $days[$start], 'sortby' => 'eventstart', 'order' => 'ASC'));
+            }
+            $template->assign("days", $days);
+            $template->assign("counts", $counts);
+            $template->assign("start", $startperiod);
+            $template->assign("totaldays", $totaldays);
+
+            if ($count == 0) {
+                flash('error',gt('No Events to Send!'));
+                echo show_msg_queue('error');
+                return;
+            }
+
+            if (bs3())
+                $css = file_get_contents(BASE . "external/bootstrap3/css/bootstrap.css");
+            elseif (bs2())
+                $css = file_get_contents(BASE . "external/bootstrap/css/bootstrap.css");
+            else
+                $css = file_get_contents(BASE . "framework/modules/events/assets/css/calendar.css");
+            $template->assign("css", $css);
+            $template->assign("config", $this->config);
+            $template->assign("src", $loc->src);
+
+            // format and send email
+            $subject = $this->config['email_title_reminder'] . " - $title";
+            $from_addr = $this->config['email_address_reminder'];
+            $headers = array(
+                "From"     => $from = $this->config['email_from_reminder'],
+                "Reply-to" => $reply = $this->config['email_reply_reminder']
+            );
+
+            // set up the html message
+            $template->assign("showdetail", !empty($this->config['email_showdetail']));
+            $htmlmsg = $template->render();
+
+            // now the same thing for the text message
+            $msg = preg_replace('/(<script[^>]*>.+?<\/script>|<style[^>]*>.+?<\/style>)/s', '', $htmlmsg); // remove any script or style blocks
+            $msg = trim(strip_tags(str_replace(array("<br />", "<br>", "br/>"), "\n", $msg)));
+
+            // Saved.  do notifs
+            $emails = array();
+            if (!empty($this->config['user_list'])) foreach ($this->config['user_list'] as $c) {
+                $u = user::getUserById($c);
+                $emails[$u->email] = trim(user::getUserAttribution($u->id));
+            }
+            if (!empty($this->config['group_list'])) foreach ($this->config['group_list'] as $c) {
+                $grpusers = group::getUsersInGroup($c);
+                foreach ($grpusers as $u) {
+                    $emails[$u->email] = trim(user::getUserAttribution($u->id));
+                }
+            }
+            if (!empty($this->config['address_list'])) foreach ($this->config['address_list'] as $c) {
+                $emails[] = $c;
+            }
+            if (empty($emails)) {
+                flash('error',gt('No One to Send Reminders to!'));
+                echo show_msg_queue('error');
+                return;
+            }
+
+            $emails = array_flip(array_flip($emails));
+            $emails = array_map('trim', $emails);
+//            $headers = array(
+//                "MIME-Version" => "1.0",
+//                "Content-type" => "text/html; charset=" . LANG_CHARSET
+//            );
+            $mail = new expMail();
+            $mail->quickSend(array(
+//                'headers'      => $headers,
+                'html_message' => $htmlmsg,
+                "text_message" => $msg,
+                'to'           => $emails,
+                'from'         => array(trim($this->config['email_address_reminder']) => $this->config['email_from_reminder']),
+                'subject'      => $subject,
+            ));
+
+            flash('message',gt('The following reminder was sent via email'));
+            echo show_msg_queue();
+//            echo($htmlmsg);
+        } else {
+            flash('error',gt('No Calendar Selected!'));
+            echo show_msg_queue('error');
+        }
+    }
+
+    /** @deprecated moved to event model
+     * @param $edates
+     * @param bool $sort_asc
+     * @param bool $featuredonly
+     * @param bool $condense
+     * @return array
+     */
+    function getEventsForDates($edates, $sort_asc = true, $featuredonly = false, $condense = false) {
+        global $eventid;
+
+        $events = array();
+        $featuresql = "";
+        if ($featuredonly) $featuresql = " AND is_featured=1";
+        foreach ($edates as $edate) {
+            $evs = $this->event->find('all', "id=" . $edate->event_id . $featuresql);
+            foreach ($evs as $key=>$event) {
+                if ($condense) {
+                    $eventid = $event->id;
+                    $multiday_event = array_filter($events, create_function('$event', 'global $eventid; return $event->id === $eventid;'));
+                    if (!empty($multiday_event)) {
+                        unset($evs[$key]);
+                        continue;
+                    }
+                }
+                $evs[$key]->eventstart += $edate->date;
+                $evs[$key]->eventend += $edate->date;
+                $evs[$key]->date_id = $edate->id;
+                if (!empty($event->expCat)) {
+                    $catcolor = empty($event->expCat[0]->color) ? null : trim($event->expCat[0]->color);
+//                    if (substr($catcolor,0,1)=='#') $catcolor = '" style="color:'.$catcolor.';';
+                    $evs[$key]->color = $catcolor;
+                }
+            }
+            if (count($events) < 500) {  // magic number to not crash loop?
+                $events = array_merge($events, $evs);
+            } else {
+//                $evs[$key]->title = gt('Too many events to list').', '.(count($edates)-count($events)).' '.gt('not displayed!');
+//                $events = array_merge($events, $evs);
+                flash('notice',gt('Too many events to list').', '.(count($edates)-count($events)).' '.gt('not displayed!'));
+                break; // keep from breaking system by too much data
+            }
+        }
+        $events = expSorter::sort(array('array' => $events, 'sortby' => 'eventstart', 'order' => $sort_asc ? 'ASC' : 'DESC'));
+        return $events;
+    }
+
+    function getExternalEvents($startdate, $enddate, $multiday = false) {
+        global $db;
+
+        $extevents = array();
+        $dy = 0;  // index of events array
+        if (!empty($this->config['pull_gcal'])) foreach ($this->config['pull_gcal'] as $key=>$extgcalurl) {
+//            $dy = count($extevents);  // index of events array
+            $cache_hit = false;
+            $gcal_cname = str_replace(array("/",":","&","?"),"_",$extgcalurl);
+            $cache_fname = BASE.'tmp/cache/'.$gcal_cname.".cache";
+            if (file_exists($cache_fname)) {
+                $cache = unserialize(file_get_contents($cache_fname));
+                if ($startdate >= $cache['start_date'] || $startdate >= $cache['first_date']) {
+                    $events = $db->selectObjects('event_cache','feed="'.$extgcalurl.'" AND ' . self::build_daterange_sql($startdate,$enddate,'eventdate',true));
+                    foreach ($events as $event) {
+                        if ($multiday) {
+                            $extevents[$event->eventdate][$dy] = $event;
+                            $extevents[$event->eventdate][$dy]->feedkey = $key;
+                            $extevents[$event->eventdate][$dy]->location_data = 'gcalevent' . $key;
+                            $extevents[$event->eventdate][$dy]->color = !empty($this->config['pull_gcal_color'][$key]) ? $this->config['pull_gcal_color'][$key] : null;
+                            if ($event->is_allday) {
+                                $extevents[$event->eventdate][$dy]->eventstart = $event->eventdate;
+                            }
+                            $dy++;
+                        } else {
+                            $endit = !empty($event->dateFinished) ? $event->dateFinished : $event->eventdate;
+//                            for ($i = $startdate; $i < $enddate; $i += 86400) {
+                            for ($i = $event->eventdate; $i <= $endit; $i += 86400) {
+                                if ((!empty($event->dateFinished) && $i > $event->dateFinished) || (empty($event->dateFinished) && $i > $event->eventdate)) {
+                                    break;
+                                } else {
+                                    $extevents[$i][$dy] = clone($event);
+                                    $extevents[$i][$dy]->eventdate = (int)$i;
+                                    $extevents[$i][$dy]->eventstart = ($event->eventstart - $event->eventdate);
+                                    $extevents[$i][$dy]->eventend = ($event->eventend - (!empty($event->dateFinished)?$event->dateFinished:$event->eventdate));
+                                    $extevents[$i][$dy]->eventstart = ($extevents[$i][$dy]->eventstart) + $i;
+                                    $extevents[$i][$dy]->eventend = ($extevents[$i][$dy]->eventend) + $i;
+                                    $extevents[$i][$dy]->feedkey = $key;
+                                    $extevents[$i][$dy]->location_data = 'gcalevent' . $key;
+                                    $extevents[$i][$dy]->color = !empty($this->config['pull_gcal_color'][$key]) ? $this->config['pull_gcal_color'][$key] : null;
+                                    $dy++;
+                                }
+                            }
+                        }
+                    }
+                    $cache_hit = true;
+                }
+            }
+            if (!$cache_hit) { // pull in the external events
+                foreach ($this->get_gcal_events($extgcalurl, $startdate, $enddate, $dy, $key, $multiday) as $date=>$events) {
+                    foreach ($events as $event) {
+                        $extevents[$date][] = $event;
+                    }
+                }
+            }
+        }
+        if (!empty($this->config['pull_ical'])) foreach ($this->config['pull_ical'] as $key=>$exticalurl) {
+//            $dy = count($extevents);  // index of events array
+            $cache_hit = false;
+            $ical_cname = str_replace(array("/",":","&","?"),"_",$exticalurl);
+            $cache_fname = BASE.'tmp/cache/'.$ical_cname.".cache";
+            if (file_exists($cache_fname)) {
+                $cache = unserialize(file_get_contents($cache_fname));
+                if ($startdate >= $cache['start_date'] || $startdate >= $cache['first_date']) {
+                    $events = $db->selectObjects('event_cache','feed="'.$exticalurl.'" AND ' . self::build_daterange_sql($startdate,$enddate,'eventdate',true));
+                    foreach ($events as $event) {
+                        $extevents[$event->eventdate][$dy] = $event;
+                        $extevents[$event->eventdate][$dy]->location_data = 'icalevent' . $key;
+                        $extevents[$event->eventdate][$dy]->color = !empty($this->config['pull_ical_color'][$key]) ? $this->config['pull_ical_color'][$key] : null;
+                        $dy++;
+                    }
+                    $cache_hit = true;
+                }
+            }
+            if (!$cache_hit) {  // pull in the external events
+                foreach ($this->get_ical_events($exticalurl, $startdate, $enddate, $dy, $key, $multiday) as $date=>$events) {
+                    foreach ($events as $event) {
+                        $extevents[$date][] = $event;
+                    }
+                }
+            }
+        }
+        return $extevents;
+    }
+
+    public function get_gcal_events($extgcalurl, $startdate, $enddate=null, &$dy=0, $key=0, $multiday=false) {
+        $extevents = array();
+        if (!empty($startdate)) $begin = date("Y-m-d\Th:i:sP", expDateTime::startOfDayTimestamp($startdate));
+        if (!empty($enddate)) $end = date("Y-m-d\Th:i:sP", expDateTime::endOfDayTimestamp($enddate));
+            else $end = date("Y-m-d\Th:i:sP", (expDateTime::endOfDayTimestamp($startdate + ((3600*24)*30))));
+
+        if (substr($extgcalurl, -5) == 'basic') {
+            $extgcalurl = substr($extgcalurl, 0, - 5) . 'full';
+        }
+        $feed = $extgcalurl . "?orderby=starttime&singleevents=true";
+        if (!empty($startdate)) $feed .= "&start-min=" . $begin;
+        if (!empty($enddate)) $feed .= "&start-max=" . $end;
+
+        // XML method
+//            $s = simplexml_load_file($feed);
+//            foreach ($s->entry as $item) {
+//                $gd = $item->children('http://schemas.google.com/g/2005');
+//                if (!empty($gd->when)) {
+//                   $dtstart = $gd->when->attributes()->startTime;
+//                } elseif (!empty($gd->recurrence)){
+//                   $dtstart = $gd->recurrence->when->attributes()->startTime;
+//                } else {
+//                    $dtstart = $item->attributes()->When;
+//                }
+//                //FIXME must convert $dtstart timezone
+//                $eventdate = expDateTime::startOfDayTimestamp(strtotime($dtstart));
+//                $ourtzoffsets = (int)(date('O',$eventdate)) * 36;
+//                $theirtzoffset = -((int)(substr($dtstart,-5,2)) * 3600);
+//                $tzoffset = $ourtzoffsets - $theirtzoffset;
+//                $extevents[$eventdate][$dy] = new stdClass();
+//                $extevents[$eventdate][$dy]->eventdate = $eventdate;
+//                $extevents[$eventdate][$dy]->eventstart += strtotime($dtstart) + $tzoffset;
+//                if (!empty($gd->when)) {
+//                    $dtend = $gd->when->attributes()->endTime;
+//                } elseif (!empty($gd->recurrence)) {
+//                    $dtend = $gd->recurrence->when->attributes()->endTime;
+//                }
+//                //FIXME must convert $dtend timezone
+//                if (!empty($dtend)) $extevents[$eventdate][$dy]->eventend += strtotime($dtend) + $tzoffset;
+//                // dtstart required, one occurrence, (orig. start date)
+//                $extevents[$eventdate][$dy]->title = $item->title;
+//                $extevents[$eventdate][$dy]->body = $item->content;
+        // End XML method
+
+        // DOM method
+        $doc = new DOMDocument();
+        $doc->load($feed);
+        $entries = $doc->getElementsByTagName("entry");
+        foreach ($entries as $item) {
+            $times = $item->getElementsByTagName("when");
+            $dtstart = $times->item(0)->getAttributeNode("startTime")->value;
+            $eventdate = expDateTime::startOfDayTimestamp(strtotime($dtstart));
+            $extevents[$eventdate][$dy] = new stdClass();
+            $extevents[$eventdate][$dy]->eventdate = $eventdate;
+            $dtend = @$times->item(0)->getAttributeNode("endTime")->value;
+            $ourtzoffsets = (int)date('O',$eventdate) * 36;
+            $theirtzoffset = -((int)substr($dtstart,-5,2) * 3600);
+            $tzoffset = $ourtzoffsets - $theirtzoffset;
+            if (strlen($dtstart) > 10) {
+                $extevents[$eventdate][$dy]->eventstart = ((int)substr($dtstart, 11, 2) * 3600) + ((int)substr($dtstart, 14, 2) * 60) + $tzoffset;
+//                    if (date("I", $eventdate)) $extevents[$eventdate][$dy]->eventstart += 3600;
+                $extevents[$eventdate][$dy]->eventend = ((int)substr($dtend, 11, 2) * 3600) + ((int)substr($dtend, 14, 2) * 60) + $tzoffset;
+//                    if (date("I", $eventdate)) $extevents[$eventdate][$dy]->eventend += 3600;
+            } else {
+                $extevents[$eventdate][$dy]->eventstart = null;
+                $extevents[$eventdate][$dy]->is_allday = 1;
+            }
+            $extevents[$eventdate][$dy]->eventstart += $eventdate;
+            $extevents[$eventdate][$dy]->eventend += $eventdate;
+            if (empty($dtend)) $extevents[$eventdate][$dy]->eventend = $extevents[$eventdate][$dy]->eventstart;
+
+            $titles = $item->getElementsByTagName("title");
+            $extevents[$eventdate][$dy]->title = $titles->item(0)->nodeValue;
+            $contents = $item->getElementsByTagName("content");
+            $extevents[$eventdate][$dy]->body = $contents->item(0)->nodeValue;
+            // End DOM method
+
+//                    $extevents[$eventdate][$dy]->location_data = serialize(expCore::makeLocation('extevent',$extcal->id));
+            $extevents[$eventdate][$dy]->location_data = 'gcalevent' . $key;
+            $extevents[$eventdate][$dy]->color = !empty($this->config['pull_gcal_color'][$key]) ? $this->config['pull_gcal_color'][$key] : null;
+            $dy++;
+        }
+        return $extevents;
+    }
+
+    public function get_ical_events($exticalurl, $startdate=null, $enddate=null, &$dy=0, $key=0, $multiday=false) {
+        $extevents = array();
+//            require_once BASE . 'external/iCalcreator.class.php';
+        require_once BASE . 'external/iCalcreator-2.22/iCalcreator.php';
+        $v = new vcalendar(); // initiate new CALENDAR
+        if (stripos($exticalurl, 'http') === 0) {
+            $v->setConfig('url', $exticalurl);
+        } else {
+            $v->setConfig('directory', dirname($exticalurl));
+            $v->setConfig('filename', basename($exticalurl));
+        }
+        $v->parse();
+        if ($startdate === null) {
+            $startYear = false;
+            $startMonth = false;
+            $startDay = false;
+        } else {
+            $startYear = date('Y', $startdate);
+            $startMonth = date('n', $startdate);
+            $startDay = date('j', $startdate);
+        }
+        if ($enddate === null) {
+            $endYear = $startYear+1;
+            $endMonth = $startMonth;
+            $endDay = $startDay;
+        } else {
+            $endYear = date('Y', $enddate);
+            $endMonth = date('n', $enddate);
+            $endDay = date('j', $enddate);
+        }
+        // get all events within period split out recurring events as single events per each day
+        $eventArray = $v->selectComponents($startYear, $startMonth, $startDay, $endYear, $endMonth, $endDay, 'vevent');
+        // Set the timezone to GMT
+        @date_default_timezone_set('GMT');
+        $tzarray = getTimezonesAsDateArrays($v);
+        // Set the default timezone
+        @date_default_timezone_set(DISPLAY_DEFAULT_TIMEZONE);
+        if (!empty($eventArray)) foreach ($eventArray as $year => $yearArray) {
+            if (!empty($yearArray)) foreach ($yearArray as $month => $monthArray) {
+                if (!empty($monthArray)) foreach ($monthArray as $day => $dailyEventsArray) {
+                    if (!empty($dailyEventsArray)) foreach ($dailyEventsArray as $vevent) {
+                        // process each event
+                        $yesterday = false;
+                        $currdate = $vevent->getProperty('x-current-dtstart');
+                        $thisday = explode('-', $currdate[1]);
+                        $thisday2 = substr($thisday[2], 0, 2);
+                        // if member of a recurrence set,
+                        // returns array( 'x-current-dtstart', <DATE>)
+                        // <DATE> = (string) date("Y-m-d [H:i:s][timezone/UTC offset]")
+                        $dtstart = $vevent->getProperty('dtstart', false, true);
+                        $dtend = $vevent->getProperty('dtend', false, true);
+                        if (empty($dtend))
+                            $dtend = $dtstart;
+
+                        // calculate the cumulative timezone offset in seconds to convert to local/system time
+                        $tzoffsets = array();
+                        $date_tzoffset = 0;
+                        if (!empty($tzarray)) {
+//                                $ourtzoffsets = -(iCalUtilityFunctions::_tz2offset(date('O',time())));
+                            $ourtzoffsets = -(iCalUtilityFunctions::_tz2offset(date('O',self::_date2timestamp($dtstart['value']))));
+                            // Set the timezone to GMT
+                            @date_default_timezone_set('GMT');
+                            if (!empty($dtstart['params']['TZID'])) $tzoffsets = getTzOffsetForDate($tzarray, $dtstart['params']['TZID'], $dtstart['value']);
+                            // Set the default timezone
+                            @date_default_timezone_set(DISPLAY_DEFAULT_TIMEZONE);
+                            if (isset($tzoffsets['offsetSec'])) $date_tzoffset = $ourtzoffsets + $tzoffsets['offsetSec'];
+                        }
+                        if (empty($tzoffsets)) {
+                            $date_tzoffset = -(iCalUtilityFunctions::_tz2offset(date('O',self::_date2timestamp($dtstart['value']))));
+                        }
+                        //FIXME we must have the real timezone offset for the date by this point
+
+                        //FIXME this is for the google ical feed which is bad!
+                        if ($dtstart['value']['day'] != (int)$thisday2 && (isset($dtstart['value']['day']) && isset($dtend['value']['hour']))&&
+                            !((int)$dtstart['value']['hour'] == 0 && (int)$dtstart['value']['min'] == 0  && (int)$dtstart['value']['sec'] == 0
+                                && (int)$dtend['value']['hour'] == 0 && (int)$dtend['value']['min'] == 0  && (int)$dtend['value']['sec'] == 0
+                                && ((((int)$dtstart['value']['day'] - (int)$dtend['value']['day']) == -1) || (((int)$dtstart['value']['month'] - (int)$dtend['value']['month']) == -1) || (((int)$dtstart['value']['month'] - (int)$dtend['value']['month']) == -11)))) {
+                            $dtst = strtotime($currdate[1]);
+                            $dtst1 = iCalUtilityFunctions::_timestamp2date($dtst);
+                            $dtstart['value']['year'] = $dtst1['year'];
+                            $dtstart['value']['month'] = $dtst1['month'];
+                            $dtstart['value']['day'] = $dtst1['day'];
+                            $currenddate = $vevent->getProperty('x-current-dtend');
+                            $dtet = strtotime($currenddate[1]);
+                            $dtet1 = iCalUtilityFunctions::_timestamp2date($dtet);
+                            $dtend['value']['year'] = $dtet1['year'];
+                            $dtend['value']['month'] = $dtet1['month'];
+                            $dtend['value']['day'] = $dtet1['day'];
+//                                $date_tzoffset = 0;
+                        }
+
+                        if (!empty($dtstart['value']['hour']) && !((int)$dtstart['value']['hour'] == 0 && (int)$dtstart['value']['min'] == 0  && (int)$dtstart['value']['sec'] == 0
+                                                            && (int)$dtend['value']['hour'] == 0 && (int)$dtend['value']['min'] == 0  && (int)$dtend['value']['sec'] == 0
+                                                            && ((((int)$dtstart['value']['day'] - (int)$dtend['value']['day']) == -1) || (((int)$dtstart['value']['month'] - (int)$dtend['value']['month']) == -1) || (((int)$dtstart['value']['month'] - (int)$dtend['value']['month']) == -11)))) {
+                            $eventdate = expDateTime::startOfDayTimestamp(self::_date2timestamp($dtstart['value']) - $date_tzoffset);
+//                                $eventend = expDateTime::startOfDayTimestamp(self::_date2timestamp($dtend['value']) - $date_tzoffset);
+                            $extevents[$eventdate][$dy] = new stdClass();
+                            $extevents[$eventdate][$dy]->eventdate = new stdClass();
+                            $extevents[$eventdate][$dy]->eventdate->date = $eventdate;
+//                                if ((int)($dtstart['value']['hour']) == 0 && (int)($dtstart['value']['min']) == 0  && (int)($dtstart['value']['sec']) == 0
+//                                    && (int)($dtend['value']['hour']) == 0 && (int)($dtend['value']['min']) == 0  && (int)($dtend['value']['sec']) == 0
+//                                    && ((((int)($dtstart['value']['day']) - (int)($dtend['value']['day'])) == -1) || (((int)($dtstart['value']['month']) - (int)($dtend['value']['month'])) == -1) || (((int)($dtstart['value']['month']) - (int)($dtend['value']['month'])) == -11))) {
+////                                    if ($dtstart['value']['day'] != (int)($thisday2)) {
+//                                    if (date('d',$eventdate) != $thisday2) {
+////                                    if (date('d',$eventdate) != date('d',$eventend)) {
+//                                        $yesterday = true;
+//                                    } else {
+//                                        $extevents[$eventdate][$dy]->eventstart = null;
+//                                        $extevents[$eventdate][$dy]->is_allday = 1;
+//                                    }
+//                                } else {
+                                if (date('d',$eventdate) != $thisday2) {
+//                                    if (date('d',$eventdate) != date('d',$eventend)) {
+                                    $yesterday = true;
+                                } else {
+                                    $extevents[$eventdate][$dy]->eventstart = ($dtstart['value']['hour'] * 3600) + ($dtstart['value']['min'] * 60) - $date_tzoffset;
+//                                        if (date("I", $eventdate)) $extevents[$eventdate][$dy]->eventstart += 3600; // adjust for daylight savings time
+                                }
+//                                }
+                        } else {
+                            // this is an all day event
+                            $eventdate = expDateTime::startOfDayTimestamp(self::_date2timestamp($dtstart['value']));
+//                                $eventend = expDateTime::startOfDayTimestamp(self::_date2timestamp($dtend['value']));
+                            $extevents[$eventdate][$dy] = new stdClass();
+                            $extevents[$eventdate][$dy]->eventdate = new stdClass();
+                            $extevents[$eventdate][$dy]->eventdate->date = $eventdate;
+//                                if ($dtstart['value']['day'] != (int)($thisday2)) {
+                            if (date('d',$eventdate) != $thisday2) {
+//                                if (date('d',$eventdate) != date('d',$eventend)) {
+                                $yesterday = true;
+                            } else {
+                                $extevents[$eventdate][$dy]->eventstart = null;
+                                $extevents[$eventdate][$dy]->is_allday = 1;
+                            }
+                        }
+
+                        // set the end time if needed
+                        if (!$yesterday && isset($dtend['value']['hour']) && empty($extevents[$eventdate][$dy]->is_allday)) {
+//                                if ($dtend['value']['day'] != (int)($thisday2)) {
+//                                if ((date('d',$eventend) != $thisday2)) {
+//                                    $yesterday = true;
+//                                } else {
+                            $extevents[$eventdate][$dy]->eventend = ($dtend['value']['hour'] * 3600) + ($dtend['value']['min'] * 60) - $date_tzoffset;
+//                                if (date("I", $eventdate)) $extevents[$eventdate][$dy]->eventend += 3600; // adjust for daylight savings time
+//                                }
+                        }
+
+                        // convert the start and end times to a full date
+                        if (isset($extevents[$eventdate][$dy]->eventstart) && $extevents[$eventdate][$dy]->eventstart != null)
+                            $extevents[$eventdate][$dy]->eventstart += $eventdate;
+                        if (isset($extevents[$eventdate][$dy]->eventend))
+                            $extevents[$eventdate][$dy]->eventend += $eventdate;
+
+                        // dtstart required, one occurrence, (orig. start date)
+                        $extevents[$eventdate][$dy]->title = $vevent->getProperty('summary');
+                        $body = $vevent->getProperty('description');
+                        // convert end of lines
+                        $body = nl2br(str_replace("\\n"," <br>\n",$body));
+                        $body = str_replace("\n"," <br>\n",$body);
+                        $body = str_replace(array('==0A','=0A','=C2=A0')," <br>\n",$body);
+                        $extevents[$eventdate][$dy]->body = $body;
+                        $extevents[$eventdate][$dy]->location_data = 'icalevent' . $key;
+                        $extevents[$eventdate][$dy]->color = !empty($this->config['pull_ical_color'][$key]) ? $this->config['pull_ical_color'][$key] : null;
+                        if (!$yesterday && $eventdate >= $startdate) {
+                            $dy++;
+                        } else {
+                            unset($extevents[$eventdate][$dy]);
+                        }
+                    }
+                }
+            }
+        }
+        return $extevents;
+    }
+
+    public static function _date2timestamp( $datetime, $wtz=null ) {
+      if( !isset( $datetime['hour'] )) $datetime['hour'] = 0;
+      if( !isset( $datetime['min'] ))  $datetime['min']  = 0;
+      if( !isset( $datetime['sec'] ))  $datetime['sec']  = 0;
+      if( empty( $wtz ) && ( !isset( $datetime['tz'] ) || empty(  $datetime['tz'] )))
+        return mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year'] );
+      $output = $offset = 0;
+      if( empty( $wtz )) {
+        if( iCalUtilityFunctions::_isOffset( $datetime['tz'] )) {
+          $offset = iCalUtilityFunctions::_tz2offset( $datetime['tz'] ) * -1;
+          $wtz    = 'UTC';
+        }
+        else
+          $wtz    = $datetime['tz'];
+      }
+      if(( 'Z' == $wtz ) || ( 'GMT' == strtoupper( $wtz )))
+        $wtz      = 'UTC';
+      try {
+        $strdate  = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', $datetime['year'], $datetime['month'], $datetime['day'], $datetime['hour'], $datetime['min'], $datetime['sec'] );
+        $d        = new DateTime( $strdate, new DateTimeZone( $wtz ));
+        if( 0    != $offset )  // adjust for offset
+          $d->modify( $offset.' seconds' );
+        $output   = $d->format( 'U' );
+        unset( $d );
+      }
+      catch( Exception $e ) {
+        $output = mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year'] );
+      }
+      return $output;
+    }
+
+    /**
+     * build/update the external event cache
+     *
+     */
+    public function build_cache() {
+        global $db;
+
+        // get our requested config
+        $cfg = new expConfig();
+        $configs = $cfg->find('all', "location_data LIKE '%event%'"); // get all event module configs
+        foreach ($configs as $config) {
+            $loc = expUnserialize($config->location_data);
+            if (!empty($this->params['title'])) {
+                if ($this->params['title'] == $config->config['feed_sef_url']) {
+                    $this->config = $config->config;
+                    break;
+                }
+            } elseif (!empty($this->params['src'])) {
+                if ($this->params['src'] == $loc->src) {
+                    $this->config = $config->config;
+                    break;
+                }
+            }
+        }
+
+        // next loop through our config pull urls
+
+        // google xml pull
+        if (!empty($this->config['pull_gcal'])) foreach ($this->config['pull_gcal'] as $key=>$extgcalurl) {
+            $start = expDateTime::startOfMonthTimestamp(time());
+            $gcal_cname = str_replace(array("/",":","&","?"),"_",$extgcalurl);
+            $cache_fname = BASE.'tmp/cache/'.$gcal_cname.".cache";
+            $db->delete('event_cache', "feed='" . $extgcalurl . "' AND eventdate > " . $start);  // replace future events
+            // loop through 12 months, 1 month at a time
+            for ($i=1; $i < 13; $i++) {
+                $end = expDateTime::endOfMonthTimestamp($start);
+                $tmp = 0;
+                $extevents = $this->get_gcal_events($extgcalurl, $start, $end, $tmp, 0, true);
+//                $extevents = $this->get_gcal_events($extgcalurl, null, null, 0, 0, 0, true);
+                foreach ($extevents as $day) {
+                    foreach ($day as $extevent) {
+                        $event_cache = new stdClass();
+                        $event_cache->feed = $extgcalurl;
+                        $event_cache->event_id = $extevent->event_id;
+                        $event_cache->title = $extevent->title;
+                        $event_cache->body = $extevent->body;
+                        $event_cache->eventdate = $extevent->eventdate->date;
+                        if (isset($extevent->dateFinished) && $extevent->dateFinished != -68400)
+                            $event_cache->dateFinished = $extevent->dateFinished;
+                        if (isset($extevent->eventstart))
+                            $event_cache->eventstart = $extevent->eventstart;
+                        if (isset($extevent->eventend))
+                            $event_cache->eventend = $extevent->eventend;
+                        if (isset($extevent->is_allday))
+                            $event_cache->is_allday = $extevent->is_allday;
+                        $found = false;
+                        if ($extevent->eventdate->date < $start)   // prevent duplicating events crossing month boundaries
+                            $found = $db->selectObject('event_cache','feed="'.$extgcalurl.'" AND event_id="'.$event_cache->event_id.'" AND eventdate='.$event_cache->eventdate);
+                        if (!$found)
+                            $db->insertObject($event_cache,'event_cache');
+                    }
+                }
+                $start = expDateTime::startOfMonthTimestamp($end + 1024);
+            }
+            $cache_contents = serialize(array('start_date'=>$start,'first_date'=>(int)$db->selectValue('event_cache','eventdate','feed="'.$extgcalurl.'" ORDER BY eventdate'),'refresh_date'=>time()));
+            file_put_contents($cache_fname, $cache_contents);
+        }
+
+        // ical pull
+        $start = expDateTime::startOfMonthTimestamp(time());
+        if (!empty($this->config['pull_ical'])) foreach ($this->config['pull_ical'] as $key=>$exticalurl) {
+            $ical_cname = str_replace(array("/",":","&","?"),"_",$exticalurl);
+            $cache_fname = BASE.'tmp/cache/'.$ical_cname.".cache";
+            $db->delete('event_cache', "feed='" . $exticalurl . "' AND eventdate > " . $start);
+            // get 1 years worth of events
+            $extevents = $this->get_ical_events($exticalurl, $start);
+            foreach ($extevents as $day) {
+                foreach ($day as $extevent) {
+                    $event_cache = new stdClass();
+                    $event_cache->feed = $exticalurl;
+                    $event_cache->title = $extevent->title;
+                    $event_cache->body = $extevent->body;
+                    $event_cache->eventdate = $extevent->eventdate->date;
+                    if (isset($extevent->dateFinished))
+                        $event_cache->dateFinished = $extevent->dateFinished;
+                    $event_cache->eventstart = $extevent->eventstart;
+                    if (isset($extevent->eventend))
+                        $event_cache->eventend = $extevent->eventend;
+                    if (isset($extevent->is_allday))
+                        $event_cache->is_allday = $extevent->is_allday;
+                    $db->insertObject($event_cache, 'event_cache');
+                }
+            }
+            $cache_contents = serialize(array('start_date'=>$start,'first_date'=>(int)$db->selectValue('event_cache','eventdate','feed="'.$exticalurl.'" ORDER BY eventdate'),'refresh_date'=>time()));
+            file_put_contents($cache_fname, $cache_contents);
+        }
+        flash('message', gt('External Calendar Event cache updated'));
+        echo show_msg_queue();
+    }
+
+    function import() {
+        $pullable_modules = expModules::listInstalledControllers($this->baseclassname);
+        $modules = new expPaginator(array(
+            'records' => $pullable_modules,
+            'controller' => $this->loc->mod,
+            'action' => $this->params['action'],
+            'order'   => isset($this->params['order']) ? $this->params['order'] : 'section',
+            'dir'     => isset($this->params['dir']) ? $this->params['dir'] : '',
+            'page'    => (isset($this->params['page']) ? $this->params['page'] : 1),
+            'columns' => array(
+                gt('Title') => 'title',
+                gt('Page')  => 'section'
+            ),
+        ));
+
+        assign_to_template(array(
+            'modules' => $modules,
+        ));
+    }
+
+    function import_select()
+    {
+        if (empty($this->params['import_aggregate'])) {
+            expValidator::setErrorField('import_aggregate[]');
+            expValidator::failAndReturnToForm(gt('You must select a module.'), $this->params);
+        }
+        $extevents = array();
+        unset(
+            $this->params['begin'],
+            $this->params['end']
+        );  // always use date value
+        $begin = yuidatetimecontrol::parseData('begin', $this->params);
+        $end = yuidatetimecontrol::parseData('end', $this->params);
+        if ($this->params['file_type'] == 'file') {
+            //Get the temp directory to put the uploaded file
+            $directory = "tmp";
+
+            //Get the file save it to the temp directory
+            if (!empty($_FILES["import_file"]) && $_FILES["import_file"]["error"] == UPLOAD_ERR_OK) {
+                $file = expFile::fileUpload(
+                    "import_file",
+                    false,
+                    false,
+                    time() . "_" . $_FILES['import_file']['name'],
+                    $directory . '/'
+                );
+                if ($file === null) {
+                    switch ($_FILES["import_file"]["error"]) {
+                        case UPLOAD_ERR_INI_SIZE:
+                        case UPLOAD_ERR_FORM_SIZE:
+                            $this->params['_formError'] = gt(
+                                'The file you attempted to upload is too large.  Contact your system administrator if this is a problem.'
+                            );
+                            break;
+                        case UPLOAD_ERR_PARTIAL:
+                            $this->params['_formError'] = gt('The file was only partially uploaded.');
+                            break;
+                        case UPLOAD_ERR_NO_FILE:
+                            $this->params['_formError'] = gt('No file was uploaded.');
+                            break;
+                        default:
+                            $this->params['_formError'] = gt(
+                                'A strange internal error has occurred.  Please contact the Exponent Developers.'
+                            );
+                            break;
+                    }
+                    expSession::set("last_POST", $this->params);
+                    header("Location: " . $_SERVER['HTTP_REFERER']);
+                    exit("");
+                } else {
+                    $extevents = $this->get_ical_events($directory . "/" . $file->filename, $begin, $end);
+                }
+            } else {
+               expValidator::setErrorField('import_file');
+               expValidator::failAndReturnToForm(gt('File failed to upload.'), $this->params);  // file upload error
+            }
+        } else {
+            if (empty($this->params['ext_feed'])) {
+                expValidator::setErrorField('ext_feed');
+                expValidator::failAndReturnToForm(gt('You must enter a feed url.'), $this->params);
+            }
+            $extevents = $this->get_ical_events($this->params['ext_feed'], $begin, $end);
+        }
+
+        $src = $this->params['import_aggregate'][0];
+        $count = 0;
+        foreach ($extevents as $day) {
+            foreach ($day as $extevent) {
+                $event = array();
+                $event['title'] = $extevent->title;
+                $event['body'] = $extevent->body;
+                $event['eventdate'] = $extevent->eventdate->date;
+                $event['eventstart'] = $extevent->eventstart;
+                $event['eventstart'] -= $event['eventdate'];
+                if (isset($extevent->eventend))
+                    $event['eventend'] = $extevent->eventend;
+                else
+                    $event['eventend'] = $extevent->eventstart;
+                $event['eventend'] -= $event['eventdate'];
+                if (isset($extevent->is_allday))
+                    $event['is_allday'] = $extevent->is_allday;
+                $event['module'] = 'event';
+                $event['src'] = $src;
+                $item = new event();  // create new populated record to auto-set things
+                $item->update($event);
+                $count++;
+            }
+        }
+
+        unlink($directory . "/" . $file->filename);
+
+        // update search index
+        $this->addContentToSearch();
+
+        flashAndFlow('message', $count . ' ' . gt('events were imported.'));
+    }
+
+    /** @deprecated
+     * function to build a control requested via ajax
+     * we the html just like the control smarty function
+     * @deprecated
+     */
+    public function buildControl() {
+        $control = new colorcontrol();
+        if (!empty($this->params['value'])) $control->value = $this->params['value'];
+        if ($this->params['value'][0] != '#') $this->params['value'] = '#' . $this->params['value'];
+        $control->default = $this->params['value'];
+        if (!empty($this->params['hide'])) $control->hide = $this->params['hide'];
+        if (isset($this->params['flip'])) $control->flip = $this->params['flip'];
+        $this->params['name'] = !empty($this->params['name']) ? $this->params['name'] : '';
+        $control->name  = $this->params['name'];
+        $this->params['id'] = !empty($this->params['id']) ? $this->params['id'] : '';
+        $control->id  = isset($this->params['id']) && $this->params['id'] != "" ? $this->params['id'] : "";
+        //echo $control->id;
+        if (empty($control->id)) $control->id = $this->params['name'];
+        if (empty($control->name)) $control->name = $this->params['id'];
+
+        // attempt to translate the label
+        if (!empty($this->params['label'])) {
+            $this->params['label'] = gt($this->params['label']);
+        } else {
+            $this->params['label'] = null;
+        }
+        echo $control->toHTML($this->params['label'], $this->params['name']);
+//        $ar = new expAjaxReply(200, gt('The control was created'), json_encode(array('data'=>$code)));
+//        $ar->send();
+    }
+
+}
+
 ?>
\ No newline at end of file

programming_language: PHP
filename: event.php
change_type: ModificationType.MODIFY
diff: @@ -52,6 +52,11 @@ class event extends expRecord {
             //note $order is boolean for 'featured'
             //note $limit is number of days, NOT number of records
             //note $limitstart is a unixtimestamp in this instance
+            $order = expString::escape($order);
+            if ($limit !== null)
+                $limit = intval($limit);
+            if ($limitstart !== null)
+                $limitstart = intval($limitstart);
             $ed = new eventdate();
             $day = expDateTime::startOfDayTimestamp(time());
             $sort_asc = true; // For the getEventsForDates call
@@ -65,7 +70,7 @@ class event extends expRecord {
 //                $begin = $day;
 //                $end = null;
                 $items = $this->getEventsForDates($dates, $sort_asc, $order ? true : false, true);
-                
+
                 // external events
 //                $extitems = $this->getExternalEvents($begin, $end);
                 // we need to crunch these down
@@ -78,7 +83,7 @@ class event extends expRecord {
 //                    }
 //                }
 //                $items = array_merge($items, $extitem);
-                
+
                 // event registration events
 //                if (!empty($this->config['aggregate_registrations'])) $regitems = eventregistrationController::getRegEventsForDates($begin, $end, $regcolor);
                 // we need to crunch these down
@@ -89,7 +94,7 @@ class event extends expRecord {
 //                    }
 //                }
 //                $items = array_merge($items, $regitem);
-                
+
                 $items = expSorter::sort(array('array' => $items, 'sortby' => 'eventstart', 'order' => 'ASC'));
                 return $items;
             }
@@ -246,7 +251,7 @@ class event extends expRecord {
         }
         return $days;
     }
-    
+
 }
 
 ?>
\ No newline at end of file

programming_language: PHP
filename: fileController.php
change_type: ModificationType.MODIFY
diff: @@ -23,20 +23,26 @@
 
 class fileController extends expController {
     public $basemodel_name = "expFile";
-    protected $add_permissions = array(
-//        'picker'=>'Manage Files',
-        'import'=>'Import',
-        'export'=>'Export',
-    );
     protected $remove_permissions = array(
         'delete'
     );
+//    protected $manage_permissions = array(
+//        'picker'=>'Manage Files',
+//        'import'=>'Import',
+//        'export'=>'Export',
+//    );
     public $requires_login = array(
-        'picker'=>'must be logged in',
-        'editAlt'=>'must be logged in',
-        'editCat'=>'must be logged in',
-        'editShare'=>'must be logged in',
-        'editTitle'=>'must be logged in',
+        'picker'=>'You must be logged in to perform this action',
+        'adder'=>'You must be logged in to perform this action',
+        'addit'=>'You must be logged in to perform this action',
+        'batchDelete'=>'You must be logged in to perform this action',
+        'createFolder'=>'You must be logged in to perform this action',
+        'deleter'=>'You must be logged in to perform this action',
+        'deleteit'=>'You must be logged in to perform this action',
+        'edit'=>'You must be logged in to perform this action',
+        'quickUpload'=>'You must be logged in to perform this action',
+        'upload'=>'You must be logged in to perform this action',
+        'uploader'=>'You must be logged in to perform this action',
     );
 
     static function displayname() { return gt("File Manager"); }
@@ -47,20 +53,20 @@ class fileController extends expController {
         // fixes file directory issues when the old file class was used to save record
         // where the trailing forward slash was not added. This simply checks to see
         // if the trailing / is there, if not, it adds it.
-        
+
         $file = new expFile();
         $files = $file->find('all');
-        
+
         foreach ($files as $key=>$file) {
             if (substr($files[$key]->directory,-1,1)!="/") {
                 $files[$key]->directory = $files[$key]->directory.'/';
             }
             $files[$key]->save();
         }
-    
+
 //        eDebug($files,true);
     }
-    
+
     public function picker() {
 //        global $user;
 
@@ -89,7 +95,7 @@ class fileController extends expController {
             'jscats'=>json_encode($jscatarray)
         ));
     }
-    
+
     public function uploader() {
         global $user;
         //expHistory::set('manageable', $this->params);
@@ -113,14 +119,14 @@ class fileController extends expController {
             'cats'=>$catarray,
         ));
     }
-    
+
     /**
      * Returns attached file view template configuration settings template
      *
      */
     public function get_view_config() {
         global $template;
-        
+
         // set paths we will search in for the view
         $paths = array(
             BASE.'themes/'.DISPLAY_THEME.'/modules/common/views/file/configure',
@@ -148,7 +154,7 @@ class fileController extends expController {
             }
         }
     }
-    
+
     /**
      * Returns view template configuration settings view template
      *
@@ -331,7 +337,7 @@ class fileController extends expController {
                 $filter .= !empty($filter) ? " AND " : "";
                 $filter .= "is_image=1";
             }
-            
+
 //            $totalrecords = $this->$modelname->find('count',$filter);
 //            $files = $this->$modelname->find('all',$filter,$sort.' '.$dir, $results, $startIndex);
             $files = $this->$modelname->find('all', $filter, $sort.' '.$dir);
@@ -364,9 +370,9 @@ class fileController extends expController {
                 'pageSize'=>$results,
                 'records'=>$files
             );
-                  
+
         }
-        
+
         echo json_encode($returnValue);
     }
 
@@ -411,8 +417,8 @@ class fileController extends expController {
             flash('error',$file->filename.' '.gt('wasn\'t deleted because you don\'t own the file.'));
         }
         redirect_to(array("controller"=>'file',"action"=>'picker',"ajax_action"=>1,"update"=>$this->params['update'],"filter"=>$this->params['filter']));
-    } 
-    
+    }
+
     public function deleter() {
 //        global $db;
 
@@ -527,7 +533,7 @@ class fileController extends expController {
     }
 
     public function upload() {
-        
+
         // upload the file, but don't save the record yet...
         if ($this->params['resize'] != 'false') {
             $maxwidth = $this->params['max_width'];
@@ -562,7 +568,7 @@ class fileController extends expController {
             echo gt('File was NOT uploaded!');
 //            flash('error',gt('File was not uploaded!'));
         }
-    } 
+    }
 
     public function quickUpload(){
         global $user;
@@ -661,10 +667,10 @@ class fileController extends expController {
             $ar = new expAjaxReply(300, gt("You didn't create this file, so you can't edit it."));
         }
         $ar->send();
-    } 
+    }
 
     public function editAlt() {
-        global $user;        
+        global $user;
         $file = new expFile($this->params['id']);
         if ($user->id==$file->poster || $user->isAdmin()) {
             $file->alt = $this->params['newValue'];
@@ -675,7 +681,7 @@ class fileController extends expController {
         }
         $ar->send();
         echo json_encode($file);  //FIXME we exit before hitting this
-    } 
+    }
 
     public function editShare() {
         global $user;

programming_language: PHP
filename: expFile.php
change_type: ModificationType.MODIFY
diff: @@ -425,7 +425,7 @@ class expFile extends expRecord {
         //Check to see if the directory exists.  If not, create the directory structure.
         // if (!file_exists(BASE . $_destDir)) {
         //  self::makeDirectory(BASE . $_destDir);
-        // }    
+        // }
 
         // Move the temporary uploaded file into the destination directory,
         // and change the name.
@@ -735,8 +735,9 @@ class expFile extends expRecord {
      */
     public static function fixName($name) {
         $name = preg_replace('/[^A-Za-z0-9\.]/','_',$name);
-        if ($name[0] == '.')
+        if ($name[0] == '.')  // attempt to upload a dot file
             $name[0] = '_';
+        $name = str_replace('_', '..', $name);  // attempt to upload with redirection to new folder
         return $name;
 //        return preg_replace('/[^A-Za-z0-9\.]/', '-', $name);
     }

programming_language: PHP
filename: filedownloadController.php
change_type: ModificationType.MODIFY
diff: @@ -38,7 +38,7 @@ class filedownloadController extends expController {
     static function displayname() { return gt("File Downloads"); }
     static function description() { return gt("Place files on your website for users to download or use as a podcast."); }
     static function isSearchable() { return true; }
-	
+
     function showall() {
         expHistory::set('viewable', $this->params);
         $limit = (isset($this->config['limit']) && $this->config['limit'] != '') ? $this->config['limit'] : 10;
@@ -90,21 +90,21 @@ class filedownloadController extends expController {
             flash('error', gt('There was an error while trying to download your file.  No File Specified.'));
             expHistory::back();
         }
-        
-        $fd = new filedownload($this->params['fileid']); 
+
+        $fd = new filedownload(intval($this->params['fileid']));
         if (empty($this->params['filenum'])) $this->params['filenum'] = 0;
 
         if (empty($fd->expFile['downloadable'][$this->params['filenum']]->id)) {
             flash('error', gt('There was an error while trying to download your file.  The file you were looking for could not be found.'));
             expHistory::back();
-        }        
-        
+        }
+
         $fd->downloads++;
         $fd->save();
-        
+
         // this will set the id to the id of the actual file..makes the download go right.
         $this->params['id'] = $fd->expFile['downloadable'][$this->params['filenum']]->id;
-        parent::downloadfile();        
+        parent::downloadfile();
     }
 
     /**
@@ -219,10 +219,10 @@ class filedownloadController extends expController {
 
         $fd = new filedownload();
         $items = $fd->find('all',$this->aggregateWhereClause(), isset($this->config['order']) ? $this->config['order'] : 'created_at DESC', $limit);
-        
+
         //Convert the items to rss items
         $rssitems = array();
-        foreach ($items as $key => $item) { 
+        foreach ($items as $key => $item) {
             $rss_item = new FeedItem();
 
             // Add the basic data
@@ -281,7 +281,7 @@ class filedownloadController extends expController {
         }
         return $rssitems;
     }
-	
+
 }
 
 ?>
\ No newline at end of file

programming_language: PHP
filename: formsController.php
change_type: ModificationType.MODIFY
diff: @@ -27,6 +27,13 @@ class formsController extends expController {
         'showall'    => 'Show All Records',
         'show'       => 'Show a Single Record',
     );
+    protected $add_permissions = array(
+        'viewdata'  => "View Data",
+        'enter_data' => "Enter Data",  // slight naming variation to not fully restrict enterdata method
+    );
+    protected $manage_permissions = array(
+        'design' => 'Design Form',
+    );
     public $remove_configs = array(
         'aggregation',
         'categories',
@@ -39,10 +46,6 @@ class formsController extends expController {
         'tags',
         'twitter',
     ); // all options: ('aggregation','categories','comments','ealerts','facebook','files','pagination','rss','tags','twitter',)
-    protected $add_permissions = array(
-        'viewdata'  => "View Data",
-        'enter_data' => "Enter Data"  // slight naming variation to not fully restrict enterdata method
-    );
 //    public $codequality = 'beta';
 
     static function displayname() {
@@ -81,7 +84,7 @@ class formsController extends expController {
             if (!empty($this->config)) {
                 $f = $this->forms->find('first', 'id=' . $this->config['forms_id']);
             } elseif (!empty($this->params['title'])) {
-                $f = $this->forms->find('first', 'sef_url="' . $this->params['title'] . '"');
+                $f = $this->forms->find('first', 'sef_url="' . expString::escape($this->params['title']) . '"');
                 $this->get_defaults($f);
             } elseif (!empty($this->params['id'])) {
                 $f = $this->forms->find('first', 'id=' . $this->params['id']);
@@ -92,7 +95,7 @@ class formsController extends expController {
                 if (empty($this->config['report_filter']) && empty($this->params['filter'])) {  // allow for param of 'filter' also
                     $where = '1';
                 } elseif (!empty($this->params['filter'])) {
-                    $where = $this->params['filter'];
+                    $where = expString::escape($this->params['filter']);
                 } else {
                     $where = $this->config['report_filter'];
                 }
@@ -200,7 +203,7 @@ class formsController extends expController {
             } elseif (!empty($this->params['forms_id'])) {
                 $f = $this->forms->find('first', 'id=' . $this->params['forms_id']);
             } elseif (!empty($this->params['title'])) {
-                $f = $this->forms->find('first', 'sef_url="' . $this->params['title'] . '"');
+                $f = $this->forms->find('first', 'sef_url="' . expString::escape($this->params['title']) . '"');
                 redirect_to(array('controller' => 'forms', 'action' => 'enterdata', 'forms_id' => $f->id));
             }
 
@@ -710,10 +713,10 @@ class formsController extends expController {
 //                );
 
                 $tmsg = trim(strip_tags(str_replace(array("<br />", "<br>", "br/>"), "\n", $this->config['auto_respond_body'])));
-                if ($this->config['auto_respond_form']) 
+                if ($this->config['auto_respond_form'])
                     $tmsg .= "\n" . $emailText;
                 $hmsg = $this->config['auto_respond_body'];
-                if ($this->config['auto_respond_form']) 
+                if ($this->config['auto_respond_form'])
                     $hmsg .= "\n" . $emailHtml;
                 $mail = new expMail();
                 $mail->quickSend(array(
@@ -1939,6 +1942,10 @@ class formsController extends expController {
     public function import_csv_data_add() {
         global $user;
 
+        if (!empty($this->params['filename']) && (strpos($this->params['filename'], 'tmp/') === false || strpos($this->params['folder'], '..') !== false)) {
+            header('Location: ' . URL_FULL);
+            exit();  // attempt to hack the site
+        }
         $line_end = ini_get('auto_detect_line_endings');
         ini_set('auto_detect_line_endings',TRUE);
         $file = fopen(BASE . $this->params["filename"], "r");

programming_language: PHP
filename: helpController.php
change_type: ModificationType.MODIFY
diff: @@ -41,7 +41,7 @@ class helpController extends expController {
     static function displayname() { return gt("Help"); }
     static function description() { return gt("Manage Exponent CMS help files."); }
     static function isSearchable() { return true; }
-	
+
     function __construct($src=null, $params=array()) {
         parent::__construct($src,$params);
         // only set the system help version if it's not already set as a session variable
@@ -74,13 +74,13 @@ class helpController extends expController {
 	    //$current_version = $hv->find('first', 'is_current=1');
 	    $ref_version = $hv->find('first', 'version=\''.$this->help_version.'\'');
 
-        // pagination parameter..hard coded for now.	    
+        // pagination parameter..hard coded for now.
 		$where = $this->aggregateWhereClause();
 	    $where .= 'AND help_version_id='.(empty($ref_version->id)?'0':$ref_version->id);
         if (empty($this->params['parent'])) {
             $where .= ' AND (parent=0 OR parent IS NULL)';
         } else {
-            $where .= ' AND parent=' . $this->params['parent'];
+            $where .= ' AND parent=' . intval($this->params['parent']);
         }
 //	    $limit = 999;
 	    $order = isset($this->config['order']) ? $this->config['order'] : 'rank';
@@ -127,6 +127,7 @@ class helpController extends expController {
                 $version_id = help_version::getCurrentHelpVersionId();
             }
 	    }
+	    $this->params['title'] = expString::escape($this->params['title']);  // escape title to prevent sql injection
 	    $doc = $help->find('first', 'help_version_id='.$version_id.' AND sef_url="'.$this->params['title'].'"');
         $children = $help->find('count','parent='.$doc->id);
         if (empty($doc)) {
@@ -201,10 +202,10 @@ class helpController extends expController {
 	public function manage() {
 	    expHistory::set('manageable', $this->params);
 	    global $db;
-	    
+
 	    $hv = new help_version();
 	    $current_version = $hv->find('first', 'is_current=1');
-	    
+
 	    if (empty($current_version)) {
 	        flash('error', gt("You don't have any software versions created yet.  Please do so now."));
 	        redirect_to(array('controller'=>'help', 'action'=>'edit_version'));
@@ -218,7 +219,7 @@ class helpController extends expController {
             }
         }
 
-	    $where = empty($this->params['version']) ? 1 : 'help_version_id='.$this->params['version'];
+	    $where = empty($this->params['version']) ? 1 : 'help_version_id='.intval($this->params['version']);
 	    $page = new expPaginator(array(
             'model'=>'help',
             'where'=>$where,
@@ -263,7 +264,7 @@ class helpController extends expController {
             $origid = $doc->id;
 	        unset($doc->id);
 	        $doc->help_version_id = $to;
-		    
+
 //	        $tmpsef = $doc->sef_url;
 //	        $doc->sef_url = "";
 //	        $doc->save();
@@ -313,10 +314,10 @@ class helpController extends expController {
      */
 	public function manage_versions() {
 	    expHistory::set('manageable', $this->params);
-	    
+
 	    $hv = new help_version();
 	    $current_version = $hv->find('first', 'is_current=1');
-	    
+
 	    $sql  = 'SELECT hv.*, COUNT(h.title) AS num_docs FROM '.DB_TABLE_PREFIX.'_help h ';
 	    $sql .= 'RIGHT JOIN '.DB_TABLE_PREFIX.'_help_version hv ON h.help_version_id=hv.id GROUP BY hv.version';
 
@@ -336,7 +337,7 @@ class helpController extends expController {
                 gt('# of Docs')=>'num_docs'
             ),
         ));
-	    
+
 	    assign_to_template(array(
             'current_version'=>$current_version,
             'page'=>$page
@@ -362,23 +363,23 @@ class helpController extends expController {
 	    if (empty($this->params['id'])) {
 	        flash('error', gt('The version you are trying to delete could not be found'));
 	    }
-	    
+
 	    // get the version
 	    $version = new help_version($this->params['id']);
 	    if (empty($version->id)) {
 	        flash('error', gt('The version you are trying to delete could not be found'));
 	    }
-	    
+
 	    // if we have errors than lets get outta here!
 	    if (!expQueue::isQueueEmpty('error')) expHistory::back();
-	    
+
 	    // delete the version
 	    $version->delete();
-	    
+
 	    expSession::un_set('help-version');
 
 	    flash('message', gt('Deleted version').' '.$version->version.' '.gt('and all documents in that version.'));
-	    expHistory::back();	    
+	    expHistory::back();
 	}
 
     /**
@@ -388,7 +389,7 @@ class helpController extends expController {
 	    // get the current version
 	    $hv = new help_version();
 	    $current_version = $hv->find('first', 'is_current=1');
-	    
+
 	    // check to see if the we have a new current version and unset the old current version.
 	    if (!empty($this->params['is_current'])) {
 //	        $db->sql('UPDATE '.DB_TABLE_PREFIX.'_help_version set is_current=0');
@@ -402,10 +403,10 @@ class helpController extends expController {
 	    // if we don't have a current version yet so we will force this one to be it
 	    if (empty($current_version->id)) $this->params['is_current'] = 1;
 	    $version->update($this->params);
-	    
+
 	    // if this is a new version we need to copy over docs
 	    if (empty($id)) {
-	        self::copydocs($current_version->id, $version->id);	        
+	        self::copydocs($current_version->id, $version->id);
 	    }
         // let's update the search index to reflect the current help version
         searchController::spider();
@@ -536,7 +537,7 @@ class helpController extends expController {
         $section = new section(intval($sid));
 	    return $section;
 	}
-	
+
 }
 
 ?>
\ No newline at end of file

programming_language: PHP
filename: help_version.php
change_type: ModificationType.MODIFY
diff: @@ -52,13 +52,13 @@ class help_version extends expRecord {
     public static function getHelpVersionId($version) {
         global $db;
 
-        return $db->selectValue('help_version', 'id', 'version="'.$version.'"');
+        return $db->selectValue('help_version', 'id', 'version="'.$db->escapeString($version).'"');
     }
 
     public static function getHelpVersion($version_id) {
         global $db;
 
-        return $db->selectValue('help_version', 'version', 'id="'.$version_id.'"');
+        return $db->selectValue('help_version', 'version', 'id="'.intval($version_id).'"');
     }
 
     public static function getHelpVersionsDropdown() {

programming_language: PHP
filename: importexportController.php
change_type: ModificationType.MODIFY
diff: @@ -22,6 +22,13 @@
  */
 
 class importexportController extends expController {
+    protected $add_permissions = array(
+        'import' => 'Import Data',
+        'export' => 'Export Data'
+    );
+    protected $manage_permissions = array(
+        'importProduct' => 'Import Product',
+    );
     // hide the configs we don't need
     public $remove_configs = array(
         'aggregation',
@@ -35,11 +42,6 @@ class importexportController extends expController {
         'twitter',
     ); // all options: ('aggregation','categories','comments','ealerts','facebook','files','pagination','rss','tags','twitter',)
 
-    //protected $permissions = array_merge(array("test"=>'Test'), array('copyProduct'=>"Copy Product"));
-    protected $add_permissions = array(
-        'import' => 'Import Data',
-        'export' => 'Export Data'
-    );
 
     static function displayname() {
         return gt("Data Import / Export Module");
@@ -177,6 +179,11 @@ class importexportController extends expController {
             expValidator::failAndReturnToForm(gt('You must select at least one item.'), $this->params);
         }
 
+        if (!empty($this->params['filename']) && (strpos($this->params['filename'], 'tmp/') === false || strpos($this->params['folder'], '..') !== false)) {
+            header('Location: ' . URL_FULL);
+            exit();  // attempt to hack the site
+        }
+
         $filename = $this->params['filename'];
         $src = $this->params['source'];
         $selected = $this->params['items'];
@@ -357,7 +364,7 @@ class importexportController extends expController {
 
     function validate() {
 //        global $db;
-        //eDebug($this->params,true); 
+        //eDebug($this->params,true);
         set_time_limit(0);
         //$file = new expFile($this->params['expFile']['import_file'][0]);
         if (!empty($_FILES['import_file']['error'])) {
@@ -397,117 +404,117 @@ class importexportController extends expController {
     {
         $handle = fopen($file->path, "r");
         $data = fgetcsv($handle, 10000, ",");
-        //eDebug($data);        
-        $source = '';   
+        //eDebug($data);
+        $source = '';
         foreach ($data as $key=>$value)
         {
-            $dataset[$value] = '';            
+            $dataset[$value] = '';
             if($key == 2 && $value=='Unique_Bill_Name') $source = '1';    //SMC
         }
-        
+
         //eDebug($source);
         //eDebug($dataset,true);
         $count = 1;
         $errorSet = array();
         $successSet = array();
         eDebug($dataset);
-        
+
         $extAddy = null;
         while (($data = fgetcsv($handle, 10000, ",")) !== FALSE) {
             $count++;
-            $extAddy = new external_address();             
+            $extAddy = new external_address();
             $bName = explode(' ',$data[3]);
             eDebug($bName);
             $extAddy->firstname = $bName[0];
             if(count($bName) == 3)
             {
                 $extAddy->middlename = $bName[1];
-                $extAddy->lastname = $bName[2];    
+                $extAddy->lastname = $bName[2];
             }
             else if (count($bName) ==1)
             {
                 $extAddy->middlename = '';
-                $extAddy->lastname = '';    
+                $extAddy->lastname = '';
             }
             else
             {
                 $extAddy->middlename = '';
-                $extAddy->lastname = $bName[1];        
+                $extAddy->lastname = $bName[1];
             }
-            
+
             $extAddy->organization = $data[4];
             $extAddy->address1 = $data[5];
-            $extAddy->address2 = $data[6];            
-            $extAddy->address2 = $data[6];            
-            $extAddy->city = $data[7];            
-            
+            $extAddy->address2 = $data[6];
+            $extAddy->address2 = $data[6];
+            $extAddy->city = $data[7];
+
             $s = new geoRegion();
             $state = $s->find('first','code="'.trim($data[8]).'"');
             eDebug($state);
-            $extAddy->state = $state->id;                        
-            $extAddy->zip = str_ireplace("'",'',$data[9]);            
-            $extAddy->phone = $data[20];            
-            $extAddy->email = $data[21];            
+            $extAddy->state = $state->id;
+            $extAddy->zip = str_ireplace("'",'',$data[9]);
+            $extAddy->phone = $data[20];
+            $extAddy->email = $data[21];
             $extAddy->source = $source;
-            
-            
+
+
             //shipping
             if($data[3] == $data[12] && $data[5] == $data[14] && $data[6] == $data[15])  //shipping and billing same
             {
                 $extAddy->is_billing = 1;
-                $extAddy->is_shipping = 1;            
-                $extAddy->save(false);            
+                $extAddy->is_shipping = 1;
+                $extAddy->save(false);
             }
             else
-            {                
+            {
                 $extAddy->is_billing = 1;
-                $extAddy->is_shipping = 0;            
-                $extAddy->save(false);            
-                
-                $extAddy = new external_address();             
+                $extAddy->is_shipping = 0;
+                $extAddy->save(false);
+
+                $extAddy = new external_address();
                 $sName = explode(' ',$data[12]);
                 eDebug($sName);
                 $extAddy->firstname = $sName[0];
                 if(count($sName) == 3)
                 {
                     $extAddy->middlename = $sName[1];
-                    $extAddy->lastname = $sName[2];    
+                    $extAddy->lastname = $sName[2];
                 }
                 else if (count($sName) ==1)
                 {
                     $extAddy->middlename = '';
-                    $extAddy->lastname = '';    
+                    $extAddy->lastname = '';
                 }
                 else
                 {
                     $extAddy->middlename = '';
-                    $extAddy->lastname = $sName[1];        
+                    $extAddy->lastname = $sName[1];
                 }
-                
+
                 $extAddy->organization = $data[13];
                 $extAddy->address1 = $data[14];
-                $extAddy->address2 = $data[15];                            
-                $extAddy->city = $data[16];            
-                
+                $extAddy->address2 = $data[15];
+                $extAddy->city = $data[16];
+
                 $s = new geoRegion();
                 $state = $s->find('first','code="'.trim($data[17]).'"');
                 eDebug($state);
-                $extAddy->state = $state->id;                        
-                $extAddy->zip = str_ireplace("'",'',$data[18]);            
-                $extAddy->phone = $data[20];            
-                $extAddy->email = $data[21];            
+                $extAddy->state = $state->id;
+                $extAddy->zip = str_ireplace("'",'',$data[18]);
+                $extAddy->phone = $data[20];
+                $extAddy->email = $data[21];
                 $extAddy->is_billing = 0;
                 $extAddy->is_shipping = 1;
-                $extAddy->source = $source;   
-                
+                $extAddy->source = $source;
+
                 $extAddy->save(false);
             }
-            
+
             echo "Successfully imported row " . $count . ", name: " . $extAddy->firstname . " " . $extAddy->lastname . "<br/>";
             //eDebug($product);
-        
-        }   
-        
+
+        }
+
         if(count($errorSet))
         {
             echo "<br/><hr><br/><font color='red'>The following records were NOT imported:<br/>";
@@ -524,7 +531,7 @@ class importexportController extends expController {
                 else echo "--" . $err . "<br/>";
             }
             echo "</font>";
-        }    
+        }
     }*/
 
     function importProduct($file=null) {

programming_language: PHP
filename: migrationController.php
change_type: ModificationType.MODIFY
diff: @@ -21,7 +21,7 @@
  */
 
 class migrationController extends expController {
-    protected $add_permissions = array(
+    protected $manage_permissions = array(
         'analyze'=>'Analyze Data',
         'migrate'=>'Migrate Data'
     );

programming_language: PHP
filename: navigationController.php
change_type: ModificationType.MODIFY
diff: @@ -1,1289 +1,1305 @@
-<?php
-
-##################################################
-#
-# Copyright (c) 2004-2016 OIC Group, Inc.
-#
-# This file is part of Exponent
-#
-# Exponent is free software; you can redistribute
-# it and/or modify it under the terms of the GNU
-# General Public License as published by the Free
-# Software Foundation; either version 2 of the
-# License, or (at your option) any later version.
-#
-# GPL: http://www.gnu.org/licenses/gpl.txt
-#
-##################################################
-/**
- * @subpackage Controllers
- * @package    Modules
- */
-class navigationController extends expController {
-    public $basemodel_name = 'section';
-    public $useractions = array(
-        'showall' => 'Show Navigation',
-        'breadcrumb' => 'Breadcrumb',
-    );
-    public $remove_configs = array(
-        'aggregation',
-        'categories',
-        'comments',
-        'ealerts',
-        'facebook',
-        'files',
-        'pagination',
-        'rss',
-        'tags',
-        'twitter',
-    );  // all options: ('aggregation','categories','comments','ealerts','facebook','files','pagination','rss','tags','twitter',)
-    protected $add_permissions = array(
-        'view' => "View Page"
-    );
-    protected $remove_permissions = array(
-//        'configure',
-//        'create',
-//        'delete',
-//        'edit'
-    );
-
-    static function displayname() { return gt("Navigation"); }
-
-    static function description() { return gt("Places navigation links/menus on the page."); }
-
-    static function isSearchable() { return true; }
-
-    function searchName() { return gt('Webpage'); }
-
-    /**
-     * @param null $src
-     * @param array $params
-     *
-     */
-    function __construct($src = null, $params = array())
-    {
-        parent::__construct($src, $params);
-        if (!empty($params['id']))  // we normally throw out the $loc->int EXCEPT with navigation pages
-            $this->loc = expCore::makeLocation($this->baseclassname, $src, $params['id']);
-    }
-
-    public function showall() {
-        global $user, $sectionObj, $sections;
-
-        expHistory::set('viewable', $this->params);
-        $id      = $sectionObj->id;
-        $current = null;
-        // all we need to do is determine the current section
-        $navsections = $sections;
-        if ($sectionObj->parent == -1) {
-            $current = $sectionObj;
-        } else {
-            foreach ($navsections as $section) {
-                if ($section->id == $id) {
-                    $current = $section;
-                    break;
-                }
-            }
-        }
-        assign_to_template(array(
-            'sections'     => $navsections,
-            'current'      => $current,
-            'canManage'    => ((isset($user->is_acting_admin) && $user->is_acting_admin == 1) ? 1 : 0),
-        ));
-    }
-
-    public function breadcrumb() {
-        global $sectionObj;
-
-        expHistory::set('viewable', $this->params);
-        $id      = $sectionObj->id;
-        $current = null;
-        // Show not only the location of a page in the hierarchy but also the location of a standalone page
-        $current = new section($id);
-        if ($current->parent == -1) {  // standalone page
-            $navsections = section::levelTemplate(-1, 0);
-            foreach ($navsections as $section) {
-                if ($section->id == $id) {
-                    $current = $section;
-                    break;
-                }
-            }
-        } else {
-            $navsections = section::levelTemplate(0, 0);
-            foreach ($navsections as $section) {
-                if ($section->id == $id) {
-                    $current = $section;
-                    break;
-                }
-            }
-        }
-        assign_to_template(array(
-            'sections'     => $navsections,
-            'current'      => $current,
-        ));
-    }
-
-    /**
-     * @deprecated 2.3.4 moved to section model
-     */
-    public static function navhierarchy($notyui=false) {
-        global $sections;
-
-        $json_array = array();
-        for ($i = 0, $iMax = count($sections); $i < $iMax; $i++) {
-            if ($sections[$i]->depth == 0) {
-                $obj = new stdClass();
-//   				$obj->id = $sections[$i]->name.$sections[$i]->id;
-                $obj->id   = $sections[$i]->id;
-                $obj->text = $sections[$i]->name;
-                $obj->title = $sections[$i]->page_title;
-                $obj->description = $sections[$i]->description;
-                $obj->new_window = $sections[$i]->new_window;
-                $obj->expFile = $sections[$i]->expFile;
-                $obj->glyph = $sections[$i]->glyph;
-                $obj->glyph_only = $sections[$i]->glyph_only;
-                $obj->type = $sections[$i]->alias_type;
-                if ($sections[$i]->active == 1) {
-                    $obj->url = $sections[$i]->link;
-                    if ($obj->type == 1 && substr($obj->url, 0, 4) != 'http') {
-                        $obj->url = 'http://' . $obj->url;
-                    }
-                } else {
-                    $obj->url     = "#";
-                    $obj->onclick = "onclick: { fn: return false }";
-                }
-                if ($obj->type == 3) {  // mostly a hack instead of adding more table fields
-                    $obj->width = $sections[$i]->internal_id;
-                    $obj->class = $sections[$i]->external_link;
-                }
-                /*if ($sections[$i]->active == 1) {
-                    $obj->disabled = false;
-                } else {
-                    $obj->disabled = true;
-                }*/
-                //$obj->disabled = true;
-                $obj->itemdata = self::getChildren($i,$notyui);
-                $obj->maxitems = count($obj->itemdata);
-                $obj->maxdepth = 0;
-                foreach ($obj->itemdata as $menu) {
-                    if ($menu->maxdepth > $obj->maxdepth) $obj->maxdepth = $menu->maxdepth;
-                }
-            }
-            $json_array[] = $obj;
-        }
-        return $json_array;
-    }
-
-    /**
-     * @deprecated 2.3.4 moved to section model
-     */
-    public static function navtojson() {
-        return json_encode(self::navhierarchy());
-    }
-
-    /**
-     * @deprecated 2.3.4 moved to section model
-     */
-    public static function getChildren(&$i, $notyui=false) {
-        global $sections;
-
-        //		echo "i=".$i."<br>";
-        if ($i + 1 == count($sections)) { // last entry
-            return array();
-        } elseif ($sections[$i]->depth == $sections[$i + 1]->depth) {
-            return array();
-        } else {
-            $ret_depth = $sections[$i]->depth;
-            $i++;
-            $ret_array = array();
-            for ($iMax = count($sections); $i < $iMax; $i++) {
-                // start setting up the objects to return
-                $obj       = new stdClass();
-                $obj->id   = $sections[$i]->id;
-                $obj->text = $sections[$i]->name;
-                $obj->title = $sections[$i]->page_title;
-                $obj->description = $sections[$i]->description;
-                $obj->new_window = $sections[$i]->new_window;
-                $obj->expFile = $sections[$i]->expFile;
-                $obj->glyph = $sections[$i]->glyph;
-                $obj->glyph_only = $sections[$i]->glyph_only;
-                $obj->depth = $sections[$i]->depth;
-                if ($sections[$i]->active == 1) {
-                    $obj->url = $sections[$i]->link;
-                    if ($sections[$i]->alias_type == 1 && substr($obj->url, 0, 4) != 'http') {
-                        $obj->url = 'http://' . $obj->url;
-                    }
-                } else {
-                    $obj->url     = "#";
-                    $obj->onclick = "onclick: { fn: return false }";
-                }
-                //echo "i=".$i."<br>";
-                if (self::hasChildren($i)) {
-                    if ($notyui) {
-                        $obj->itemdata = self::getChildren($i,$notyui);
-                        $obj->maxitems = count($obj->itemdata);
-                        $obj->maxdepth = 0;
-                        foreach ($obj->itemdata as $menu) {
-                            if (!empty($menu->maxdepth)) {
-                                if ($menu->maxdepth > $obj->maxdepth) $obj->maxdepth = $menu->maxdepth;
-                            } else {
-                                if ($menu->depth > $obj->maxdepth) $obj->maxdepth = $menu->depth;
-                            }
-                        }
-                    } else {
-                        $obj->submenu     = new stdClass();
-                        $obj->submenu->id = $sections[$i]->name . $sections[$i]->id;
-                        //echo "getting children of ".$sections[$i]->name;
-                        $obj->submenu->itemdata = self::getChildren($i,$notyui);
-                        $obj->maxitems = count($obj->submenu->itemdata);
-                        $obj->maxdepth = 0;
-                        foreach ($obj->submenu->itemdata as $menu) {
-                            if (!empty($menu->maxdepth)) {
-                                if ($menu->maxdepth > $obj->maxdepth) $obj->maxdepth = $menu->maxdepth;
-                            } else {
-                                if ($menu->depth > $obj->maxdepth) $obj->maxdepth = $menu->depth;
-                            }
-                        }
-                    }
-                    $ret_array[]            = $obj;
-                } else {
-                    $obj->maxdepth = $obj->depth;
-                    $ret_array[] = $obj;
-                }
-                if (($i + 1) >= count($sections) || $sections[$i + 1]->depth <= $ret_depth) {
-                    return $ret_array;
-                }
-            }
-            return array();
-        }
-    }
-
-    /**
-     * @deprecated 2.3.4 moved to section model
-     */
-    public static function hasChildren($i) {
-        global $sections;
-
-        if (($i + 1) >= count($sections)) return false;
-        return ($sections[$i]->depth < $sections[$i + 1]->depth) ? true : false;
-    }
-
-    /** exdoc
-     * Creates a location object, based off of the three arguments passed, and returns it.
-     *
-     * @return array
-     * @deprecated 2.3.4 moved to section model
-     */
-    public static function initializeNavigation() {
-        $sections = section::levelTemplate(0, 0);
-        return $sections;
-    }
-
-    /**
-     * returns all the section's children
-     *
-     * @static
-     *
-     * @param int   $parent top level parent id
-     * @param int   $depth  variable to hold level of recursion
-     * @param array $parents
-     *
-     * @return array
-     * @deprecated 2.3.4 moved to section model
-     */
-    public static function levelTemplate($parent, $depth = 0, $parents = array()) {
-        global $user;
-
-        if ($parent != 0) $parents[] = $parent;
-        $nodes = array();
-        $cache = expSession::getCacheValue('navigation');
-        $sect = new section();
-        if (!isset($cache['kids'][$parent])) {
-            $kids = $sect->find('all','parent=' . $parent);
-            $cache['kids'][$parent] = $kids;
-            expSession::setCacheValue('navigation', $cache);
-        } else {
-            $kids = $cache['kids'][$parent];
-        }
-        $kids = expSorter::sort(array('array' => $kids, 'sortby' => 'rank', 'order' => 'ASC'));
-        for ($i = 0, $iMax = count($kids); $i < $iMax; $i++) {
-            $child = $kids[$i];
-            //foreach ($kids as $child) {
-            if ($child->public == 1 || expPermissions::check('view', expCore::makeLocation('navigation', '', $child->id))) {
-                $child->numParents    = count($parents);
-                $child->depth         = $depth;
-                $child->first         = ($i == 0 ? 1 : 0);
-                $child->last          = ($i == count($kids) - 1 ? 1 : 0);
-                $child->parents       = $parents;
-                $child->canManage     = (isset($user->is_acting_admin) && $user->is_acting_admin == 1 ? 1 : 0);
-                $child->canManageRank = $child->canManage;
-                if (!isset($child->sef_name)) {
-                    $child->sef_name = '';
-                }
-                // Generate the link attribute base on alias type.
-                if ($child->alias_type == 1) {
-                    // External link.  Set the link to the configured website URL.
-                    // This is guaranteed to be a full URL because of the
-                    // section::updateExternalAlias() method in models-1/section.php
-                    $child->link = $child->external_link;
-                } else if ($child->alias_type == 2) {
-                    // Internal link.
-                    // Need to check and see if the internal_id is pointing at an external link.
-//                    $dest = $db->selectObject('section', 'id=' . $child->internal_id);
-                    $dest = $sect->find('first','id=' . $child->internal_id);
-                    if (!empty($dest->alias_type) && $dest->alias_type == 1) {
-                        // This internal alias is pointing at an external alias.
-                        // Use the external_link of the destination section for the link
-                        $child->link = $dest->external_link;
-                    } else {
-                        // Pointing at a regular section.  This is guaranteed to be
-                        // a regular section because aliases cannot be turned into sections,
-                        // (and vice-versa) and because the section::updateInternalLink
-                        // does 'alias to alias' dereferencing before the section is saved
-                        // (see models-1/section.php)
-                        //added by Tyler to pull the descriptions through for the children view
-                        $child->description = !empty($dest->description) ? $dest->description : '';
-                        $child->link        = expCore::makeLink(array('section' => $child->internal_id));
-                    }
-                } else {
-                    // Normal link, alias_type == 0.  Just create the URL from the section's id.
-                    $child->link = expCore::makeLink(array('section' => $child->id), '', $child->sef_name);
-                }
-                //$child->numChildren = $db->countObjects('section','parent='.$child->id);
-                $nodes[] = $child;
-                $nodes   = array_merge($nodes, section::levelTemplate($child->id, $depth + 1, $parents));
-            }
-        }
-        return $nodes;
-    }
-
-    /**
-     * Returns a flat representation of the full site hierarchy.
-     *
-     * @param int    $parent         top level parent id
-     * @param int    $depth          variable to hold level of recursion
-     * @param array  $ignore_ids     array of pages to ignore
-     * @param bool   $full           include a 'top' level entry
-     * @param string $perm           permission level to build list
-     * @param bool   $addstandalones should we add the stand-alone pages also
-     * @param bool   $addinternalalias
-     *
-     * @return array
-     * @deprecated 2.3.4 moved to section model, HOWEVER still used in theme config
-     */
-    public static function levelDropdownControlArray($parent, $depth = 0, $ignore_ids = array(), $full = false, $perm = 'view', $addstandalones = false, $addinternalalias = true) {
-        global $db;
-
-        $ar = array();
-        if ($parent == 0 && $full) {
-            $ar[0] = '&lt;' . gt('Top of Hierarchy') . '&gt;';
-        }
-        if ($addinternalalias) {
-            $intalias = '';
-        } else {
-            $intalias = ' AND alias_type != 2';
-        }
-        $nodes = $db->selectObjects('section', 'parent=' . $parent . $intalias, 'rank');
-        foreach ($nodes as $node) {
-            if ((($perm == 'view' && $node->public == 1) || expPermissions::check($perm, expCore::makeLocation('navigation', '', $node->id))) && !in_array($node->id, $ignore_ids)) {
-                if ($node->active == 1) {
-                    $text = str_pad('', ($depth + ($full ? 1 : 0)) * 3, '.', STR_PAD_LEFT) . $node->name;
-                } else {
-                    $text = str_pad('', ($depth + ($full ? 1 : 0)) * 3, '.', STR_PAD_LEFT) . '(' . $node->name . ')';
-                }
-                $ar[$node->id] = $text;
-                foreach (self::levelDropdownControlArray($node->id, $depth + 1, $ignore_ids, $full, $perm, $addstandalones, $addinternalalias) as $id => $text) {
-                    $ar[$id] = $text;
-                }
-            }
-        }
-        if ($addstandalones && $parent == 0) {
-            $sections = $db->selectObjects('section', 'parent=-1');
-            foreach ($sections as $node) {
-                if ((($perm == 'view' && $node->public == 1) || expPermissions::check($perm, expCore::makeLocation('navigation', '', $node->id))) && !in_array($node->id, $ignore_ids)) {
-                    if ($node->active == 1) {
-                        $text = str_pad('', ($depth + ($full ? 1 : 0)) * 3, '.', STR_PAD_LEFT) . $node->name;
-                    } else {
-                        $text = str_pad('', ($depth + ($full ? 1 : 0)) * 3, '.', STR_PAD_LEFT) . '(' . $node->name . ')';
-                    }
-                    $ar[$node->id] = '(' . gt('Standalone') . ') ' . $text;
-                }
-            }
-//            $ar = array_merge($ar,$sections);
-        }
-        return $ar;
-    }
-
-    /**
-     * add all module items to search index
-     *
-     * @return int
-     */
-    function addContentToSearch() {
-        global $db;
-
-        //global $sections;
-        //		global $router;
-//        $db->delete('search', "ref_module='navigation' AND ref_type='section'");
-        $db->delete('search', "ref_module='".$this->baseclassname."' AND ref_type='section'");
-        // this now ensures we get internal pages, instead of relying on the global $sections, which does not.
-        $sections = $db->selectObjects('section', 'active=1');
-        foreach ($sections as $section) {
-            $search_record = new stdClass();
-//            $search_record->category = 'Webpages';
-//            $search_record->ref_module = 'navigationController';
-//            $search_record->ref_type = 'section';
-//            $search_record->ref_module  = $this->classname;
-            $search_record->ref_module  = $this->baseclassname;
-            $search_record->category    = $this->searchName();
-            $search_record->ref_type    = $this->searchCategory();
-            $search_record->original_id = $section->id;
-            $search_record->title       = $section->name;
-            //$search_record->view_link = $router->buildUrlByPageId($section->id);
-            $link = str_replace(URL_FULL, '', makeLink(array('section' => $section->id)));
-            if ($link . '/' == URL_FULL) $link = '';
-            $search_record->view_link = $link;
-            $search_record->body      = $section->description;
-            $search_record->keywords  = $section->keywords;
-            // now we're going to grab all the textmodules on this page and build the body for the page based off the content
-            // of all the text module added together.
-            $loc = expCore::makeLocation('text');
-            $controllername = 'text';
-            foreach ($db->selectObjects('sectionref', "module='" . $controllername . "' AND section=" . $section->id) as $module) {
-                $loc->src   = $module->source;
-//                $controller = new $controllername();
-                $controller = expModules::getController($controllername);
-                $textitems  = $db->selectObjects($controller->model_table, "location_data='" . serialize($loc) . "'");
-                foreach ($textitems as $textitem) {
-                    if (!empty($textitem)) {
-                        $search_record->body .= ' ' . search::removeHTML($textitem->body) . ' ';
-                        $search_record->keywords .= " " . $textitem->title;
-                    }
-                }
-            }
-            $db->insertObject($search_record, 'search');
-        }
-        return count($sections);
-    }
-
-    /**
-     * Retrieve either the entire hierarchy, or a subset of the hierarchy, as an array suitable for use
-     * in a dropdowncontrol.  This is used primarily by the section datatype for moving and adding
-     * sections to specific parts of the site hierarchy.
-     *
-     * @param int   $parent     The id of the subtree parent.  If passed as 0 (the default), the entire subtree is parsed.
-     * @param int   $depth
-     * @param int   $default
-     * @param array $ignore_ids a value-array of IDs to be ignored when generating the list.  This is used
-     *                          when moving a section, since a section cannot be made a subsection of itself or any of its subsections.
-     *
-     * @return string
-     */
-    function levelShowDropdown($parent, $depth = 0, $default = 0, $ignore_ids = array()) {
-        global $db;
-
-        $html = '';
-        $nodes = $db->selectObjects('section', 'parent=' . $parent, 'rank');
-//		$nodes = expSorter::sort(array('array'=>$nodes,'sortby'=>'rank', 'order'=>'ASC'));
-        foreach ($nodes as $node) {
-            if (($node->public == 1 || expPermissions::check('view', expCore::makeLocation('navigation', '', $node->id))) && !in_array($node->id, $ignore_ids)) {
-                $html .= '<option value="' . $node->id . '" ';
-                if ($default == $node->id) $html .= 'selected';
-                $html .= '>';
-                if ($node->active == 1) {
-                    $html .= str_pad('', $depth * 3, '.', STR_PAD_LEFT) . $node->name;
-                } else {
-                    $html .= str_pad('', $depth * 3, '.', STR_PAD_LEFT) . '(' . $node->name . ')';
-                }
-                $html .= '</option>';
-                $html .= self::levelShowDropdown($node->id, $depth + 1, $default, $ignore_ids);
-            }
-        }
-        return $html;
-    }
-
-    /**
-     * recursively lists the template hierarchy
-     *
-     * @static
-     *
-     * @param int $parent top level parent id
-     * @param int $depth  variable to hold level of recursion
-     *
-     * @return array
-     * @deprecated 2.0.0 this only for deprecated templates
-     */
-    public static function getTemplateHierarchyFlat($parent, $depth = 1) {
-        global $db;
-
-        $arr  = array();
-        $kids = $db->selectObjects('section_template', 'parent=' . $parent, 'rank');
-//		$kids = expSorter::sort(array('array'=>$kids,'sortby'=>'rank', 'order'=>'ASC'));
-        for ($i = 0, $iMax = count($kids); $i < $iMax; $i++) {
-            $page        = $kids[$i];
-            $page->depth = $depth;
-            $page->first = ($i == 0 ? 1 : 0);
-            $page->last  = ($i == count($kids) - 1 ? 1 : 0);
-            $arr[]       = $page;
-            $arr         = array_merge($arr, self::getTemplateHierarchyFlat($page->id, $depth + 1));
-        }
-        return $arr;
-    }
-
-    /**
-     * @deprecated 2.0.0 this only for deprecated templates
-     */
-    public static function process_section($section, $template) {
-        global $db;
-
-        if (!is_object($template)) {
-            $template          = $db->selectObject('section_template', 'id=' . $template);
-            $section->subtheme = $template->subtheme;
-            $db->updateObject($section, 'section');
-        }
-        $prefix = '@st' . $template->id;
-        $refs   = $db->selectObjects('sectionref', "source LIKE '$prefix%'");
-        // Copy all modules and content for this section
-        foreach ($refs as $ref) {
-            $src = substr($ref->source, strlen($prefix)) . $section->id;
-            if (call_user_func(array($ref->module, 'hasContent'))) {
-                $oloc = expCore::makeLocation($ref->module, $ref->source);
-                $nloc = expCore::makeLocation($ref->module, $src);
-                if ($ref->module != "container") {
-                    call_user_func(array($ref->module, 'copyContent'), $oloc, $nloc);
-                } else {
-                    call_user_func(array($ref->module, 'copyContent'), $oloc, $nloc, $section->id);
-                }
-            }
-        }
-        // Grab sub pages
-        foreach ($db->selectObjects('section_template', 'parent=' . $template->id) as $t) {
-            self::process_subsections($section, $t);
-        }
-
-    }
-
-    /**
-     * @deprecated 2.0.0 this only for deprecated templates
-     */
-    function process_subsections($parent_section, $subtpl) {
-        global $db, $router;
-
-        $section              = new stdClass();
-        $section->parent      = $parent_section->id;
-        $section->name        = $subtpl->name;
-        $section->sef_name    = $router->encode($section->name);
-        $section->subtheme    = $subtpl->subtheme;
-        $section->active      = $subtpl->active;
-        $section->public      = $subtpl->public;
-        $section->rank        = $subtpl->rank;
-        $section->page_title  = $subtpl->page_title;
-        $section->keywords    = $subtpl->keywords;
-        $section->description = $subtpl->description;
-        $section->id          = $db->insertObject($section, 'section');
-        self::process_section($section, $subtpl);
-    }
-
-    /**
-     * Delete page and send its contents to the recycle bin
-     *
-     * @param $parent
-     * @deprecated 2.3.4 moved to section model
-     */
-    public static function deleteLevel($parent) {
-        global $db;
-
-        $kids = $db->selectObjects('section', 'parent=' . $parent);
-        foreach ($kids as $kid) {
-            self::deleteLevel($kid->id);
-        }
-        $secrefs = $db->selectObjects('sectionref', 'section=' . $parent);
-        foreach ($secrefs as $secref) {
-            $loc = expCore::makeLocation($secref->module, $secref->source, $secref->internal);
-            recyclebin::sendToRecycleBin($loc, $parent);
-            //FIXME if we delete the module & sectionref the module completely disappears
-//            if (class_exists($secref->module)) {
-//                $modclass = $secref->module;
-//                //FIXME: more module/controller glue code
-//                if (expModules::controllerExists($modclass)) {
-//                    $modclass = expModules::getControllerClassName($modclass);
-//                    $mod = new $modclass($loc->src);
-//                    $mod->delete_instance();
-//                } else {
-//                    $mod = new $modclass();
-//                    $mod->deleteIn($loc);
-//                }
-//            }
-        }
-//        $db->delete('sectionref', 'section=' . $parent);
-        $db->delete('section', 'parent=' . $parent);
-    }
-
-    /**
-     * Move content page and its children to stand-alones
-     *
-     * @param $parent
-     * @deprecated 2.3.4 moved to section model
-     */
-    public static function removeLevel($parent) {
-        global $db;
-
-        $kids = $db->selectObjects('section', 'parent=' . $parent);
-        foreach ($kids as $kid) {
-            $kid->parent = -1;
-            $db->updateObject($kid, 'section');
-            self::removeLevel($kid->id);
-        }
-    }
-
-    /**
-     * Check for cascading page view permission, esp. if not public
-     * @deprecated 2.3.4 moved to section model
-     */
-    public static function canView($section) {
-        global $db;
-
-        if ($section == null) {
-            return false;
-        }
-        if ($section->public == 0) {
-            // Not a public section.  Check permissions.
-            return expPermissions::check('view', expCore::makeLocation('navigation', '', $section->id));
-        } else { // Is public.  check parents.
-            if ($section->parent <= 0) {
-                // Out of parents, and since we are still checking, we haven't hit a private section.
-                return true;
-            } else {
-                $s = $db->selectObject('section', 'id=' . $section->parent);
-                return self::canView($s);
-            }
-        }
-    }
-
-    /**
-     * Check to see if page is public with cascading
-     * @deprecated 2.3.4 moved to section model
-     */
-    public static function isPublic($s) {
-        if ($s == null) {
-            return false;
-        }
-        while ($s->public && $s->parent > 0) {
-            $s = new section($s->parent);
-        }
-        $lineage = (($s->public) ? 1 : 0);
-        return $lineage;
-    }
-
-    public static function canManageStandalones() {
-        global $user;
-
-        if ($user->isAdmin()) return true;
-        $standalones = section::levelTemplate(-1, 0);
-        //		$canmanage = false;
-        foreach ($standalones as $standalone) {
-            $loc = expCore::makeLocation('navigation', '', $standalone->id);
-            if (expPermissions::check('manage', $loc)) return true;
-        }
-        return false;
-    }
-
-    /**
-     * Reassign permissions based on a check/change in menu/page hierarchy
-     *
-     * @static
-     *
-     * @param $id
-     */
-    public static function checkForSectionalAdmins($id) {
-        global $db;
-
-        $section = $db->selectObject('section', 'id=' . $id);
-        $branch  = section::levelTemplate($id, 0);
-        array_unshift($branch, $section);
-        $allusers  = array();
-        $allgroups = array();
-        while ($section->parent > 0) {
-            //			$ploc = expCore::makeLocation('navigationController', null, $section);
-            $allusers  = array_merge($allusers, $db->selectColumn('userpermission', 'uid', "permission='manage' AND module='navigation' AND internal=" . $section->parent));
-            $allgroups = array_merge($allgroups, $db->selectColumn('grouppermission', 'gid', "permission='manage' AND module='navigation' AND internal=" . $section->parent));
-            $section   = $db->selectObject('section', 'id=' . $section->parent);
-        }
-        foreach ($branch as $section) {
-            $sloc = expCore::makeLocation('navigation', null, $section->id);
-            // remove any manage permissions for this page and it's children
-            // $db->delete('userpermission', "module='navigationController' AND internal=".$section->id);
-            // $db->delete('grouppermission', "module='navigationController' AND internal=".$section->id);
-            foreach ($allusers as $uid) {
-                $u = user::getUserById($uid);
-                expPermissions::grant($u, 'manage', $sloc);
-            }
-            foreach ($allgroups as $gid) {
-                $g = group::getGroupById($gid);
-                expPermissions::grantGroup($g, 'manage', $sloc);
-            }
-        }
-    }
-
-    function manage() {
-        global $db, $router, $user;
-
-        expHistory::set('manageable', $router->params);
-        assign_to_template(array(
-            'canManageStandalones' => self::canManageStandalones(),
-            'sasections'           => $db->selectObjects('section', 'parent=-1'),
-            'user'                 => $user,
-//            'canManagePagesets'    => $user->isAdmin(),
-//            'templates'            => $db->selectObjects('section_template', 'parent=0'),
-        ));
-    }
-
-    public function manage_sitemap() {
-        global $db, $user, $sectionObj, $sections;
-
-        expHistory::set('viewable', $this->params);
-        $id      = $sectionObj->id;
-        $current = null;
-        // all we need to do is determine the current section
-        $navsections = $sections;
-        if ($sectionObj->parent == -1) {
-            $current = $sectionObj;
-        } else {
-            foreach ($navsections as $section) {
-                if ($section->id == $id) {
-                    $current = $section;
-                    break;
-                }
-            }
-        }
-        assign_to_template(array(
-            'sasections'   => $db->selectObjects('section', 'parent=-1'),
-            'sections'     => $navsections,
-            'current'      => $current,
-            'canManage'    => ((isset($user->is_acting_admin) && $user->is_acting_admin == 1) ? 1 : 0),
-        ));
-    }
-
-    /**
-     * Ajax request for specific pages as json date to yui tree
-     */
-    public static function returnChildrenAsJSON() {
-        global $db;
-
-        //$nav = section::levelTemplate(intval($_REQUEST['id'], 0));
-        $id         = isset($_REQUEST['id']) ? intval($_REQUEST['id']) : 0;
-        $nav        = $db->selectObjects('section', 'parent=' . $id, 'rank');
-        //FIXME $manage_all is moot w/ cascading perms now?
-        $manage_all = false;
-        if (expPermissions::check('manage', expCore::makeLocation('navigation', '', $id))) {
-            $manage_all = true;
-        }
-        //FIXME recode to use foreach $key=>$value
-        $navcount = count($nav);
-        for ($i = 0; $i < $navcount; $i++) {
-            if ($manage_all || expPermissions::check('manage', expCore::makeLocation('navigation', '', $nav[$i]->id))) {
-                $nav[$i]->manage = 1;
-                $view = true;
-            } else {
-                $nav[$i]->manage = 0;
-                $view = $nav[$i]->public ? true : expPermissions::check('view', expCore::makeLocation('navigation', '', $nav[$i]->id));
-            }
-            $nav[$i]->link = expCore::makeLink(array('section' => $nav[$i]->id), '', $nav[$i]->sef_name);
-            if (!$view) unset($nav[$i]);
-        }
-        $nav= array_values($nav);
-//        $nav[$navcount - 1]->last = true;
-        if (count($nav)) $nav[count($nav) - 1]->last = true;
-//        echo expJavascript::ajaxReply(201, '', $nav);
-        $ar = new expAjaxReply(201, '', $nav);
-        $ar->send();
-    }
-
-    /**
-     * Ajax request for all pages as json date to jstree
-     */
-    public static function returnChildrenAsJSON2() {
-        global $db;
-
-        $icons = array(
-            0 => 'addpage',
-            1 => 'addextpage',
-            2 => 'addintpage',
-            3 => 'addfreeform',
-        );
-
-        $navs        = $db->selectObjects('section', 'parent!=-1', 'rank');
-        foreach ($navs as $i=>$nav) {
-            $navs[$i]->parent = $nav->parent?$nav->parent:'#';
-            $navs[$i]->text = $nav->name;
-            $navs[$i]->icon = $icons[$nav->alias_type];
-            if (!$nav->active) {
-                $navs[$i]->icon .= ' inactive';
-                $attr = new stdClass();
-                $attr->class = 'inactive';  // class to obscure elements
-                $navs[$i]->a_attr = $attr;
-            }
-            if (expPermissions::check('manage', expCore::makeLocation('navigation', '', $navs[$i]->id))) {
-                $navs[$i]->manage = 1;
-                $view = true;
-            } else {
-                $navs[$i]->manage = 0;
-                $navs[$i]->state->disabled = true;
-                $view = $navs[$i]->public ? true : expPermissions::check('view', expCore::makeLocation('navigation', '', $navs[$i]->id));
-            }
-            $navs[$i]->link = expCore::makeLink(array('section' => $navs[$i]->id), '', $navs[$i]->sef_name);
-            if (!$view) {
-//                unset($navs[$i]);  //FIXME this breaks jstree if we remove a parent and not the child
-                $attr = new stdClass();
-                $attr->class = 'hidden';  // bs3 class to hide elements
-                $navs[$i]->li_attr = $attr;
-            }
-        }
-        $navs= array_values($navs);
-//        header('Content-Type: application/json; charset=utf8');
-		echo json_encode($navs);
-//        echo expJavascript::ajaxReply(201, '', $navs);
-        exit;
-    }
-
-    /**
-     * Ajax function to reorder page hierarchy from yui tree control
-     */
-    public static function DragnDropReRank() {
-        global $db, $router;
-
-        $move   = $router->params['move'];
-        $target = $router->params['target'];
-        $type   = $router->params['type'];
-        $targSec = $db->selectObject("section","id=".$target);
-//        $targSec  = new section($target);
-        $check_id = $targSec->parent;
-        $moveSec = $db->selectObject("section","id=".$move);
-//        $moveSec = new section($move);
-
-        // dropped on top of page
-        if ($type == "append") {
-            //save the old parent in case we are changing the depth of the moving section
-            $oldParent = $moveSec->parent;
-            //assign the parent of the moving section to the ID of the target section
-            $moveSec->parent = $targSec->id;
-            //set the rank of the moving section to 0 since it will appear first in the new order
-            $moveSec->rank = 1;
-            //select all children currently of the parent we're about to append to
-            $targSecChildren = $db->selectObjects("section", "parent=" . $targSec->id . " ORDER BY rank");
-            //update the ranks of the children to +1 higher to accommodate our new rank 0 section being moved in.
-            $newrank = 1;
-            foreach ($targSecChildren as $value) {
-                if ($value->id != $moveSec->id) {
-                    $value->rank = $newrank;
-                    $db->updateObject($value, 'section');
-                    $newrank++;
-                }
-            }
-            $db->updateObject($moveSec, 'section');
-            if ($oldParent != $moveSec->parent) {
-                //we need to re-rank the children of the parent that the miving section has just left
-                $childOfLastMove = $db->selectObjects("section", "parent=" . $oldParent . " ORDER BY rank");
-                for ($i = 0, $iMax = count($childOfLastMove); $i < $iMax; $i++) {
-                    $childOfLastMove[$i]->rank = $i;
-                    $db->updateObject($childOfLastMove[$i], 'section');
-                }
-
-            }
-//            echo $moveSec->name . " was appended to " . $targSec->name;
-
-        } elseif ($type == "after") {  // dropped between (after) pages
-            if ($targSec->parent == $moveSec->parent) {
-                //are we moving up...
-                if ($targSec->rank < $moveSec->rank) {
-                    $moveSec->rank    = $targSec->rank + 1;
-                    $moveNextSiblings = $db->selectObjects("section", "id!=" . $moveSec->id . " AND parent=" . $targSec->parent . " AND rank>" . $targSec->rank . " ORDER BY rank");
-                    $rerank           = $moveSec->rank + 1;
-                    foreach ($moveNextSiblings as $value) {
-                        if ($value->id != $moveSec->id) {
-                            $value->rank = $rerank;
-                            $db->updateObject($value, 'section');
-                            $rerank++;
-                        }
-                    }
-                    $db->updateObject($targSec, 'section');
-//                    $targSec->update();
-                    $db->updateObject($moveSec, 'section');
-//                    $moveSec->update();
-                    //or are we moving down...
-                } else {
-                    $targSec->rank        = $targSec->rank - 1;
-                    $moveSec->rank        = $targSec->rank + 1;
-                    $movePreviousSiblings = $db->selectObjects("section", "id!=" . $moveSec->id . " AND parent=" . $targSec->parent . " AND rank<=" . $targSec->rank . " ORDER BY rank");
-                    $rerank               = 1;
-                    foreach ($movePreviousSiblings as $value) {
-                        if ($value->id != $moveSec->id) {
-                            $value->rank = $rerank;
-                            $db->updateObject($value, 'section');
-                            $rerank++;
-                        }
-                    }
-                    $db->updateObject($targSec, 'section');
-//                    $targSec->update();
-                    $db->updateObject($moveSec, 'section');
-//                    $moveSec->update();
-                }
-            } else {  // 'before', is this used?
-                //store ranks from the depth we're moving from.  Used to re-rank the level depth the moving section is moving from.
-                $oldRank   = $moveSec->rank;
-                $oldParent = $moveSec->parent;
-                //select all children of the target sections parent with a rank higher than it's own
-                $moveNextSiblings = $db->selectObjects("section", "parent=" . $targSec->parent . " AND rank>" . $targSec->rank . " ORDER BY rank");
-                //update moving sections rank and parent
-                $moveSec->rank   = $targSec->rank + 1;
-                $moveSec->parent = $targSec->parent;
-                //$rerank=$moveSec->rank+1;
-                foreach ($moveNextSiblings as $value) {
-                    $value->rank = $value->rank + 1;
-                    $db->updateObject($value, 'section');
-                }
-                $db->updateObject($moveSec, 'section');
-                //handle re-ranking of previous parent
-                $oldSiblings = $db->selectObjects("section", "parent=" . $oldParent . " AND rank>" . $oldRank . " ORDER BY rank");
-                $rerank      = 1;
-                foreach ($oldSiblings as $value) {
-                    if ($value->id != $moveSec->id) {
-                        $value->rank = $rerank;
-                        $db->updateObject($value, 'section');
-                        $rerank++;
-                    }
-                }
-                if ($oldParent != $moveSec->parent) {
-                    //we need to re-rank the children of the parent that the moving section has just left
-                    $childOfLastMove = $db->selectObjects("section", "parent=" . $oldParent . " ORDER BY rank");
-                    for ($i = 0, $iMax = count($childOfLastMove); $i < $iMax; $i++) {
-                        $childOfLastMove[$i]->rank = $i;
-                        $db->updateObject($childOfLastMove[$i], 'section');
-                    }
-                }
-            }
-        }
-        self::checkForSectionalAdmins($move);
-        expSession::clearAllUsersSessionCache('navigation');
-    }
-
-    /**
-     * Ajax function to reorder page hierarchy from jstree control
-     */
-    public static function DragnDropReRank2() {
-        global $router, $db;
-
-        $id = $router->params['id'];
-        $page = new section($id);
-        $old_rank = $page->rank;
-        $old_parent = $page->parent;
-        $new_rank = $router->params['position'] + 1;  // rank
-        $new_parent = intval($router->params['parent']);
-
-        $db->decrement($page->tablename, 'rank', 1, 'rank>' . $old_rank . ' AND parent=' . $old_parent);  // close in hole
-        $db->increment($page->tablename, 'rank', 1, 'rank>=' . $new_rank . ' AND parent=' . $new_parent);  // make room
-
-        $params = array();
-        $params['parent'] = $new_parent;
-        $params['rank'] = $new_rank;
-        $page->update($params);
-
-        self::checkForSectionalAdmins($id);
-        expSession::clearAllUsersSessionCache('navigation');
-    }
-
-    function edit_section() {
-        global $db, $user;
-
-        $parent = new section($this->params['parent']);
-        if (empty($parent->id)) $parent->id = 0;
-        assign_to_template(array(
-            'haveStandalone'  => ($db->countObjects('section', 'parent=-1') && $parent->id >= 0),
-            'parent'          => $parent,
-            'isAdministrator' => $user->isAdmin(),
-        ));
-    }
-
-    function edit_contentpage() {
-        //FIXME we come here for new/edit content/standalone pages
-        // FIXME: Allow non-administrative users to manage certain parts of the section hierarchy.
-        //if ($user->is_acting_admin == 1 /*TODO: section admin*/) {
-//        $section = null;
-        $section = new stdClass();
-        if (isset($this->params['id'])) {
-            // Check to see if an id was passed in get.  If so, retrieve that section from
-            // the database, and perform an edit on it.
-            $section  = $this->section->find($this->params['id']);
-        } elseif (isset($this->params['parent'])) {
-            // The isset check is merely a precaution.  This action should
-            // ALWAYS be invoked with a parent or id value.
-            $section  = new section($this->params);
-        } else {
-            notfoundController::handle_not_found();
-            exit;
-        }
-        if (!empty($section->id)) {
-            $check_id = $section->id;
-        } else {
-            $check_id = $section->parent;
-        }
-        if (expPermissions::check('manage', expCore::makeLocation('navigation', '', $check_id))) {
-            if (empty($section->id)) {
-                $section->active = 1;
-                $section->public = 1;
-                if (!isset($section->parent)) {
-                    // This is another precaution.  The parent attribute
-                    // should ALWAYS be set by the caller.
-                    //FJD - if that's the case, then we should die.
-                    notfoundController::handle_not_authorized();
-                    exit;
-                    //$section->parent = 0;
-                }
-            }
-            assign_to_template(array(
-                'section' => $section,
-                'glyphs' => self::get_glyphs(),
-            ));
-        } else {  // User does not have permission to manage sections.  Throw a 403
-            notfoundController::handle_not_authorized();
-        }
-    }
-
-    private static function get_glyphs() {
-        if (bs()) {
-            require_once(BASE . 'external/font-awesome.class.php');
-            $fa = new Smk_FontAwesome;
-            if (bs3()) {
-                $icons = $fa->getArray(BASE . 'external/font-awesome4/css/font-awesome.css');
-                $icons = $fa->sortByName($icons);
-                return $fa->nameGlyph($icons);
-            } elseif (bs2()) {
-                expCSS::auto_compile_less(
-                    'external/font-awesome/less/font-awesome.less',
-                    'external/font-awesome/css/font-awesome.css'
-                ); // font-awesome is included within bootstrap2, but not as a separate .css file
-                $icons = $fa->getArray(BASE . 'external/font-awesome/css/font-awesome.css', 'icon-');
-                return $fa->nameGlyph($icons, 'icon-');
-            }
-        } else {
-            return array();
-        }
-    }
-
-    function edit_internalalias() {
-        $section = isset($this->params['id']) ? $this->section->find($this->params['id']) : new section($this->params);
-        if ($section->parent == -1) {
-            notfoundController::handle_not_found();
-            exit;
-        } // doesn't work for standalone pages
-        if (empty($section->id)) {
-            $section->public = 1;
-            if (!isset($section->parent)) {
-                // This is another precaution.  The parent attribute
-                // should ALWAYS be set by the caller.
-                //FJD - if that's the case, then we should die.
-                notfoundController::handle_not_authorized();
-                exit;
-                //$section->parent = 0;
-            }
-        }
-        assign_to_template(array(
-            'section' => $section,
-            'glyphs' => self::get_glyphs(),
-        ));
-    }
-
-    function edit_freeform() {
-        $section = isset($this->params['id']) ? $this->section->find($this->params['id']) : new section($this->params);
-        if ($section->parent == -1) {
-            notfoundController::handle_not_found();
-            exit;
-        } // doesn't work for standalone pages
-        if (empty($section->id)) {
-            $section->public = 1;
-            if (!isset($section->parent)) {
-                // This is another precaution.  The parent attribute
-                // should ALWAYS be set by the caller.
-                //FJD - if that's the case, then we should die.
-                notfoundController::handle_not_authorized();
-                exit;
-                //$section->parent = 0;
-            }
-        }
-        assign_to_template(array(
-            'section' => $section,
-            'glyphs' => self::get_glyphs(),
-        ));
-    }
-
-    function edit_externalalias() {
-        $section = isset($this->params['id']) ? $this->section->find($this->params['id']) : new section($this->params);
-        if ($section->parent == -1) {
-            notfoundController::handle_not_found();
-            exit;
-        } // doesn't work for standalone pages
-        if (empty($section->id)) {
-            $section->public = 1;
-            if (!isset($section->parent)) {
-                // This is another precaution.  The parent attribute
-                // should ALWAYS be set by the caller.
-                //FJD - if that's the case, then we should die.
-                notfoundController::handle_not_authorized();
-                exit;
-                //$section->parent = 0;
-            }
-        }
-        assign_to_template(array(
-            'section' => $section,
-            'glyphs' => self::get_glyphs(),
-        ));
-    }
-
-    function update() {
-        parent::update();
-        expSession::clearAllUsersSessionCache('navigation');
-    }
-
-    function move_standalone() {
-        expSession::clearAllUsersSessionCache('navigation');
-        assign_to_template(array(
-            'parent' => $this->params['parent'],
-        ));
-    }
-
-    /**
-     * Move standalone back to hierarchy
-     *
-     */
-    function reparent_standalone() {
-        $standalone = $this->section->find($this->params['page']);
-        if ($standalone) {
-            $standalone->parent = $this->params['parent'];
-            $standalone->update();
-            expSession::clearAllUsersSessionCache('navigation');
-            expHistory::back();
-        } else {
-            notfoundController::handle_not_found();
-        }
-    }
-
-    /**
-     * Move content page to standalones
-     *
-     */
-    function remove() {
-        global $db;
-
-        $section = $db->selectObject('section', 'id=' . $this->params['id']);
-        if ($section) {
-            section::removeLevel($section->id);
-            $db->decrement('section', 'rank', 1, 'rank > ' . $section->rank . ' AND parent=' . $section->parent);
-            $section->parent = -1;
-            $db->updateObject($section, 'section');
-            expSession::clearAllUsersSessionCache('navigation');
-            expHistory::back();
-        } else {
-            notfoundController::handle_not_authorized();
-        }
-    }
-
-    function delete_standalones() {
-        if (!empty($this->params['deleteit'])) {
-            foreach ($this->params['deleteit'] as $page) {
-                $section = new section(intval($page));
-                if ($section) {
-//                    self::deleteLevel($section->id);
-                    $section->delete();
-                }
-            }
-        }
-        expSession::clearAllUsersSessionCache('navigation');
-        expHistory::back();
-    }
-
-    // create a psuedo global manage pages permission
-    public static function checkPermissions($permission,$location) {
-        global $exponent_permissions_r, $router;
-
-        // only applies to the 'manage' method
-        if (empty($location->src) && empty($location->int) && (!empty($router->params['action']) && $router->params['action'] == 'manage') || strpos($router->current_url, 'action=manage') !== false) {
-            if (!empty($exponent_permissions_r['navigation'])) foreach ($exponent_permissions_r['navigation'] as $page) {
-                foreach ($page as $pageperm) {
-                    if (!empty($pageperm['manage'])) return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Rebuild the sectionref table as a list of modules on a page
-     * @deprecated 2.3.4 moved to sectionref model
-     */
-    public static function rebuild_sectionrefs() {
-        global $db;
-
-        // recursive run though all the nested containers
-        function scan_container($container_id, $page_id) {
-            global $db;
-
-            $containers = $db->selectObjects('container',"external='" . $container_id . "'");
-            $ret = '';
-            foreach ($containers as $container) {
-                $iLoc = expUnserialize($container->internal);
-                $newret = recyclebin::restoreFromRecycleBin($iLoc, $page_id);
-                if (!empty($newret)) $ret .= $newret . '<br>';
-                if ($iLoc->mod == 'container') {
-                    $ret .= scan_container($container->internal, $page_id);
-                }
-            }
-            return $ret;
-        }
-
-        // recursive run through all the nested pages
-        function scan_page($parent_id) {
-            global $db;
-
-            $sections = $db->selectObjects('section','parent=' . $parent_id);
-            $ret = '';
-            foreach ($sections as $page) {
-                $cLoc = serialize(expCore::makeLocation('container','@section' . $page->id));
-                $ret .= scan_container($cLoc, $page->id);
-                $ret .= scan_page($page->id);
-            }
-            return $ret;
-        }
-
-        // first remove duplicate records
-        $db->sql('DELETE FROM ' . $db->prefix . 'sectionref WHERE id NOT IN (SELECT * FROM (SELECT MIN(n.id) FROM ' . $db->prefix . 'sectionref n GROUP BY n.module, n.source) x)');
-        $ret = scan_page(0);  // the page hierarchy
-        $ret .= scan_page(-1);  // now the stand alone pages
-
-        // we need to get the non-main containers such as sidebars, footers, etc...
-        $hardcodedmods = $db->selectObjects('sectionref',"refcount=1000 AND source NOT LIKE '%@section%' AND source NOT LIKE '%@random%'");
-        foreach ($hardcodedmods as $hardcodedmod) {
-            if ($hardcodedmod->module == 'container') {
-                $page_id = intval(preg_replace('/\D/', '', $hardcodedmod->source));
-                if (empty($page_id)) {
-                    $page_id = SITE_DEFAULT_SECTION;  // we'll default to the home page
-                }
-                $ret .= scan_container(serialize(expCore::makeLocation($hardcodedmod->module, $hardcodedmod->source)), $page_id);
-            } else {
-                $hardcodedmod->section = 0;  // this is a hard-coded non-container module
-                $db->updateObject($hardcodedmod, 'sectionref');
-            }
-        }
-
-        // mark modules in the recycle bin as section 0
-        $db->columnUpdate('sectionref', 'section', 0, "refcount=0");
-//        $recycledmods = $db->selectObjects('sectionref',"refcount=0");
-//        foreach ($recycledmods as $recycledmod) {
-//            $recycledmod->section = 0;  // this is a module in the recycle bin
-//            $db->updateObject($recycledmod, 'sectionref');
-//        }
-        return $ret;
-    }
-
-}
-
-?>
+<?php
+
+##################################################
+#
+# Copyright (c) 2004-2016 OIC Group, Inc.
+#
+# This file is part of Exponent
+#
+# Exponent is free software; you can redistribute
+# it and/or modify it under the terms of the GNU
+# General Public License as published by the Free
+# Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# GPL: http://www.gnu.org/licenses/gpl.txt
+#
+##################################################
+/**
+ * @subpackage Controllers
+ * @package    Modules
+ */
+class navigationController extends expController {
+    public $basemodel_name = 'section';
+    public $useractions = array(
+        'showall' => 'Show Navigation',
+        'breadcrumb' => 'Breadcrumb',
+    );
+    protected $remove_permissions = array(
+//        'configure',
+//        'create',
+//        'delete',
+//        'edit'
+    );
+    protected $add_permissions = array(
+        'manage'    => 'Manage',
+        'view'      => "View Page"
+    );
+    protected $manage_permissions = array(
+        'move'      => 'Move Page',
+        'remove'    => 'Remove Page',
+        'reparent'    => 'Reparent Page',
+    );
+    public $remove_configs = array(
+        'aggregation',
+        'categories',
+        'comments',
+        'ealerts',
+        'facebook',
+        'files',
+        'pagination',
+        'rss',
+        'tags',
+        'twitter',
+    );  // all options: ('aggregation','categories','comments','ealerts','facebook','files','pagination','rss','tags','twitter',)
+
+    static function displayname() { return gt("Navigation"); }
+
+    static function description() { return gt("Places navigation links/menus on the page."); }
+
+    static function isSearchable() { return true; }
+
+    function searchName() { return gt('Webpage'); }
+
+    /**
+     * @param null $src
+     * @param array $params
+     *
+     */
+    function __construct($src = null, $params = array())
+    {
+        parent::__construct($src, $params);
+        if (!empty($params['id']))  // we normally throw out the $loc->int EXCEPT with navigation pages
+            $this->loc = expCore::makeLocation($this->baseclassname, $src, $params['id']);
+    }
+
+    public function showall() {
+        global $user, $sectionObj, $sections;
+
+        expHistory::set('viewable', $this->params);
+        $id      = $sectionObj->id;
+        $current = null;
+        // all we need to do is determine the current section
+        $navsections = $sections;
+        if ($sectionObj->parent == -1) {
+            $current = $sectionObj;
+        } else {
+            foreach ($navsections as $section) {
+                if ($section->id == $id) {
+                    $current = $section;
+                    break;
+                }
+            }
+        }
+        assign_to_template(array(
+            'sections'     => $navsections,
+            'current'      => $current,
+            'canManage'    => ((isset($user->is_acting_admin) && $user->is_acting_admin == 1) ? 1 : 0),
+        ));
+    }
+
+    public function breadcrumb() {
+        global $sectionObj;
+
+        expHistory::set('viewable', $this->params);
+        $id      = $sectionObj->id;
+        $current = null;
+        // Show not only the location of a page in the hierarchy but also the location of a standalone page
+        $current = new section($id);
+        if ($current->parent == -1) {  // standalone page
+            $navsections = section::levelTemplate(-1, 0);
+            foreach ($navsections as $section) {
+                if ($section->id == $id) {
+                    $current = $section;
+                    break;
+                }
+            }
+        } else {
+            $navsections = section::levelTemplate(0, 0);
+            foreach ($navsections as $section) {
+                if ($section->id == $id) {
+                    $current = $section;
+                    break;
+                }
+            }
+        }
+        assign_to_template(array(
+            'sections'     => $navsections,
+            'current'      => $current,
+        ));
+    }
+
+    /**
+     * @deprecated 2.3.4 moved to section model
+     */
+    public static function navhierarchy($notyui=false) {
+        global $sections;
+
+        $json_array = array();
+        for ($i = 0, $iMax = count($sections); $i < $iMax; $i++) {
+            if ($sections[$i]->depth == 0) {
+                $obj = new stdClass();
+//   				$obj->id = $sections[$i]->name.$sections[$i]->id;
+                $obj->id   = $sections[$i]->id;
+                $obj->text = $sections[$i]->name;
+                $obj->title = $sections[$i]->page_title;
+                $obj->description = $sections[$i]->description;
+                $obj->new_window = $sections[$i]->new_window;
+                $obj->expFile = $sections[$i]->expFile;
+                $obj->glyph = $sections[$i]->glyph;
+                $obj->glyph_only = $sections[$i]->glyph_only;
+                $obj->type = $sections[$i]->alias_type;
+                if ($sections[$i]->active == 1) {
+                    $obj->url = $sections[$i]->link;
+                    if ($obj->type == 1 && substr($obj->url, 0, 4) != 'http') {
+                        $obj->url = 'http://' . $obj->url;
+                    }
+                } else {
+                    $obj->url     = "#";
+                    $obj->onclick = "onclick: { fn: return false }";
+                }
+                if ($obj->type == 3) {  // mostly a hack instead of adding more table fields
+                    $obj->width = $sections[$i]->internal_id;
+                    $obj->class = $sections[$i]->external_link;
+                }
+                /*if ($sections[$i]->active == 1) {
+                    $obj->disabled = false;
+                } else {
+                    $obj->disabled = true;
+                }*/
+                //$obj->disabled = true;
+                $obj->itemdata = self::getChildren($i,$notyui);
+                $obj->maxitems = count($obj->itemdata);
+                $obj->maxdepth = 0;
+                foreach ($obj->itemdata as $menu) {
+                    if ($menu->maxdepth > $obj->maxdepth) $obj->maxdepth = $menu->maxdepth;
+                }
+            }
+            $json_array[] = $obj;
+        }
+        return $json_array;
+    }
+
+    /**
+     * @deprecated 2.3.4 moved to section model
+     */
+    public static function navtojson() {
+        return json_encode(self::navhierarchy());
+    }
+
+    /**
+     * @deprecated 2.3.4 moved to section model
+     */
+    public static function getChildren(&$i, $notyui=false) {
+        global $sections;
+
+        //		echo "i=".$i."<br>";
+        if ($i + 1 == count($sections)) { // last entry
+            return array();
+        } elseif ($sections[$i]->depth == $sections[$i + 1]->depth) {
+            return array();
+        } else {
+            $ret_depth = $sections[$i]->depth;
+            $i++;
+            $ret_array = array();
+            for ($iMax = count($sections); $i < $iMax; $i++) {
+                // start setting up the objects to return
+                $obj       = new stdClass();
+                $obj->id   = $sections[$i]->id;
+                $obj->text = $sections[$i]->name;
+                $obj->title = $sections[$i]->page_title;
+                $obj->description = $sections[$i]->description;
+                $obj->new_window = $sections[$i]->new_window;
+                $obj->expFile = $sections[$i]->expFile;
+                $obj->glyph = $sections[$i]->glyph;
+                $obj->glyph_only = $sections[$i]->glyph_only;
+                $obj->depth = $sections[$i]->depth;
+                if ($sections[$i]->active == 1) {
+                    $obj->url = $sections[$i]->link;
+                    if ($sections[$i]->alias_type == 1 && substr($obj->url, 0, 4) != 'http') {
+                        $obj->url = 'http://' . $obj->url;
+                    }
+                } else {
+                    $obj->url     = "#";
+                    $obj->onclick = "onclick: { fn: return false }";
+                }
+                //echo "i=".$i."<br>";
+                if (self::hasChildren($i)) {
+                    if ($notyui) {
+                        $obj->itemdata = self::getChildren($i,$notyui);
+                        $obj->maxitems = count($obj->itemdata);
+                        $obj->maxdepth = 0;
+                        foreach ($obj->itemdata as $menu) {
+                            if (!empty($menu->maxdepth)) {
+                                if ($menu->maxdepth > $obj->maxdepth) $obj->maxdepth = $menu->maxdepth;
+                            } else {
+                                if ($menu->depth > $obj->maxdepth) $obj->maxdepth = $menu->depth;
+                            }
+                        }
+                    } else {
+                        $obj->submenu     = new stdClass();
+                        $obj->submenu->id = $sections[$i]->name . $sections[$i]->id;
+                        //echo "getting children of ".$sections[$i]->name;
+                        $obj->submenu->itemdata = self::getChildren($i,$notyui);
+                        $obj->maxitems = count($obj->submenu->itemdata);
+                        $obj->maxdepth = 0;
+                        foreach ($obj->submenu->itemdata as $menu) {
+                            if (!empty($menu->maxdepth)) {
+                                if ($menu->maxdepth > $obj->maxdepth) $obj->maxdepth = $menu->maxdepth;
+                            } else {
+                                if ($menu->depth > $obj->maxdepth) $obj->maxdepth = $menu->depth;
+                            }
+                        }
+                    }
+                    $ret_array[]            = $obj;
+                } else {
+                    $obj->maxdepth = $obj->depth;
+                    $ret_array[] = $obj;
+                }
+                if (($i + 1) >= count($sections) || $sections[$i + 1]->depth <= $ret_depth) {
+                    return $ret_array;
+                }
+            }
+            return array();
+        }
+    }
+
+    /**
+     * @deprecated 2.3.4 moved to section model
+     */
+    public static function hasChildren($i) {
+        global $sections;
+
+        if (($i + 1) >= count($sections)) return false;
+        return ($sections[$i]->depth < $sections[$i + 1]->depth) ? true : false;
+    }
+
+    /** exdoc
+     * Creates a location object, based off of the three arguments passed, and returns it.
+     *
+     * @return array
+     * @deprecated 2.3.4 moved to section model
+     */
+    public static function initializeNavigation() {
+        $sections = section::levelTemplate(0, 0);
+        return $sections;
+    }
+
+    /**
+     * returns all the section's children
+     *
+     * @static
+     *
+     * @param int   $parent top level parent id
+     * @param int   $depth  variable to hold level of recursion
+     * @param array $parents
+     *
+     * @return array
+     * @deprecated 2.3.4 moved to section model
+     */
+    public static function levelTemplate($parent, $depth = 0, $parents = array()) {
+        global $user;
+
+        if ($parent != 0) $parents[] = $parent;
+        $nodes = array();
+        $cache = expSession::getCacheValue('navigation');
+        $sect = new section();
+        if (!isset($cache['kids'][$parent])) {
+            $kids = $sect->find('all','parent=' . $parent);
+            $cache['kids'][$parent] = $kids;
+            expSession::setCacheValue('navigation', $cache);
+        } else {
+            $kids = $cache['kids'][$parent];
+        }
+        $kids = expSorter::sort(array('array' => $kids, 'sortby' => 'rank', 'order' => 'ASC'));
+        for ($i = 0, $iMax = count($kids); $i < $iMax; $i++) {
+            $child = $kids[$i];
+            //foreach ($kids as $child) {
+            if ($child->public == 1 || expPermissions::check('view', expCore::makeLocation('navigation', '', $child->id))) {
+                $child->numParents    = count($parents);
+                $child->depth         = $depth;
+                $child->first         = ($i == 0 ? 1 : 0);
+                $child->last          = ($i == count($kids) - 1 ? 1 : 0);
+                $child->parents       = $parents;
+                $child->canManage     = (isset($user->is_acting_admin) && $user->is_acting_admin == 1 ? 1 : 0);
+                $child->canManageRank = $child->canManage;
+                if (!isset($child->sef_name)) {
+                    $child->sef_name = '';
+                }
+                // Generate the link attribute base on alias type.
+                if ($child->alias_type == 1) {
+                    // External link.  Set the link to the configured website URL.
+                    // This is guaranteed to be a full URL because of the
+                    // section::updateExternalAlias() method in models-1/section.php
+                    $child->link = $child->external_link;
+                } else if ($child->alias_type == 2) {
+                    // Internal link.
+                    // Need to check and see if the internal_id is pointing at an external link.
+//                    $dest = $db->selectObject('section', 'id=' . $child->internal_id);
+                    $dest = $sect->find('first','id=' . $child->internal_id);
+                    if (!empty($dest->alias_type) && $dest->alias_type == 1) {
+                        // This internal alias is pointing at an external alias.
+                        // Use the external_link of the destination section for the link
+                        $child->link = $dest->external_link;
+                    } else {
+                        // Pointing at a regular section.  This is guaranteed to be
+                        // a regular section because aliases cannot be turned into sections,
+                        // (and vice-versa) and because the section::updateInternalLink
+                        // does 'alias to alias' dereferencing before the section is saved
+                        // (see models-1/section.php)
+                        //added by Tyler to pull the descriptions through for the children view
+                        $child->description = !empty($dest->description) ? $dest->description : '';
+                        $child->link        = expCore::makeLink(array('section' => $child->internal_id));
+                    }
+                } else {
+                    // Normal link, alias_type == 0.  Just create the URL from the section's id.
+                    $child->link = expCore::makeLink(array('section' => $child->id), '', $child->sef_name);
+                }
+                //$child->numChildren = $db->countObjects('section','parent='.$child->id);
+                $nodes[] = $child;
+                $nodes   = array_merge($nodes, section::levelTemplate($child->id, $depth + 1, $parents));
+            }
+        }
+        return $nodes;
+    }
+
+    /**
+     * Returns a flat representation of the full site hierarchy.
+     *
+     * @param int    $parent         top level parent id
+     * @param int    $depth          variable to hold level of recursion
+     * @param array  $ignore_ids     array of pages to ignore
+     * @param bool   $full           include a 'top' level entry
+     * @param string $perm           permission level to build list
+     * @param bool   $addstandalones should we add the stand-alone pages also
+     * @param bool   $addinternalalias
+     *
+     * @return array
+     * @deprecated 2.3.4 moved to section model, HOWEVER still used in theme config
+     */
+    public static function levelDropdownControlArray($parent, $depth = 0, $ignore_ids = array(), $full = false, $perm = 'view', $addstandalones = false, $addinternalalias = true) {
+        global $db;
+
+        $ar = array();
+        if ($parent == 0 && $full) {
+            $ar[0] = '&lt;' . gt('Top of Hierarchy') . '&gt;';
+        }
+        if ($addinternalalias) {
+            $intalias = '';
+        } else {
+            $intalias = ' AND alias_type != 2';
+        }
+        $nodes = $db->selectObjects('section', 'parent=' . $parent . $intalias, 'rank');
+        foreach ($nodes as $node) {
+            if ((($perm == 'view' && $node->public == 1) || expPermissions::check($perm, expCore::makeLocation('navigation', '', $node->id))) && !in_array($node->id, $ignore_ids)) {
+                if ($node->active == 1) {
+                    $text = str_pad('', ($depth + ($full ? 1 : 0)) * 3, '.', STR_PAD_LEFT) . $node->name;
+                } else {
+                    $text = str_pad('', ($depth + ($full ? 1 : 0)) * 3, '.', STR_PAD_LEFT) . '(' . $node->name . ')';
+                }
+                $ar[$node->id] = $text;
+                foreach (self::levelDropdownControlArray($node->id, $depth + 1, $ignore_ids, $full, $perm, $addstandalones, $addinternalalias) as $id => $text) {
+                    $ar[$id] = $text;
+                }
+            }
+        }
+        if ($addstandalones && $parent == 0) {
+            $sections = $db->selectObjects('section', 'parent=-1');
+            foreach ($sections as $node) {
+                if ((($perm == 'view' && $node->public == 1) || expPermissions::check($perm, expCore::makeLocation('navigation', '', $node->id))) && !in_array($node->id, $ignore_ids)) {
+                    if ($node->active == 1) {
+                        $text = str_pad('', ($depth + ($full ? 1 : 0)) * 3, '.', STR_PAD_LEFT) . $node->name;
+                    } else {
+                        $text = str_pad('', ($depth + ($full ? 1 : 0)) * 3, '.', STR_PAD_LEFT) . '(' . $node->name . ')';
+                    }
+                    $ar[$node->id] = '(' . gt('Standalone') . ') ' . $text;
+                }
+            }
+//            $ar = array_merge($ar,$sections);
+        }
+        return $ar;
+    }
+
+    /**
+     * add all module items to search index
+     *
+     * @return int
+     */
+    function addContentToSearch() {
+        global $db;
+
+        //global $sections;
+        //		global $router;
+//        $db->delete('search', "ref_module='navigation' AND ref_type='section'");
+        $db->delete('search', "ref_module='".$this->baseclassname."' AND ref_type='section'");
+        // this now ensures we get internal pages, instead of relying on the global $sections, which does not.
+        $sections = $db->selectObjects('section', 'active=1');
+        foreach ($sections as $section) {
+            $search_record = new stdClass();
+//            $search_record->category = 'Webpages';
+//            $search_record->ref_module = 'navigationController';
+//            $search_record->ref_type = 'section';
+//            $search_record->ref_module  = $this->classname;
+            $search_record->ref_module  = $this->baseclassname;
+            $search_record->category    = $this->searchName();
+            $search_record->ref_type    = $this->searchCategory();
+            $search_record->original_id = $section->id;
+            $search_record->title       = $section->name;
+            //$search_record->view_link = $router->buildUrlByPageId($section->id);
+            $link = str_replace(URL_FULL, '', makeLink(array('section' => $section->id)));
+            if ($link . '/' == URL_FULL) $link = '';
+            $search_record->view_link = $link;
+            $search_record->body      = $section->description;
+            $search_record->keywords  = $section->keywords;
+            // now we're going to grab all the textmodules on this page and build the body for the page based off the content
+            // of all the text module added together.
+            $loc = expCore::makeLocation('text');
+            $controllername = 'text';
+            foreach ($db->selectObjects('sectionref', "module='" . $controllername . "' AND section=" . $section->id) as $module) {
+                $loc->src   = $module->source;
+//                $controller = new $controllername();
+                $controller = expModules::getController($controllername);
+                $textitems  = $db->selectObjects($controller->model_table, "location_data='" . serialize($loc) . "'");
+                foreach ($textitems as $textitem) {
+                    if (!empty($textitem)) {
+                        $search_record->body .= ' ' . search::removeHTML($textitem->body) . ' ';
+                        $search_record->keywords .= " " . $textitem->title;
+                    }
+                }
+            }
+            $db->insertObject($search_record, 'search');
+        }
+        return count($sections);
+    }
+
+    /**
+     * Retrieve either the entire hierarchy, or a subset of the hierarchy, as an array suitable for use
+     * in a dropdowncontrol.  This is used primarily by the section datatype for moving and adding
+     * sections to specific parts of the site hierarchy.
+     *
+     * @param int   $parent     The id of the subtree parent.  If passed as 0 (the default), the entire subtree is parsed.
+     * @param int   $depth
+     * @param int   $default
+     * @param array $ignore_ids a value-array of IDs to be ignored when generating the list.  This is used
+     *                          when moving a section, since a section cannot be made a subsection of itself or any of its subsections.
+     *
+     * @return string
+     */
+    function levelShowDropdown($parent, $depth = 0, $default = 0, $ignore_ids = array()) {
+        global $db;
+
+        $html = '';
+        $nodes = $db->selectObjects('section', 'parent=' . $parent, 'rank');
+//		$nodes = expSorter::sort(array('array'=>$nodes,'sortby'=>'rank', 'order'=>'ASC'));
+        foreach ($nodes as $node) {
+            if (($node->public == 1 || expPermissions::check('view', expCore::makeLocation('navigation', '', $node->id))) && !in_array($node->id, $ignore_ids)) {
+                $html .= '<option value="' . $node->id . '" ';
+                if ($default == $node->id) $html .= 'selected';
+                $html .= '>';
+                if ($node->active == 1) {
+                    $html .= str_pad('', $depth * 3, '.', STR_PAD_LEFT) . $node->name;
+                } else {
+                    $html .= str_pad('', $depth * 3, '.', STR_PAD_LEFT) . '(' . $node->name . ')';
+                }
+                $html .= '</option>';
+                $html .= self::levelShowDropdown($node->id, $depth + 1, $default, $ignore_ids);
+            }
+        }
+        return $html;
+    }
+
+    /**
+     * recursively lists the template hierarchy
+     *
+     * @static
+     *
+     * @param int $parent top level parent id
+     * @param int $depth  variable to hold level of recursion
+     *
+     * @return array
+     * @deprecated 2.0.0 this only for deprecated templates
+     */
+    public static function getTemplateHierarchyFlat($parent, $depth = 1) {
+        global $db;
+
+        $arr  = array();
+        $kids = $db->selectObjects('section_template', 'parent=' . $parent, 'rank');
+//		$kids = expSorter::sort(array('array'=>$kids,'sortby'=>'rank', 'order'=>'ASC'));
+        for ($i = 0, $iMax = count($kids); $i < $iMax; $i++) {
+            $page        = $kids[$i];
+            $page->depth = $depth;
+            $page->first = ($i == 0 ? 1 : 0);
+            $page->last  = ($i == count($kids) - 1 ? 1 : 0);
+            $arr[]       = $page;
+            $arr         = array_merge($arr, self::getTemplateHierarchyFlat($page->id, $depth + 1));
+        }
+        return $arr;
+    }
+
+    /**
+     * @deprecated 2.0.0 this only for deprecated templates
+     */
+    public static function process_section($section, $template) {
+        global $db;
+
+        if (!is_object($template)) {
+            $template          = $db->selectObject('section_template', 'id=' . $template);
+            $section->subtheme = $template->subtheme;
+            $db->updateObject($section, 'section');
+        }
+        $prefix = '@st' . $template->id;
+        $refs   = $db->selectObjects('sectionref', "source LIKE '$prefix%'");
+        // Copy all modules and content for this section
+        foreach ($refs as $ref) {
+            $src = substr($ref->source, strlen($prefix)) . $section->id;
+            if (call_user_func(array($ref->module, 'hasContent'))) {
+                $oloc = expCore::makeLocation($ref->module, $ref->source);
+                $nloc = expCore::makeLocation($ref->module, $src);
+                if ($ref->module != "container") {
+                    call_user_func(array($ref->module, 'copyContent'), $oloc, $nloc);
+                } else {
+                    call_user_func(array($ref->module, 'copyContent'), $oloc, $nloc, $section->id);
+                }
+            }
+        }
+        // Grab sub pages
+        foreach ($db->selectObjects('section_template', 'parent=' . $template->id) as $t) {
+            self::process_subsections($section, $t);
+        }
+
+    }
+
+    /**
+     * @deprecated 2.0.0 this only for deprecated templates
+     */
+    function process_subsections($parent_section, $subtpl) {
+        global $db, $router;
+
+        $section              = new stdClass();
+        $section->parent      = $parent_section->id;
+        $section->name        = $subtpl->name;
+        $section->sef_name    = $router->encode($section->name);
+        $section->subtheme    = $subtpl->subtheme;
+        $section->active      = $subtpl->active;
+        $section->public      = $subtpl->public;
+        $section->rank        = $subtpl->rank;
+        $section->page_title  = $subtpl->page_title;
+        $section->keywords    = $subtpl->keywords;
+        $section->description = $subtpl->description;
+        $section->id          = $db->insertObject($section, 'section');
+        self::process_section($section, $subtpl);
+    }
+
+    /**
+     * Delete page and send its contents to the recycle bin
+     *
+     * @param $parent
+     * @deprecated 2.3.4 moved to section model
+     */
+    public static function deleteLevel($parent) {
+        global $db;
+
+        $kids = $db->selectObjects('section', 'parent=' . $parent);
+        foreach ($kids as $kid) {
+            self::deleteLevel($kid->id);
+        }
+        $secrefs = $db->selectObjects('sectionref', 'section=' . $parent);
+        foreach ($secrefs as $secref) {
+            $loc = expCore::makeLocation($secref->module, $secref->source, $secref->internal);
+            recyclebin::sendToRecycleBin($loc, $parent);
+            //FIXME if we delete the module & sectionref the module completely disappears
+//            if (class_exists($secref->module)) {
+//                $modclass = $secref->module;
+//                //FIXME: more module/controller glue code
+//                if (expModules::controllerExists($modclass)) {
+//                    $modclass = expModules::getControllerClassName($modclass);
+//                    $mod = new $modclass($loc->src);
+//                    $mod->delete_instance();
+//                } else {
+//                    $mod = new $modclass();
+//                    $mod->deleteIn($loc);
+//                }
+//            }
+        }
+//        $db->delete('sectionref', 'section=' . $parent);
+        $db->delete('section', 'parent=' . $parent);
+    }
+
+    /**
+     * Move content page and its children to stand-alones
+     *
+     * @param $parent
+     * @deprecated 2.3.4 moved to section model
+     */
+    public static function removeLevel($parent) {
+        global $db;
+
+        $kids = $db->selectObjects('section', 'parent=' . $parent);
+        foreach ($kids as $kid) {
+            $kid->parent = -1;
+            $db->updateObject($kid, 'section');
+            self::removeLevel($kid->id);
+        }
+    }
+
+    /**
+     * Check for cascading page view permission, esp. if not public
+     * @deprecated 2.3.4 moved to section model
+     */
+    public static function canView($section) {
+        global $db;
+
+        if ($section == null) {
+            return false;
+        }
+        if ($section->public == 0) {
+            // Not a public section.  Check permissions.
+            return expPermissions::check('view', expCore::makeLocation('navigation', '', $section->id));
+        } else { // Is public.  check parents.
+            if ($section->parent <= 0) {
+                // Out of parents, and since we are still checking, we haven't hit a private section.
+                return true;
+            } else {
+                $s = $db->selectObject('section', 'id=' . $section->parent);
+                return self::canView($s);
+            }
+        }
+    }
+
+    /**
+     * Check to see if page is public with cascading
+     * @deprecated 2.3.4 moved to section model
+     */
+    public static function isPublic($s) {
+        if ($s == null) {
+            return false;
+        }
+        while ($s->public && $s->parent > 0) {
+            $s = new section($s->parent);
+        }
+        $lineage = (($s->public) ? 1 : 0);
+        return $lineage;
+    }
+
+    public static function canManageStandalones() {
+        global $user;
+
+        if ($user->isAdmin()) return true;
+        $standalones = section::levelTemplate(-1, 0);
+        //		$canmanage = false;
+        foreach ($standalones as $standalone) {
+            $loc = expCore::makeLocation('navigation', '', $standalone->id);
+            if (expPermissions::check('manage', $loc)) return true;
+        }
+        return false;
+    }
+
+    /**
+     * Reassign permissions based on a check/change in menu/page hierarchy
+     *
+     * @static
+     *
+     * @param $id
+     */
+    public static function checkForSectionalAdmins($id) {
+        global $db;
+
+        $section = $db->selectObject('section', 'id=' . $id);
+        $branch  = section::levelTemplate($id, 0);
+        array_unshift($branch, $section);
+        $allusers  = array();
+        $allgroups = array();
+        while ($section->parent > 0) {
+            //			$ploc = expCore::makeLocation('navigationController', null, $section);
+            $allusers  = array_merge($allusers, $db->selectColumn('userpermission', 'uid', "permission='manage' AND module='navigation' AND internal=" . $section->parent));
+            $allgroups = array_merge($allgroups, $db->selectColumn('grouppermission', 'gid', "permission='manage' AND module='navigation' AND internal=" . $section->parent));
+            $section   = $db->selectObject('section', 'id=' . $section->parent);
+        }
+        foreach ($branch as $section) {
+            $sloc = expCore::makeLocation('navigation', null, $section->id);
+            // remove any manage permissions for this page and it's children
+            // $db->delete('userpermission', "module='navigationController' AND internal=".$section->id);
+            // $db->delete('grouppermission', "module='navigationController' AND internal=".$section->id);
+            foreach ($allusers as $uid) {
+                $u = user::getUserById($uid);
+                expPermissions::grant($u, 'manage', $sloc);
+            }
+            foreach ($allgroups as $gid) {
+                $g = group::getGroupById($gid);
+                expPermissions::grantGroup($g, 'manage', $sloc);
+            }
+        }
+    }
+
+    function manage() {
+        global $db, $router, $user;
+
+        expHistory::set('manageable', $router->params);
+        assign_to_template(array(
+            'canManageStandalones' => self::canManageStandalones(),
+            'sasections'           => $db->selectObjects('section', 'parent=-1'),
+            'user'                 => $user,
+//            'canManagePagesets'    => $user->isAdmin(),
+//            'templates'            => $db->selectObjects('section_template', 'parent=0'),
+        ));
+    }
+
+    public function manage_sitemap() {
+        global $db, $user, $sectionObj, $sections;
+
+        expHistory::set('viewable', $this->params);
+        $id      = $sectionObj->id;
+        $current = null;
+        // all we need to do is determine the current section
+        $navsections = $sections;
+        if ($sectionObj->parent == -1) {
+            $current = $sectionObj;
+        } else {
+            foreach ($navsections as $section) {
+                if ($section->id == $id) {
+                    $current = $section;
+                    break;
+                }
+            }
+        }
+        assign_to_template(array(
+            'sasections'   => $db->selectObjects('section', 'parent=-1'),
+            'sections'     => $navsections,
+            'current'      => $current,
+            'canManage'    => ((isset($user->is_acting_admin) && $user->is_acting_admin == 1) ? 1 : 0),
+        ));
+    }
+
+    /**
+     * Ajax request for specific pages as json date to yui tree
+     */
+    public static function returnChildrenAsJSON() {
+        global $db;
+
+        //$nav = section::levelTemplate(intval($_REQUEST['id'], 0));
+        $id         = isset($_REQUEST['id']) ? intval($_REQUEST['id']) : 0;
+        $nav        = $db->selectObjects('section', 'parent=' . $id, 'rank');
+        //FIXME $manage_all is moot w/ cascading perms now?
+        $manage_all = false;
+        if (expPermissions::check('manage', expCore::makeLocation('navigation', '', $id))) {
+            $manage_all = true;
+        }
+        //FIXME recode to use foreach $key=>$value
+        $navcount = count($nav);
+        for ($i = 0; $i < $navcount; $i++) {
+            if ($manage_all || expPermissions::check('manage', expCore::makeLocation('navigation', '', $nav[$i]->id))) {
+                $nav[$i]->manage = 1;
+                $view = true;
+            } else {
+                $nav[$i]->manage = 0;
+                $view = $nav[$i]->public ? true : expPermissions::check('view', expCore::makeLocation('navigation', '', $nav[$i]->id));
+            }
+            $nav[$i]->link = expCore::makeLink(array('section' => $nav[$i]->id), '', $nav[$i]->sef_name);
+            if (!$view) unset($nav[$i]);
+        }
+        $nav= array_values($nav);
+//        $nav[$navcount - 1]->last = true;
+        if (count($nav)) $nav[count($nav) - 1]->last = true;
+//        echo expJavascript::ajaxReply(201, '', $nav);
+        $ar = new expAjaxReply(201, '', $nav);
+        $ar->send();
+    }
+
+    /**
+     * Ajax request for all pages as json date to jstree
+     */
+    public static function returnChildrenAsJSON2() {
+        global $db;
+
+        $icons = array(
+            0 => 'addpage',
+            1 => 'addextpage',
+            2 => 'addintpage',
+            3 => 'addfreeform',
+        );
+
+        $navs        = $db->selectObjects('section', 'parent!=-1', 'rank');
+        foreach ($navs as $i=>$nav) {
+            $navs[$i]->parent = $nav->parent?$nav->parent:'#';
+            $navs[$i]->text = $nav->name;
+            $navs[$i]->icon = $icons[$nav->alias_type];
+            if (!$nav->active) {
+                $navs[$i]->icon .= ' inactive';
+                $attr = new stdClass();
+                $attr->class = 'inactive';  // class to obscure elements
+                $navs[$i]->a_attr = $attr;
+            }
+            if (expPermissions::check('manage', expCore::makeLocation('navigation', '', $navs[$i]->id))) {
+                $navs[$i]->manage = 1;
+                $view = true;
+            } else {
+                $navs[$i]->manage = 0;
+                $navs[$i]->state->disabled = true;
+                $view = $navs[$i]->public ? true : expPermissions::check('view', expCore::makeLocation('navigation', '', $navs[$i]->id));
+            }
+            $navs[$i]->link = expCore::makeLink(array('section' => $navs[$i]->id), '', $navs[$i]->sef_name);
+            if (!$view) {
+//                unset($navs[$i]);  //FIXME this breaks jstree if we remove a parent and not the child
+                $attr = new stdClass();
+                $attr->class = 'hidden';  // bs3 class to hide elements
+                $navs[$i]->li_attr = $attr;
+            }
+        }
+        $navs= array_values($navs);
+//        header('Content-Type: application/json; charset=utf8');
+		echo json_encode($navs);
+//        echo expJavascript::ajaxReply(201, '', $navs);
+        exit;
+    }
+
+    /**
+     * Ajax function to reorder page hierarchy from yui tree control
+     */
+    public static function DragnDropReRank() {
+        global $db, $router;
+
+        $move   = $router->params['move'];
+        $target = $router->params['target'];
+        $type   = $router->params['type'];
+        $targSec = $db->selectObject("section","id=".$target);
+//        $targSec  = new section($target);
+        $check_id = $targSec->parent;
+        $moveSec = $db->selectObject("section","id=".$move);
+//        $moveSec = new section($move);
+
+        // dropped on top of page
+        if ($type == "append") {
+            //save the old parent in case we are changing the depth of the moving section
+            $oldParent = $moveSec->parent;
+            //assign the parent of the moving section to the ID of the target section
+            $moveSec->parent = $targSec->id;
+            //set the rank of the moving section to 0 since it will appear first in the new order
+            $moveSec->rank = 1;
+            //select all children currently of the parent we're about to append to
+            $targSecChildren = $db->selectObjects("section", "parent=" . $targSec->id . " ORDER BY rank");
+            //update the ranks of the children to +1 higher to accommodate our new rank 0 section being moved in.
+            $newrank = 1;
+            foreach ($targSecChildren as $value) {
+                if ($value->id != $moveSec->id) {
+                    $value->rank = $newrank;
+                    $db->updateObject($value, 'section');
+                    $newrank++;
+                }
+            }
+            $db->updateObject($moveSec, 'section');
+            if ($oldParent != $moveSec->parent) {
+                //we need to re-rank the children of the parent that the miving section has just left
+                $childOfLastMove = $db->selectObjects("section", "parent=" . $oldParent . " ORDER BY rank");
+                for ($i = 0, $iMax = count($childOfLastMove); $i < $iMax; $i++) {
+                    $childOfLastMove[$i]->rank = $i;
+                    $db->updateObject($childOfLastMove[$i], 'section');
+                }
+
+            }
+//            echo $moveSec->name . " was appended to " . $targSec->name;
+
+        } elseif ($type == "after") {  // dropped between (after) pages
+            if ($targSec->parent == $moveSec->parent) {
+                //are we moving up...
+                if ($targSec->rank < $moveSec->rank) {
+                    $moveSec->rank    = $targSec->rank + 1;
+                    $moveNextSiblings = $db->selectObjects("section", "id!=" . $moveSec->id . " AND parent=" . $targSec->parent . " AND rank>" . $targSec->rank . " ORDER BY rank");
+                    $rerank           = $moveSec->rank + 1;
+                    foreach ($moveNextSiblings as $value) {
+                        if ($value->id != $moveSec->id) {
+                            $value->rank = $rerank;
+                            $db->updateObject($value, 'section');
+                            $rerank++;
+                        }
+                    }
+                    $db->updateObject($targSec, 'section');
+//                    $targSec->update();
+                    $db->updateObject($moveSec, 'section');
+//                    $moveSec->update();
+                    //or are we moving down...
+                } else {
+                    $targSec->rank        = $targSec->rank - 1;
+                    $moveSec->rank        = $targSec->rank + 1;
+                    $movePreviousSiblings = $db->selectObjects("section", "id!=" . $moveSec->id . " AND parent=" . $targSec->parent . " AND rank<=" . $targSec->rank . " ORDER BY rank");
+                    $rerank               = 1;
+                    foreach ($movePreviousSiblings as $value) {
+                        if ($value->id != $moveSec->id) {
+                            $value->rank = $rerank;
+                            $db->updateObject($value, 'section');
+                            $rerank++;
+                        }
+                    }
+                    $db->updateObject($targSec, 'section');
+//                    $targSec->update();
+                    $db->updateObject($moveSec, 'section');
+//                    $moveSec->update();
+                }
+            } else {  // 'before', is this used?
+                //store ranks from the depth we're moving from.  Used to re-rank the level depth the moving section is moving from.
+                $oldRank   = $moveSec->rank;
+                $oldParent = $moveSec->parent;
+                //select all children of the target sections parent with a rank higher than it's own
+                $moveNextSiblings = $db->selectObjects("section", "parent=" . $targSec->parent . " AND rank>" . $targSec->rank . " ORDER BY rank");
+                //update moving sections rank and parent
+                $moveSec->rank   = $targSec->rank + 1;
+                $moveSec->parent = $targSec->parent;
+                //$rerank=$moveSec->rank+1;
+                foreach ($moveNextSiblings as $value) {
+                    $value->rank = $value->rank + 1;
+                    $db->updateObject($value, 'section');
+                }
+                $db->updateObject($moveSec, 'section');
+                //handle re-ranking of previous parent
+                $oldSiblings = $db->selectObjects("section", "parent=" . $oldParent . " AND rank>" . $oldRank . " ORDER BY rank");
+                $rerank      = 1;
+                foreach ($oldSiblings as $value) {
+                    if ($value->id != $moveSec->id) {
+                        $value->rank = $rerank;
+                        $db->updateObject($value, 'section');
+                        $rerank++;
+                    }
+                }
+                if ($oldParent != $moveSec->parent) {
+                    //we need to re-rank the children of the parent that the moving section has just left
+                    $childOfLastMove = $db->selectObjects("section", "parent=" . $oldParent . " ORDER BY rank");
+                    for ($i = 0, $iMax = count($childOfLastMove); $i < $iMax; $i++) {
+                        $childOfLastMove[$i]->rank = $i;
+                        $db->updateObject($childOfLastMove[$i], 'section');
+                    }
+                }
+            }
+        }
+        self::checkForSectionalAdmins($move);
+        expSession::clearAllUsersSessionCache('navigation');
+    }
+
+    /**
+     * Ajax function to reorder page hierarchy from jstree control
+     */
+    public static function DragnDropReRank2() {
+        global $router, $db;
+
+        $id = $router->params['id'];
+        $page = new section($id);
+        $old_rank = $page->rank;
+        $old_parent = $page->parent;
+        $new_rank = $router->params['position'] + 1;  // rank
+        $new_parent = intval($router->params['parent']);
+
+        $db->decrement($page->tablename, 'rank', 1, 'rank>' . $old_rank . ' AND parent=' . $old_parent);  // close in hole
+        $db->increment($page->tablename, 'rank', 1, 'rank>=' . $new_rank . ' AND parent=' . $new_parent);  // make room
+
+        $params = array();
+        $params['parent'] = $new_parent;
+        $params['rank'] = $new_rank;
+        $page->update($params);
+
+        self::checkForSectionalAdmins($id);
+        expSession::clearAllUsersSessionCache('navigation');
+    }
+
+    function edit_section() {
+        global $db, $user;
+
+        $parent = new section($this->params['parent']);
+        if (empty($parent->id)) $parent->id = 0;
+        assign_to_template(array(
+            'haveStandalone'  => ($db->countObjects('section', 'parent=-1') && $parent->id >= 0),
+            'parent'          => $parent,
+            'isAdministrator' => $user->isAdmin(),
+        ));
+    }
+
+    function edit_contentpage() {
+        //FIXME we come here for new/edit content/standalone pages
+        // FIXME: Allow non-administrative users to manage certain parts of the section hierarchy.
+        //if ($user->is_acting_admin == 1 /*TODO: section admin*/) {
+//        $section = null;
+        $section = new stdClass();
+        if (isset($this->params['id'])) {
+            // Check to see if an id was passed in get.  If so, retrieve that section from
+            // the database, and perform an edit on it.
+            $section  = $this->section->find($this->params['id']);
+        } elseif (isset($this->params['parent'])) {
+            // The isset check is merely a precaution.  This action should
+            // ALWAYS be invoked with a parent or id value.
+            $section  = new section($this->params);
+        } else {
+            notfoundController::handle_not_found();
+            exit;
+        }
+        if (!empty($section->id)) {
+            $check_id = $section->id;
+        } else {
+            $check_id = $section->parent;
+        }
+        if (expPermissions::check('manage', expCore::makeLocation('navigation', '', $check_id))) {
+            if (empty($section->id)) {
+                $section->active = 1;
+                $section->public = 1;
+                if (!isset($section->parent)) {
+                    // This is another precaution.  The parent attribute
+                    // should ALWAYS be set by the caller.
+                    //FJD - if that's the case, then we should die.
+                    notfoundController::handle_not_authorized();
+                    exit;
+                    //$section->parent = 0;
+                }
+            }
+            assign_to_template(array(
+                'section' => $section,
+                'glyphs' => self::get_glyphs(),
+            ));
+        } else {  // User does not have permission to manage sections.  Throw a 403
+            notfoundController::handle_not_authorized();
+        }
+    }
+
+    private static function get_glyphs() {
+        if (bs()) {
+            require_once(BASE . 'external/font-awesome.class.php');
+            $fa = new Smk_FontAwesome;
+            if (bs3()) {
+                $icons = $fa->getArray(BASE . 'external/font-awesome4/css/font-awesome.css');
+                $icons = $fa->sortByName($icons);
+                return $fa->nameGlyph($icons);
+            } elseif (bs2()) {
+                expCSS::auto_compile_less(
+                    'external/font-awesome/less/font-awesome.less',
+                    'external/font-awesome/css/font-awesome.css'
+                ); // font-awesome is included within bootstrap2, but not as a separate .css file
+                $icons = $fa->getArray(BASE . 'external/font-awesome/css/font-awesome.css', 'icon-');
+                return $fa->nameGlyph($icons, 'icon-');
+            }
+        } else {
+            return array();
+        }
+    }
+
+    function edit_internalalias() {
+        $section = isset($this->params['id']) ? $this->section->find($this->params['id']) : new section($this->params);
+        if ($section->parent == -1) {
+            notfoundController::handle_not_found();
+            exit;
+        } // doesn't work for standalone pages
+        if (empty($section->id)) {
+            $section->public = 1;
+            if (!isset($section->parent)) {
+                // This is another precaution.  The parent attribute
+                // should ALWAYS be set by the caller.
+                //FJD - if that's the case, then we should die.
+                notfoundController::handle_not_authorized();
+                exit;
+                //$section->parent = 0;
+            }
+        }
+        assign_to_template(array(
+            'section' => $section,
+            'glyphs' => self::get_glyphs(),
+        ));
+    }
+
+    function edit_freeform() {
+        $section = isset($this->params['id']) ? $this->section->find($this->params['id']) : new section($this->params);
+        if ($section->parent == -1) {
+            notfoundController::handle_not_found();
+            exit;
+        } // doesn't work for standalone pages
+        if (empty($section->id)) {
+            $section->public = 1;
+            if (!isset($section->parent)) {
+                // This is another precaution.  The parent attribute
+                // should ALWAYS be set by the caller.
+                //FJD - if that's the case, then we should die.
+                notfoundController::handle_not_authorized();
+                exit;
+                //$section->parent = 0;
+            }
+        }
+        assign_to_template(array(
+            'section' => $section,
+            'glyphs' => self::get_glyphs(),
+        ));
+    }
+
+    function edit_externalalias() {
+        $section = isset($this->params['id']) ? $this->section->find($this->params['id']) : new section($this->params);
+        if ($section->parent == -1) {
+            notfoundController::handle_not_found();
+            exit;
+        } // doesn't work for standalone pages
+        if (empty($section->id)) {
+            $section->public = 1;
+            if (!isset($section->parent)) {
+                // This is another precaution.  The parent attribute
+                // should ALWAYS be set by the caller.
+                //FJD - if that's the case, then we should die.
+                notfoundController::handle_not_authorized();
+                exit;
+                //$section->parent = 0;
+            }
+        }
+        assign_to_template(array(
+            'section' => $section,
+            'glyphs' => self::get_glyphs(),
+        ));
+    }
+
+    function update() {
+        parent::update();
+        expSession::clearAllUsersSessionCache('navigation');
+    }
+
+    function move_standalone() {
+        expSession::clearAllUsersSessionCache('navigation');
+        assign_to_template(array(
+            'parent' => $this->params['parent'],
+        ));
+    }
+
+    /**
+     * Move standalone back to hierarchy
+     *
+     */
+    function reparent_standalone() {
+        $standalone = $this->section->find($this->params['page']);
+        if ($standalone) {
+            $standalone->parent = $this->params['parent'];
+            $standalone->update();
+            expSession::clearAllUsersSessionCache('navigation');
+            expHistory::back();
+        } else {
+            notfoundController::handle_not_found();
+        }
+    }
+
+    /**
+     * Move content page to standalones
+     *
+     */
+    function remove() {
+        global $db;
+
+        $section = $db->selectObject('section', 'id=' . $this->params['id']);
+        if ($section) {
+            section::removeLevel($section->id);
+            $db->decrement('section', 'rank', 1, 'rank > ' . $section->rank . ' AND parent=' . $section->parent);
+            $section->parent = -1;
+            $db->updateObject($section, 'section');
+            expSession::clearAllUsersSessionCache('navigation');
+            expHistory::back();
+        } else {
+            notfoundController::handle_not_authorized();
+        }
+    }
+
+    function delete_standalones() {
+        if (!empty($this->params['deleteit'])) {
+            foreach ($this->params['deleteit'] as $page) {
+                $section = new section(intval($page));
+                if ($section) {
+//                    self::deleteLevel($section->id);
+                    $section->delete();
+                }
+            }
+        }
+        expSession::clearAllUsersSessionCache('navigation');
+        expHistory::back();
+    }
+
+    /**
+     * permission functions to aggregate a module's visible permissions based on add/remove permissions
+     *
+     * @return array
+     */
+    public function permissions() {
+        //set the permissions array
+        return $this->add_permissions;
+    }
+
+    // create a psuedo global manage pages permission
+    public static function checkPermissions($permission,$location) {
+        global $exponent_permissions_r, $router;
+
+        // only applies to the 'manage' method
+        if (empty($location->src) && empty($location->int) && ((!empty($router->params['action']) && $router->params['action'] == 'manage') || strpos($router->current_url, 'action=manage') !== false)) {
+            if (!empty($exponent_permissions_r['navigation'])) foreach ($exponent_permissions_r['navigation'] as $page) {
+                foreach ($page as $pageperm) {
+                    if (!empty($pageperm['manage'])) return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Rebuild the sectionref table as a list of modules on a page
+     * @deprecated 2.3.4 moved to sectionref model
+     */
+    public static function rebuild_sectionrefs() {
+        global $db;
+
+        // recursive run though all the nested containers
+        function scan_container($container_id, $page_id) {
+            global $db;
+
+            $containers = $db->selectObjects('container',"external='" . $container_id . "'");
+            $ret = '';
+            foreach ($containers as $container) {
+                $iLoc = expUnserialize($container->internal);
+                $newret = recyclebin::restoreFromRecycleBin($iLoc, $page_id);
+                if (!empty($newret)) $ret .= $newret . '<br>';
+                if ($iLoc->mod == 'container') {
+                    $ret .= scan_container($container->internal, $page_id);
+                }
+            }
+            return $ret;
+        }
+
+        // recursive run through all the nested pages
+        function scan_page($parent_id) {
+            global $db;
+
+            $sections = $db->selectObjects('section','parent=' . $parent_id);
+            $ret = '';
+            foreach ($sections as $page) {
+                $cLoc = serialize(expCore::makeLocation('container','@section' . $page->id));
+                $ret .= scan_container($cLoc, $page->id);
+                $ret .= scan_page($page->id);
+            }
+            return $ret;
+        }
+
+        // first remove duplicate records
+        $db->sql('DELETE FROM ' . $db->prefix . 'sectionref WHERE id NOT IN (SELECT * FROM (SELECT MIN(n.id) FROM ' . $db->prefix . 'sectionref n GROUP BY n.module, n.source) x)');
+        $ret = scan_page(0);  // the page hierarchy
+        $ret .= scan_page(-1);  // now the stand alone pages
+
+        // we need to get the non-main containers such as sidebars, footers, etc...
+        $hardcodedmods = $db->selectObjects('sectionref',"refcount=1000 AND source NOT LIKE '%@section%' AND source NOT LIKE '%@random%'");
+        foreach ($hardcodedmods as $hardcodedmod) {
+            if ($hardcodedmod->module == 'container') {
+                $page_id = intval(preg_replace('/\D/', '', $hardcodedmod->source));
+                if (empty($page_id)) {
+                    $page_id = SITE_DEFAULT_SECTION;  // we'll default to the home page
+                }
+                $ret .= scan_container(serialize(expCore::makeLocation($hardcodedmod->module, $hardcodedmod->source)), $page_id);
+            } else {
+                $hardcodedmod->section = 0;  // this is a hard-coded non-container module
+                $db->updateObject($hardcodedmod, 'sectionref');
+            }
+        }
+
+        // mark modules in the recycle bin as section 0
+        $db->columnUpdate('sectionref', 'section', 0, "refcount=0");
+//        $recycledmods = $db->selectObjects('sectionref',"refcount=0");
+//        foreach ($recycledmods as $recycledmod) {
+//            $recycledmod->section = 0;  // this is a module in the recycle bin
+//            $db->updateObject($recycledmod, 'sectionref');
+//        }
+        return $ret;
+    }
+
+}
+
+?>

programming_language: PHP
filename: newsController.php
change_type: ModificationType.MODIFY
diff: @@ -26,6 +26,14 @@ class newsController extends expController {
         'showall'=>'Show all News',
         'tags'=>"Tags",
     );
+    protected $add_permissions = array(
+        'showUnpublished'=>'View Unpublished News',
+        'showExpired'=>'View Unpublished News',
+    );
+    protected $manage_permissions = array(
+        'import'=>'Import News Items',
+        'export'=>'Export News Items'
+    );
     public $remove_configs = array(
         'categories',
         'comments',
@@ -33,11 +41,6 @@ class newsController extends expController {
 //        'facebook',
 //        'twitter',
     );  // all options: ('aggregation','categories','comments','ealerts','facebook','files','pagination','rss','tags','twitter',)
-    protected $add_permissions = array(
-        'showUnpublished'=>'View Unpublished News',
-        'import'=>'Import News Items',
-        'export'=>'Export News Items'
-    );
 
     static function displayname() { return gt("News"); }
     static function description() { return gt("Display & manage news type content on your site."); }
@@ -58,7 +61,7 @@ class newsController extends expController {
             $limit = $this->params['limit'] == 'none' ? null : $this->params['limit'];
         } else {
             $limit = (isset($this->config['limit']) && $this->config['limit'] != '') ? $this->config['limit'] : 10;
-        }       
+        }
         $order = isset($this->config['order']) ? $this->config['order'] : 'publish DESC';
 
         // pull the news posts from the database
@@ -66,7 +69,7 @@ class newsController extends expController {
 
         // merge in any RSS news and perform the sort and limit the number of posts we return to the configured amount.
         if (!empty($this->config['pull_rss'])) $items = $this->mergeRssData($items);
-        
+
         // setup the pagination object to paginate the news stories.
         $page = new expPaginator(array(
             'records'=>$items,
@@ -78,7 +81,7 @@ class newsController extends expController {
             'src'=>$this->loc->src,
             'view'=>empty($this->params['view']) ? null : $this->params['view']
         ));
-            
+
         assign_to_template(array(
             'page'=>$page,
             'items'=>$page->records,
@@ -134,7 +137,7 @@ class newsController extends expController {
         if (isset($this->params['id'])) {
             $id = $this->params['id'];
         } elseif (isset($this->params['title'])) {
-            $id = $this->params['title'];
+            $id = expString::escape($this->params['title']);
         }
 
         $record = new news($id);
@@ -176,7 +179,7 @@ class newsController extends expController {
 
     public function showUnpublished() {
         expHistory::set('viewable', $this->params);
-        
+
         // setup the where clause for looking up records.
         $where = parent::aggregateWhereClause();
         $where = "((unpublish != 0 AND unpublish < ".time().") OR (publish > ".time().")) AND ".$where;
@@ -197,38 +200,38 @@ class newsController extends expController {
                 gt('Status')=>'unpublish'
             ),
         ));
-            
+
         assign_to_template(array(
             'page'=>$page
         ));
     }
-    
+
     public function showExpired() {
         redirect_to(array('controller'=>'news', 'action'=>'showUnpublished','src'=>$this->params['src']));
     }
-    
+
 //    public function configure() {
 //        parent::configure();
 //        assign_to_template(array('sortopts'=>$this->sortopts));
 //    }
-    
-    public function saveConfig() { 
+
+    public function saveconfig() {
         if (!empty($this->params['aggregate']) || !empty($this->params['pull_rss'])) {
             if ($this->params['order'] == 'rank ASC') {
                 expValidator::failAndReturnToForm(gt('User defined ranking is not allowed when aggregating or pull RSS data feeds.'), $this->params);
             }
         }
-        
-        parent::saveConfig();
+
+        parent::saveconfig();
     }
-    
+
     public function getRSSContent($limit = 0) {
         // pull the news posts from the database
         $items = $this->news->find('all', $this->aggregateWhereClause(), isset($this->config['order']) ? $this->config['order'] : 'publish DESC', $limit);
 
         //Convert the newsitems to rss items
         $rssitems = array();
-        foreach ($items as $key => $item) { 
+        foreach ($items as $key => $item) {
             $rss_item = new FeedItem();
             $rss_item->title = expString::convertSmartQuotes($item->title);
             $rss_item->link = $rss_item->guid = makeLink(array('controller'=>'news', 'action'=>'show', 'title'=>$item->sef_url));
@@ -252,7 +255,7 @@ class newsController extends expController {
      * @return array
      */
     private function mergeRssData($items) {
-        if (!empty($this->config['pull_rss'])) {    
+        if (!empty($this->config['pull_rss'])) {
             $RSS = new SimplePie();
 	        $RSS->set_cache_location(BASE.'tmp/rsscache');  // default is ./cache
 //	        $RSS->set_cache_duration(3600);  // default is 3600

programming_language: PHP
filename: photosController.php
change_type: ModificationType.MODIFY
diff: @@ -28,6 +28,9 @@ class photosController extends expController {
 //        'slideshow'=>'Slideshow',
 //        //'showall_tags'=>"Tag Categories"
 //    );
+    protected $manage_permissions = array(
+        'multi'=>'Bulk Actions',
+    );
     public $remove_configs = array(
         'comments',
         'ealerts',
@@ -41,7 +44,7 @@ class photosController extends expController {
     static function displayname() { return gt("Photo Album"); }
     static function description() { return gt("Displays and manages images."); }
     static function isSearchable() { return true; }
-    
+
     public function showall() {
         expHistory::set('viewable', $this->params);
         $limit = (isset($this->config['limit']) && $this->config['limit'] != '') ? $this->config['limit'] : 10;
@@ -66,22 +69,22 @@ class photosController extends expController {
                 gt('Title')=>'title'
             ),
         ));
-                    
+
         assign_to_template(array(
             'page'=>$page,
             'params'=>$this->params,
         ));
     }
-    
+
     function show() {
         expHistory::set('viewable', $this->params);
-        
+
         // figure out if we're looking this up by id or title
         $id = null;
         if (isset($this->params['id'])) {
             $id = $this->params['id'];
         } elseif (isset($this->params['title'])) {
-            $id = $this->params['title'];
+            $id = expString::escape($this->params['title']);
         }
         $record = new photo($id);
         if (empty($record->id))
@@ -121,7 +124,7 @@ class photosController extends expController {
             'config'=>$config
         ));
     }
-    
+
     public function slideshow() {
         expHistory::set('viewable', $this->params);
         $order = isset($this->config['order']) ? $this->config['order'] : "rank";
@@ -147,7 +150,7 @@ class photosController extends expController {
             'slides'=>$page->records,
         ));
     }
-    
+
     public function showall_tags() {
         $images = $this->image->find('all');
         $used_tags = array();
@@ -160,14 +163,14 @@ class photosController extends expController {
                     $used_tags[$tag->id] = $exptag;
                     $used_tags[$tag->id]->count = 1;
                 }
-                
+
             }
         }
-        
+
         assign_to_template(array(
             'tags'=>$used_tags
         ));
-    }           
+    }
 
     /**
      * Returns rich snippet PageMap meta data
@@ -195,7 +198,7 @@ class photosController extends expController {
 
         //populate the alt tag field if the user didn't
         if (empty($this->params['alt'])) $this->params['alt'] = $this->params['title'];
-        
+
         // call expController update to save the image
         parent::update();
     }

programming_language: PHP
filename: pixidouController.php
change_type: ModificationType.MODIFY
diff: @@ -22,11 +22,10 @@
  */
 
 class pixidouController extends expController {
-//    public $cacheDir = "framework/modules/pixidou/images/";
 	public $cacheDir = "tmp/pixidou/";
     public $requires_login = array(
-        'editor',
-        'exitEditor'
+        'editor'=>'You must be logged in to perform this action',
+        'exitEditor'=>'You must be logged in to perform this action',
     );
 
     static function displayname() { return gt("Pixidou Image Editor"); }
@@ -40,23 +39,23 @@ class pixidouController extends expController {
 
     function editor() {
         global $user;
-        
+
         $file = new expFile($this->params['id']);
-        
-        $canSaveOg = $user->id==$file->poster || $user->is_admin ? 1 : 0 ;
-	    if (file_exists(BASE.$file->directory.$file->filename)) {
-			$file->copyToDirectory(BASE.$this->cacheDir);
+
+        $canSaveOg = $user->id==$file->poster || $user->isSuperAdmin() ? 1 : 0 ;
+	    if (file_exists(BASE . $file->directory . $file->filename)) {
+			$file->copyToDirectory(BASE . $this->cacheDir);
 			assign_to_template(array(
                 'image'=>$file,
                 'update'=>$this->params['update'],
                 'saveog'=>$canSaveOg
             ));
 	    } else {
-		    flash('error',gt('The file').' "'.BASE.$file->directory.$file->filename.'" '.gt('does not exist on the server.'));
-		    redirect_to(array("controller"=>'file',"action"=>'picker',"ajax_action"=>1,"update"=>$this->params['update'],"filter"=>$this->params['filter']));
+		    flash('error', gt('The file') . ' "' . BASE . $file->directory . $file->filename . '" ' . gt('does not exist on the server.'));
+		    redirect_to(array("controller"=>'file', "action"=>'picker', "ajax_action"=>1, "update"=>$this->params['update'], "filter"=>$this->params['filter']));
 	    }
     }
-    
+
     public function exitEditor() {
         // clean up parameters
         $this->params['fid'] = intval($this->params['fid']);
@@ -65,17 +64,17 @@ class pixidouController extends expController {
         }
         switch ($this->params['exitType']) {
             case 'saveAsCopy':
-                $oldimage = new expFile($this->params['fid']);                
-                $copyname = expFile::resolveDuplicateFilename($oldimage->path); 
-                copy(BASE.$this->cacheDir."/".$this->params['cpi'],$oldimage->directory.$copyname); //copy the edited file over to the files dir
+                $oldimage = new expFile($this->params['fid']);
+                $copyname = expFile::resolveDuplicateFilename($oldimage->path);
+                copy(BASE . $this->cacheDir . "/" . $this->params['cpi'], $oldimage->directory . $copyname); //copy the edited file over to the files dir
                 $newFile = new expFile(array("filename"=>$copyname)); //construct a new expFile
                 $newFile->directory = $oldimage->directory;
                 $newFile->title = $oldimage->title;
                 $newFile->shared = $oldimage->shared;
                 $newFile->mimetype = $oldimage->mimetype;
                 $newFile->posted = time();
-                $newFile->filesize = filesize(BASE.$this->cacheDir."/".$this->params['cpi']);
-                $resized = getimagesize(BASE.$this->cacheDir."/".$this->params['cpi']);
+                $newFile->filesize = filesize(BASE . $this->cacheDir . "/" . $this->params['cpi']);
+                $resized = getimagesize(BASE . $this->cacheDir . "/" . $this->params['cpi']);
                 $newFile->image_width = $resized[0];
                 $newFile->image_height = $resized[1];
                 $newFile->alt = $oldimage->alt;
@@ -86,36 +85,36 @@ class pixidouController extends expController {
             case 'saveAsIs':
                 //eDebug($this->params,true);
                 $oldimage = new expFile($this->params['fid']);
-                $resized = getimagesize(BASE.$this->cacheDir."/".$this->params['cpi']);
+                $resized = getimagesize(BASE . $this->cacheDir . "/" . $this->params['cpi']);
                 $oldimage->image_width = $resized[0];
                 $oldimage->image_height = $resized[1];
                 $oldimage->save();
-                copy(BASE.$this->cacheDir."/".$this->params['cpi'],$oldimage->directory.$oldimage->filename); //copy the edited file over to the files dir
+                copy(BASE . $this->cacheDir . "/" . $this->params['cpi'], $oldimage->directory . $oldimage->filename); //copy the edited file over to the files dir
                 break;
-            
+
             default:
                 # code...
                 break;
         }
         // proper file types to look for
-        $types = array(".jpg",".gif",".png");
-        
+        $types = array(".jpg", ".gif", ".png");
+
         //Pixidou images directory, the editor's cache
-        $cachedir = BASE.$this->cacheDir;
-        
+        $cachedir = BASE . $this->cacheDir;
+
         if (is_dir($cachedir) && is_readable($cachedir) ) {
             $dh = opendir($cachedir);
             while (($tmpfile = readdir($dh)) !== false) {
-                if (in_array(substr($tmpfile,-4,4),$types)) {
-                    $filename = $cachedir.$tmpfile;
+                if (in_array(substr($tmpfile, -4, 4), $types)) {
+                    $filename = $cachedir . $tmpfile;
                     unlink($filename);
                 }
             }
         }
-        
-        redirect_to(array("controller"=>'file',"action"=>'picker',"ajax_action"=>1,"update"=>$this->params['update'],"filter"=>$this->params['filter']));
+
+        redirect_to(array("controller"=>'file', "action"=>'picker', "ajax_action"=>1, "update"=>$this->params['update'], "filter"=>$this->params['filter']));
     }
-    
+
 }
 
-?>
\ No newline at end of file
+?>

programming_language: PHP
filename: portfolioController.php
change_type: ModificationType.MODIFY
diff: @@ -27,6 +27,10 @@ class portfolioController extends expController {
         'tags'=>"Tags",
         'slideshow'=>"Slideshow"
     );
+    protected $manage_permissions = array(
+        'import'=>'Import Portfolio Items',
+        'export'=>'Export Portfolio Items'
+    );
     public $remove_configs = array(
         'comments',
         'ealerts',
@@ -34,10 +38,6 @@ class portfolioController extends expController {
         'rss',
         'twitter',
     );  // all options: ('aggregation','categories','comments','ealerts','facebook','files','pagination','rss','tags','twitter',)
-    protected $add_permissions = array(
-        'import'=>'Import Portfolio Items',
-        'export'=>'Export Portfolio Items'
-    );
 
     static function displayname() { return gt("Portfolio"); }
     static function description() { return gt("Display a portfolio or listing."); }

programming_language: PHP
filename: recyclebinController.php
change_type: ModificationType.MODIFY
diff: @@ -22,7 +22,7 @@
  */
 class recyclebinController extends expController
 {
-    protected $add_permissions = array(
+    protected $manage_permissions = array(
         'showall' => 'View Recycle Bin',
         'show' => 'View Recycle Bin',
         'remove' => 'Remove Recycle Bin Item'
@@ -97,6 +97,8 @@ class recyclebinController extends expController
     {
         global $db;
 
+        $this->params['mod'] = expString::escape($this->params['mod']);
+        $this->params['src'] = expString::escape($this->params['src']);
         $mod = expModules::getController($this->params['mod'], $this->params['src']);
         if ($mod != null) {
             $mod->delete_instance();  // delete all assoc items

programming_language: PHP
filename: reportController.php
change_type: ModificationType.MODIFY
diff: @@ -22,18 +22,23 @@
  */
 
 class reportController extends expController {
-    protected $add_permissions = array(
-        'build_report' => 'Manage',
+    protected $manage_permissions = array(
+        'abandoned_carts' => 'Abandoned Carts Report',
+        'batch_export' => 'Export Products',
         'cart_summary' => 'View Cart Summary Report',
+        'current_carts' => 'Current Carts Report',
         'dashboard' => 'View the e-Commerce Dashboard',
-        'order_report' => 'Generate Order Report',
-        'product_report' => 'Generate Product Report',
+        'download' => 'Download Report',
         'generateOrderReport' => 'View Order Report',
         'generateProductReport' => 'View Product Report',
+        'order_report' => 'Generate Order Report',
+        'payment_report' => 'Generate Payment Report',
         'print_orders' => 'Print Orders',
-        'batch_export' => 'Export Products',
+        'product_report' => 'Generate Product Report',
+        'purge_abandoned_carts' => 'Purge Abandoned Carts',
         'show_payment_summary' => 'Show Payment Summary',
-        'export_order_items' => 'Export Order Items File');
+        'status_export' => 'Export Status',
+    );
 
     static function displayname() {
         return gt("Ecom Report Builder");
@@ -339,13 +344,13 @@ class reportController extends expController {
         //echo $sql . $sqlwhere . "<br>";
         /*
         Need: order, orderitems, order status, ordertype, billingmethods, geo region, shipping methods, products
-            [date-startdate] => 
-            [time-h-startdate] => 
-            [time-m-startdate] => 
+            [date-startdate] =>
+            [time-h-startdate] =>
+            [time-m-startdate] =>
             [ampm-startdate] => am
-            [date-enddate] => 
-            [time-h-enddate] =>     
-            [time-m-enddate] => 
+            [date-enddate] =>
+            [time-h-enddate] =>
+            [time-m-enddate] =>
             [ampm-enddate] => am
             [order_status] => Array
                 (
@@ -361,20 +366,20 @@ class reportController extends expController {
                 )
 
             [order-range-op] => e
-            [order-range-num] => 
+            [order-range-num] =>
             [order-price-op] => l
-            [order-price-num] => 
-            [pnam] => 
-            [sku] => 
+            [order-price-num] =>
+            [pnam] =>
+            [sku] =>
             [discounts] => Array
                 (
                     [0] => -1
                 )
 
-            [blshpname] => 
-            [email] => 
+            [blshpname] =>
+            [email] =>
             [bl-sp-zip] => s
-            [zip] => 
+            [zip] =>
             [bl-sp-state] => s
             [state] => Array
                 (
@@ -393,8 +398,8 @@ class reportController extends expController {
         //$order = 'id';
         //$prod = new product();
         // $order = new order();
-        //$items = $prod->find('all', 1, 'id DESC',25);  
-        //$items = $order->find('all', 1, 'id DESC',25);  
+        //$items = $prod->find('all', 1, 'id DESC',25);
+        //$items = $order->find('all', 1, 'id DESC',25);
         //$res = $mod->find('all',$sql,'id',25);
 
         //eDebug($items);
@@ -458,7 +463,7 @@ class reportController extends expController {
         }
 
         /*$geo = new geoRegion();
-        $geos = $geo->find('all');        
+        $geos = $geo->find('all');
         $states = array();
         $states[-1] = gt('--Any--');
         foreach ($geos as $skey=>$state)
@@ -473,7 +478,7 @@ class reportController extends expController {
 
         //eDebug(mktime(0,0,0,(strftime("%m")-1),1,strftime("%Y")));
 //        $prev_month = strftime("%A, %d %B %Y", mktime(0,0,0,(strftime("%m")-1),1,strftime("%Y")));
-        //eDebug(strftime("%A, %d %B %Y", mktime(0,0,0,(strftime("%m")-1),1,strftime("%Y"))));  
+        //eDebug(strftime("%A, %d %B %Y", mktime(0,0,0,(strftime("%m")-1),1,strftime("%Y"))));
 //        $now_date = strftime("%A, %d %B %Y");
         $prev_month = strftime(DISPLAY_DATE_FORMAT, mktime(0, 0, 0, (strftime("%m") - 1), 1, strftime("%Y")));
         $now_date = strftime(DISPLAY_DATE_FORMAT);
@@ -501,7 +506,7 @@ class reportController extends expController {
         $p = $this->params;
 
         //eDebug();
-        //build 
+        //build
         $start_sql = "SELECT DISTINCT(o.id), ";
         $count_sql = "SELECT COUNT(DISTINCT(o.id)) as c, ";
         $sql = "o.invoice_id, FROM_UNIXTIME(o.purchased,'%c/%e/%y %h:%i:%s %p') as purchased_date, b.firstname as bfirst, b.lastname as blast, concat('".expCore::getCurrencySymbol()."',format(o.grand_total,2)) as grand_total, os.title as status_title, ot.title as order_type";
@@ -685,7 +690,7 @@ class reportController extends expController {
         if (isset($p['payment_method'])) {
             $inc = 0;
             $sqltmp = '';
-            //get each calculator's id  
+            //get each calculator's id
 
             foreach ($p['payment_method'] as $s) {
                 if ($s == -1) continue;
@@ -710,13 +715,13 @@ class reportController extends expController {
         //echo $sql . $sqlwhere . "<br>";
         /*
         Need: order, orderitems, order status, ordertype, billingmethods, geo region, shipping methods, products
-            [date-startdate] => 
-            [time-h-startdate] => 
-            [time-m-startdate] => 
+            [date-startdate] =>
+            [time-h-startdate] =>
+            [time-m-startdate] =>
             [ampm-startdate] => am
-            [date-enddate] => 
-            [time-h-enddate] =>     
-            [time-m-enddate] => 
+            [date-enddate] =>
+            [time-h-enddate] =>
+            [time-m-enddate] =>
             [ampm-enddate] => am
             [order_status] => Array
                 (
@@ -732,20 +737,20 @@ class reportController extends expController {
                 )
 
             [order-range-op] => e
-            [order-range-num] => 
+            [order-range-num] =>
             [order-price-op] => l
-            [order-price-num] => 
-            [pnam] => 
-            [sku] => 
+            [order-price-num] =>
+            [pnam] =>
+            [sku] =>
             [discounts] => Array
                 (
                     [0] => -1
                 )
 
-            [blshpname] => 
-            [email] => 
+            [blshpname] =>
+            [email] =>
             [bl-sp-zip] => s
-            [zip] => 
+            [zip] =>
             [bl-sp-state] => s
             [state] => Array
                 (
@@ -772,11 +777,11 @@ class reportController extends expController {
         //$order = 'id';
         //$prod = new product();
         // $order = new order();
-        //$items = $prod->find('all', 1, 'id DESC',25);  
-        //$items = $order->find('all', 1, 'id DESC',25);  
+        //$items = $prod->find('all', 1, 'id DESC',25);
+        //$items = $order->find('all', 1, 'id DESC',25);
         //$res = $mod->find('all',$sql,'id',25);
         //eDebug($items);
-        //eDebug($sql . $sqlwhere); 
+        //eDebug($sql . $sqlwhere);
 
         $page = new expPaginator(array(
             //'model'=>'order',
@@ -803,7 +808,7 @@ class reportController extends expController {
             ),
         ));
 
-        //strftime("%a %d-%m-%Y", get_first_day(3, 1, 2007)); Thursday, 1 April 2010  
+        //strftime("%a %d-%m-%Y", get_first_day(3, 1, 2007)); Thursday, 1 April 2010
         //$d_month_previous = date('n', mktime(0,0,0,(strftime("%m")-1),1,strftime("%Y")));
 
         $action_items = array(
@@ -944,7 +949,7 @@ class reportController extends expController {
         unset($item);
         foreach ($items as $item) {
             $line = '';
-            //$line = expString::outputField("SMC Inventory - Laurie");         
+            //$line = expString::outputField("SMC Inventory - Laurie");
             $line .= expString::outputField($item['model']);
             //$line.= expString::outputField($item['name']);
             $line .= expString::outputField($item['qty']);
@@ -1160,9 +1165,9 @@ class reportController extends expController {
         //expSession::set('product_export_query', "SELECT  DISTINCT(p.id) FROM `exponent_product` p WHERE (title like '%Velcro%' OR feed_title like '%Velcro%' OR title like '%Multicam%' OR feed_title like '%Multicam%') AND parent_id = 0");
 
         $product = new product();
-        //$items = $product->find('all', '', 'id', 25);     
-        //$page = new expPaginator();   
-        //eDebug($page,true);   
+        //$items = $product->find('all', '', 'id', 25);
+        //$page = new expPaginator();
+        //eDebug($page,true);
         $page = new expPaginator(array(
 //            'model'      => 'product',
             //'records'=>$items,
@@ -1197,7 +1202,7 @@ class reportController extends expController {
             'page'=>(isset($this->params['page']) ? $this->params['page'] : 1),
             'columns'=>array(
                 'Customer'=>'lastname',
-                'Invoice #'=>'invoice_id', 
+                'Invoice #'=>'invoice_id',
                 'Total'=>'total',
                 'Date Purchased'=>'purchased',
                 'Status'=>'order_status_id',
@@ -1211,16 +1216,16 @@ class reportController extends expController {
             'page'         => $page,
             'action_items' => $action_items
         ));
-        // 
-        //     
-        // assign_to_template(array('page'=>$page)); 
+        //
+        //
+        // assign_to_template(array('page'=>$page));
     }
 
     /**
      * @deprecated 2.3.3 moved to expString
      */
     public static function parseAndTrimExport($str, $isHTML = false) { //�Death from above�? �
-        //echo "1<br>"; eDebug($str); 
+        //echo "1<br>"; eDebug($str);
 
         $str = str_replace("�", "&rsquo;", $str);
         $str = str_replace("�", "&lsquo;", $str);
@@ -1268,7 +1273,7 @@ class reportController extends expController {
         $str = str_replace("\,", ",", $str);
         $str = str_replace('""', '"', $str); //do this no matter what...in case someone added a quote in a non HTML field
         if (!$isHTML) {
-            //if HTML, then leave the single quotes alone, otheriwse replace w/ special Char            
+            //if HTML, then leave the single quotes alone, otheriwse replace w/ special Char
             $str = str_replace('"', "&quot;", $str);
         }
         $str = str_replace("�", "&#188;", $str);
@@ -1303,7 +1308,7 @@ class reportController extends expController {
         $str = str_replace("�", "&rdquo;", $str);
         $str = str_replace("�", "&ldquo;", $str);
         $str = str_replace("\r\n", " ", $str);
-        //$str = str_replace(",","\,",$str); 
+        //$str = str_replace(",","\,",$str);
 
         $str = str_replace('\"', "&quot;", $str);
         $str = str_replace('"', "&quot;", $str);
@@ -1539,14 +1544,14 @@ class reportController extends expController {
         //check query password to avoid DDOS
         /*
             * condition  = new
-            * description      
-            * id - SKU      
-            * link      
-            * price      
-            * title      
-            * brand - manufacturer      
-            * image link - fullsized image, up to 10, comma seperated          
-            * product type - category - "Electronics > Audio > Audio Accessories MP3 Player Accessories","Health & Beauty > Healthcare > Biometric Monitors > Pedometers"      
+            * description
+            * id - SKU
+            * link
+            * price
+            * title
+            * brand - manufacturer
+            * image link - fullsized image, up to 10, comma seperated
+            * product type - category - "Electronics > Audio > Audio Accessories MP3 Player Accessories","Health & Beauty > Healthcare > Biometric Monitors > Pedometers"
          */
         $out = '"id","condition","description","like","price","title","brand","image link","product type"' . chr(13) . chr(10);
 
@@ -1730,45 +1735,45 @@ class reportController extends expController {
         eDebug(date('Y-m-d'), true);
         // eDebug($this->tend);
         eDebug(date('Y-m-d, g:i:s A', $this->tend));
-        $allOrderCount = $this->o->find('count','created_at >= ' . $this->tstart . ' AND created_at <= ' . $this->tend,null,null,null,true,false,$except,true);            
+        $allOrderCount = $this->o->find('count','created_at >= ' . $this->tstart . ' AND created_at <= ' . $this->tend,null,null,null,true,false,$except,true);
         $sql = "SELECT COUNT(DISTINCT(`orders_id`)) as c FROM " . $db->prefix . "orderitems oi ";
         $sql .= "JOIN " . $db->prefix . "orders o ON  oi.orders_id = o.id ";
         $sql .= "WHERE o.created_at >= " . $this->tstart . " AND o.created_at <= " . $this->tend;
         //$sql .= " AND o.user_id != 0 AND o.order_type_id = 1";
-        
+
         eDebug($sql);
         $allCartsWithItems = $db->countObjectsBySql($sql);
-        
+
         $sql = "SELECT COUNT(DISTINCT(`orders_id`)) as c FROM " . $db->prefix . "orderitems oi ";
         $sql .= "JOIN " . $db->prefix . "orders o ON  oi.orders_id = o.id ";
         $sql .= "WHERE o.created_at >= " . $this->tstart . " AND o.created_at <= " . $this->tend;
         eDebug($sql);
         $realUserCartsWithItems = $db->countObjectsBySql($sql);
-                
-        $ordersInCheckout = $this->o->find('count','created_at >= ' . $this->tstart . ' AND created_at <= ' . $this->tend . " AND user_id != 0",null,null,null,true,false,$except,true);            
-        
-        //$ordersPurchased = $this->o->find('count','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend . " AND user_id != 0 AND order_type_id = 1",null,null,null,true,false,$except,true);     
-        //$ordersPurchased = $this->o->find('count','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend . " AND user_id != 0",null,null,null,true,false,$except,true);     
-        $ordersPurchased = $this->o->find('count','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend,null,null,null,true,false,$except,true);     
-        $orders = $this->o->find('all','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend,null,null,null,true,false,$except,true);     
-               
-        eDebug("All:" . $allOrderCount);    
-        eDebug("Carts w/ Items:" . $allCartsWithItems);           
-        eDebug("Carts w/ Items in Checkout:" . $ordersInCheckout);           
-        eDebug("Purchased:" . $ordersPurchased);  
-        
+
+        $ordersInCheckout = $this->o->find('count','created_at >= ' . $this->tstart . ' AND created_at <= ' . $this->tend . " AND user_id != 0",null,null,null,true,false,$except,true);
+
+        //$ordersPurchased = $this->o->find('count','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend . " AND user_id != 0 AND order_type_id = 1",null,null,null,true,false,$except,true);
+        //$ordersPurchased = $this->o->find('count','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend . " AND user_id != 0",null,null,null,true,false,$except,true);
+        $ordersPurchased = $this->o->find('count','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend,null,null,null,true,false,$except,true);
+        $orders = $this->o->find('all','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend,null,null,null,true,false,$except,true);
+
+        eDebug("All:" . $allOrderCount);
+        eDebug("Carts w/ Items:" . $allCartsWithItems);
+        eDebug("Carts w/ Items in Checkout:" . $ordersInCheckout);
+        eDebug("Purchased:" . $ordersPurchased);
+
         $totalAbandoned = ($allCartsWithItems - $ordersPurchased) / $allCartsWithItems;
         $checkoutAbandoned = ($ordersInCheckout - $ordersPurchased) / $ordersInCheckout;
         eDebug("Total Abandoned: " . $totalAbandoned);
         eDebug("Checkout Abandoned: " . $checkoutAbandoned);
-        
-        
-  
-        
+
+
+
+
         $quickrange = array(0=>'Last 24 Hours',1=>'Last 7 Days',2=>'Last 30 Days');
         $quickrange_default = isset($this->params['quickrange']) ? $this->params['quickrange'] : 0;
         assign_to_template(array('orders'=>$oar,'quickrange'=>$quickrange,'quickrange_default'=>$quickrange_default));
-        assign_to_template(array('prev_month'=>$this->prev_month, 'now_date'=>$this->now_date, 'now_hour'=>$this->now_hour, 'now_min'=>$this->now_min, 'now_ampm'=>$this->now_ampm, 'prev_hour'=>$this->prev_hour, 'prev_min'=>$this->prev_min, 'prev_ampm'=>$this->prev_ampm)); 
+        assign_to_template(array('prev_month'=>$this->prev_month, 'now_date'=>$this->now_date, 'now_hour'=>$this->now_hour, 'now_min'=>$this->now_min, 'now_ampm'=>$this->now_ampm, 'prev_hour'=>$this->prev_hour, 'prev_min'=>$this->prev_min, 'prev_ampm'=>$this->prev_ampm));
         */
     }
 
@@ -1885,7 +1890,7 @@ class reportController extends expController {
         /*eDebug(BASE . "tmp/export.csv");
         $db->sql($sql);
         eDebug($db->error());*/
-        /*OPTIONALLY ENCLOSED BY '" . '"' . 
+        /*OPTIONALLY ENCLOSED BY '" . '"' .
         "' ESCAPED BY '\\'
         LINES TERMINATED BY '" . '\\n' .
         "' */
@@ -2016,7 +2021,7 @@ class reportController extends expController {
         /*eDebug(BASE . "tmp/export.csv");
         $db->sql($sql);
         eDebug($db->error());*/
-        /*OPTIONALLY ENCLOSED BY '" . '"' . 
+        /*OPTIONALLY ENCLOSED BY '" . '"' .
         "' ESCAPED BY '\\'
         LINES TERMINATED BY '" . '\\n' .
         "' */

programming_language: PHP
filename: searchController.php
change_type: ModificationType.MODIFY
diff: @@ -26,10 +26,11 @@ class searchController extends expController {
         'show'=>'Show Search Form',
         'cloud'=>'Show Tag Cloud'
     );
-    protected $add_permissions = array(
-        'spider'=>'Spider Site'
+    protected $manage_permissions = array(
+        'spider'=>'Spider Site',
+        'searchQueryReport'=>'Search Query Report',
+        'topSearchReport'=>'Top Search Report',
     );
-
     public $remove_configs = array(
         'aggregation',
         'categories',
@@ -109,7 +110,7 @@ class searchController extends expController {
             'params'=>$this->params,
         ));
     }
-    
+
     public static function spider() {
         global $db;
 
@@ -136,18 +137,18 @@ class searchController extends expController {
                 $mods[$controller->searchName()] = $controller->addContentToSearch();
 		    }
 	    }
-	
+
 	    uksort($mods,'strnatcasecmp');
 	    assign_to_template(array(
             'mods'=>$mods
         ));
     }
-        
+
     public function show() {
         //no need to do anything..we're just showing the form... so far! MUAHAHAHAHAHAAA!   what?
 //        redirect_to(array("controller"=>'search',"action"=>'showall'));
     }
-    
+
     public function showall() {
 //        redirect_to(array("controller"=>'search',"action"=>'show'));
 //        $this->show();
@@ -220,26 +221,26 @@ class searchController extends expController {
         }*/
         //    $sql .= ' AND parent_id=0';
         //eDebug($sql);
-        
+
         //$res = $mod->find('all',$sql,'id',25);
         $sql = "select DISTINCT(p.id), p.title, model, sef_url, f.id as fileid from ".$db->prefix."product as p INNER JOIN ".$db->prefix."content_expfiles as cef ON p.id=cef.content_id INNER JOIN ".$db->prefix."expfiles as f ON cef.expfiles_id = f.id where match (p.title,p.model,p.body) against ('" . $this->params['query'] . "') AND p.parent_id=0 order by match (p.title,p.model,p.body) against ('" . $this->params['query'] . "') desc LIMIT 25";
         //$res = $db->selectObjectsBySql($sql);
         //$res = $db->selectObjectBySql('SELECT * FROM `exponent_product`');
-        
+
         $ar = new expAjaxReply(200, gt('Here\'s the items you wanted'), $res);
         $ar->send();
     }
-	
+
 	public function searchQueryReport() {
 		global $db;
-		
+
 		//Instantiate the search model
 		$search = new search();
-		
+
 		//Store the keywords that returns nothing
         $badSearch = array();
 		$badSearchArr =  array();
-		
+
 		//User Records Initialization
 		$all_user  = -1;
 		$anonymous = -2;
@@ -247,33 +248,33 @@ class searchController extends expController {
 
 		$user_default = '';
 		$where = '';
-		
+
 		if(isset($this->params['user_id']) && $this->params['user_id'] != -1) {
 			$user_default = $this->params['user_id'];
 		}
-		
+
 		expHistory::set('manageable', $this->params);
 
 		$ctr  = 2;
 		$ctr2 = 0;
-		
+
 		//Getting the search users
 		$records = $db->selectObjects('search_queries');
-		
-		
+
+
 		foreach($records as $item) {
 			$u = user::getUserById($item->user_id);
 
 			if($item->user_id == 0) {
 				$item->user_id = $anonymous;
 			}
-			
+
 			if(!in_array($item->user_id, $uname['id'])) {
 				$uname['name'][$ctr] = $u->firstname . ' ' . $u->lastname;
 				$uname['id'][$ctr] = $item->user_id;
 				$ctr++;
 			}
-			
+
 			$result  = $search->getSearchResults($item->query, false, true);
 			if(empty($result) && !in_array($item->query, $badSearchArr)) {
 				$badSearchArr[] = $item->query;
@@ -281,9 +282,9 @@ class searchController extends expController {
 				$badSearch[$ctr2]['count'] = $db->countObjects("search_queries", "query='{$item->query}'");
 				$ctr2++;
 			}
-			
+
 		}
-	
+
 		//Check if the user choose from the dropdown
 		if(!empty($user_default)) {
 			if($user_default == $anonymous) {
@@ -293,7 +294,7 @@ class searchController extends expController {
 			}
 			$where .= "user_id = {$u_id}";
 		}
-	
+
 		//Get all the search query records
 		$records = $db->selectObjects('search_queries', $where);
         for ($i = 0, $iMax = count($records); $i < $iMax; $i++) {
@@ -302,7 +303,7 @@ class searchController extends expController {
 				$records[$i]->user = $u->firstname . ' ' . $u->lastname;
 			}
 		}
-		
+
         $page = new expPaginator(array(
             'records' => $records,
             'where'=>1,
@@ -328,19 +329,19 @@ class searchController extends expController {
             'user_default' => $user_default,
             'badSearch' => $badSearch
         ));
-		
+
 	}
-	
+
 	public function topSearchReport() {
 		global $db;
 		$limit = intval(TOP_SEARCH);
-		
+
 		if(empty($limit)) {
 			$limit = 10;
 		}
 
 		$count   = $db->countObjects('search_queries');
-	
+
 		$records = $db->selectObjectsBySql("SELECT COUNT(query) cnt, query FROM " .$db->prefix . "search_queries GROUP BY query ORDER BY cnt DESC LIMIT 0, {$limit}");
 
         $records_key_arr = array();
@@ -351,7 +352,7 @@ class searchController extends expController {
 		}
 		$records_key   = implode(",", $records_key_arr);
 		$records_values = implode(",", $records_values_arr);
-		
+
 		assign_to_template(array(
             'records'=>$records,
             'total'=>$count,

programming_language: PHP
filename: simplePollController.php
change_type: ModificationType.MODIFY
diff: @@ -143,7 +143,7 @@ class simplePollController extends expController {
         global $user;
 
         if (isset($this->params['choice'])) {
-            $answer = new simplepoll_answer($this->params['choice']);
+            $answer = new simplepoll_answer(intval($this->params['choice']));
             if (empty($this->config)) {
                 $this->config['anonymous_timeout'] = 5*3600;
                 $this->config['thank_you_message'] = 'Thank you for voting.';

programming_language: PHP
filename: loginController.php
change_type: ModificationType.MODIFY
diff: @@ -125,7 +125,7 @@ class loginController extends expController {
 	 * main login method
 	 */
 	public static function login() {
-		user::login(expString::sanitize($_POST['username']),expString::sanitize($_POST['password']));
+		user::login(expString::escape(expString::sanitize($_POST['username'])),expString::escape(expString::sanitize($_POST['password'])));
 		if (!isset($_SESSION[SYS_SESSION_KEY]['user'])) {  // didn't successfully log in
 			flash('error', gt('Invalid Username / Password'));
 			if (expSession::is_set('redirecturl_error')) {

programming_language: PHP
filename: usersController.php
change_type: ModificationType.MODIFY
diff: @@ -24,7 +24,11 @@
 
 class usersController extends expController {
     public $basemodel_name = 'user';
-    protected $add_permissions = array(
+//    protected $remove_permissions = array(
+//        'create',
+//        'edit'
+//    );
+    protected $manage_permissions = array(
         'toggle_extension' => 'Activate Extensions',
         'kill_session'     => 'End Sessions',
         'boot_user'        => 'Boot Users',
@@ -32,10 +36,7 @@ class usersController extends expController {
         'groupperms'       => 'Group Permissions',
         'import'           => 'Import Users',
         'export'           => 'Export Users',
-    );
-    protected $remove_permissions = array(
-        'create',
-        'edit'
+        'update'           => 'Update Users',
     );
 
     static function displayname() {
@@ -171,7 +172,7 @@ class usersController extends expController {
             expHistory::back();
         }
 
-        // if this is a new user account we need to check the password.  
+        // if this is a new user account we need to check the password.
         // the password fields wont come thru on an edit. Otherwise we will
         // just update the existing account.
         if (!empty($id)) {
@@ -233,7 +234,7 @@ class usersController extends expController {
             if ($u->id == $user->id) expSession::triggerRefresh();
         }
 
-        // if this is a new account then we will check to see if we need to send 
+        // if this is a new account then we will check to see if we need to send
         // a welcome message or admin notification of new accounts.
         if (empty($id)) {
             // Calculate Group Memberships for newly created users.  Any groups that
@@ -491,6 +492,7 @@ class usersController extends expController {
         global $db;
 
         // find the user
+        $this->params['username'] = expString::escape($this->params['username']);
         $u = user::getUserByName($this->params['username']);
         if (empty($u)) {
             $u = user::getUserByEmail($this->params['username']);
@@ -539,7 +541,7 @@ class usersController extends expController {
         global $db;
 
         $db->delete('passreset_token', 'expires < ' . time());
-        $tok = $db->selectObject('passreset_token', 'uid=' . $this->params['uid'] . " AND token='" . preg_replace('/[^A-Za-z0-9]/', '', $this->params['token']) . "'");
+        $tok = $db->selectObject('passreset_token', 'uid=' . intval($this->params['uid']) . " AND token='" . preg_replace('/[^A-Za-z0-9]/', '', expString::escape($this->params['token'])) . "'");
         if ($tok == null) {
             flash('error', gt('Your password reset request has expired.  Please try again.'));
             expHistory::back();
@@ -617,7 +619,7 @@ class usersController extends expController {
             expHistory::returnTo('editable');
         }
         //eDebug($user);
-        $u = new user($this->params['uid']);
+        $u = new user(intval($this->params['uid']));
 
         $ret = $u->setPassword($this->params['new_password1'], $this->params['new_password2']);
         //eDebug($u, true);
@@ -654,6 +656,13 @@ class usersController extends expController {
     }
 
     public function update_userpassword() {
+        global $user;
+
+        if (!$user->isAdmin() && $this->params['id'] != $user->id) {
+            flash('error', gt('You do not have permissions to change this users password.'));
+            expHistory::back();
+        }
+
         if (empty($this->params['id'])) {
             expValidator::failAndReturnToForm(gt('You must specify the user whose password you want to change'), $this->params);
         }
@@ -1497,6 +1506,10 @@ class usersController extends expController {
     }
 
     public function import_users_add() {
+        if (!empty($this->params['filename']) && (strpos($this->params['filename'], 'tmp/') === false || strpos($this->params['folder'], '..') !== false)) {
+            header('Location: ' . URL_FULL);
+            exit();  // attempt to hack the site
+        }
         $line_end = ini_get('auto_detect_line_endings');
         ini_set('auto_detect_line_endings',TRUE);
         $file = fopen(BASE . $this->params["filename"], "r");

programming_language: PHP