CVE-2016-8900 (published 2019-05-24T17:29Z)

Exponent CMS version 2.3.9 suffers from a Object Injection vulnerability in framework/modules/core/controllers/expTagController.php related to change_tags.

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-74
cwe_name: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
description: The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component.
extended_description: Software or other automated logic has certain assumptions about what constitutes data and control respectively. It is the lack of verification of these assumptions for user-controlled input that leads to injection problems. Injection problems encompass a wide variety of issues -- all mitigated in very different ways and usually attempted in order to alter the control flow of the process. For this reason, the most effective way to discuss these weaknesses is to note the distinct features that classify them as injection weaknesses. The most important issue to note is that all injection problems share one thing in common -- i.e., they allow for the injection of control plane data into the user-controlled data plane. This means that the execution of the process may be altered by sending code in through legitimate data channels, using no other mechanism. While buffer overflows, and many other flaws, involve the use of some further issue to gain execution, injection problems need only for the data to be parsed.
         

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