CVE-2016-8897: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') (CWE-89)
value: Exponent CMS version 2.3.9 suffers from a sql injection vulnerability in framework/modules/help/controllers/helpController.php.
CWE description: The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
CVSS v3 base score: 9.8
Published: 2019-05-23T19:29Z
Repository: https://github.com/exponentcms/exponent-cms
Language: PHP
Files changed: framework/core/controllers/expController.php, framework/core/expFramework.php, framework/core/models/expRecord.php, framework/core/subsystems/database/mysqli.php, framework/core/subsystems/expDatabase.php, framework/core/subsystems/expPaginator.php, framework/core/subsystems/expSettings.php, framework/core/subsystems/expString.php, framework/core/subsystems/expTheme.php, framework/modules/addressbook/controllers/addressController.php, framework/modules/administration/controllers/administrationController.php, framework/modules/banners/controllers/bannerController.php, framework/modules/blog/controllers/blogController.php, framework/modules/core/controllers/expCatController.php, framework/modules/core/controllers/expCommentController.php, framework/modules/core/controllers/expDefinableFieldController.php, framework/modules/core/controllers/expHTMLEditorController.php, framework/modules/core/controllers/expSimpleNoteController.php, framework/modules/core/controllers/expTagController.php, framework/modules/eaas/controllers/eaasController.php, framework/modules/ealerts/controllers/ealertController.php, framework/modules/ecommerce/controllers/billingController.php, framework/modules/ecommerce/controllers/ecomconfigController.php, framework/modules/ecommerce/controllers/eventregistrationController.php, framework/modules/ecommerce/controllers/orderController.php, framework/modules/ecommerce/controllers/order_statusController.php, framework/modules/ecommerce/controllers/purchaseOrderController.php, framework/modules/ecommerce/controllers/shippingController.php, framework/modules/ecommerce/controllers/storeCategoryController.php, framework/modules/ecommerce/controllers/storeController.php, framework/modules/ecommerce/controllers/taxController.php, framework/modules/ecommerce/products/models/donation.php, framework/modules/events/controllers/eventController.php, framework/modules/events/models/event.php, framework/modules/file/controllers/fileController.php, framework/modules/file/models/expFile.php, framework/modules/filedownloads/controllers/filedownloadController.php, framework/modules/forms/controllers/formsController.php, framework/modules/help/controllers/helpController.php, framework/modules/help/models/help_version.php, framework/modules/importexport/controllers/importexportController.php, framework/modules/migration/controllers/migrationController.php, framework/modules/navigation/controllers/navigationController.php, framework/modules/news/controllers/newsController.php, framework/modules/photoalbum/controllers/photosController.php, framework/modules/pixidou/controllers/pixidouController.php, framework/modules/portfolio/controllers/portfolioController.php, framework/modules/recyclebin/controllers/recyclebinController.php, framework/modules/report/controllers/reportController.php, framework/modules/search/controllers/searchController.php, framework/modules/simplepoll/controllers/simplePollController.php, framework/modules/users/controllers/loginController.php, framework/modules/users/controllers/usersController.php
Commit date: 2016-09-28 15:21:21 -0400
Commit message: iniitial effort to greatly enhance system security (xss, sql inject, file exploit, rce, etc...)

Diff: diff --git a/framework/core/controllers/expController.php b/framework/core/controllers/expController.php
index 9f7d259dba..c90afd5c38 100755
--- a/framework/core/controllers/expController.php
+++ b/framework/core/controllers/expController.php
@@ -39,15 +39,23 @@ abstract class expController {
         'manage'    => 'Manage',
         'configure' => 'Configure',
         '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
     public $relative_viewpath = ''; // relative location of controller's views
     public $asset_path = ''; // location of this controller's assets; defaults to controller file location
@@ -129,10 +137,12 @@ abstract class expController {
         // get this controllers config data if there is any
         $config = new expConfig($this->loc);
         $this->config = $config->config;
 
         $this->params = $params;
+        if (ENABLE_WORKFLOW)
+            $this->permissions = array_merge($this->permissions, array('approve'=>'Approval'));
     }
 
     /**
      * name of module for backwards compat with old modules
      *
@@ -292,11 +302,11 @@ abstract class expController {
          // set history
         expHistory::set('viewable', $this->params);
         $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());
 
         // find all the items that this tag is attached to
@@ -326,11 +336,11 @@ abstract class expController {
         $page->records = expSorter::sort(array('array' => $page->records, 'sortby' => 'created_at', 'order' => 'DESC', 'ignore_case' => true));
 
         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
         ));
     }
 
     /**
@@ -452,11 +462,11 @@ abstract class expController {
         // 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 $modelname($id);
         if (empty($record->id))
             redirect_to(array('controller'=>'notfound','action'=>'page_not_found','title'=>$this->params['title']));
@@ -483,10 +493,11 @@ abstract class expController {
     public function showByTitle() {
         expHistory::set('viewable', $this->params);
         $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'] . "'");
         }
         $this->loc = unserialize($record->location_data);
@@ -1010,11 +1021,11 @@ abstract class expController {
      * method to display an rss feed from this module
      */
     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']);
         }
         $site_rss = new expRss($id);
@@ -1141,11 +1152,11 @@ 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
      */
     public function permissions() {
         //set the permissions array
@@ -1155,10 +1166,25 @@ abstract class expController {
         }
         $perms = array_merge($perms, $this->add_permissions);
         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;
     }
 
diff --git a/framework/core/expFramework.php b/framework/core/expFramework.php
index 3943d34fe5..913905fd74 100755
--- a/framework/core/expFramework.php
+++ b/framework/core/expFramework.php
@@ -283,17 +283,17 @@ function renderAction(array $parms=array()) {
         expQueue::flashAndFlow('error', gt('The requested action could not be performed: Action not found'));
     }
 
     // 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
         // flag for needing approval check
         if ($controller->$model->supports_revisions && ENABLE_WORKFLOW) {
@@ -322,32 +322,34 @@ function renderAction(array $parms=array()) {
         $title->int = '';
         $template->assign('moduletitle', $db->selectValue('container', 'title', "internal='".serialize($title)."'"));
     }
 
     // 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'];
     }
 
     // Here is where we check for ownership of an item and 'create' perm
     if (($parms['action'] == 'edit' || $parms['action'] == 'update' || $parms['action'] == 'delete' ||
@@ -422,28 +424,28 @@ 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();
         }
     } 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);
 
     // lastly, run the action which can also override the above assignments
     $controller->$action();
@@ -484,11 +486,11 @@ function redirect_to($params=array(), $secure=false) {
 
     $secure = empty($secure) ? false : true;
     $link = (!is_array($params)) ? $params : $router->makeLink($params, false, $secure);
     header("Location: " . $link);
     exit();
-}   
+}
 
 function flash($name, $msg) {
     expQueue::flash($name, $msg);
 }
 
@@ -512,11 +514,11 @@ function show_msg_queue($name=null) {
  * @param array $vars
  * @return bool
  */
 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);
     }
 }
@@ -538,11 +540,11 @@ function get_common_template($view, $loc, $controllername='') {
     return expTemplate::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';
 
     if (bs(true)) {
@@ -579,23 +581,23 @@ function get_common_template($view, $loc, $controllername='') {
  */
 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']);
     }
     $moduleconfig = array();
@@ -606,11 +608,11 @@ function get_config_templates($controller, $loc) {
     $module_views = expTemplate::find_config_views($modpaths);
     foreach ($module_views as $key=>$value) {
         $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'])) {
 //        $viewname = $controller->params['hcview'];
 //    } else {
@@ -623,11 +625,11 @@ function get_config_templates($controller, $loc) {
 //            if ($fileparts[0]=='show'||$fileparts[0]=='showall') array_shift($fileparts);
 //            $module_views[$viewname]['name'] = ucwords(implode(' ', $fileparts)).' '.gt('View Configuration');
 //            $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
     // when we're finished to get them back in the right order
     krsort($common_views);
@@ -669,11 +671,11 @@ function find_config_views($paths=array(), $excludes=array()) {
                     }
                 }
             }
         }
     }
-    
+
     return $views;
 }
 
 /**
  * @deprecated 2.3.3 moved to expTemplate subsystem
@@ -757,16 +759,16 @@ function get_action_views($ctl, $action, $human_readable) {
     // setup the controller
 //    $controllerName = expModules::getControllerClassName($ctl);
 //    $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)) {
             $dh = opendir($path);
             while (($file = readdir($dh)) !== false) {
@@ -802,11 +804,11 @@ function get_filedisplay_views() {
 
     $paths = array(
         BASE.'framework/modules/common/views/file/',
         BASE.'themes/'.DISPLAY_THEME.'modules/common/views/file/',
     );
-    
+
     $views = array();
     foreach ($paths as $path) {
         if (is_readable($path)) {
             $dh = opendir($path);
             while (($file = readdir($dh)) !== false) {
@@ -815,11 +817,11 @@ function get_filedisplay_views() {
                     $views[$filename] = gt($filename);
                 }
             }
         }
     }
-    
+
     return $views;
 }
 
 function object2Array($object=null) {
     $ret_array = array();
diff --git a/framework/core/models/expRecord.php b/framework/core/models/expRecord.php
index 0ffbfe7a77..b49d05a6fd 100644
--- a/framework/core/models/expRecord.php
+++ b/framework/core/models/expRecord.php
@@ -102,11 +102,11 @@ class expRecord {
 
         $supports_revisions = $this->supports_revisions && ENABLE_WORKFLOW;
         $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)) {
             $where = '';
             if (is_numeric($params)) {
@@ -120,11 +120,11 @@ class expRecord {
                 if (empty($values)) $values = $db->selectArray($this->tablename, "title='" . expString::sanitize($params) . "'", null, $supports_revisions, $needs_approval);
                 $this->build($values);
                 $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);
         }
 
         // establish a pseudo publish date
         if (!empty($this->publish)) {
@@ -133,11 +133,11 @@ class expRecord {
             $this->publish_date = $this->edited_at;
         } elseif (!empty($this->created_at)) {
             $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();
             $params['cascade_except'] = isset($params['cascade_except']) ? $params['cascade_except'] : false;
 
@@ -178,10 +178,15 @@ class expRecord {
 
         $sql = empty($where) ? 1 : $where;
         //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;
         } else {
             $needs_approval = false;
@@ -359,14 +364,14 @@ class expRecord {
 
         // Build Class properties based off table fields
         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) {
                     $this->$col = preg_replace("/[^0-9-]/", "", $value);
                 } elseif ($colDef[0] == DB_DEF_DECIMAL) {
@@ -462,11 +467,11 @@ class expRecord {
 
         $this->beforeSave();
 
         // 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();
         $table   = $db->getDataDefinition($this->tablename);
         foreach ($table as $col=> $colDef) {
@@ -532,11 +537,11 @@ class expRecord {
             if (!isset($this->validates['is_valid_sef_name']['sef_url'])) $this->validates['is_valid_sef_name']['sef_url'] = array();
             if (!isset($this->validates['uniqueness_of']['sef_url'])) $this->validates['uniqueness_of']['sef_url']         = array();
         }
 
         // 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;
         }
 
diff --git a/framework/core/subsystems/database/mysqli.php b/framework/core/subsystems/database/mysqli.php
index 6a323b561e..f1b4328127 100644
--- a/framework/core/subsystems/database/mysqli.php
+++ b/framework/core/subsystems/database/mysqli.php
@@ -349,11 +349,11 @@ class mysqli_database extends database {
 	 * @param  $col
 	 * @param $val
 	 * @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();
         $objects = array();
         for ($i = 0; $i < mysqli_num_rows($res); $i++)
@@ -482,12 +482,12 @@ class mysqli_database extends database {
 	 * @return null|void
 	 */
     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;
         return mysqli_fetch_object($res);
     }
@@ -738,25 +738,25 @@ class mysqli_database extends database {
 	 * @param string $lockType
 	 * @return mixed
 	 */
 	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;
     }
 
 	/**
 	 * @return mixed
 	 */
 	function unlockTables() {
         $sql = "UNLOCK TABLES";
-        
+
         $res = mysqli_query($this->connection, $sql);
         return $res;
     }
-    
+
 	/**
      * Insert an Object into some table in the Database
      *
      * This method will return the ID assigned to the new record by MySQL.  Note that
      * object attributes starting with an underscore ('_') will be ignored and NOT inserted
@@ -766,11 +766,11 @@ class mysqli_database extends database {
      * @param string $table The logical table name to insert into.  This does not include the table prefix, which
      *    is automagically prepended for you.
      * @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) {
             //We do not want to save any fields that start with an '_'
             if ($var{0} != '_') {
@@ -826,21 +826,21 @@ class mysqli_database extends database {
 
         if ($is_revisioned) {
             $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;
         }
         $sql = "UPDATE " . $this->prefix . "$table SET ";
         foreach (get_object_vars($object) as $var => $val) {
             //We do not want to save any fields that start with an '_'
             //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) . "',";
                 }
             }
@@ -848,11 +848,11 @@ class mysqli_database extends database {
         $sql = substr($sql, 0, -1) . " WHERE ";
         if ($where != null)
             $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;
     }
 
 	/**
@@ -1107,11 +1107,11 @@ class mysqli_database extends database {
     function inError() {
         return ($this->connection != null && mysqli_errno($this->connection) != 0);
     }
 
 	/**
-	 * Unescape a string based on the database connection
+	 * Escape a string based on the database connection
 	 * @param $string
 	 * @return string
 	 */
 	function escapeString($string) {
 	    return (mysqli_real_escape_string($this->connection, $string));
@@ -1160,11 +1160,11 @@ class mysqli_database extends database {
      * array of arrays, in any random order.
      *
      * @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();
         $arrays = array();
         for ($i = 0, $iMax = mysqli_num_rows($res); $i < $iMax; $i++)
@@ -1292,11 +1292,11 @@ class mysqli_database extends database {
             return array();
 		$records = array();
 		while($row = mysqli_fetch_object($res)) {
 			$records[] = $row->Field;
 		}
-		
+
 		return $records;
 	}
 
 }
 
diff --git a/framework/core/subsystems/expDatabase.php b/framework/core/subsystems/expDatabase.php
index 50630c366f..7c0fca37ae 100644
--- a/framework/core/subsystems/expDatabase.php
+++ b/framework/core/subsystems/expDatabase.php
@@ -1097,18 +1097,18 @@ abstract class database {
 	* @return bool
 	*/
 	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
    	 */
    	function injectProof($string) {
    	    $quotes = substr_count("'", $string);
diff --git a/framework/core/subsystems/expPaginator.php b/framework/core/subsystems/expPaginator.php
index 46ea29d0b1..318c5c1eea 100755
--- a/framework/core/subsystems/expPaginator.php
+++ b/framework/core/subsystems/expPaginator.php
@@ -21,26 +21,26 @@
  *
  * The expPaginator class is used to retrieve objects from the database
  * 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,
  *      'action'=>$this->params['action'],
  *      'columns'=>array('In FAQ'=>'include_in_faq', 'Submitted'=>'created_at', 'Submitted By'=>'submitter_name'),
  *  ));
  * </code>
- * 
+ *
  * @package Subsystems
  * @subpackage Subsystems
  */
 
 class expPaginator {
@@ -50,11 +50,11 @@ class expPaginator {
      */
 	public $model = null;
     public $search_string = '';
 	public $sql = '';
     public $count_sql = '';
-	public $where = '';	
+	public $where = '';
 	public $controller = '';
 	public $action = '';
 	public $order = '';
 	public $order_direction = '';
 	public $firstpage = '';
@@ -89,11 +89,11 @@ class expPaginator {
 //    public $version = 0;
 //    public $content_id = 0;
 	/**#@+
      * @access public
      * @var array
-     */	
+     */
 	public $pages = array();
 	public $records = array();
     public $cats = array();
     public $sort_dropdown = array();
 
@@ -104,25 +104,25 @@ class expPaginator {
 	 *
 	 * @param array $params Use this to set any of the class variables. Ones not passed will be set to a default.
 	 * @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();
         $this->grouplimit = !empty($params['grouplimit']) ? $params['grouplimit'] : null;
         $this->dontsortwithincat = !empty($params['dontsortwithincat']) ? $params['dontsortwithincat'] : null;
@@ -135,19 +135,19 @@ class expPaginator {
         // setup the model if one was passed.
         if (isset($params['model'])) {
             $this->model = $params['model'];
             $class = new $this->model(null, false, false);
         }
-	
+
 	    // auto-include the CSS for pagination links
 	    expCSS::pushToHead(array(
 //		    "unique"=>"pagination",
 //		    "link"=>PATH_RELATIVE."framework/core/assets/css/pagination.css",
             'corecss'=>'pagination'
 		    )
 		);
-		
+
 		if ($this->limit)
             $this->start = (($this->page * $this->limit) - $this->limit);
         if ($this->start < 0)
             $this->start = 0;
 
@@ -165,23 +165,27 @@ class expPaginator {
 		                $this->linkables[$key][$prm[0]] = $prm[1];
 		            }
 		        }
 		    }
 		}
-		
+
 		//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," ")) {
             $orderby = explode(" ",$this->order);
             $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
             $sort = $this->order.' '.$this->order_direction;
 
@@ -207,17 +211,17 @@ class expPaginator {
 			//$records = $db->selectObjectsBySql($this->sql);
 			//$this->total_records = count($records);
             //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) {
                     $type = $params['model_field'];
 			        $classname = isset($params['model_field']) ? $record->$type : $this->model;
@@ -225,11 +229,11 @@ class expPaginator {
 					$this->records[] = new $classname($record->id, false, true); //From Merge //added false, true, as we shouldn't need associated items here, but do need attached. FJD.
 			    }
 			} 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))
             expCatController::addCats($this->records,$sort,$this->uncat,$this->groups,$this->dontsortwithincat);
 
@@ -312,11 +316,11 @@ class expPaginator {
                 $this->lastrecord = $this->total_records;
 		} else {
 			$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);
         foreach (array("__utma", "__utmz", "route_sanitized") as $key) {
             if (isset($page_params[$key]))
@@ -341,26 +345,30 @@ class expPaginator {
     //			}
                 $mod = !empty($router->params['controller']) ? $router->params['controller'] : $router->params['module'];
                 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)) {
                     $mod = $params->controller;
                 } else {
                     $mod = '';
                 }
             }
             $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']);
 
 		//build a 'more' link we can use in the headlines views.
 		$this->morelink = $router->makeLink($page_params, false, false, true);
@@ -368,14 +376,14 @@ class expPaginator {
 		if (!empty($this->view))
             $page_params['view'] = $this->view;
 
 		//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
 		if ($this->page > $this->total_pages) {
 			$this->page = $this->total_pages;
@@ -405,11 +413,11 @@ class expPaginator {
 		if ($this->total_pages > $this->pages_to_show) {
 			$this->first_pagelink = max(1, floor(($this->page) - ($this->pages_to_show) / 2));
 		    $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;
 			$this->last_pagelink = $this->total_pages;
 		}
@@ -431,102 +439,102 @@ class expPaginator {
 			$page_params['page'] = $this->total_pages;
 			$this->lastpage = $router->makeLink($page_params, false, false, true);
         }
 
 		// 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'];
         else
             unset($sortparams['page']);
         //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'];
                 unset($params['order']);
             } 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
 
                 if (empty($col)) {
                     $this->header_columns .= '<span>'.$colname.'</span>';
                     $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){
 //                            if (e.target.test('.select-all')) {
 //                                if (!e.target.get('checked')) {
@@ -563,16 +571,16 @@ class expPaginator {
                         $this->header_columns .= $colname;
                     } else {
                         $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) {
             if (isset($record->ref_type)) {
                 $refType = $record->ref_type;
@@ -583,13 +591,13 @@ class expPaginator {
                         $item = new $type($record->original_id);
                         $item->paginationCallback($record);
                     }
                 }
             }
-        }    
+        }
     }
-    
+
 	public function makeSortDropdown($params) {
 		global $router;
 
 		if (!empty($this->columns) && is_array($this->columns)) {
 			$this->sort_dropdown = array();
@@ -598,63 +606,63 @@ class expPaginator {
 			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'];
 				unset($params['order']);
 			} 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'];
             $defaultParams['action'] = $params['action'];
             if (isset($params['title']))
                 $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;
 					if (isset($params['dir'])) {
 						$params['dir'] = $params['dir'] == 'ASC' ? 'DESC' : 'ASC';
 					} 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
      */
     public function asc($a,$b) {
diff --git a/framework/core/subsystems/expSettings.php b/framework/core/subsystems/expSettings.php
index 104e5d650d..2abcbe5e45 100644
--- a/framework/core/subsystems/expSettings.php
+++ b/framework/core/subsystems/expSettings.php
@@ -189,17 +189,17 @@ class expSettings
 //              $value = str_replace(array("\r\n","\r","\n"),"<br />",$value);
                 $value = str_replace(array("\r\n", "\r", "\n"), "", $value);
 //                $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";
         }
 
@@ -582,10 +582,14 @@ class expSettings
      *
      * @node Subsystems:Config
      */
     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"
             )
         ) {
             //FIXME do we need to delete current config first??
@@ -633,6 +637,6 @@ class expSettings
 
 }
 
 expSettings::initialize();  // auto-initialize when loaded
 
-?>
\ No newline at end of file
+?>
diff --git a/framework/core/subsystems/expString.php b/framework/core/subsystems/expString.php
index 2639cf57d1..677884fded 100644
--- a/framework/core/subsystems/expString.php
+++ b/framework/core/subsystems/expString.php
@@ -32,11 +32,11 @@ class expString {
      * @param string $string
      * @return string
      */
 	static function convertUTF($string) {
 		return $string = str_replace('?', '', htmlspecialchars($string, ENT_IGNORE, 'UTF-8'));
-	} 
+	}
 
     /**
      * Routine to check if string is valid UTF string
      *
      * @static
@@ -44,11 +44,11 @@ class expString {
      * @return bool
      */
 	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;
 	}
 
     /**
      * Routine to strip unreadable characters from string - ascii 32 to 126
@@ -103,13 +103,13 @@ class expString {
         $str = str_replace("¼","&#188;",$str);
         $str = str_replace("½","&#189;",$str);
         $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);
         }
 
         return $str;
@@ -128,31 +128,31 @@ class expString {
         $str = str_replace("<br/>","",$str);
         $str = str_replace("<br />","",$str);
         $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);
         $str = str_replace("&#189;"," 1/2",$str);
         $str = str_replace("�"," 3/4",$str);
         $str = str_replace("&#190;"," 3/4",$str);
         $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);
 	}
 
     /**
      * Routine to convert any smart quotes into normal quotes
@@ -447,11 +447,11 @@ class expString {
         return $str;
     }
 
     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);
         $str = str_replace("�", "&#174;", $str);
         $str = str_replace("�", "-", $str);
@@ -469,17 +469,17 @@ class expString {
         $str = str_replace("�", "&#189;", $str);
         $str = str_replace("�", "&#190;", $str);
         //$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;
     }
 
     public static function outputField($val, $eof = ',', $isHTML = false) {
diff --git a/framework/core/subsystems/expTheme.php b/framework/core/subsystems/expTheme.php
index 617d7be1fa..a87d4017f5 100755
--- a/framework/core/subsystems/expTheme.php
+++ b/framework/core/subsystems/expTheme.php
@@ -239,17 +239,23 @@ class expTheme
         }
         if (!isset($config['meta']['ie_compat'])) {
             $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(
                     true
                 ) . self::getThemeDetails() . '" ' . XHTML_CLOSING . '>' . "\n";
@@ -359,13 +365,10 @@ class expTheme
 //            $str .= "\t" . '<!--[if lt IE 9]><script src="' . PATH_RELATIVE . 'external/excanvas.js"></script><![endif]-->' . "\n";
 
             //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;
     }
 
@@ -1968,6 +1971,6 @@ class expTheme
         }
     }
 
 }
 
-?>
\ No newline at end of file
+?>
diff --git a/framework/modules/addressbook/controllers/addressController.php b/framework/modules/addressbook/controllers/addressController.php
index 269b2d63e1..0f800575bd 100755
--- a/framework/modules/addressbook/controllers/addressController.php
+++ b/framework/modules/addressbook/controllers/addressController.php
@@ -20,21 +20,21 @@
  * @package Modules
  * @subpackage Controllers
  */
 
 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',
         'categories',
         'comments',
@@ -57,11 +57,11 @@ class addressController extends expController {
 
     function showall() {
 //        redirect_to(array("controller"=>'address',"action"=>'myaddressbook'));
         $this->myaddressbook();
 	}
-    
+
     public function edit()
     {
         if((isset($this->params['id']))) $record = new address(intval($this->params['id']));
         else $record = null;
         $config = ecomconfig::getConfig('address_allow_admins_all');
@@ -73,11 +73,11 @@ class addressController extends expController {
             assign_to_template(array(
                 'checkout'=>true
             ));
         }
     }
-    
+
 	public function myaddressbook() {
 		global $user;
 
 		// check if the user is logged in.
 		expQueue::flashIfNotLoggedIn('message',gt('You must be logged in to manage your address book.'));
@@ -85,11 +85,11 @@ class addressController extends expController {
 		$userid = (empty($this->params['user_id'])) ? $user->id : $this->params['user_id'];
 		assign_to_template(array(
             'addresses'=>$this->address->find('all', 'user_id='.$userid)
         ));
 	}
-	
+
 	function show() {
 	    expHistory::set('viewable', $this->params);
 		assign_to_template(array(
             'address'=>new address($this->params['id'])
         ));
@@ -109,11 +109,11 @@ class addressController extends expController {
         }
 		if ($user->isLoggedIn()) {
 			// 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;
                 $this->params['is_shipping'] = 1;
             }
@@ -121,35 +121,35 @@ class addressController extends expController {
 			$this->params['user_id'] = $user->id;
 			// save the object
 			$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)
                 {
                     $billAddress = $this->address->find('first', 'user_id=' . $user->id . " AND id != " . $address->id);
                     $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;
                     $shipAddress->save();
                 }
@@ -160,66 +160,66 @@ class addressController extends expController {
         {
             flash("error", gt("You must have at least one address."));
         }
 	    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;
 
         //eDebug($this->params,true);
         //countries
         $db->columnUpdate('geo_country','active',0,'active=1');
         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');
         foreach($this->params['region'] as $region_id=>$is_active)
         {
             $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'));
 //        $this->manage();
     }
diff --git a/framework/modules/administration/controllers/administrationController.php b/framework/modules/administration/controllers/administrationController.php
index 80e5a2c8a6..2e35d5cbb3 100644
--- a/framework/modules/administration/controllers/administrationController.php
+++ b/framework/modules/administration/controllers/administrationController.php
@@ -22,21 +22,21 @@
  */
 /** @define "BASE" "../../../.." */
 
 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"); }
     static function description() { return gt("This is the Administration Module"); }
 
@@ -60,11 +60,11 @@ class administrationController extends expController {
         ));
    	}
 
     public function manage_unused_tables() {
         global $db;
-        
+
         expHistory::set('manageable', $this->params);
         $unused_tables = array();
         $used_tables = array();
         $tables = $db->getTables();
         //eDebug($tables);
@@ -112,25 +112,25 @@ class administrationController extends expController {
                 $unused_tables[$basename] = new stdClass();
                 $unused_tables[$basename]->name = $table;
                 $unused_tables[$basename]->rows = $db->countObjects($basename);
             }
         }
-        
+
         assign_to_template(array(
             'unused_tables'=>$unused_tables
         ));
     }
-    
+
     public function delete_unused_tables() {
         global $db;
 
         $count = 0;
         foreach($this->params['tables'] as $del=>$table) {
             $basename = str_replace($db->prefix, '', $table);
             $count += $db->dropTable($basename);
         }
-        
+
         flash('message', gt('Deleted').' '.$count.' '.gt('unused tables').'.');
         expHistory::back();
     }
 
 	public function fix_optimize_database() {
@@ -145,18 +145,18 @@ class administrationController extends expController {
             'before'=>$before,
             'after'=>$after
         ));
 	}
 
-	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;
 
 	// upgrade sectionref's that have lost their originals
@@ -216,11 +216,10 @@ class administrationController extends expController {
                     $newSecRef->source   = $iloc->src;
                     $newSecRef->internal = '';
                     $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;
 						$db->insertObject($newSecRef,"sectionref");
 						$missing_sectionrefs[] = gt("Missing sectionref for container replaced").": ".$iloc->mod." - ".$iloc->src." - PageID #".$section->id;
@@ -284,32 +283,32 @@ 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();
     }
 
@@ -383,11 +382,11 @@ class administrationController extends expController {
             );
             flash('message', $message);
         }
     	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.'));
         } else {
             $newvalue = (DEVELOPMENT == 1) ? 0 : 1;
@@ -1045,11 +1044,11 @@ class administrationController extends expController {
 
         assign_to_template(array(
             '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.'));
         }
     	expSettings::change('DISPLAY_THEME_REAL', $this->params['theme']);
@@ -1072,12 +1071,12 @@ class administrationController extends expController {
 //        expSession::un_set('framework');
         expSession::set('force_less_compile', 1);
 //        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']:'';
 		if (strtolower($sv)=='default') {
 		   $sv = '';
@@ -1177,17 +1176,17 @@ class administrationController extends expController {
         // TYPES OF ANTISPAM CONTROLS... CURRENTLY ONLY ReCAPTCHA
         $as_types = array(
             '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')) {
         	$theme_dh = opendir(BASE.'themes');
         	while (($theme_file = readdir($theme_dh)) !== false) {
@@ -1241,28 +1240,28 @@ class administrationController extends expController {
 //            'username'=>'jdoe'
 //        );
         $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();
         $start_of_week = $daysofweek['long'];
 
         // File Permissions
         $file_permisions = glist(expSettings::dropdownData('file_permissions'));
-        
+
         // File Permissions
         $dir_permissions = glist(expSettings::dropdownData('dir_permissions'));
 
         // Homepage Dropdown
         $section_dropdown = section::levelDropdownControlArray(0, 0, array(), false, 'view', true);
diff --git a/framework/modules/banners/controllers/bannerController.php b/framework/modules/banners/controllers/bannerController.php
index 5a5496a246..6fcabb2da4 100755
--- a/framework/modules/banners/controllers/bannerController.php
+++ b/framework/modules/banners/controllers/bannerController.php
@@ -20,10 +20,16 @@
  * @subpackage Controllers
  * @package Modules
  */
 
 class bannerController extends expController {
+    public $useractions = array(
+        'showall'=>'Display Banner(s)'
+    );
+    protected $manage_permissions = array(
+        'reset' => 'Reset Stats'
+    );
     public $remove_configs = array(
         'aggregation',
         'categories',
         'comments',
         'ealerts',
@@ -32,47 +38,44 @@ class bannerController extends expController {
         'module_title',
         'rss',
         '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.
 //        $count = $db->countObjects('companies');
         $comp = new company();
@@ -83,19 +86,19 @@ class bannerController extends expController {
 //            $this->edit();
         } else {
             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,
 			'order'=>'title',
             'page'=>(isset($this->params['page']) ? $this->params['page'] : 1),
@@ -112,45 +115,45 @@ class bannerController extends expController {
 
 		assign_to_template(array(
             '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(
             'banners'=>$banners,
             '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');
         $out = '"Banner ID","Banner Title","Banner URL","Company Name","Impression Limit","Click Limit","Impressions","Clicks"' . "\n";
         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
         expFile::download($export);
     }
@@ -161,12 +164,12 @@ class bannerController extends expController {
         // reset the counters
 //        $db->sql ('UPDATE '.$db->prefix.'banner SET impressions=0 WHERE 1');
         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();
     }
 
 }
diff --git a/framework/modules/blog/controllers/blogController.php b/framework/modules/blog/controllers/blogController.php
index e077420ecd..d2c6fa183e 100755
--- a/framework/modules/blog/controllers/blogController.php
+++ b/framework/modules/blog/controllers/blogController.php
@@ -27,19 +27,17 @@ class blogController extends expController {
         'authors'=>"Show Post Authors",
         'categories'=>"Show Post Categories",
         '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."); }
     static function author() { return "Phillip Ball - OIC Group, Inc"; }
     static function hasSources() { return false; }  // must be explicitly added by config['add_source'] or config['aggregate']
@@ -166,10 +164,11 @@ 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,
             'where'=>($this->aggregateWhereClause()?$this->aggregateWhereClause()." AND ":"")."poster=".$user->id,
             'limit'=>isset($this->config['limit']) ? $this->config['limit'] : 10,
@@ -192,11 +191,11 @@ class blogController extends expController {
 	public function show() {
         expHistory::set('viewable', $this->params);
 	    $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
 	    // populate the location data in the template now.
         $config = expConfig::getConfig($record->location_data);
@@ -229,11 +228,11 @@ class blogController extends expController {
         // set the history point for this action
         expHistory::set('viewable', $this->params);
 
         // 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
         $sql  = 'SELECT DISTINCT m.id FROM '.$db->prefix.$model->tablename.' m ';
         $sql .= 'JOIN '.$db->prefix.$tagobj->attachable_table.' ct ';
diff --git a/framework/modules/core/controllers/expCatController.php b/framework/modules/core/controllers/expCatController.php
index 12b88dc52b..8f421c57a0 100644
--- a/framework/modules/core/controllers/expCatController.php
+++ b/framework/modules/core/controllers/expCatController.php
@@ -21,10 +21,13 @@
  * @package Core
  * @subpackage Controllers
  */
 
 class expCatController extends expController {
+    protected $manage_permissions = array(
+        'change' => 'Change Cats'
+    );
 
 	/**
 	 * name of module
 	 * @return string
 	 */
diff --git a/framework/modules/core/controllers/expCommentController.php b/framework/modules/core/controllers/expCommentController.php
index 8f3248ca4d..8173d2be57 100644
--- a/framework/modules/core/controllers/expCommentController.php
+++ b/framework/modules/core/controllers/expCommentController.php
@@ -22,43 +22,44 @@
  * @subpackage Controllers
  */
 
 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
 		assign_to_template(array(
 		    'content_id'=>$this->params['content_id'],
             'content_type'=>$this->params['content_type'],
 		    'comment'=>$comment
 		));
-	}	
-	
+	}
+
 	function manage() {
 	    expHistory::set('manageable', $this->params);
 
         $order = 'approved';
         $dir = 'ASC';
@@ -66,11 +67,11 @@ class expCommentController extends expController {
         //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'];
-	    
+
 	    $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'])) {
             $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".$this->params['content_type']."' ";
             $order = 'created_at';
@@ -78,11 +79,11 @@ class expCommentController extends expController {
         }
         //$sql .= 'AND c.approved=0';
 
         $page = new expPaginator(array(
 //            'model'=>'expComment',
-            'sql'=>$sql, 
+            'sql'=>$sql,
             'limit'=>10,
             'order'=>$order,
             'dir'=>$dir,
             'page'=>(isset($this->params['page']) ? $this->params['page'] : 1),
             'controller'=>$this->baseclassname,
@@ -113,31 +114,31 @@ class expCommentController extends expController {
 	function showComments() {
 		global $user, $db;
 
         /* 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 ';
 //        $sql .= 'JOIN '.$db->prefix.'user_avatar ua ON c.poster=ua.user_id ';
 //        $sql .= 'JOIN '.$db->prefix.'user u ON c.poster=u.id ';
 //        $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".$this->params['content_type']."' ";
 
         $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),
             'controller'=>$this->baseclassname,
             'action'=>$this->params['action'],
@@ -155,31 +156,31 @@ class expCommentController extends expController {
             $comments->records[$key]->avatar = $db->selectObject('user_avatar',"user_id='".$record->poster."'");
         }
 
         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;
 
         assign_to_template(array(
             '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'],
 			'hidecomments'=>$this->params['hidecomments'],
 			'title'=>$this->params['title'],
@@ -322,11 +323,11 @@ class expCommentController extends expController {
         return $comments->records;
     }
 
     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'];
         $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'];
@@ -337,23 +338,23 @@ class expCommentController extends expController {
         }
         // check the anti-spam control
         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'];
 //		$obj->content_id = $this->params['content_id'];
 //		$obj->expcomments_id = $this->expComment->id;
@@ -364,68 +365,68 @@ class expCommentController extends expController {
 		$msg = 'Thank you for posting a comment.';
 		if ($require_approval == 1 && !$user->isAdmin()) {
 		    $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);
 		}
         if ($require_approval==1 && $this->params['approved']==1 && $this->expComment->poster != $user->id) {
 		    $this->sendApprovalNotification($this->expComment,$this->params);
         }
 
 		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'];
 //        $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'];
@@ -477,46 +478,46 @@ class expCommentController extends expController {
         expHistory::returnTo('manageable');
     }
 
 	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));
         $tos = array_filter($tos);
         if (empty($tos)) return false;
@@ -524,11 +525,11 @@ class expCommentController extends expController {
         $model = new $params['content_type']($params['content_id']);
 //	    $loc = expUnserialize($model->location_data);
 
         $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>';
         $body .= '<p>'.$comment->name."</p>";
         $body .= '<h2>'.gt('Poster\'s Email').'</h2>';
@@ -538,33 +539,33 @@ class expCommentController extends expController {
         $body .= '<h3>'.gt('View posting').'</h3>';
         $body .= '<a href="'.$posting.'">'.$posting.'</a>';
         //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));
         $tos[] = $comment->email;
 		$tos = array_filter($tos);
@@ -585,18 +586,18 @@ class expCommentController extends expController {
         $body .= '<p>'.$comment->body."</p>";
         $body .= '<h3>'.gt('View posting').'</h3>';
         $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;
 	}
 
 }
 
diff --git a/framework/modules/core/controllers/expDefinableFieldController.php b/framework/modules/core/controllers/expDefinableFieldController.php
index d48269a639..7ff6e354c8 100644
--- a/framework/modules/core/controllers/expDefinableFieldController.php
+++ b/framework/modules/core/controllers/expDefinableFieldController.php
@@ -45,30 +45,30 @@ 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
     }
 
 	/**
 	 * manage definable field
 	 */
 	function manage() {
         global $db;
-		
+
         expHistory::set('manageable', $this->params);
 		$fields = $db->selectObjects("expDefinableFields",'1','rank');
 		$types = expTemplate::listControlTypes();
         uasort($types, "strnatcmp");
 		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'])) {
 			$control = $db->selectObject("expDefinableFields","id=".$this->params['id']);
 			if ($control) {
@@ -78,25 +78,25 @@ class expDefinableFieldController extends expController {
 				$control_type = get_class($ctl);
 			}
 		}
 		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);
 		}
 		$form->meta("action","save");
 		$form->meta('module',"expDefinableField");
 		$form->meta('control_type',$control_type);
 		$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;
 		if (isset($this->params['id'])) {
 			$control = $db->selectObject('expDefinableFields','id='.$this->params['id']);
@@ -104,34 +104,34 @@ class expDefinableFieldController extends expController {
 				$ctl = unserialize($control->data);
 				$ctl->name = $ctl->identifier;
 			}
 		}
 
-		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'));
 	}
 
 }
 
diff --git a/framework/modules/core/controllers/expHTMLEditorController.php b/framework/modules/core/controllers/expHTMLEditorController.php
index 0433259e82..392e3027c2 100644
--- a/framework/modules/core/controllers/expHTMLEditorController.php
+++ b/framework/modules/core/controllers/expHTMLEditorController.php
@@ -22,10 +22,18 @@
  * @subpackage Controllers
  */
 
 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");
     }
 
@@ -47,15 +55,10 @@ class expHTMLEditorController extends expController
     static function hasContent()
     {
         return false;
     }
 
-    protected $add_permissions = array(
-        'activate' => "Activate",
-        'preview'  => "Preview Editor Toolbars"
-    );
-
     function __construct($src = null, $params = array())
     {
         parent:: __construct($src, $params);
         if (empty($this->params['editor'])) {
             $this->params['editor'] = SITE_WYSIWYG_EDITOR;
diff --git a/framework/modules/core/controllers/expSimpleNoteController.php b/framework/modules/core/controllers/expSimpleNoteController.php
index 2bd630314d..ae04f3dd20 100644
--- a/framework/modules/core/controllers/expSimpleNoteController.php
+++ b/framework/modules/core/controllers/expSimpleNoteController.php
@@ -22,33 +22,33 @@
  * @subpackage Controllers
  */
 
 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',
 //        'create'
 //    );
 
     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']))
             {
                 $formtitle = gt("Add New Note");
             }
@@ -59,11 +59,11 @@ class expSimpleNoteController extends expController {
         }
         else
         {
             $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
 
         assign_to_template(array(
@@ -76,30 +76,30 @@ class expSimpleNoteController extends expController {
             'formtitle'=>$formtitle,
             'content_type'=>$this->params['content_type'],
             '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',
             'page'=>(isset($this->params['page']) ? $this->params['page'] : 1),
             'controller'=>$this->baseclassname,
@@ -108,11 +108,11 @@ class expSimpleNoteController extends expController {
                 gt('Approved')=>'approved',
                 gt('Poster')=>'name',
                 gt('Comment')=>'body'
             ),
         ));
-        
+
         //FIXME here is where we might sanitize the notes before displaying them
 
         assign_to_template(array(
             'page'=>$page,
             'require_login'=>$require_login,
@@ -120,58 +120,58 @@ class expSimpleNoteController extends expController {
             'require_notification'=>$require_notification,
             'notification_email'=>$notification_email,
             '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',
             'page'=>(isset($this->params['page']) ? $this->params['page'] : 1),
             'controller'=>$this->baseclassname,
             'action'=>$this->params['action'],
             'columns'=>array(
                 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'],
             'hidenotes'=>$this->params['hidenotes'],
             'title'=>$this->params['title'],
@@ -184,32 +184,32 @@ 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'];
 //        $obj->content_id = $this->params['content_id'];
 //        $obj->expsimplenote_id = $this->expSimpleNote->id;
@@ -220,168 +220,168 @@ class expSimpleNoteController extends expController {
         $msg = gt('Your note has been added.');
         if ($require_approval == 1 && !$user->isAdmin()) {
             $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']))
         {
             $lastUrl .= "#".$this->params['tab'];
         }
         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,
             'require_login'=>$require_login,
             'require_approval'=>$require_approval,
             'require_notification'=>$require_notification,
             'notification_email'=>$notification_email,
             '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']))
         {
             $lastUrl .= "#".$this->params['tab'];
         }
         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']))
         {
             $lastUrl .= "#".$this->params['tab'];
         }
         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']))
         {
             $lastUrl .= "#".$this->params['tab'];
         }
         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;
     }
 
 }
 
diff --git a/framework/modules/core/controllers/expTagController.php b/framework/modules/core/controllers/expTagController.php
index 0c32d22513..3a623aabfa 100644
--- a/framework/modules/core/controllers/expTagController.php
+++ b/framework/modules/core/controllers/expTagController.php
@@ -21,10 +21,16 @@
  * @package Core
  * @subpackage Controllers
  */
 
 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
 	 */
     static function displayname() { return gt("Tag Manager"); }
@@ -57,11 +63,11 @@ class expTagController extends expController {
         $id = null;
         $tag = '';
         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;
         }
 
         $record = new $modelname($id);
         if (empty($tag) && !empty($record->title)) {
diff --git a/framework/modules/eaas/controllers/eaasController.php b/framework/modules/eaas/controllers/eaasController.php
index 90a7f6f784..6b2453c582 100644
--- a/framework/modules/eaas/controllers/eaasController.php
+++ b/framework/modules/eaas/controllers/eaasController.php
@@ -39,24 +39,19 @@ class eaasController extends expController {
         'pagination',
         'rss',
         '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', 
         'photo'=>'Photos', 
         'media'=>'Media',
         'event'=>'Events',
         'filedownload'=>'File Downloads', 
         'news'=>'News'
     );
-
     protected $data = array();
     
     static function displayname() { return gt("Exponent as a Service"); }
 
     static function description() { return gt("This module allows you make service calls and return JSON for parts of Exponent"); }
diff --git a/framework/modules/ealerts/controllers/ealertController.php b/framework/modules/ealerts/controllers/ealertController.php
index ac3216774b..1ec8e9306a 100755
--- a/framework/modules/ealerts/controllers/ealertController.php
+++ b/framework/modules/ealerts/controllers/ealertController.php
@@ -21,11 +21,13 @@
  * @package Modules
  */
 
 class ealertController extends expController {
     public $basemodel_name = 'expeAlerts';
-
+    protected $manage_permissions = array(
+        'send'=>'Send E-Alert',
+    );
 	public $remove_configs = array(
         'aggregation',
         'categories',
         'comments',
         'ealerts',
@@ -34,14 +36,14 @@ class ealertController extends expController {
         'pagination',
         'rss',
         '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;
     }
 
     public function showall() {
@@ -50,16 +52,16 @@ class ealertController extends expController {
         assign_to_template(array(
             'ealerts'=>$ealerts->find('all'),
             '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']));
         }
 
@@ -67,47 +69,47 @@ class ealertController extends expController {
         $model = $this->params['model'];
         $record = new $model($this->params['id']);
         // 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;
 
         $obj = new stdClass();
         $obj->subject = $this->params['subject'];
         $obj->body = $this->params['body'];
         $link = $router->makelink(array('controller'=>$this->params['model'], 'action'=>'show', 'title'=>$this->params['sef_url']));
         $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
         $model = $this->params['model'];
         $record = new $model($this->params['id']);
@@ -134,40 +136,40 @@ class ealertController extends expController {
         expHistory::back();
     }
 
     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,
 		        'to'=>array(trim($subscriber->email) => trim(user::getUserAttribution($subscriber->id))),
                 '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);
     }
 
     public function subscribe() {
         global $user,$db;
@@ -199,156 +201,160 @@ 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
diff --git a/framework/modules/ecommerce/controllers/billingController.php b/framework/modules/ecommerce/controllers/billingController.php
index 9f71b233d0..9fa9b4fe8d 100755
--- a/framework/modules/ecommerce/controllers/billingController.php
+++ b/framework/modules/ecommerce/controllers/billingController.php
@@ -20,18 +20,19 @@
  * @subpackage Controllers
  * @package Modules
  */
 
 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);
 		$ar = new expAjaxReply(200, 'ok', $billing, array('controller'=>'cart', 'action'=>'checkout'),true);
 		$ar->send();
@@ -43,16 +44,16 @@ class billingController extends expController {
 		$ar = new expAjaxReply(200, 'ok', new address($billing->billingmethod->addresses_id), array('controller'=>'cart', 'action'=>'checkout'),true);
 		$ar->send();
 	}
 
 	function selectBillingOptions() {
-		
+
 	}
-	
+
 	function manage() {
 	    global $db;
-	    
+
 	    expHistory::set('manageable', $this->params);
 //	    $classes = array();
         $dir = BASE."framework/modules/ecommerce/billingcalculators";
         if (is_readable($dir)) {
             $dh = opendir($dir);
@@ -66,28 +67,28 @@ class billingController extends expController {
                         $calcobj = new $classname();
                         if ($calcobj->isSelectable() == true) {
                             $obj = new billingcalculator(array(
                                 'title'=>$calcobj->name(),
 //                                'user_title'=>$calcobj->title,
-                                'body'=>$calcobj->description(), 
+                                'body'=>$calcobj->description(),
                                 'calculator_name'=>$classname,
                                 'enabled'=>false));
                             $obj->save();
                         }
                     }
                 }
             }
         }
-        
+
         $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);
             //FIXME we need to ensure our default calculator is still active
 	        if ($calc->calculator->hasConfig() && empty($calc->config)) {
@@ -119,11 +120,11 @@ class billingController extends expController {
         assign_to_template(array(
             'calculator'=>$calc,
             'title'=>static::displayname()
         ));
     }
-    
+
     public function saveconfig() {
         $calc = new billingcalculator($this->params['id']);
         $conf = serialize($calc->calculator->parseConfig($this->params));
         $calc->update(array('config'=>$conf));
         expHistory::back();
diff --git a/framework/modules/ecommerce/controllers/ecomconfigController.php b/framework/modules/ecommerce/controllers/ecomconfigController.php
index 3a3a330f98..6fd2dff834 100755
--- a/framework/modules/ecommerce/controllers/ecomconfigController.php
+++ b/framework/modules/ecommerce/controllers/ecomconfigController.php
@@ -24,126 +24,129 @@
 
 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; }
 
     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;
 
         $id = empty($this->params['id']) ? null : $this->params['id'];
         $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();
         $optiongroups = $optiongroup->find('all');
         assign_to_template(array(
             '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',
 			'limit'=> 10,
 			'order'=>isset($this->params['order']) ? $this->params['order'] : null,
@@ -156,20 +159,20 @@ class ecomconfigController extends expController {
         assign_to_template(array(
         /*'apply_rules'=>$discountObj->apply_rules, 'discount_types'=>$discountObj->discount_types,*/
             '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'
                 );
         //loop our groups and append them to the array
        // foreach ($group->find() as $g){
@@ -181,21 +184,21 @@ class ecomconfigController extends expController {
            {
                 $groups[$g->id] = $g->name;
            };
        }
        //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();
 //        $shipping = new shipping();
         foreach (shipping::listAvailableCalculators() as $calcid=>$name) {
@@ -203,47 +206,47 @@ class ecomconfigController extends expController {
                 $calc = new $name($calcid);
                 $shipping_services[$calcid] = $calc->title;
                 $shipping_methods[$calcid] = $calc->availableMethods();
             }
         }
-        
+
        assign_to_template(array(
            'discount'=>$discount,
            'groups'=>$groups,
            'selected_groups'=>$selected_groups,
            'shipping_services'=>$shipping_services,
            'shipping_methods'=>$shipping_methods
        ));
     }
-    
+
     public function update_discount() {
         $id = empty($this->params['id']) ? null : $this->params['id'];
         $discount = new discounts($id);
         // find required shipping method if needed
         if ($this->params['required_shipping_calculator_id'] > 0) {
             $this->params['required_shipping_method'] = $this->params['required_shipping_methods'][$this->params['required_shipping_calculator_id']];
         } 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);
             //if ($discount->discountulator->hasConfig() && empty($discount->config)) {
                 //flash('messages', $discount->discountulator->name().' requires configuration. Please do so now.');
                 //redirect_to(array('controller'=>'billing', 'action'=>'configure', 'id'=>$discount->id));
             //}
         }
-        
+
         expHistory::back();
     }
-    
+
     /*****************************************************************/
     /***************  PROMO CODE       *******************************/
     /*****************************************************************/
 	public function manage_promocodes() {
 		expHistory::set('manageable', $this->params);
@@ -262,11 +265,11 @@ class ecomconfigController extends expController {
 	    //$id = empty($this->params['id']) ? null : $this->params['id'];
 	    $code = new promocodes();
 	    $code->update($this->params);
 	    expHistory::back();
 	}
-	
+
     /*****************************************************************/
     /***************  GROUP DISCOUNTS  *******************************/
     /*****************************************************************/
 	public function manage_groupdiscounts() {
 		global $db;
@@ -287,56 +290,56 @@ 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']);
 	        if (!empty($existing_id)) flashAndFlow('error',gt('There is already a discount for that group.'));
 	    }
 
         $gd = new groupdiscounts();
 	    $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,
             'views'=>$views,
             'countries'=>$countries,
             'regions'=>$regions,
             'title'=>static::displayname()
         ));
-    }   
+    }
 
     function saveconfig() {
         $this->params['min_order'] = substr($this->params['min_order'], 1) ;
    		$this->params['minimum_gift_card_purchase'] = substr($this->params['minimum_gift_card_purchase'], 1) ;
    		$this->params['custom_message_product']     = substr($this->params['custom_message_product'], 1) ;
@@ -352,45 +355,45 @@ 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,
             'regions'=>$regions,
             '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) {
 			if(!empty($item)) {
 				$upcharge[$key] = $item;
 			}
 		}
 		$this->config['upcharge'] = $upcharge;
-		
+
         $config->update(array('config'=>$this->config));
         flash('message', gt('Configuration updated'));
         expHistory::back();
     }
-	
+
 }
 
 ?>
\ No newline at end of file
diff --git a/framework/modules/ecommerce/controllers/eventregistrationController.php b/framework/modules/ecommerce/controllers/eventregistrationController.php
index b20e0c1ac0..35ca16b6fd 100755
--- a/framework/modules/ecommerce/controllers/eventregistrationController.php
+++ b/framework/modules/ecommerce/controllers/eventregistrationController.php
@@ -29,18 +29,22 @@ function compare($x, $y) {
         return 1;
 }
 
 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',
         'categories',
         'comments',
@@ -50,15 +54,10 @@ class eventregistrationController extends expController {
         'rss',
         'tags',
         '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");
     }
 
     static function description() {
diff --git a/framework/modules/ecommerce/controllers/orderController.php b/framework/modules/ecommerce/controllers/orderController.php
index 2ddfbdadad..d05c3285de 100755
--- a/framework/modules/ecommerce/controllers/orderController.php
+++ b/framework/modules/ecommerce/controllers/orderController.php
@@ -20,34 +20,36 @@
  * @subpackage Controllers
  * @package    Modules
  */
 
 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() {
         return gt("e-Commerce Order Manager");
     }
@@ -64,25 +66,25 @@ class orderController extends expController {
         // remove abaondoned carts
         /*$count = $db->countObjects('orders', 'purchased=0');
         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
 //        $closed_count = 0;
         if (empty($this->params['showclosed'])) {
@@ -245,11 +247,11 @@ class orderController extends expController {
 //        $storeConfig = new expConfig(expCore::makeLocation("ecomconfig","@globalstoresettings",""));
 
         //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']));
             } else {
                 flashAndFlow('error', gt('You do not have permission to view this order.'));
@@ -413,11 +415,11 @@ class orderController extends expController {
         $invoice .= '</HEAD><BODY>';
         if (is_array($orders)) {
             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'));
                 }
                 $invoice .= '<p style="page-break-before: always;"></p>';
             }
@@ -548,11 +550,11 @@ $pdf->Output('example_001.pdf', 'I');
 exit();
 //============================================================+
 // END OF FILE
 //============================================================+
 
-            
+
             // create new PDF document
             $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
 
             // set document information
             $pdf->SetCreator(PDF_CREATOR);
@@ -876,11 +878,11 @@ exit();
 //            $noteObj->content_id       = $order->id;
 //            $noteObj->content_type     = 'order';
 //            $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();
         }
 
@@ -918,11 +920,11 @@ exit();
     function metainfo() {
         global $router;
 
         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);
         $storename = ecomconfig::getConfig('storename');
         switch ($action) {
@@ -955,11 +957,11 @@ 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();
 
         //eDebug($billing, true);
@@ -1291,11 +1293,11 @@ exit();
     function save_reference_order() {
 //        global $user;
 
         //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'];
         $newOrder->order_type_id   = $this->params['order_type_id'];
         //$newOrder->order_references = $order->id;
@@ -1346,12 +1348,12 @@ exit();
         $newBillingMethod->billing_cost         = 0;
         $newBillingMethod->transaction_state    = 'authorization pending';
         $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
         $newBillingTransaction->billingcalculator_id = billingcalculator::getDefault();
         $newBillingTransaction->billing_cost         = 0;
@@ -1375,11 +1377,11 @@ exit();
             $newOi->quantity                = $this->params['quantity'][$oikey];
             $newOi->orders_id               = $newOrder->id;
             $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();
         }
 
         $newOrder->shippingmethod = $newShippingMethod;
@@ -1404,11 +1406,11 @@ exit();
         customer_type = 2 //existing Internal
         customer_type = 3 //existing external*/
 //        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) {
             //blank order
             $newAddy->save(false);
@@ -1488,12 +1490,12 @@ exit();
         $newBillingMethod->zip                  = $newAddy->zip;
         $newBillingMethod->phone                = $newAddy->phone;
         $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
         $newBillingTransaction->billingcalculator_id = billingcalculator::getDefault();
         $newBillingTransaction->billing_cost         = 0;
@@ -1664,11 +1666,11 @@ exit();
         $params['options'] = $oi->opts;
         $params['user_input_fields'] = $oi->user_input_fields;
         $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?
 //        $oi->selectedOpts = array();
 //        if (!empty($oi->opts)) {
@@ -1774,33 +1776,33 @@ exit();
         $user_input_info = array();
         //check user input fields
         //$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]);
         }
         //eDebug($options);
         //eDebug($user_input_info,true);
 
         $oi->options           = serialize($options);
         $oi->user_input_fields = serialize($user_input_info);
-        //eDebug($oi);        
+        //eDebug($oi);
         $oi->save();
         $oi->refresh();
         //eDebug($oi,true);
 
         $order = new order($oi->orders_id);
@@ -1854,11 +1856,11 @@ exit();
         //eDebug($this->params,true);
         //check for multiple product adding
         $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;
                 }
                 if (isset($child)) $this->params['product_id'] = $child->parent_id;
@@ -2005,18 +2007,18 @@ exit();
 
         //eDebug($this->params);
         /*$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
             {
                 flashAndFlow('message',"Orders containing " . $search . " in the order number not found.");
             }
@@ -2031,20 +2033,20 @@ exit();
         if (is_int($oid) && $oid > 0)
         {
             $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
             {
                 flashAndFlow('message',"Order #" . intval($this->params['ordernum']) . " not found.");
             }
         }
         else
         {
-            flashAndFlow('message','Invalid order number.');        
+            flashAndFlow('message','Invalid order number.');
         }*/
     }
 
     public function verifyReturnShopper() {
 //        global $user, $order;
@@ -2069,11 +2071,11 @@ exit();
 
         $sessAr = expSession::get('verify_shopper');
         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];
 
                 if (($this->params['lastname'] == $shippingMethod->lastname || $this->params['lastname'] == $billingMethod->lastname) &&
                     ($this->params['email'] == $shippingMethod->email || $this->params['email'] == $billingMethod->email) &&
@@ -2123,11 +2125,11 @@ exit();
     public function search() {
 //        global $db, $user;
         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) ";
         $sql .= "order by match (a.firstname,a.lastname,a.email,a.organization)  against ('" . $this->params['query'] . "*' IN BOOLEAN MODE) ASC LIMIT 12";
         $res = $db->selectObjectsBySql($sql);
@@ -2146,11 +2148,11 @@ exit();
     public function search_external() {
 //        global $db, $user;
         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) ";
         $sql .= "order by match (a.firstname,a.lastname,a.email,a.organization)  against ('" . $this->params['query'] . "*' IN BOOLEAN MODE) ASC LIMIT 12";
         $res = $db->selectObjectsBySql($sql);
diff --git a/framework/modules/ecommerce/controllers/order_statusController.php b/framework/modules/ecommerce/controllers/order_statusController.php
index 3e3cf78ac4..f58a2ba7d3 100755
--- a/framework/modules/ecommerce/controllers/order_statusController.php
+++ b/framework/modules/ecommerce/controllers/order_statusController.php
@@ -20,18 +20,21 @@
  * @subpackage Controllers
  * @package Modules
  */
 
 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,
             'limit'=>10,
 			'order'=>'rank',
@@ -43,14 +46,14 @@ class order_statusController extends expController {
 
 		assign_to_template(array(
             'page'=>$page
         ));
     }
-    
+
     public function manage_messages() {
         expHistory::set('manageable', $this->params);
-        
+
         $page = new expPaginator(array(
 			'model'=>'order_status_messages',
 			'where'=>1,
             'limit'=>10,
 			'order'=>'body',
@@ -63,57 +66,57 @@ class order_statusController extends expController {
         //eDebug($page);
 		assign_to_template(array(
             'page'=>$page
         ));
     }
-    
+
     public function edit_message() {
         $id = isset($this->params['id']) ? $this->params['id'] : null;
         $msg = new order_status_messages($id);
         assign_to_template(array(
             'record'=>$msg
         ));
         //$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;
 
         $order_status = new order_status($this->params['id']);
         $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
diff --git a/framework/modules/ecommerce/controllers/purchaseOrderController.php b/framework/modules/ecommerce/controllers/purchaseOrderController.php
index a93ff1373c..e87f1e8ff1 100644
--- a/framework/modules/ecommerce/controllers/purchaseOrderController.php
+++ b/framework/modules/ecommerce/controllers/purchaseOrderController.php
@@ -20,63 +20,56 @@
  * @subpackage Controllers
  * @package Modules
  */
 
 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'])) {
 			$purchase_orders = $this->purchase_order->find('all', 'vendor_id=' . $this->params['vendor']);
 		} 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;
 			$state = new geoRegion($vendor->state);
 			$vendor->state = $state->name;
@@ -86,54 +79,54 @@ class purchaseOrderController extends expController {
                 $vendor->table,
                 $vendor->tablename,
                 $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(
                 'vendor'=>$vendor
             ));
 		}
 	}
-	
+
 	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
diff --git a/framework/modules/ecommerce/controllers/shippingController.php b/framework/modules/ecommerce/controllers/shippingController.php
index f64259c831..baf0cab6f7 100755
--- a/framework/modules/ecommerce/controllers/shippingController.php
+++ b/framework/modules/ecommerce/controllers/shippingController.php
@@ -20,12 +20,15 @@
  * @subpackage Controllers
  * @package Modules
  */
 
 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"); }
     static function description() { return ""; }
 	static function hasSources() { return false; }
@@ -36,20 +39,20 @@ class shippingController extends expController {
      */
 	function selectShippingCalculator() {
 	    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();
 	}
 
     /**
@@ -75,30 +78,30 @@ class shippingController extends expController {
 		$shipping->shippingmethod->setAddress($this->params['shipping_address']);
 		$shipping->refresh();
 		$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
 
 	    $shipping = new shipping();
@@ -117,31 +120,31 @@ class shippingController extends expController {
                 $opt = $shipping->pricelist[0][$shipping->shippingmethod->option];
             } else {
                 $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
      */
 	function listPrices() {
 	    $shipping = new shipping();  //FIXME this model has no listPrices() method???
 	    $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";
         $default = false;
         $on = false;
@@ -149,14 +152,14 @@ class shippingController extends expController {
             $dh = opendir($dir);
             while (($file = readdir($dh)) !== false) {
                 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 {
                         $calcobj = new $classname($id);
                     }
@@ -174,12 +177,12 @@ class shippingController extends expController {
         }
         assign_to_template(array(
             'calculators'=>$calculators
         ));
 	}
-	
-		
+
+
 	public function toggle() {
 	    global $db;
 
 	    if (isset($this->params['id'])) $db->toggle('shippingcalculator', 'enabled', 'id='.$this->params['id']);
         //FIXME we need to ensure our default calculator is still active...not sure this does it
@@ -220,44 +223,44 @@ class shippingController extends expController {
         assign_to_template(array(
             'calculator'=>$calc,
             '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;
 
         if (empty($this->params['id'])) return false;
         $calcname = $db->selectValue('shippingcalculator', 'calculator_name', 'id='.$this->params['id']);
         $calc = new $calcname($this->params['id']);
         assign_to_template(array(
             'calculator'=>$calc
         ));
-		
+
     }
-	
+
 	public function saveEditSpeed() {
 		global $db;
 
         $obj = new stdClass();
 		$obj->speed = $this->params['speed'];
 		$obj->shippingcalculator_id = $this->params['shippingcalculator_id'];
 		$db->insertObject($obj, $this->params['table']);
 		redirect_to(array('controller'=>'shipping', 'action'=>'configure', 'id'=>$this->params['shippingcalculator_id']));
 	}
-	
+
 	public function deleteSpeed() {
 		global $db;
 
         if (empty($this->params['id'])) return false;
 		$db->delete('shippingspeeds',' id =' . $this->params['id']);
diff --git a/framework/modules/ecommerce/controllers/storeCategoryController.php b/framework/modules/ecommerce/controllers/storeCategoryController.php
index af742414fa..ff82021282 100755
--- a/framework/modules/ecommerce/controllers/storeCategoryController.php
+++ b/framework/modules/ecommerce/controllers/storeCategoryController.php
@@ -20,22 +20,15 @@
  * @subpackage Controllers
  * @package    Modules
  */
 
 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',
         'categories',
         'comments',
@@ -47,10 +40,18 @@ class storeCategoryController extends expNestedNodeController {
         'rss',
         'tags',
         '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;
     }
 
     static function canExportData() {
@@ -188,22 +189,22 @@ class storeCategoryController extends expNestedNodeController {
 
     function manage() {
         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() {
         $product_types = ecomconfig::getConfig('product_types');
 
@@ -403,11 +404,11 @@ class storeCategoryController extends expNestedNodeController {
 
         // takes a flat array with propper parent/child relationships in propper order
         // 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;
             $counter=1;
             $prevDepth=0;
@@ -437,14 +438,14 @@ class storeCategoryController extends expNestedNodeController {
                         $categories[$trackParents[$l - 1]]['rgt'] = $counter;
                         array_pop($trackParents);
                         $counter++;
                         $l--;
                     }
-                    
+
                     $categories[$key]['lft'] = $counter;
                     //???$counter++;
-                }        
+                }
                 $prevDepth=$val['depth'];
             }
 
             $categories[$key]['rgt'] = $counter;
             return $categories;
@@ -495,47 +496,47 @@ class storeCategoryController extends expNestedNodeController {
 
         // this will test our data manipulation
         // 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'];
             $cat->rgt = $v['rgt'];
             $cat->save();
             eDebug($cat);
         }
           */
         //-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"])) {
         //         DrawBranch($MyNode["Children"]);
         //     }
         // }
         // 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>");
         //     }
         // }
     }
 
diff --git a/framework/modules/ecommerce/controllers/storeController.php b/framework/modules/ecommerce/controllers/storeController.php
index 07a773ff70..bafe73433c 100755
--- a/framework/modules/ecommerce/controllers/storeController.php
+++ b/framework/modules/ecommerce/controllers/storeController.php
@@ -22,11 +22,10 @@
  */
 /** @define "BASE" "../../../.." */
 
 class storeController extends expController {
     public $basemodel_name = 'product';
-
     public $useractions = array(
         'showall'                         => 'Products - All Products and Categories',
         'showallFeaturedProducts'         => 'Products - Only Featured',
         'showallCategoryFeaturedProducts' => 'Products - Featured Products under current category',
         'showallManufacturers'            => 'Products - By Manufacturer',
@@ -38,11 +37,34 @@ class storeController extends expController {
         'ecomSearch'                      => 'Product Search - Autocomplete',
         'searchByModel'                   => 'Product Search - By Model',
         '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',
         'categories',
 //        'comments',
@@ -52,35 +74,10 @@ class storeController extends expController {
         'rss',
         'tags',
         '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");
     }
 
     static function description() {
@@ -506,26 +503,26 @@ class storeController extends expController {
 
         //eDebug($this->category);
 
         /*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;
                         break;
                     }
                 }
             }
             eDebug($sections);
-            $ancestors = $this->category->pathToNode();       
+            $ancestors = $this->category->pathToNode();
         }*/
 
         $ancestors = $this->category->pathToNode();
         // eDebug($ancestors);
         assign_to_template(array(
@@ -1272,11 +1269,11 @@ class storeController extends expController {
 
                         $editable_options[$group->title]->options[] = $opt;
                     }
                 }
             }
-            //eDebug($editable_options[$group->title]);        
+            //eDebug($editable_options[$group->title]);
         }
         //die();
 
         uasort($editable_options, array("optiongroup", "sortOptiongroups"));
 
@@ -1494,11 +1491,11 @@ class storeController extends expController {
         global $db;
 
         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);
         //}
 
@@ -1633,22 +1630,22 @@ 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();
         }
     }
 
     function searchByModelForm() {
@@ -1820,11 +1817,11 @@ class storeController extends expController {
             $db->prefix . "content_expFiles as cef ON p.id=cef.content_id AND cef.content_type IN ('product','eventregistration','donation','giftcard') AND cef.subtype='mainimage'  INNER JOIN " . $db->prefix .
             "expFiles as f ON cef.expFiles_id = f.id WHERE ";
         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);
         $res = $db->selectObjectsBySql($sql);
         eDebug($res, true);
@@ -1849,45 +1846,45 @@ class storeController extends expController {
         /*
           Testing
         */
         /*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;*/
 
         ###########
 
         global $db;
         $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'])) {
             flash('error', gt('There was an error uploading your file.  Please try again.'));
             redirect_to(array('controller' => 'store', 'action' => 'batch_process'));
@@ -1923,11 +1920,11 @@ class storeController extends expController {
         ini_set('auto_detect_line_endings',TRUE);
         $handle = fopen($file->path, "r");
 
         // read in the header line
         $data = fgetcsv($handle, 10000, ",");
-        //eDebug($data);      
+        //eDebug($data);
 //        $dataset = array();
         $carrier = '';
         if (trim($data[0]) == 'ShipmentInformationShipmentID') {
             echo "Detected UPS file...<br/>";
             $carrier = "UPS";
@@ -1998,12 +1995,12 @@ class storeController extends expController {
                 if (method_exists($calc, 'delayed_capture')) {
                     //$result = $calc->delayed_capture($bm,$bm->billing_cost);
                     $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;
                         $successSet[$count]['request_id'] = $result->request_id;
                         $successSet[$count]['reference_id'] = $result->PNREF;
@@ -2011,37 +2008,37 @@ class storeController extends expController {
                         $successSet[$count]['shipping_tracking_number'] = $data[0];
                         $successSet[$count]['carrier'] = $carrier;
                     } 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)
                         {
                             $change = new order_status_changes();
                             // save the changes
                             $change->from_status_id = $order->order_status_id;
                             //$change->comment = $this->params['comment'];
                             $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.";
                         $errorSet[$count]['order_id'] = $data[2];
                         $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;
                     $successSet[$count]['shipping_tracking_number'] = $data[0];
                     $successSet[$count]['carrier'] = $carrier;
@@ -2124,11 +2121,11 @@ class storeController extends expController {
                     //    $errorSet[$count]['message'] .= "<br/>Order " . $data[2] . " was captured successfully, however the email notification was not successful.";
                     //}
                 }
             }
 
-            //eDebug($product);        
+            //eDebug($product);
         }
         fclose($handle);
         ini_set('auto_detect_line_endings',$line_end);
 
         assign_to_template(array(
@@ -2229,11 +2226,11 @@ class storeController extends expController {
         ini_set('auto_detect_line_endings',TRUE);
         $handle = fopen($file->path, "r");
 
         // read in the header line and discard it
         $data = fgetcsv($handle, 10000, ",");
-        //eDebug($data);      
+        //eDebug($data);
 //        $dataset = array();
 
         //mc=1, nt=2, amm=3
 
         if ($this->params['type_of_address'][0] == 'mc') {
diff --git a/framework/modules/ecommerce/controllers/taxController.php b/framework/modules/ecommerce/controllers/taxController.php
index 651d108b63..713d2e855d 100644
--- a/framework/modules/ecommerce/controllers/taxController.php
+++ b/framework/modules/ecommerce/controllers/taxController.php
@@ -22,17 +22,10 @@
  */
 
 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");
     }
 
     static function description() {
diff --git a/framework/modules/ecommerce/products/models/donation.php b/framework/modules/ecommerce/products/models/donation.php
index aacb5ad912..c5c05ec30d 100644
--- a/framework/modules/ecommerce/products/models/donation.php
+++ b/framework/modules/ecommerce/products/models/donation.php
@@ -63,14 +63,14 @@ class donation extends product {
             $range = 'first';
         }
 
         $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';
             $records = $db->selectExpObjects($this->tablename, $sql, $this->classname);
             return empty($records) ? null : $records[0];
diff --git a/framework/modules/events/controllers/eventController.php b/framework/modules/events/controllers/eventController.php
index 35e95c7e71..4614935776 100644
--- a/framework/modules/events/controllers/eventController.php
+++ b/framework/modules/events/controllers/eventController.php
@@ -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
diff --git a/framework/modules/events/models/event.php b/framework/modules/events/models/event.php
index 982c5a293e..2609d11c10 100644
--- a/framework/modules/events/models/event.php
+++ b/framework/modules/events/models/event.php
@@ -50,10 +50,15 @@ class event extends expRecord {
             return parent::find($range, $where, $order, $limit, $limitstart, $get_assoc, $get_attached, $except, $cascade_except);
         } else {  // 'upcoming', 'month', 'week', 'day', etc...
             //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
             if (strcasecmp($range, 'upcoming') == 0) {
                 if (!empty($limit)) {
@@ -63,11 +68,11 @@ class event extends expRecord {
                 }
                 $dates = $ed->find("all", $where . " AND date >= " . $day . $eventlimit . " ORDER BY date ASC ");
 //                $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
 //                $extitem = array();
 //                foreach ($extitems as $days) {
@@ -76,22 +81,22 @@ class event extends expRecord {
 //                        if (empty($event->eventstart)) $event->eventstart = $event->eventdate->date;
 //                        $extitem[] = $event;
 //                    }
 //                }
 //                $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
 //                $regitem = array();
 //                if (!empty($regitems)) foreach ($regitems as $days) {
 //                    foreach ($days as $value) {
 //                        $regitem[] = $value;
 //                    }
 //                }
 //                $items = array_merge($items, $regitem);
-                
+
                 $items = expSorter::sort(array('array' => $items, 'sortby' => 'eventstart', 'order' => 'ASC'));
                 return $items;
             }
         }
     }
@@ -244,9 +249,9 @@ class event extends expRecord {
             $days['med'][$i] = strftime("%a", mktime(0, 0, 0, 6, $i+2, 2013));
             $days['long'][$i] = strftime('%A ', mktime(0, 0, 0, 6, $i+2, 2013));
         }
         return $days;
     }
-    
+
 }
 
 ?>
\ No newline at end of file
diff --git a/framework/modules/file/controllers/fileController.php b/framework/modules/file/controllers/fileController.php
index 8cf627359d..27dc1f1c4a 100755
--- a/framework/modules/file/controllers/fileController.php
+++ b/framework/modules/file/controllers/fileController.php
@@ -21,48 +21,54 @@
  * @package Modules
  */
 
 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"); }
     static function description() { return gt("Add and manage Exponent Files"); }
     static function author() { return "Phillip Ball - OIC Group, Inc"; }
 
     public function manage_fixPaths() {
         // 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;
 
         $expcat = new expCat();
         $cats = $expcat->find('all','module="file"');
@@ -87,11 +93,11 @@ class fileController extends expController {
             'filter'=>!empty($this->params['filter'])?$this->params['filter']:null,
             'cats'=>$catarray,
             'jscats'=>json_encode($jscatarray)
         ));
     }
-    
+
     public function uploader() {
         global $user;
         //expHistory::set('manageable', $this->params);
         flash('message',gt('Upload size limit').': '.ini_get('upload_max_filesize'));
         if(intval(ini_get('upload_max_filesize'))!=intval(ini_get('post_max_size')) && $user->isAdmin()){
@@ -111,18 +117,18 @@ class fileController extends expController {
             "post_size"=>ini_get('post_max_size'),
             "bmax"=>intval(ini_get('upload_max_filesize')/1024*1000000000),
             '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',
             BASE.'framework/modules/common/views/file/configure',
         );
@@ -146,11 +152,11 @@ class fileController extends expController {
                 $ar = new expAjaxReply(200, 'ok');
 		        $ar->send();
             }
         }
     }
-    
+
     /**
      * Returns view template configuration settings view template
      *
      */
     public function get_module_view_config() {
@@ -329,11 +335,11 @@ class fileController extends expController {
 //            if ($this->params['update']=='ck' || $this->params['update']=='tiny') {
             if (!empty($this->params['filter']) && $this->params['filter'] == 'image') {
                 $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);
 
             $groupedfiles = array();
@@ -362,13 +368,13 @@ class fileController extends expController {
                 'sort'=>$sort,
                 'dir'=>$dir,
                 'pageSize'=>$results,
                 'records'=>$files
             );
-                  
+
         }
-        
+
         echo json_encode($returnValue);
     }
 
     /**
      * create a new virtual folder in response to an ajax request
@@ -409,12 +415,12 @@ class fileController extends expController {
             }
         } else {
             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;
 
         $notafile = array();
 //        $files = $db->selectObjects('expFiles',1);
@@ -525,11 +531,11 @@ class fileController extends expController {
         }
         redirect_to(array("controller"=>'file',"action"=>'picker',"ajax_action"=>1,"update"=>$this->params['update'],"filter"=>$this->params['filter']));
     }
 
     public function upload() {
-        
+
         // upload the file, but don't save the record yet...
         if ($this->params['resize'] != 'false') {
             $maxwidth = $this->params['max_width'];
         } else {
             $maxwidth = null;
@@ -560,11 +566,11 @@ class fileController extends expController {
             }
         } else {
             echo gt('File was NOT uploaded!');
 //            flash('error',gt('File was not uploaded!'));
         }
-    } 
+    }
 
     public function quickUpload(){
         global $user;
 
         if (!empty($this->params['folder']) || (defined('QUICK_UPLOAD_FOLDER') && QUICK_UPLOAD_FOLDER != '' && QUICK_UPLOAD_FOLDER != 0)) {
@@ -659,25 +665,25 @@ class fileController extends expController {
             $ar = new expAjaxReply(200, gt('Your title was updated successfully'), $file);
         } else {
             $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'];
             $file->save();
             $ar = new expAjaxReply(200, gt('Your alt was updated successfully'), $file);
         } else {
             $ar = new expAjaxReply(300, gt("You didn't create this file, so you can't edit it."));
         }
         $ar->send();
         echo json_encode($file);  //FIXME we exit before hitting this
-    } 
+    }
 
     public function editShare() {
         global $user;
         $file = new expFile($this->params['id']);
 		if(!isset($this->params['newValue'])) {
diff --git a/framework/modules/file/models/expFile.php b/framework/modules/file/models/expFile.php
index f1b60fe946..ab52df0b86 100644
--- a/framework/modules/file/models/expFile.php
+++ b/framework/modules/file/models/expFile.php
@@ -423,11 +423,11 @@ 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.
         $resized = false;
         $maxwidth = intval($_max_width);
@@ -733,12 +733,13 @@ class expFile extends expRecord {
      * @throws void
      *
      */
     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);
     }
 
     /**
diff --git a/framework/modules/filedownloads/controllers/filedownloadController.php b/framework/modules/filedownloads/controllers/filedownloadController.php
index aec54859f6..6039250d79 100755
--- a/framework/modules/filedownloads/controllers/filedownloadController.php
+++ b/framework/modules/filedownloads/controllers/filedownloadController.php
@@ -36,11 +36,11 @@ class filedownloadController extends expController {
     public $rss_is_podcast = true;
 
     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;
         if (!empty($this->params['view']) && ($this->params['view'] == 'showall_accordion' || $this->params['view'] == 'showall_tabbed')) {
             $limit = '0';
@@ -88,25 +88,25 @@ class filedownloadController extends expController {
     public function downloadfile() {
         if (empty($this->params['fileid'])) {
             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();
     }
 
     /**
      * Returns rich snippet PageMap meta data
      *
@@ -217,14 +217,14 @@ class filedownloadController extends expController {
     function getRSSContent($limit = 0) {
         include_once(BASE.'external/mp3file.php');
 
         $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
             $rss_item->title = expString::convertSmartQuotes($item->title);
             $rss_item->link = $rss_item->guid = makeLink(array('controller'=>$this->baseclassname, 'action'=>'show', 'title'=>$item->sef_url));
@@ -279,9 +279,9 @@ class filedownloadController extends expController {
             if ($limit && count($rssitems) >= $limit)
                 break;
         }
         return $rssitems;
     }
-	
+
 }
 
 ?>
\ No newline at end of file
diff --git a/framework/modules/forms/controllers/formsController.php b/framework/modules/forms/controllers/formsController.php
index 6ff7afb9a3..e32cfbbe74 100644
--- a/framework/modules/forms/controllers/formsController.php
+++ b/framework/modules/forms/controllers/formsController.php
@@ -25,10 +25,17 @@ class formsController extends expController {
     public $useractions = array(
         'enterdata' => 'Input Records',
         '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',
         'comments',
         'ealerts',
@@ -37,14 +44,10 @@ class formsController extends expController {
 //        'pagination',
         'rss',
         '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() {
         return gt("Forms");
     }
@@ -79,22 +82,22 @@ class formsController extends expController {
             expHistory::set('viewable', $this->params);
             $f = null;
             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']);
                 $this->get_defaults($f);
             }
 
             if (!empty($f)) {
                 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'];
                 }
                 $fc = new forms_control();
                 if (empty($this->config['column_names_list'])) {
@@ -198,11 +201,11 @@ class formsController extends expController {
             if (!empty($this->config)) {
                 $f = $this->forms->find('first', 'id=' . $this->config['forms_id']);
             } 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));
             }
 
             if (!empty($f)) {
                 $fc = new forms_control();
@@ -708,14 +711,14 @@ class formsController extends expController {
 //                    "MIME-Version" => "1.0",
 //                    "Content-type" => "text/html; charset=" . LANG_CHARSET
 //                );
 
                 $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(
 //                    'headers'      => $headers,
                     "text_message" => $tmsg,
@@ -1937,10 +1940,14 @@ 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");
         $recordsdone = 0;
         $linenum = 1;
diff --git a/framework/modules/help/controllers/helpController.php b/framework/modules/help/controllers/helpController.php
index d2dac57cbe..1982ea6aee 100755
--- a/framework/modules/help/controllers/helpController.php
+++ b/framework/modules/help/controllers/helpController.php
@@ -39,11 +39,11 @@ class helpController extends expController {
     );  // all options: ('aggregation','categories','comments','ealerts','facebook','files','pagination','rss','tags','twitter',)
 
     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
         if (!expSession::is_set('help-version')) {
             $version = help_version::getCurrentHelpVersion();
@@ -72,17 +72,17 @@ class helpController extends expController {
 	    expHistory::set('viewable', $this->params);
 	    $hv = new help_version();
 	    //$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';
 
 	    // grab the pagination object
@@ -125,10 +125,11 @@ class helpController extends expController {
             $version_id = help_version::getHelpVersionId($this->params['version']);
             if (empty($version_id)) {
                 $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)) {
             redirect_to(array('controller'=>'notfound','action'=>'page_not_found','title'=>$this->params['title']));
         }
@@ -199,14 +200,14 @@ class helpController extends expController {
      * Manage help documents
      */
 	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'));
 //            $this->edit_version();
 	    }
@@ -216,11 +217,11 @@ class helpController extends expController {
             if (!empty($sectionref->source) && empty($sections[$sectionref->source])) {
                 $sections[$sectionref->source] = $db->selectValue('section', 'name', 'id="' . $sectionref->section .'"');
             }
         }
 
-	    $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,
             'limit'=>30,
             'order'      => (isset($this->params['order']) ? $this->params['order'] : 'help_version_id'),
@@ -261,11 +262,11 @@ class helpController extends expController {
 	    $current_docs = $help->find('all', 'help_version_id='.$from.' AND parent=0',$order);
 	    foreach ($current_docs as $doc) {
             $origid = $doc->id;
 	        unset($doc->id);
 	        $doc->help_version_id = $to;
-		    
+
 //	        $tmpsef = $doc->sef_url;
 //	        $doc->sef_url = "";
 //	        $doc->save();
 //	        $doc->sef_url = $tmpsef;
 //	        $doc->do_not_validate = array('sef_url');
@@ -311,14 +312,14 @@ class helpController extends expController {
     /**
      * Manage help versions
      */
 	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';
 
 	    $page = new expPaginator(array(
             'sql'=>$sql,
@@ -334,11 +335,11 @@ class helpController extends expController {
                 gt('Title')=>'title',
                 gt('Current')=>'is_current',
                 gt('# of Docs')=>'num_docs'
             ),
         ));
-	    
+
 	    assign_to_template(array(
             'current_version'=>$current_version,
             'page'=>$page
         ));
 	}
@@ -360,37 +361,37 @@ class helpController extends expController {
      */
 	public function delete_version() {
 	    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();
 	}
 
     /**
      * Creates a new help version, possibly based on existing help version
      */
 	public function update_version() {
 	    // 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');
             help_version::clearHelpVersion();
 	    }
@@ -400,14 +401,14 @@ class helpController extends expController {
 	    $id = empty($this->params['id']) ? null : $this->params['id'];
 	    $version = new help_version();
 	    // 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();
 
 	    flash('message', gt('Saved help version').' '.$version->version);
@@ -534,9 +535,9 @@ class helpController extends expController {
         }
 //	    $section = $db->selectObject('section','id='. intval($sid));
         $section = new section(intval($sid));
 	    return $section;
 	}
-	
+
 }
 
 ?>
\ No newline at end of file
diff --git a/framework/modules/help/models/help_version.php b/framework/modules/help/models/help_version.php
index 5413e9c2c3..a3b53c8751 100644
--- a/framework/modules/help/models/help_version.php
+++ b/framework/modules/help/models/help_version.php
@@ -50,17 +50,17 @@ 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() {
         global $db;
 
diff --git a/framework/modules/importexport/controllers/importexportController.php b/framework/modules/importexport/controllers/importexportController.php
index 4e84c32081..32deeb39ef 100644
--- a/framework/modules/importexport/controllers/importexportController.php
+++ b/framework/modules/importexport/controllers/importexportController.php
@@ -20,10 +20,17 @@
  * @subpackage Controllers
  * @package    Modules
  */
 
 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',
         'categories',
         'comments',
@@ -33,15 +40,10 @@ class importexportController extends expController {
         'rss',
         'tags',
         '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");
     }
 
@@ -175,10 +177,15 @@ class importexportController extends expController {
         if (!count($this->params['items'])) {
             expValidator::setErrorField('items');
             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'];
         $errors = array();
         $model = new $type->basemodel_name;
@@ -355,11 +362,11 @@ class importexportController extends expController {
         expHistory::back();
     }
 
     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'])) {
             flash('error', gt('There was an error uploading your file.  Please try again.'));
             redirect_to(array('controller' => 'store', 'action' => 'import_external_addresses'));
@@ -395,121 +402,121 @@ class importexportController extends expController {
 
     /*function importAddresses($file)
     {
         $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/>";
             foreach ($errorSet as $row=>$err)
             {
@@ -522,11 +529,11 @@ class importexportController extends expController {
                     }
                 }
                 else echo "--" . $err . "<br/>";
             }
             echo "</font>";
-        }    
+        }
     }*/
 
     function importProduct($file=null) {
         if (empty($file->path)) {
             $file = new stdClass();
diff --git a/framework/modules/migration/controllers/migrationController.php b/framework/modules/migration/controllers/migrationController.php
index 16454b6c43..906e1bfdbe 100755
--- a/framework/modules/migration/controllers/migrationController.php
+++ b/framework/modules/migration/controllers/migrationController.php
@@ -19,11 +19,11 @@
  * @subpackage Controllers
  * @package Modules
  */
 
 class migrationController extends expController {
-    protected $add_permissions = array(
+    protected $manage_permissions = array(
         'analyze'=>'Analyze Data',
         'migrate'=>'Migrate Data'
     );
 
     // this is a list of modules that we can convert to exp2 type modules.
diff --git a/framework/modules/navigation/controllers/navigationController.php b/framework/modules/navigation/controllers/navigationController.php
index bb50bd761b..4db87e64de 100644
--- a/framework/modules/navigation/controllers/navigationController.php
+++ b/framework/modules/navigation/controllers/navigationController.php
@@ -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;
+    }
+
+}
+
+?>
diff --git a/framework/modules/news/controllers/newsController.php b/framework/modules/news/controllers/newsController.php
index fedfeb7faa..6f3d088d69 100755
--- a/framework/modules/news/controllers/newsController.php
+++ b/framework/modules/news/controllers/newsController.php
@@ -24,22 +24,25 @@
 class newsController extends expController {
     public $useractions = array(
         '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',
 //        'ealerts',
 //        '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."); }
     static function isSearchable() { return true; }
 
@@ -56,19 +59,19 @@ class newsController extends expController {
         // figure out if should limit the results
         if (isset($this->params['limit'])) {
             $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
         $items = $this->news->find('all', $this->aggregateWhereClause(), $order);
 
         // 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,
             'limit'=>$limit,
             'order'=>$order,
@@ -76,11 +79,11 @@ class newsController extends expController {
             'controller'=>$this->params['controller'],
             'action'=>$this->params['action'],
             'src'=>$this->loc->src,
             'view'=>empty($this->params['view']) ? null : $this->params['view']
         ));
-            
+
         assign_to_template(array(
             'page'=>$page,
             'items'=>$page->records,
             'rank'=>($order==='rank')?1:0,
             'params'=>$this->params,
@@ -132,11 +135,11 @@ class newsController extends expController {
         // 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 news($id);
         if (empty($record->id))
             redirect_to(array('controller'=>'notfound','action'=>'page_not_found','title'=>$this->params['title']));
@@ -174,11 +177,11 @@ 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;
         if (isset($this->config['only_featured'])) $where .= ' AND is_featured=1';
 
@@ -195,42 +198,42 @@ class newsController extends expController {
                 gt('Title')=>'title',
                 gt('Published On')=>'publish',
                 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));
             $rss_item->description = expString::convertSmartQuotes($item->body);
             $rss_item->author = user::getUserById($item->poster)->firstname.' '.user::getUserById($item->poster)->lastname;
@@ -250,11 +253,11 @@ class newsController extends expController {
      *
      * @param $items
      * @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
 	        $RSS->set_timeout(20);  // default is 10
 //	        $RSS->set_output_encoding('UTF-8');  // default is UTF-8
diff --git a/framework/modules/photoalbum/controllers/photosController.php b/framework/modules/photoalbum/controllers/photosController.php
index 824f78fe43..b2208ffea3 100755
--- a/framework/modules/photoalbum/controllers/photosController.php
+++ b/framework/modules/photoalbum/controllers/photosController.php
@@ -26,10 +26,13 @@ class photosController extends expController {
 //    public $useractions = array(
 //        'showall'=>'Gallery',
 //        'slideshow'=>'Slideshow',
 //        //'showall_tags'=>"Tag Categories"
 //    );
+    protected $manage_permissions = array(
+        'multi'=>'Bulk Actions',
+    );
     public $remove_configs = array(
         'comments',
         'ealerts',
         'facebook',
         'files',
@@ -39,11 +42,11 @@ class photosController extends expController {
     );  // all options: ('aggregation','categories','comments','ealerts','facebook','files','pagination','rss','tags','twitter',)
 
     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;
         if (!empty($this->params['view']) && ($this->params['view'] == 'showall_accordion' || $this->params['view'] == 'showall_tabbed')) {
             $limit = '0';
@@ -64,26 +67,26 @@ class photosController extends expController {
             'src'=>$this->loc->src,
             'columns'=>array(
                 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))
             redirect_to(array('controller'=>'notfound','action'=>'page_not_found','title'=>$this->params['title']));
 
@@ -119,11 +122,11 @@ class photosController extends expController {
 //            "next"=>$next,
 //            "previous"=>$prev,
             'config'=>$config
         ));
     }
-    
+
     public function slideshow() {
         expHistory::set('viewable', $this->params);
         $order = isset($this->config['order']) ? $this->config['order'] : "rank";
         $page = new expPaginator(array(
             'model'=>'photo',
@@ -145,11 +148,11 @@ class photosController extends expController {
         assign_to_template(array(
 //            'slides'=>$slides
             'slides'=>$page->records,
         ));
     }
-    
+
     public function showall_tags() {
         $images = $this->image->find('all');
         $used_tags = array();
         foreach ($images as $image) {
             foreach($image->expTag as $tag) {
@@ -158,18 +161,18 @@ class photosController extends expController {
                 } else {
                     $exptag = new expTag($tag->id);
                     $used_tags[$tag->id] = $exptag;
                     $used_tags[$tag->id]->count = 1;
                 }
-                
+
             }
         }
-        
+
         assign_to_template(array(
             'tags'=>$used_tags
         ));
-    }           
+    }
 
     /**
      * Returns rich snippet PageMap meta data
      *
      * @param $request
@@ -193,11 +196,11 @@ class photosController extends expController {
 
     public function update() {
 
         //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();
     }
 
     public function multi_add() {
diff --git a/framework/modules/pixidou/controllers/pixidouController.php b/framework/modules/pixidou/controllers/pixidouController.php
index 14afb2284a..6294e5134b 100755
--- a/framework/modules/pixidou/controllers/pixidouController.php
+++ b/framework/modules/pixidou/controllers/pixidouController.php
@@ -20,15 +20,14 @@
  * @subpackage Controllers
  * @package Modules
  */
 
 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"); }
     static function description() { return gt("Add and manage Exponent Files"); }
     static function author() { return "Phillip Ball - OIC Group, Inc"; }
@@ -38,84 +37,84 @@ class pixidouController extends expController {
         return false;
     }
 
     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']);
         if (!empty($this->params['cpi']) && strpos($this->params['cpi'], '..') !== false) {
             $this->params['exitType'] = 'error';
         }
         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;
                 $newFile->is_image = $oldimage->is_image;
                 $newFile->save(); //Save it to the database
 
                 break;
             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
+?>
diff --git a/framework/modules/portfolio/controllers/portfolioController.php b/framework/modules/portfolio/controllers/portfolioController.php
index f81fc505ce..5d26b122da 100755
--- a/framework/modules/portfolio/controllers/portfolioController.php
+++ b/framework/modules/portfolio/controllers/portfolioController.php
@@ -25,21 +25,21 @@ class portfolioController extends expController {
     public $useractions = array(
         'showall'=>'Show all', 
         'tags'=>"Tags",
         'slideshow'=>"Slideshow"
     );
+    protected $manage_permissions = array(
+        'import'=>'Import Portfolio Items',
+        'export'=>'Export Portfolio Items'
+    );
     public $remove_configs = array(
         'comments',
         'ealerts',
         'facebook',
         '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."); }
     static function isSearchable() { return true; }
 
diff --git a/framework/modules/recyclebin/controllers/recyclebinController.php b/framework/modules/recyclebin/controllers/recyclebinController.php
index 63945fb77d..29f0d4fa64 100755
--- a/framework/modules/recyclebin/controllers/recyclebinController.php
+++ b/framework/modules/recyclebin/controllers/recyclebinController.php
@@ -20,11 +20,11 @@
  * @subpackage Controllers
  * @package Modules
  */
 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'
     );
 
@@ -95,10 +95,12 @@ class recyclebinController extends expController
      */
     public function remove()
     {
         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
             $db->delete(
                 'sectionref',
diff --git a/framework/modules/report/controllers/reportController.php b/framework/modules/report/controllers/reportController.php
index ca81e9f62a..ccd4132167 100755
--- a/framework/modules/report/controllers/reportController.php
+++ b/framework/modules/report/controllers/reportController.php
@@ -20,22 +20,27 @@
  * @subpackage Controllers
  * @package    Modules
  */
 
 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");
     }
 
@@ -337,17 +342,17 @@ 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
                 (
                     [0] => 0
                     [1] => 1
@@ -359,24 +364,24 @@ class reportController extends expController {
                     [0] => 0
                     [1] => 2
                 )
 
             [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
                 (
                     [0] => -1
                 )
@@ -391,12 +396,12 @@ class reportController extends expController {
         expSession::set('order_print_query', $sql . $sqlwhere);
         //$where = 1;//$this->aggregateWhereClause();
         //$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);
 
         $page = new expPaginator(array(
@@ -456,11 +461,11 @@ class reportController extends expController {
         foreach ($diss as $discount) {
             $discounts[$discount->id] = $discount->coupon_code;
         }
 
         /*$geo = new geoRegion();
-        $geos = $geo->find('all');        
+        $geos = $geo->find('all');
         $states = array();
         $states[-1] = gt('--Any--');
         foreach ($geos as $skey=>$state)
         {
             $states[$skey] = $state->name;
@@ -471,11 +476,11 @@ class reportController extends expController {
         ksort($payment_methods);
         //array('-1'=>'', 'V'=>'Visa','MC'=>'Mastercard','D'=>'Discover','AMEX'=>'American Express','PP'=>'PayPal','GC'=>'Google Checkout','Other'=>'Other');
 
         //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);
         $now_hour = strftime("%I");
         $now_min = strftime("%M");
@@ -499,11 +504,11 @@ class reportController extends expController {
         global $db;
         //eDebug($this->params);
         $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";
         if ((count($p['order_status_changed']) == 1 && $p['order_status_changed'][0] != -1) || count($p['order_status_changed']) > 1 || (!empty($p['include_status_date']) && (!empty($p['date-sstartdate']) || !empty($p['date-senddate'])))) $sql .= ", FROM_UNIXTIME(osc.created_at,'%c/%e/%y %h:%i:%s %p') as status_changed_date";
         $sql .= " from " . $db->prefix . "orders as o ";
@@ -683,11 +688,11 @@ 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;
                 if ($s == 'VisaCard' || $s == 'AmExCard' || $s == 'MasterCard' || $s == 'DiscoverCard') {
                     $paymentQuery = 'b.billing_options LIKE "%' . $s . '%"';
@@ -708,17 +713,17 @@ 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
                 (
                     [0] => 0
                     [1] => 1
@@ -730,24 +735,24 @@ class reportController extends expController {
                     [0] => 0
                     [1] => 2
                 )
 
             [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
                 (
                     [0] => -1
                 )
@@ -770,15 +775,15 @@ class reportController extends expController {
         //eDebug(expSession::get('order_export_values'));
         //$where = 1;//$this->aggregateWhereClause();
         //$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',
             //'records'=>$items,
             // 'where'=>$where,
@@ -801,11 +806,11 @@ class reportController extends expController {
                 gt('Order Type')          => 'order_type',
                 gt('Status')              => 'status_title'
             ),
         ));
 
-        //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(
             'print_orders' => 'Print Orders',
             'export_odbc' => 'Export Shipping Data to CSV',
@@ -942,11 +947,11 @@ 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']);
             $ui = array();
             $uiInfo = '';
@@ -1158,13 +1163,13 @@ class reportController extends expController {
 //        eDebug("Stored:" . $exportSQL);
         expSession::set('product_export_query', $exportSQL);
         //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,
             // 'where'=>$where,
             'sql'        => $sqlstart . $sql . $sqlwhere,
@@ -1195,11 +1200,11 @@ class reportController extends expController {
             'order'=>'purchased',
             'dir'=>'DESC',
             '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',
             )
         ));            */
@@ -1209,20 +1214,20 @@ class reportController extends expController {
         );
         assign_to_template(array(
             '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);
         $str = str_replace("�", "&#174;", $str);
         $str = str_replace("�", "-", $str);
@@ -1266,11 +1271,11 @@ class reportController extends expController {
         $str = str_replace("�", "&ldquo;", $str);
         $str = str_replace("\r\n", " ", $str);
         $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);
         $str = str_replace("�", "&#189;", $str);
         $str = str_replace("�", "&#190;", $str);
@@ -1301,11 +1306,11 @@ class reportController extends expController {
         $str = str_replace("�", "-", $str);
         $str = str_replace("�", "&#151;", $str);
         $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);
         $str = str_replace("�", "&#188;", $str);
         $str = str_replace("�", "&#189;", $str);
@@ -1537,18 +1542,18 @@ class reportController extends expController {
     function productFeed() {
 //        global $db;
         //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);
 
         $p = new product();
         $prods = $p->find('all', 'parent_id=0 AND ');
@@ -1728,49 +1733,49 @@ class reportController extends expController {
         //$orders = $this->o->find('all','purchased >= ' . $this->tstart . ' AND purchased <= ' . $this->tend,null,null,null,true,false,$except,true);
         // $sql = "SELECT DATE_FORMAT(created_at, '%Y-%m-%d') as formattedDate FROM orders WHERE created_at
         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));
         */
     }
 
     function batch_export() {
         global $db;
@@ -1883,11 +1888,11 @@ class reportController extends expController {
         echo "<br/><br/>".gt('Download the file here').": <a href='" . PATH_RELATIVE . $outFile . "'>".gt('Product Export')."</a>";
 
         /*eDebug(BASE . "tmp/export.csv");
         $db->sql($sql);
         eDebug($db->error());*/
-        /*OPTIONALLY ENCLOSED BY '" . '"' . 
+        /*OPTIONALLY ENCLOSED BY '" . '"' .
         "' ESCAPED BY '\\'
         LINES TERMINATED BY '" . '\\n' .
         "' */
     }
 
@@ -2014,11 +2019,11 @@ class reportController extends expController {
         echo "<br/><br/>".gt('Download the file here').": <a href='" . PATH_RELATIVE . $outFile . "'>".gt('Product Export')."</a>";
 
         /*eDebug(BASE . "tmp/export.csv");
         $db->sql($sql);
         eDebug($db->error());*/
-        /*OPTIONALLY ENCLOSED BY '" . '"' . 
+        /*OPTIONALLY ENCLOSED BY '" . '"' .
         "' ESCAPED BY '\\'
         LINES TERMINATED BY '" . '\\n' .
         "' */
     }
 
diff --git a/framework/modules/search/controllers/searchController.php b/framework/modules/search/controllers/searchController.php
index 79c6a222ed..582a0f3858 100755
--- a/framework/modules/search/controllers/searchController.php
+++ b/framework/modules/search/controllers/searchController.php
@@ -24,14 +24,15 @@
 class searchController extends expController {
     public $useractions = array(
         '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',
         'comments',
         'ealerts',
@@ -107,11 +108,11 @@ class searchController extends expController {
             'page'=>$page,
             'terms'=>$terms,
             'params'=>$this->params,
         ));
     }
-    
+
     public static function spider() {
         global $db;
 
         // reinitialize search index
 	    $db->delete('search');
@@ -134,22 +135,22 @@ class searchController extends expController {
 		    if (method_exists($controller,'isSearchable') && $controller->isSearchable()) {
 //			    $mods[$controller->name()] = $controller->addContentToSearch();
                 $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();
     }
 
@@ -218,93 +219,93 @@ class searchController extends expController {
             if ($i>=1) $sql .= " OR ";
             $sql .= $srchcol[$i].' LIKE \'%'.$this->params['query'].'%\'';
         }*/
         //    $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;
 		$uname = array('id'=>array($all_user, $anonymous), 'name'=>array('All Users', 'Anonymous'));
 
 		$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;
 				$badSearch[$ctr2]['query'] = $item->query;
 				$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) {
 				$u_id = 0;
 			} else {
 				$u_id = $user_default;
 			}
 			$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++) {
 			if(!empty($records[$i]->user_id)) {
 				$u = user::getUserById($records[$i]->user_id);
 				$records[$i]->user = $u->firstname . ' ' . $u->lastname;
 			}
 		}
-		
+
         $page = new expPaginator(array(
             'records' => $records,
             'where'=>1,
             'model'=>'search_queries',
             'limit'=>(isset($this->config['limit']) && $this->config['limit'] != '') ? 10 : $this->config['limit'],
@@ -326,34 +327,34 @@ class searchController extends expController {
             'page'=>$page,
             'users'=>$uname,
             '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();
         $records_values_arr = array();
 		foreach($records as $item) {
 			$records_key_arr[] = '"' . addslashes($item->query) . '"';
 			$records_values_arr[] = number_format((($item->cnt / $count)*100), 2);
 		}
 		$records_key   = implode(",", $records_key_arr);
 		$records_values = implode(",", $records_values_arr);
-		
+
 		assign_to_template(array(
             'records'=>$records,
             'total'=>$count,
             'limit' => $limit,
             'records_key' => $records_key,
diff --git a/framework/modules/simplepoll/controllers/simplePollController.php b/framework/modules/simplepoll/controllers/simplePollController.php
index a324b9ff99..40c4008f90 100644
--- a/framework/modules/simplepoll/controllers/simplePollController.php
+++ b/framework/modules/simplepoll/controllers/simplePollController.php
@@ -141,11 +141,11 @@ class simplePollController extends expController {
 
     public function vote() {
         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.';
                 $this->config['already_voted_message'] = 'You have already voted in this poll.';
                 $this->config['voting_closed_message'] = 'Voting has been closed for this poll.';
diff --git a/framework/modules/users/controllers/loginController.php b/framework/modules/users/controllers/loginController.php
index 43f7771d8e..55e015e114 100644
--- a/framework/modules/users/controllers/loginController.php
+++ b/framework/modules/users/controllers/loginController.php
@@ -123,11 +123,11 @@ 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')) {
 				$url = expSession::get('redirecturl_error');
 				expSession::un_set('redirecturl_error');
diff --git a/framework/modules/users/controllers/usersController.php b/framework/modules/users/controllers/usersController.php
index 75e72cf5ea..207c24959d 100755
--- a/framework/modules/users/controllers/usersController.php
+++ b/framework/modules/users/controllers/usersController.php
@@ -22,22 +22,23 @@
  */
 /** @define "BASE" "../../../.." */
 
 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',
         'userperms'        => 'User Permissions',
         'groupperms'       => 'Group Permissions',
         'import'           => 'Import Users',
         'export'           => 'Export Users',
-    );
-    protected $remove_permissions = array(
-        'create',
-        'edit'
+        'update'           => 'Update Users',
     );
 
     static function displayname() {
         return gt("User Manager");
     }
@@ -169,11 +170,11 @@ class usersController extends expController {
         } elseif (!$user->isAdmin() && ($user->isLoggedIn() && $user->id != $id)) {
             flash('error', gt('You do not have permission to edit this user account'));
             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)) {
             $u = new user($id);
             $u->update($this->params);
@@ -231,11 +232,11 @@ class usersController extends expController {
                 $db->insertObject($memb, 'groupmembership');
             }
             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
             // are marked as 'inclusive' automatically pick up new users.  This is the part
             // of the code that goes out, finds those groups, and makes the new user a member
@@ -489,10 +490,11 @@ class usersController extends expController {
 
     public function send_new_password() {
         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']);
             if (!empty($u) && $u->count > 1) {
                 expValidator::failAndReturnToForm(gt('That email address applies to more than one user account, please enter your username instead.'));
@@ -537,11 +539,11 @@ class usersController extends expController {
 
     public function confirm_password_reset() {
         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();
         }
 
@@ -615,11 +617,11 @@ class usersController extends expController {
         if (($isuser && empty($this->params['password'])) || (!empty($this->params['password']) && $user->password != user::encryptPassword($this->params['password']))) {
             flash('error', gt('The current password you entered is not correct.'));
             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);
         if (is_string($ret)) {
             flash('error', $ret);
@@ -652,10 +654,17 @@ class usersController extends expController {
             'u' => $u
         ));
     }
 
     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);
         }
 
         if (empty($this->params['new_password1'])) {
@@ -1495,10 +1504,14 @@ class usersController extends expController {
             "params" => $this->params,
         ));
     }
 
     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");
         $userinfo = array();
         $userarray = array();

Vulnerable code:         'approve'  => 'Approval',
    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
        $tag = new expTag($this->params['tag']);
            'moduletitle' => ucfirst($modelname) . ' ' . gt('items tagged with') . ' "' . expString::sanitize($this->params['tag']) . '"',
            $id = $this->params['title'];
        $id = isset($this->params['title']) ? $this->params['title'] : (isset($this->params['id']) ? $this->params['id'] : null);
     * permission functions to aggregate a module's permissions based on add/remove permissions
    $controller = new $fullControllerName($src, $parms);    
    
    
    $perms = $controller->permissions();
    
    $common_action = null;
    //FIXME do we also need to account for actions with camelcase action/perm such as editItem ???
    if ($parms['action'] == 'update') {
    } elseif ($parms['action'] == 'edit' && (!isset($parms['id']) || $parms['id'] == 0)) {
        // 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;
            $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[$common_action]) ? gt("You must be logged in to perform this action") : $controller->requires_login[$common_action];
    } 
    
    
}   
    
    
    
    
    
    // get the common configuration files    
    // look for a config form for this module's current view    
    
    
    // set path information 
    
    
    
        // retrieve objects 
            // Otherwise we assume that in inbound is an array or Object to be processed as is.        
        // setup the exception array if it's not there.  This array tells the getAssociatedObjectsForThisModel() function which 
            // if not, then we check to see if we had a previous value in this particular 
            // this is good for when the developer is trying to update just a field or two 
            // in an existing record. 
        //$this->saveAssociatedObjects(); 
        // mapped view and src hasn't been passed in via link to the form 
    function columnUpdate($table, $col, $val, $where=1) {         
        //fwrite($lfh, $sql . "\n");    
        //fclose($lfh);                 
       
        $res = mysqli_query($this->connection, $sql); 
        
    
        //if ($table=="text") eDebug($object,true); 
            //if ($table=="text") eDebug($object,true); 
                    $val = serialize($val);   
        //if ($table == 'text') eDebug($sql,true);        
	 * Unescape a string based on the database connection
    function selectArraysBySql($sql) {        
		
	 * Unescape a string based on the database connection
   	 * Unescape a string based on the database connection
 * 
 *  
 *      'where'=>1, 
 * 
	public $where = '';	
     */	
		global $router,$db;
        $this->limit = empty($params['limit']) ? 0 : $params['limit'];
		$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_direction = $this->dir;	
                        
			
		}	
			
		
		
		
		
		        $this->last_pagelink = $this->total_pages; 
		for($i=$this->first_pagelink; $i<=$this->last_pagelink; $i++) { 
		} 	
		
         
		
       
        
	
        $func = new ReflectionClass($this);       
                $newParams[$propname] = $params[$propname];                
            }               
        }        
                $newParams[$propname] = $params[$propname];                
            }               
        }        
        
    
            
            
            
                
                } 
                
                    
                
    
        }    
    
			
			
            
				
				} 
				$params['order'] = $col;      				                        
				
				if (!empty($col)) {	
                        $params['dir'] = 'ASC'; 
                        $params['dir'] = 'DESC'; 
                        $params['dir'] = 'ASC'; 
                    }	
				}                  								
	
                $str .= "'" . $value . "'";
                    $str .= "'" . str_replace("'", "\'", $value) . "'";  //FIXME is this still necessary since we stripslashes above???
                    $str .= "'" . str_replace("'", '', $value) . "'";
?>
	} 
		}		
		
			$str = stripcslashes($str);  
        $str = str_replace("&lsquo;","'",$str);        
        $str = str_replace("�","-", $str); 
        $str = str_replace("\r\n"," ",$str); 
        $str = str_replace("�","(R)",$str);        
        $str = str_replace("&","&amp;",$str);      
		$str = str_replace(">","&gt;",$str);      		
        global $db;
//	        $str = @mysqli_real_escape_string($db->connection,trim(str_replace("�", "&trade;", $str)));
//            $str = @mysql_real_escape_string(trim(str_replace("�", "&trade;", $str)),$db->connection);
        $str = @$db->escapeString($db->connection, trim(str_replace("�", "&trade;", $str)));
        $str = '<title>' . $metainfo['title'] . "</title>\n";
            $str .= "\t" . '<meta http-equiv="Content-Type" content="text/html; charset=' . LANG_CHARSET . '" ' . XHTML_CLOSING . '>' . "\n";
            $str .= "\t" . '<meta content="' . $locale . '" http-equiv="Content-Language" ' . XHTML_CLOSING . '>' . "\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";
?>
	public $useractions = array(
    );
    protected $add_permissions = array(
        'import' => 'Import External Addresses',
//        'export' => 'Export External Addresses'
    
    
	
			if ($count == 0) 
            //user is not logged in, but allow anonymous checkout is enabled so we'll check 
            $this->params['is_shipping'] = 1; 
		expHistory::back(); 
	
        {    
                if ($address->is_shipping) 
    
        $db->setUniqueFlag($object, 'addresses', $this->params['is_what'], "user_id=" . $user->id);
        expHistory::back(); 
    
        
        $gr = new geoRegion();             
        
    
            $gc->active = true;            
            $gc->save();            
            $gc = new geoCountry($this->params['country_default']);            
            $db->setUniqueFlag($gc,'geo_country','is_default','id=' . $gc->id);    
            $gc->refresh();            
            $gr->save();            
    protected $add_permissions = array(
        'mass'=>'Mass Mailing',
        'update'=>'Update Settings',
        'change'=>'Change Settings',
        'save'=>'Save Settings',
        
        
    
        
	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();
	}
//					$section = $db->selectObject('sectionref',"module='containermodule' AND source='".$eloc->src."'");
		ksort($menu);		
        
        
    
    
    
    
    }	
    
        
        
        
        
        
        
    public $useractions = array(
        'showall'=>'Display Banner(s)'
    );
    
            // randomly grab one banner to be displayed 
            $where = 'id IN ('.implode(',', $this->config['banners']).')';    
            foreach($banners as $banner) {            
        
    
    
    
        
		
    
        }  
	
	
        
        $filename = 'banner_export' . date("m-d-Y") . '.csv';        
        fclose($fh);        
        
        // let the user know we did stuff.      
    protected $add_permissions = array(
        'approve'=>"Approve Comments",
        'import'=>'Import Blog Items',
        'export'=>'Export Blog Items'
    );
            redirect_to(array('controller'=>'notfound','action'=>'page_not_found','title'=>$this->params['title']));
        $modelname = empty($this->params['model']) ? $this->basemodel_name : $this->params['model'];
    protected $add_permissions = array(
        'approve'=>"Approve Comments"
    );
   	protected $remove_permissions = array(
    
            expHistory::back();  
	    } 
        
        
	}	
	
	    
            'sql'=>$sql, 
        $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'];
        $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".$this->params['content_type']."' ";
            'sql'=>$sql, 
        
            $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".$this->params['content_type']."' ";
        }        
        
			'content_id'=>$this->params['content_id'], 
        
        
                        
        
		
		
	
        
        /* The global constants can be overriden by passing appropriate params */ 
	    
	    
	
        
        /* The global constants can be overriden by passing appropriate params */ 
	    
	
        
        /* The global constants can be overriden by passing appropriate params */ 
        
        /* The global constants can be overriden by passing appropriate params */ 
	    
	    
        
        $db->delete($comment->attachable_table, 'expcomments_id='.$this->params['id']);        
        
	
        
        /* The global constants can be overriden by passing appropriate params */ 
	    
        
        
        $mail = new expMail();        
        
        
        /* The global constants can be overriden by passing appropriate params */ 
	    
        $mail = new expMail();        
        
        assign_to_template(array('record'=>$record,'tag'=>$tag));  //FIXME $record & $tag are undefined
		
	
		 
		if ($ctl) { 
		assign_to_template(array('form_html'=>$form->toHTML(), 'types'=>$types[$control_type]));			
	
	function save() {	
		if (call_user_func(array($_POST['control_type'],'useGeneric')) == true) { 	
		
	
	
			
		
    protected $add_permissions = array(
        'activate' => "Activate",
        'preview'  => "Preview Editor Toolbars"
    );

    protected $add_permissions = array(
        'approve'=>"Approve Comments"
    
        
        /* The global constants can be overriden by passing appropriate params */ 
        
        if (empty($this->params['formtitle'])) 
        
    }    
    
        
        /* The global constants can be overriden by passing appropriate params */ 
        
        
            'sql'=>$sql, 
        
    
        
        /* The global constants can be overriden by passing appropriate params */ 
        $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 .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".$this->params['content_type']."' ";
        
            'sql'=>$sql, 
        
        // count the unapproved comments
            $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".$this->params['content_type']."' ";
        }        
 
            'unapproved'=>$unapproved, 
            'content_id'=>$this->params['content_id'], 
        
        /* The global constants can be overriden by passing appropriate params */ 
        
        
        // if simplenotes are configed to require approvals set this to 0 otherwise we 
        
        
        
        
        
        
    
        
        /* The global constants can be overriden by passing appropriate params */ 
        
        
    
        
        
        /* The global constants can be overriden by passing appropriate params */ 
        
        
    
        
        
        /* The global constants can be overriden by passing appropriate params */ 
        
        
        
    
        
        /* The global constants can be overriden by passing appropriate params */ 
        
        
        
        $db->delete($simplenote->attachable_table, 'expsimplenote_id='.$this->params['id']);        
        
    
        
        /* The global constants can be overriden by passing appropriate params */ 
        $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'];
        
        
        
        $mail = new expMail();        
        
            $id = $this->params['title'];
    protected $add_permissions = array(
        // 'approve'=>"Approve Comments"
    );



	
    
    
        $src = empty($this->params['src']) ? null : $this->params['src'];
        
        
    
        
        
    
        $src = empty($this->params['src']) ? null : $this->params['src'];
        
        
        
            
            
        } 
        
    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 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 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 pending() {
        
        // 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
        ));
    }
    
    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
        ));
    }
    protected $add_permissions = array(
        'activate'=>'Activate Payment Options'
    
	
		
	
	    
                                'body'=>$calcobj->description(), 
        
	
	public function activate(){	
    
	
    
        
        $record = new optiongroup_master($id);       
    
        
        
    
        
        
        
        
    
        
    
        
        $record = new option_master($params);      
    
    function update_option_master() {        
        
        
            
        
    
    
    
		
    
        
        
        $groups = array( 
       // eDebug($discount);                        
       
       
        
    
        
    
    public function activate_discount(){    
        
    
	
	    
	
    
        
        
        $gc = new geoCountry();             
        
        $gr = new geoRegion();             
        
    }   
	
		$gc = new geoCountry();             
        
        $gr = new geoRegion();             
	 
		
		
	


    protected $add_permissions = array(
        'view_registrants'=> 'View Registrants',
        'emailRegistrants'=> 'Email Registrants',
    );

    protected $add_permissions = array(
        'showall'             => 'Manage',
        'show'                => 'View Orders',
        'setStatus'           => 'Change Status',
        'edit_payment_info'   => 'Edit Payment Info',
        'edit_address'        => 'Edit Address',
        'edit_order_item'     => 'Edit Order Item',
        'add_order_item'      => 'Add Order Item',
        'save_new_order_item'=> 'Save New Order Item',
        'edit_totals'         => 'Edit Totals',
        'edit_invoice_id'     => 'Edit Invoice Id',
        'update_sales_reps'   => 'Manage Sales Reps',
        'quickfinder'=> 'Do a quick order lookup',
        'edit_shipping_method'=> 'Edit Shipping Method',
        'create_new_order'    => 'Create A New Order',
        'createReferenceOrder'=> 'Create Reference Order',
        'save_reference_order'=> 'Save Reference Order'
            
                    $db->delete('orderitems', 'orders_id='.$cart->id);    
                
            }           
            
        //viewing of the order?        
                    //eDebug($order['id'] . ": " . $timer->mark());                        
            
            //eDebug($note,true);            
        // figure out what metadata to pass back based on the action 
        /*eDebug($this->params); 
        //eDebug($order,true); 
        //eDebug(expUnserialize($order->billingmethod[0]->billing_options));        
        //eDebug(expUnserialize($order->billingmethod[0]->billingtransaction[0]->billing_options),true); 
            //$newOi->products_tax = 0;        
        //eDebug($order,true); 
        //eDebug(expUnserialize($order->billingmethod[0]->billing_options));        
        //eDebug(expUnserialize($order->billingmethod[0]->billingtransaction[0]->billing_options),true); 
            //$oi->product->optiongroup = $parProd->optiongroup;   
            /*if ($uif['is_required'] || (!$uif['is_required'] && strlen($params['user_input_fields'][$uifkey]) > 0)) 
                    //flash('error', 'test');    
                    //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));      
                } 
        //eDebug($oi);        
            //we'll send over the product_id of the parent, along with id's and quantities of children we're adding 
        
                redirect_to(array('controller'=>'order','action'=>'show','id'=>$order[0]->id));            
                redirect_to(array('controller'=>'order','action'=>'show','id'=>$order->id));            
            flashAndFlow('message','Invalid order number.');        
                //eDebug($tmpCart,true); 
        $sql .= "from " . $db->prefix . "addresses as a "; //R JOIN " . 
        $sql .= "from " . $db->prefix . "external_addresses as a "; //R JOIN " . 
    
        
    
        
    
    
    
    
    
    
    
    

	protected $add_permissions = array(
        'manage'=>'Manage Purchase Orders',
        'edit'=>'Edit Purchase Orders',
        'manage_vendors'=>'Manage Vendors',
        'edit_vendor'=>'Edit Vendor',
        'update_vendor'=>'Update Vendor',
        'delete_vendor'=>'Delete vendors',
	
	
		
		
	
    
		
	
		
		
	
		
	
		
	
		
	
		
		
    
    protected $add_permissions = array(
        'toggle'=>'Enable/Disable Options'
		
		
		
	
		    
		        $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']; 
		
		$ar->send();		
	
        
        
	
	
	    
                    $id = $db->selectValue('shippingcalculator', 'id', 'calculator_name="'.$classname.'"');                    
                        if ($calcobj->isSelectable() == true) {                            
	
		
    
        $conf = serialize($calc->parseConfig($this->params));        
	
		
	
	
    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(

        //         
        //         //  $this->tags[$i]->draggable = $this->draggable; 
        //         //  $this->tags[$i]->checkable = $this->checkable; 
        // $obj = json_encode($categories);  
            // Trees mapped            
                    
                }        
                
        // 
        // 
        // 
        // 
        // 
        // 
        // 
        // 


    //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',
    );

            $ancestors = $this->category->pathToNode();       
            {                   
            $ancestors = $this->category->pathToNode();       
            //eDebug($editable_options[$group->title]);        
        //eDebug($product_type);  
        //eDebug($this->params,true);        
        if (empty($product->id)) // || empty($product->previous_id)) 
            //fwrite($lfh, "Deleting:" . $ctd->id . "\n");                             
        //$sql .= "GROUP BY p.id "; 
        $req = 'a29f9shsgh32hsf80s7';        
        {   
            $successSet[$count]['message'] = "Sucessfully imported row " . $count . ", order: " . $data[2] . "<br/>";                
            $successSet[$count]['shipping_tracking_number'] = '1ZNF453937547';    
        {   
            $data[2] = $inv + $count;                
            $amt += $count*$count;        
        
        assign_to_template(array('errorSet'=>$errorSet, 'successSet'=>$successSet));     
        //eDebug($this->params,true); 
        //eDebug($data);      
                        //just need to set the order shipping info, check and see if we send user an email, and set statuses.  
                        //shipping info:                                      
                        //$failMessage = "Attempted to delay capture order " . $data[2] . " and it failed with the following error: " . $result->errorCode . " - " .$result->message;   
                            
                            $order->save();                             
                        //continue;   
                    //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.";  
            //eDebug($product);        
        //eDebug($data);      
    protected $add_permissions = array(
        'manage_zones' => 'Manages Zones',
        'edit_zone'    => 'Add/Edit Zone',
        'update_zone'  => 'Update Zone',
        'delete_zone'  => 'Delete Zone'
    );

        $sql .= empty($order) ? '' : ' ORDER BY ' . $order;
            $sql .= empty($limit) ? '' : ' LIMIT ' . $limitstart . ',' . $limit;
<?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();
    }

}

                
                
                
    
    protected $add_permissions = array(
//        'picker'=>'Manage Files',
        'import'=>'Import',
        'export'=>'Export',
    );
        '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',
        
        
    
    
    
    
        
    
            
                  
        
    } 
    
        
    } 
    } 
        global $user;        
    } 
        // }    
        if ($name[0] == '.')
	
        
        $fd = new filedownload($this->params['fileid']); 
        }        
        
        
        parent::downloadfile();        
        
        foreach ($items as $key => $item) { 
	
    protected $add_permissions = array(
        'viewdata'  => "View Data",
        'enter_data' => "Enter Data"  // slight naming variation to not fully restrict enterdata method
    );
                $f = $this->forms->find('first', 'sef_url="' . $this->params['title'] . '"');
                    $where = $this->params['filter'];
                $f = $this->forms->find('first', 'sef_url="' . $this->params['title'] . '"');
                if ($this->config['auto_respond_form']) 
                if ($this->config['auto_respond_form']) 
	
        // pagination parameter..hard coded for now.	    
            $where .= ' AND parent=' . $this->params['parent'];
	    
	    
	    $where = empty($this->params['version']) ? 1 : 'help_version_id='.$this->params['version'];
		    
	    
	    
	    
	    
	    
	    
	    
	    expHistory::back();	    
	    
	    
	        self::copydocs($current_version->id, $version->id);	        
	
        return $db->selectValue('help_version', 'id', 'version="'.$version.'"');
        return $db->selectValue('help_version', 'version', 'id="'.$version_id.'"');
    //protected $permissions = array_merge(array("test"=>'Test'), array('copyProduct'=>"Copy Product"));
    protected $add_permissions = array(
        'import' => 'Import Data',
        'export' => 'Export Data'
    );
        //eDebug($this->params,true); 
        //eDebug($data);        
        $source = '';   
            $dataset[$value] = '';            
        
        
            $extAddy = new external_address();             
                $extAddy->lastname = $bName[2];    
                $extAddy->lastname = '';    
                $extAddy->lastname = $bName[1];        
            
            $extAddy->address2 = $data[6];            
            $extAddy->address2 = $data[6];            
            $extAddy->city = $data[7];            
            
            $extAddy->state = $state->id;                        
            $extAddy->zip = str_ireplace("'",'',$data[9]);            
            $extAddy->phone = $data[20];            
            $extAddy->email = $data[21];            
            
            
                $extAddy->is_shipping = 1;            
                $extAddy->save(false);            
            {                
                $extAddy->is_shipping = 0;            
                $extAddy->save(false);            
                
                $extAddy = new external_address();             
                    $extAddy->lastname = $sName[2];    
                    $extAddy->lastname = '';    
                    $extAddy->lastname = $sName[1];        
                
                $extAddy->address2 = $data[15];                            
                $extAddy->city = $data[16];            
                
                $extAddy->state = $state->id;                        
                $extAddy->zip = str_ireplace("'",'',$data[18]);            
                $extAddy->phone = $data[20];            
                $extAddy->email = $data[21];            
                $extAddy->source = $source;   
                
            
        
        }   
        
        }    
    protected $add_permissions = array(
<?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;
    }

}

?>
    protected $add_permissions = array(
        'showUnpublished'=>'View Unpublished News',
        'import'=>'Import News Items',
        'export'=>'Export News Items'
    );
        }       
        
            
            $id = $this->params['title'];
        
            
    
    
    
    public function saveConfig() { 
        
        parent::saveConfig();
    
        foreach ($items as $key => $item) { 
        if (!empty($this->config['pull_rss'])) {    
    
                    
    
        
            $id = $this->params['title'];
    
    
                
        
    }           
        
//    public $cacheDir = "framework/modules/pixidou/images/";
        'editor',
        'exitEditor'
        
        
        $canSaveOg = $user->id==$file->poster || $user->is_admin ? 1 : 0 ;
	    if (file_exists(BASE.$file->directory.$file->filename)) {
			$file->copyToDirectory(BASE.$this->cacheDir);
		    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']));
    
                $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->filesize = filesize(BASE.$this->cacheDir."/".$this->params['cpi']);
                $resized = getimagesize(BASE.$this->cacheDir."/".$this->params['cpi']);
                $resized = getimagesize(BASE.$this->cacheDir."/".$this->params['cpi']);
                copy(BASE.$this->cacheDir."/".$this->params['cpi'],$oldimage->directory.$oldimage->filename); //copy the edited file over to the files dir
            
        $types = array(".jpg",".gif",".png");
        
        $cachedir = BASE.$this->cacheDir;
        
                if (in_array(substr($tmpfile,-4,4),$types)) {
                    $filename = $cachedir.$tmpfile;
        
        redirect_to(array("controller"=>'file',"action"=>'picker',"ajax_action"=>1,"update"=>$this->params['update'],"filter"=>$this->params['filter']));
    
?>
    protected $add_permissions = array(
        'import'=>'Import Portfolio Items',
        'export'=>'Export Portfolio Items'
    );
    protected $add_permissions = array(
    protected $add_permissions = array(
        'build_report' => 'Manage',
        'order_report' => 'Generate Order Report',
        'product_report' => 'Generate Product Report',
        'batch_export' => 'Export Products',
        'export_order_items' => 'Export Order Items File');
            [date-startdate] => 
            [time-h-startdate] => 
            [time-m-startdate] => 
            [date-enddate] => 
            [time-h-enddate] =>     
            [time-m-enddate] => 
            [order-range-num] => 
            [order-price-num] => 
            [pnam] => 
            [sku] => 
            [blshpname] => 
            [email] => 
            [zip] => 
        //$items = $prod->find('all', 1, 'id DESC',25);  
        //$items = $order->find('all', 1, 'id DESC',25);  
        $geos = $geo->find('all');        
        //eDebug(strftime("%A, %d %B %Y", mktime(0,0,0,(strftime("%m")-1),1,strftime("%Y"))));  
        //build 
            //get each calculator's id  
            [date-startdate] => 
            [time-h-startdate] => 
            [time-m-startdate] => 
            [date-enddate] => 
            [time-h-enddate] =>     
            [time-m-enddate] => 
            [order-range-num] => 
            [order-price-num] => 
            [pnam] => 
            [sku] => 
            [blshpname] => 
            [email] => 
            [zip] => 
        //$items = $prod->find('all', 1, 'id DESC',25);  
        //$items = $order->find('all', 1, 'id DESC',25);  
        //eDebug($sql . $sqlwhere); 
        //strftime("%a %d-%m-%Y", get_first_day(3, 1, 2007)); Thursday, 1 April 2010  
            //$line = expString::outputField("SMC Inventory - Laurie");         
        //$items = $product->find('all', '', 'id', 25);     
        //$page = new expPaginator();   
        //eDebug($page,true);   
                'Invoice #'=>'invoice_id', 
        // 
        //     
        // assign_to_template(array('page'=>$page)); 
        //echo "1<br>"; eDebug($str); 
            //if HTML, then leave the single quotes alone, otheriwse replace w/ special Char            
        //$str = str_replace(",","\,",$str); 
            * 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"      
        $allOrderCount = $this->o->find('count','created_at >= ' . $this->tstart . ' AND created_at <= ' . $this->tend,null,null,null,true,false,$except,true);            
        
        
                
        $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);  
        
        
        
  
        
        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)); 
        /*OPTIONALLY ENCLOSED BY '" . '"' . 
        /*OPTIONALLY ENCLOSED BY '" . '"' . 
    protected $add_permissions = array(
        'spider'=>'Spider Site'

    
	
        
    
        
        
	
		
		
		
		
		
		
		
		
			
			
			
	
	
		
		
	
		
	
		
            $answer = new simplepoll_answer($this->params['choice']);
		user::login(expString::sanitize($_POST['username']),expString::sanitize($_POST['password']));
    protected $add_permissions = array(
    );
    protected $remove_permissions = array(
        'create',
        'edit'
        // if this is a new user account we need to check the password.  
        // if this is a new account then we will check to see if we need to send 
        $tok = $db->selectObject('passreset_token', 'uid=' . $this->params['uid'] . " AND token='" . preg_replace('/[^A-Za-z0-9]/', '', $this->params['token']) . "'");
        $u = new user($this->params['uid']);
Fixed code:     );
    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 $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
        if (ENABLE_WORKFLOW)
            $this->permissions = array_merge($this->permissions, array('approve'=>'Approval'));
        $tag = new expTag(expString::escape($this->params['tag']));
            'moduletitle' => ucfirst($modelname) . ' ' . gt('items tagged with') . ' "' . expString::escape($this->params['tag']) . '"',
            $id = expString::escape($this->params['title']);
        $this->params['title'] = expString::escape($this->params['title']);  // escape title to prevent sql injection
        $id = isset($this->params['title']) ? expString::escape($this->params['title']) : (isset($this->params['id']) ? $this->params['id'] : null);
     * permission functions to aggregate a module's visible permissions based on add/remove permissions
    /**
     * 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;
    }

    $controller = new $fullControllerName($src, $parms);


    $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;
    if ($parms['action'] == 'update' || $common_action == 'update') {
    } elseif (($parms['action'] == 'edit' || $common_action == 'edit') && (!isset($parms['id']) || $parms['id'] == 0)) {
            $msg = empty($controller->requires_login[$perm_action]) ? gt("You must be logged in to perform this action") : gt($controller->requires_login[$perm_action]);
            $msg = empty($controller->requires_login[$common_action]) ? gt("You must be logged in to perform this action") : gt($controller->requires_login[$common_action]);
    }


}





    // get the common configuration files
    // look for a config form for this module's current view


    // set path information



        // retrieve objects
            // Otherwise we assume that in inbound is an array or Object to be processed as is.
        // setup the exception array if it's not there.  This array tells the getAssociatedObjectsForThisModel() function which
        $order = expString::escape($order);
        if ($limit !== null)
            $limit = intval($limit);
        if ($limitstart !== null)
            $limitstart = intval($limitstart);
            // if not, then we check to see if we had a previous value in this particular
            // this is good for when the developer is trying to update just a field or two
            // in an existing record.
        //$this->saveAssociatedObjects();
        // mapped view and src hasn't been passed in via link to the form
    function columnUpdate($table, $col, $val, $where=1) {
        //fwrite($lfh, $sql . "\n");
        //fclose($lfh);

        $res = mysqli_query($this->connection, $sql);


        //if ($table=="text") eDebug($object,true);
            //if ($table=="text") eDebug($object,true);
                    $val = serialize($val);
        //if ($table == 'text') eDebug($sql,true);
	 * Escape a string based on the database connection
    function selectArraysBySql($sql) {

	 * Escape a string based on the database connection
   	 * Attempt to prevent a sql injection
 *
 *
 *      'where'=>1,
 *
	public $where = '';
     */
		global $router, $db;
        $this->limit = empty($params['limit']) ? 0 : intval($params['limit']);
		$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->order_direction = $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';


		}

                    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';




		        $this->last_pagelink = $this->total_pages;
		for($i=$this->first_pagelink; $i<=$this->last_pagelink; $i++) {
		}






        $func = new ReflectionClass($this);
                $newParams[$propname] = $params[$propname];
            }
        }
                $newParams[$propname] = $params[$propname];
            }
        }






                }




        }





				}
				$params['order'] = $col;

				if (!empty($col)) {
                        $params['dir'] = 'ASC';
                        $params['dir'] = 'DESC';
                        $params['dir'] = 'ASC';
                    }
				}

                $str .= "'" . intval($value) . "'";
                    $str .= "'" . expString::escape(str_replace("'", "\'", $value)) . "'";  //FIXME is this still necessary since we stripslashes above???
                    $str .= "'" . expString::escape(str_replace("'", '', $value)) . "'";
        if (!empty($profile) && (strpos($profile, '..') !== false || strpos($profile, '/') !== false)) {
            header('Location: ' . URL_FULL);
            exit();  // attempt to hack the site
        }
?>
	}
		}

			$str = stripcslashes($str);
        $str = str_replace("&lsquo;","'",$str);
        $str = str_replace("�","-", $str);
        $str = str_replace("\r\n"," ",$str);
        $str = str_replace("�","(R)",$str);
        $str = str_replace("&","&amp;",$str);
		$str = str_replace(">","&gt;",$str);
//        global $db;
//	        $str = self::escape(trim(str_replace("�", "&trade;", $str)));
//            $str = self::escape(trim(str_replace("�", "&trade;", $str)));
        $str = self::escape(trim(str_replace("�", "&trade;", $str)));
        $str = '';
            $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";
            $str .= "\t" . '<meta http-equiv="Content-Language" content="' . $locale . '" ' . XHTML_CLOSING . '>' . "\n";
?>
//	public $useractions = array(
//    );
    protected $manage_permissions = array(
//        'import' => 'Import External Addresses',
        'process' => 'Import External Addresses'



			if ($count == 0)
            //user is not logged in, but allow anonymous checkout is enabled so we'll check
            $this->params['is_shipping'] = 1;
		expHistory::back();

        {
                if ($address->is_shipping)

        $db->setUniqueFlag($object, 'addresses', expString::escape($this->params['is_what']), "user_id=" . $user->id);
        expHistory::back();


        $gr = new geoRegion();


            $gc->active = true;
            $gc->save();
            $gc = new geoCountry(intval($this->params['country_default']));
            $db->setUniqueFlag($gc,'geo_country','is_default','id=' . $gc->id);
            $gc->refresh();
            $gr->save();
    protected $manage_permissions = array(
        'change'=>'Change Settings',
        'mass'=>'Mass Mailing',
        'save'=>'Save Settings',
//        'update'=>'Update Settings',




//	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();
//	}
		ksort($menu);






    }







    public $useractions = array(
        'showall'=>'Display Banner(s)'
    );
    protected $manage_permissions = array(
        'reset' => 'Reset Stats'
    );

            // randomly grab one banner to be displayed
            $where = 'id IN ('.implode(',', $this->config['banners']).')';
            foreach($banners as $banner) {







        }



        $filename = 'banner_export' . date("m-d-Y") . '.csv';
        fclose($fh);

        // let the user know we did stuff.
    protected $manage_permissions = array(
//        'approve'=>"Approve Comments",
    );
        $this->params['author'] = expString::escape($this->params['author']);
            redirect_to(array('controller'=>'notfound','action'=>'page_not_found','title'=>expString::escape($this->params['title'])));
        $modelname = empty($this->params['model']) ? $this->basemodel_name : expString::escape($this->params['model']);
    protected $manage_permissions = array(
        'change' => 'Change Cats'
    );
    protected $remove_permissions = array(
    protected $add_permissions = array(
        'approve'=>"Approve Comments",
        'bulk'=>"Bulk Actions"
    );

            expHistory::back();
	    }


	}


            'sql'=>$sql,
        $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 .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".expString::escape($this->params['content_type'])."' ";
            'sql'=>$sql,

            $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".expString::escape($this->params['content_type'])."' ";
        }

			'content_id'=>$this->params['content_id'],








        /* The global constants can be overriden by passing appropriate params */




        /* The global constants can be overriden by passing appropriate params */



        /* The global constants can be overriden by passing appropriate params */

        /* The global constants can be overriden by passing appropriate params */



        $db->delete($comment->attachable_table, 'expcomments_id='.$this->params['id']);



        /* The global constants can be overriden by passing appropriate params */



        $mail = new expMail();


        /* The global constants can be overriden by passing appropriate params */

        $mail = new expMail();

//        assign_to_template(array('record'=>$record,'tag'=>$tag));  //FIXME $record & $tag are undefined



		if ($ctl) {
		assign_to_template(array('form_html'=>$form->toHTML(), 'types'=>$types[$control_type]));

	function save() {
		if (call_user_func(array($_POST['control_type'],'useGeneric')) == true) {





    protected $manage_permissions = array(
        'activate' => "Activate",
        'preview'  => "Preview Editor Toolbars"
    );
    public $requires_login = array(
        'preview'=>'Preview Editor',
    );

    protected $manage_permissions = array(
        'approve'=>"Approve Notes"


        /* The global constants can be overriden by passing appropriate params */

        if (empty($this->params['formtitle']))

    }


        /* The global constants can be overriden by passing appropriate params */


            'sql'=>$sql,



        /* The global constants can be overriden by passing appropriate params */
        $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 .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".expString::escape($this->params['content_type'])."' ";

            'sql'=>$sql,

        // count the unapproved notes
            $sql .= 'WHERE cnt.content_id='.$this->params['content_id']." AND cnt.content_type='".expString::escape($this->params['content_type'])."' ";
        }

            'unapproved'=>$unapproved,
            'content_id'=>$this->params['content_id'],

        /* The global constants can be overriden by passing appropriate params */


        // if simplenotes are configed to require approvals set this to 0 otherwise we








        /* The global constants can be overriden by passing appropriate params */





        /* The global constants can be overriden by passing appropriate params */





        /* The global constants can be overriden by passing appropriate params */





        /* The global constants can be overriden by passing appropriate params */



        $db->delete($simplenote->attachable_table, 'expsimplenote_id='.$this->params['id']);



        /* The global constants can be overriden by passing appropriate params */
        $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']);



        $mail = new expMail();

    protected $manage_permissions = array(
//        'import' => 'Import Tags',
//        'importTags' => 'Import Tags',
//        'export' => 'Export Tags',
        'change' => 'Change Tags',
    );
            $id = expString::escape($this->params['title']);
    protected $manage_permissions = array(
        'send'=>'Send E-Alert',
    );



        $src = empty($this->params['src']) ? null : expString::escape($this->params['src']);






        $src = empty($this->params['src']) ? null : expString::escape($this->params['src']);





        }

//    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 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 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 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() {
//
//        // 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
//        ));
//    }
    protected $manage_permissions = array(
        'select'=>'Select Feature',
        'toggle'=>'Toggle Feature',





                                'body'=>$calcobj->description(),


	public function activate(){

    protected $manage_permissions = array(
        'options'=>'Display Options'
    );



        $record = new optiongroup_master($id);












        $record = new option_master($params);

    function update_option_master() {











        $groups = array(
       // eDebug($discount);






    public function activate_discount(){








        $gc = new geoCountry();

        $gr = new geoRegion();

    }

		$gc = new geoCountry();

        $gr = new geoRegion();




    protected $add_permissions = array(
//        'emailRegistrants'=> 'Email Registrants',
    );
    protected $manage_permissions = array(
        'emailRegistrants'=> 'Email Registrants',
    );
    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_new_order_item'=> 'Save New Order Item',
        'save_reference_order'=> 'Save Reference Order',
        'set'           => 'Change Status',
        'showall'             => 'Manage',
        'show'                => 'View Orders',
        'update'                => 'update order',

                    $db->delete('orderitems', 'orders_id='.$cart->id);

            }

        //viewing of the order?
                    //eDebug($order['id'] . ": " . $timer->mark());

            //eDebug($note,true);
        // figure out what metadata to pass back based on the action
        /*eDebug($this->params);
        //eDebug($order,true);
        //eDebug(expUnserialize($order->billingmethod[0]->billing_options));
        //eDebug(expUnserialize($order->billingmethod[0]->billingtransaction[0]->billing_options),true);
            //$newOi->products_tax = 0;
        //eDebug($order,true);
        //eDebug(expUnserialize($order->billingmethod[0]->billing_options));
        //eDebug(expUnserialize($order->billingmethod[0]->billingtransaction[0]->billing_options),true);
            //$oi->product->optiongroup = $parProd->optiongroup;
            /*if ($uif['is_required'] || (!$uif['is_required'] && strlen($params['user_input_fields'][$uifkey]) > 0))
                    //flash('error', 'test');
                    //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));
                }
        //eDebug($oi);
            //we'll send over the product_id of the parent, along with id's and quantities of children we're adding

                redirect_to(array('controller'=>'order','action'=>'show','id'=>$order[0]->id));
                redirect_to(array('controller'=>'order','action'=>'show','id'=>$order->id));
            flashAndFlow('message','Invalid order number.');
                //eDebug($tmpCart,true);
        $sql .= "from " . $db->prefix . "addresses as a "; //R JOIN " .
        $sql .= "from " . $db->prefix . "external_addresses as a "; //R JOIN " .
    protected $manage_permissions = array(
        'toggle'=>'Toggle Status'
    );












	protected $manage_permissions = array(




















    protected $manage_permissions = array(
        'editspeed'=>'Edit Shipping Speed',
        'save'=>'Save Configuration',
        'select'=>'Select Feature',
        'toggle'=>'Enable/Disable Options',





		        $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'];

		$ar->send();






                    $id = $db->selectValue('shippingcalculator', 'id', 'calculator_name="'.$classname.'"');
                        if ($calcobj->isSelectable() == true) {



        $conf = serialize($calc->parseConfig($this->params));




    protected $manage_permissions = array(
//        'import' => 'Import Category',
//        'importCategory' => 'Import Category',
    static function displayname() {
        return gt("e-Commerce Category Manager");
    }

    static function description() {
        return gt("This module is for managing categories in your store.");
    }

        //
        //         //  $this->tags[$i]->draggable = $this->draggable;
        //         //  $this->tags[$i]->checkable = $this->checkable;
        // $obj = json_encode($categories);
            // Trees mapped

                }

        //
        //
        //
        //
        //
        //
        //
        //
    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',
    );
            $ancestors = $this->category->pathToNode();
            {
            $ancestors = $this->category->pathToNode();
            //eDebug($editable_options[$group->title]);
        //eDebug($product_type);
        //eDebug($this->params,true);
        if (empty($product->id)) // || empty($product->previous_id))
            //fwrite($lfh, "Deleting:" . $ctd->id . "\n");
        //$sql .= "GROUP BY p.id ";
        $req = 'a29f9shsgh32hsf80s7';
        {
            $successSet[$count]['message'] = "Sucessfully imported row " . $count . ", order: " . $data[2] . "<br/>";
            $successSet[$count]['shipping_tracking_number'] = '1ZNF453937547';
        {
            $data[2] = $inv + $count;
            $amt += $count*$count;

        assign_to_template(array('errorSet'=>$errorSet, 'successSet'=>$successSet));
        //eDebug($this->params,true);
        //eDebug($data);
                        //just need to set the order shipping info, check and see if we send user an email, and set statuses.
                        //shipping info:
                        //$failMessage = "Attempted to delay capture order " . $data[2] . " and it failed with the following error: " . $result->errorCode . " - " .$result->message;

                            $order->save();
                        //continue;
                    //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.";
            //eDebug($product);
        //eDebug($data);
        $sql .= empty($order) ? '' : ' ORDER BY ' . expString::escape($order);
            $sql .= empty($limit) ? '' : ' LIMIT ' . intval($limitstart) . ',' . intval($limit);
<?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();
    }

}

            $order = expString::escape($order);
            if ($limit !== null)
                $limit = intval($limit);
            if ($limitstart !== null)
                $limitstart = intval($limitstart);




//    protected $manage_permissions = array(
//        'picker'=>'Manage Files',
//        'import'=>'Import',
//        'export'=>'Export',
//    );
        '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',











    }


    }
    }
        global $user;
    }
        // }
        if ($name[0] == '.')  // attempt to upload a dot file
        $name = str_replace('_', '..', $name);  // attempt to upload with redirection to new folder


        $fd = new filedownload(intval($this->params['fileid']));
        }


        parent::downloadfile();

        foreach ($items as $key => $item) {

    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',
    );
                $f = $this->forms->find('first', 'sef_url="' . expString::escape($this->params['title']) . '"');
                    $where = expString::escape($this->params['filter']);
                $f = $this->forms->find('first', 'sef_url="' . expString::escape($this->params['title']) . '"');
                if ($this->config['auto_respond_form'])
                if ($this->config['auto_respond_form'])
        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
        }

        // pagination parameter..hard coded for now.
            $where .= ' AND parent=' . intval($this->params['parent']);
	    $this->params['title'] = expString::escape($this->params['title']);  // escape title to prevent sql injection


	    $where = empty($this->params['version']) ? 1 : 'help_version_id='.intval($this->params['version']);








	    expHistory::back();


	        self::copydocs($current_version->id, $version->id);

        return $db->selectValue('help_version', 'id', 'version="'.$db->escapeString($version).'"');
        return $db->selectValue('help_version', 'version', 'id="'.intval($version_id).'"');
    protected $add_permissions = array(
        'import' => 'Import Data',
        'export' => 'Export Data'
    );
    protected $manage_permissions = array(
        'importProduct' => 'Import Product',
    );
        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
        }

        //eDebug($this->params,true);
        //eDebug($data);
        $source = '';
            $dataset[$value] = '';


            $extAddy = new external_address();
                $extAddy->lastname = $bName[2];
                $extAddy->lastname = '';
                $extAddy->lastname = $bName[1];

            $extAddy->address2 = $data[6];
            $extAddy->address2 = $data[6];
            $extAddy->city = $data[7];

            $extAddy->state = $state->id;
            $extAddy->zip = str_ireplace("'",'',$data[9]);
            $extAddy->phone = $data[20];
            $extAddy->email = $data[21];


                $extAddy->is_shipping = 1;
                $extAddy->save(false);
            {
                $extAddy->is_shipping = 0;
                $extAddy->save(false);

                $extAddy = new external_address();
                    $extAddy->lastname = $sName[2];
                    $extAddy->lastname = '';
                    $extAddy->lastname = $sName[1];

                $extAddy->address2 = $data[15];
                $extAddy->city = $data[16];

                $extAddy->state = $state->id;
                $extAddy->zip = str_ireplace("'",'',$data[18]);
                $extAddy->phone = $data[20];
                $extAddy->email = $data[21];
                $extAddy->source = $source;



        }

        }
    protected $manage_permissions = array(
<?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;
    }

}

?>
    protected $add_permissions = array(
        'showUnpublished'=>'View Unpublished News',
        'showExpired'=>'View Unpublished News',
    );
    protected $manage_permissions = array(
        'import'=>'Import News Items',
        'export'=>'Export News Items'
    );
        }


            $id = expString::escape($this->params['title']);





    public function saveconfig() {

        parent::saveconfig();

        foreach ($items as $key => $item) {
        if (!empty($this->config['pull_rss'])) {
    protected $manage_permissions = array(
        'multi'=>'Bulk Actions',
    );




            $id = expString::escape($this->params['title']);




    }

        'editor'=>'You must be logged in to perform this action',
        'exitEditor'=>'You must be logged in to perform this action',


        $canSaveOg = $user->id==$file->poster || $user->isSuperAdmin() ? 1 : 0 ;
	    if (file_exists(BASE . $file->directory . $file->filename)) {
			$file->copyToDirectory(BASE . $this->cacheDir);
		    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']));

                $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->filesize = filesize(BASE . $this->cacheDir . "/" . $this->params['cpi']);
                $resized = getimagesize(BASE . $this->cacheDir . "/" . $this->params['cpi']);
                $resized = getimagesize(BASE . $this->cacheDir . "/" . $this->params['cpi']);
                copy(BASE . $this->cacheDir . "/" . $this->params['cpi'], $oldimage->directory . $oldimage->filename); //copy the edited file over to the files dir

        $types = array(".jpg", ".gif", ".png");

        $cachedir = BASE . $this->cacheDir;

                if (in_array(substr($tmpfile, -4, 4), $types)) {
                    $filename = $cachedir . $tmpfile;

        redirect_to(array("controller"=>'file', "action"=>'picker', "ajax_action"=>1, "update"=>$this->params['update'], "filter"=>$this->params['filter']));

?>
    protected $manage_permissions = array(
        'import'=>'Import Portfolio Items',
        'export'=>'Export Portfolio Items'
    );
    protected $manage_permissions = array(
        $this->params['mod'] = expString::escape($this->params['mod']);
        $this->params['src'] = expString::escape($this->params['src']);
    protected $manage_permissions = array(
        'abandoned_carts' => 'Abandoned Carts Report',
        'batch_export' => 'Export Products',
        'current_carts' => 'Current Carts Report',
        'download' => 'Download Report',
        'order_report' => 'Generate Order Report',
        'payment_report' => 'Generate Payment Report',
        'product_report' => 'Generate Product Report',
        'purge_abandoned_carts' => 'Purge Abandoned Carts',
        'status_export' => 'Export Status',
    );
            [date-startdate] =>
            [time-h-startdate] =>
            [time-m-startdate] =>
            [date-enddate] =>
            [time-h-enddate] =>
            [time-m-enddate] =>
            [order-range-num] =>
            [order-price-num] =>
            [pnam] =>
            [sku] =>
            [blshpname] =>
            [email] =>
            [zip] =>
        //$items = $prod->find('all', 1, 'id DESC',25);
        //$items = $order->find('all', 1, 'id DESC',25);
        $geos = $geo->find('all');
        //eDebug(strftime("%A, %d %B %Y", mktime(0,0,0,(strftime("%m")-1),1,strftime("%Y"))));
        //build
            //get each calculator's id
            [date-startdate] =>
            [time-h-startdate] =>
            [time-m-startdate] =>
            [date-enddate] =>
            [time-h-enddate] =>
            [time-m-enddate] =>
            [order-range-num] =>
            [order-price-num] =>
            [pnam] =>
            [sku] =>
            [blshpname] =>
            [email] =>
            [zip] =>
        //$items = $prod->find('all', 1, 'id DESC',25);
        //$items = $order->find('all', 1, 'id DESC',25);
        //eDebug($sql . $sqlwhere);
        //strftime("%a %d-%m-%Y", get_first_day(3, 1, 2007)); Thursday, 1 April 2010
            //$line = expString::outputField("SMC Inventory - Laurie");
        //$items = $product->find('all', '', 'id', 25);
        //$page = new expPaginator();
        //eDebug($page,true);
                'Invoice #'=>'invoice_id',
        //
        //
        // assign_to_template(array('page'=>$page));
        //echo "1<br>"; eDebug($str);
            //if HTML, then leave the single quotes alone, otheriwse replace w/ special Char
        //$str = str_replace(",","\,",$str);
            * 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"
        $allOrderCount = $this->o->find('count','created_at >= ' . $this->tstart . ' AND created_at <= ' . $this->tend,null,null,null,true,false,$except,true);



        $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);





        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));
        /*OPTIONALLY ENCLOSED BY '" . '"' .
        /*OPTIONALLY ENCLOSED BY '" . '"' .
    protected $manage_permissions = array(
        'spider'=>'Spider Site',
        'searchQueryReport'=>'Search Query Report',
        'topSearchReport'=>'Top Search Report',


























            $answer = new simplepoll_answer(intval($this->params['choice']));
		user::login(expString::escape(expString::sanitize($_POST['username'])),expString::escape(expString::sanitize($_POST['password'])));
//    protected $remove_permissions = array(
//        'create',
//        'edit'
//    );
    protected $manage_permissions = array(
        'update'           => 'Update Users',
        // if this is a new user account we need to check the password.
        // if this is a new account then we will check to see if we need to send
        $this->params['username'] = expString::escape($this->params['username']);
        $tok = $db->selectObject('passreset_token', 'uid=' . intval($this->params['uid']) . " AND token='" . preg_replace('/[^A-Za-z0-9]/', '', expString::escape($this->params['token'])) . "'");
        $u = new user(intval($this->params['uid']));
        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['filename']) && (strpos($this->params['filename'], 'tmp/') === false || strpos($this->params['folder'], '..') !== false)) {
            header('Location: ' . URL_FULL);
            exit();  // attempt to hack the site
        }